Changelog
This page aggregates the changelogs from the most relevant MOLA repositories:
Changelog for package mola_bridge_ros2
3.2.1 (2026-09-15)
Merge pull request #214 from MOLAorg/fix/reloc-request-race-with-module-discovery FIX: relocalization requests raced with MOLA module discovery
Throttle and coalesce the on-demand MOLA module scan
Contributors: Jose Luis Blanco-Claraco
3.2.0 (2026-08-21)
Merge pull request #198 from Zeal-Robotics/fix/bridge_ros2-tf-buffer-staleness fix(bridge_ros2): keep the TF buffer current under bridge executor load
fix(bridge_ros2): give the TF listener its own spin thread The listener was constructed with spin_thread=false, against tf2’s own default, on the grounds that the bridge already spins rosNode_ and a second spinner would be redundant. That holds only while the bridge executor keeps up with /tf, and makes buffer freshness a function of everything else the node is handling – sensor callbacks, timers, map publishing. When it does not keep up, the failure is silent: lookups still succeed, they just answer from a buffer that is behind, and the resulting poses look plausible. With spin_thread=true the /tf and /tf_static subscriptions move to a callback group and executor the listener owns, so ingestion is independent of the bridge executor’s load. No new sharing is introduced. The buffer is already read from other threads – publishLocalizationTf() from the localization source’s thread, transform_tree() from whichever module calls it – and tf2::BufferCore serialises readers and writers on a single mutex. The listener’s group is created with automatically_add_to_executor_with_node=false, so add_node() does not adopt it and no second executor can dispatch those subscriptions. Its destructor cancels and joins its thread, and it is declared after tf_buffer_ and rosNode_, so that happens while both are still alive.
fix(bridge_ros2): drain the ROS queues instead of one message per topic The ROS thread polls spin_some() on a 10 ms sleep. That loop replaced a blocking rclcpp::spin() so the destructor could stop the thread via shouldExit_, and the sleep was only ever there to keep the flag poll from busy-waiting. But spin_some() collects the ready set once and executes each ready entity at most once per call, so the pair caps every subscription at roughly one message per 10 ms and puts a 10 ms floor under handling anything. Any topic arriving faster than ~100 Hz therefore keeps its subscription queue permanently full, and every message the node sees is stale by the whole queue depth. /tf is the worst case: it aggregates every broadcaster on the graph, so on a robot publishing a few hundred transforms/s the listener’s KeepLast(100) queue leaves the TF buffer several hundred ms behind. The visible symptom is REP-105 composition falling back to the stale odom transform with “extrapolation into the future” while the odom broadcaster is publishing on time and a normally-spun listener on the same graph reads it as current. A 200 Hz IMU on the same node loses half its samples the same way. spin_once(timeout) blocks until there is work while still bounding how long shouldExit_ goes unchecked, and spin_all() then drains whatever else is ready. Both are needed: spin_some() and spin_all() each call wait_for_work(0ms), so spin_all() alone returns immediately when idle and would busy-wait. With work pending spin_once() returns at once, so no iteration sleeps while a queue is non-empty. Cost is that the two bounds stack: worst case for observing shouldExit_ goes from 10 ms to 20 ms. Measured with two TF listeners on the same /tf, one per spin strategy: draining fully leaves the buffer 12.6 ms behind the broadcaster, taking one message per 10 ms tick leaves it 358 ms behind. A blocking spin() cancelled via executor.cancel() would remove the poll loop altogether and is the better end state, but cancel() racing the spinning.exchange(true) in spin() means the destructor has to retry until the thread joins. That is left as a separate change.
Merge remote-tracking branch ‘origin/feat/map-frame-gauge-change’ into feat/map-frame-gauge-change
Merge branch ‘develop’ into feat/map-frame-gauge-change
Contributors: Jose Luis Blanco-Claraco, Robin Van Cauwenbergh
3.1.1 (2026-08-10)
fix build in ros rolling (newer gcc)
fix format
mola_bridge_ros2: use tf2_ros .hpp headers instead of deprecated .h Avoids #warning deprecation spam on newer ROS2 distros while building unchanged from Humble to Rolling.
Contributors: Jose Luis Blanco Claraco, Jose Luis Blanco-Claraco
3.1.0 (2026-08-06)
Add mola::TransformTreeSource: expose the /tf tree to other MOLA modules (#188) * Add mola::TransformTreeSource: expose the /tf tree to other modules New mola_kernel interface letting a data source publish its tree of coordinate frames, so consumers (e.g. a LiDAR-odometry viewer) can draw a robot’s joints as it moves. transform_tree(root) returns the subtree below ‘root’ with poses already resolved against it. The filtering is done in the source, which is what owns the transform buffer, so a consumer never receives nor walks unrelated subtrees. The interface carries no ROS/tf2 type, keeping mola_kernel ROS-independent. Implemented by Rosbag1Dataset (separate repo), Rosbag2Dataset and BridgeROS2. No locking is added around the subtree walk: tf2::BufferCore guards its own internals, which is also what lets BridgeROS2’s TransformListener feed the buffer from its own thread. * Address review: depth-first comment, cycle guard in the tf walk * No need for include guards inside this same git repo
Merge pull request #187 from MOLAorg/feat/incremental-point-cloud-kdtree-bake Bake IncrementalPointCloud’s k-d tree index (mm-ipc-bake-kdtree)
changelog
fix: ros rolling changed arguments of tf2_ros tf listeners
fix: GCC error in Rolling due to missing direct rclcpp/Node.hpp include
totally drop mrpt2 point cloud classes
Merge pull request #177 from MOLAorg/feat/rep105-loud-stale-odom-warning Make the REP-105 stale-odom fallback loud on first occurrence
fix(bridge): make the REP-105 stale-odom fallback loud on first occurrence When publish_localization_following_rep105 is on and the exact sensor-stamp odom->base_link transform is unavailable, the bridge composes map->odom against the latest (stale) odom transform. That biases the published TF by the robot’s motion over the stamp gap (motion-correlated jitter, worst mid-turn), and it is the normal path whenever the localizer publishes an estimate extrapolated to “now” while odom only exists in the past. The warning was throttled to 60 s, which hid this persistent timing violation. Emit a loud, explanatory warning the first time the fallback fires, naming the consequence and the recommended fix (have the state estimator publish map->odom directly via StateEstimationSmoother’s publish_map_to_odom_tf, and route the bridge TF source filter to that /map_odom method), then continue with the throttled steady-state warning so logs are not flooded. No behavior change to the published transform itself.
Contributors: Jose Luis Blanco-Claraco
fix: ros rolling changed arguments of tf2_ros tf listeners; fixed GCC error in Rolling due to missing direct rclcpp/Node.hpp include; dropped MRPT2 point cloud classes.
fix(bridge): REP-105 stale-odom TF fallback now logs a loud, explanatory warning the first time it fires (with the recommended fix), instead of only a throttled one.
Contributors: Jose Luis Blanco-Claraco
3.0.0 (2026-07-17)
chore: less verbose warning
fix: rep105 mode made robust against lagging odom frame
fix: replace rclcpp deprecated spin_some()
Merge pull request #153 from Zeal-Robotics/fix/bridge_ros2-relocalize-frame fix(bridge_ros2): transform relocalization pose into reference frame
fix(bridge_ros2): transform relocalization pose into reference frame The relocalization topic callback and the relocalize_near_pose service fed the incoming PoseWithCovarianceStamped straight to relocalize_near_pose_pdf(), ignoring its header.frame_id. The pose was therefore interpreted in the localization reference_frame regardless of the frame it was actually expressed in. When a tool publishes it in a different frame (e.g. RViz’s “2D Pose Estimate” in the fixed frame) that differs from reference_frame, the relocalization lands in the wrong place. Compose reference_frame <- header.frame_id via the tf buffer before relocalizing, in both the topic callback and the service. The covariance is propagated through the rotation by CPose3DPDFGaussian::changeCoordinatesReference(). Requests are skipped (topic) or rejected (service) when the transform is unavailable, instead of silently relocalizing to a wrong pose.
fix: safer owned_rclcpp flag
Merge pull request #150 from MOLAorg/fix/bridge-ros2-rclcpp-shutdown-ownership feat: bridge ros2 now autodetects rclpp shutdown ownership
feat: bridge ros2 now autodetects rclpp shutdown ownership
Merge pull request #149 from MOLAorg/fix/tf-listener-share-ros-node fix(mola_bridge_ros2): share rosNode_ with TF listener for consistent clock/use_sim_time
fix(mola_bridge_ros2): share rosNode_ with TF listener for consistent clock/use_sim_time handling Pass rosNode_ to TransformListener so its /tf and /tf_static subscriptions share the bridge’s DDS participant, clock, and use_sim_time setting. Without this, the default constructor creates an anonymous node that ignores use_sim_time – causing subtle inconsistencies when playing bags with –clock. spin_thread=false avoids a redundant second spinner since rosNode_ is already spun by the bridge’s main loop.
Contributors: Jose Luis Blanco-Claraco, Robin Van Cauwenbergh
2.9.0 (2026-05-11)
Merge pull request #143 from MOLAorg/bump-cmake-version bump min req cmake version to 3.22
bump min req cmake version to 3.22
Less verbose output: don’t print covariance matrix for each geo-referenced solution
Contributors: Jose Luis Blanco-Claraco
2.8.0 (2026-04-29)
Merge pull request #140 from MOLAorg/feat/bridge-ros2-qos feat: BridgeROS2 now have configurable QoS
fix: harden parameter parsing
feat: BridgeROS2 now have configurable QoS
Merge pull request #135 from MOLAorg/pr-132 feat(bridge_ros2): align REP-105 TF with Nav2 conventions without regressing direct-publish mode
feat(bridge_ros2): align REP-105 TF publishing with Nav2 conventions This brings the localization /tf publisher in line with the convention used by AMCL, slam_toolbox, RTAB-Map and Cartographer, addressing three issues observed when MOLA is consumed by Nav2-style downstream nodes: 1. REP-105 composition bug (fix). The inner factor of map -> odom = (map -> base)(t_scan) * (base -> odom)(t) was sampled at “latest” via waitForTransform(), which only supports tf2::TimePoint{}. The two factors must be sampled at the same instant or the published correction is biased by the odom-frame motion accumulated during the localizer’s processing latency. Switch to tf_buffer_->lookupTransform(…, scan_tp). On lookup failure the publish is skipped (an empty default-constructed TransformStamped would inject TF_NO_FRAME_ID into every consumer’s tf2 buffer). 2. transform_tolerance (new param, default 0.1s). The published stamp is now node->now() + transform_tolerance so consumers can do lookupTransform(map, base_link, now()) without ExtrapolationException. Mirrors AMCL’s transform_tolerance and RTAB-Map’s tf_tolerance. Uses the ROS clock so use_sim_time is honored automatically. 3. transform_publish_period (new param, default 0.05s = 20 Hz). A wall timer re-broadcasts the cached map -> odom independent of localization update rate, keeping the TF buffer continuously fresh even when the localizer runs slower than the consumer query rate. Set to 0 to disable. Mirrors slam_toolbox’s transform_publish_period and RTAB-Map’s tf_delay. Backwards compat: to exactly preserve the prior (post-bugfix) stamping behavior set transform_tolerance: 0 and transform_publish_period: 0. publish_in_sim_time retains its meaning for all other publishers (sensor TFs, odom messages, etc.); only the localization /tf stamp source changed.
Merge branch ‘develop’ into perf/keyframe-prewarm-global-submap
Merge pull request #133 from Zeal-Robotics/fix/bridge-ros2-throttle-tf-lookup-errors fix(bridge_ros2): throttle TF lookup error logging
fix(bridge_ros2): throttle TF lookup error logging Failed sensor TF lookups (e.g. missing static URDF transforms during bring-up) flooded the console with two unthrottled ERROR lines per observation. With a Livox IMU at ~100 Hz this produced ~200 lines/s per affected topic, drowning out other diagnostics. - Throttle (5 s) every per-observation “Could not forward ROS2 observation to MOLA due to timeout…” in the PointCloud2, LaserScan, Imu, NavSatFix and gps_msgs paths, plus the “Could not get /tf” path that uses lookupSensorPose, and the REP-105 odom->base_link recompute warning in publishLocalizationTf. - Drop the redundant printErrors plumbing from waitForTransform: the inner MRPT_LOG_ERROR(ex.what()) duplicated what callers already print with more context (frames + timestamp). The raw tf2 reason is still emitted at DEBUG for deep diagnostics. Per-callsite throttle state means independent sensors still surface “this stream stopped” promptly; we just stop spamming the same one.
Contributors: Jose Luis Blanco-Claraco, Robin Van Cauwenbergh
2.7.0 (2026-04-22)
Merge pull request #131 from MOLAorg/feat/actions-custom-runner CI actions: build for arm64 too
Merge branch ‘Zeal-Robotics-fix/bridge-ros2-skip-empty-tf-on-rep105-failure’ into develop
Fix formatting and clarify function arguments
fix(bridge_ros2): skip TF publish when REP-105 odom lookup fails In publishLocalizationTf, when publish_localization_following_rep105 is enabled, the bridge needs to look up odom_frame -> base_link_frame to compose map -> odom. If that lookup fails (e.g. wheel odometry hasn’t started publishing yet during system startup), the previous code logged the error but still fell through to tf_bc_->sendTransform(tf) with a default-constructed TransformStamped (empty frame_id and child_frame_id). This poisoned every subscriber’s tf2 buffer at the localization rate, producing a continuous stream of TF_NO_FRAME_ID, TF_NO_CHILD_FRAME_ID, and TF_SELF_TRANSFORM errors across every node in the system until the odom TF became available. Fix: return early on lookup failure so no broadcast happens. While here, restructure the function with an early-return guard for publish_tf_from_slam to flatten the nesting, and include the actual frame names in the error message. Behavior unchanged in the success path.
Merge pull request #129 from MOLAorg/feat/ros2-diagnostics Feature: ROS2 diagnostics
feat(bridge_ros2): publish REP-107 /diagnostics DiagnosticArray Collect structured diagnostics from modules implementing the new mola::DiagnosticsProvider interface and publish them on the standard ROS 2 /diagnostics topic alongside the existing ad-hoc mola_diagnostics/ topics. Adds the diagnostic_msgs dependency. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Merge pull request #122 from MOLAorg/feat/ros2-bridge-multiple-odometries Add param ‘odometry_as_robot_pose_observation’ to switch OdometryMsg …
Skip entries with empty topic name
Add param ‘odometry_as_robot_pose_observation’ to switch OdometryMsg mapping to MRPT types
Merge pull request #121 from MOLAorg/fix/clean-up-old-mrpt-version-checks Clean up: remove old mrpt version fallback code sections
Contributors: Jose Luis Blanco-Claraco, Robin Van Cauwenbergh
2.6.1 (2026-04-02)
2.6.0 (2026-03-12)
Remove now obsolete version check macro
Merge pull request #108 from MOLAorg/feat/use-gps-msgs Support gps_msgs data types too for ROS2
Support gps_msgs as alternative to NavSatFix
Merge pull request #107 from MOLAorg/fix/viz-decay-clouds Fix/viz-decay-clouds
Update coyright notes
Contributors: Jose Luis Blanco-Claraco
2.5.0 (2026-02-14)
Merge pull request #105 from MOLAorg/feat/refactor-ros2-bridges Refactor to use external rosbag2 conversion in mrpt_ros_bridge
Use refactored ros2mrpt bridge in live node too
Fix: potential access to the ROS2 node before it’s ready
Merge pull request #101 from MOLAorg/fix/mola-bridge-no-pub-queue Fix: mola bridge no pub queue
BridgeRos2: publish localization updates immediately, do not buffer them
Add debug traces
Merge pull request #99 from MOLAorg/feat/ros2-bridge-pub-geographic ROS2 bridge: publish geographic poses too
ros2 bridge: use geographic_msgs, store the last georeference info internally, and publish georef poses merge of these commits: - Enable many more clang-tidy checks - lint clean - implement publishing georeferenced poses - mola-viz: fix potential crash on edge case with all points having NaN value - FIX: potential crash if no MapServer is present and map services are called
fix clang-format
FIX: potential deadlock in BridgeROS2 dtor due to early errors before ros2 is initialized
Contributors: Jose Luis Blanco-Claraco
2.4.0 (2025-12-28)
Prepare for not using deprecated mrpt_maps types starting for mrpt >=3.0.0
FIX: Potential segfault if observations come before ROS2 /tf broadcasters are initialized
Contributors: Jose Luis Blanco-Claraco
2.3.0 (2025-12-15)
Import all pcd fields from ros2 messages using CGenericPointsMap
Contributors: Jose Luis Blanco-Claraco
2.2.1 (2025-11-08)
BridgeROS2: more debug traces in map publishing
Contributors: Jose Luis Blanco-Claraco
2.2.0 (2025-10-28)
format
Fix build against upcoming mrpt v2.15.0
Contributors: Jose Luis Blanco-Claraco
2.1.0 (2025-10-20)
Publish to ROS all map types implementing getAsSimplePointsMap()
format
FIX: ROS2 bridge must use timestamps for map updates to publish maps and deskewed clouds
Support publishing several maps from the same source per iteration to ROS
clang-format
Make use of ConstPtr across API
Contributors: Jose Luis Blanco-Claraco
2.0.0 (2025-10-13)
fix clang-format
Modernize copyright notice
Contributors: Jose Luis Blanco-Claraco
1.9.1 (2025-07-07)
1.9.0 (2025-06-06)
fix clang-format
Implement publishing of optional “metadata” map field too
Contributors: Jose Luis Blanco-Claraco
1.8.1 (2025-05-28)
Fix: Do not use the deprecated ament_target_dependencies()
Contributors: Jose Luis Blanco-Claraco
1.8.0 (2025-05-25)
Update license tag to “BSD-3-Clause”
Update copyright year
Contributors: Jose Luis Blanco-Claraco
1.7.0 (2025-05-06)
1.6.4 (2025-04-23)
fix: Correctly handling Livox cloud timestamps (“double”s, but in nanoseconds) in BridgeROS2 and bag2 data sources. They are automatically detected, no need to change any parameter.
modernize clang-format
Merge pull request #82 from ahpinder/develop Add Support for Voxel Map ROS2 Publishing Via Point Map Conversion
fixed Clang formatting
Clean up voxel map publishing code
Added voxel map point cloud publishing Added code to timerPubMap to publish the occupied voxels of a mrpt::maps::CVoxelMap as a point cloud to ROS2, allowing for real-time ROS2 visualization of 2D map capture
Contributors: Jose Luis Blanco-Claraco, ahpinder
1.6.3 (2025-03-15)
clang-tidy: const correctness
Service renamed: RelocalizeFromGNSS -> RelocalizeFromStateEstimator
FIX: Potential deadlock in initialization
Contributors: Jose Luis Blanco-Claraco
1.6.2 (2025-02-22)
Implement publish Diagnostics per mola module & ROS2 publishers refactored (code clean up)
BridgeROS2: add source filter for forwarding localization updates to ROS2
ROS2: base_footprint_frame /tf is broadcasted now as base_link -> base_footprint to avoid /tf warnings (better as a child than as a second parent in the tf tree)
FIX: In parsing base_footprint_to_base_link_tf
Contributors: Jose Luis Blanco-Claraco
1.6.1 (2025-02-13)
Add new option: publish_tf_from_slam; add better docs on the meaning of all parameters
Publish georef /tf as /tf_static
ROS2 bridge now publishes georeferenced map metadata as /tf’s and as mrpt_nav_interfaces/GeoreferencingMetadata
Revert “Feature: all MOLA modules got its MRPT logger to ROS console for easier debugging” This reverts commit 8a84611d85022f37b80d8bdcb7acaa1910669fc1.
FIX: wrong variable in former commit
Merge pull request #75 from MOLAorg/feature/mrpt-to-ros-console Feature: all MOLA modules got its MRPT logger to ROS console for easier debugging
Feature: all MOLA modules got its MRPT logger to ROS console for easier debugging
Contributors: Jose Luis Blanco-Claraco
1.6.0 (2025-01-21)
Publish gridmaps too
ros2 bridge: rep105 only for map->base_link tfs
BridgeROS2: support forwarding more than one localization message per timer call
Fix published /tf’s: those from LocalizationSources now can explicitly define their parent and child frames
Contributors: Jose Luis Blanco-Claraco
1.5.1 (2024-12-29)
1.5.0 (2024-12-26)
1.4.1 (2024-12-20)
BridgeROS2: add option (now enabled by default) to publish /tfs following REP105 order
BUG FIX: Published odometry msg lacked target frame_id
Rename method for better reflecting its goal
Contributors: Jose Luis Blanco-Claraco
1.4.0 (2024-12-18)
Publish localization quality topic
Forward –ros-args to BridgeROS2
expose services for runtime parameters
Load relocalize_from_topic from yaml file
ros2bridge: handle /initialpose topic -> relocalize service
Contributors: Jose Luis Blanco-Claraco
1.3.0 (2024-12-11)
Support publishing IMU readings MOLA -> ROS2
Contributors: Jose Luis Blanco-Claraco
1.2.1 (2024-09-29)
BUGFIX: Prevent potential race condition
Contributors: Jose Luis Blanco-Claraco
1.2.0 (2024-09-16)
sort <depend> entries
Contributors: Jose Luis Blanco-Claraco
1.1.3 (2024-08-28)
Depend on new mrpt_lib packages (deprecate mrpt2)
Contributors: Jose Luis Blanco-Claraco
1.1.2 (2024-08-26)
1.1.1 (2024-08-23)
1.1.0 (2024-08-18)
Merge pull request #65 from MOLAorg/add-more-srvs Add more Services
Offer ROS2 services for the new MOLA MapServer interface
clang-format: switch to 100 columns
ros2bridge: offer ROS2 services for relocalization
Merge pull request #62 from MOLAorg/docs-fixes Docs fixes
Fix ament_xmllint warnings in package.xml
change ament linters to apply in test builds
Contributors: Jose Luis Blanco-Claraco
1.0.8 (2024-07-29)
ament_lint_cmake: clean warnings
Contributors: Jose Luis Blanco-Claraco
1.0.7 (2024-07-24)
Fix GNSS typo
Contributors: Jose Luis Blanco-Claraco
1.0.6 (2024-06-21)
1.0.5 (2024-05-28)
1.0.4 (2024-05-14)
bump cmake_minimum_required to 3.5
Contributors: Jose Luis Blanco-Claraco
1.0.3 (2024-04-22)
BridgeROS2: more robust /tf find_transform by using tf2::BufferCore
FIXBUG: inverse sensor poses in rosbag2 reader. Also: unify notation in C++ calls to lookupTransform()
Fix package.xml website URL
Contributors: Jose Luis Blanco-Claraco
1.0.2 (2024-04-04)
update docs
Contributors: Jose Luis Blanco-Claraco
1.0.1 (2024-03-28)
BridgeROS2: do not quit on temporary /tf timeout
mola_bridge_ros2: option to publish /tf_static for base_footprint
mola_bridge_ros2: implement missing MOLA->ROS2 conversion for GNSS observations
BUGFIX: Inverted value of “use_fixed_sensor_pose” was used
Contributors: Jose Luis Blanco-Claraco
1.0.0 (2024-03-19)
Comply with ROS2 REP-2003
Merge ROS2 input and output in one module
Contributors: Jose Luis Blanco-Claraco
0.2.2 (2023-09-08)
Changelog for package mola_kernel
3.2.1 (2026-09-15)
mola_viz_imgui: show “???” for an unknown dataset duration (#203)
mola_viz_imgui: show dataset playback time in the dataset UI panel (#202)
Contributors: Jose Luis Blanco-Claraco
3.2.0 (2026-08-21)
Merge pull request #192 from MOLAorg/feat/map-frame-gauge-change Support re-expressing estimator and pose-list state in a new frame
Merge remote-tracking branch ‘origin/feat/map-frame-gauge-change’ into feat/map-frame-gauge-change
mola_kernel: declare transform_frame() last; test SearchablePoseList frame change Appending the new optional virtual only grows the vtable, whereas the previous mid-list position shifted the slot index of the three virtuals after it, breaking any prebuilt NavStateFilter plugin. A note asks that future optional virtuals also go at the end. Adds regression coverage for SearchablePoseList::transform_left_multiply() in both storage modes: that the kd-tree follows the transformed poses (verified to fail if the spatial index is left stale), that the empty and identity cases are no-ops, and that the id-keyed lookup survives.
Merge branch ‘develop’ into feat/map-frame-gauge-change
Support re-expressing estimator and pose-list state in a new frame Adds the two pieces a one-off gauge change of the map frame needs, so that leveling the frame once gravity is known does not have to throw state away: - NavStateFilter::transform_frame(), an optional virtual returning false by default, so existing estimators are unaffected and a caller that gets false falls back to reset(). Guarded by a feature macro for downstream detection. - SearchablePoseList::transform_left_multiply(), so keyframe-density bookkeeping moves with the frame instead of being invalidated by it. Both are pure left-multiplications, p -> b + p. Note that relative motion, and hence any velocity expressed in the vehicle’s own frame, is invariant under this and must NOT be rotated.
Contributors: Jose Luis Blanco-Claraco
3.1.1 (2026-08-10)
Fix C++20 build: keep TransformTree/TransformTreeNode aggregates by dropping their defaulted default constructors, which made brace initialization stop compiling on ROS 2 Lyrical (C++20).
Contributors: Jose Luis Blanco-Claraco
3.1.0 (2026-08-06)
Add mola::TransformTreeSource: expose the /tf tree to other MOLA modules (#188) * Add mola::TransformTreeSource: expose the /tf tree to other modules New mola_kernel interface letting a data source publish its tree of coordinate frames, so consumers (e.g. a LiDAR-odometry viewer) can draw a robot’s joints as it moves. transform_tree(root) returns the subtree below ‘root’ with poses already resolved against it. The filtering is done in the source, which is what owns the transform buffer, so a consumer never receives nor walks unrelated subtrees. The interface carries no ROS/tf2 type, keeping mola_kernel ROS-independent. Implemented by Rosbag1Dataset (separate repo), Rosbag2Dataset and BridgeROS2. No locking is added around the subtree walk: tf2::BufferCore guards its own internals, which is also what lets BridgeROS2’s TransformListener feed the buffer from its own thread. * Address review: depth-first comment, cycle guard in the tf walk * No need for include guards inside this same git repo
fix formatting
mola_kernel: don’t flood ERROR logs when GUI preview has no viz module A launch YAML can populate gui_preview_sensors for a sensor without gating that entry behind MOLA_WITH_GUI (several mola_lidar_odometry launch files did exactly this). In that case every observation for that sensor label enqueued a task that threw and caught “Could not find a running MolaViz module” – thousands of ERROR-level log lines per headless run, found via SLAM quality-eval sweeps producing 20k+ of them on a single KITTI sequence. Check once, outside the per-observation lambda, whether a VizInterface is actually running; if not, log a single throttled warning and skip enqueueing entirely instead of relying on every launch file getting its own MOLA_WITH_GUI gate right.
Merge pull request #187 from MOLAorg/feat/incremental-point-cloud-kdtree-bake Bake IncrementalPointCloud’s k-d tree index (mm-ipc-bake-kdtree)
changelog
fix: mola_kernel listed mrpt::gui as dependency but could be removed
Merge pull request #185 from MOLAorg/chore/remove-keyframe-map-capable Remove the KeyframeMapCapable interface
chore: remove the KeyframeMapCapable interface This mixin was introduced to expose per-KF pose plumbing to mola_lidar_odometry’s trajectory-rebake experiment, which corrected accumulated tilt by re-integrating the keyframe chain. That experiment is being removed: it was never wired in, and rotating map keyframes without transforming the trajectory consistently leaks vertical position. The interface had exactly one implementation and no callers, so it is removed along with the two methods that existed only for the rebake path, oldestActiveKeyframeID() and applyPivotTransform(). keyframePoses() is kept, since the regroup tests already use it as ordinary map API, and the duplicate cloneKFPoses() (whose only difference was not being the virtual one) is folded into it.
Merge pull request #183 from MOLAorg/feat/child-loggers-console-hook Let a module expose child loggers for console capture
feat(kernel): let a module expose child loggers for console capture ExecutableBase gains child_loggers(), an optional hook returning additional mrpt::system::COutputLogger instances a module owns but does not log through itself (e.g. a library engine run on its own background thread). mola_viz_imgui’s console window now discovers and hooks these the same way it already does for the module itself, tagged with a “module/child” source name, so their output is captured without the owning module having to relay each message through its own logger (which would otherwise re-apply the module’s own verbosity gating). Motivated by mola_mapper’s background loop-closure engine (mola_sm_loop_closure), which has its own independent logger whose output was previously invisible to the imgui console.
Merge pull request #180 from MOLAorg/feat/combobox-fixed-width GUI: add optional fixed_width to ComboBox (both backends)
Add optional fixed_width to ComboBox, honored by both GUI backends Without it, ImGui::Combo defaults to an item width that scales with the window, so short option lists visibly balloon in wide sub-windows (seen when packing a ComboBox next to a checkbox in a Row). 0 keeps each backend’s current auto-sizing behavior.
Contributors: Jose Luis Blanco-Claraco
fix: removed unused mrpt::gui dependency and the unused KeyframeMapCapable interface (dead code from an abandoned trajectory-rebake experiment).
feat(kernel): added child_loggers() hook to ExecutableBase so modules can expose background-thread loggers for console capture.
feat: ComboBox GUI widget gained an optional fixed_width parameter (both backends).
Contributors: Jose Luis Blanco-Claraco
3.0.0 (2026-07-17)
fix: default-dock Dataset_UI panel at top; fix Console dock on old layouts Add WindowDescription::dock_top_by_default so a window without a saved imgui.ini entry gets docked into a strip reserved at the top of the main window instead of floating; enabled for the per-module Dataset_UI panel. Also make the Console’s default bottom-dock (and the new top-dock) key off whether that specific window has a saved imgui.ini entry, instead of whether the whole ini file already existed. This fixes both never docking new window kinds added to an already-existing layout, and splitting a stale, no-longer-leaf dock node once more than one default dock has been applied.
fix: avoid enque on shutdown
Merge branch ‘feat/imviz-metric-plots’ into develop
Remove deprecated nanogui-specific VizInterface API create_subwindow(), enqueue_custom_nanogui_code(), subwindow_grid_layout() and subwindow_move_resize() have no remaining callers now that create_subwindow_from_description() and enqueue_custom_gui_code() cover their use cases on both backends.
Merge pull request #172 from MOLAorg/feat/imviz-metric-plots feat(mola_viz_imgui): add metric time-series plot windows
feat(mola_viz_imgui): add metric time-series plot windows Adds a backend-agnostic register_metric()/push_metric() API to VizInterface (guarded by MOLA_KERNEL_VIZ_HAS_METRICS) so any MOLA module can stream timestamped scalar values to live, autoscrolling plot windows opened from a new “Plots” menu in the mola_viz_imgui (ImGui/ImPlot) backend. The nanogui MolaViz backend implements the API as a no-op, mirroring the set_menu_bar precedent. The Plots menu also gives the Console window its first working close/reopen toggle. Vendors ImPlot as a submodule under mola_viz_imgui/3rdparty/implot.
NavStateFilter: introduce optional virtual georef setter/getter
Merge pull request #165 from MOLAorg/imgui-window-icon feat: mola viz imgui set window icon
feat: mola viz imgui set window icon
Merge pull request #163 from MOLAorg/fix/race-conditions fix(mola_kernel): guard RawDataSourceBase consumer list against concu…
fix(mola_kernel): guard RawDataSourceBase consumer list against concurrent attach mola_launcher initializes modules in parallel threads (executor_thread), so when two consumers subscribe to the SAME raw_data_source (e.g. both LidarOdometry and a mapper module use raw_data_source: dataset_input), both call attachToDataConsumer() concurrently and race on the unsynchronized std::vector<RawDataConsumer*> push_back. This corrupted the heap and caused an intermittent SIGSEGV at startup (caught via coredump: _M_realloc_insert into a garbage pointer under RawDataSourceBase::attachToDataConsumer <- FrontEndBase:: initialize <- MolaLauncherApp::executor_thread). Add a mutex guarding rdc_: lock the push_back, and snapshot the list under the lock in sendObservationsToFrontEnds() before dispatching (dispatch itself runs without the lock so onNewObservation() is not serialized). Validated: 16/16 SharedMapOnly startups on MulRan DCC01 with two consumers, 0 crashes / 0 cores.
Merge pull request #162 from MOLAorg/feat/viz-decay-lookat-frame-aware feat: frame-aware parentFrame for decay clouds and camera look-at
fix: decay eviction uses per-entry container; look-at fails on missing frame Four reviewer findings, all confirmed valid: 1. VizInterface.h comment: add update_viewport_look_at() to the list of APIs covered by MOLA_KERNEL_VIZ_HAS_MOVABLE_FRAMES (it was omitted). 2/3. Decay cloud eviction (both backends): the eviction path inside insert_point_cloud_with_decay() was removing the oldest cloud from the current insertion’s container rather than the container that cloud was originally placed in. If parentFrame ever changes between calls the wrong container would be used, leaking the cloud in the scene. Fix: add a container member to DecayingCloud and store the owning container at insert time; use it at eviction time. 4/5. Look-at frame not found (both backends): when parentFrame is non-empty but the frame node does not yet exist in the scene, the code was silently falling back to treating the raw local-frame coordinates as world-space and moving the camera to the wrong position. Fix: return false so the camera is not moved until the frame node is present.
feat: extend VizInterface for frame-aware decay clouds and camera look-at insert_point_cloud_with_decay() and update_viewport_look_at() now both accept an optional parentFrame argument (same semantics as the existing parentFrame on update_3d_object()): when non-empty, the backend looks up the named movable frame node and composes its current scene pose with the supplied point before inserting the cloud / moving the camera. This lets callers (e.g. mola_lidar_odometry) pass a local-odom-frame point while the camera and transient clouds still end up at the correct world-space position when a central mapper (mola_mapper_3d) is continuously repositioning the frame node. Both backends (MolaViz / MolaVizImGuiCore) and the MolaVizImGui forwarder are updated. The MOLA_KERNEL_VIZ_HAS_MOVABLE_FRAMES feature macro already covers both new parameters; no additional macro is added.
Merge pull request #160 from MOLAorg/feat/viz-with-movable-frames feat: viz with movable frames
feat: viz with movable frames
Merge pull request #159 from MOLAorg/feat/central-map feat: Add virtual interface for central keyframe map for mapper-3d
feat: Add virtual interface for central keyframe map for mapper-3d
Merge pull request #151 from MOLAorg/fix/imgui-slider fix: imgui slider
fix: imgui slider
Contributors: Jose Luis Blanco-Claraco
2.9.0 (2026-05-11)
Merge pull request #143 from MOLAorg/bump-cmake-version bump min req cmake version to 3.22
bump min req cmake version to 3.22
Merge pull request #142 from MOLAorg/feat/add-keyframe-map-capable-api feat: Add keyframe map capable API
feat: Add keyframe map capable API
kernel: utils RegexCache made thread-safe
Contributors: Jose Luis Blanco-Claraco
2.8.0 (2026-04-29)
Merge branch ‘Zeal-Robotics-fix/map-source-latched-replay’ into develop
chore: transient callbacks done with a copy of last updates
fix(mola_kernel): replay latched MapUpdates to late subscribers MapSourceBase::subscribeToMapUpdates() now caches the most recent MapUpdate per map_name whenever it was advertised with keep_last_one_only=true, and replays it once into any callback registered later. This mirrors ROS’ transient_local durability at the MOLA-callback layer. Without this, a producer that advertises its initial map before a consumer has had a chance to subscribe (e.g. mola_lidar_odometry publishing the loaded .mm on its first scan, before mola_bridge_ros2::doLookForNewMolaSubs() has run for the first time) would silently lose that update. The race is more likely with small maps, where odometry initialization is fast enough to beat the bridge’s first sub-discovery poll. With this change the late subscriber receives the cached update on registration, and the ROS publisher created by the bridge then carries the map onward via its existing transient_local QoS. Updates flagged with keep_last_one_only=false (e.g. deskewed scans) are intentionally not cached, matching their fire-and-forget semantics.
Contributors: Jose Luis Blanco-Claraco, Robin Van Cauwenbergh
2.7.0 (2026-04-22)
Merge pull request #129 from MOLAorg/feat/ros2-diagnostics Feature: ROS2 diagnostics
feat(kernel): add DiagnosticsProvider interface for REP-107 diagnostics Introduce an opt-in mix-in interface for modules to publish structured, severity-tagged diagnostics, to be bridged to ROS 2 /diagnostics by mola_bridge_ros2 in a follow-up. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Merge pull request #121 from MOLAorg/fix/clean-up-old-mrpt-version-checks Clean up: remove old mrpt version fallback code sections
Bump minimum required MRPT version to 2.15.0
Clean up: remove old mrpt version fallback code sections
Contributors: Jose Luis Blanco-Claraco
2.6.1 (2026-04-02)
Merge pull request #116 from MOLAorg/update-rds-gui Update RDS gui creation to new backend agnostic API
RDS: Fix parsing initial window pos and width
Update RDS gui creation to new backend agnostic API
Contributors: Jose Luis Blanco-Claraco
2.6.0 (2026-03-12)
Merge pull request #113 from MOLAorg/feat/kf-map-view-vectors Feat:kf map view vectors filter for NN search
comments formatting
Merge pull request #109 from MOLAorg/feat/support-imgui Feature: GUI backend agnostic API in mola_kernel (Step towards supporting imgui)
safer multithread
Several visual and safety fixes in the new GUI interface
Add support for menu bars
VizInterface made backend agnostic (ImGUI and Nanogui)
Merge pull request #108 from MOLAorg/feat/use-gps-msgs Support gps_msgs data types too for ROS2
Support gps_msgs as alternative to NavSatFix
Merge pull request #107 from MOLAorg/fix/viz-decay-clouds Fix/viz-decay-clouds
fix typo in comments
Update coyright notes
fix clang-tidy warnings
Contributors: Jose Luis Blanco-Claraco
2.5.0 (2026-02-14)
Merge pull request #104 from MOLAorg/feat/better-regex Explain error on bad regex
Explain error on bad regex
Merge pull request #103 from MOLAorg/feat/RegexCache Add utility RegexCache
Add utility RegexCache
Add has_converged_localization() method for state estimation
Merge pull request #100 from MOLAorg/fix/remove-mrpt-deprecated-maps Remove use of mrpt deprecated maps
Avoid use of deprecated mrpt::maps classes
Merge pull request #99 from MOLAorg/feat/ros2-bridge-pub-geographic ROS2 bridge: publish geographic poses too
ros2 bridge: use geographic_msgs, store the last georeference info internally, and publish georef poses merge of these commits: - Enable many more clang-tidy checks - lint clean - implement publishing georeferenced poses - mola-viz: fix potential crash on edge case with all points having NaN value - FIX: potential crash if no MapServer is present and map services are called
Contributors: Jose Luis Blanco-Claraco
2.4.0 (2025-12-28)
2.3.0 (2025-12-15)
2.2.1 (2025-11-08)
2.2.0 (2025-10-28)
2.1.0 (2025-10-20)
Send sensor_rate_decimation to Viz
interfaces/MapSourceBase: Add keep_last_one_only property
Make use of ConstPtr across API
Contributors: Jose Luis Blanco-Claraco
2.0.0 (2025-10-13)
Merge pull request #93 from MOLAorg/feature/better-lio Changes for new LIO
MolaViz: Add method clear_all_point_clouds_with_decay()
MolaViz: Add support for inserting clouds with decay_time
Large clean up of unused code from older MOLA versions. In particular, all abstract definitions of factors, entities, and WorldModel have been removed. It seems more natural and efficient to keep them in the specific SLAM modules.
Allow extra parameters in mola_viz per-sensor preview windows
fix clang-format
Modernize copyright notice
Remove old code that was needed to support very old MRPT versions
Contributors: Jose Luis Blanco-Claraco
1.9.1 (2025-07-07)
1.9.0 (2025-06-06)
MapSourceBase: add a new optional field “metadata”
NavStateFilter interface: Now is a RawDataConsumer too
Contributors: Jose Luis Blanco-Claraco
1.8.1 (2025-05-28)
1.8.0 (2025-05-25)
Update Viz interface: add methods to run arbitrary Scene manipulation and camera orthographic mode
Update copyright year
fix reversed logic
clang-format fix
Add mola::Synchronizer for grouping observations
Contributors: Jose Luis Blanco-Claraco
1.7.0 (2025-05-06)
code clean up: remove useless dtors, and mark the required copy ctors as deleted
Contributors: Jose Luis Blanco-Claraco
1.6.4 (2025-04-23)
fix: Correctly handling Livox cloud timestamps (“double”s, but in nanoseconds) in BridgeROS2 and bag2 data sources. They are automatically detected, no need to change any parameter.
modernize clang-format
Contributors: Jose Luis Blanco-Claraco
1.6.3 (2025-03-15)
1.6.2 (2025-02-22)
ExecutableBase inteface: added diagnostics API
Contributors: Jose Luis Blanco Claraco
1.6.1 (2025-02-13)
mola_kernel: Add Georeferencing structure and add it to map updates
Contributors: Jose Luis Blanco-Claraco
1.6.0 (2025-01-21)
Fix published /tf’s: those from LocalizationSources now can explicitly define their parent and child frames
LocalizationSources now can explicitly define both, their reference and child frames for each estimated pose
docs: add state estimation images
Contributors: Jose Luis Blanco-Claraco
1.5.1 (2024-12-29)
NavStateFilter API: add estimated_trajectory()
Contributors: Jose Luis Blanco-Claraco
1.5.0 (2024-12-26)
NavStateFilter Interface now also inherits from ExecutableBase for convenience
MinimalModuleContainer ctor should not be explicit
Add mola::MinimalModuleContainer
Drop dependency on mrpt-gui in kernel by abstracting MolaViz subwindow layout operations
Contributors: Jose Luis Blanco-Claraco
1.4.1 (2024-12-20)
1.4.0 (2024-12-18)
MOLA system yaml files: added “enabled” optional property for modules and rds visualizers
Add field for localization quality
cmake: remove duplicated info message
ExecutableBase: Add support for runtime-configurable parameter API
mola-kernel Doxygen docs: add groups
Contributors: Jose Luis Blanco-Claraco
1.3.0 (2024-12-11)
NavStateFilter interface: add API for merging GNSS observations
Contributors: Jose Luis Blanco-Claraco
1.2.1 (2024-09-29)
1.2.0 (2024-09-16)
Update RTTI macros for upcoming MRPT 2.14.0
Contributors: Jose Luis Blanco-Claraco
1.1.3 (2024-08-28)
Depend on new mrpt_lib packages (deprecate mrpt2)
Contributors: Jose Luis Blanco-Claraco
1.1.2 (2024-08-26)
1.1.1 (2024-08-23)
1.1.0 (2024-08-18)
add <mola_kernel/version.h> with a version-checking macro
Merge pull request #65 from MOLAorg/add-more-srvs Add more Services
Avoid cmake file glob expressions
mola_kernel: add MapServer interface
mola_kernel: add public symbols MOLA_{MAJOR,MINOR,PATCH}_VERSION
Update clang-format style; add reformat bash script
Merge pull request #62 from MOLAorg/docs-fixes Docs fixes
Fix ament_xmllint warnings in package.xml
Contributors: Jose Luis Blanco-Claraco
1.0.8 (2024-07-29)
mola_kernel: add C++ virtual interface for relocalization methods
ament_lint_cmake: clean warnings
Contributors: Jose Luis Blanco-Claraco
1.0.7 (2024-07-24)
Viz interface: add API for rotate camera
Contributors: Jose Luis Blanco-Claraco
1.0.6 (2024-06-21)
Create new NavStateFilter interface and separate the simple fuser and the factor-graph approach in two packages
mola_kernel: renamed factor FactorConstVelKinematics
Contributors: Jose Luis Blanco-Claraco
1.0.5 (2024-05-28)
viz: fix mismatched free/delete inside nanogui layout
Contributors: Jose Luis Blanco-Claraco
1.0.4 (2024-05-14)
bump cmake_minimum_required to 3.5
Avoid global static objects
remove useless #include’s
Define Dataset_UI dtor/ctor in a separate translation unit
Contributors: Jose Luis Blanco-Claraco
1.0.3 (2024-04-22)
Fix package.xml website URL
Contributors: Jose Luis Blanco-Claraco
1.0.2 (2024-04-04)
1.0.1 (2024-03-28)
Remove now-useless build dependencies and includes for mola-kernel
Contributors: Jose Luis Blanco-Claraco
1.0.0 (2024-03-19)
add methods to query for subscribers
New interfaces
Refactor initialize()
mola_kernel: new UI interface for datasets
New option to shutdown automatically mola-cli after dataset ends
viz API: add enqueue_custom_nanogui_code()
mola_viz: show console messages
Correct usage of mola:: namespace in cmake targets
copyright update
mola_viz: support visualizing velodyne observations
Add look_at() viz interface
Fewer mutex locking()
dont force by default load() lazy-load observations
FrontEndBase: attach to VizInterface too
Fix loss of yaml key/values when using import-from-file feature
kitti eval cli moves to its own package
port to mrpt::lockHelper()
reorganize as monorepo
Contributors: Jose Luis Blanco-Claraco
0.2.2 (2023-09-08)
Correct references to the license.
viz interface: new service update_3d_object()
Fix const-correctness of observations
FIX missing dependency on mrpt::gui for public header
Contributors: Jose Luis Blanco-Claraco
0.2.1 (2023-09-02)
Add virtual interface for dataset groundtruth
Update copyright date
Update to new colcon ROS2 build system
Contributors: Jose Luis Blanco-Claraco
Changelog for package mola_lidar_odometry
3.2.0 (2026-08-21)
Offline CLI Enhancements: Made the offline CLI state estimator deterministic by default, added run totals at shutdown, and exposed range-adaptive matcher thresholds.
Offline CLI Linking Fix: Resolved runtime crashes in the offline CLI by correctly linking mola_state_estimation_smoother and its GTSAM dependencies.
Wheel Odometry Support: Wired optional wheel odometry (MOLA_ODOMETRY_TOPIC) into the offline rosbag1 CLI path and corrected related documentation.
Robust Observation Radius: Introduced observation_radius_quantile to prevent single stray far returns from skewing the scale, while keeping the default max-norm path bit-identical.
GICP Tuning & Profiles: Moved tuned GICP defaults (coarse-voxel sizes, IMU deskew) out of global configurations and into per-dataset profiles (KITTI, Oxford) to prevent regressions on untested datasets.
New Matching Pipelines: Added lidar3d-ndt-blend.yaml, lidar3d-fastlio-matching.yaml, and lidar3d-icp-blend.yaml to support matching protocol studies.
KITTI Profile Updates: Configured the KITTI profile to use the more accurate point-to-point pipeline (lidar3d-icp.yaml) and documented the logic behind its velocity prior settings.
BotanicGarden Profile Updates: Switched the profile to IncrementalPointCloud for better mean APE, but reverted experimental deskew/decimation overrides that didn’t confidently improve results.
Dataset Profile Consolidation: Unified dataset configurations (topics, extrinsics, layouts) into single shared scripts utilized by both GUI and offline CLI tools.
CitrusFarm Multi-part Bags: Updated launch and GUI scripts to properly accept and route multi-part base_*.bag sequences.
ICP Threshold Adjustment: Raised the ICP adaptive threshold min_motion from 0.04 to 0.5 to prevent correspondence search windows from collapsing.
Voxel Decimation Splitting: Allowed each decimation stage to use its own voxel size for better short-range precision and long-range drift reduction, and exposed the decimation method via environment variables.
Observation Layer Bug Fix: Added a step to clear the observation layer in lidar3d-gicp before filling it to prevent crashes when optimize_twist is enabled.
Eviction Cube Widened: Increased the default IncrementalPointCloud eviction cube size in lidar3d-gicp.yaml to retain more in-range points.
New Environment Overrides: Exposed environment variables for the solver’s inner iteration count, initial twist uncertainties, and MOLA_INITIAL_VX overrides.
Reverted Dead Parameters: Removed the freezePairingsAfterIteration parameter exposure after discovering it does not actually exist in the released mp2p_icp library.
Dependency Fix: Added a missing execution dependency for mola_viz_imgui.
Contributors: Jose Luis Blanco-Claraco, SamueleSandrini
3.1.0 (2026-08-06)
fix: keep the local-map render and the IMU worker off the LiDAR critical path (#126)
Moves the local-map render off the LiDAR thread onto its own worker, and introduces a dedicated
imu_state_mtx_so the IMU handler no longer serializes behind every LiDAR scan viastate_mtx_. The render worker now deep-copies the map layers under the map mutex and does the expensive recolorize/OpenGL build on that private copy, unlocked. On Oxford Spires/GrandTour benchmarks this cutonLidarmax latency roughly in half (up to ~216 ms -> ~107 ms) and the IMU thread’s total blocked time by more than half, eliminating the scan-queue backlog. Also exposesmap_update_decimationasMOLA_GUI_MAP_UPDATE_DECIMATION.Visualize the robot /tf tree in the LO viewer (opt-in) (#125)
Draws the subtree of coordinate frames below a configurable root frame as the robot moves (e.g. a legged robot’s joint tree), via the new
mola::TransformTreeSource. Supports excluding frames/subtrees (tf_tree_exclude_frames), is toggled live from the GUI’s View tab, and is enabled by default for the GrandTour dataset with its non-body frames excluded.Add mola-lo-gui-grandtour launch script for the GrandTour dataset (#124)
GrandTour publishes one ROS1 bag per topic, so
lidar_odometry_from_rosbag1.yamlnow accepts up to three bags replayed jointly. The wrapper locates sibling bags from a mission directory and uses the dataset’s own/tf_staticfor sensor extrinsics.Gate
gui_preview_sensorsentries behindMOLA_WITH_GUIconsistently across all launch YAMLs, removing noisy “no running MolaViz module” warnings in headless CI runs. Also adds theMOLA_WITH_GUIheadless toggle to the remainingmola-clilaunch files.Launch scripts for the citrus farm dataset; conslam dataset now also accepts ROS2 bags.
CLI: reduce/disable the batch progress bar; port CLI argument parsing from mrpt-tclap to CLI11 (#123)
Adds
--progress-bar-periodto control per-scan progress logging (useful for Jenkins batch runs), and replaces the legacy TCLAP parser with CLI11, preserving all existing flags/defaults while fixing several--help/docs discrepancies along the way.CI: don’t let
rosdepfailures on unresolvable packages abort the job before the build/test steps run;mola-lidar-odometry-cligains--input-rosbag1support (#122) and now accepts a comma-separated bag list for multi-part recordings.Add
lidar3d-gicp-single-filter.yaml: one decimation filter feeding both map and ICP layers instead of two chained ones (#121), plus a DLIO-like pipeline, VoxelAverage/forward-alone decimation-axis variants, and map-policy leave-one-out/decimation-method ablation pipelines from the 809 investigation.Add
log_onlymode for the map-gravity estimator (validate against ground truth without feeding back into the map frame) and retry the one-shot accelerometer verticality capture on later scans instead of giving up permanently.fix: deadlock rendering the local map without owning
state_mtx_, and a related potential deadlock for large maps under the incremental map class (#120). Declaremola_yamlas an explicit dependency (#109).Estimate the map-frame gravity direction online, default off (#116)
The verticality reference used by the ICP gravity prior was captured once from a single 50 ms accelerometer average and never updated, biasing the map frame by up to several degrees. Wires in
mola::imu::MapGravityEstimator, which continuously solves for gravity in the map frame from preintegrated IMU and the odometry’s own relative attitudes/velocities, and uses it as the prior’sup_mapreference. The one-shot rigid re-levelling half of this feature was found unsafe on some sequences and deferred to a separate experimental branch.Add option to hide the current-pose XYZ corner OpenGL object (#117); expose the max-range filter as
MOLA_MAXIMUM_RANGE_FILTERand add a hybrid cov-to-cov/point-to-point reference pipeline.fix: silently-ignored IMU label filter in
state-estimation-simple.yaml(wrong YAML key), yaw-free rank-2 gravity constraint with self-silencing sigma for the ICP solver, removal of the unused trajectory-rebake research scaffold, and a CI fix so one broken distro no longer cancels the sibling x86_64 jobs (#112, #114, #113, #115).feat: make the GICP local-map class selectable via
${MOLA_LOCALMAP_CLASS}between the existing keyframe map and the newmola::IncrementalPointCloud(async k-d tree rebuild off the mapping thread) (#111). Expose local-map update time as a plottable metric.fix: ICP prior information matrix used MRPT’s Euler tangent-index ordering instead of the SE(3) Lie tangent mp2p_icp’s solver expects, swapping roll and yaw in the IMU gravity correction and 2D-lidar constraints (#110).
fix: honor
MOLA_WITH_GUIfor headless runs in the MulRan launcher (#108); six launchers were missingraw_data_sourceon the state estimator, silently disabling every IMU-based factor (#107).fix: an ICP debug-file functor was installed unconditionally and took priority over
mp2p_icp’s ownMP2P_ICP_GENERATE_DEBUG_FILESswitch, silently disabling native debug-file generation; now only installed when one of its own triggers is actually configured (#105).Share the keyframe-creation policy between the local map and the simplemap, and let it optionally consider a time window instead of pure spatial distance, so revisiting an already-mapped area can still spawn the keyframes loop closure needs (#104).
feat: add
mola-lo-gui-oxford-spireshelper for the Oxford Spires dataset (multi-part rosbag2 stitching, calibration-derived extrinsics) (#103); addmola-lo-gui-conslam/mola-lo-gui-botanicgardenhelpers with the smoother state estimator enabled; exposecamera_follows_vehicleand a--headless/--no-guiflag.feat(launch): make the localization
/tfpublish source overridable (localization_publish_tf_source), enablingmap->odomto be published directly from the state-estimation smoother instead of being composed by the bridge from a mismatched-timestamp odom lookup (#102).Contributors: Jose Luis Blanco-Claraco
3.0.0 (2026-07-17)
Merge pull request #101 from MOLAorg/fix/relocalize-tf-source-and-sigma-recovery fix: two bugs blocking GNSS+IMU relocalization (FromStateEstimator)
fix: MOLA_LOCALIZATION_PUBLISH_TF_SOURCE used the wrong module-name string
fix: maximum_sigma default equal to initial_sigma made sustained-failure recovery a no-op
Remove dead mrpt/gui included
fix: enable adaptive-threshold recovery by default; add initial_pose launch arg
fix: show sensible errors if in localization only but there’s no local map
feat: map freeze after relocalization (#100)
fix: drop stale LiDAR scans and keep the freshest under overload (#99)
feat: export as plot data the complete onLidar CPU time
fix: don’t process/insert a scan into the map before initial localization converges
fix: don’t discard a preexisting map on IMU releveling or bad-first-ICP restart
Merge pull request #98 from MOLAorg/feature/imu-leveling-preserve-xyzyaw fix: preserve x/y/z/yaw prior in InitLocalization::PitchAndRollFromIMU
Merge pull request #97 from MOLAorg/feature/imu-bag-recv-timestamp-env-var Wire MOLA_IMU_USE_BAG_RECV_TIME env var for IMU bag-recv-time timestamp override
fix: preserve x/y/z/yaw prior in InitLocalization::PitchAndRollFromIMU
lidar_odometry_from_rosbag2.yaml: wire MOLA_IMU_USE_BAG_RECV_TIME env var
debug: add env-gated ICP quality/adaptive-threshold trace
Merge pull request #95 from MOLAorg/feat/shared-keyframe-velocity-metadata Carry per-keyframe velocity metadata in shared-keyframe push
refactor: remove dead pushKeyframeToSharedKeyframeMap helper
feat: carry per-keyframe velocity metadata in shared-keyframe push
Merge pull request #94 from MOLAorg/feat/icp-metric-plots
feat: stream ICP time/goodness to mola_viz_imgui plot windows
Merge pull request #93 from MOLAorg/feat/expose-approximate-cov-env-var
feat: expose KeyframePointCloudMap’s approximate_cov as MOLA_LOCALMAP_APPROXIMATE_COV
docs: show ImGui as the new default
feat: expose new simple estimator GNSS fuse params
feat: pass georef to state estimator, if compatible
feat: expose color changing as public API
launch: default viz module to MolaVizImGui with per-app imgui_app_name Sets a unique imgui_app_name in each launch file so Dear ImGui’s layout persistence stores a separate UI configuration per app.
fix: uncheck show trajectory never cleared old viz
Merge pull request #92 from MOLAorg/feat/viz-decay-lookat-frame-aware feat: frame-aware decay clouds and camera look-at for mapper_3d
feat: frame-aware decay clouds and camera look-at for mapper_3d
Merge pull request #91 from MOLAorg/feat/use-viz-with-movable-frames
feat: viz with movable frames
Merge pull request #90 from MOLAorg/feat/push-to-central-map feat: push KFs to central map server
Merge pull request #89 from MOLAorg/fix/imu-grav-align fix: bugs in gravity-alignment from IMU accelerometer
Merge pull request #88 from MOLAorg/feat/delayed-map-load feat: add delayed map load option
Merge pull request #87 from MOLAorg/fix/state-mtx-non-recursive refactor: convert state_mtx_ from recursive_mutex to plain mutex
Merge pull request #86 from MOLAorg/fix/lidar-odometry-shutdown-order-segfault fix: avoid use-after-free during shutdown via LidarOdometry::onQuit()
Merge pull request #85 from MOLAorg/feat/ros2-launch-tf-no-ns-option
feat: add new ros2 launch argument to optionally disable /tf NS remappings
Merge pull request #84 from MOLAorg/feat/simpler-adaptive-sigma feat: simplify adaptive sigma algorithm
chore: put all yaml files in sync re adaptive parameters
feat: simplify adaptive sigma algorithm
docs: explain how to select the viz module
Merge pull request #83 from MOLAorg/feat/ros1-input
feat: Add ros1 bag input helper scripts
Contributors: Jose Luis Blanco-Claraco
2.2.1 (2026-06-04)
simple state estimator: MOLA_NAVSTATE_VELOCITY_FILTER is now true by default
ci: fix Jazzy Jalisco EOL date in CI workflow comment (May 2024 - May 2029)
ci: scope arm64 apt-cacher-ng proxy to apt only (fix xmllint test) (#82)
chore: add profiler to unit tests
ci: add tests run in self-hosted
fix self-runner label
CI: add self hosted runner jobs too
feat: selective disabling each of the imgui tabs
gicp yaml: expose more viz params and the new velocity filter param
docs: sync pipeline variables from actual yaml
Merge pull request #81 from MOLAorg/clean-gui-code GUI: clear dead code and reorganize ImGui tabs
fix: multithread issues
gui: split in 3 tabs when in imgui mode
chore: remove dead code for mola<2.6.0 compatibility
Merge pull request #80 from MOLAorg/more-robust-multi-sensor More robust multi sensor
fix: gracefully handle missing scans in multi-lidar settings
chore: add warning if dropped lidar scans in multi-sensor mode
chore: add debug-level traces for multi-lidar settings
Contributors: Jose Luis Blanco-Claraco
2.2.0 (2026-05-11)
fix: don’t exit upon state estimator lack of convergence
Merge pull request #79 from MOLAorg/simplify-ci CI: simplify clang-format helpers and use ros: docker image for jazzy stable
CI: simplify clang-format helpers and use ros: docker image for jazzy stable - Replace the old formatter.sh with a new version supporting –check mode - Simplify check-clang-format.yml to just apt-install clang-format-14 and run the script - Use ros:jazzy pre-built image for jazzy stable CI build (faster, no setup-ros needed)
Update error threshold in lidar odometry test
fix: do not wipe out a loaded map if first scan is bad
fix: viz must clear current obs when unchecked live
fix: safer thread viz with just one thread
chore: set default for adaptive threshold ‘alpha’ low-pass filter 0.99 to 0.90 for adapting faster to changes
feat: show sensor pose corners in MolaViz
chore: fix comment formatting (seems to trigger a libfyaml/mola_yaml parser bug)
fix: initial pose from yaml files expected yaw/pitch/roll in degrees
Expose initial sigma as env var too
chore: expose viz module as env var (prepare for testing imgui)
CI: sensible job names
Merge pull request #78 from MOLAorg/bump-cmake-version bump min req cmake version to 3.22
bump min req cmake version to 3.22
FIX: regression in last adaptive sigma PR
chore: add minimal agents.md
Merge pull request #76 from Zeal-Robotics/feat/sustained-failure-recovery feat: optional adaptive-threshold recovery on sustained ICP failure
feat: optional adaptive-threshold recovery on sustained ICP failure The KISS-ICP adaptive threshold only updates sigma on a good ICP, which is correct for isolated bad scans but creates a deadlock under sustained failure: once sigma is frozen at a small value, the matcher window (2*sigma) is too tight to find correspondences, ICP stays bad, sigma stays frozen, and the system cannot recover without an external relocalize. Add three opt-in fields to AdaptiveThreshold: recover_on_sustained_failure (default false) recover_after_n_bad (default 5) recover_growth_factor (default 1.5) After N consecutive bad ICPs, sigma is grown multiplicatively (capped at maximum_sigma) so the next attempt has a wider correspondence search radius. The counter resets on any good ICP, at which point the standard KISS-ICP rule resumes and re-tightens sigma. With the flag off, behavior is identical to before. The four bundled pipeline YAMLs (lidar3d-gicp, -gicp-optimize-twist, -icp, -ndt) gain matching ${MOLA_ADAPT_THRESHOLD_RECOVER*|default} hooks so the feature can be toggled via env vars without forking the YAML.
Fix CI escaping
fix: CI code coverage flags
feat: Add new mola-lo-gui-ouster script
Update build-ros.yml to disable known regression in current stable Humble Comment out the configuration for non-testing ROS build.
Merge pull request #75 from Zeal-Robotics/fix/cli-warn-no-state-estimator-yaml fix(cli): warn when no –state-estimator-param-file is provided
fix(cli): warn when no –state-estimator-param-file is provided When mola-lidar-odometry-cli is invoked without –state-estimator-param-file, the state estimator is constructed but initialize() is never called, so it silently runs with the built-in C++ defaults. These differ from the bundled state-estimator-params/*.yaml shipped with this package and used by the corresponding mola-cli-launchs/*.yaml files, which makes the CLI and the GUI launcher behave noticeably differently for the same estimator. Add an else branch that prints a clear warning naming the active estimator class and pointing at the bundled YAMLs, so users know to pass –state-estimator-param-file (or accept the C++ defaults deliberately). No behaviour change otherwise.
fix: GUI update staled in some conditions
fix: don’t reduce adaptive threshold on bad ICPs
fix: UI text labels never updated if ICP was bad
fix: clearing gravity vector
IMU buffer for gravity alignment: increase max circular buffer size
Merge pull request #62 from MOLAorg/wip/draw-gravity-align-as-arrow Draw arrow from IMU gravity alignment
CI: Fix for new ROS rolling
feat: Optional visualization of IMU gravity alignment vector
tests: show error levels even if test pass
gicp: lower covariance floors
fix: decaying clouds were not cleared if unchecked UI box
icp pipeline yaml: add new covariance selection method params
feat: ros2 launch file new “use-sim-time:=true” argument
feat: Localmap is now also rendered using ‘intensity’ or whatever color channel
docs: clear README
Merge pull request #72 from manankharwar/patch-1 docs: add FusionCore to Related projects
Update README.md
Contributors: Jose Luis Blanco-Claraco, Robin Van Cauwenbergh
2.1.0 (2026-04-29)
FIX: show_localmap was not loaded from YAML file; expose more pipeline env vars
Merge pull request #70 from MOLAorg/feat/multiple-scans-per-volume simple estimator params file: expose all hardcoded values as env vars
simple estimator params file: expose all hardcoded values as env vars
Merge pull request #69 from MOLAorg/feat/multiple-scans-per-volume feat: new option to include multiple scans per space volume
feat: new option to include multiple scans per space volume
feat: Add IMU & LiDAR configurable QoS (requires latest mola_bridge_ros2)
Merge pull request #67 from Zeal-Robotics/fix/pose-timestamp-after-deskew fix: stamp published pose with deskew reference time, not raw obs stamp
fix: stamp published pose with deskew reference time, not raw obs stamp The ICP-derived pose corresponds to the vehicle at t=0 of the deskewed cloud. With the default FilterAdjustTimestamps: MiddleIsZero, t=0 is the middle of the scan, while obs->timestamp (taken from the LiDAR driver header) is the start of the scan. The published LocalizationUpdate.timestamp and the timestamp fed back into navstate_fuse->fuse_pose() were both using obs->timestamp, so downstream consumers (and the internal fuser) saw a pose tagged with a time roughly half a scan period (~50 ms at 10 Hz) before the moment the pose actually holds. The absolute reference time is already tracked inside ParameterSource::localVelocityBuffer.get_reference_zero_time(): - Generator seeds it with obs->timestamp - FilterAdjustTimestamps shifts it by the same offset it applies to per-point timestamps - FilterAbsoluteTimestamp already uses it as the absolute reference for per-point timestamps This commit reads it back after the observation pipeline runs and threads it through every pose-time use site: - ICP initial-guess query (estimated_navstate) - ICP result fusion (fuse_pose) - estimated_trajectory insertion - past_simplemaps_observations keyframe key - Published LocalizationUpdate, map, deskewed-scan, debug-trace timestamps Sensor-cadence uses (rate stats, drop-too-close logic, debug log context, last_obs_timestamp, per-label staleness tracking) keep the raw obs->timestamp since they are about when the observation arrived, not when the pose holds. If FilterAdjustTimestamps is not configured the buffer’s reference equals obs->timestamp and behavior is unchanged. There is a fallback to obs->timestamp for safety if the buffer was never seeded.
Merge pull request #66 from MOLAorg/better-grav-aligner-tests review: address gravity-aligner / rebaker review comments
review: address gravity-aligner / rebaker review comments - Fix stale Doxygen on onNewKeyframe (window param) and computePublishResidual (drop tail_kf_id reference, document unconditional residual contract). - TrajectoryRebaker::rebake: slide anchor forward to lower_bound when no KF >= anchor_id exists, so corrected_poses and reported anchor_id stay consistent. - Remove redundant empty-input guard in two-arg rebake overload. - Replace composePoint+subtraction delta computation with rotateVector in TrajectoryRebaker and the test helper. - Extract kDefaultAxisEps single source of truth used by Params and rotationFromGravity. - Fix sign in test bodyGravity comment (a_body.z = +g*cos), clarify accelerometer convention. - Wire maxGravityErrorDeg into KnownPitchTilt_converges as a sanity check. - Clarify LinearDrift_recoversHorizontalPath comment that R_grav per-KF exactly cancels T_odom.R (scenario justifying the 5cm Z tolerance).
Merge pull request #65 from MOLAorg/feat/better-gravity-align feat: add GravityMapAligner with per-KF IMU pool and robust gravity estimation
fix minimum accelerometer noise
feat: add TrajectoryRebaker for per-KF gravity-aware pose chain re-integration
feat: add GravityMapAligner with per-KF IMU pool and robust gravity estimation New class GravityMapAligner stores one time-averaged body-frame accelerometer sample per keyframe and provides: - estimateGravityVector / estimatePerKFCorrection: IRLS/Huber-robust weighted mean of R_i·a_body_i to estimate gravity direction in the odom frame, with per-window support for the per-KF rebake path. - rotationFromGravity: pitch/roll-only correction (zero yaw by construction) that sends the estimated gravity vector to +Z. - onNewKeyframe / onKeyframeDropped for pool lifecycle management. Unit tests cover: nullopt below threshold, zero-tilt identity correction, 2° pitch convergence (<0.1°), Huber robustness with 20% outlier KFs, pool eviction, yaw-free output, and per-KF windowed estimation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Merge pull request #64 from MOLAorg/fix/more-rational-use-mutexes FIX: More rational use of mutexes and shared opengl objects
FIX: More rational use of mutexes and shared opengl objects
Merge pull request #63 from MOLAorg/fix/deadlock-load-map FIX: potential dead locks/long waits requesting relocalization
FIX: potential dead locks/long waits requesting relocalization
Merge pull request #60 from Zeal-Robotics/fix/sensor-frame-max-range-and-filter-anchors fix(mola_lidar_odometry): anchor ESTIMATED_SENSOR_MAX_RANGE and FilterByRange at the sensor
Rename pipeline _sensor_ names to _observation_radius_, document base_link-anchored deadzone The pipeline variables and YAML param keys historically called _SENSOR_MAX_RANGE / *_sensor_range_ are actually the bounding-radius of the latest observation cloud measured from base_link, not anything sensor-anchored. This caused real-world confusion: users reading the name expected sensor-frame semantics and were puzzled when the canonical FilterByRange deadzone removed points around base_link instead of around the sensor. Rename to make the semantics self-documenting: - Dynamic vars (parameter source): ESTIMATED_SENSOR_MAX_RANGE -> ESTIMATED_OBSERVATION_RADIUS INSTANTANEOUS_SENSOR_MAX_RANGE -> INSTANTANEOUS_OBSERVATION_RADIUS - YAML param keys: max_sensor_range_filter_coefficient -> observation_radius_filter_coefficient absolute_minimum_sensor_range -> absolute_minimum_observation_radius - Mirroring C++ symbol renames in state_, params_, and methods (doInitializeEstimatedObservationRadius etc.). GUI label tweaked. All legacy names remain working as deprecated aliases (dynamic vars are double-published; YAML keys fall back via cfg.getOrDefault). A one-shot warning is emitted at init when the loaded YAML still references any legacy name; aliases can be removed in a future release. The user-facing env var MOLA_ABS_MIN_SENSOR_RANGE is intentionally kept unchanged: the YAML ${VAR|default} substitution is single-pass, so the elegant chained-default pattern doesn’t aliasing it cleanly, and a setenv shim has caveats for callers that load pipelines outside of the canonical entry points. The misnomer survives at the env-var name only; docs already point to the renamed concept. Also clarify in lidar3d-gicp.yaml that the Lu221E cube deadzone is intentionally vehicle-anchored (centered at base_link, not at the sensor) so it covers the vehicle body and a person standing next to the robot regardless of where the sensor is mounted. Users who additionally want a sensor-anchored cut can layer one on via observations_prefilter_file. No behavioral change.
Merge branch ‘Zeal-Robotics-perf/prewarm-icp-search-on-startup’ into develop
perf(initialize): pre-warm ICP search structures for preloaded local maps When the local map is loaded from disk via load_existing_local_map (the multi-session SLAM / localization-only path), each layer that implements mp2p_icp::IcpPrepareCapable defers building its ICP search structures (per-keyframe global-frame cloud materialization, merged submap construction, KD-tree build, …) until the first call to mp2p_icp::ICP::align(). For a non-trivial preloaded map this is seconds of work that blocks the lidar worker on the very first scan, backs the bag-feed up, and freezes the GUI. Move that cost to startup by walking state_.local_map->layers right after load_from_file and calling icp_get_prepared_as_global() on every IcpPrepareCapable layer, using the configured initial pose as the reference point. The total amount of work is unchanged; it just happens alongside load_from_file (where the user already expects a delay) instead of during real-time playback. If the actual first ICP estimate ends up far from the initial pose, the selected sub-keyframe set may be rebuilt then, but the per-keyframe point-cloud and cache data is already materialized so that rebuild is cheap.
Merge pull request #59 from Zeal-Robotics/feat/expose-transform-tolerance-env-vars feat(launch): expose transform_tolerance and transform_publish_period
feat(launch): expose transform_tolerance and transform_publish_period Plumbs the two new BridgeROS2 params through the standard MOLA_ROS2_* env-var convention so they can be overridden from ros2 launch without editing YAML: MOLA_ROS2_TRANSFORM_TOLERANCE default 0.1 MOLA_ROS2_TRANSFORM_PUBLISH_PERIOD default 0.05 (20 Hz; 0 disables) Defaults match BridgeROS2 and the AMCL / slam_toolbox / RTAB-Map convention, so consumers can lookupTransform(map, base_link, now()) without tf2 ExtrapolationException.
Add MOLA_DESKEW_IGNORE_ACCELEROMETER env var
consistent ros2 topic name var MOLA_ODOMETRY_TOPIC for both offline/online
Merge pull request #58 from MOLAorg/feat/ros2-diagnostics Implement new mola_kernel diagnostics API
clang format
diagnostics: use wall-clock reception time for input-data staleness check last_obs_timestamp stores the sensor hardware timestamp which may not be synchronized to system time (GPS-disciplined lidars, unsync’d clocks, etc.). Introduce last_obs_reception_time (set via mrpt::Clock::now() when each scan arrives) and use it for the Input Data stale/error age computation so the check reflects actual data flow rather than sensor-vs-host clock drift. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docs/launch: alphabetical ordering for use_* args; drop spurious tf remap from aggregator - mola_lo_ros_node.rst: move use_diagnostic_aggregator before use_imu_for_lio - launch.py: remove remappings=tf_remaps from diagnostic_aggregator node (it only needs diagnostics topics, not tf) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
diagnostics: fix ICP quality startup false-ERROR, timing period source, and overall scope - ICP Quality: treat as STALE (not ERROR) until state_.last_icp_timestamp is set - Timing: derive sensorPeriod from observed scan interval (last_observed_scan_period_sec) rather than params_.min_time_between_scans throttle threshold - Overall Status: iterate only over entries added by this provider (startIndex..end) so unrelated providers’ diagnostics do not influence the overall level Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
diagnostics: validate threshold ordering in Parameters::Diagnostics::initialize Assert that warn < error for icp_quality, input_stale_sec, and dropped_ratio, and that all values are in their valid ranges, so misconfiguration cannot silently invert severities at runtime. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add optional diagnostic_aggregator launch + sample config Off by default (use_diagnostic_aggregator:=True to enable). Intended for isolated bring-up/demos; in a larger stack a central aggregator should group LidarOdometry statuses instead. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
docs: add REP-107 diagnostics page for MOLA-LO Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Implement new mola_kernel diagnostics API (exported to ROS2 via BridgeROS2)
ros2 launch: improved configuration validator
ros2 launch: Add missing mola_bridge_odometry_frame argument; fix broken behavior
Merge pull request #57 from MOLAorg/feat/clarify-usage-modes docs: clarify usage modes; cli: add /tf selection args
ros2 launch: safe guard against importing duplicated odometry
ros2 launch: add wheels odometry arguments; fix opaque function must come last
docs: clarify usage modes; cli: add /tf selection args
Auto-transition to active mode after state estimator convergence
GUI: Add message when lidar stream starts
Merge pull request #55 from MOLAorg/feat/add-odom-frame-env-var ros2 launch: export MOLA_TF_ESTIMATED_ODOMETRY
ros2 launch: export MOLA_TF_ESTIMATED_ODOMETRY from mola_lo_reference_frame for consistency
Merge pull request #54 from MOLAorg/fix-missing-ros2-launch-base-link BUGFIX: Changing base_link in ros2 launch didn’t propagate to LO
BUGFIX: Changing base_link in ros2 launch didn’t propagate to LO
Merge pull request #45 from MOLAorg/fix/init-from-gps-imu Support initialization from state estimator
Support initialization from state estimator
Contributors: Jose Luis Blanco-Claraco, Robin Van Cauwenbergh
Rename the family of _sensor_ pipeline names that actually meant observation-from-
base_linkto _observation_radius_ /*_OBSERVATION_RADIUSto clarify semantics. The legacy names remain as deprecated aliases so existing pipelines keep working unchanged; a one-shot warning is emitted at init when the loaded YAML still references any legacy name. The aliases will be removed in a future release.Dynamic variables:
ESTIMATED_SENSOR_MAX_RANGE→ESTIMATED_OBSERVATION_RADIUS,INSTANTANEOUS_SENSOR_MAX_RANGE→INSTANTANEOUS_OBSERVATION_RADIUS.YAML param keys:
max_sensor_range_filter_coefficient→observation_radius_filter_coefficient,absolute_minimum_sensor_range→absolute_minimum_observation_radius.
2.0.0 (2026-04-02)
Merge pull request #53 from MOLAorg/feat/use-imu-grav-align Use IMU readings to estimate gravity up vector as ICP prior constraint
Add formal CLA
mola-cli-launch files: apply yaml format
FIX: mola-lidar-odometry-cli now can handle the two types of GPS messages too
gui stats: more robust sensor rate estimation (include gnss now too)
docs: add layer name to pipeline table
gicp pipeline: expose new KF-metric map parameters as optional env vars
ros2 launch: add new argument ‘gpsfix_topic_name’ for GPSFix messages
Merge pull request #50 from MOLAorg/feat/refactor-gui Port to the new backend agnostic GUI API
Port to the new backend agnostic GUI API
ROS2 node and ros2bags: support gps_msgs/GpsFix messages too
On bad ICP, do neither publish or show deskewed scans
gicp pipeline: expose more env vars for KF map params
Merge pull request #48 from MOLAorg/feat/selective-icp-log New env var to debug bad ICP cases: MOLA_WRITE_DEBUG_ICP_LOG_IF_QUALITY_UNDER
New env var to debug bad ICP cases: MOLA_WRITE_DEBUG_ICP_LOG_IF_QUALITY_UNDER
CSV stats: include icp_quality too
Merge pull request #47 from MOLAorg/better-deskew-performance More efficient deskew and visualization
refactor deskew and viz updates
Ensure no detached threads (#46) * Fix: potential miss error report saving mm files * Ensure no detached threads for disk io * minor fixes
fix obsolete usage of ament_target_dependencies()
Remove no longer needed param period_publish_new_localization (Removed in BridgeROS2)
Fix: provide a mechanism to read 2D lidar from ROS (#43) * Fix: provide a mechanism to read 2D lidar from ROS * docs: add new ros launch argument lidar_topic_type * doc: better roslaunch arg description
Fix building against older versions of mrpt & mp2p_icp
Saving simplemap with lazy-load is done in its own detaled thread
Merge pull request #40 from MOLAorg/feat/more-clang-tidy-checks Add many more clang-tidy checks
Remove thread_local aux variable for viz camera rotation
Increase level of clang-tidy warnings, and fix them
Copyright year bump
Merge pull request #39 from MOLAorg/feat/optional-prefilter-pipeline Add optional prefilter pipeline for all ICP methods
Add many more clang-tidy checks
Add optional prefilter pipeline for all ICP methods
Contributors: Jose Luis Blanco-Claraco
1.3.1 (2025-12-29)
Merge pull request #36 from MOLAorg/feat/use-generic-map-fields Use CGenericPointsMap to propagate all sensor per-point fields thru mapping pipelines
Support to visualize clouds in MOLA Viz recolorized by any cloud point field
Use CGenericPointsMap to propagate all sensor per-point fields thru mapping pipelines
Contributors: Jose Luis Blanco-Claraco
1.3.0 (2025-12-15)
Add CI and documentation badges to README Added badges for CI build, clang-format, documentation, and code coverage.
Add option ‘use_imu_orientation’ to disable using IMU orientation for initialization
docs: add table clarifying localmap types
Make it compatible with observations w/o cov
Discard GPS readings with invalid cov matrix
Add warning if sensor stamps go backwards in time
Update usage instructions for mola_lo_apps.rst Added usage instructions for LIO with Ouster in mola_lo_apps.rst.
Contributors: Jose Luis Blanco-Claraco
1.2.2 (2025-11-08)
Add quick instructions to launch mola-lo-gui on an Ouster dataset
Add option to store persistent settings and check version
Fix: missing publication of LocalMap if BridgeROS2 loads after this module.
Contributors: Jose Luis Blanco-Claraco
1.2.1 (2025-10-28)
Fix build against upcoming mrpt v2.15.0
Reduce the limit of published points to avoid FoxGlove WS overflow
docs: show first usage with rosbags & rawlogs
Contributors: Jose Luis Blanco-Claraco
1.2.0 (2025-10-21)
Tune ROS2 publication rates for reduced viz load
New option ‘publish_deskewed_scans’
Fix unit tests
ros2 launch: sort arguments
Contributors: Jose Luis Blanco-Claraco
1.1.0 (2025-10-20)
Docs: describe the new GICP and LIO pipelines
Update rviz settings
Prefer to publish deskewed clouds in ‘map’ frame
FIX: ROS2 interface must use correct cloud and pose timestamps
Update and fix LIO ROS2 launch demo and docs
ROS: support rendering deskewed clouds
Replace deprecated ament_target_dependencies() with pure cmake
Publish deskewed scans for ROS visualization
Make use of ConstPtr for processing incoming observations
Code clean up: remove macros for building against very old mola_kernel versions
ros2 launch: add argument ‘mola_tf_base_link’
Contributors: Jose Luis Blanco-Claraco
1.0.0 (2025-10-13)
Merge pull request #26 from MOLAorg/feature/better-lio Better LIO & new GICP pipeline
CI: Run on ROS testing only
Add custom ‘name’ to pipeline stages for profiler
Update docs: Show example of use for MOLA_TF_BASE_LINK=os_sensor
Feature: add option to save deskewed clouds
refactor part of processScan() for code clarity
fix clang-tidy warnings
New config flag MOLA_SAVE_MM to save final metric map at session end
add option to re-colorize clouds by intensity (local map)
Add a clear message at initialization showing the name of the used pipeline
Fix macro to detect newer mp2p_icp version
cli app: show LO pose
Refactor the way Lidar scans are enqueued depending on LO/LIO usage
ICP pipelines: renamed old ‘default’ as ‘icp’, and add new ‘default’ symlink pointing to ‘gicp’
cli: use MOLA YAML parser for state estimation files
Fix kitti eval scripts
cli: fix expected contents of state estimation param files
Debug traces: more covariance data
GUI: Show keyframe stats
configurable icp quality setpoint
Fix lidar rate for multiple lidars
New param to change the color of trajectory in the GUI
reset local viz clouds when re-localizing
gicp pipeline: use 2 resolutions (icp / map)
Auto-scale intensity for visualization
Less aggressive P controller for adaptive sigma
Use adaptive sampler
Update to latest mp2p_icp library API
Progress optimizing new gicp pipeline
New GICP pipeline file
Fix for latest mola imu API changes
Send velocity and orientations to the local velocity buffer
Better visualization of current / past clouds, with configurable colormaps from the yaml file
Move to the new deskew_method flag in mp2p_icp
README.md: update bibtex reference
Move IMU initialization to package mola_imu_preintegration
IMU initializer moved out to the mola_imu_preintegration package for better reusability
PitchRoll init: Add to-do note on IMU bias
GUI: show lidar & imu rates
remove obsolete pipeline
Fix typos in YAML comments
Configurable GUI background color
Implement display dense local map (decaying deskewed clouds)
Implement visualization of past clouds as transparent, decaying clouds
Add missing header for latest mola_kernel
option to show mulran dataset clouds with their real intensity channel
Visualization: show the deskewed current observation instead of raw
Contributors: Jose Luis Blanco-Claraco
0.9.0 (2025-08-26)
FIX: bug in formula for pitch-roll initialization from IMU
Store local IMU velocity buffer in key-frame simplemaps
mola-lidar-odometry-cli: New CLI arguments to support datasets with IMUs
Implement precise IMU-based deskew (requires latest mp2p_icp library)
fix clang-format
Modernize copyright notices
rosbag2 mola-cli launch file: add MOLA_ROS2BAG_EXPORT_TO_RAWLOG_FILE optional env var
Contributors: Jose Luis Blanco-Claraco
0.8.0 (2025-06-06)
Publish mp2p_icp metric map metadata, if existing in loaded maps.
state estimation config yaml file: expose IMU sensor name env var
Update mola_lo_pipelines.rst: explicitly show an example of using the NDT pipeline
ros2 launch: add new argument to control the scan validity filter based on minimum point count (now, enabled by default)
Update broken link to ROS Index
mola-lidar-odometry-cli: now also forward raw sensor data to state estimator
Fix build against mola <1.8.0
Docs: better explain existing variables to override sensor poses
gui option: implement show as orthographic camera
Contributors: Jose Luis Blanco-Claraco
0.7.3 (2025-05-25)
feature: new threshold to discard state estimation as invalid if uncertainty is too high
Fixed unit tests in CI
Prepare GUI for ortho camera option
progress implementing init pitch/roll from IMU
pipelines YAML files reformated with RedHat YAML formatter
Update env var name to explicitly mention LO: MOLA_LO_INITIAL_LOCALIZATION_METHOD
docs: on initial localization methods
ROS2 launch: Add new mola_state_estimator_reference_frame argument. It should be used together with mola_lo_reference_frame to use an alternative reference map TF frame than the default map.
Fix wrong namespace in class name (it worked anyway because of a fall-back mechanism using unqualified names)
Expose env vars to change the reference frame_id for smoother (MOLA_TF_MAP)
fix: potential missing publication of updated poses if there is no map subscriber
lidar 3d pipeline: add rendering options for local map
Contributors: Jose Luis Blanco-Claraco
0.7.2 (2025-04-23)
better integration of clang-tidy, colcon_defaults, and clangd with vscode
Expose two more env vars: MOLA_MAP_CLOUD_DECIMATION, MOLA_ICP_CLOUD_DECIMATION
FIX: also initial pose for localmap
BUGFIX: Initial twist was wrong for custom initial poses
Contributors: Jose Luis Blanco-Claraco
0.7.1 (2025-03-15)
FIX: Handle correctly the case of input scans with non-normal numbers
docs: format of ros2 launch argument
FIX: reset map to start again might lead to divergence; Add new ‘reset_state’ command via MOLA dynamic variables
Force requiring valid poses for IMU and GNSS inputs
Refactor implementation source into several smaller files
FIX: mola-lo didn’t exit due to waiting ICP queue if fed faster than ICP processing
FIX: mola-lo-gui apps may show duplicated UI controls in particular circumstances
Drop frames warning message now tells the exact drop ratio
Initial localization method is now loadable from yaml or ros2 launch file
MOLA-LO no longer subscribes to wheels odometry. That is now delegated directly to state estimation modules.
Add new ROS2 launch argument: forward_ros_tf_odom_to_mola
Contributors: Jose Luis Blanco-Claraco
0.7.0 (2025-02-22)
Implement new mola_kernel diagnostics API
Ensure map is published after ROS2 bridge is already listening (FIXES: potential loss of map publication if MM map is given via env var)
FIX: Proper configurable dropped frames mechanism and stats
FIX: Update GUI, publish maps, correctly independently of whether MolaGUI is enabled
launch: fix localization source name
FIX: Do not ever reset the map when in localization mode
Fix: refresh GUI with initial map
Allow dropping LiDAR frames in too slow for real-time, but not any other observation type
FIX: ensure georef metadata is published when map_load service is called
rename kitti ros2 demo file to unclutter ros2 launch autocompletion
Add ros launch argument ‘use_state_estimator’
FIX: publish georeferencing metadata at start up
Add ROS2 launch arguments to select an state_estimator method
update citation
Add more params to smoother state estimation default YAML file
Add env variable MOLA_STATE_ESTIMATOR_PUBLISH_RATE to control filtered pose update rate
Add new env var MOLA_NAVSTATE_ENFORCE_PLANAR_MOTION and ros2 launch argument for it
Add new ros launch argument mola_footprint_to_base_link_tf
Fix expected pose format in yaml
ROS2 launch: shutdown if mvsim crashes
Fix parse error with default .mm and .simplemap launch arguments
Contributors: Jose Luis Blanco Claraco, Jose Luis Blanco-Claraco
0.6.2 (2025-02-13)
ros2 launch: add .mm and .simplemap optional initial map arguments
All exhaustive docs on ros2-related mola launch YAML files with the meaning of all BridgeROS2 parameter
Delegate publishing georeference info to BridgeROS2
Contributors: Jose Luis Blanco-Claraco
0.6.1 (2025-01-26)
Do not re-publish the map if it does not change, e.g. in localization-only mode
ros2 launch file: two new arguments ‘mola_lo_pipeline’ and ‘generate_simplemap’
Default 3D-LO pipeline: Add new env var ‘MOLA_LOCALMAP_LAYER_NAME’, useful when localizing with prebuilt maps
Merge pull request #12 from r-aguilera/develop fix launch file params
fix launch file params
Contributors: Jose Luis Blanco-Claraco, Raúl Aguilera
0.6.0 (2025-01-21)
Fix: publish map on first iteration
Publish georeferencing frames (utm, enu) when loading a metric map with georef. info
ros2 lidar odometry launch: add ros argument for /tf reference_frame
ROS2 kitti Lidar-Odometry demo: fixed to publish correct /tf’s
Add new frame parameters to pipeline YAML files
Two new parameters (publish_reference_frame, publish_vehicle_frame), to have explicit control on frame names published to both, ROS, and the MOLA state_estimator
ROS2 service call for load_map(): more concise error messages
Contributors: Jose Luis Blanco-Claraco
0.5.4 (2025-01-16)
Add a debug helper env var MOLA_BRIDGE_ROS2_EXPORT_TO_RAWLOG_FILE
Do not reset the state estimator on a bad ICP, allowing merging from other sensors or extrapolating.
Docs: add missing ros2 launch args
More ROS2 launch arguments
Contributors: Jose Luis Blanco-Claraco
0.5.3 (2025-01-15)
FIX: mola_state_estimator_simple must be available as a build dep too for easier usage of mola-lo-cli
Contributors: Jose Luis Blanco-Claraco
0.5.2 (2025-01-11)
Merge pull request #11 from MOLAorg/10-bad-first-icp-re-starting-from-scratch-with-a-new-local-map Fix NaN pointcloud radius in doInitializeEstimatedMaxSensorRange()
Unit tests: add test run against MulRan dataset fragment (Lidar+IMU)
cli: fix name of example pipeline file when –help invoked
unit tests: fix wrong usage of state estimator yaml file
mola-lo-gui-mulran: show IMU & GPS data in GUI
Define a sensible value for maxRange
Fix cmake warning when built w/o mola_state_estimation_simple sourced in the env
Contributors: Jose Luis Blanco-Claraco
0.5.1 (2025-01-07)
mola-lidar-odometry-cli: add flags to select the state estimation method
Contributors: Jose Luis Blanco-Claraco
0.5.0 (2024-12-29)
cmake test logic: add find_package() for state_estimation_simple
Merge pull request #7 from MOLAorg/wip/new-state-estimators New state estimators (Merge after MOLA 1.5.0 is installable via apt)
Split state estimation params so each implementation has its own yaml file
CI: build against both, ROS testing and stable
Add new state estimator module in all MOLA-CLI yaml files
Update to new state estimation packages
Reorganization such as state estimator is now an independent external module
docs: add new ros-arg publish_localization_following_rep105
FIX: publish local map even when not active
Contributors: Jose Luis Blanco-Claraco
0.4.1 (2024-12-20)
ROS2 launch: add ros argument for new option publish_localization_following_rep105
rviz2 demo file: better orbit view
ROS2 config file: define env vars for all tf frames (odom, map, base_link)
Contributors: Jose Luis Blanco-Claraco
0.4.0 (2024-12-18)
demo rviz file: fix lidar topic name
Include /tf remaps too in ros2 launch
mola launch for ROS 2: Add placeholder for ros args parsing
mola launch for ROS 2: add env variables to quickly control verbosity of each module. Env. vars. are: MOLA_VERBOSITY_MOLA_VIZ, MOLA_VERBOSITY_MOLA_LO,MOLA_VERBOSITY_BRIDGE_ROS2 (Default: INFO)
Support for ROS2 namespaces in launch file
docs; and fix launch var typo
ROS 2 launch: add more ros args
move MOLA-LO ROS2 docs to the main MOLA repo
Expose one more runtime param: generate_simplemap
clarify docs on sensor input topic names
runtime parameters: update in GUI too
publish ICP quality as part of localization updates
mola module name changed: ‘icp_odom’ -> ‘lidar_odom’
Do not publish localization if ICP is not good
Expose runtime parameters using MOLA v1.4.0 configurable parameters: active, mapping_enabled
docs clarifications
map_load service: allow not having a .simplemap file and don’t report it as an error
FIX: motion model handling during re-localization
Implement map_save
reset adaptive sigma upon relocalization
Implement map_load; Implement relocalize around pose
Forward IMU readings to the navstate fusion module
CI and readme: remove ROS2 iron
Merge branch ‘wip/map_load_save’ into develop
docs: add ref to yaml extensions
Add docs on 3D-NDT pipeline and demo usage with Mulran
parameterize maximum_sigma
CLI: add flag to retrieve all twists in a file; avoid use of “static” variables
LO: Add a getter for the latest pose and twist
doc: explain “no tf” error message
tune 3D-NDT defaults
Kitti and Mulran evaluation scripts: extend so they can be run with other pipelines
ros2 launch: Add ‘use_rviz’ argument
NDT pipeline: expose max sigma as parameter too
Avoid anoying warning message when not really needed
Extend options for GNSS initialization
Add docs on mola-lo-gui-rawlog
Default pipeline: reduce density of keyframes in simplemap
Docs: mola_lo_apps.rst fix PIPELINE_YAML var name
Update mola_lo_pipelines.rst: fix format
recover passing var args to mola-lo-gui-rosbag2 script
UI: show instantaneous max. sensor range too
FIX: formula for the estimated max. sensor range fixed for asymmetric cases
add new visualization param ground_grid_spacing
viz: grow ground grid as the local map grows
FIX: disabling visualization of raw observations left last raw observation rendered
fix: separate GPS topic and sensorLabel variables
Consistent GPS topic name
Add another env variable: MOLA_LOCAL_VOXELMAP_RESOLUTION
Expose new param for local map max size
enable the relocalize API
Expose fixed sensor pose coords as optional env variables
Readme: add ROS badges for arm64 badges
GitHub actions: use ROS2-testing packages
Contributors: Jose Luis Blanco-Claraco
0.3.3 (2024-09-01)
default 3D pipeline: Expose a couple more parameters as env variables
Depend on new mrpt_lib packages (deprecate mrpt2)
Contributors: Jose Luis Blanco-Claraco
0.3.2 (2024-08-26)
Support input dataset directories for split bags
Contributors: Jose Luis Blanco-Claraco
0.3.1 (2024-08-22)
add missing exec dependencies to package.xml for mola-lo-* commands.
Contributors: Jose Luis Blanco-Claraco
0.3.0 (2024-08-14)
First public release
Contributors: Jose Luis Blanco-Claraco
Changelog for package mola_metric_maps
3.2.1 (2026-09-15)
TSDF: render the actual zero level set, not the voxel centers (#217)
Merge pull request #213 from MOLAorg/feat/tsdf-uses-shared-hash Drop TSDF’s private voxel hash for the shared one
Read the voxel index through its members, not through a cast
Merge pull request #211 from MOLAorg/feat/tsdf-local-map Add mola::TSDF, a truncated signed distance field local map
Expose the two constants of the per-point plane regularization (#200)
Optional diagnostic: scan-side covariance degeneracy in cov-to-cov matching (#199)
Merge pull request #197 from MOLAorg/feat/ndt-plane-candidates NDT: report every candidate cell plane, not only the closest one
Guard NDT::nn_visit_pt2pl_candidates() for older mp2p_icp
Contributors: Jose Luis Blanco-Claraco
3.2.0 (2026-08-21)
Merge pull request #195 from MOLAorg/feat/cov2cov-ambiguity-gating mola_metric_maps: adopt mp2p_icp::MatchingDistanceProfile in nn_search_cov2cov
Merge branch ‘develop’ into feat/cov2cov-ambiguity-gating
mola_metric_maps: remove the ambiguity gate from nn_search_cov2cov() Companion to the removal in mp2p_icp`#89 <https://github.com/MOLAorg/mola/issues/89>`_: firstToSecondDistanceMin/ firstToSecondMinRange were not yet justified by results. Drop the gate logic (and the k=2 / radius-inflated query it required) from IncrementalPointCloud and KeyframePointCloudMap’s exact and approximate-cov paths, the flat compat stand-in, and the corresponding test coverage, keeping the range-adaptive matching distance.
mola_metric_maps: build against mp2p_icp releases without MatchingDistanceProfile rosdep resolves mp2p_icp to the last released binary package in every CI job, so this tree has to compile against an mp2p_icp that predates MatchingDistanceProfile. Adds MatchingDistanceProfileCompat.h, which either aliases the real type or, when the header is absent, supplies a flat-only stand-in with the same small surface. The search implementations are written against that alias and so stay free of preprocessor branches; only the public overload, and the tests that exercise the ambiguity gate, are guarded by MP2P_ICP_HAS_MATCHING_DISTANCE_PROFILE. Both map classes now implement the flat-threshold overload (still the pure virtual upstream) as a forwarder into a shared private nn_search_cov2cov_impl(), so the two public entry points cannot drift apart.
mola_metric_maps: adopt mp2p_icp::MatchingDistanceProfile in nn_search_cov2cov Follows the mp2p_icp interface change: nn_search_cov2cov() now receives a MatchingDistanceProfile instead of a flat float search distance. Implemented in IncrementalPointCloud and in both KeyframePointCloudMap paths (exact and approximate-cov). The flat, ungated default keeps a dedicated fast path in all three: no per-point range is computed and the KD-tree query stays k=1, so the previous behavior is reproduced exactly and at the same cost. When the ambiguity test is active for a query point, the search radius is inflated by the ratio, so any runner-up able to disqualify the winner is guaranteed to lie inside it, and the best two candidates are kept. In the approximate-cov path the runner-up may live in a different keyframe than the winner, so the best two are folded across all active keyframes rather than per keyframe. Range is measured in the query point’s own untransformed (sensor) frame. Tests added for the ambiguity gate in both map classes.
Merge pull request #193 from MOLAorg/fix/incremental-map-pairing-order Give IncrementalPointCloud::nn_search_cov2cov() a canonical pairing order
Give IncrementalPointCloud::nn_search_cov2cov() a canonical pairing order The same defect fixed for KeyframePointCloudMap in bfe6cb2e, which did not cover this map class: the parallel path accumulates correspondences into a tbb::enumerable_thread_specific and merges it by iteration, whose order is unspecified. The permutation is not cosmetic, it reaches the solver, which sums the normal equations over the pairing list in order. This class needs a stronger fix than the keyframe map did, because here the sequential path was not canonical either. The live local points come from snapshotLiveIndices(), a depth-first walk of the k-d tree, so they arrive in tree-topology order rather than in slot order. Tombstones and rebuilds change that shape, so with async_rebuild enabled the pairing order varied between runs even single-threaded. The sort is therefore applied to the shared intermediate match list, before the pairings are assembled, which pins both paths to the same order and makes the result independent of the tree shape a rebuild happened to leave behind. Two sibling call sites in this file already sort that snapshot for the same reason. Sorting the intermediate list rather than the output pairings also keeps the comparison on an 8-byte key instead of a full pairing, and gives the assembly pass ascending access into the coordinate and covariance buffers. Each local point yields at most one match, so its slot is a unique key and the resulting order is total. test_pairing_order_is_canonical asserts ascending local_idx and identical order across repeated calls, over a cloud with tombstones so tree order really does diverge from slot order, and large enough that TBB splits the range across workers. It fails without this change with “Pairings are not in canonical (ascending local_idx) order”.
silent a gcc warning (safe)
Merge remote-tracking branch ‘origin/feat/map-frame-gauge-change’ into feat/map-frame-gauge-change
Merge branch ‘develop’ into feat/map-frame-gauge-change
Contributors: Jose Luis Blanco-Claraco
3.1.1 (2026-08-10)
mola_metric_maps: fix calloc arg order and nodiscard warnings on newer GCC.
Give nn_search_cov2cov() a canonical pairing order. The parallel path merged per-thread correspondences in unspecified order, making ICP results non-deterministic run to run; now sorted by local_idx to match the sequential path.
IncrementalPointCloud: rebuild the k-d tree on a global SE(3) re-map. changeCoordinatesReference() rewrote coordinates in place without resizing, so the k-d tree kept stale split planes and nearest-neighbor queries silently returned wrong results. Fixes #186.
mola_metric_maps: depend on nanoflann_vendor instead of nanoflann, since the rosdep key otherwise resolves to the distro’s older libnanoflann-dev.
fix(mola_metric_maps): don’t require nanoflann>=1.5.1 for KeyframePointCloudMap covariances. Ubuntu jammy’s older nanoflann made every use of mola::KeyframePointCloudMap throw on Humble; now falls back to a plain kNN truncated at the same radius, verified numerically equivalent.
Contributors: Jose Luis Blanco-Claraco
3.1.0 (2026-08-06)
Merge pull request #187 from MOLAorg/feat/incremental-point-cloud-kdtree-bake Bake IncrementalPointCloud’s k-d tree index (mm-ipc-bake-kdtree)
address review comments
Add k-d tree baking for IncrementalPointCloud + mm-ipc-bake-kdtree tool Serializes the incremental k-d tree index alongside an IncrementalPointCloud layer’s points (TCreationOptions::serialize_kdtree), so it does not have to be rebuilt (an O(N log M) bulk build) on every load. Unlike KeyframePointCloudMap’s baked static trees, nanoflann’s incremental index had no save/load support at all; this depends on saveIndex()/loadIndex() added upstream (nanoflann >= 1.11.0, see the companion nanoflann PR), gated behind MOLA_METRIC_MAPS_HAS_INCREMENTAL_KDTREE_BAKE so older builds keep working with the option as a documented no-op. Serialization always writes/reads the compacted (tombstone-free) point order, so baking builds a throwaway index over that exact order rather than reusing the live index (whose slots may not match after tombstones/slot recycling). Adds the mm-ipc-bake-kdtree CLI tool (analogous to mm-kf-bake-kdtrees) and a shared mm_cli_utils.h generic layer-iteration helper for it. Unit tests cover: bake/load round-trip through memory and through a real temporary file, k-d tree parameters differing between bake and load time, clearing and re-inserting into a loaded (baked) map, further insertions/trims on a loaded map, and serialize_kdtree=false remaining a no-op – all independent of whether this build’s nanoflann actually supports baking.
changelog
chore: document and fix some multithreading issues
Merge pull request #185 from MOLAorg/chore/remove-keyframe-map-capable Remove the KeyframeMapCapable interface
docs: drop the KeyframeMapCapable references left behind
chore: remove the KeyframeMapCapable interface This mixin was introduced to expose per-KF pose plumbing to mola_lidar_odometry’s trajectory-rebake experiment, which corrected accumulated tilt by re-integrating the keyframe chain. That experiment is being removed: it was never wired in, and rotating map keyframes without transforming the trajectory consistently leaks vertical position. The interface had exactly one implementation and no callers, so it is removed along with the two methods that existed only for the rebake path, oldestActiveKeyframeID() and applyPivotTransform(). keyframePoses() is kept, since the regroup tests already use it as ordinary map API, and the duplicate cloneKFPoses() (whose only difference was not being the virtual one) is folded into it.
Merge pull request #184 from MOLAorg/feat/incremental-pointcloud-map feat(metric_maps): add mola::IncrementalPointCloud (incremental k-d tree local map)
docs: correct the trySetCreationOptions contract The k-d tree parameters used to require an empty map, with trySetCreationOptions() returning false rather than discarding points. It now compacts and rebuilds instead, so it always succeeds and keeps the map contents; only the previously returned point indices are invalidated. The TCreationOptions docs still described the old behaviour.
style: apply clang-format-14
feat(metric_maps): degrade gracefully on distros with an old nanoflann The incremental k-d tree index needs nanoflann >= 1.10.0. Previously the whole class was compiled out below that, so a YAML naming mola::IncrementalPointCloud failed with MRPT’s generic “no such registered CMetricMap class”, which reads like a typo or a missing plugin rather than a missing feature. Now the class is always declared, compiled and registered; only the k-d tree factory is conditional. Without a suitable nanoflann, IncrementalKDTree_stub.cpp provides a factory that throws an explanatory std::runtime_error naming the version actually found and pointing at mola::KeyframePointCloudMap as the alternative. CMake emits a warning at configure time instead of a silent status message. MOLA_METRIC_MAPS_HAS_INCREMENTAL_POINT_CLOUD keeps advertising whether the feature is functional, and the unit test is still only built when it is. Verified by configuring against the nanoflann 1.9.0 shipped by ROS Humble: builds clean, class registers, and construction throws the expected message.
feat(metric_maps): add mola::IncrementalPointCloud A single-global-frame, sliding-window local map for LiDAR (inertial) odometry, backed by one incremental self-balancing nanoflann k-d tree instead of a static tree rebuilt on every scan. It derives from mrpt::maps::CGenericPointsMap, so points arrive through the usual insertObservation()/insertAnotherMap() entry points with all per-point channels preserved, and the index picks up appended points lazily. Points far from the robot are evicted on insertion (creationOptions.remove_points_farther_than, a cube half-side), and the slots the index reclaims are recycled so storage stays bounded under churn. GICP matching is supported via mp2p_icp::NearestPointWithCovCapable with lazily computed, cached, plane-regularized per-point covariances. This is an odometry local map only: a single global tree cannot absorb a loop-closure re-map, so KeyframePointCloudMap remains the choice there. Notes: - Requires nanoflann >= 1.10.0 (the release that introduced the incremental index). The class is simply not built otherwise, gated by the CMake-set MOLA_METRIC_MAPS_HAS_INCREMENTAL_POINT_CLOUD. - nanoflann is included by src/IncrementalKDTree.cpp alone, by absolute path and with its namespace renamed, and is never exposed through a public header. MRPT bundles its own, usually older, copy of the same header and the two differ in non-template entities that share mangled names, so letting both reach one program is an ODR violation. Include path ordering cannot select ours either: MRPT exports its copy as an -isystem directory, and a directory listed both as -I and -isystem is deduplicated by GCC in favour of the system entry. - Removal is lazy, so the inherited size() counts live plus not-yet-reused slots; livePointCount() and compact() expose the live set. Reclaimed slots are blanked to NaN so that generic CPointsMap walkers (notably insertAnotherMap(), used to copy layers out for visualization) cannot resurrect evicted geometry. - With async_rebuild the balancing rebuilds run on a background thread. Its worker reads the coordinate buffers, so reserve()/resize()/setSize() are overridden to wait for it before those can move, and insertion keeps spare capacity for one batch so a raw insertPointFast() loop cannot reallocate either. Tested against a brute-force nearest-neighbour oracle (both index variants), for bounded memory under churn, cov2cov pairings, serialization round-trip and copy.
Contributors: Jose Luis Blanco Claraco, Jose Luis Blanco-Claraco
chore: documented and fixed some multithreading issues; removed the unused KeyframeMapCapable interface and its stale docs.
feat(metric_maps): added mola::IncrementalPointCloud, a nanoflann-based incremental k-d tree local map for LiDAR odometry, with graceful degradation on distros with an old nanoflann. Two different thresholds apply: the incremental k-d tree itself requires nanoflann >= 1.10.0 (with older versions the map falls back to a stub and is unavailable at runtime), while baking (creationOptions.serialize_kdtree, mm-ipc-bake-kdtree) and loading baked k-d tree indexes additionally require nanoflann >= 1.11.0. Thus, with nanoflann 1.10.x only the incremental functionality works, and baking is a documented no-op.
docs: corrected trySetCreationOptions docs to match its new compact-and-rebuild (always-succeeds) behavior.
Contributors: Jose Luis Blanco-Claraco
3.0.0 (2026-07-17)
fix: dont crash on empty maps
feat: –unify-all flag for mm-kf-regroup
fix(mola_metric_maps): don’t restore stale icp_search_kfs cache from serialized maps icp_search_kfs was serialized purely for post-mortem debugging, but serializeFrom() restored it straight into the live cache. Since icp_search_submap (the actual prepared search structure it gates) is never serialized, this let icp_get_prepared_as_global()’s already-up-to-date fast path skip rebuilding the submap whenever the freshly computed active-keyframe selection happened to coincide with the stale, reloaded set. The next nn_search_cov2cov() call would then fail its ‘icp_get_prepared_as_global() first’ assertion. Reproduced reliably when chaining multi-session/multi-robot maps (loading a previously saved map as the starting point for a new robot/session).
fix: sort by indices to avoid gcc warnings on ABI changes
chore: tune default island param
debug: add env-gated point-density match-stats trace Adds MOLA_KEYFRAME_MAP_DEBUG_MATCH_STATS (off by default), counting per-call accepted / no-candidate-in-range / rejected-by-view-filter totals in nn_search_cov2cov_approximate(). Used to diagnose a localization stall on a real dataset: distinguishes a genuine point-density gap in the map (points with no nearby candidate) from a view-direction-filter rejection or a keyframe-selection problem, which look identical from the ICP goodness trace alone.
fix(mola_metric_maps): bound island-merge distance; never starve the diverse KF slot Address CodeRabbit review on #174 plus a second, distinct tracking-loss mode found during full-bag testing: - regroupKeyframes(): cap island absorption distance at extent_factor * (seed radii sum) so a tiny cluster is not glued to a spatially disjoint neighbor merely because it’s the “nearest” one left; islands beyond that bound stay standalone. - icp_get_prepared_as_global(): the diverse-keyframe slot’s distance limit (3x the nearest primary candidate) could reject every other candidate when a map has only a handful of large super-keyframes, leaving that slot empty and ICP running against a single keyframe. At the edge of that keyframe’s own coverage this can permanently stall tracking (quality stuck just under threshold, no fallback). Now falls back to the best-diversity candidate regardless of distance rather than leaving the slot unfilled.
fix(mola_metric_maps): density-aware nearest-keyframe selection + island merging in regroup A sparse, under-merged keyframe (e.g. a leftover cluster from regroupKeyframes()) could outrank a much better-populated keyframe in icp_get_prepared_as_global()’s proximity search purely because its pose happened to be closer, starving ICP of real geometry and causing localization to get stuck with zero correspondences. - KeyframePointCloudMap: add a distance penalty for keyframes below density_penalty_min_points, so sparse candidates no longer win over well-populated ones just by pose proximity. - regroupKeyframes(): absorb clusters below island_merge_fraction of the largest cluster’s point count into their nearest neighbor instead of emitting them as standalone, near-empty super-keyframes. - mm-kf-regroup: expose –island-merge-fraction. - Adds env-gated debug traces (MOLA_KEYFRAME_MAP_DEBUG_ACTIVE_KFS, MOLA_KEYFRAME_MAP_DEBUG_DUMP_KFS_ON_LOAD) used to diagnose this.
Merge pull request #173 from MOLAorg/perf/mm-kf-regroup-tbb-parallel-superkf mm-kf-regroup: parallelize super-keyframe cloud building with TBB
mm-kf-regroup: parallelize super-keyframe cloud building with TBB Building each super-keyframe’s merged/decimated point cloud in regroupKeyframes() was the most expensive step but ran single-threaded. Clusters are independent, so parallelize with tbb::parallel_for (gated by MOLA_METRIC_MAPS_USE_TBB, already a mola_metric_maps dependency), falling back to a serial loop when TBB is unavailable.
better defaults for regroup KF algorithm
feat: mm-kf-bake-kdtrees sets approximate cov by default
Merge pull request #171 from MOLAorg/feat/keyframe-map-persist-covariances-local-tree feat(mola_metric_maps): persist per-KF covariances + query baked local KD-tree in approximate cov2cov
fix(mola_metric_maps): handle v3 in serializeFrom + clang-format - Add case 3: to KeyframePointCloudMap::serializeFrom(): serializeGetVersion() returns 3, so v3 maps (with baked covariances) were hitting MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION on load and never reaching the new covariance-read block. (CodeRabbit) - Apply clang-format-14 to the changed files (CI clang-format-check).
feat(mola_metric_maps): persist per-KF covariances and query baked local KD-tree in approximate cov2cov Two changes that make localization-only startup with a baked .mm actually fast, eliminating the occasional multi-second stalls seen when a fresh keyframe first enters the active set: A) approximate_cov now queries each active keyframe’s own LOCAL-frame cloud and KD-tree directly (kf.pointcloud(), the one baked by mm-kf-bake-kdtrees). The query point is transformed into each KF’s local frame before the lookup and the match composed back to global for the pairing. A KD-tree’s structure is invariant under the rigid KF pose, so this avoids ever materializing a per-KF global-frame cloud or rebuilding a KD-tree on it. Previously the baked (local) index never touched this hot path, which used a separate global-frame tree rebuilt from scratch on first activation. Also robust to online KF pose nudges (LIO gravity-tilt correction), which no longer invalidate a global cloud. B) New serialize_covariances creationOption: bakes each keyframe’s per-point local covariances into the .mm (map serialization bumped to v3), so the plane-regularized K-NN + SVD pass is not repeated on load. This is the single most expensive part of warming a keyframe and needs no special MRPT API, so it works on any build (unlike serialize_kdtrees). The cheap per-pose global rotation is still done at runtime. mm-kf-bake-kdtrees now bakes both KD-trees and covariances by default (–no-kdtrees / –no-covariances to select, –disable to strip both). Adds a round-trip test asserting a covariance-baked map yields byte-identical cov2cov pairings (points + cov_inv) to a runtime-computed one.
Merge pull request #169 from MOLAorg/feat/keyframe-map-approximate-cov2cov feat(mola_metric_maps): approximate cov2cov mode for KeyframePointCloudMap
fix(mola_metric_maps): tolerate concurrent KF eviction in approximate cov2cov nn_search_cov2cov_approximate() looked up each active KF id via keyframes_.at(), which throws std::out_of_range if the KF was evicted by a concurrent insertObservation() (remove_frames_farther_than) between the earlier icp_get_prepared_as_global() snapshot and this call. The exact (merged-submap) path is immune since it deep-copies points at prepare time; the approximate path intentionally keeps live references into keyframes_ instead, so it needs to check existence. Found by CodeRabbit review on MOLAorg/mola#169.
feat(mola_metric_maps): approximate cov2cov mode for KeyframePointCloudMap Add TCreationOptions::approximate_cov: when enabled, nn_search_cov2cov() skips building the merged, multi-keyframe submap in icp_get_prepared_as_global() and instead queries each active keyframe’s own already-cached KD-tree and per-point covariances directly (N per-KF KD-tree lookups instead of one on a merged cloud). This trades covariance exactness (estimated only from within-KF neighbors) for speed (no merge/KD-tree rebuild), and is opt-in (default false, unchanged exact behavior).
fix: stable re-coloring
Merge pull request #168 from MOLAorg/feat/kf-viz-color-by-kf feat(mola_metric_maps): debug env var to color each keyframe distinctly
feat(mola_metric_maps): debug env var to color each keyframe distinctly Add MOLA_KEYFRAME_MAP_VIZ_COLOR_BY_KF: when set, KeyframePointCloudMap renders every keyframe with a single, distinct color (golden-ratio hue spacing) so regrouped super-keyframes / clusters are easy to tell apart visually while debugging. KeyFrame::getViz() gains an optional overrideColor argument; the override path paints all points uniformly and is not cached, so toggling the env var takes effect on the next render.
Merge pull request #167 from MOLAorg/feat/keyframe-map-regroup-and-kdtree-persist Keyframe map regrouping + optional KD-tree persistence (localization-only speedups)
address review: clearer error when –layer is not present in the map
address review: shared CLI helper, unsupported-build warning, decimation test - Extract the duplicated plugin-load / map-load / KeyframePointCloudMap-layer iteration logic of the two CLI tools into a shared apps/kf_cli_utils.h. - mm-kf-bake-kdtrees now warns when built against an MRPT lacking the KD-tree save/load index API (baking would silently be a no-op otherwise). - Add a regroup test exercising merge_decimate_voxel > 0: the duplicated points collapse and the per-point view-direction fields survive decimation (verified via the cov-to-cov view filter).
feat(mola_metric_maps): keyframe regrouping + optional kd-tree persistence Two offline optimizations of a KeyframePointCloudMap layer for fast localization-only operation: - regroupKeyframes() + mm-kf-regroup CLI: group many small keyframes into fewer, larger, deliberately-overlapping “super-keyframes” so the ICP active set stays size 1 (no per-scan keyframe switching). Graph-theoretic: keyframe adjacency graph with voxel Jaccard-min overlap edge weights, greedy overlapping set-cover clustering auto-sized from each keyframe bounding box, merged clouds voxel-decimated (view-direction fields carried). - serialize_kdtrees creationOption + mm-kf-bake-kdtrees CLI: cache each keyframe’s per-cloud 3D KD-tree index inside the .mm so it is not rebuilt on every load. Bumps map serialization to v2 (self-describing per-KF flag byte + KD-tree blob). Requires the MRPT KD-tree save/load index API, feature-detected via MRPT_HAS_KDTREE_SAVE_LOAD_INDEX; when absent the option is a no-op on write and readers skip any stored blob, so .mm files stay interoperable across MRPT builds. Adds unit tests (regroup reduction/coverage/roundtrip, kd-tree serialization roundtrip) and updates agents.md.
docs: clarify clouds are deskwed
remove not used macros
Add mm2ini/ini2mm CLI tools to export/import metric map layer options (#158) * Add mm2ini/ini2mm CLI tools to export/import metric map layer options mm2ini exports the CLoadableOptions (creation/insertion/likelihood/render options) of every layer in a .mm file to a human-editable .ini file; ini2mm applies such a file back, overwriting only the options sections present in it while leaving map data untouched. Supported layer classes are identified via dynamic_cast in OptionsIniIO.h, covering this library’s own map types plus basic mrpt::maps classes (CPointsMap and derivatives, COccupancyGridMap2D). Also works around a few known dumpToTextStream()/loadFromConfigFile() inconsistencies in upstream MRPT (COccupancyGridMap2D’s horizontalTolerance unit mismatch, rayTracing_decimation being write-only, and bare Y/N booleans) without requiring any MRPT changes. Adds test-options-ini-io.cpp, which builds a synthetic in-memory CSimpleMap and round-trips the options of all 7 supported classes. * Add MapOptionsCapable interface for generic, safe creation-options handling Introduces mola::MapOptionsCapable, a mixin interface implemented by all map classes in this library, with two methods: - optionsByName(): lists every CLoadableOptions group by name, so callers (e.g. OptionsIniIO/mm2ini/ini2mm) no longer need per-class knowledge of which option structs a map defines. - trySetCreationOptions(): applies new creation options (e.g. voxel/grid size) only if doing so doesn’t require discarding the map’s current contents; otherwise returns false and leaves the map untouched. NDT, HashedVoxelPointCloud, SparseVoxelPointCloud and SparseTreesPointCloud gain a real TCreationOptions (their voxel/grid size, previously only a constructor argument), kept in sync with the internal structure via setVoxelProperties()/setGridProperties(). KeyframePointCloudMap’s existing TCreationOptions are pure runtime thresholds, so it always accepts changes. OptionsIniIO.cpp’s five near-duplicate per-class dynamic_cast blocks collapse into one generic path for any MapOptionsCapable map, keeping a dynamic_cast fallback only for classes outside this library (mrpt::maps::CPointsMap, COccupancyGridMap2D). ini2mm now reports rejected creation-option changes explicitly instead of a generic warning. * Rename MapOptionsCapable to OptionsCapable * Fix critical data-wipe bug and stale-cache issue found by CodeRabbit - NDT/HashedVoxelPointCloud/SparseVoxelPointCloud/SparseTreesPointCloud’s trySetCreationOptions() called setVoxelProperties()/setGridProperties() unconditionally, which clears the map – so re-applying an unchanged voxel/grid size (e.g. a routine ini2mm run that doesn’t touch that field) silently wiped all map contents. Now only called when the value actually changes. - KeyframePointCloudMap::trySetCreationOptions() updated the top-level creationOptions but left already-inserted KeyFrames with their own cached k_correspondences_for_cov/min_correspondences_for_cov/ max_distance_for_cov (frozen at insertion time for lazy per-point covariance computation), so existing keyframes kept using stale values. Added KeyFrame::updateCovarianceParams() and propagate the new values to every existing keyframe, under state_mtx_ like other mutators. - Added regression tests for both: re-applying an unchanged voxel_size on a non-empty map must be a no-op (not a wipe), and clarified the agents.md wording on which classes implement OptionsCapable.
Merge pull request #157 from MOLAorg/fix/keyframemap-view-vector-rotation Fix view-direction vector frame mismatch in KeyframePointCloudMap
Fix compat shim: real if constexpr discarding requires a template The previous compat shim used if constexpr inside a non-template member function (updatePointsGlobal). Per the standard, if constexpr only skips type-checking the untaken branch inside a template – in ordinary code both branches are fully compiled. Against a real old mp2p_icp checkout (2.9.0, lacking rotateViewDirectionFields()), this made the discarded “call the real helper” branch resolve to our own ellipsis fallback and try to pass CPointsMap by value through it, which is ill-formed since CPointsMap’s copy constructor is deleted – a hard build failure caught by CI (x86_64 / humble stable job on PR #157). Fix: move the dispatch into a small template function (rotateViewDirectionFieldsOrFallback<Pts, Pose>), and factor the legacy rotation loop into its own function (rotateViewDirectionFieldsLegacy) so it isn’t duplicated between the “header missing” and “header present but function missing” cases. With a genuine template parameter, if constexpr now actually discards the untaken branch without instantiating it. Verified: rebuilt and ran mola_metric_maps’ full test suite (12/12 pass) against the real (new) mp2p_icp, and syntax-checked the file with -fsyntax-only against a hand-crafted header lacking rotateViewDirectionFields() to confirm the fallback path compiles too.
Keep building against older mp2p_icp checkouts lacking rotateViewDirectionFields() Detect the helper’s availability purely in C++ via a SFINAE trait (the containing header predates the function, so __has_include() alone can’t tell old and new mp2p_icp_map apart) and fall back to the original open-coded rotation loop when it’s absent. MRPT_TODO marks the fallback for removal once the minimum required mp2p_icp_map version provides the helper (MOLAorg/mp2p_icp#70).
Fix view-direction vector frame mismatch in KeyframePointCloudMap KeyFrame::updatePointsGlobal() rotated a keyframe’s view_x/y/z vectors to the global frame assuming they were stored in the local KF frame, but mp2p_icp_filters::FilterMerge was leaving them in the global frame after inserting into a KeyframePointCloudMap, causing a double rotation that made the cov-to-cov view-angle pairing filter reject valid pairs as the keyframe heading diverged from the map’s build-time reference. Replaces the open-coded rotation loop with the new shared mp2p_icp::rotateViewDirectionFields() helper (also used by the FilterMerge fix in MOLAorg/mp2p_icp#70), documents the local-KF-frame contract in KeyframePointCloudMap.h, and adds a heading-sweep regression test.
Merge pull request #156 from MOLAorg/feat/cov-viz feat: add debug viz of map covariances
feat: add debug viz of map covariances
Merge pull request #155 from MOLAorg/fix/more-robust-kf-map-covariances fix: more robust KF map convariances
fix: more robust KF map convariances
docs(mola_metric_maps): expand class-level Doxygen and complete README - HashedVoxelPointCloud: document SSO, robin_map backend, global ID packing - SparseVoxelPointCloud: document two-level hierarchy, voxel-mean ICP option - NDT: document dual-interface design (point-to-point vs. point-to-plane) - KeyframePointCloudMap: full description of keyframe storage, ICP integration, and implemented interfaces - FixedDenseGrid3D: document calloc rationale, cell layout, trivially-copyable requirement - index3d_t / index3d_hash: document coordinate range, hash algorithm reference, dual-role as hash and comparator - OccGrid: mark as experimental/incomplete (likelihood cache not populated) - SparseTreesPointCloud: document per-block KD-tree design; mark as experimental - README: replace two-class stub with full table of all classes, including production vs. experimental status
fix KeyframePointCloudMap::boundingBox() using TOrientedBox for correct AABB The previous implementation called TBoundingBox::compose(pose), which only transforms the two diagonal corners (min/max), giving an incorrect result under rotation. Replace with TOrientedBoxf::getAxisAlignedBox(), which transforms all 8 corners before taking the envelope.
Contributors: Jose Luis Blanco-Claraco
2.9.0 (2026-05-11)
fix: KeyframePointCloudMap viz should honor pointSize
Merge pull request #143 from MOLAorg/bump-cmake-version bump min req cmake version to 3.22
bump min req cmake version to 3.22
Merge pull request #142 from MOLAorg/feat/add-keyframe-map-capable-api feat: Add keyframe map capable API
feat: Add keyframe map capable API
Contributors: Jose Luis Blanco-Claraco
2.8.0 (2026-04-29)
Merge pull request #139 from MOLAorg/fix/monothonic-kf-ids Fix: ensure monothonic KF ids
Fix: ensure monothonic KF ids
Merge pull request #138 from MOLAorg/fix/kf-map fix: robustify edge cases from last API changes
fix: robustify edge cases from last API changes
Merge pull request #137 from MOLAorg/feat/metric-map-changes-for-lo-grav-align mola_metric_maps: per-KF pose plumbing for online gravity rebake
feat(mola_metric_maps): per-KF pose plumbing for online gravity rebake Add the KeyframePointCloudMap APIs needed by mola_lidar_odometry’s online gravity-rebake feature: - cloneKFPoses: snapshot of all KF poses keyed by id - setKeyframePose: per-KF pose overwrite with cache invalidation - lastInsertedKeyFrameID / nextFreeKeyFrameID_public: id introspection - drainEvictedKeyFrameIDs: pull-then-clear list of KFs dropped during remove_frames_farther_than-driven evictions inside insertObservation Also exports the MOLA_METRIC_MAPS_HAS_KFM_POSE_PLUMBING feature macro so downstream packages in separate repos (mola_lidar_odometry) can guard usage with __has_include + this macro and stay buildable against older mola_metric_maps checkouts. Adds unit-test coverage for the new APIs in test-mola_metric_maps_keyframemap. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Merge pull request #134 from Zeal-Robotics/perf/keyframe-prewarm-global-submap perf(mola_metric_maps): pre-warm global-frame submap data in icp_get_prepared_as_global
perf(mola_metric_maps): pre-warm global-frame submap data in icp_get_prepared_as_global icp_get_prepared_as_global() was building, on the search submap, only the local-frame KD-tree and per-point covariances (via KeyFrame::buildCache): - bbox - kdTreeEnsureIndexBuilt3D() on pointcloud_ (local frame) - computeCovariancesAndDensity() (local frame) The very first call to nn_search_cov2cov() then lazily materialized the global-frame counterparts on the caller thread: - pointcloud_global() (deep copy of pointcloud_ rotated by pose()) - kdTreeEnsureIndexBuilt3D() on the global cloud - covariancesGlobal() (rotated covariances) For a non-trivial preloaded local map this stalled the first ICP align() by several seconds (e.g. ~6 s on a typical localization map), defeating the purpose of having a separate “prepare global” hook. Front-ends that explicitly pre-warm via icp_get_prepared_as_global() at startup were hit hardest, since the remaining lazy work then showed up on the very first scan instead of being amortized across startup. Pre-trigger the same three calls at the end of icp_get_prepared_as_global() so the search submap is fully ready by the time ICP::align() / nn_search_cov2cov() runs.
Contributors: Jose Luis Blanco-Claraco, Robin Van Cauwenbergh
2.7.0 (2026-04-22)
Reorganize website
Merge pull request #121 from MOLAorg/fix/clean-up-old-mrpt-version-checks Clean up: remove old mrpt version fallback code sections
Contributors: Jose Luis Blanco-Claraco
2.6.1 (2026-04-02)
Merge pull request #119 from MOLAorg/fix/thread-safety Fix/thread safety
mola_metric_maps: FIX potential race conditions They didn’t happen in practice but to be safe code clean up wip
Fix potential race in KeyframePointCloudMap::icp_get_prepared_as_global()
Fix MRPT version required for updated insertAnotherMap() API
Contributors: Jose Luis Blanco Claraco, Jose Luis Blanco-Claraco
2.6.0 (2026-03-12)
Merge pull request #113 from MOLAorg/feat/kf-map-view-vectors Feat:kf map view vectors filter for NN search
Honor the documented disable semantics for max_view_angle_deg
NDT tests: fix clang-tidy warnings
view-direction NN filter; add KF map unit tests
Fix: possible invalid deref
Better criterion to select active frames
KeyFramePointCloudMap: Add two debug env vars to control visualization
Merge pull request #107 from MOLAorg/fix/viz-decay-clouds Fix/viz-decay-clouds
BUG FIX: creationOptions were not loaded from ini file in KeyframePointCloudMap
fix clang-tidy warning: avoid std::endl
Update coyright notes
Contributors: Jose Luis Blanco Claraco, Jose Luis Blanco-Claraco
2.5.0 (2026-02-14)
Merge pull request #100 from MOLAorg/fix/remove-mrpt-deprecated-maps Remove use of mrpt deprecated maps
Avoid use of deprecated mrpt::maps classes
Merge pull request #99 from MOLAorg/feat/ros2-bridge-pub-geographic ROS2 bridge: publish geographic poses too
ros2 bridge: use geographic_msgs, store the last georeference info internally, and publish georef poses merge of these commits: - Enable many more clang-tidy checks - lint clean - implement publishing georeferenced poses - mola-viz: fix potential crash on edge case with all points having NaN value - FIX: potential crash if no MapServer is present and map services are called
Contributors: Jose Luis Blanco-Claraco
2.4.0 (2025-12-28)
KeyframePointCloudMap: viz now reuses mrpt function for better generalized per-field coloring and avoid code duplication
Contributors: Jose Luis Blanco-Claraco
2.3.0 (2025-12-15)
KF metric map: change heuristic to select nearby KFs for NN matching taking into account the orientation
KeyFramePointCloudMap: new rendering option to show XYZ axes
Contributors: Jose Luis Blanco-Claraco
2.2.1 (2025-11-08)
Metric maps: implement missing loading ‘color.A’ from config files
Contributors: Jose Luis Blanco-Claraco
2.2.0 (2025-10-28)
format
Upgrade to use the upcoming MRPT 2.15 API for CGenericsPointsMap
KeyFrames metric map: new option to visualize (via ROS publish) with a maximum number of points, downsampling for better performance
Contributors: Jose Luis Blanco-Claraco
2.1.0 (2025-10-20)
Fix formatting
Implement getAsSimplePointsMap()
KeyframePointCloudMap: Fix class must be copy-constructible
Contributors: Jose Luis Blanco-Claraco
2.0.0 (2025-10-13)
Merge pull request #93 from MOLAorg/feature/better-lio Changes for new LIO
add optional debug viz files; fix race conditions
cov2cov pairings now saves the sqrt(cov_inv)
Move to new mp2p_icp cov2cov matcher API
Update missing copyright notices
New KeyframePointCloudMap map
Fix typos and clang-tidy hints
Fix clang-tidy formatting tips
Contributors: Jose Luis Blanco-Claraco
1.9.1 (2025-07-07)
1.9.0 (2025-06-06)
1.8.1 (2025-05-28)
Fix: Do not use the deprecated ament_target_dependencies()
Contributors: Jose Luis Blanco-Claraco
1.8.0 (2025-05-25)
Update copyright year
Contributors: Jose Luis Blanco-Claraco
1.7.0 (2025-05-06)
fix clang-format
Metric maps can now be rendered as semitransparent pointclouds
Contributors: Jose Luis Blanco-Claraco
1.6.4 (2025-04-23)
robin-map: Update to v1.4.0
modernize clang-format
Contributors: Jose Luis Blanco-Claraco
1.6.3 (2025-03-15)
1.6.2 (2025-02-22)
1.6.1 (2025-02-13)
1.6.0 (2025-01-21)
1.5.1 (2024-12-29)
1.5.0 (2024-12-26)
1.4.1 (2024-12-20)
1.4.0 (2024-12-18)
1.3.0 (2024-12-11)
NDT maps: more render options (enable colormaps,etc.)
mola_metric_maps: robin-maps upgraded to latest version
Contributors: Jose Luis Blanco-Claraco
1.2.1 (2024-09-29)
1.2.0 (2024-09-16)
gcc warning fix
Avoid gcc warning
Merge pull request #69 from MOLAorg/new-map-ndt New NDT-3D metric map
Add NDT-3D map class
Remove leftover dead .cpp file from MOLA package template
FIX BUG: missing cmake dependency on robin_map in exported targets
Contributors: Jose Luis Blanco-Claraco
1.1.3 (2024-08-28)
Depend on new mrpt_lib packages (deprecate mrpt2)
Contributors: Jose Luis Blanco-Claraco
1.1.2 (2024-08-26)
1.1.1 (2024-08-23)
1.1.0 (2024-08-18)
Update clang-format style; add reformat bash script
Merge pull request #62 from MOLAorg/docs-fixes Docs fixes
Fix ament_xmllint warnings in package.xml
Contributors: Jose Luis Blanco-Claraco
1.0.8 (2024-07-29)
Update robin-map to latest version (Fix cmake < 3.5 compatibility warning)
ament_lint_cmake: clean warnings
Contributors: Jose Luis Blanco-Claraco
1.0.7 (2024-07-24)
1.0.6 (2024-06-21)
1.0.5 (2024-05-28)
1.0.4 (2024-05-14)
Metric maps: load insertion options from field ‘insertOpts’ instead of ‘insertionOptions’ for compatibility with all other MRPT maps
disable clang-format in 3rdparty submodules
Fix usage of const_cast<> with proper value() method
bump cmake_minimum_required to 3.5
Contributors: Jose Luis Blanco-Claraco
1.0.3 (2024-04-22)
Add macro HASHED_VOXEL_POINT_CLOUD_WITH_CACHED_ACCESS
Fix package.xml website URL
Contributors: Jose Luis Blanco-Claraco
1.0.2 (2024-04-04)
1.0.1 (2024-03-28)
1.0.0 (2024-03-19)
implement cached conversion to pointcloud
make cfg file section optional
FIX: error on rendering empty voxel maps
HashedVoxelPointCloud: add missing reserve()
copyright update
Contributors: Jose Luis Blanco-Claraco
0.2.2 (2023-09-08)
Changelog for package mola_state_estimation_simple
2.4.2 (2026-06-04)
feat(#33): velocity filter now handles multi-rate interleaved sources via per-component clocks, fixing linear velocity starvation when LiDAR pose stamps lag IMU stamps
feat: velocity filter enabled by default (set
velocity_filter_enabled: falseto restore legacy behavior)feat: opt-in CSV instrumentation via
MOLA_VEL_FILTER_DUMPandMOLA_NAVSTATE_DUMPenv varsfix: missing
vel_filter_Presettest: multi-rate interleaved velocity regression test
Contributors: Jose Luis Blanco-Claraco
2.4.1 (2026-06-02)
Merge pull request #32 from MOLAorg/feat/1d-kalman-velocities feat: new 1D kalman velocity filter
feat: new 1D kalman velocity filter
Contributors: Jose Luis Blanco-Claraco
2.4.0 (2026-05-11)
Merge pull request #30 from MOLAorg/bump-cmake-version bump min req cmake version to 3.22
bump min req cmake version to 3.22
Merge pull request #29 from MOLAorg/fix/odometry-fuse-pose-twist-corruption fix(state_estimation_simple): correct twist and initial-guess corruption when wheel odometry is active
Add more unit test cases
fix: odom twist does not overwrite IMU wx/wy
fix(state_estimation_simple): correct twist and initial-guess corruption when wheel odometry is active Three inter-related bugs caused the LiDAR adaptive threshold sigma to grow toward maximum_sigma whenever wheel odometry was fused: 1. Wrong twist from fuse_pose() when odometry is active. fuse_pose() computed incrPose = new_ICP - last_pose, but last_pose had been modified by fuse_odometry() / fuse_odometry_3d_pose() between scans. The result was the odometry residual / dt instead of the true robot velocity, corrupting de-skewing and the rot_error term in the adaptive threshold. Fix: per-source SourceState in State tracks each source’s own last absolute pose and timestamp. fuse_pose() now computes incrPose = new_ICP - src.last_pose, which is always the true ICP-to-ICP motion regardless of intervening odom updates. 2. CObservationRobotPose (3D odom path) overwrote last_pose_obs_tim. When BridgeROS2 forwards wheel odometry as CObservationRobotPose (odometry_as_robot_pose_observation=true), onNewObservation() routed it to fuse_pose(), which updated last_pose_obs_tim to the odom timestamp. If the next LiDAR ICP fuse_pose() arrived with a slightly earlier timestamp, dt < 0 and the call was silently rejected. last_pose was then the absolute wheel odometry pose (in the odom frame), producing ~90-degree initial-guess errors for ICP (confirmed by debug traces showing motionModelError with yaw ~ -1.56 rad and pitch ~ 0.51 rad on a stationary ground robot). Fix: route CObservationRobotPose matching do_process_odometry_labels_re to a new fuse_odometry_3d_pose() method that applies an incremental delta to last_pose (keeping it in the SLAM frame) and never touches last_pose_obs_tim. 3. fuse_odometry() ignored the velocity carried in CObservationOdometry. BridgeROS2 always populates hasVelocities / velocityLocal from the ROS /odom twist. Those values were discarded, leaving last_twist stale. Fix: when hasVelocities is true, update last_twist from velocityLocal. IMU angular rates (fuse_imu) still override wx/wy/wz when available. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chore: reduce fuse_pose() backwards in time warning rate
Contributors: Jose Luis Blanco-Claraco
2.3.1 (2026-05-04)
Merge pull request #28 from Zeal-Robotics/fix/simple-fuse-imu-preserve-linear-twist fix(state_estimation_simple): preserve linear twist across fuse_imu() Regression introduced in 15a1fce (“Add tests for simple estimator”).
Merge pull request #26 from MOLAorg/fix/smoother-issues Fix misc smoother issues
Remove copies of RegexCache.h and use the shared version in mola_kernel
Merge pull request #25 from MOLAorg/feat/simple-also-process-robot-pose-obs feat: Simple estimator now also processes CObservationsRobotPose
add regex filtering
feat: Simple estimator now also processes CObservationsRobotPose
Contributors: Jose Luis Blanco-Claraco, Robin Van Cauwenbergh
2.3.0 (2026-04-29)
Merge pull request #24 from MOLAorg/fix/bugs-in-simple-estimator-cov Fix: Avoid double covariance increment
fix: don’t use twist cov in propagating pose uncertainty in this simple mode
Fix: Avoid double covariance increment
Contributors: Jose Luis Blanco-Claraco
2.2.0 (2026-03-03)
2.1.0 (2026-02-14)
Merge pull request #13 from MOLAorg/feat/publish-georef-on-converge Publish geo-ref on convergence
Include the RDC API in the tests
Refactor publish georef and sensor label regex fix filtering observations by sensor label regex refactor to publish georef on converged automatically fix build against older mola_kernel Fix wrong logic in GNSS fuse
remove old mola version guards
Contributors: Jose Luis Blanco-Claraco
2.0.1 (2026-01-15)
2.0.0 (2026-01-14)
Merge pull request #7 from MOLAorg/feature/tricycle-kinematic Add tricycle kinematics
lint clean ups
Copyright year bump
Merge pull request #8 from MOLAorg/fix/add-simple-estimator-unit-tests Add tests for simple estimator
Add tests for simple estimator
Merge pull request #5 from MOLAorg/feature/fuse-gnss-imu-odom Refactor: new packages mola_georeferencing, mola_gtsam_factors, functional smoother state estimator
One further fix for cmake
integrate code coverage in cmake
Refactor to expose all gtsam factors into a new library ‘mola_gtsam_factors’
Contributors: Jose Luis Blanco-Claraco
1.11.1 (2025-10-20)
Update to build against MOLA>=2.1.0 with ConstPtr API
Contributors: Jose Luis Blanco-Claraco
1.11.0 (2025-10-05)
Move mola_imu_preintegration out of this repo The new repository is: https://github.com/MOLAorg/mola_imu_preintegration
Merge pull request #4 from MOLAorg/feature/imu Refactor IMU library
Fix using new IMU integration API
Move LocalVelocityBuffer class here from mp2p_icp repository
Contributors: Jose Luis Blanco-Claraco
1.10.0 (2025-09-07)
Update copyright notice
Make unhandled sensor input topic message less verbose
Contributors: Jose Luis Blanco-Claraco
1.9.0 (2025-06-06)
State estimation interface is now raw data consumer too
FIX: Error if sensor labels were provided in config yaml file
Contributors: Jose Luis Blanco-Claraco
1.8.1 (2025-05-25)
Feature: Implement basic twist covariance handling in the SimpleEstimator
fixes for clang-tidy
Contributors: Jose Luis Blanco-Claraco
1.8.0 (2025-03-15)
const correctness
State estimation modules now are proper MOLA raw inputs, so they automatically subscribe and consume input sensors (IMU, GPS, wheels odometry)
Contributors: Jose Luis Blanco-Claraco
1.7.0 (2025-02-22)
Add parameter enforce_planar_motion
Contributors: Jose Luis Blanco-Claraco
1.6.1 (2025-01-10)
Merge pull request #1 from MOLAorg/9-need-help-on-integrating-imu-for-lidar-odometry More stable integration of IMU twist information
Shorter logger name
Fix package.xml URLs
tolerate unsorted sensor inputs without throwing
Contributors: Jose Luis Blanco-Claraco
1.6.0 (2025-01-03)
Simple estimator: Integrate IMU angular velocity readings
Contributors: Jose Luis Blanco-Claraco
1.5.0 (2024-12-26)
1.4.1 (2024-12-20)
1.4.0 (2024-12-18)
Allow zero variances for some pose components
Contributors: Jose Luis Blanco-Claraco
1.3.0 (2024-12-11)
Start integrating GNSS observation. Added a new CLI program mola-navstate-cli for testing state fusion
Contributors: Jose Luis Blanco-Claraco
1.2.1 (2024-09-29)
1.2.0 (2024-09-16)
1.1.3 (2024-08-28)
Depend on new mrpt_lib packages (deprecate mrpt2)
Contributors: Jose Luis Blanco-Claraco
1.1.2 (2024-08-26)
1.1.1 (2024-08-23)
1.1.0 (2024-08-18)
Merge pull request #62 from MOLAorg/docs-fixes Docs fixes
Fix ament_xmllint warnings in package.xml
Contributors: Jose Luis Blanco-Claraco
1.0.8 (2024-07-29)
ament_lint_cmake: clean warnings
Contributors: Jose Luis Blanco-Claraco
1.0.7 (2024-07-24)
1.0.6 (2024-06-21)
Create new NavStateFilter interface and separate the simple fuser and the factor-graph approach in two packages
Twist in local frame
Contributors: Jose Luis Blanco-Claraco
1.0.5 (2024-05-28)
1.0.4 (2024-05-14)
bump cmake_minimum_required to 3.5
Contributors: Jose Luis Blanco-Claraco
1.0.3 (2024-04-22)
Fix package.xml website URL
Contributors: Jose Luis Blanco-Claraco
1.0.2 (2024-04-04)
1.0.1 (2024-03-28)
1.0.0 (2024-03-19)
use odometry
add new package mola_state_estimation_simple
Contributors: Jose Luis Blanco-Claraco
0.2.2 (2023-09-08)
Changelog for package mola_state_estimation_smoother
2.4.2 (2026-06-04)
2.4.1 (2026-06-02)
2.4.0 (2026-05-11)
FIX: reset() should reinitialize gtsam
FIX: don’t let gtsam exceptions to crash the node
fix: support building in ROS2 humble with newer cmake
Merge pull request #30 from MOLAorg/bump-cmake-version bump min req cmake version to 3.22
bump min req cmake version to 3.22
Contributors: Jose Luis Blanco-Claraco
2.3.1 (2026-05-04)
Merge pull request #27 from MOLAorg/feature/ros2-integration-tests Add ROS 2 launch-testing integration tests for StateEstimationSmoother
fix missing test dep
workaround for older mola_yaml
Fix frames of reference for the test checker
Progress fixing integration test
mock test code clean up
More debug traces in python mock integration test
Add ROS 2 launch-testing integration tests for StateEstimationSmoother Two end-to-end test scenarios driven by a Python sensor mock node.
Merge pull request #26 from MOLAorg/fix/smoother-issues Fix misc smoother issues
Clarify docs and fix test noise thresholds
Remove copies of RegexCache.h and use the shared version in mola_kernel
fix: make RegexCache move-assignable after adding std::mutex
fix: guard IMU quaternion path against NaN components in fuse_imu
fix: make RegexCache::get_regex thread-safe
fix: replace ASSERT_ with descriptive exception in get_latest_state_and_covariance
fix: use monotonic counter for odometry frame IDs
fix: check both link sets before inserting in add_kinematic_factor_between
fix: make GNSS Huber threshold a configurable parameter
fix: skip BetweenFactor on first fuse_odometry call
feat: Print number of active factors in DEBUG log level
Contributors: Jose Luis Blanco-Claraco
2.3.0 (2026-04-29)
Merge pull request #23 from MOLAorg/feat/fuse-ros2-demos Add ros2 launch demo files to fuse 2 odometries
mola cli launch file: made generic for multiple odometry sources
harden frame name usage
Odometry sources: use CObservationRobotPose::sensorLabel as ‘tf’ frame name
Add ros2 launch demo files to fuse 2 odometries
Merge pull request #22 from MOLAorg/feat/refactor-mutexes Feat/refactor mutexes
Refactor to use regular mutex instead of recursive_mutex
Merge pull request #21 from MOLAorg/fix-misc Fixes for 2D motion
FIX: Planar constraints didn’t constraint roll / pitch, only tz
FIX: 2D probabilistic model used wrong XY uncertainty
Contributors: Jose Luis Blanco-Claraco
2.2.0 (2026-03-03)
Merge pull request #14 from MOLAorg/feature/use-imu-for-georef-hint Feature/use-imu-for-georef-hint
clang-format
Contributors: Jose Luis Blanco-Claraco
2.1.0 (2026-02-14)
Merge pull request #13 from MOLAorg/feat/publish-georef-on-converge Publish geo-ref on convergence
get onObservation() and has_converged_localization() method tested too
Refactor publish georef and sensor label regex fix filtering observations by sensor label regex refactor to publish georef on converged automatically fix build against older mola_kernel Fix wrong logic in GNSS fuse
remove old mola version guards
unit test: relax threshold to avoid spurious failures
Publish geo-ref on convergence add new params to yaml file
Contributors: Jose Luis Blanco-Claraco
2.0.1 (2026-01-15)
test: less strict limits to avoid random failures
cmake: Remove non-used find_package() for ament_lint_auto
Merge pull request #11 from MOLAorg/feat/improve-docs Improve docs for mola_gtsam_factors
Contributors: Jose Luis Blanco-Claraco
2.0.0 (2026-01-14)
Merge pull request #7 from MOLAorg/feature/tricycle-kinematic Add tricycle kinematics
Use bad initial pose for unit test
unit test: same conditions for different kinematic models
Copyright year bump
Add FactorTricycleKinematic
Implement twist fusion
Add twist unit test
Unit test: include tricycle tests too
Enable connection to MolaViz for console messages
converted into ament_cmake; update template yaml params file
Add templates to launch the estimator as a standalone ROS 2 node
Merge pull request #5 from MOLAorg/feature/fuse-gnss-imu-odom Refactor: new packages mola_georeferencing, mola_gtsam_factors, functional smoother state estimator
More realistic drift case: IMU helps LO
fix test: correct IMU acc simulation
Default params: more common case of starting near static
fixed imu acc gravity alignment
Add two-odometry unit test
fix error, and add support for azimuth offset
add IMU+GPS based azimuth estimation
Refactor: symbolic factor classes moved as internal smoother classes
Make mola_gtsam_factors non headers-only and rename GNSS2ENU as GnssEnu for consistency
fixed missing extrapolation steps
implement basic pose extrapolation
honor initial twist
Fixed odom+gnss fusion
implement correct auto geo-referenciation
Support fusing poses wrt map frame too
marginals for uncertainty
refactor to use Pose3 instead of P+R
initialize georef gtsam variables
Make important parameters mandatory in yaml config files
New unit test for fusing GPS+odometry
process CObservationRobotPose
One further fix for cmake
integrate code coverage in cmake
Update .h docs to match the new design
Enable code coverage
Update parameters to hold new geo-ref fields
Refactor to expose all gtsam factors into a new library ‘mola_gtsam_factors’
Contributors: Jose Luis Blanco-Claraco
1.11.1 (2025-10-20)
Update to build against MOLA>=2.1.0 with ConstPtr API
Contributors: Jose Luis Blanco-Claraco
1.11.0 (2025-10-05)
Move LocalVelocityBuffer class here from mp2p_icp repository
Contributors: Jose Luis Blanco-Claraco
1.10.0 (2025-09-07)
Fix build against gtsam>=4.3
Update copyright notice
Make unhandled sensor input topic message less verbose
Contributors: Jose Luis Blanco-Claraco
1.9.0 (2025-06-06)
State estimation interface is now raw data consumer too
FIX: Error if sensor labels were provided in config yaml file
Contributors: Jose Luis Blanco-Claraco
1.8.1 (2025-05-25)
Update copyright year
fixes for clang-tidy
Contributors: Jose Luis Blanco-Claraco
1.8.0 (2025-03-15)
const correctness
State estimation modules now are proper MOLA raw inputs, so they automatically subscribe and consume input sensors (IMU, GPS, wheels odometry)
Contributors: Jose Luis Blanco-Claraco
1.7.0 (2025-02-22)
Use more generic localization source name
make it thread safe; fix replaying extrapolated poses using past timestamps
Documentation: explain the different types of factors and kinematic models
Smoother: observe the enforce_planar_motion parameter
FIX: use last guess as initial values to improve optimization stability; expose more parameters
StateEstimationSmoother: Publish pose updates in a timely manner
Add parameter enforce_planar_motion
Fix gtsam must be a runtime depend too
Contributors: Jose Luis Blanco Claraco, Jose Luis Blanco-Claraco
1.6.1 (2025-01-10)
Shorter logger name
Contributors: Jose Luis Blanco-Claraco
1.6.0 (2025-01-03)
1.5.0 (2024-12-26)
1.4.1 (2024-12-20)
1.4.0 (2024-12-18)
1.3.0 (2024-12-11)
Start integrating GNSS observation. Added a new CLI program mola-navstate-cli for testing state fusion
Contributors: Jose Luis Blanco-Claraco
1.2.1 (2024-09-29)
1.2.0 (2024-09-16)
1.1.3 (2024-08-28)
Depend on new mrpt_lib packages (deprecate mrpt2)
Contributors: Jose Luis Blanco-Claraco
1.1.2 (2024-08-26)
1.1.1 (2024-08-23)
1.1.0 (2024-08-18)
Update test-navstate-basic.cpp: less noisy test data for more predictable results
Merge pull request #62 from MOLAorg/docs-fixes Docs fixes
Fix ament_xmllint warnings in package.xml
Contributors: Jose Luis Blanco-Claraco
1.0.8 (2024-07-29)
ament_lint_cmake: clean warnings
Contributors: Jose Luis Blanco-Claraco
1.0.7 (2024-07-24)
Fix GNSS typo
Contributors: Jose Luis Blanco-Claraco
1.0.6 (2024-06-21)
Create new NavStateFilter interface and separate the simple fuser and the factor-graph approach in two packages
Contributors: Jose Luis Blanco-Claraco
1.0.5 (2024-05-28)
1.0.4 (2024-05-14)
bump cmake_minimum_required to 3.5
Contributors: Jose Luis Blanco-Claraco
1.0.3 (2024-04-22)
Fix package.xml website URL
Contributors: Jose Luis Blanco-Claraco
1.0.2 (2024-04-04)
1.0.1 (2024-03-28)
1.0.0 (2024-03-19)
use odometry
add new package mola_state_estimation_simple
Contributors: Jose Luis Blanco-Claraco
0.2.2 (2023-09-08)
Changelog for package mola_viz
3.2.1 (2026-09-15)
mola_viz_imgui: show “???” for an unknown dataset duration (#203)
Contributors: Jose Luis Blanco-Claraco
3.2.0 (2026-08-21)
Remove stray COLCON_IGNORE from mola_viz, mola_viz_imgui Both were accidentally swept into 2c5735f5 (“declare transform_frame() last…”), unrelated to that commit’s actual content. With colcon no longer building them from source, any package depending on mola_viz (e.g. mola_mapper’s exec_depend) falls back to the stale public ros-<distro>-mola-viz release, which pulls in a matching stale ros-<distro>-mola-kernel via apt – and since /opt/ros/<distro>/include is searched before the workspace install prefix, that stale mola_kernel silently shadows the freshly-built one, breaking any translation unit that needs a recent mola_kernel API (ChildLoggerName/child_loggers()).
Merge pull request #192 from MOLAorg/feat/map-frame-gauge-change Support re-expressing estimator and pose-list state in a new frame
Merge remote-tracking branch ‘origin/feat/map-frame-gauge-change’ into feat/map-frame-gauge-change
mola_kernel: declare transform_frame() last; test SearchablePoseList frame change Appending the new optional virtual only grows the vtable, whereas the previous mid-list position shifted the slot index of the three virtuals after it, breaking any prebuilt NavStateFilter plugin. A note asks that future optional virtuals also go at the end. Adds regression coverage for SearchablePoseList::transform_left_multiply() in both storage modes: that the kd-tree follows the transformed poses (verified to fail if the spatial index is left stale), that the empty and identity cases are no-ops, and that the id-keyed lookup survives.
Merge branch ‘develop’ into feat/map-frame-gauge-change
Contributors: Jose Luis Blanco-Claraco
3.1.1 (2026-08-10)
3.1.0 (2026-08-06)
Merge pull request #187 from MOLAorg/feat/incremental-point-cloud-kdtree-bake Bake IncrementalPointCloud’s k-d tree index (mm-ipc-bake-kdtree)
changelog
Merge pull request #180 from MOLAorg/feat/combobox-fixed-width GUI: add optional fixed_width to ComboBox (both backends)
Add optional fixed_width to ComboBox, honored by both GUI backends Without it, ImGui::Combo defaults to an item width that scales with the window, so short option lists visibly balloon in wide sub-windows (seen when packing a ComboBox next to a checkbox in a Row). 0 keeps each backend’s current auto-sizing behavior.
Contributors: Jose Luis Blanco-Claraco
feat: ComboBox GUI widget gained an optional fixed_width parameter (both backends).
Contributors: Jose Luis Blanco-Claraco
3.0.0 (2026-07-17)
Merge branch ‘feat/imviz-metric-plots’ into develop
Remove deprecated nanogui-specific VizInterface API create_subwindow(), enqueue_custom_nanogui_code(), subwindow_grid_layout() and subwindow_move_resize() have no remaining callers now that create_subwindow_from_description() and enqueue_custom_gui_code() cover their use cases on both backends.
Merge pull request #172 from MOLAorg/feat/imviz-metric-plots feat(mola_viz_imgui): add metric time-series plot windows
feat(mola_viz_imgui): add metric time-series plot windows Adds a backend-agnostic register_metric()/push_metric() API to VizInterface (guarded by MOLA_KERNEL_VIZ_HAS_METRICS) so any MOLA module can stream timestamped scalar values to live, autoscrolling plot windows opened from a new “Plots” menu in the mola_viz_imgui (ImGui/ImPlot) backend. The nanogui MolaViz backend implements the API as a no-op, mirroring the set_menu_bar precedent. The Plots menu also gives the Console window its first working close/reopen toggle. Vendors ImPlot as a submodule under mola_viz_imgui/3rdparty/implot.
Merge pull request #165 from MOLAorg/imgui-window-icon feat: mola viz imgui set window icon
feat: mola viz imgui set window icon
Merge pull request #162 from MOLAorg/feat/viz-decay-lookat-frame-aware feat: frame-aware parentFrame for decay clouds and camera look-at
fix: decay eviction uses per-entry container; look-at fails on missing frame Four reviewer findings, all confirmed valid: 1. VizInterface.h comment: add update_viewport_look_at() to the list of APIs covered by MOLA_KERNEL_VIZ_HAS_MOVABLE_FRAMES (it was omitted). 2/3. Decay cloud eviction (both backends): the eviction path inside insert_point_cloud_with_decay() was removing the oldest cloud from the current insertion’s container rather than the container that cloud was originally placed in. If parentFrame ever changes between calls the wrong container would be used, leaking the cloud in the scene. Fix: add a container member to DecayingCloud and store the owning container at insert time; use it at eviction time. 4/5. Look-at frame not found (both backends): when parentFrame is non-empty but the frame node does not yet exist in the scene, the code was silently falling back to treating the raw local-frame coordinates as world-space and moving the camera to the wrong position. Fix: return false so the camera is not moved until the frame node is present.
feat: extend VizInterface for frame-aware decay clouds and camera look-at insert_point_cloud_with_decay() and update_viewport_look_at() now both accept an optional parentFrame argument (same semantics as the existing parentFrame on update_3d_object()): when non-empty, the backend looks up the named movable frame node and composes its current scene pose with the supplied point before inserting the cloud / moving the camera. This lets callers (e.g. mola_lidar_odometry) pass a local-odom-frame point while the camera and transient clouds still end up at the correct world-space position when a central mapper (mola_mapper_3d) is continuously repositioning the frame node. Both backends (MolaViz / MolaVizImGuiCore) and the MolaVizImGui forwarder are updated. The MOLA_KERNEL_VIZ_HAS_MOVABLE_FRAMES feature macro already covers both new parameters; no additional macro is added.
Merge pull request #160 from MOLAorg/feat/viz-with-movable-frames feat: viz with movable frames
feat: viz with movable frames
Merge pull request #151 from MOLAorg/fix/imgui-slider fix: imgui slider
fix: imgui slider
Merge pull request #146 from MOLAorg/fix-upgrade-points-classes fix: upgrade not to use deprecated mrpt2 point cloud classes
fix: upgrade not to use deprecated mrpt2 point cloud classes
Contributors: Jose Luis Blanco Claraco, Jose Luis Blanco-Claraco
2.9.0 (2026-05-11)
Merge pull request #112 from MOLAorg/feat/dear-imgui-viz Introduce Dear ImGui alternative viz module
chore: misc improvements
Introduce Dear ImGui alternative viz module
Merge pull request #143 from MOLAorg/bump-cmake-version bump min req cmake version to 3.22
bump min req cmake version to 3.22
Contributors: Jose Luis Blanco-Claraco
2.8.0 (2026-04-29)
2.7.0 (2026-04-22)
2.6.1 (2026-04-02)
Merge pull request #116 from MOLAorg/update-rds-gui Update RDS gui creation to new backend agnostic API
Add missing nanogui layout
Contributors: Jose Luis Blanco-Claraco
2.6.0 (2026-03-12)
Merge pull request #113 from MOLAorg/feat/kf-map-view-vectors Feat:kf map view vectors filter for NN search
comments formatting
Merge pull request #109 from MOLAorg/feat/support-imgui Feature: GUI backend agnostic API in mola_kernel (Step towards supporting imgui)
safer multithread
Several visual and safety fixes in the new GUI interface
Use safer livestring registry
minor fixes
Add support for menu bars
MolaViz implements the new backend agnostic API
Merge pull request #107 from MOLAorg/fix/viz-decay-clouds Fix/viz-decay-clouds
Refactor decay-clouds so they are invariant to wallclock incoming speed
Update coyright notes
fix clang-tidy warnings
Contributors: Jose Luis Blanco Claraco, Jose Luis Blanco-Claraco
2.5.0 (2026-02-14)
Fix: mola_viz lidar preview didn’t filter Inf ranges in stats
Merge pull request #99 from MOLAorg/feat/ros2-bridge-pub-geographic ROS2 bridge: publish geographic poses too
ros2 bridge: use geographic_msgs, store the last georeference info internally, and publish georef poses merge of these commits: - Enable many more clang-tidy checks - lint clean - implement publishing georeferenced poses - mola-viz: fix potential crash on edge case with all points having NaN value - FIX: potential crash if no MapServer is present and map services are called
Contributors: Jose Luis Blanco-Claraco
2.4.0 (2025-12-28)
Fix build against upcoming mrpt 2.15.4
Prepare for deprecated mrpt::maps classes towards mrpt 3.0.0
viz pointclouds preview: fix missing uint8_t fields
Contributors: Jose Luis Blanco-Claraco
2.3.0 (2025-12-15)
Fix: missing uint fields stats in PCD preview GUI in mola_viz
mola-viz: fix NaNs in range of each point channel preview window
Viz: Fix handling multi-line messages in the UI terminal
Contributors: Jose Luis Blanco-Claraco
2.2.1 (2025-11-08)
2.2.0 (2025-10-28)
format
Upgrade to use the upcoming MRPT 2.15 API for CGenericsPointsMap
Contributors: Jose Luis Blanco-Claraco
2.1.0 (2025-10-20)
FIX: Show correct sensor rate in Hz when visualizing with a decimation
Fix clang-tidy warnings
Contributors: Jose Luis Blanco-Claraco
2.0.0 (2025-10-13)
Merge pull request #93 from MOLAorg/feature/better-lio Changes for new LIO
Fix warnings
fix build against old mrpt versions
Implement removal of decayed clouds
MolaViz: Add method clear_all_point_clouds_with_decay()
MolaViz: Add support for inserting clouds with decay_time
fix clang-format
Allow extra parameters in mola_viz per-sensor preview windows
MolaViz: show min/max intensity in input sensor point clouds
Remove old code that was needed to support very old MRPT versions
Contributors: Jose Luis Blanco-Claraco
1.9.1 (2025-07-07)
1.9.0 (2025-06-06)
1.8.1 (2025-05-28)
1.8.0 (2025-05-25)
Implement new virtual Viz methods
Update copyright year
Contributors: Jose Luis Blanco-Claraco
1.7.0 (2025-05-06)
Metric maps can now be rendered as semitransparent pointclouds
Contributors: Jose Luis Blanco-Claraco
1.6.4 (2025-04-23)
modernize clang-format
Contributors: Jose Luis Blanco-Claraco
1.6.3 (2025-03-15)
1.6.2 (2025-02-22)
1.6.1 (2025-02-13)
1.6.0 (2025-01-21)
1.5.1 (2024-12-29)
1.5.0 (2024-12-26)
Drop dependency on mrpt-gui in kernel by abstracting MolaViz subwindow layout operations
MolaViz: show package name in GUI windows
Contributors: Jose Luis Blanco-Claraco
1.4.1 (2024-12-20)
1.4.0 (2024-12-18)
1.3.0 (2024-12-11)
mola_viz: Show IMU data in the GUI too
Contributors: Jose Luis Blanco-Claraco
1.2.1 (2024-09-29)
1.2.0 (2024-09-16)
mola_viz: do not add a XY ground grid by default to all GUIs
Contributors: Jose Luis Blanco-Claraco
1.1.3 (2024-08-28)
Depend on new mrpt_lib packages (deprecate mrpt2)
Contributors: Jose Luis Blanco-Claraco
1.1.2 (2024-08-26)
1.1.1 (2024-08-23)
1.1.0 (2024-08-18)
Update clang-format style; add reformat bash script
Merge pull request #62 from MOLAorg/docs-fixes Docs fixes
Fix ament_xmllint warnings in package.xml
Contributors: Jose Luis Blanco-Claraco
1.0.8 (2024-07-29)
ament_lint_cmake: clean warnings
Contributors: Jose Luis Blanco-Claraco
1.0.7 (2024-07-24)
Viz interface: add API for rotate camera
Contributors: Jose Luis Blanco-Claraco
1.0.6 (2024-06-21)
1.0.5 (2024-05-28)
viz: fix mismatched free/delete inside nanogui layout
Contributors: Jose Luis Blanco-Claraco
1.0.4 (2024-05-14)
bump cmake_minimum_required to 3.5
MolaViz: BUGFIX: shared_ptr were captured by lambdas, delaying proper dtors. Replaced by weak_ptr’s
Contributors: Jose Luis Blanco-Claraco
1.0.3 (2024-04-22)
Fix package.xml website URL
Contributors: Jose Luis Blanco-Claraco
1.0.2 (2024-04-04)
1.0.1 (2024-03-28)
1.0.0 (2024-03-19)
ROS2 launch demos
use new mrpt GPS covariance field
visualize sensor pose
mola_kernel: new UI interface for datasets
mola-viz: show image channel of RGBD observations
Fix sensorPose on lidar preview
Viz: show GPS data
mola_viz: add custom icon
viz: more options to visualize RGBD camera observations
viz API: add enqueue_custom_nanogui_code()
viz console: add fading effect
mola_viz: show console messages
Correct usage of mola:: namespace in cmake targets
copyright update
mola_viz: support visualizing velodyne observations
Add look_at() viz interface
Fewer mutex locking()
reorganize as monorepo
Contributors: Jose Luis Blanco-Claraco
0.2.2 (2023-09-08)
Initial public release.
Contributors: Jose Luis Blanco-Claraco
Changelog for package mp2p_icp_core
2.14.0 (2026-09-05)
Point matchers (Matcher_Points_DistanceThreshold, Matcher_Points_Blend): fixed a nondeterministic pairing order caused by parallel reduction depending on TBB thread scheduling; the correspondence list is now a function of the input alone, regardless of thread count.
Solver_GaussNewton: the robust kernel now receives a whitened residual (using the existing pair weight as the whitening factor) instead of a raw metric or Mahalanobis norm, so robustKernelParam means the same number of sigmas for every pair type. Bit-identical for pipelines using default weights.
GravityPrior: report the fraction of the final rotational information the prior actually contributed, via new gravity_information_share field in OptimalTF_Result and Results (negative when no prior was given); this value is now also persisted across serialization (Results format v1) and reset at the start of each solve.
New FilterPlanePatches: extracts large planar patches (equation, centroid, area, point count) into metric_map_t::planes, complementing FilterEdgesPlanes’ per-point labeling. Deterministic greedy extraction seeded by per-point normals. metric_map_t serialization goes to v6.
FilterVoxelReduction: made the downsampling order-independent (selection no longer depends on input point order) and tightened bounds on range_min and normal_agreement_deg.
Contributors: Jose Luis Blanco-Claraco
2.13.1 (2026-08-25)
Merge pull request #94 from MOLAorg/feat/mm-filter-generators-create-layer mm-filter: create new metric map layers via generators:
Fix stale doc URLs missing the mp2p_icp_core path segment These sm2mm/mm-filter demo comments and the sm2mm.h docstring still pointed at pre-split paths (apps/sm2mm, apps/mm-filter, top-level demos/), left over from the mp2p_icp_core/mp2p_icp_viz package split. Same class of issue as flagged in review for the new demo added in this branch; fixing the other pre-existing occurrences found by a repo-wide search.
Address review: fix demo URL, doc precedence, and unresolved formula check - Fix stale doc link in the new demo (missing mp2p_icp_core path segment). - CreateMetricMapFromDefinition(): docs said “exactly one” of the two definition sources must be given, but the implementation actually prefers metricMapDefinitionIniFile if both are non-empty; reword to match. - Generator::createTargetLayerIfNeeded(): call Parameterizable::checkAllParametersAreRealized() before creating the map, matching the guard Generator::process() already has. Without it, a metric_map_definition formula (e.g. “$f{…}”) referencing a variable that’s never bound in this code path (createTargetLayerIfNeeded has no attached ParameterSource) would silently serialize as its unresolved 0.0 placeholder instead of raising a clear error.
Let mm-filter pipelines create new metric map layers via generators: mm-filter operates on an already-built .mm file, so it had no way to instantiate a brand-new layer of an arbitrary mrpt::maps::CMetricMap subclass (e.g. mola::KeyframePointCloudMap): that logic lived inside Generator, and only ran as a side effect of processing an observation, which mm-filter does not have. Factor the map-creation logic (TSetOfMetricMapInitializers + CMultiMetricMap, driven by a metric_map_definition YAML block) out of Generator::implProcessCustomMap() into a standalone mp2p_icp_filters::CreateMetricMapFromDefinition(), and expose it via a new Generator::createTargetLayerIfNeeded(), callable without any observation at hand. mm-filter now optionally parses a generators: section (same schema as sm2mm) and uses it only to pre-create each generator’s target_layer if missing, before running filters:. A plain FilterMerge step can then insert an existing point cloud layer into it, closing the gap reported in MOLAorg/mola#147.
Add feature-detection macro for nn_visit_pt2pl_candidates() Downstream code (e.g. mola) needs to build against both this and older mp2p_icp releases still distributed via ROS binary repos, which predate NearestPlaneCapable::nn_visit_pt2pl_candidates() and the PlaneCandidate/plane_candidate_visitor_t types.
Contributors: Jose Luis Blanco Claraco, Jose Luis Blanco-Claraco
2.13.0 (2026-08-21)
Merge pull request #91 from MOLAorg/feat/ndt-blend-matcher Add Matcher_NDT_Blend: a smooth alternative to the nearest-plane argmin
Restore include ordering in the matcher registry
Add Matcher_Points_Blend and Matcher_Points_KnnPlane Two more correspondence rules, at opposite ends of the same axis, so that the question “does the discreteness of the correspondence rule drive the sensitivity” can be measured rather than argued. Matcher_Points_Blend is the point-based counterpart of Matcher_NDT_Blend: the target is the distance-weighted mean of the map points in a radius instead of the nearest one, so it moves continuously as the query crosses the perpendicular bisector between two map points. temperature 0 runs the very same nn_single_search() query as Matcher_Points_DistanceThreshold with pairingsPerPoint 1, so it reproduces it exactly. The neighborhood is a radius query and never a fixed-k one: a point entering or leaving a top-k list is a harder flip than the one being removed. Its intrinsic cost is that a weighted mean of surface points is pulled toward the interior of the neighborhood, so the temperature has to be chosen against the map’s point spacing. Matcher_Points_KnnPlane goes the other way: k nearest map points, a least-squares plane through them, and three hard gates. Every gate is a constant or a function of a static property of the measurement, so nothing in it reads back the registration’s own quality. The plane is fitted by solving A x = -1 with a column-pivoting Householder QR in single precision rather than by an eigen fit, because the two are not numerically the same on near-degenerate neighborhoods and this matcher exists to reproduce a protocol faithfully. One consequence worth knowing: that form cannot represent a plane through the origin. Two hazards found while writing them, both silent: - nn_radius_search() applies a small hard cap on the number of results whenever maxPoints is nonzero, ranking candidates and keeping the best few. Only maxPoints 0 keeps a radius query a radius query, so that is what the blend passes, and the parameter that could change it is documented as such. - A k-NN query asked for more neighbors than the map holds can still return exactly k, padding the tail by repeating an earlier point under a fabricated zero distance. The “reject if fewer than k were found” gate therefore cannot be implemented as a size check; each neighbor is validated against its own coordinates instead. Matcher_NDT_Blend gains optional weight-distribution statistics, gated on MP2P_ICP_BLEND_STATS, reporting how many candidates a query really combines, and now rejects negative temperature and searchRadius rather than silently falling back to the unblended path.
Formatting, and keep the zero-temperature bounding-box test identical too At temperature 0 the search radius now reverts to distanceThreshold, so the bounding-box early-return matches Matcher_Point2Plane as well, not just the per-point query. Behavior is unchanged wherever the boxes overlap, which is every case exercised so far, but the control is now exact by construction.
Add Matcher_NDT_Blend: a smooth alternative to the nearest-plane argmin Matcher_Point2Plane resolves its candidate planes with a hard argmin, so an arbitrarily small pose change can swap the winner and move the residual by the full disagreement between the two candidates. Matcher_NDT_Blend keeps the same inputs and emits the same one point-to-plane pairing per local point, but takes a likelihood-weighted combination of the candidates instead of the best one, so the residual varies continuously with the pose. Solvers are unchanged. Candidates are read through a new NearestPlaneCapable::nn_visit_pt2pl_candidates(), whose default implementation reports only the best match, so maps that expose just an argmin keep working. Three details carry the behavior: - temperature 0 takes the plain nn_search_pt2pl() path and therefore reproduces Matcher_Point2Plane exactly, which makes it a usable control. - The weight fades to zero with zero derivative at searchRadius, so a candidate entering or leaving the window does so continuously; a hard cutoff would reintroduce the discontinuity at the window edge instead. - Normals are combined through their outer products rather than as vectors. The point-to-plane cost is invariant to a plane’s normal sign, and this keeps the blend invariant too; a vector average would instead depend on each map cell’s own sign bookkeeping. The cost is that two exactly perpendicular candidates carrying exactly equal weight switch rather than interpolate, which no single plane could represent anyway. Defaults reproduce the previous behavior, so no shipped pipeline changes.
Merge pull request #90 from MOLAorg/feat/decimate-adaptive-dynamic-budget FilterDecimateAdaptive: dynamic point budgets, and a bound on the voxel stride
Clamp the stride-derived budget at the input point count An arbitrarily small maximum_voxel_stride made ceil(nVoxels/stride) exceed uint32_t, and the narrowing conversion is undefined there. The input is the real ceiling anyway, since no decimation method can emit more points than it was given. Strides below 1 stay legal: the methods that take several points out of one voxel can honor them.
FilterDecimateAdaptive: dynamic point budgets, and a bound on the voxel stride The point budget and the voxel size were loaded with MCP_LOAD_*, which parses a YAML scalar up to its first non-numeric character and keeps the truncated value without complaint. A budget written as an expression therefore became something else entirely, silently. Both are now declared parameters, so they accept formulas over the pipeline’s variables like the range and map-size parameters already do. The sampling walk uses a stride of nVoxels/desired_output_point_count and stops as soon as the count is reached, so a stride above 1 means only one in every stride occupied cells is ever visited. An absolute point count thus expresses very different sampling densities depending on how many occupied cells the input happens to have, which is a property of the scene, the sensor and the voxel size rather than of the configuration. The new optional maximum_voxel_stride bounds that ratio directly. It only ever raises the effective count, so the absolute budget keeps acting as a floor and leaving it unset preserves today’s behavior exactly. Also: size the outputs vector up front. Declaring a dynamic parameter stores a pointer to its target field, and growing the vector afterwards would dangle the ones already declared. A DEBUG line now reports nVoxels, the effective budget, the stride and the emitted count per output, so a configuration can be checked against its actual input instead of assumed.
Merge pull request #89 from MOLAorg/feat/cov2cov-ambiguity-gating Matcher_Cov2Cov: optional range-adaptive matching distance and ambiguity gate
Merge branch ‘develop’ into feat/cov2cov-ambiguity-gating
Remove the ambiguity gate from MatchingDistanceProfile firstToSecondDistanceMin/firstToSecondMinRange were not yet justified by results (regressed translation error ~62% on a held-out sequence relative to the range-adaptive distance alone). Drop the fields, Matcher_Cov2Cov params, NearestPointWithCovCapable’s guard against them, and the corresponding test coverage, keeping only the range-adaptive matching distance.
Keep nn_search_cov2cov() source-compatible with older map implementations The flat-threshold overload goes back to being the pure virtual, and the MatchingDistanceProfile one becomes a non-pure overload whose default implementation forwards to it. A map class written against an earlier release therefore keeps compiling, overriding and behaving exactly as before, which is what the downstream CI jobs need: they resolve mola_metric_maps to the last released binary package, which is older than this source tree. The forwarding default refuses, rather than silently ignores, a profile such an implementation cannot honor: a range-adaptive distance or an active ambiguity gate throws instead of quietly degrading to a flat threshold. Adds MP2P_ICP_HAS_MATCHING_DISTANCE_PROFILE so downstream packages can detect the new API. Since MatchingDistanceProfile.h is an entirely new header, a plain __has_include() settles it for consumers; the macro is what survives if the struct later grows members. Also documents the name-hiding consequence: a derived class declaring only one of the two overloads hides the other for calls on that derived type. Harmless for the matchers, which always dispatch through a base reference.
Matcher_Cov2Cov: optional range-adaptive matching distance and ambiguity gate Introduce mp2p_icp::MatchingDistanceProfile, the acceptance criteria used by NearestPointWithCovCapable::nn_search_cov2cov(). It replaces the flat float max_search_distance argument, and is implicitly constructible from a float, so every existing caller keeps compiling and behaving as before. Two opt-in refinements over a single flat distance, both disabled by default: - Range-adaptive distance: thresholdFar, thresholdKneeRange and thresholdTransitionWidth turn the acceptance distance into a logistic function of the query point’s range from the sensor. Map point density falls off with range, so one flat threshold is loose near the sensor and tight far away. - Ambiguity test: firstToSecondDistanceMin rejects a correspondence whose runner-up candidate is within that ratio of the winner’s distance, i.e. the match is too close to call. firstToSecondMinRange restricts the test to beyond a given range, leaving the dense near field, where the runner-up is the same surface seen again, untouched. All five are declared with DECLARE_PARAMETER_OPT so they accept dynamic formulas like “3.0*ADAPTIVE_THRESHOLD_SIGMA”, exactly as threshold does. A static YAML load would convert such a string by stopping at the first non-numeric character and silently yield a fixed value in meters. No shipped pipeline enables either refinement; defaults reproduce the previous behavior bit for bit, including the k=1 KD-tree query and no per-point range computation.
Merge pull request #88 from MOLAorg/fix/matcher-param-formula-parsing fix: load matcher/filter distance parameters as dynamic formulas
fix: load matcher/filter distance parameters as dynamic formulas Several numeric parameters that pipelines legitimately want to express as formulas were read with MCP_LOAD_REQ/MCP_LOAD_OPT, a static YAML load. mrpt::containers::yaml::as<double>() truncates a string at the first non-numeric character, so “2.0*ADAPTIVE_THRESHOLD_SIGMA” was silently turned into the constant 2.0, with no warning and no error, and was never re-evaluated afterwards. Since ADAPTIVE_THRESHOLD_SIGMA is the output of the LO adaptive-threshold controller, the affected parameters were left frozen at a value that is not even in the right units. Switched to DECLARE_PARAMETER_*, the same macros the equivalent parameters of the other matchers already use: * Matcher_Point2Line::distanceThreshold. Same name and same role as Matcher_Point2Plane::distanceThreshold, which is dynamic and is set to “1.0*ADAPTIVE_THRESHOLD_SIGMA” in the shipped lidar3d-ndt pipeline. * Matcher_Adaptive::absoluteMaxSearchDistance, minimumCorrDist and planeMinimumDistance: all distances in meters gating pairing acceptance. * FilterCurvature::max_cosine, min_clearance and max_gap, which the sibling GeneratorEdgesFromCurvature already declares dynamically. Also added checkAllParametersAreRealized() to Matcher_Point2Line, Matcher_Adaptive and FilterCurvature, so an unrealized formula now fails loudly instead of running with a stale value. Tests: test-mp2p_matcher_pt2pt_parameterizable now covers Point2Plane, Point2Line and Adaptive; test-mp2p_matcher_pt2ln gets an end-to-end check that the formula actually gates pairings across two realize() calls; new test-mp2p_FilterCurvature. All of them fail against the previous code.
Merge pull request #87 from MOLAorg/perf/decimate-adaptive-flat-voxel-index-array Store voxel point indices in one flat array (recovers the FilterDecimateAdaptive regression)
Store voxel point indices in one flat array PointCloudToVoxelGrid kept a std::vector per voxel, that is, one heap allocation per voxel, rebuilt from scratch for every processed cloud. The point indices now live in a single contiguous array, with each voxel holding just an offset and a count into it, and are stored as 32 bit to halve the memory traffic. FilterDecimateAdaptive also merges all of its per-thread grids in one single call, so that the flat array is laid out once instead of once per merged grid. This matters because the thread-local grids accumulate over successive runs, and most of them are empty on any given one. The output is unchanged: voxel contents and their canonical ordering are the same as before.
Merge per-thread voxel grids in FilterDecimateAdaptive (#86) * Merge per-thread voxel grids in FilterDecimateAdaptive Under TBB the input cloud is binned in parallel into one grid per thread, but the voxel key is global, so a single spatial voxel was left split into one fragment per thread that saw points in it. The fragments were then visited as if they were independent voxels. That had three consequences: - The output depended on how TBB happened to split and steal work, so two identical runs gave different decimated clouds. - Decimation emitted up to one representative per thread per voxel instead of one per voxel, so the output was denser and less uniform than requested. - minimum_input_points_per_voxel was applied per fragment, so a voxel legitimately above the threshold was dropped whenever its points were split across threads. For a rotating lidar, whose consecutive point indices sweep azimuth, this affected most voxels. Reassemble the per-thread grids by voxel key before sampling, into an owning grid, which keeps voxel_t a plain non-owning span. Voxel point indices are then sorted so the contents no longer depend on the binning order. The voxel list is also given a canonical order, by the first input point of each voxel, in both the parallel and the sequential paths. The resampling walks this list with a stride, so which voxels reach the output would otherwise depend on hash map traversal order, which is an implementation detail of the map type. Adds regression tests over a cloud that revisits voxels at distant input indices, as a rotating lidar does. All three checks fail before this change. * Apply clang-format * Test mergeFrom() directly, independently of worker count The end-to-end fragmentation checks only exercise the merge when TBB actually runs the blocks concurrently, so on a low-core machine they would pass without touching it. Bin a cloud in three unequal pieces, merge, and assert the result equals binning it in one pass. * Require a matching map type in mergeFrom(), and cover both The four-way dispatch handled combinations that cannot occur: only FilterDecimateAdaptive merges grids, and it always uses robin maps. Assert the two agree and keep the two reachable branches. The merge test now runs over both backing map types and asserts they produce the same voxel contents, which is what the canonical voxel ordering is built from.
update robin-map to latest version (avoid cmake deprecation)
Merge pull request #85 from MOLAorg/fix/decimate-voxels-maybe-uninitialized-warning fix: spurious -Wmaybe-uninitialized in FilterDecimateVoxels::initialize_filter
fix: spurious -Wmaybe-uninitialized in FilterDecimateVoxels::initialize_filter Both optional grid members were unconditionally .reset() before .emplace()-ing only one of them, so the one about to be (re)constructed was torn down twice in quick succession (once explicitly, once inside emplace()). GCC 15’s flow analysis loses track of the pimpl’s function-pointer deleter across that redundant double-teardown and warns on an unrelated unique_ptr destructor. Only reset the other optional, which was the only thing the explicit reset() was ever needed for. Verified by compiling the function in isolation before/after: warning count goes from 1 to 0, no new warnings, and the pre-existing test suite (112/112) is unaffected.
Merge pull request #83 from MOLAorg/feat/decimate-adaptive-multi-output FilterDecimateAdaptive: several output layers from one voxelization pass, plus decimate_method
FilterDecimateAdaptive: several output layers from one voxelization pass, plus decimate_method Two independent additions to FilterDecimateAdaptive: 1) An optional “outputs” YAML sequence, each entry holding its own output_pointcloud_layer + desired_output_point_count. All of them are sampled from ONE voxelization pass (the dominant cost), each walking the shared voxel list with its own stride. The single-output keys keep working exactly as before, and are mutually exclusive with “outputs”. This lets a consumer obtain a dense cloud for its local map and a sparse one for ICP without paying for two full passes. Chaining two filters also computed the second cloud from already-decimated voxel statistics rather than from the full scan. Measured on test-mp2p_gicp_pipeline_benchmark (new env var MP2P_BENCH_SINGLE_DECIMATION=1 selects the single-pass variant there), 1st-pass filtering drops from ~15.0 ms to ~13.0 ms per 100k-point scan, with unchanged ICP quality and recovered pose. 2) Support for decimate_method, as in FilterDecimateVoxels. The DecimateMethod enum moves to its own header, mp2p_icp_filters/DecimateMethod.h, now shared by both filters (FilterDecimateVoxels.h includes it, so its users are unaffected). Since this filter revisits voxels in as many rounds as needed to reach the requested point count, the methods behave differently here: - FirstPoint (default, previous behavior) and RandomPoint take successive points out of each voxel, in insertion order or from a random per-voxel offset. - ClosestToAverage and VoxelAverage summarize the whole voxel and hence emit one point per voxel only, so the output cannot exceed the number of valid voxels. VoxelAverage synthesizes points, so per-point fields are not propagated. Their per-voxel results are precomputed once and reused by all output targets. Unit tests cover the multiple outputs, the mutually-exclusive parameters and the four decimation methods.
Merge pull request #82 from MOLAorg/feat/filter-transform-pointcloud Add FilterTransformPointCloud: rigidly transform a point-cloud layer by a pose or its inverse
test: cover view-direction field rotation in FilterTransformPointCloud Addresses CodeRabbit nitpick: the existing tests only exercised XYZ transform, never the rotateViewDirectionFields() path the filter also runs. Mirrors the fixture pattern already used in test-mp2p_FilterMerge_view.cpp.
fix: apply clang-format-14 to test-mp2p_FilterTransformPointCloud.cpp CI’s pinned clang-format-14 wants different alignment on the pose assignment line than my local (newer) clang-format produced.
Add FilterTransformPointCloud: rigidly transform a point-cloud layer by a pose or its inverse Some odometry systems (e.g. DLIO) voxelize incoming scans after transforming them into the map/world frame, so voxel membership is anchored to the map rather than to the vehicle’s instantaneous local frame. No existing filter in this library exposes that as a composable building block: FilterMerge only inserts local points into an existing target map (one direction, and tied to insertObservation()), so there was no way to get a plain, freshly transformed point-cloud layer usable as input to another filter (e.g. FilterDecimateAdaptive), nor any way to transform back by a pose’s inverse. FilterTransformPointCloud fills that gap: input layer -> output layer, replacing each point p_i by pose (+) p_i (or pose^-1 (+) p_i if invert_pose is set), reusing CPointsMap::insertAnotherMap() plus the same rotateViewDirectionFields() call FilterMerge already relies on to keep view-direction fields consistent.
fix format
Add robust_max_range(): percentile-based, outlier-robust point cloud extent A plain bounding-box max norm is dominated by a single spurious far return. Observed on Livox sensors (TIERS dataset): specular-reflection artifacts hundreds of meters away in an otherwise <20 m scene inflate any consumer’s observation-radius estimate 10-40x, which then starves a downstream range filter or voxel grid of the real, near-field points. robust_max_range() returns a percentile of the per-point range (default 0.95) instead of the raw maximum, computed with std::nth_element (O(n) average, no full sort). Not wired into any consumer yet; that is a separate follow-up.
Merge pull request #80 from MOLAorg/fix/viz-skip-non-finite-points fix: skip non-finite points when rendering a point map layer
fix: also drop non-finite points on the map’s own-renderer viz path get_visualization_map_layer() returns early when the layer is not a CPointsMap, or when keep_original_cloud_color asks for the map’s own colors: both delegate to map->getVisualizationInto(). That return happens before the source-map filtering added previously, so a map holding blank (NaN) storage slots could still hang the renderer through this path. Filtering the source beforehand is not possible here: the map draws itself, so there is no input cloud, and in the non-CPointsMap case there is nothing to filter either. Swapping in a filtered copy would discard the custom renderer that this path exists to use. The non-finite points are therefore dropped from the already-built render objects, in place, in the same loops that already walk them to apply the point size. Each surviving point keeps its own color, since colors are per point in the render object.
fix: skip non-finite points when rendering a point map layer get_visualization_map_layer() copied the raw point buffers of a map layer into a CPointCloud / CPointCloudColoured verbatim. Map classes that recycle storage slots expose slots holding no point: mola::IncrementalPointCloud blanks them to NaN, precisely so that generic code walking the inherited CPointsMap buffers does not resurrect evicted geometry. A single non-finite coordinate is enough to hang the GUI thread: MRPT’s LOD octree splits a node at the mean of its points, so the mean becomes NaN, every comparison against it is false, all points land in the same child and the recursive split repeats identically forever. Each level costs two passes over the whole cloud, so it presents as a frozen viewer rather than a crash. It only triggers once a cloud exceeds OCTREE_RENDER_MAX_POINTS_PER_NODE (1e6 by default), which is why it appears at one reproducible point of a mapping run. The source map is filtered, not the render object, because recolorize3Dpc() skips colorization unless both hold the same number of points. Maps whose points are all finite (the usual case) are passed through untouched, with no copy.
Merge pull request #78 from MOLAorg/feature/serialize-gravity-prior-in-icplog Record the GravityPrior in .icplog files
Record the GravityPrior in .icplog files mp2p_icp::GravityPrior was passed to ICP::align() but never serialized, so the verticality observation the solver actually received could not be recovered from a log afterwards. That matters because its sigma is not necessarily the configured one: callers may widen it at run time (mola_lidar_odometry’s adaptive_sigma does), and the only way to see the effective value was to re-run the whole dataset with debug-level logging. - Add CArchive operators for GravityPrior, plus DECLARE_TTYPENAME_CLASSNAME, which std::optional serialization requires. - Add LogRecord::gravityPrior, bumping the serialization version 2 -> 3. Older logs still load: the new field is read only when version >= 3. - Populate it in ICP::align(), next to the existing motion prior.
fix: remove racy per-point pt2pt weight path in Gauss-Newton solver (#77) * fix: remove racy per-point pt2pt weight path in Gauss-Newton solver Pairings::point_weights fed a sequential run-length-encoded cursor that optimal_tf_gauss_newton.cpp consumed from inside a tbb::parallel_reduce lambda captured by reference. Concurrent threads processing different point sub-ranges raced on the same shared cursor state, and the cursor was never reset across inner Gauss-Newton iterations either, making the per-layer weight: in pointLayerMatches silently unreliable in TBB builds. visit_correspondences.h had the same cursor pattern, though it was safe there since it only ever runs sequentially. The per-layer weighting granularity was never exercised with differing weights in any real pipeline (every pointLayerMatches block in-tree uses a single layer pair), so instead of making the cursor thread-safe, this drops per-point/per-layer pt2pt weighting entirely. All pt2pt pairs now use the single PairWeights::pt2pt scalar, matching every other pairing type. Matcher_Points_Base keeps pointLayerMatches for selecting which local/global layers to pair, just without a per-entry weight. Pairings serialization bumped to v3; older archives are still read correctly (the removed field is skipped). * docs: fix stale pointLayerMatches doc comment in Matcher_Points_Base Flagged by CodeRabbit on #77: initialize()’s docstring still described pointLayerMatches as relative weights after the per-layer weighting removal; the class member’s own docstring had already been updated.
feat: yaw-free rank-2 gravity prior for the Gauss-Newton solver (#76) Adds an optional gravity (“verticality”) observation, independent of the existing SE(3) prior, that constrains only the two tilt DOFs and leaves rotation about gravity and all three translations exactly free. Residual: r(R) = B^T (R u_body) in R^2, with B an orthonormal basis of the plane orthogonal to up_map, weighted isotropically by 1/sigma^2. The isotropy is what makes the cost invariant to rotation about gravity: the induced 6x6 information has rank 2, a zero translation block, and null space exactly span(u_body), so yaw stays free at any attitude. This is the correct way to express a verticality constraint, versus encoding tilt into a 6x6 SE(3) prior information matrix, whose diagonal only isolates roll/pitch near yaw=0 and inevitably couples into translation. Purely additive and inert unless a caller sets it. Also documents that the prior information matrix is expressed in the SE(3) Lie tangent, not MRPT’s (x,y,z,yaw,pitch,roll) Euler ordering; the two swap indices 3 and 5. New unit test with 4 cases: yaw recovery to <5e-7 deg at yaw in {0,45,90,170,-120}; leveling of a tilted solution; zero translation injected by a consistent prior; convergence with a non-level map frame.
Merge pull request #75 from MOLAorg/feat/expose-cov2cov-alpha Expose cov2cov_alpha and cov2cov_auto_balance_with_prior in Solver_Ga…
Expose cov2cov_alpha and cov2cov_auto_balance_with_prior in Solver_GaussNewton These OptimalTF_GN_Parameters knobs were hard-coded to their struct defaults (1.0 and true). Load them via MCP_LOAD_OPT and forward them to gnParams so a pipeline YAML can scale the cov-to-cov data block against the pose prior (e.g. to let an IMU gravity pitch/roll prior carry more relative weight).
sm-cli info: report the first keyframe’s pose Useful to recover the absolute orientation a map was actually built with, which is not always the one it was seeded with: MOLA-LO’s IMU-based initial leveling overwrites the configured pitch/roll at mapping time, so the only reliable source is the stored keyframe itself.
fix: dont throw if saving icplogs to cwd
fix(sm-cli): restore brackets stripped by CLI11 from tf pose argument CLI11 unconditionally strips a leading/trailing bracket pair from variadic option values, so the “[x y z yaw pitch roll]” pose string passed to sm-cli tf loses its brackets before CPose3D::fromString() sees it, which then throws since it requires them.
cmake: add git submodule early fail
Contributors: Jose Luis Blanco-Claraco
2.12.0 (2026-07-10)
add missing changelogs
Merge pull request #74 from MOLAorg/split-core-viz-packages Split repo into mp2p_icp_core (headless) + mp2p_icp_viz (GUI) + mp2p_icp (metapackage)
fix: apply clang-format-14 to TCLAP->CLI11 converted files Address CI failure: several files from the TCLAP-to-CLI11 conversion weren’t run through clang-format-14 before the previous commit.
Split repo into mp2p_icp_core (headless) + mp2p_icp_viz (GUI) + mp2p_icp (metapackage) Consumers that only need the headless C++ libraries and CLI apps no longer need to pull in mrpt_libgui (nanogui/GLFW/X11) or build the GUI apps. mp2p_icp remains as a backward-compatible metapackage depending on both, so existing <depend>mp2p_icp</depend> consumers are unaffected. - mp2p_icp_core: mp2p_icp_common/map/filters + the ICP algorithms lib + 13 headless CLI apps. Root find_package(MRPT COMPONENTS …) drops “gui”; mrpt::opengl/system/expr remain available transitively via maps->obs and tfest->poses->bayes->config. - mp2p_icp_viz: mm-viewer and icp-log-viewer, the only two apps that actually use mrpt::gui (sm-cli’s dependency on it was vestigial and dropped instead). - Removed the one real GUI leak in the mp2p_icp (ICP) library: an interactive CDisplayWindow debug feature in QualityEvaluator_RangeImageSimilarity (debug_show_all_in_window), which was the only reason that library linked mrpt::gui at all. The headless debug_save_all_matrices option remains. - Dropped the mola_common git submodule and its standalone-build bootstrap logic; standalone (non-colcon) plain-CMake builds are no longer supported, matching every other MOLAorg package in this ecosystem (find_package(mola_common REQUIRED) via the ROS workspace). robin-map stays vendored (no rosdep key, private dep of filters). - Replaced TCLAP with CLI11 for all CLI apps’ argument parsing (rosdep key “cli11”, same pattern already used elsewhere in MOLAorg repos). Behavior-preserving: same flags, defaults, and help text everywhere. - Removed .circleci/config.yml: its bare-cmake + PPA-installed libmrpt-dev jobs tested exactly the standalone-build path being dropped, and can’t provide mola_common without reintroducing the bootstrap complexity just removed from CMakeLists. The colcon-based GH Actions jobs (humble/jazzy) are now the CI. - Updated docs (agents.md, README.md, docs/source/index.rst) and check-clang-format.yml/formatter.sh for the new layout. Verified: mp2p_icp_core, mp2p_icp_viz, mp2p_icp all build via colcon; all 104 mp2p_icp_core tests pass; mp2p_icp_core binaries have zero GUI/nanogui/GLFW linkage; mm-viewer still loads and renders a real georeferenced .mm file; a real downstream consumer (mola_metric_maps) builds unmodified against the new layout. Note: mp2p_icp/CMakeLists.txt shows as “modified” rather than deleted+added in the diff – this is a git rename-detection artifact from the old mp2p_icp/ (ICP library) subfolder and the new mp2p_icp/ (metapackage) folder sharing the same repo-relative path after the library moved one level deeper into mp2p_icp_core/mp2p_icp/.
Contributors: Jose Luis Blanco-Claraco
2.11.0 (2026-07-04)
Merge pull request #72 from MOLAorg/fix/filterdeskew-graceful-imu-anchor fix(FilterDeskew): never let IMU trajectory errors crash the pipeline
Merge pull request #71 from MOLAorg/feat/prior-referenced-robust-kernel Prior-referenced robust kernel for the Gauss-Newton solver
Merge pull request #70 from MOLAorg/fix/filtermerge-view-vector-rotation Fix view-direction vector frame mismatch in FilterMerge
chore: demo sm2mm files updated for LIO localization maps
demos: add sm2mm_pointcloud_voxelize_merged_keyframe_map.yaml
Merge pull request #69 from MOLAorg/feat/filter-decimate-range-adaptive feat: FilterDecimateRangeAdaptive (EllipseLIO range-adaptive scan filter)
feat: add FilterBase::enabled for env-based pipeline toggling Adds an enabled boolean field to FilterBase (default: true)
feat: add FilterDecimateRangeAdaptive (EllipseLIO range-adaptive scan filter)
Fix build status badge for ROS 2 Lyrical arm64
docs: add ROS 2 Lyrical badge row, update Rolling to Ubuntu 26.04 (resolute)
Merge pull request #68 from MOLAorg/feature/filter-polygon-2d
Contributors: Jose Luis Blanco-Claraco
2.10.3 (2026-05-24)
Merge pull request #67 from MOLAorg/fix/deskew-empty-trajectory FIX: robust against temporary lack of IMU in Deskew
Merge pull request #66 from MOLAorg/add-gicp-benchmark test: add new end-to-end gicp test as benchmark
test: add new end-to-end gicp test as benchmark
fix: icp-log-viewer bug in translations if view prior was enabled
Contributors: Jose Luis Blanco-Claraco
2.10.2 (2026-05-11)
Merge pull request #65 from MOLAorg/simplify-ci CI: simplify CI scripts and docker install
chore: don’t use anymore map classes deprecated and to be removed in mrpt 3.0.0
fix: maps creating multiple CPointsCloud won’t have all with pointSize honored
Merge pull request #64 from MOLAorg/bump-cmake bump min req cmake version to 3.22
CI: Use sensible names for jobs matrix
bump min req cmake version to 3.22
Contributors: Jose Luis Blanco-Claraco
2.10.1 (2026-05-04)
FIX: sm2mm pipeline for keyframe maps need valid KF poses
FIX: copy/paste error in guard against missing layer
mm-viewer: UI now has an easier near/far clipping plane tool
chore: map contents as string made less verbose (hide full covariance)
Merge pull request #63 from MOLAorg/feat/optional-final-run-quality-matchers feat: optional last run of matchers with final ICP_ITERATION for adaptive thresholds to see final thresholds
feat: optional last run of matchers with final ICP_ITERATION for adaptive thresholds to see final thresholds
fix: wrong decimation applied in sm2mm filters
Merge pull request #62 from MOLAorg/feat/prior-weight-mitigations feat: Implement Birge-ratio auto-balance for cov2cov and prior weighting
feat: Implement Birge-ratio auto-balance for cov2cov and prior weighting
fix: icp-log-viewer didn’t show the prior covariance at its correct location
Contributors: Jose Luis Blanco-Claraco
2.10.0 (2026-05-02)
CI: Update actions for new ROS rolling
icp-log-viewer: better formatting of uncertainties
demo sm2mm file: store as independent keyframes
Merge pull request #60 from MOLAorg/feat/censi3d-covariance Feat: Censi3D covariance method
feat: Add new covariance method (Censi, 3D version)
demo sm2mm files: add Keyframe map variant
Contributors: Jose Luis Blanco-Claraco
2.9.1 (2026-04-29)
Merge pull request #59 from MOLAorg/fix/cov2cov-covariance-whitening Fix cov2cov whitening and add residual-variance scaling in covariance()
Fix cov2cov whitening and add residual-variance scaling in covariance() The cov2cov branch in covariance.cpp whitened residuals with the full information matrix (cov_inv * e), so the assembled Hessian became J^T * cov_inv^2 * J instead of J^T * cov_inv * J. Combined with hundreds of pairings this drove det(cov) down to ~1e-20 and made the estimate unusable. - Use the Cholesky factor L^T (with L L^T = cov_inv) to whiten the cov2cov residual, matching what optimal_tf_gauss_newton accumulates. - Multiply the inverse-Hessian by chi^2 / (m - 6), the standard a-posteriori unit-weight variance, to rescale the (otherwise optimistic) result by the empirical residual level.
Merge pull request #58 from MOLAorg/feat/icp-viewer-show-prior feat: icp-logs now store the prior SE(3) PDF
feat: icp-logs now store the prior SE(3) PDF
icp-log-viewer: safer against exceptions in gui thread
demo sm2mm files: ignore_accelerometer=true in all deskew stages by default (prevent noisy maps from low-quality IMUs)
Contributors: Jose Luis Blanco-Claraco
2.9.0 (2026-04-22)
Merge pull request #57 from MOLAorg/feat/deskew-filter-ignore-acc FilterDeskew: add new option “ignore_accelerometer”
Merge pull request #55 from MOLAorg/feat/mm-viewer-read-bin-files mm-viewer: can be also open .bin files with serialized CGenericPointsMap
Merge pull request #54 from MOLAorg/feat/mm-apps-plugins mm-info, mm2grid, mm2las, mm2ply, mm2txt now have a –load-plugins flag
Optimization in PointCloudToVoxelGridSingle
Add <stdexcept> to all required files (don’t depend on transitive includes)
mm-info, mm2grid, mm2las, mm2ply, mm2txt now have a –load-plugins flag
Merge branch ‘generator-generic-cloud’ into develop
cloud rendering: Implement observing the autoBoundingBoxOutliersPercentile
Merge pull request #53 from MOLAorg/generator-generic-cloud Generator: creates CGenericPointsMap by default; add sanity checks in most filters
remove more old mrpt version guards
New sanity check function: warn_on_field_padding_mismatch()
FilterDeskew: guard against new MRPT behavior to keep all field lengths in sync
Add sanity checks in filters
Bump minimum MRPT version to 2.15.4 (and remove now old dead code)
Generator new param ‘filterOutPointsAtZero’, set to true in demo pipelines
Generator: now has a param ‘default_pointcloud_class’ which defaults to ‘CGenericPointsMap’
Code clean up (remove now dead code; mrpt backwards compatibility)
Merge pull request #52 from MOLAorg/icp-log-viewer-quality-filter icp-log-viewer: add –min-quality filter CLI flag
Contributors: Jose Luis Blanco-Claraco
2.8.1 (2026-04-06)
Merge pull request #51 from MOLAorg/fix/new-mrpt-api Update to build against mrpt >=2.15.13
Update to build against mrpt >=2.15.13 (pointcloud field names as std::string instead of string_view)
Contributors: Jose Luis Blanco-Claraco
2.8.0 (2026-04-01)
BUGFIX: Fix potential crash (regression in former voxel parallelization)
Merge pull request #50 from MOLAorg/fix/ram-usage Fix/ram usage
Process points by chunks to limit RAM usage
reduce memory allocations in voxel views
Smarter usage of reserve() in tsl maps
Add agents.md
Merge pull request #49 from MOLAorg/mm2las/georef mm2las: export flag ‘–frame geodetic’ for georeferenced clouds
Use geodetic coords cache
Correctly honor exportGeodetic
mm2las: Add sanity checks
Fix: X=lon, Y=lat coord order for WKT2
mm2las: export flag ‘–frame geodetic’ for georeferenced clouds
Contributors: Jose Luis Blanco-Claraco
2.7.1 (2026-03-08)
Merge pull request #48 from MOLAorg/fix/filter-adaptive-avoid-fpe FIX: Avoid potential division by zero in FilterDecimateAdaptive
Update minimum required MRPT version 2.15.0
FIX: Avoid potential division by zero in FilterDecimateAdaptive
Merge pull request #47 from MOLAorg/fix/georef-yaml-missing-fields FIX: georeferencing yaml serialization missed orientation fields
FIX: georeferencing yaml serialization missed orientation fields
Merge pull request #46 from MOLAorg/feat/sm2mm-in-enu-frame sm2mm: new feature to directly use georef as input and produce maps (and apply filters!) in ENU frame
sm2mm: new feature to directly use georef as input and produce maps in ENU frame
Contributors: Jose Luis Blanco-Claraco
2.7.0 (2026-03-03)
Merge pull request #45 from MOLAorg/feat/mm2grid Add new cli app: mm2grid
Add new cli app: mm2grid
Merge pull request #44 from MOLAorg/feat/view-vector Generators now optionally generate a ‘view’ direction vector per point
FilterMLS: now uses the view-direction vectors to ensure normals point outwards
Generator: add safety consistency check
Generators are now also included into sm2mm profiler
Generators now optionally generate a ‘view’ direction vector per point
mm-viewer: FIX: show/hide all buttons did not apply to extra viz layers
mm-georef: Fix creation of empty output map if input didn’t exist
mm2txt: Fix wrong console message saying mm-info instead of mm2txt
mm-viewer UI: show XY grid plane at the root frame of reference (ENU or map)
Merge pull request #43 from MOLAorg/feat/export-enu-frame Export tools now accept “–frame enu” to generate XYZ data in ENU frame
Export tools now accept “–frame enu” to generate XYZ data in ENU frame
Contributors: Jose Luis Blanco-Claraco
2.6.0 (2026-02-16)
Merge pull request #42 from MOLAorg/feat/filter-remove-several-point-fields FilterRemovePointCloudField now accepts multiple fields
FilterRemovePointCloudField now accepts multiple fields
Merge pull request #41 from MOLAorg/feat/functor-save-log-file Add functor_should_generate_debug_file to override the decision of whether to write .icplog files
Add functor_should_generate_debug_file to override the decision of whether to write .icplog files
Merge pull request #40 from MOLAorg/feat/new-clear-remove-field-filters Add new filters: FilterClear and FilterRemovePointCloudField
Add new filters: FilterClear and FilterRemovePointCloudField
docs: refer to the online pipeline editor
docs: add missing docs for FilterRenameLayer
Contributors: Jose Luis Blanco-Claraco
2.5.0 (2026-02-04)
Merge pull request #39 from MOLAorg/feat/permit-missing-externals sm2mm: Add optional flag –permit-missing-externals
sm2mm: Add optional flag –permit-missing-externals
Merge pull request #38 from MOLAorg/feat/mls-optimizations FilterMLS performance optimizations
Merge pull request #37 from MOLAorg/feat/use-zstd Use ZStd compression by default (for MRPT>=2.15.7)
docs: sm2mm add “–compression-method”
Explicitly include mrpt/core/Clock.h where used
Use ZStd compression by default (for MRPT>=2.15.7)
Merge pull request #36 from MOLAorg/feat/mm2txt-missing-fields-dont-emit mm2txt, mm2ply: don’t emit columns of zeros for missing user-given fields
Merge pull request #35 from MOLAorg/feat/mm2txt-ignore-fields mm2txt and mm2ply: Add new option –ignore-missing-fields
Merge pull request #34 from MOLAorg/feat/mm2txt-mm2ply-more-precision Exploit the maximum float32/float64 precision in exported txt formats
Merge pull request #33 from MOLAorg/feat/sm2mm-new-options Feat/sm2mm-new-options
sm2mm cli app: add new flags for downsampling options
sm2mm: add new downsample options and refactor into update_velocity_buffer_from_obs()
Contributors: Jose Luis Blanco-Claraco
2.4.1 (2026-01-27)
Add more unit tests
Update README to keep it in sync with the provided apps and libraries
Merge pull request #29 from MOLAorg/fix/cov Fix bugs in covariance estimation for some cases
fix covariance estimation bugs; add unit tests for cov2cov
Update commit for mola_common
Merge pull request #28 from MOLAorg/feat/mm-viewer-3d-layers mm-viewer: add CLI flags to load overlaid 3D scenes for visualization
mm-viewer: add CLI flags to load overlaid 3D scenes for visualization
Contributors: Jose Luis Blanco-Claraco
2.4.0 (2026-01-21)
Merge pull request #27 from MOLAorg/feat/new-filter-voxel-sor
Add new unit test for class factory
Add new FilterVoxelSOR filter
Merge pull request #26 from MOLAorg/feat/mm2las
Add mm2las CLI tool
Contributors: Jose Luis Blanco-Claraco
2.3.1 (2026-01-14)
Merge pull request #25 from MOLAorg/feat/naive-decimate Add trivial FilterDecimate for fast downsampling without spatial awareness
lint fixes
Add trivial FilterDecimate for fast downsampling without spatial awareness
Parameterizable: add virtual base dtor
Remove the NormalizeIntensity stage in the demo pipelines; visualization does that already
docs: fill missing manpages
docs: add sm2mm pipelines page
Clarify map layers and simple maps descriptions Updated references to CMetricMap and CGenericPointsMap in the documentation for clarity and accuracy.
Contributors: Jose Luis Blanco-Claraco
2.3.0 (2026-01-08)
Merge pull request #24 from MOLAorg/feat/mm2txt-select-fields mm2txt and mm2ply now have a –export-fields flag
mm2txt and mm2ply now have a –export-fields flag
Merge pull request #23 from MOLAorg/fix/some-deprecations Fix usage of deprecated cloud types
Provide shortcut names for common cloud field names
More deprecated cloud usage
FIX bug: FilterDecimateVoxel, if using flatten, did not propagate all input cloud fields
Fix usage of some deprecated cloud types
FilterSOR: create output layers even if input is empty
FilterDeskew: propagate input fields even if the cloud is empty
FilterByExpression: show debug-level stats
FilterNormalizeIntensity: do not throw on empty clouds
Merge pull request #22 from MOLAorg/feat/new-filters Add new filter FilterRenameLayer
Added filter FilterRenameLayer
mm2txt: prepare for deprecated classes in 3.0.0
FilterAdjustTimestamps: new method ‘None’ to bypass filter
Fix: sm2mm did not attach to ParameterSource the final_filter elements
sm2mm: did not observe the optional profiler parameter for the final_filter stage
Fix: FilterMLS did not properly copy all point fields when using upsampling
Fix: FilterAbsoluteTimestamp now also works for accumulated points in one layer
Contributors: Jose Luis Blanco-Claraco
2.2.1 (2026-01-06)
Merge pull request #21 from MOLAorg/feat/abs-stamp-filter Added new filter: FilterAbsoluteTimestamp
Fix the logic of the FilterEdgePlane filter parameters
Added new filter: FilterAbsoluteTimestamp
mm2txt: also export uint8 fields (missing in last release)
Merge pull request #20 from MOLAorg/feat/more-unit-tests More unit tests
Add generators unit tests
More unit tests
Contributors: Jose Luis Blanco-Claraco
2.2.0 (2025-12-28)
docs: explain FilterSOR
Merge pull request #19 from MOLAorg/feat/mm2ply Add mm2ply CLI tool
Merge pull request #18 from MOLAorg/feat/new-sor-filter Add FilterSOR: Statistical Outlier Rejection
More unit tests: cover MLS
Merge pull request #17 from MOLAorg/feat/filter-by-expr Add new filter: FilterByExpression
More code coverage; fix protected-level initialize methods
Add new filter: FilterByExpression
FIX: missing uint8 fields in Deskew
sanityCheck: also check all double/uint8 fields
ui: fix case without geo-ref
mm-viewer: show lat/lon coordinates for mouse selected points
mm-viewer: GUI now shows the ENU & map miniviews for orientation hints
mm-viewer: handle special coloring channel groups ‘rgb’ and ‘rgbf’
clean non used code in deskew test
map viz: use new mrpt 2.15.3 coloring modes
sm2mm: auto-guess lazy-load externals directory for .simplemap files
mm-viewer: implement colorize clouds by any field
MLS filter: add ‘output_layer_class’ parameter
mm2txt: export all fields of CGenericPointsMap layers
Merge pull request #16 from MOLAorg/fix/generic-cloud-deskew-fields Add test for missing fields in generic cloud deskew
FIX: correctly register arbitrary pointcloud fields into output clouds
Add test for missing fields in generic cloud deskew
sm2mm: FIx console message on “FinalFilters” did not obey verbosity level
Fix clang-tidy warnings
Contributors: Jose Luis Blanco-Claraco
2.1.2 (2025-11-28)
mm-viewer: Automatic retry to load maps if missing plugins, trying to reload with libmola_metric_maps.so
Enable coverage run for noble docker image
Add new unit tests
docs: fix broken formatting of filters page
Merge pull request #14 deskew filter: refactoring to handle arbitrary point fields
get code ready for API update in MRPT 2.15.3
Fix build w/o imu library
mm-viewer: add keystrokes shift+cursor arrows to move up/down
Add Codecov badge to README
MLS filter: add progress report logging
Contributors: Jose Luis Blanco-Claraco
2.1.1 (2025-11-08)
FIX: SanityCheck was triggering as errors optional pointcloud fields in XYZIRT clouds
FIX: Throw exception instead of crashing if FilterDeskew is invoked with an empty local velocity buffer
Fix yaml file for not using mola_yaml extensions
Add more sm2mm demo pipelines
Contributors: Jose Luis Blanco-Claraco
2.1.0 (2025-10-28)
Merge pull request #13 from MOLAorg/fix/filterdecimate-bug
Add unit test for FilterDecimateVoxel
mm-viewer: ensure proper order of opengl object destruction
Add more debug traces for Filters
Generator: Add more info on layer contents in debug traces
FIX: Avoid crash in FilterVoxelSlice if there are no points in the ROI
Merge pull request #12 from MOLAorg/feat/mls Implemented MLS filter
Merge pull request #11 from MOLAorg/feat/use-faster-insertion Use the faster insertion-with-context in MRPT 2.15.0
Update to build using CGenericPointsMap in upcoming MRPT >=2.15
Merge pull request #10 from MOLAorg/fix/ci
Upgrade CircleCI images to u24.04
Fix build out of ROS and w/o IMU preintegration
Update mola_common version
Fix: Warning message missing new line
FilterDecimateVoxels: add new parameter ‘minimum_points_per_voxel’
Fix docs typo
Update docs for Deskew filter
Update README.md badges
Contributors: Jose Luis Blanco-Claraco
2.0.0 (2025-10-13)
Merge pull request #9 from MOLAorg/feature/better-lio Better LIO
sm2mm cli app: add –profiler flag
demo sm2mm pipelines: add deskew method entry
CI: Add another pipeline without TBB
FIX: bug in non-TBB serial implementation of GN optimizer
CI: add running unit tests
FIX: potential crash in FilterDeskew
Add deskew unit tests
Add unit test for cov2cov optimizer
Add ‘name’ property to all generators and filters for disaggregated stats
Allow building without the IMU library
Update mola_common to 0.5.1
clang-tidy fixes
Remove dead code
Refactor errorTerm for pt2pt for better reusability
mm-viewer: add combo box to select intensity colormap
Add docs for filters
BUGFIX: FilterMerge would lost all point fields except XYZ
Remove external libpointmatcher
Update formatter script
icp log viewer: more options for cov2cov visualization
Define virtual API MetricMapMergeCapable
fix bug in FilterByIntensity params parser
Render cov2cov pairings
FilterByRange new parameter: metric_l_infinity
FilterDecimateAdaptive now exploits parallelization
Progress visualizing cov2cov pairings
New cov2cov ICP optimizer
Implement a new Cov2Cov matcher
Make Matcher_Points_Base::transform_local_to_global() to use TBB, and remove unused parameters
Add [[nodiscard]] to estimate_points_eigen()
BBox filter: fix target layer must be same type than input
Use fractional integers for faster sampling
New FPS filter
Remove FilterDecimateVoxelsQuadratic
Style: public ‘params_’ rename as ‘params’
New interface ‘IcpPrepareCapable’
Add new virtual interface NearestPointWithCovCapable
Refactor mp2p_icp_map into mp2p_icp_common for IMU-related parts
Finished integration of new IMU API package
Depend on imu external library
Move code out to the imu preintegration package
Move LocalVelocityBuffer to the IMU repository
Add [[nodiscard]] to icp_pipeline_from_yaml()
deskew filter: new option ‘in_place’ to avoid allocating a new cloud whenever possible
Finish implementation of higher-order IMU interpolator
Implement trajectory reconstruction for deskew
cmake files: prefer spaces indentation
Add imu preintegration package as dependency
FilterNormalizeIntensity can now use a fixed min/max range given by hand
Docs: update mp2p_icp_basics for better searchability of simplemaps
New option to set pointcloud alpha channel
Contributors: Jose Luis Blanco-Claraco
1.8.0 (2025-08-26)
Modernize and unify license notes in all files
Merge pull request #8 from MOLAorg/feat/precise-deskew Precise scan deskew: - Implement LocalVelocityBuffer inside ParameterSource’s - Update LocalVelocityBuffer from IMU data from Generators. - Export / Import LocalVelocityBuffer to/from YAML - Implement precise cloud undistortion in FilterDeskew - Use precise cloud undistortion in the context of sm2mm.
sm2mm: Use local velocity buffer if available
add serialization to velocity buffer
Generators now handle IMU readings and forward them to the velocity buffer
Update to latest mola_common for embedded builds
linter: clang-tidy fixes
fix param name for better consistency
feature: Option to use std::map instead of tsl robin_map in voxelization filters
docs: fill txt2mm man page
Feature: txt2mm new import format ‘xyzrgb_normalized’
remove code to support older MRPT versions; code style clean ups
Fix: FilterAdjustTimestamps may trigger exception if input cloud is empty
Contributors: Jose Luis Blanco-Claraco
1.7.1 (2025-06-20)
docs: Populate sm2mm app page
New feature: all pipeline modules now has an optional “plugin” YAML field to load them from user-provided plugins.
Update REAME ROS badges
Contributors: Jose Luis Blanco-Claraco
1.7.0 (2025-06-02)
metric map data type: add new metadata YAML field
Update broken link to ROS Index
docs: change references to default branch master->develop
Default generator: more details in debug traces when ignoring an observation
Update package license tag to “BSD-3-Clause”
Integrate vscode with colcon custom settings and clang-tidy
Fix build unit tests with older gcc versions
Drop apparently useless build dep
Contributors: Jose Luis Blanco-Claraco
1.6.7 (2025-04-03)
mm-georef cli app: support reading/writing georef info in YAML format
georeferencing metadata now can be read/writen as YAML files
clang-format: switch to column limit=100
Update to robin-map v1.4.0
Contributors: Jose Luis Blanco-Claraco
1.6.6 (2025-02-26)
Docs: add page for mm-georef
docs: Update 2025 paper citation
print metric_map_t as string: show lat/lon coordinates in a format directly compatible with Google Map searches.
New cli tool: mm-georef, to manipulate the geo-referencing metadata of metric map files
Contributors: Jose Luis Blanco-Claraco
1.6.5 (2025-01-28)
Add GitHub actions
Add pole-detector filter
mm-filter app: add –load-plugins flag too
Add sanity check assert in FilterDeskew
Contributors: Jose Luis Blanco-Claraco
1.6.4 (2024-12-18)
merge two docs pages in one to shorten the docs TOC
Update README.md: Mark ROS2 Iron as EOL
Also use TBB for parallel solving point-to-plane pairings
Contributors: Jose Luis Blanco-Claraco
1.6.3 (2024-11-11)
icp-log-viewer: also reduce GUI refresh rate
mm-viewer: avoid useless GUI refresh (CPU usage reduction)
txt2mm: Add input filter xyzrgb
mm-viewer: add a ‘fit view to map’ button
New cli app rawlog-filter
FilterCurvature: better handling scans with <=3 points in some rings
new subcommand ‘sm-cli tf’
Contributors: Jose Luis Blanco-Claraco
1.6.2 (2024-09-14)
Expose << and >> operators for geo-reference data structures
Fix missing build_dep
Contributors: Jose Luis Blanco-Claraco
1.6.1 (2024-09-11)
Fix missing catkin buildtoo_depend for ROS1 builds
Update RTTI macros for upcoming MRPT 2.14.0
Contributors: Jose Luis Blanco-Claraco
1.6.0 (2024-09-08)
Port Point2Plane matcher to use the new NN-for-planes API
mp2p_icp_map library: add NearestPlaneCapable virtual API
cmake: move from glob expressions to explicit lists of source files
clarify eigenvalues order in headers
Contributors: Jose Luis Blanco-Claraco
1.5.6 (2024-09-07)
sm2mm cli: show map contents before writing to disk
add another demo sm2mm file for the mola tutorials
Add another sm2mm demo file w/o deskew for the mola mapping tutorial
Matcher_Point2Plane: fix build error in armhf
Fix build with embedded mola_common
README: Add ROS badges for all architectures
Contributors: Jose Luis Blanco-Claraco
1.5.5 (2024-08-27)
Explicitly add tbb as dependency in package.xml
Depend on new mrpt_lib packages (deprecate mrpt2)
FIX: build errors in armhf arch
Contributors: Jose Luis Blanco-Claraco
1.5.4 (2024-08-20)
Do not use Eigen::Vector for compatibility with Eigen3 <3.4 in ROS Noetic
Contributors: Jose Luis Blanco-Claraco
1.5.3 (2024-08-20)
Re-add ROS1 Noetic as supported distribution
Generator sanity check asserts: more informative error messages
sm-cli: new command ‘join’ to merge simplemaps
icp-log-viewer UI: new keybind ‘I’ to switch initial/final pose
icp-log-viewer UI: add option to visualize voxelmaps empty space
Contributors: Jose Luis Blanco-Claraco
1.5.2 (2024-07-24)
Add sm2mm yaml example for dynamic/static obstacles
Update sample sm2mm pipelines to use de-skew
docs: add mm-filter example
Fix pointcloud ptr typo
More safety sanity checks added in mm-viewer and sm2mm
BUGFIX: Generator should not create empty maps for GPS observations
Contributors: Jose Luis Blanco-Claraco, Raúl Aguilera López
1.5.1 (2024-07-03)
Update docs
ICP: Add optional functors for before-logging maps
icp-log-viewer UI: fix potential out-of-range exception when autoplay is on
FilterAdjustTimestamps: add new param ‘time_offset’ useful for multiple LiDARs setups
Contributors: Jose Luis Blanco-Claraco
1.5.0 (2024-06-21)
ICP: Add optional user-provided per-iteration hooks
Add new filter: FilterByRing
Add new filter: FilterAdjustTimestamps
Add sanity checks for point cloud fields.
Fix typo in default class for FilterDeskew
generators API: add bool return type to detect if observation was actually processed
generic Generator: handle velodyne observations so timestamps are generated
Contributors: Jose Luis Blanco-Claraco
1.4.3 (2024-06-11)
Add pointcloud_sanity_check() auxiliary function
Generator: more DEBUG level traces
BUGFIX: FilterDeskew generated buggy output points if the input does not contain timestamps
Add sanity checks for point cloud fields
ICP log records now also store the dynamic variables. icp-log-viewer displays them.
ICP log files: automatically create output directory if it does not exist
Update ros2 badges (added Jazzy)
Contributors: Jose Luis Blanco-Claraco
1.4.2 (2024-05-28)
mm-viewer: add check-all, check-none to layer filters
Add new filter: FilterRemoveByVoxelOccupancy
mm-viewer: camera travelling keyframes-based animations
mm-viewer: navigate the map with keyboard arrows; add a load button
mm-viewer: can now also draws a TUM trajectory overlaid with the map
UI apps: smoother rendering
icp-log-viewer and mm-viewer: the UI now has a XYZ corner overlay
sm-cli: command “export-kfs” now has an optional flag ‘–output-twist’
FilterDeskew: ignore empty input maps
More debug-level traces
deskew filter: Fix case of variable names in docs
sm-cli app: Add new command ‘trim’ to cut simplemaps by bounding box
mm-viewer: show mouse pointing coordinates
Contributors: Jose Luis Blanco-Claraco
1.4.1 (2024-05-19)
Fix build for older mrpt versions
ICP pipelines: Implement loading
quality_checkpointsparameter from YAML config fileQuality evaluators: add the option for ‘hard discard’
Update QualityEvaluator_Voxels to use prebuilt voxel layers from input maps. Add unit tests.
BUGFIX: Fix deserializing georeferenced .mm files stored in <1.4.0 format
ICP: quality evaluators can now have formulas in their parameters too
mm-viewer and icp-log-viewer: extend zoom range so maps of tens of kms can be viewed at once
Contributors: Jose Luis Blanco-Claraco
1.4.0 (2024-05-06)
Update commit for robin-map to latest version (patch contributed upstream)
icp-log-viewer: UI now has a slider for each map point size
ICP: Add a new quality_checkpoint parameter to early abort ICP attempts
georeferenced maps: T_enu_to_map now has a covariance field
mm-viewer: display ENU frame too
Contributors: Jose Luis Blanco-Claraco
1.3.3 (2024-04-30)
Add minimum_input_points_to_filter option to FilterDecimateVoxels
FIX: QualityEvaluator_PairedRatio throws when one of the reference maps is empty
FIX BUG: Won’t try to match 2D pointclouds if their height is different
Clarify comments in metricmap.h about geodetic references
Fix printing metric_map_t contents when it only has a gridmap
Fix potential dangling references (g++ 13 warning)
Fix potential use of uninitialized point index
Bump cmake_minimum_required to 3.5
Contributors: Jose Luis Blanco-Claraco
1.3.2 (2024-04-22)
tsl::robin_map library is no longer exposed neither in the public API nor as public headers (PIMPL pattern) This is to prevent Debian-level collisions with other packages also exposing it.
add first icp-log-viewer docs
Contributors: Jose Luis Blanco-Claraco
1.3.1 (2024-04-16)
mm-viewer and icp-log-viewer: saves UI state in persistent user config file
FIX: missing UI refresh when clicking showPairings checkbox
renamed apps for less verbose names: icp-run, icp-log-viewer
ICP core now defines a variable ICP_ITERATION for use in programmable formulas in pipelines
icp-log-viewer: much faster rendering of ICP iteration details
mm-viewer: fix bug in calculation of bounding box
Merge docs with main MOLA repo
Contributors: Jose Luis Blanco-Claraco
1.3.0 (2024-03-10)
mm-viewer: new options to visualize georeferenced maps
New sm-cli commands: –cut, –export-keyframes, –export-rawlog
propagate cmake deps downstream
metric_map_t: add georeferencing optional field
mm-filter: add –rename operation
GetOrCreatePointLayer() moved to its own header and uses shared ptrs
FilterMerge: add param input_layer_in_local_coordinates
Contributors: Jose Luis Blanco-Claraco
1.2.0 (2024-02-16)
Add new apps: sm-cli, mm-info, txt2mm, mm2txt, mm-filter
Improved documentation.
new filter FilterByIntensity
FilterNormalizeIntensity: add option for intensity range memory
FilterByRange: renamed params to simplify them (removed param ‘keep_between’)
FIX: missing intensity channel in decimate voxel when using some decimation methods
sm-cli: new subcommand ‘level’ to maximize the ‘horizontality’ of built maps
add optional profiler to filter pipelines
Contributors: Jose Luis Blanco-Claraco
1.1.1 (2024-02-07)
MergeFilter: now also handles CVoxelMap as inputs
more memory efficient defaults
FilterCurvature: now based on ring_id channel
Use hash map min_factor to speed up clear()s
add missing hash reserve
PointCloudToVoxelGridSingle: Fix wrong initialization of point count
Contributors: Jose Luis Blanco-Claraco
1.1.0 (2024-01-25)
FilterDecimateVoxels: Replace 3 bool parameters with an enum
Fix clang warnings
Save and visualize ICP step partial solutions
QualityEvaluator_PairedRatio: now does not require parameters
Add filter: Bonxai VoxelMap -> 2D gridmap. Bayesian filtering of voxel columns
Generator: allow defining custom metric maps directly in the YAML configuration
Contributors: Jose Luis Blanco-Claraco
1.0.0 (2024-01-20)
Gauss-Newton solver: Add optional prior term
Added FilterMerge and modifications to allow sm2mm to build any type maps
sm2mm: add option for lazy-load external directory
Decimate filter: add flatten_to option to efficiently convert 3D->2D point clouds
FilterBoundingBox: parameter name changed for clearer split of inside / outside bbox
Deskew: add option to bypass de-skew operation
bump minimum required mrpt version
Better coloring; add option to export mm layers
Use new mrpt api to propagate point properties; add final_filter stage to sm2mm
sm2mm: add verbosity flag
bbox filter: allow processing variables too
Introduce robot_{x,y,z} variables
Better mm-viewer; update sm2mm demo file
Progress with RST docs
Add missing robotPose argument to generators; progress with mm-viewer
Add sm2mm app
Add FILE attribute to license tag
More dynamic parameters
fix print format
Add Deskew filter
update CI to u22.04
Introduce Parameterizable interface
New layers: create of the same input cloud type
Add FilterCurvature
filter: optional additional layer for deleted points
FIX: important error in robust gradient
expose GN params as public
new generators and filters
Filters: use tsl robin_map, faster than std::unordered_map
prefer nn_radius_search() to exploit nanoflann rknn
Minor UI updates
gui: autoplay
estimate_points_eigen.h moved to the mp2p_icp_map library
Solvers: add option to select by correction magnitude
add [[nodiscard]] to generator API
Add specialized implementation of voxelize for 1 pt/vx
add Cauchy robust kernel
Add support for TBB for parallelization
add angularThresholdFactor; add max plane-to-pt distance
viewer UI: show number of points per layer
Prefer Teschner’s spatial hash
Use nn_single_search() when possible
viewer: add follow local checkbox
Add new filter: FilterDecimateVoxelsQuadratic
FilterDecimateVoxels: new option use_closest_to_voxel_average
FilterDecimateVoxels: new param use_random_point_within_voxel
less unnecesary mem allocs
generator: create map layers first, then filter by observation name/class filter
port to NN radius search
add “enabled” property to base Matcher class
Solvers: add property ‘enabled’
Add robust kernels to GN solver
Add optional profiler to ICP
New parameter decimationDebugFiles
Add plugin option to viewer
VoxelFilter: is now ~7 times faster and does not need a bounding box parameter, thanks to using an associative container.
viewer: add new flag -f to load one single log file
viewer: increase slider range for max far plane
Options to recolorize maps in icp log viewer
Fix regression in rendering options for point clouds
Matcher: new parameter bounding_box_intersection_check_epsilon
New env var MP2P_ICP_GENERATE_DEBUG_FILES can be use to override generation of icp log files
BUGFIX: Ignored sensorPose for Generator::filterPointCloud()
Allow ICP matching against voxel metric map types
mp2p_icp_filters::Generator now can create a map from a generic INI file (e.g. voxelmaps)
fix references to old pointcloud_t -> metric_map_t
Remove support for MRPT<2.4.0
Contributors: Jose Luis Blanco-Claraco
0.2.2 (2023-09-08)
Fix missing cmake dependencies between libraries
Update mola_common
Refactor into a new small library mp2p_icp_map with just the metric_map_t class
sync mola_common submodule
Update submodule mola_common
Remove redundant section
Update ROS badges
Contributors: Jose Luis Blanco-Claraco
0.2.1 (2023-09-02)
Update copyright date
Update to new name of mola_common
update ros badges
Contributors: Jose Luis Blanco-Claraco
0.2.0 (2023-08-24)
First release as MOLA submodule.
0.1.0 (2023-06-14)
First official release of the mp2p_icp libraries
Contributors: FranciscoJManasAlvarez, Jose Luis Blanco-Claraco
Changelog for package mp2p_icp_viz
2.14.0 (2026-09-05)
2.13.1 (2026-08-25)
2.13.0 (2026-08-21)
2.12.0 (2026-07-10)
add missing changelogs
Merge pull request #74 from MOLAorg/split-core-viz-packages Split repo into mp2p_icp_core (headless) + mp2p_icp_viz (GUI) + mp2p_icp (metapackage)
Split repo into mp2p_icp_core (headless) + mp2p_icp_viz (GUI) + mp2p_icp (metapackage) Consumers that only need the headless C++ libraries and CLI apps no longer need to pull in mrpt_libgui (nanogui/GLFW/X11) or build the GUI apps. mp2p_icp remains as a backward-compatible metapackage depending on both, so existing <depend>mp2p_icp</depend> consumers are unaffected. - mp2p_icp_core: mp2p_icp_common/map/filters + the ICP algorithms lib + 13 headless CLI apps. Root find_package(MRPT COMPONENTS …) drops “gui”; mrpt::opengl/system/expr remain available transitively via maps->obs and tfest->poses->bayes->config. - mp2p_icp_viz: mm-viewer and icp-log-viewer, the only two apps that actually use mrpt::gui (sm-cli’s dependency on it was vestigial and dropped instead). - Removed the one real GUI leak in the mp2p_icp (ICP) library: an interactive CDisplayWindow debug feature in QualityEvaluator_RangeImageSimilarity (debug_show_all_in_window), which was the only reason that library linked mrpt::gui at all. The headless debug_save_all_matrices option remains. - Dropped the mola_common git submodule and its standalone-build bootstrap logic; standalone (non-colcon) plain-CMake builds are no longer supported, matching every other MOLAorg package in this ecosystem (find_package(mola_common REQUIRED) via the ROS workspace). robin-map stays vendored (no rosdep key, private dep of filters). - Replaced TCLAP with CLI11 for all CLI apps’ argument parsing (rosdep key “cli11”, same pattern already used elsewhere in MOLAorg repos). Behavior-preserving: same flags, defaults, and help text everywhere. - Removed .circleci/config.yml: its bare-cmake + PPA-installed libmrpt-dev jobs tested exactly the standalone-build path being dropped, and can’t provide mola_common without reintroducing the bootstrap complexity just removed from CMakeLists. The colcon-based GH Actions jobs (humble/jazzy) are now the CI. - Updated docs (agents.md, README.md, docs/source/index.rst) and check-clang-format.yml/formatter.sh for the new layout. Verified: mp2p_icp_core, mp2p_icp_viz, mp2p_icp all build via colcon; all 104 mp2p_icp_core tests pass; mp2p_icp_core binaries have zero GUI/nanogui/GLFW linkage; mm-viewer still loads and renders a real georeferenced .mm file; a real downstream consumer (mola_metric_maps) builds unmodified against the new layout. Note: mp2p_icp/CMakeLists.txt shows as “modified” rather than deleted+added in the diff – this is a git rename-detection artifact from the old mp2p_icp/ (ICP library) subfolder and the new mp2p_icp/ (metapackage) folder sharing the same repo-relative path after the library moved one level deeper into mp2p_icp_core/mp2p_icp/.
Contributors: Jose Luis Blanco-Claraco
2.11.0 (2026-07-04)
Merge pull request #72 from MOLAorg/fix/filterdeskew-graceful-imu-anchor fix(FilterDeskew): never let IMU trajectory errors crash the pipeline
Merge pull request #71 from MOLAorg/feat/prior-referenced-robust-kernel Prior-referenced robust kernel for the Gauss-Newton solver
Merge pull request #70 from MOLAorg/fix/filtermerge-view-vector-rotation Fix view-direction vector frame mismatch in FilterMerge
chore: demo sm2mm files updated for LIO localization maps
demos: add sm2mm_pointcloud_voxelize_merged_keyframe_map.yaml
Merge pull request #69 from MOLAorg/feat/filter-decimate-range-adaptive feat: FilterDecimateRangeAdaptive (EllipseLIO range-adaptive scan filter)
feat: add FilterBase::enabled for env-based pipeline toggling Adds an enabled boolean field to FilterBase (default: true)
feat: add FilterDecimateRangeAdaptive (EllipseLIO range-adaptive scan filter)
Fix build status badge for ROS 2 Lyrical arm64
docs: add ROS 2 Lyrical badge row, update Rolling to Ubuntu 26.04 (resolute)
Merge pull request #68 from MOLAorg/feature/filter-polygon-2d
Contributors: Jose Luis Blanco-Claraco
2.10.3 (2026-05-24)
Merge pull request #67 from MOLAorg/fix/deskew-empty-trajectory FIX: robust against temporary lack of IMU in Deskew
Merge pull request #66 from MOLAorg/add-gicp-benchmark test: add new end-to-end gicp test as benchmark
test: add new end-to-end gicp test as benchmark
fix: icp-log-viewer bug in translations if view prior was enabled
Contributors: Jose Luis Blanco-Claraco
2.10.2 (2026-05-11)
Merge pull request #65 from MOLAorg/simplify-ci CI: simplify CI scripts and docker install
chore: don’t use anymore map classes deprecated and to be removed in mrpt 3.0.0
fix: maps creating multiple CPointsCloud won’t have all with pointSize honored
Merge pull request #64 from MOLAorg/bump-cmake bump min req cmake version to 3.22
CI: Use sensible names for jobs matrix
bump min req cmake version to 3.22
Contributors: Jose Luis Blanco-Claraco
2.10.1 (2026-05-04)
FIX: sm2mm pipeline for keyframe maps need valid KF poses
FIX: copy/paste error in guard against missing layer
mm-viewer: UI now has an easier near/far clipping plane tool
chore: map contents as string made less verbose (hide full covariance)
Merge pull request #63 from MOLAorg/feat/optional-final-run-quality-matchers feat: optional last run of matchers with final ICP_ITERATION for adaptive thresholds to see final thresholds
feat: optional last run of matchers with final ICP_ITERATION for adaptive thresholds to see final thresholds
fix: wrong decimation applied in sm2mm filters
Merge pull request #62 from MOLAorg/feat/prior-weight-mitigations feat: Implement Birge-ratio auto-balance for cov2cov and prior weighting
feat: Implement Birge-ratio auto-balance for cov2cov and prior weighting
fix: icp-log-viewer didn’t show the prior covariance at its correct location
Contributors: Jose Luis Blanco-Claraco
2.10.0 (2026-05-02)
CI: Update actions for new ROS rolling
icp-log-viewer: better formatting of uncertainties
demo sm2mm file: store as independent keyframes
Merge pull request #60 from MOLAorg/feat/censi3d-covariance Feat: Censi3D covariance method
feat: Add new covariance method (Censi, 3D version)
demo sm2mm files: add Keyframe map variant
Contributors: Jose Luis Blanco-Claraco
2.9.1 (2026-04-29)
Merge pull request #59 from MOLAorg/fix/cov2cov-covariance-whitening Fix cov2cov whitening and add residual-variance scaling in covariance()
Fix cov2cov whitening and add residual-variance scaling in covariance() The cov2cov branch in covariance.cpp whitened residuals with the full information matrix (cov_inv * e), so the assembled Hessian became J^T * cov_inv^2 * J instead of J^T * cov_inv * J. Combined with hundreds of pairings this drove det(cov) down to ~1e-20 and made the estimate unusable. - Use the Cholesky factor L^T (with L L^T = cov_inv) to whiten the cov2cov residual, matching what optimal_tf_gauss_newton accumulates. - Multiply the inverse-Hessian by chi^2 / (m - 6), the standard a-posteriori unit-weight variance, to rescale the (otherwise optimistic) result by the empirical residual level.
Merge pull request #58 from MOLAorg/feat/icp-viewer-show-prior feat: icp-logs now store the prior SE(3) PDF
feat: icp-logs now store the prior SE(3) PDF
icp-log-viewer: safer against exceptions in gui thread
demo sm2mm files: ignore_accelerometer=true in all deskew stages by default (prevent noisy maps from low-quality IMUs)
Contributors: Jose Luis Blanco-Claraco
2.9.0 (2026-04-22)
Merge pull request #57 from MOLAorg/feat/deskew-filter-ignore-acc FilterDeskew: add new option “ignore_accelerometer”
Merge pull request #55 from MOLAorg/feat/mm-viewer-read-bin-files mm-viewer: can be also open .bin files with serialized CGenericPointsMap
Merge pull request #54 from MOLAorg/feat/mm-apps-plugins mm-info, mm2grid, mm2las, mm2ply, mm2txt now have a –load-plugins flag
Optimization in PointCloudToVoxelGridSingle
Add <stdexcept> to all required files (don’t depend on transitive includes)
mm-info, mm2grid, mm2las, mm2ply, mm2txt now have a –load-plugins flag
Merge branch ‘generator-generic-cloud’ into develop
cloud rendering: Implement observing the autoBoundingBoxOutliersPercentile
Merge pull request #53 from MOLAorg/generator-generic-cloud Generator: creates CGenericPointsMap by default; add sanity checks in most filters
remove more old mrpt version guards
New sanity check function: warn_on_field_padding_mismatch()
FilterDeskew: guard against new MRPT behavior to keep all field lengths in sync
Add sanity checks in filters
Bump minimum MRPT version to 2.15.4 (and remove now old dead code)
Generator new param ‘filterOutPointsAtZero’, set to true in demo pipelines
Generator: now has a param ‘default_pointcloud_class’ which defaults to ‘CGenericPointsMap’
Code clean up (remove now dead code; mrpt backwards compatibility)
Merge pull request #52 from MOLAorg/icp-log-viewer-quality-filter icp-log-viewer: add –min-quality filter CLI flag
Contributors: Jose Luis Blanco-Claraco
2.8.1 (2026-04-06)
Merge pull request #51 from MOLAorg/fix/new-mrpt-api Update to build against mrpt >=2.15.13
Update to build against mrpt >=2.15.13 (pointcloud field names as std::string instead of string_view)
Contributors: Jose Luis Blanco-Claraco
2.8.0 (2026-04-01)
BUGFIX: Fix potential crash (regression in former voxel parallelization)
Merge pull request #50 from MOLAorg/fix/ram-usage Fix/ram usage
Process points by chunks to limit RAM usage
reduce memory allocations in voxel views
Smarter usage of reserve() in tsl maps
Add agents.md
Merge pull request #49 from MOLAorg/mm2las/georef mm2las: export flag ‘–frame geodetic’ for georeferenced clouds
Use geodetic coords cache
Correctly honor exportGeodetic
mm2las: Add sanity checks
Fix: X=lon, Y=lat coord order for WKT2
mm2las: export flag ‘–frame geodetic’ for georeferenced clouds
Contributors: Jose Luis Blanco-Claraco
2.7.1 (2026-03-08)
Merge pull request #48 from MOLAorg/fix/filter-adaptive-avoid-fpe FIX: Avoid potential division by zero in FilterDecimateAdaptive
Update minimum required MRPT version 2.15.0
FIX: Avoid potential division by zero in FilterDecimateAdaptive
Merge pull request #47 from MOLAorg/fix/georef-yaml-missing-fields FIX: georeferencing yaml serialization missed orientation fields
FIX: georeferencing yaml serialization missed orientation fields
Merge pull request #46 from MOLAorg/feat/sm2mm-in-enu-frame sm2mm: new feature to directly use georef as input and produce maps (and apply filters!) in ENU frame
sm2mm: new feature to directly use georef as input and produce maps in ENU frame
Contributors: Jose Luis Blanco-Claraco
2.7.0 (2026-03-03)
Merge pull request #45 from MOLAorg/feat/mm2grid Add new cli app: mm2grid
Add new cli app: mm2grid
Merge pull request #44 from MOLAorg/feat/view-vector Generators now optionally generate a ‘view’ direction vector per point
FilterMLS: now uses the view-direction vectors to ensure normals point outwards
Generator: add safety consistency check
Generators are now also included into sm2mm profiler
Generators now optionally generate a ‘view’ direction vector per point
mm-viewer: FIX: show/hide all buttons did not apply to extra viz layers
mm-georef: Fix creation of empty output map if input didn’t exist
mm2txt: Fix wrong console message saying mm-info instead of mm2txt
mm-viewer UI: show XY grid plane at the root frame of reference (ENU or map)
Merge pull request #43 from MOLAorg/feat/export-enu-frame Export tools now accept “–frame enu” to generate XYZ data in ENU frame
Export tools now accept “–frame enu” to generate XYZ data in ENU frame
Contributors: Jose Luis Blanco-Claraco
2.6.0 (2026-02-16)
Merge pull request #42 from MOLAorg/feat/filter-remove-several-point-fields FilterRemovePointCloudField now accepts multiple fields
FilterRemovePointCloudField now accepts multiple fields
Merge pull request #41 from MOLAorg/feat/functor-save-log-file Add functor_should_generate_debug_file to override the decision of whether to write .icplog files
Add functor_should_generate_debug_file to override the decision of whether to write .icplog files
Merge pull request #40 from MOLAorg/feat/new-clear-remove-field-filters Add new filters: FilterClear and FilterRemovePointCloudField
Add new filters: FilterClear and FilterRemovePointCloudField
docs: refer to the online pipeline editor
docs: add missing docs for FilterRenameLayer
Contributors: Jose Luis Blanco-Claraco
2.5.0 (2026-02-04)
Merge pull request #39 from MOLAorg/feat/permit-missing-externals sm2mm: Add optional flag –permit-missing-externals
sm2mm: Add optional flag –permit-missing-externals
Merge pull request #38 from MOLAorg/feat/mls-optimizations FilterMLS performance optimizations
Merge pull request #37 from MOLAorg/feat/use-zstd Use ZStd compression by default (for MRPT>=2.15.7)
docs: sm2mm add “–compression-method”
Explicitly include mrpt/core/Clock.h where used
Use ZStd compression by default (for MRPT>=2.15.7)
Merge pull request #36 from MOLAorg/feat/mm2txt-missing-fields-dont-emit mm2txt, mm2ply: don’t emit columns of zeros for missing user-given fields
Merge pull request #35 from MOLAorg/feat/mm2txt-ignore-fields mm2txt and mm2ply: Add new option –ignore-missing-fields
Merge pull request #34 from MOLAorg/feat/mm2txt-mm2ply-more-precision Exploit the maximum float32/float64 precision in exported txt formats
Merge pull request #33 from MOLAorg/feat/sm2mm-new-options Feat/sm2mm-new-options
sm2mm cli app: add new flags for downsampling options
sm2mm: add new downsample options and refactor into update_velocity_buffer_from_obs()
Contributors: Jose Luis Blanco-Claraco
2.4.1 (2026-01-27)
Add more unit tests
Update README to keep it in sync with the provided apps and libraries
Merge pull request #29 from MOLAorg/fix/cov Fix bugs in covariance estimation for some cases
fix covariance estimation bugs; add unit tests for cov2cov
Update commit for mola_common
Merge pull request #28 from MOLAorg/feat/mm-viewer-3d-layers mm-viewer: add CLI flags to load overlaid 3D scenes for visualization
mm-viewer: add CLI flags to load overlaid 3D scenes for visualization
Contributors: Jose Luis Blanco-Claraco
2.4.0 (2026-01-21)
Merge pull request #27 from MOLAorg/feat/new-filter-voxel-sor
Add new unit test for class factory
Add new FilterVoxelSOR filter
Merge pull request #26 from MOLAorg/feat/mm2las
Add mm2las CLI tool
Contributors: Jose Luis Blanco-Claraco
2.3.1 (2026-01-14)
Merge pull request #25 from MOLAorg/feat/naive-decimate Add trivial FilterDecimate for fast downsampling without spatial awareness
lint fixes
Add trivial FilterDecimate for fast downsampling without spatial awareness
Parameterizable: add virtual base dtor
Remove the NormalizeIntensity stage in the demo pipelines; visualization does that already
docs: fill missing manpages
docs: add sm2mm pipelines page
Clarify map layers and simple maps descriptions Updated references to CMetricMap and CGenericPointsMap in the documentation for clarity and accuracy.
Contributors: Jose Luis Blanco-Claraco
2.3.0 (2026-01-08)
Merge pull request #24 from MOLAorg/feat/mm2txt-select-fields mm2txt and mm2ply now have a –export-fields flag
mm2txt and mm2ply now have a –export-fields flag
Merge pull request #23 from MOLAorg/fix/some-deprecations Fix usage of deprecated cloud types
Provide shortcut names for common cloud field names
More deprecated cloud usage
FIX bug: FilterDecimateVoxel, if using flatten, did not propagate all input cloud fields
Fix usage of some deprecated cloud types
FilterSOR: create output layers even if input is empty
FilterDeskew: propagate input fields even if the cloud is empty
FilterByExpression: show debug-level stats
FilterNormalizeIntensity: do not throw on empty clouds
Merge pull request #22 from MOLAorg/feat/new-filters Add new filter FilterRenameLayer
Added filter FilterRenameLayer
mm2txt: prepare for deprecated classes in 3.0.0
FilterAdjustTimestamps: new method ‘None’ to bypass filter
Fix: sm2mm did not attach to ParameterSource the final_filter elements
sm2mm: did not observe the optional profiler parameter for the final_filter stage
Fix: FilterMLS did not properly copy all point fields when using upsampling
Fix: FilterAbsoluteTimestamp now also works for accumulated points in one layer
Contributors: Jose Luis Blanco-Claraco
2.2.1 (2026-01-06)
Merge pull request #21 from MOLAorg/feat/abs-stamp-filter Added new filter: FilterAbsoluteTimestamp
Fix the logic of the FilterEdgePlane filter parameters
Added new filter: FilterAbsoluteTimestamp
mm2txt: also export uint8 fields (missing in last release)
Merge pull request #20 from MOLAorg/feat/more-unit-tests More unit tests
Add generators unit tests
More unit tests
Contributors: Jose Luis Blanco-Claraco
2.2.0 (2025-12-28)
docs: explain FilterSOR
Merge pull request #19 from MOLAorg/feat/mm2ply Add mm2ply CLI tool
Merge pull request #18 from MOLAorg/feat/new-sor-filter Add FilterSOR: Statistical Outlier Rejection
More unit tests: cover MLS
Merge pull request #17 from MOLAorg/feat/filter-by-expr Add new filter: FilterByExpression
More code coverage; fix protected-level initialize methods
Add new filter: FilterByExpression
FIX: missing uint8 fields in Deskew
sanityCheck: also check all double/uint8 fields
ui: fix case without geo-ref
mm-viewer: show lat/lon coordinates for mouse selected points
mm-viewer: GUI now shows the ENU & map miniviews for orientation hints
mm-viewer: handle special coloring channel groups ‘rgb’ and ‘rgbf’
clean non used code in deskew test
map viz: use new mrpt 2.15.3 coloring modes
sm2mm: auto-guess lazy-load externals directory for .simplemap files
mm-viewer: implement colorize clouds by any field
MLS filter: add ‘output_layer_class’ parameter
mm2txt: export all fields of CGenericPointsMap layers
Merge pull request #16 from MOLAorg/fix/generic-cloud-deskew-fields Add test for missing fields in generic cloud deskew
FIX: correctly register arbitrary pointcloud fields into output clouds
Add test for missing fields in generic cloud deskew
sm2mm: FIx console message on “FinalFilters” did not obey verbosity level
Fix clang-tidy warnings
Contributors: Jose Luis Blanco-Claraco
2.1.2 (2025-11-28)
mm-viewer: Automatic retry to load maps if missing plugins, trying to reload with libmola_metric_maps.so
Enable coverage run for noble docker image
Add new unit tests
docs: fix broken formatting of filters page
Merge pull request #14 deskew filter: refactoring to handle arbitrary point fields
get code ready for API update in MRPT 2.15.3
Fix build w/o imu library
mm-viewer: add keystrokes shift+cursor arrows to move up/down
Add Codecov badge to README
MLS filter: add progress report logging
Contributors: Jose Luis Blanco-Claraco
2.1.1 (2025-11-08)
FIX: SanityCheck was triggering as errors optional pointcloud fields in XYZIRT clouds
FIX: Throw exception instead of crashing if FilterDeskew is invoked with an empty local velocity buffer
Fix yaml file for not using mola_yaml extensions
Add more sm2mm demo pipelines
Contributors: Jose Luis Blanco-Claraco
2.1.0 (2025-10-28)
Merge pull request #13 from MOLAorg/fix/filterdecimate-bug
Add unit test for FilterDecimateVoxel
mm-viewer: ensure proper order of opengl object destruction
Add more debug traces for Filters
Generator: Add more info on layer contents in debug traces
FIX: Avoid crash in FilterVoxelSlice if there are no points in the ROI
Merge pull request #12 from MOLAorg/feat/mls Implemented MLS filter
Merge pull request #11 from MOLAorg/feat/use-faster-insertion Use the faster insertion-with-context in MRPT 2.15.0
Update to build using CGenericPointsMap in upcoming MRPT >=2.15
Merge pull request #10 from MOLAorg/fix/ci
Upgrade CircleCI images to u24.04
Fix build out of ROS and w/o IMU preintegration
Update mola_common version
Fix: Warning message missing new line
FilterDecimateVoxels: add new parameter ‘minimum_points_per_voxel’
Fix docs typo
Update docs for Deskew filter
Update README.md badges
Contributors: Jose Luis Blanco-Claraco
2.0.0 (2025-10-13)
Merge pull request #9 from MOLAorg/feature/better-lio Better LIO
sm2mm cli app: add –profiler flag
demo sm2mm pipelines: add deskew method entry
CI: Add another pipeline without TBB
FIX: bug in non-TBB serial implementation of GN optimizer
CI: add running unit tests
FIX: potential crash in FilterDeskew
Add deskew unit tests
Add unit test for cov2cov optimizer
Add ‘name’ property to all generators and filters for disaggregated stats
Allow building without the IMU library
Update mola_common to 0.5.1
clang-tidy fixes
Remove dead code
Refactor errorTerm for pt2pt for better reusability
mm-viewer: add combo box to select intensity colormap
Add docs for filters
BUGFIX: FilterMerge would lost all point fields except XYZ
Remove external libpointmatcher
Update formatter script
icp log viewer: more options for cov2cov visualization
Define virtual API MetricMapMergeCapable
fix bug in FilterByIntensity params parser
Render cov2cov pairings
FilterByRange new parameter: metric_l_infinity
FilterDecimateAdaptive now exploits parallelization
Progress visualizing cov2cov pairings
New cov2cov ICP optimizer
Implement a new Cov2Cov matcher
Make Matcher_Points_Base::transform_local_to_global() to use TBB, and remove unused parameters
Add [[nodiscard]] to estimate_points_eigen()
BBox filter: fix target layer must be same type than input
Use fractional integers for faster sampling
New FPS filter
Remove FilterDecimateVoxelsQuadratic
Style: public ‘params_’ rename as ‘params’
New interface ‘IcpPrepareCapable’
Add new virtual interface NearestPointWithCovCapable
Refactor mp2p_icp_map into mp2p_icp_common for IMU-related parts
Finished integration of new IMU API package
Depend on imu external library
Move code out to the imu preintegration package
Move LocalVelocityBuffer to the IMU repository
Add [[nodiscard]] to icp_pipeline_from_yaml()
deskew filter: new option ‘in_place’ to avoid allocating a new cloud whenever possible
Finish implementation of higher-order IMU interpolator
Implement trajectory reconstruction for deskew
cmake files: prefer spaces indentation
Add imu preintegration package as dependency
FilterNormalizeIntensity can now use a fixed min/max range given by hand
Docs: update mp2p_icp_basics for better searchability of simplemaps
New option to set pointcloud alpha channel
Contributors: Jose Luis Blanco-Claraco
1.8.0 (2025-08-26)
Modernize and unify license notes in all files
Merge pull request #8 from MOLAorg/feat/precise-deskew Precise scan deskew: - Implement LocalVelocityBuffer inside ParameterSource’s - Update LocalVelocityBuffer from IMU data from Generators. - Export / Import LocalVelocityBuffer to/from YAML - Implement precise cloud undistortion in FilterDeskew - Use precise cloud undistortion in the context of sm2mm.
sm2mm: Use local velocity buffer if available
add serialization to velocity buffer
Generators now handle IMU readings and forward them to the velocity buffer
Update to latest mola_common for embedded builds
linter: clang-tidy fixes
fix param name for better consistency
feature: Option to use std::map instead of tsl robin_map in voxelization filters
docs: fill txt2mm man page
Feature: txt2mm new import format ‘xyzrgb_normalized’
remove code to support older MRPT versions; code style clean ups
Fix: FilterAdjustTimestamps may trigger exception if input cloud is empty
Contributors: Jose Luis Blanco-Claraco
1.7.1 (2025-06-20)
docs: Populate sm2mm app page
New feature: all pipeline modules now has an optional “plugin” YAML field to load them from user-provided plugins.
Update REAME ROS badges
Contributors: Jose Luis Blanco-Claraco
1.7.0 (2025-06-02)
metric map data type: add new metadata YAML field
Update broken link to ROS Index
docs: change references to default branch master->develop
Default generator: more details in debug traces when ignoring an observation
Update package license tag to “BSD-3-Clause”
Integrate vscode with colcon custom settings and clang-tidy
Fix build unit tests with older gcc versions
Drop apparently useless build dep
Contributors: Jose Luis Blanco-Claraco
1.6.7 (2025-04-03)
mm-georef cli app: support reading/writing georef info in YAML format
georeferencing metadata now can be read/writen as YAML files
clang-format: switch to column limit=100
Update to robin-map v1.4.0
Contributors: Jose Luis Blanco-Claraco
1.6.6 (2025-02-26)
Docs: add page for mm-georef
docs: Update 2025 paper citation
print metric_map_t as string: show lat/lon coordinates in a format directly compatible with Google Map searches.
New cli tool: mm-georef, to manipulate the geo-referencing metadata of metric map files
Contributors: Jose Luis Blanco-Claraco
1.6.5 (2025-01-28)
Add GitHub actions
Add pole-detector filter
mm-filter app: add –load-plugins flag too
Add sanity check assert in FilterDeskew
Contributors: Jose Luis Blanco-Claraco
1.6.4 (2024-12-18)
merge two docs pages in one to shorten the docs TOC
Update README.md: Mark ROS2 Iron as EOL
Also use TBB for parallel solving point-to-plane pairings
Contributors: Jose Luis Blanco-Claraco
1.6.3 (2024-11-11)
icp-log-viewer: also reduce GUI refresh rate
mm-viewer: avoid useless GUI refresh (CPU usage reduction)
txt2mm: Add input filter xyzrgb
mm-viewer: add a ‘fit view to map’ button
New cli app rawlog-filter
FilterCurvature: better handling scans with <=3 points in some rings
new subcommand ‘sm-cli tf’
Contributors: Jose Luis Blanco-Claraco
1.6.2 (2024-09-14)
Expose << and >> operators for geo-reference data structures
Fix missing build_dep
Contributors: Jose Luis Blanco-Claraco
1.6.1 (2024-09-11)
Fix missing catkin buildtoo_depend for ROS1 builds
Update RTTI macros for upcoming MRPT 2.14.0
Contributors: Jose Luis Blanco-Claraco
1.6.0 (2024-09-08)
Port Point2Plane matcher to use the new NN-for-planes API
mp2p_icp_map library: add NearestPlaneCapable virtual API
cmake: move from glob expressions to explicit lists of source files
clarify eigenvalues order in headers
Contributors: Jose Luis Blanco-Claraco
1.5.6 (2024-09-07)
sm2mm cli: show map contents before writing to disk
add another demo sm2mm file for the mola tutorials
Add another sm2mm demo file w/o deskew for the mola mapping tutorial
Matcher_Point2Plane: fix build error in armhf
Fix build with embedded mola_common
README: Add ROS badges for all architectures
Contributors: Jose Luis Blanco-Claraco
1.5.5 (2024-08-27)
Explicitly add tbb as dependency in package.xml
Depend on new mrpt_lib packages (deprecate mrpt2)
FIX: build errors in armhf arch
Contributors: Jose Luis Blanco-Claraco
1.5.4 (2024-08-20)
Do not use Eigen::Vector for compatibility with Eigen3 <3.4 in ROS Noetic
Contributors: Jose Luis Blanco-Claraco
1.5.3 (2024-08-20)
Re-add ROS1 Noetic as supported distribution
Generator sanity check asserts: more informative error messages
sm-cli: new command ‘join’ to merge simplemaps
icp-log-viewer UI: new keybind ‘I’ to switch initial/final pose
icp-log-viewer UI: add option to visualize voxelmaps empty space
Contributors: Jose Luis Blanco-Claraco
1.5.2 (2024-07-24)
Add sm2mm yaml example for dynamic/static obstacles
Update sample sm2mm pipelines to use de-skew
docs: add mm-filter example
Fix pointcloud ptr typo
More safety sanity checks added in mm-viewer and sm2mm
BUGFIX: Generator should not create empty maps for GPS observations
Contributors: Jose Luis Blanco-Claraco, Raúl Aguilera López
1.5.1 (2024-07-03)
Update docs
ICP: Add optional functors for before-logging maps
icp-log-viewer UI: fix potential out-of-range exception when autoplay is on
FilterAdjustTimestamps: add new param ‘time_offset’ useful for multiple LiDARs setups
Contributors: Jose Luis Blanco-Claraco
1.5.0 (2024-06-21)
ICP: Add optional user-provided per-iteration hooks
Add new filter: FilterByRing
Add new filter: FilterAdjustTimestamps
Add sanity checks for point cloud fields.
Fix typo in default class for FilterDeskew
generators API: add bool return type to detect if observation was actually processed
generic Generator: handle velodyne observations so timestamps are generated
Contributors: Jose Luis Blanco-Claraco
1.4.3 (2024-06-11)
Add pointcloud_sanity_check() auxiliary function
Generator: more DEBUG level traces
BUGFIX: FilterDeskew generated buggy output points if the input does not contain timestamps
Add sanity checks for point cloud fields
ICP log records now also store the dynamic variables. icp-log-viewer displays them.
ICP log files: automatically create output directory if it does not exist
Update ros2 badges (added Jazzy)
Contributors: Jose Luis Blanco-Claraco
1.4.2 (2024-05-28)
mm-viewer: add check-all, check-none to layer filters
Add new filter: FilterRemoveByVoxelOccupancy
mm-viewer: camera travelling keyframes-based animations
mm-viewer: navigate the map with keyboard arrows; add a load button
mm-viewer: can now also draws a TUM trajectory overlaid with the map
UI apps: smoother rendering
icp-log-viewer and mm-viewer: the UI now has a XYZ corner overlay
sm-cli: command “export-kfs” now has an optional flag ‘–output-twist’
FilterDeskew: ignore empty input maps
More debug-level traces
deskew filter: Fix case of variable names in docs
sm-cli app: Add new command ‘trim’ to cut simplemaps by bounding box
mm-viewer: show mouse pointing coordinates
Contributors: Jose Luis Blanco-Claraco
1.4.1 (2024-05-19)
Fix build for older mrpt versions
ICP pipelines: Implement loading
quality_checkpointsparameter from YAML config fileQuality evaluators: add the option for ‘hard discard’
Update QualityEvaluator_Voxels to use prebuilt voxel layers from input maps. Add unit tests.
BUGFIX: Fix deserializing georeferenced .mm files stored in <1.4.0 format
ICP: quality evaluators can now have formulas in their parameters too
mm-viewer and icp-log-viewer: extend zoom range so maps of tens of kms can be viewed at once
Contributors: Jose Luis Blanco-Claraco
1.4.0 (2024-05-06)
Update commit for robin-map to latest version (patch contributed upstream)
icp-log-viewer: UI now has a slider for each map point size
ICP: Add a new quality_checkpoint parameter to early abort ICP attempts
georeferenced maps: T_enu_to_map now has a covariance field
mm-viewer: display ENU frame too
Contributors: Jose Luis Blanco-Claraco
1.3.3 (2024-04-30)
Add minimum_input_points_to_filter option to FilterDecimateVoxels
FIX: QualityEvaluator_PairedRatio throws when one of the reference maps is empty
FIX BUG: Won’t try to match 2D pointclouds if their height is different
Clarify comments in metricmap.h about geodetic references
Fix printing metric_map_t contents when it only has a gridmap
Fix potential dangling references (g++ 13 warning)
Fix potential use of uninitialized point index
Bump cmake_minimum_required to 3.5
Contributors: Jose Luis Blanco-Claraco
1.3.2 (2024-04-22)
tsl::robin_map library is no longer exposed neither in the public API nor as public headers (PIMPL pattern) This is to prevent Debian-level collisions with other packages also exposing it.
add first icp-log-viewer docs
Contributors: Jose Luis Blanco-Claraco
1.3.1 (2024-04-16)
mm-viewer and icp-log-viewer: saves UI state in persistent user config file
FIX: missing UI refresh when clicking showPairings checkbox
renamed apps for less verbose names: icp-run, icp-log-viewer
ICP core now defines a variable ICP_ITERATION for use in programmable formulas in pipelines
icp-log-viewer: much faster rendering of ICP iteration details
mm-viewer: fix bug in calculation of bounding box
Merge docs with main MOLA repo
Contributors: Jose Luis Blanco-Claraco
1.3.0 (2024-03-10)
mm-viewer: new options to visualize georeferenced maps
New sm-cli commands: –cut, –export-keyframes, –export-rawlog
propagate cmake deps downstream
metric_map_t: add georeferencing optional field
mm-filter: add –rename operation
GetOrCreatePointLayer() moved to its own header and uses shared ptrs
FilterMerge: add param input_layer_in_local_coordinates
Contributors: Jose Luis Blanco-Claraco
1.2.0 (2024-02-16)
Add new apps: sm-cli, mm-info, txt2mm, mm2txt, mm-filter
Improved documentation.
new filter FilterByIntensity
FilterNormalizeIntensity: add option for intensity range memory
FilterByRange: renamed params to simplify them (removed param ‘keep_between’)
FIX: missing intensity channel in decimate voxel when using some decimation methods
sm-cli: new subcommand ‘level’ to maximize the ‘horizontality’ of built maps
add optional profiler to filter pipelines
Contributors: Jose Luis Blanco-Claraco
1.1.1 (2024-02-07)
MergeFilter: now also handles CVoxelMap as inputs
more memory efficient defaults
FilterCurvature: now based on ring_id channel
Use hash map min_factor to speed up clear()s
add missing hash reserve
PointCloudToVoxelGridSingle: Fix wrong initialization of point count
Contributors: Jose Luis Blanco-Claraco
1.1.0 (2024-01-25)
FilterDecimateVoxels: Replace 3 bool parameters with an enum
Fix clang warnings
Save and visualize ICP step partial solutions
QualityEvaluator_PairedRatio: now does not require parameters
Add filter: Bonxai VoxelMap -> 2D gridmap. Bayesian filtering of voxel columns
Generator: allow defining custom metric maps directly in the YAML configuration
Contributors: Jose Luis Blanco-Claraco
1.0.0 (2024-01-20)
Gauss-Newton solver: Add optional prior term
Added FilterMerge and modifications to allow sm2mm to build any type maps
sm2mm: add option for lazy-load external directory
Decimate filter: add flatten_to option to efficiently convert 3D->2D point clouds
FilterBoundingBox: parameter name changed for clearer split of inside / outside bbox
Deskew: add option to bypass de-skew operation
bump minimum required mrpt version
Better coloring; add option to export mm layers
Use new mrpt api to propagate point properties; add final_filter stage to sm2mm
sm2mm: add verbosity flag
bbox filter: allow processing variables too
Introduce robot_{x,y,z} variables
Better mm-viewer; update sm2mm demo file
Progress with RST docs
Add missing robotPose argument to generators; progress with mm-viewer
Add sm2mm app
Add FILE attribute to license tag
More dynamic parameters
fix print format
Add Deskew filter
update CI to u22.04
Introduce Parameterizable interface
New layers: create of the same input cloud type
Add FilterCurvature
filter: optional additional layer for deleted points
FIX: important error in robust gradient
expose GN params as public
new generators and filters
Filters: use tsl robin_map, faster than std::unordered_map
prefer nn_radius_search() to exploit nanoflann rknn
Minor UI updates
gui: autoplay
estimate_points_eigen.h moved to the mp2p_icp_map library
Solvers: add option to select by correction magnitude
add [[nodiscard]] to generator API
Add specialized implementation of voxelize for 1 pt/vx
add Cauchy robust kernel
Add support for TBB for parallelization
add angularThresholdFactor; add max plane-to-pt distance
viewer UI: show number of points per layer
Prefer Teschner’s spatial hash
Use nn_single_search() when possible
viewer: add follow local checkbox
Add new filter: FilterDecimateVoxelsQuadratic
FilterDecimateVoxels: new option use_closest_to_voxel_average
FilterDecimateVoxels: new param use_random_point_within_voxel
less unnecesary mem allocs
generator: create map layers first, then filter by observation name/class filter
port to NN radius search
add “enabled” property to base Matcher class
Solvers: add property ‘enabled’
Add robust kernels to GN solver
Add optional profiler to ICP
New parameter decimationDebugFiles
Add plugin option to viewer
VoxelFilter: is now ~7 times faster and does not need a bounding box parameter, thanks to using an associative container.
viewer: add new flag -f to load one single log file
viewer: increase slider range for max far plane
Options to recolorize maps in icp log viewer
Fix regression in rendering options for point clouds
Matcher: new parameter bounding_box_intersection_check_epsilon
New env var MP2P_ICP_GENERATE_DEBUG_FILES can be use to override generation of icp log files
BUGFIX: Ignored sensorPose for Generator::filterPointCloud()
Allow ICP matching against voxel metric map types
mp2p_icp_filters::Generator now can create a map from a generic INI file (e.g. voxelmaps)
fix references to old pointcloud_t -> metric_map_t
Remove support for MRPT<2.4.0
Contributors: Jose Luis Blanco-Claraco
0.2.2 (2023-09-08)
Fix missing cmake dependencies between libraries
Update mola_common
Refactor into a new small library mp2p_icp_map with just the metric_map_t class
sync mola_common submodule
Update submodule mola_common
Remove redundant section
Update ROS badges
Contributors: Jose Luis Blanco-Claraco
0.2.1 (2023-09-02)
Update copyright date
Update to new name of mola_common
update ros badges
Contributors: Jose Luis Blanco-Claraco
0.2.0 (2023-08-24)
First release as MOLA submodule.
0.1.0 (2023-06-14)
First official release of the mp2p_icp libraries
Contributors: FranciscoJManasAlvarez, Jose Luis Blanco-Claraco