Robotics - [3D SLAM - 2] Scan Matching Hands-On Notes

Preact-Mojave, Lidar-Only Front-End

Posted by Rico's Nerd Cluster on March 3, 2025

Preact-Mojave Build & Workflow

The ROS2 driver for Preact-Mojave can be found here. When testing it, I ran into below questions:

  • Why make provision & make ros2?
    • make provision installs any missing OS-level deps via apt-get install ….
    • make ros2 runs colcon build in the ros2/ subfolder with the right flags.
      • The top-level Makefile actually does cd ros2 && colcon build --merge-install.
      • If you run colcon build at the root without an install space or without ROS_PACKAGE_PATH pointing at ros2/, your packages won’t be found.
  • The driver’s visualization seems noisy. Is it possible to make it look better?
    • Search for the official promo video and download the highest-quality version before visualizing.
    • I bumped up the point size and tweaked the colors so the 3D view is crystal-clear.
  • Lidar Odometry: Keyframes vs. full matching
    • Only add keyframes into your point-cloud map.
    • But don’t skip frame-to-frame matching—this detailed check often exposes alignment issues that keyframe-only tests miss.
    • Leaf size tuning
      • Beware: lowering the leaf size too much can break alignment.
      • add_scan_leaf_size: 0.1 (default)
  • How bad are scan distortions? It could definitely create odometry drift. In the below snapshot, a wall is “curved” instead of being straight.

SLAM Pipeline Issues And Improvements

  • .getFitnessScore() actually returns the mean squared distance from each point in the source cloud to its closest point in the target cloud. By itself, this metric can be misleading—two scans that share only a large, flat plane may outperform a correct pair that has lots of small features

Front End Improvements

  • Switch to PCL’s NDT implementation.

Point filtering

  • Moving-Least-Squares Smoothing takes up around 80ms to per ~20k points. The surface of objects are smoother, but in many cases, this smoothing does not change point distribution much and is optional
    • How it works: 1. Fit a plane H across a set of points. 2. Calculate height of each point w.r.t H, $p_i$, and their projections onto H, $(x_i, y_i)$ 3. Fit a low-degree bivariate polynomial g(x,y) across all $p_i$. Then, the output MLS points are $g(x_i, y_i)$

      Left: no MLS, Right: with MLS

Loop Detection Improvements

  • Reject single-plane match by hessian conditioning:
\[\begin{gather*} \begin{aligned} & cond = \frac{\lambda_{max}}{\lambda_{min}} \end{aligned} \end{gather*}\]

The ndt hessian

  • Symmetric Fitness Check: Run NDT A->B and B->A

Gotchas

  • Appllying rotation to translation in motion updates does make this estimate better
  • In motion prediction, use the half motion to reduce the effect of noisy last pose