SLAM:
- ikd-Tree: A state-of-art dynamic KD-Tree for 3D kNN search.
- R2LIVE: A high-precision LiDAR-inertial-Vision fusion work using FAST-LIO as LiDAR-inertial front-end.
- LI_Init: A robust, real-time LiDAR-inertial initialization and synchronization package..
- FAST-LIO-LOCALIZATION: The integration of FAST-LIO with Re-localization function module.
- FAST-LIVO | FAST-LIVO2: A state-of-art LiDAR-inertial-visual odometry (LIVO) system with high computational efficiency, robustness, and pixel-level accuracy.
Control and Plan:
- IKFOM: A Toolbox for fast and high-precision on-manifold Kalman filter.
- UAV Avoiding Dynamic Obstacles: One of the implementation of FAST-LIO in robot's planning.
- UGV Demo: Model Predictive Control for Trajectory Tracking on Differentiable Manifolds.
- Bubble Planner: Planning High-speed Smooth Quadrotor Trajectories using Receding Corridors.
This fork adds optional GPU acceleration via Apple Metal (macOS) and NVIDIA CUDA (Linux/Windows) for the computational bottleneck in FAST-LIO2: the h_share_model() function, which performs per-point plane fitting, residual computation, and Jacobian construction every ESKF iteration.
Key design: The GPU backend is entirely optional. The system automatically selects the best available backend: Metal on macOS, CUDA on Linux/Windows with NVIDIA GPU, or CPU fallback everywhere else — with zero code changes required.
A ComputeBackend abstraction (include/compute/compute_backend.h) defines 7 GPU-amenable kernels:
| Kernel | Operation | Description |
|---|---|---|
| 1 | batch_transform_points |
Body-to-world point transformation with LiDAR-IMU extrinsic |
| 2 | batch_plane_fit |
Per-point least-squares plane fitting (5 neighbors) |
| 3 | batch_compute_residuals |
Point-to-plane residual + validity scoring |
| 4 | batch_build_jacobian |
ESKF measurement Jacobian (Mx12) construction |
| 5 | compute_HTH |
H^T * H parallel reduction (Mx12 -> 12x12) |
| 6 | compute_HTh |
H^T * h parallel reduction (Mx12 + Mx1 -> 12x1) |
| 7 | batch_undistort_points |
IMU motion compensation per LiDAR point |
Plus a fused pipeline (fused_h_share_model) that chains kernels 1-6 keeping data on the GPU.
Implementations:
include/compute/cpu_backend.h— CPU reference using Eigen (always available)include/compute/metal_backend.mm— Metal GPU backend (macOS with Metal-capable GPU)include/compute/metal/kernels.metal— 9 Metal compute shadersinclude/compute/cuda/cuda_backend.cu— CUDA GPU backend (NVIDIA GPU with CUDA toolkit)include/compute/cuda/kernels.cu— 9 CUDA compute kernels
Fused h_share_model pipeline (superkernel — 2 GPU dispatches, end-to-end):
| Points | CPU | Metal | Speedup |
|---|---|---|---|
| 1,000 | 0.41 ms | 0.077 ms | 5.3x |
| 5,000 | 2.0 ms | 0.16 ms | 12.8x |
| 10,000 | 4.1 ms | 0.25 ms | 16.5x |
| 50,000 | 20.2 ms | 0.88 ms | 23.1x |
| 100,000 | 40.3 ms | 1.79 ms | 22.5x |
Isolated plane fitting (the single biggest bottleneck kernel):
| Points | CPU | Metal | Speedup |
|---|---|---|---|
| 10,000 | 3.7 ms | 9 us | 414x |
| 100,000 | 37 ms | 13 us | 2,866x |
| 500,000 | 186 ms | 22 us | 8,593x |
Validation shows 100% feature count agreement and HTH trace ratio of 1.000 between CPU and Metal backends at all tested sizes (1k-500k points).
GPU backends will not affect builds on unsupported systems. The safety guarantees:
- CMake gating: Metal compilation is wrapped in
if(APPLE)+find_library(Metal). CUDA compilation usescheck_language(CUDA). On systems without a supported GPU, only the CPU backend is compiled. - Factory pattern:
create_backend("cpu")always works.create_backend("metal")andcreate_backend("cuda")returnnullptron unsupported systems.create_default_backend()selects the best available backend automatically (Metal > CUDA > CPU). - Header guards: The CPU backend's factory functions are guarded by
#if !defined(HAS_METAL) && !defined(HAS_CUDA). GPU-linked targets define the appropriate macro and provide their own factory implementations. - No new dependencies: Metal uses Apple system frameworks (Metal.framework, Foundation.framework). CUDA requires the NVIDIA CUDA Toolkit (>= 11.0). The CPU backend has no additional dependencies beyond Eigen.
# Prerequisites: Xcode Command Line Tools (includes Metal compiler)
xcode-select --install
# Debug build (for testing)
cmake -S test -B test/build
cmake --build test/build -j$(sysctl -n hw.ncpu)
# Release build (for benchmarks)
cmake -S test -B test/build-release -DCMAKE_BUILD_TYPE=Release
cmake --build test/build-release -j$(sysctl -n hw.ncpu)
# Run all tests (85 total: 74 core + 11 Metal)
./test/build/test_so3_math # 17 tests - SO(3) math operations
./test/build/test_plane_estimation # 6 tests - Plane fitting
./test/build/test_ikd_tree # 14 tests - ikd-Tree operations
./test/build/test_compute_backend # 26 tests - CPU compute backend
./test/build/test_metal_backend # 11 tests - Metal GPU backend
# Run benchmarks (includes CPU vs Metal validation + timing)
./test/build-release/bench_metal_backend# Prerequisites: CUDA Toolkit >= 11.0, CMake >= 3.18
# Install CUDA: https://developer.nvidia.com/cuda-downloads
# Debug build (for testing)
cmake -S test -B test/build
cmake --build test/build -j$(nproc)
# Release build (for benchmarks)
cmake -S test -B test/build-release -DCMAKE_BUILD_TYPE=Release
cmake --build test/build-release -j$(nproc)
# Run all tests (85 total: 74 core + 11 CUDA)
./test/build/test_so3_math # 17 tests - SO(3) math operations
./test/build/test_plane_estimation # 6 tests - Plane fitting
./test/build/test_ikd_tree # 14 tests - ikd-Tree operations
./test/build/test_compute_backend # 26 tests - CPU compute backend
./test/build/test_cuda_backend # 11 tests - CUDA GPU backend
# Run benchmarks (includes CPU vs CUDA validation + timing)
./test/build-release/bench_cuda_backendOn platforms without a supported GPU, the GPU-specific test/benchmark targets are simply not generated by CMake. All core tests build and run normally.
- Float precision on GPU, double on CPU: Both Metal and CUDA shaders use float32 for per-point operations (transform, plane fit, residual, Jacobian). The Jacobian matrix H is float on the GPU and converted to double during readback. HTH/HTh reductions accumulate in float on the GPU with block/threadgroup partial sums, then the final reduction across blocks happens on the CPU in double.
- Cholesky solver for plane fitting: Both GPU backends use Cholesky decomposition of the 3x3 normal equations matrix (A^T*A) with coordinate pre-scaling for numerical stability. This matches the CPU's
colPivHouseholderQrresults at 100% validity agreement. - Zero-copy on Apple Silicon: The Metal backend uses shared memory (
MTLResourceStorageModeShared), enabling zero-copy buffer access between CPU and GPU on unified memory architectures. - CUDA architecture support: The CUDA backend targets compute capabilities 6.0 through 9.0 (Pascal through Hopper/Ada). Shared memory reduction uses 256 threads per block with 78 upper-triangle elements for symmetric HTH accumulation.
- CUDA-specific optimizations: The CUDA kernels go beyond a direct Metal port with NVIDIA-specific intrinsics and host-side optimizations:
__ldg()read-only texture cache loads on all global memory reads (doubles effective cache bandwidth)__fmaf_rn()fused multiply-add throughout all linear algebra (faster and more precise than separate mul+add)rsqrtf()hardware reciprocal square root instead ofsqrt+ divisionsincosf()simultaneous sin/cos in Rodrigues rotation- Closed-form upper-triangle index mapping (eliminates divergent loop in HTH reduction)
#pragma unrollon critical inner loops (shared memory loads, matrix ops, reduction)- Persistent GPU buffer pool (eliminates ~600us/call of
cudaMalloc/cudaFreeoverhead) - Pinned (page-locked) host memory for DMA transfers (2-3x faster than pageable)
- CUDA streams with
cudaMemcpyAsync— single sync point instead of 4 per pipeline call - Pre-reserved host vectors to avoid heap thrashing during feature compaction
Note: The CUDA backend has been written and compiles, but has not yet been tested on actual NVIDIA hardware. The development machine is an Apple M3 Pro (Metal only). The kernel logic is a direct port of the validated Metal shaders with CUDA-specific optimizations layered on top. If you have access to an NVIDIA GPU and encounter issues, please open an issue.
Prerequisites:
- NVIDIA GPU (compute capability >= 6.0 — Pascal or newer)
- CUDA Toolkit >= 11.0 (download)
- CMake >= 3.18
Building with CUDA (mainline FAST-LIO):
On a Linux system with CUDA installed, the standard catkin_make build will automatically detect CUDA and enable the GPU backend:
cd ~/$A_ROS_DIR$/src
git clone https://github.com/hku-mars/FAST_LIO.git
cd FAST_LIO
git submodule update --init
cd ../..
catkin_make
source devel/setup.bashCMake will print CUDA GPU backend: ENABLED during configuration. At runtime, the node will log:
[ INFO] GPU compute backend: CUDA (NVIDIA GeForce RTX XXXX)
If CUDA is not detected (no GPU, no toolkit), the build falls back to CPU automatically — no code changes needed.
What to expect: The GPU accelerates the h_share_model() function which runs every ESKF iteration (typically 3-4 times per LiDAR scan). The k-NN search against the ikd-tree remains on the CPU (it's a pointer-based structure that doesn't parallelize to GPU). For scans with 10k+ points, the GPU should provide a significant speedup on the plane fitting + Jacobian construction + HTH/HTh reduction portion.
Known limitations:
- Untested on real hardware — correctness is inferred from Metal validation (identical kernel logic)
- No CUDA benchmarks yet (contributions welcome!)
- The
n > dof_Measurementpath in the ESKF (< 24 valid features, extremely rare) falls back to CPU - Targets architectures 60-90; if your GPU is older than Pascal, you may need to add your arch to
CMakeLists.txt
FAST-LIO (Fast LiDAR-Inertial Odometry) is a computationally efficient and robust LiDAR-inertial odometry package. It fuses LiDAR feature points with IMU data using a tightly-coupled iterated extended Kalman filter to allow robust navigation in fast-motion, noisy or cluttered environments where degeneration occurs. Our package address many key issues:
- Fast iterated Kalman filter for odometry optimization;
- Automaticaly initialized at most steady environments;
- Parallel KD-Tree Search to decrease the computation;
Related video: FAST-LIO2, FAST-LIO1
Pipeline:
New Features:
- Incremental mapping using ikd-Tree, achieve faster speed and over 100Hz LiDAR rate.
- Direct odometry (scan to map) on Raw LiDAR points (feature extraction can be disabled), achieving better accuracy.
- Since no requirements for feature extraction, FAST-LIO2 can support many types of LiDAR including spinning (Velodyne, Ouster) and solid-state (Livox Avia, Horizon, MID-70) LiDARs, and can be easily extended to support more LiDARs.
- Support external IMU.
- Support ARM-based platforms including Khadas VIM3, Nivida TX2, Raspberry Pi 4B(8G RAM).
Related papers:
FAST-LIO2: Fast Direct LiDAR-inertial Odometry
FAST-LIO: A Fast, Robust LiDAR-inertial Odometry Package by Tightly-Coupled Iterated Kalman Filter
Contributors
Wei Xu 徐威,Yixi Cai 蔡逸熙,Dongjiao He 贺东娇,Fangcheng Zhu 朱方程,Jiarong Lin 林家荣,Zheng Liu 刘政, Borong Yuan
Ubuntu >= 16.04
For Ubuntu 18.04 or higher, the default PCL and Eigen is enough for FAST-LIO to work normally.
ROS >= Melodic. ROS Installation
PCL >= 1.8, Follow PCL Installation.
Eigen >= 3.3.4, Follow Eigen Installation.
Follow livox_ros_driver Installation.
Remarks:
- Since the FAST-LIO must support Livox serials LiDAR firstly, so the livox_ros_driver must be installed and sourced before run any FAST-LIO luanch file.
- How to source? The easiest way is add the line
source $Livox_ros_driver_dir$/devel/setup.bashto the end of file~/.bashrc, where$Livox_ros_driver_dir$is the directory of the livox ros driver workspace (should be thews_livoxdirectory if you completely followed the livox official document).
If you want to use docker conatiner to run fastlio2, please install the docker on you machine. Follow Docker Installation.
User can create a new script with anyname by the following command in linux:
touch <your_custom_name>.sh
Place the following code inside the <your_custom_name>.sh script.
#!/bin/bash
mkdir docker_ws
# Script to run ROS Kinetic with GUI support in Docker
# Allow X server to be accessed from the local machine
xhost +local:
# Container name
CONTAINER_NAME="fastlio2"
# Run the Docker container
docker run -itd \
--name=$CONTAINER_NAME \
--user mars_ugv \
--network host \
--ipc=host \
-v /home/$USER/docker_ws:/home/mars_ugv/docker_ws \
--privileged \
--env="QT_X11_NO_MITSHM=1" \
--volume="/etc/localtime:/etc/localtime:ro" \
-v /dev/bus/usb:/dev/bus/usb \
--device=/dev/dri \
--group-add video \
-v /tmp/.X11-unix:/tmp/.X11-unix \
--env="DISPLAY=$DISPLAY" \
kenny0407/marslab_fastlio2:latest \
/bin/bash
execute the following command to grant execute permissions to the script, making it runnable:
sudo chmod +x <your_custom_name>.sh
execute the following command to download the image and create the container.
./<your_custom_name>.sh
Script explanation:
- The docker run command provided below creates a container with a tag, using an image from Docker Hub. The download duration for this image can differ depending on the user's network speed.
- This command also establishes a new workspace called
docker_ws, which serves as a shared folder between the Docker container and the host machine. This means that if users wish to run the rosbag example, they need to download the rosbag file and place it in thedocker_wsdirectory on their host machine. - Subsequently, a folder with the same name inside the Docker container will receive this file. Users can then easily play the file within Docker.
- In this example, we've shared the network of the host machine with the Docker container. Consequently, if users execute the
rostopic listcommand, they will observe identical output whether they run it on the host machine or inside the Docker container."
Clone the repository and catkin_make:
cd ~/$A_ROS_DIR$/src
git clone https://github.com/hku-mars/FAST_LIO.git
cd FAST_LIO
git submodule update --init
cd ../..
catkin_make
source devel/setup.bash
- Remember to source the livox_ros_driver before build (follow 1.3 livox_ros_driver)
- If you want to use a custom build of PCL, add the following line to ~/.bashrc
export PCL_ROOT={CUSTOM_PCL_PATH}
Noted:
A. Please make sure the IMU and LiDAR are Synchronized, that's important.
B. The warning message "Failed to find match for field 'time'." means the timestamps of each LiDAR points are missed in the rosbag file. That is important for the forward propagation and backwark propagation.
C. We recommend to set the extrinsic_est_en to false if the extrinsic is give. As for the extrinsic initiallization, please refer to our recent work: Robust Real-time LiDAR-inertial Initialization.
Connect to your PC to Livox Avia LiDAR by following Livox-ros-driver installation, then
cd ~/$FAST_LIO_ROS_DIR$
source devel/setup.bash
roslaunch fast_lio mapping_avia.launch
roslaunch livox_ros_driver livox_lidar_msg.launch
- For livox serials, FAST-LIO only support the data collected by the
livox_lidar_msg.launchsince only itslivox_ros_driver/CustomMsgdata structure produces the timestamp of each LiDAR point which is very important for the motion undistortion.livox_lidar.launchcan not produce it right now. - If you want to change the frame rate, please modify the publish_freq parameter in the livox_lidar_msg.launch of Livox-ros-driver before make the livox_ros_driver pakage.
mapping_avia.launch theratically supports mid-70, mid-40 or other livox serial LiDAR, but need to setup some parameters befor run:
Edit config/avia.yaml to set the below parameters:
- LiDAR point cloud topic name:
lid_topic - IMU topic name:
imu_topic - Translational extrinsic:
extrinsic_T - Rotational extrinsic:
extrinsic_R(only support rotation matrix)
- The extrinsic parameters in FAST-LIO is defined as the LiDAR's pose (position and rotation matrix) in IMU body frame (i.e. the IMU is the base frame). They can be found in the official manual.
- FAST-LIO produces a very simple software time sync for livox LiDAR, set parameter
time_sync_ento ture to turn on. But turn on ONLY IF external time synchronization is really not possible, since the software time sync cannot make sure accuracy.
Step A: Setup before run
Edit config/velodyne.yaml to set the below parameters:
- LiDAR point cloud topic name:
lid_topic - IMU topic name:
imu_topic(both internal and external, 6-aixes or 9-axies are fine) - Set the parameter
timestamp_unitbased on the unit of time (Velodyne) or t (Ouster) field in PoindCloud2 rostopic - Line number (we tested 16, 32 and 64 line, but not tested 128 or above):
scan_line - Translational extrinsic:
extrinsic_T - Rotational extrinsic:
extrinsic_R(only support rotation matrix)
- The extrinsic parameters in FAST-LIO is defined as the LiDAR's pose (position and rotation matrix) in IMU body frame (i.e. the IMU is the base frame).
Step B: Run below
cd ~/$FAST_LIO_ROS_DIR$
source devel/setup.bash
roslaunch fast_lio mapping_velodyne.launch
Step C: Run LiDAR's ros driver or play rosbag.
Install MARSIM: https://github.com/hku-mars/MARSIM and run MARSIM as below
cd ~/$MARSIM_ROS_DIR$
roslaunch test_interface single_drone_avia.launch
Then Run FAST-LIO:
roslaunch fast_lio mapping_marsim.launch
Set pcd_save_enable in launchfile to 1. All the scans (in global frame) will be accumulated and saved to the file FAST_LIO/PCD/scans.pcd after the FAST-LIO is terminated. pcl_viewer scans.pcd can visualize the point clouds.
Tips for pcl_viewer:
- change what to visualize/color by pressing keyboard 1,2,3,4,5 when pcl_viewer is running.
1 is all random
2 is X values
3 is Y values
4 is Z values
5 is intensity
Files: Can be downloaded from google drive
Run:
roslaunch fast_lio mapping_avia.launch
rosbag play YOUR_DOWNLOADED.bag
NCLT Dataset: Original bin file can be found here.
We produce Rosbag Files and a python script to generate Rosbag files: python3 sensordata_to_rosbag_fastlio.py bin_file_dir bag_name.bag
Run:
roslaunch fast_lio mapping_velodyne.launch
rosbag play YOUR_DOWNLOADED.bag
In order to validate the robustness and computational efficiency of FAST-LIO in actual mobile robots, we build a small-scale quadrotor which can carry a Livox Avia LiDAR with 70 degree FoV and a DJI Manifold 2-C onboard computer with a 1.8 GHz Intel i7-8550U CPU and 8 G RAM, as shown in below.
The main structure of this UAV is 3d printed (Aluminum or PLA), the .stl file will be open-sourced in the future.
Thanks for LOAM(J. Zhang and S. Singh. LOAM: Lidar Odometry and Mapping in Real-time), Livox_Mapping, LINS and Loam_Livox.



