Map-based 3D LiDAR localization for ROS 2 and Nav2.
Green: localized path. Red: pointcloud map. Grid: 50 m × 50 m cells.
This package provides:
- NDT/GICP-based localization against
.pcdor.plymaps - standalone and Nav2 launch files
- optional odometry and IMU prediction
- alignment diagnostics and guarded reinitialization signals
- repeatable rosbag benchmark tools
New users should start with ROS 2 Jazzy and the default NDT_OMP backend. Experimental deskew and global-localization features are off by default. See docs/v1_status.md for the validated scope and limitations.
Expected workspace layout:
lidarloc_ws/src/
lidar_localization_ros2/
ndt_omp_ros2/
Bootstrap and build:
mkdir -p ~/lidarloc_ws/src
cd ~/lidarloc_ws/src
git clone https://github.com/rsasaki0109/lidar_localization_ros2.git
cd lidar_localization_ros2
scripts/bootstrap_colcon_workspace.sh --build
source ~/lidarloc_ws/install/setup.bashManual build:
cd ~/lidarloc_ws
vcs import src < src/lidar_localization_ros2/dependencies.repos
source /opt/ros/${ROS_DISTRO:-jazzy}/setup.bash
colcon build --symlink-install --packages-up-to lidar_localization_ros2
source install/setup.bashSee docs/local_build.md for the no-sudo local-prefix workflow.
Generate a small configuration file:
ros2 run lidar_localization_ros2 create_lidar_localization_config.py \
--profile standalone \
--map-path /absolute/path/to/map.pcd \
--output /tmp/lidar_localization.yamlThe generator prints the matching launch and bringup-check commands. For rosbag replay,
add --use-sim-time. Add --initial-pose X Y Z QX QY QZ QW when the map pose is known.
Common launches:
# LiDAR localization
ros2 launch lidar_localization_ros2 nav2_lidar_localization.launch.py
# Full Nav2 wrapper
ros2 launch lidar_localization_ros2 nav2_navigation.launch.py \
map_yaml:=/absolute/path/to/map.yaml
# Livox MID-360 preset
ros2 launch lidar_localization_ros2 mid360_legged_localization.launch.py \
map_path:=/absolute/path/to/map.pcd \
cloud_topic:=/livox/points \
imu_topic:=/livox/imuCheck topics, TF, pose output, and diagnostics before tuning registration:
ros2 run lidar_localization_ros2 check_lidar_localization_bringup.py \
--profile standaloneThe Autoware Istanbul demo downloads its public assets, builds the package when needed, replays 60 seconds, and writes a trajectory report:
source scripts/setup_local_env.sh
scripts/run_public_demo.shFirst-time setup usually takes 15–30 minutes because of downloads. Results vary between runs; use the regression suite for release decisions:
source scripts/setup_local_env.sh
scripts/run_public_regression_suite.shSee docs/benchmarking.md for datasets, metrics, and variance notes.
Default frames are map, odom, and base_link.
/initialposemust be expressed inmap.- Default mode publishes
map -> base_link. - Nav2 mode publishes
map -> odomand requires externalodom -> base_link. use_odom: trueconsumes the/odomtopic for prediction; it does not create odom TF.- Do not publish the same static LiDAR or IMU transform from two nodes.
See docs/frame_contract.md for the complete contract and docs/troubleshooting.md when poses do not update.
Full Nav2 operation requires:
- a 3D pointcloud map for localization
- a 2D occupancy map YAML for planning
- an
odom -> base_linksource - an initial pose in the
mapframe
Generate a 2D map from a pointcloud with
generate_occupancy_map_from_pcd.py; usage is documented in
docs/benchmarking.md.
| Direction | Topic | Type |
|---|---|---|
| Input | /cloud |
sensor_msgs/msg/PointCloud2 |
| Input | /initialpose |
geometry_msgs/msg/PoseWithCovarianceStamped |
| Input | /odom |
nav_msgs/msg/Odometry |
| Input | /imu |
sensor_msgs/msg/Imu |
| Output | /pcl_pose |
geometry_msgs/msg/PoseStamped |
| Output | /path |
nav_msgs/msg/Path |
| Output | /alignment_status |
diagnostic_msgs/msg/DiagnosticArray |
| Output | /reinitialization_requested |
std_msgs/msg/Bool |
Topic names are configurable. Runtime map paths accept .pcd and .ply.
- Continuous-time deskew and IMU pose-history variants are default-off.
- Global localization is an opt-in BBS_2D service and is not part of normal launch.
- Hessian localizability diagnostics are default-off and are too expensive for normal runtime.
- Automatic recovery requires explicit supervisor safety gates.
Read docs/imu_estimation.md and docs/global_localization.md before enabling these paths.
source scripts/setup_local_env.sh
cd ../build_ws
colcon build --symlink-install --packages-up-to lidar_localization_ros2
ros2 run lidar_localization_ros2 run_experiment_suite.py
ros2 run lidar_localization_ros2 run_release_regression_suite.shPublic replay validation does not replace sensor-specific or real-robot testing.
The experimental LiDAR/IMU track now has a reproducible 3/3 full-sequence pass on
Koide outdoor_hard_01a. See the
GLIM GICP 6500 result for
metrics, fixed configuration, image provenance, and the replay command. This is
research evidence and does not change the runtime default.
| Need | Document |
|---|---|
| Validated scope | v1 status |
| Build and benchmarks | local build, benchmarking |
| Frames and troubleshooting | frame contract, troubleshooting |
| Nav2/MID-360 | MID-360 bringup |
| IMU and covariance | IMU estimation, pose covariance |
| Relocalization | global localization, v1.1 relocalization |
| Plans and decisions | development plan, global localization + LIO plan, decisions |
ROS 2 Jazzy is the primary target; Humble remains supported for existing deployments. Required dependency: ndt_omp_ros2. small_gicp is optional.
See CHANGELOG.md for release notes.