Repository navigation
navmap_core, navmap_ros: fixes for large maps (DistanceField, set_are… - #42
Open
jmguerreroh wants to merge 1 commit into
Open
jmguerreroh wants to merge 1 commit into
jmguerreroh wants to merge 1 commit into
Conversation
…a, operator=, save size limit)
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
navmap_core / navmap_ros: four fixes found by benchmarking large maps
Branch base:
rolling. Files:navmap_core(DistanceField, NavMap::set_area, NavMap::operator=)and
navmap_ros(navmap_io). Independent of thenavmap_toolsPR; neither needs the other.These came out of a comparison of NavMap and a level-of-detail maps manager on maps of 100 to
10 000 cells per side (50 m to 5 km at 0.5 m). Each one is a separate commit-sized change with its
own regression test.
1. DistanceField: indexing a seed cost the square of its length
DistanceField::index_seedput a segment seed (an open edge of the mesh) into every bucket of itsbounding box. For an axis-aligned edge that is a line of buckets, but for a diagonal one it is a
square: an edge of 16 m at 45° filled ~1 000 buckets instead of ~40, and every query near it then
scanned them. Meshes with long diagonal open edges (coarse NavCels of a level-of-detail map, a
rotated map with holes) spent seconds in
compute().Now a seed is indexed by points sampled along it every
bucket_metres (deduplicated), and thequeries in
update()look one bucket further on each side, so no seed within reach is missed(every point of the segment is within half a bucket of a sample).
Measured (the same mesh, 22 944 NavCels, 9 586 open edges, with legs of 0.5 to 16 m; time of
compute()). Rotated 45°, before / after:A diagonal mesh now costs what an axis-aligned one does (linear in the edge length, as the
number of NavCels it touches).
Test:
test_incrementalgets a fourth map in its equivalence sweep (4 m cells with holes, rotated30°: the incremental field must equal the full recomputation there too), and
LongDiagonalOpenEdgesCostAboutAsMuchAsShortOnes(the 16 m mesh within 25× the 0.5 m one; it was~600×).
2. NavMap::set_area: O(map) per call, and its writes were invisible to incremental filters
std::vector<char> visited(navcels.size()): writing a 0.5 m disc on a map of50 M NavCels allocated and zeroed 50 MB per call. It is now an
unordered_setof the NavCels thearea actually visits: the cost is the area's.
mutable_data()directly, so the layer's change list (changed(), used by theincremental InflationFilter of EasyNav) did not see the new values: an obstacle written with
set_areawas not inflated until something else marked the layer. Every NavCel written is nowrecorded with
mark_changed, aslayer_setdoes.Test:
NavMap_SetArea_Systematic.TheWrittenNavCelsAreRecordedAsChangedForIncrementalConsumers(the change list equals exactly the NavCels written). The existing set_area tests are unchanged and
pass.
3. NavMap::operator=: crash when a layer changed type
When the destination already had a layer of the same name but another type (the source removed it
and re-created it, e.g. U8 → F32),
operator=askedadd_or_get<T>for a view of the new type,got
nullptrand dereferenced it. This happens in EasyNav when a node copies the map from theNavState, re-creates a layer with another type and sets it back. The old layer is now removed
before the copy when the types differ.
Test:
NavMapAssign.ALayerReCreatedWithAnotherTypeIsReplacedNotDereferencedAsNull(U8 → F32 andback). It segfaulted before the fix.
4. navmap_io: a map too big for one CDR message failed with a bare I/O error
Fast-CDR cannot serialise more than 4 GiB.
save_msg_to_file/save_to_fileof a bigger map(about 180 M NavCels with one layer) allocated gigabytes, then failed deep inside the serialiser
with a non-
stdexception that was reported asEIO. Now:SaveOptions::max_serialized_bytes(default 4 GiB − 1 MiB) andestimated_serialized_size(const msg::NavMap &), a close upper estimate computed from the arraysizes, without serialising;
std::errc::file_too_large(
EFBIG) and a log line with the estimated size. Nothing is written.Tests:
NavMapIoMsg.TheSizeEstimateIsCloseAboveTheSerialisedSize(above the real size by less thana few KB),
NavMapIoMsg.AMapBeyondWhatAMessageHoldsIsRefusedAsTooLargeAndNothingIsWritten(a smalllimit, so the test needs no 4 GB map).
No API is removed or changed in a breaking way: one field added to
SaveOptions(with the oldbehaviour's effective limit as default) and one free function added.
Tests
navmap_core:
test_incremental(8),test_navmap_easy(19),test_distance_field(8),test_navmap_assign(7) and the rest of the suite pass; navmap_ros:test_navmap_io(6) and therest pass. Built and run on ROS 2 Rolling, Ubuntu 24.04.