This repository implements three different odometry estimation algorithms using LiDAR and IMU data in ROS 2 Humble:
- LiDAR-only Incremental Odometry (scan-to-scan translation estimation)
- ICP-based Odometry (using PCL Iterative Closest Point)
- Extended Kalman Filter (EKF) Fusion of IMU (predict) + ICP (update)
All methods publish odometry on: /odom_est
The algorithms operate on Livox sensor topics:
/livox/amr/lidar(PointCloud2)/livox/amr/imu(IMU)
├── src/
│ ├── lidar_odometry.cpp # Method 1: Pure LiDAR odom
│ ├── icp_odometry.cpp # Method 2: ICP-based odom
│ ├── ekf_lidar_imu.cpp # Method 3: EKF fusion of ICP + IMU
│ ├── ekf_lidar_odom.hpp # EKF implementation
│ └── ...
├── config/
│ └── ekf_lidar_imu.yaml # Optional EKF config
├── result/
│ ├── result1.png # Sample trajectory / ATE plot
│ └── result2.png # Yaw error or comparison plot
└── README.md
A fast scan-to-scan translation estimation method:
- Extract 2D slice from 3D LiDAR
- Compute nearest-neighbor point correspondences
- Estimate translation (dx, dy)
- Accumulate pose
Pros: Fast, simple
Cons: Drift over time, fails on rotation-only motion
This uses PCL’s Iterative Closest Point:
- Convert PointCloud2 → PCL
- Apply filtering (voxel grid, z-slice, range gating)
- Align
curr_cloudtoprev_cloudusing ICP - Extract
dx,dy,dyaw - Publish odometry
Pros: More accurate, handles rotation
Cons: Slower, may fail with repeated structures
State vector:
x = [x, y, yaw, vx, vy]
- Integrate
angular_velocity.z→ yaw - Convert IMU acceleration to world frame
- Update velocity & position
- Propagate covariance
- ICP computes relative translation
- Use as measurement to correct EKF state
Pros:
- Best accuracy
- Robust against motion types
- Smooth output
Cons:
- Requires tuning (Q, R, ICP thresholds)
### **Absolute Trajectory Error Plot** ### **Yaw Error Plot**
Install required ROS packages:
sudo apt install ros-humble-pcl-conversions \
ros-humble-nav-msgs \
ros-humble-tf2 \
ros-humble-robot-localizationPCL is included with ROS 2 Humble.
cd ~/ros_ws2
colcon build --packages-select indoor_lidar_odom_cpp
source install/setup.bashMethod 1: LiDAR-only odometry
ros2 run indoor_lidar_odom_cpp lidar_odometryMethod 2: ICP odometry
ros2 run indoor_lidar_odom_cpp icp_odometryMethod 3: EKF (IMU + ICP)
ros2 run indoor_lidar_odom_cpp ekf_lidar_imuTopic Type Description
/odom_est nav_msgs/Odometry Output odometry
/tf transform tree odom → base_link_estEKF Parameters
Q: IMU process noise
R: ICP measurement noise
Initial covariance
Velocity process variance
ICP Parameters
MaximumIterations
MaxCorrespondenceDistance
TransformationEpsilon
EuclideanFitnessEpsilon
Voxel leaf size
Z-slice limits
Range gating (min/max distance)
Method Speed (Hz) Notes
LiDAR-only ~25–30 Hz Fastest
ICP ~7–20 Hz Depends on cloud size & filtering
EKF IMU rate (predict) + ~10–25 Hz (update) Smooth & accurate



