Skip to content

rsasaki0109/localization_zoo

Repository files navigation

Localization Zoo

C++ implementations, derived variants, and compact baselines for localization papers

C++17 ROS2 Humble Reimplementations and Derived Variants CTest MIT License


Why Localization Zoo?

Many localization papers do not ship reusable reference implementations. This repository collects paper-oriented C++ implementations behind a unified API, with ROS 2 nodes and evaluation tools that are ready to run.

  • Pure C++: ROS-independent core libraries for research, education, and embedded use
  • ROS 2 Humble: Ready-to-run nodes via ros2 run
  • Built-in benchmarking: Compare methods immediately after build
  • Degeneracy-aware methods: Includes RELEAD and X-ICP for constrained environments

Scope Note

This repository mixes three levels of implementation scope:

  • Paper reimplementation: intended to track the published method closely
  • Derived variant: built from the paper idea, but adapted to this repository's shared components
  • Compact baseline: a smaller approximation that keeps the interface and core intuition, but not the full paper pipeline

Methods already labeled Derived or Hybrid are intentionally adapted versions. Some paper-named entries still use compact or simplified internals today, especially NDT, KISS-ICP, and DLIO. Check each method README for current scope and deviations.


Experiment-Driven Development

This repository now keeps a small stable benchmark core and a discardable experiment layer. The current search state is externalized here:

Concrete variants live under experiments/ and are meant to be compared, challenged, and replaced. The matrix runner tracks the generated problem set in experiments/results/index.json across Istanbul windows, HDL-400 reference windows, public ROS1 HDL-400 synthetic-time windows, MCD (Ouster) windows, and KITTI Raw (short and full-sequence windows). For heavy KITTI Raw full-sequence HDL Graph SLAM runs, the repository now keeps truthful exceptions instead of inventing pseudo-equivalent lightweight profiles: kitti_raw_0009_full stays default-only, and kitti_raw_0061_full stays skipped. docs/interfaces.md lists the current active selectors wired into pcd_dogfooding; the full integration surface is intentionally broader than any single manuscript-facing subset. CT-LIO and CLINS now both have public ROS1 HDL-400 synthetic-time comparisons, while GT-backed public CT-LIO remains blocked pending an independently curated trajectory CSV for that LiDAR+IMU stack. Those public ROS1 synthetic-time runs are useful comparative evidence, but they should be treated as a separate public-only benchmark, not as an exact native per-point-time reproduction of the reference/native-time HDL-400 setup.

Three-step sanity check (after clone)

cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j"$(nproc)"
bash evaluation/scripts/smoke_ci_fixture.sh

To run ctest, synthetic_benchmark, and the same smoke fixture in one go: bash evaluation/scripts/run_local_evaluation_suite.sh (see evaluation/README.md).

The fixture is a three-frame MCD slice committed under evaluation/fixtures/mcd_kth_smoke/ (~3MB); the same script runs in GitHub Actions after ctest. Full experiment docs need local dogfooding_results/ trees: python3 evaluation/scripts/refresh_study_docs.py (or see evaluation/scripts/SETUP_PUBLIC_BENCHMARK_WINDOWS.md).

python3 evaluation/scripts/run_experiment_matrix.py

Use --reuse-existing to regenerate docs and aggregates from stored summaries without rerunning every benchmark. Use --manifest experiments/<name>_matrix.json only for local iteration; a manifest-only run rewrites experiments/results/index.json to that subset, so commit paths should finish with python3 evaluation/scripts/refresh_study_docs.py (or a full run_experiment_matrix.py without --manifest). Use python3 evaluation/scripts/refresh_study_docs.py to refresh both experiment docs and publication docs together. Publication docs alone can be regenerated with python3 evaluation/scripts/generate_publication_docs.py. Paper-ready tables and Pareto figures can be regenerated with python3 evaluation/scripts/export_paper_assets.py.


Benchmark

Real LiDAR Data

The repository currently ships one real-data benchmark snapshot from the official Autoware Istanbul localization bag. GitHub Pages publishes the latest repository-stored report from docs/benchmarks/latest/results.json. The table below is the last full multi-method snapshot. Per-method profile adoption decisions are tracked separately in docs/decisions.md. The current snapshot uses a speed-oriented dogfooding profile with recent/local-map pruning. LiTAMIN2 additionally uses OpenMP-enabled voxel-map and cost accumulation in this repository, with the benchmark profile defaulting to half of the detected hardware threads. For GT-seeded scan-to-map methods, weak updates fall back to the seed pose instead of forcing a poor refinement.

  • Topic: /localization/util/downsample/pointcloud
  • Window: frames 10200-10307
  • Sequence length: 108 frames, 302.1 m, 10.70 s
  • Reference poses: reference_pose_full.csv
  • Scan density: 940-1380 points per frame, 1128.7 average
Method Status ATE [m] FPS Notes
NDT OK 0.109 1.2 GT-seeded scan-to-map init with weak-update fallback; current snapshot uses a recent/local-map profile
LiTAMIN2 OK 1.213 21.0 GT-seeded scan-to-map init with weak-update fallback; current snapshot uses a recent/local-map profile plus OpenMP parallelism
GICP OK 0.994 3.1 GT-seeded scan-to-map init with weak-update fallback; current snapshot uses a recent/local-map profile
CT-ICP OK 75.075 1.3 Odometry-only; ATE is measured after anchoring to the first GT pose
KISS-ICP OK 183.178 3.2 Odometry-only; ATE is measured after anchoring to the first GT pose
CT-LIO SKIPPED - - The bag window does not contain IMU data, so imu.csv was not generated

Autoware Istanbul benchmark

./pcd_dogfooding <pcd_dir> <gt_csv> [max_frames] --methods <selector> --summary-json <path> [variant flags...] evaluates sequential PCD datasets against a shared trajectory CSV contract. The exact current selector list and manifest contract are generated in docs/interfaces.md. Method-specific profile flags now span the older paper-style families plus newer graph/LIO surfaces such as --hdl-graph-slam-*, --vgicp-slam-*, --suma-*, --balm2-*, --isc-loam-*, --loam-livox-*, --lio-sam-*, --lins-*, --fast-lio-slam-*, --point-lio-*, and --clins-*.

CT-LIO and CLINS expect imu.csv plus a dense raw LiDAR sequence. Sparse keyframe or submap sequences such as graph/000000xx/cloud.pcd are skipped automatically.

To extract a raw sequence from ROS 1 bags, use ./evaluation/scripts/extract_ros1_lidar_imu.py --pointcloud-bag corrected.bag --imu-bag record_slam.bag --output-dir dogfooding_results/raw_seq.

To build a KITTI Raw sync export (Velodyne *.bin + OXTS) into the sequential NNNNNNNN/cloud.pcd layout plus a trajectory CSV, run:

python3 evaluation/scripts/kitti_raw_to_benchmark.py \
  --drive-dir /path/to/2011_09_26_drive_XXXX_sync \
  --output-dir dogfooding_results/kitti_raw_XXXX \
  --gt-csv experiments/reference_data/kitti_raw_XXXX_gt.csv \
  --write-imu-csv   # optional: writes imu.csv for DLIO/CT-LIO (OXTS-derived, index-aligned stamps)

If you already have a dogfooding tree and only need imu.csv, use python3 evaluation/scripts/kitti_oxts_imu_for_dogfooding.py --drive-dir <sync> --pcd-dir <dogfooding_dir>.

To reproduce the repository-stored Istanbul run from a ROS 2 bag:

python3 -m pip install rosbags numpy matplotlib

python3 evaluation/scripts/extract_ros2_lidar_imu.py \
  --bag ../lidarloc_ws/data/official/autoware_istanbul/localization_rosbag \
  --pointcloud-topic /localization/util/downsample/pointcloud \
  --output-dir dogfooding_results/autoware_istanbul_open_108 \
  --start-frame 10200 \
  --max-frames 108

python3 evaluation/scripts/reference_pose_to_gt_csv.py \
  --input ../lidarloc_ws/data/official/autoware_istanbul/reference_pose_full.csv \
  --output dogfooding_results/autoware_istanbul_open_108_gt.csv

./build/evaluation/pcd_dogfooding \
  dogfooding_results/autoware_istanbul_open_108 \
  dogfooding_results/autoware_istanbul_open_108_gt.csv \
  --methods litamin2,gicp,ndt,kiss_icp,ct_lio,ct_icp

LiTAMIN2, GICP, and NDT currently use GT-seeded scan-to-map initialization inside pcd_dogfooding so that sequential PCD exports remain comparable. If a refinement step becomes weak or unstable, the current dogfooding profile falls back to that seeded pose instead of forcing the update. --litamin2-paper-profile switches LiTAMIN2 to a more paper-like setting centered on voxel_resolution=3.0. --litamin2-icp-only disables the covariance-shape term so the first KL-derived distance term can be benchmarked on its own. --litamin2-max-source-points caps the per-frame source cloud after voxel filtering, and --litamin2-num-threads overrides the OpenMP worker count. KISS-ICP and CT-ICP remain odometry-style methods in this tool, so their absolute ATE is reported after anchoring the estimated trajectory to the first GT pose. For long runs, methods can be filtered with ./pcd_dogfooding ... --methods gicp,ndt,kiss_icp. --ct-lio-estimate-bias is experimental and carries the previous-frame bias with a random-walk prior. --ct-lio-fixed-lag-window 4 enables a short history prior on velocity and bias. Current defaults are velocity_weight=0.0, gyro_bias_scale=0.25, accel_bias_scale=0.25, and history_decay=1.0. Lower history_decay biases the prior toward the most recent state. --ct-lio-fixed-lag-smoother re-optimizes begin/end pose + begin_velocity + bias inside the window with local point-to-plane and IMU residuals. --ct-lio-fixed-lag-outer-iterations controls correspondence relinearization passes in the smoother. The current default is 3 for accuracy; 1 is lighter but usually hurts long-run ATE. For public HDL-400 experiments, this repository now also supports a reference-trajectory CSV converted from pose_trace.csv via python3 evaluation/scripts/pose_trace_to_gt_csv.py. For additional HDL-400 windows, python3 evaluation/scripts/slice_trajectory_csv_by_frames.py can slice the shared reference CSV to the timestamp span covered by a newly extracted frame_timestamps.csv. The repository keeps those reference/native-time-style HDL-400 windows separate from the public ROS1 synthetic-time reconstructions under dogfooding_results/hdl_400_ros1_open_ct_lio_*_time_index. The latter are public and reproducible from the released ROS1 bag, but they use synthesized per-point time and therefore should not be described as exact native-time reproduction.

Synthetic Urban (30 frames)

Method         ATE [m]     FPS
─────────────────────────────────
CT-ICP         0.124       0.1   << best accuracy
A-LOAM         2.059       4.6   << balanced baseline
X-ICP          16.634      5.9
LiTAMIN2       31.155      2.6

Reproduce with ./synthetic_benchmark. No external dataset is required.


Implementations

Point Cloud Registration

Paper Venue Key Idea Reference
LiTAMIN2 ICRA 2021 KL-divergence ICP with aggressive point reduction for faster registration arXiv
GICP RSS 2009 Plane-to-plane ICP with local covariance modeling and Mahalanobis distance Paper
Voxel-GICP RA-L 2021 GICP accelerated with voxel representatives and voxel-level covariance Paper
small_gicp Derived Compact GICP with voxel downsampling and capped correspondences GitHub
VGICP-SLAM Derived Voxel-GICP front-end with Scan Context and loop-graph back-end -
NDT IROS 2003 NDT-style registration against voxel Gaussian models with a compact optimizer Paper
KISS-ICP RA-L 2023 Compact KISS-ICP-style pipeline with voxel hashing, adaptive thresholds, and robust ICP Paper
A-LOAM RSS 2014 Curvature-based feature extraction with a three-stage odom-to-map pipeline GitHub (ROS1)
F-LOAM Derived Lightweight LOAM pipeline with input thinning and sparse map updates -
ISC-LOAM Derived Lightweight LOAM with intensity descriptors and F-LOAM/GICP loop graph -
LOAM Livox Derived LOAM variant for solid-state LiDAR using pseudo scan lines from azimuth sectors Reference
LeGO-LOAM IROS 2018 Ground-aware feature extraction for vehicle-oriented LOAM Paper
MULLS Derived Multi-metric scan-to-map alignment using edge, plane, and point residuals -
BALM2 T-RO 2022 Local bundle adjustment over recent keyframes with line and plane residuals arXiv
SuMa RSS 2018 Dense surfel-based point-to-plane odometry from range-image maps GitHub
DLO Derived Direct keyframe odometry that aligns dense scans to a local GICP map GitHub
HDL Graph SLAM Derived NDT front-end with floor priors, Scan Context, and GICP loop closures GitHub
CT-ICP ICRA 2022 Continuous-time registration with two poses per frame and SLERP motion compensation GitHub (ROS1)
X-ICP T-RO 2024 Constrained ICP using Hessian SVD to classify observable directions arXiv

Degeneracy-Aware Methods

Paper Venue Key Idea Reference
RELEAD ICRA 2024 Constrained ESIKF with projection-based suppression along degenerate directions arXiv
CT-ICP + RELEAD Hybrid Continuous-time CT-ICP interpolation combined with RELEAD degeneracy handling -

Foundations

Paper Venue Key Idea Reference
IMU Preintegration T-RO 2017 Preintegration on SO(3) with first-order bias correction for LIO pipelines Paper

LIO / Continuous-Time Fusion

Paper Venue Key Idea Reference
CT-LIO Hybrid Lightweight LIO that combines CT-ICP interpolation with IMU preintegration constraints CLINS
DLIO ICRA 2023 Compact DLIO-style LIO built on DLO-style registration plus IMU preintegration GitHub
LINS Derived Lightweight LiDAR-inertial estimator with iterated filtering and point-to-plane updates -
Point-LIO Derived Compact direct LIO with raw-point planarity correspondences and iterated filtering -
CLINS Derived Sequence pipeline version of CT-LIO-style continuous-time registration -
VILENS Derived Compact visual-lidar-inertial smoother with Point-LIO-style local maps and reprojection fusion -
LIO-SAM IROS 2020 Lightweight pose graph with A-LOAM front-end, Scan Context, GICP, and IMU rotation priors Paper
LVI-SAM Derived Compact visual-lidar-inertial SLAM built on top of a LIO-SAM-style pose graph -
VINS-Fusion Derived Compact visual-inertial odometry with landmark reprojection and IMU preintegration -
OKVIS Derived Fixed-window VIO with landmark reprojection and IMU preintegration -
ORB-SLAM3 Derived Compact visual-inertial SLAM with keyframe graph and overlap-based loop closure -
FAST-LIO2 T-RO 2022 Lightweight direct LIO with raw-point scan-to-map alignment and IMU prediction Paper
FAST-LIVO2 Derived Compact local visual-lidar-inertial odometry built on FAST-LIO2 poses and reprojection residuals -
R2LIVE Derived Compact visual-lidar-inertial SLAM combining FAST-LIO2 odometry and visual landmark factors -
FAST-LIO-SLAM Derived Lightweight graph SLAM with FAST-LIO2 front-end, Scan Context, and GICP loop closures -

Place Recognition / Loop Closure

Paper Venue Key Idea Reference
Scan Context IROS 2018 Lightweight place recognition with polar ring-sector descriptors and yaw-shift search Paper

Quick Start

# Dependencies (Ubuntu 22.04)
sudo apt install libeigen3-dev libpcl-dev libopencv-dev libceres-dev libgtest-dev

# Build and test
mkdir build && cd build
cmake .. && make -j$(nproc)
ctest

# Benchmark (no external data required)
./evaluation/synthetic_benchmark

ROS 2

cd ros2 && colcon build
source install/setup.bash

# Launch any algorithm node
ros2 run localization_zoo_ros litamin2_node
ros2 run localization_zoo_ros aloam_node
ros2 run localization_zoo_ros kiss_icp_node
ros2 run localization_zoo_ros ndt_node
ros2 run localization_zoo_ros ct_icp_node
ros2 run localization_zoo_ros gicp_node
ros2 run localization_zoo_ros dlo_node
ros2 run localization_zoo_ros ct_lio_node
ros2 run localization_zoo_ros fast_lio2_node
ros2 run localization_zoo_ros dlio_node
ros2 run localization_zoo_ros relead_node
ros2 run localization_zoo_ros xicp_node

# Play a rosbag
ros2 launch localization_zoo_ros play_rosbag.launch.py \
  bag_path:=/path/to/bag points_topic:=/velodyne_points

Evaluation

# Compare trajectories on any dataset such as KITTI, MulRan, nuScenes, or TUM
python3 evaluation/scripts/benchmark.py \
  --gt gt_poses.txt \
  --est LiTAMIN2:litamin2_poses.txt A-LOAM:aloam_poses.txt \
  --output_dir results/

Architecture

localization_zoo/
├── common/                    # Shared Eigen/PCL utilities
├── papers/
│   ├── litamin2/              # KL-divergence ICP
│   ├── gicp/                  # Generalized ICP
│   ├── voxel_gicp/            # Voxelized GICP
│   ├── small_gicp/            # Compact lightweight GICP
│   ├── vgicp_slam/            # Voxel-GICP graph SLAM
│   ├── ndt/                   # Normal Distributions Transform
│   ├── kiss_icp/              # KISS-ICP
│   ├── scan_context/          # Loop closure / place recognition
│   ├── aloam/                 # Three-stage LOAM pipeline
│   ├── floam/                 # Fast LOAM-style lightweight pipeline
│   ├── isc_loam/              # Intensity-aware loop-closure LOAM
│   ├── loam_livox/            # Solid-state LiDAR-oriented LOAM
│   ├── lego_loam/             # Ground-aware LOAM for UGVs
│   ├── mulls/                 # Multi-metric scan-to-map
│   ├── balm2/                 # Local bundle-adjustment mapping
│   ├── suma/                  # Surfel-based dense LiDAR odometry
│   ├── dlo/                   # Direct LiDAR odometry
│   ├── hdl_graph_slam/        # NDT plus graph-based LiDAR SLAM
│   ├── ct_icp/                # Continuous-time ICP
│   ├── ct_lio/                # Continuous-time LiDAR-inertial odometry
│   ├── dlio/                  # Direct LiDAR-inertial odometry
│   ├── lins/                  # Iterated-filter LIO
│   ├── point_lio/             # Direct raw-point LiDAR-inertial odometry
│   ├── clins/                 # Continuous-time LiDAR-inertial pipeline
│   ├── lio_sam/               # Graph-based LiDAR-inertial SLAM
│   ├── lvi_sam/               # Graph-based visual-lidar-inertial SLAM
│   ├── vins_fusion/           # Compact visual-inertial odometry
│   ├── okvis/                 # Local-window visual-inertial odometry
│   ├── orb_slam3/             # Visual-inertial SLAM with loop closure
│   ├── fast_lio2/             # Direct LiDAR-inertial odometry
│   ├── fast_lio_slam/         # FAST-LIO2 with loop-closure graph SLAM
│   ├── relead/                # Degeneracy-aware constrained ESIKF
│   ├── xicp/                  # Observability-aware ICP
│   ├── ct_icp_relead/         # Hybrid method
│   └── imu_preintegration/    # IMU preintegration
├── evaluation/                # Benchmark and evaluation tools
├── ros2/                      # ROS 2 Humble wrappers
└── .github/workflows/ci.yml   # CI

Each directory under papers/*/ is self-contained with headers, sources, and tests. The core libraries are ROS-independent and can be used without ROS 2.


Degeneracy Detection Demo

RELEAD and X-ICP can detect degenerate geometry such as tunnel-like environments:

=== Tunnel Environment ===
Has degeneracy: yes
Degenerate translation dirs: 1
  dir: [1, 0, 0]              # x direction (tunnel axis) is degenerate

=== Normal Environment ===
Has degeneracy: no             # walls and ground constrain all directions

ROS 2 nodes publish real-time status on /degeneracy with std_msgs/Bool.


Adding a New Paper

mkdir -p papers/your_method/{include/your_method,src,test}
# 1. Write headers, sources, and tests
# 2. Add CMakeLists.txt
# 3. Add add_subdirectory to the top-level CMakeLists.txt
# 4. Run ctest and keep the full suite passing

Dependencies

Library Version Purpose
Eigen3 >= 3.3 Linear algebra
PCL >= 1.10 Point cloud processing
Ceres Solver >= 2.0 Nonlinear optimization
GTest >= 1.11 Unit testing
OpenCV >= 4.0 I/O utilities

License

MIT

About

C++ implementations, derived variants, and compact baselines for localization papers with ROS 2, tests, and benchmarks.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors