拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FAST-LIO2实战:从环境搭建到数据集跑通的全流程指南

FAST-LIO2实战:从环境搭建到数据集跑通的全流程指南

做SLAM的人如果2024年还没听说过FAST-LIO2,那基本等于学视觉SLAM不知道ORB-SLAM。这套出自香港大学火星实验室(MaRS Lab)的开源LiDAR-Inertial Odometry框架,从论文公开到代码开源,一直是激光惯性里程计方向绕不过去的参考实现。它把紧耦合迭代卡尔曼滤波、增量式ikd-Tree地图、原始点云直接配准这些事情揉在了一起,做出来的效果能打,代码结构又足够清晰,很多人入门LIO的第一站就是它。

这篇文章我想用实战的方式聊一聊怎么把FAST-LIO2从零搭起来。不是复述论文,也不是看README,而是按照我实际踩坑的顺序讲:环境怎么准备、代码怎么编译、官方数据集怎么跑通、跑完怎么判断好坏、以及那些文档里不会明说但你在编译到运行时一定会撞上的问题。适合刚接触SLAM的机器人方向学生,也适合已经跑过LOAM、LIO-SAM但想换一套紧耦合框架看看的人。

1. 先把框架看透:FAST-LIO2到底解决了什么问题

1.1 从LIO到FAST-LIO2:这套框架的定位

先明确一个概念。LIO全称是LiDAR-Inertial Odometry,核心是把激光雷达点云和IMU(惯性测量单元)数据融合在一起,估计机器人的位姿,同时在线建一张点云地图。和纯LiDAR里程计相比,多加一个IMU有两个明显好处:高速运动、旋转剧烈的时候不至于跟丢,点云运动畸变也能靠IMU做补偿。

FAST-LIO2在这条技术路线上做了两个很关键的事情。第一,它采用紧耦合方式,IMU状态和雷达观测在一个迭代误差状态卡尔曼滤波(IESKF)里一起估计,不需要像LOAM那样先做特征提取、再分odometry和mapping两个模块。第二,它维护一张全局增量点云地图,用自己实现的ikd-Tree做索引,每一帧新点云直接和全局地图做配准,而不是跟一个滑动窗口里的局部子图做配准。这一点从FAST-LIO一代到二代是最大变化,带来的好处是大场景下不容易丢,地图一致性更好。

用一句话概括:FAST-LIO2是一个依赖比较少、计算效率高、适合中低速机器人平台(轮式、四足、无人机都有人用)的紧耦合LIO框架。你要说它有没有缺点,当然有,后面我会聊到无回环、退化场景漂移这些问题,但作为学习和落地的起点,它足够优秀。

1.2 核心模块拆解:ikd-Tree、IESKF、运动畸变补偿

理解FAST-LIO2,我觉得看三个模块就够了。

第一个是ikd-Tree,这是港大MaRS Lab自己提的一种增量kd-tree。传统PCL里的KdTree是静态的,建一次树之后如果往地图里插新的点,要么整棵树重建,要么用效率很低的方式逐点插入。ikd-Tree支持增量式插入、删除、动态re-balance,并且维护了每个节点的信息,做范围搜索和最近邻搜索时性能非常稳。在FAST-LIO2里面,全局地图就是一棵ikd-Tree,新点不断插进去,旧点可能被删掉,树本身会自己保持平衡。这个东西你在跑的时候看不到,但它是FAST-LIO2能在大规模环境里保持实时性的根本。

第二个是IESKF,迭代误差状态卡尔曼滤波。传统扩展卡尔曼(EKF)在强非线性场景下容易发散,ESKF是把误差状态作为估计对象,而迭代的意思是:用当前估计值重投影、重算观测残差、再更新状态,反复迭代几次,类似Gauss-Newton的思想。FAST-LIO2在每次雷达帧到达时做多轮迭代,直到收敛或者达到最大迭代次数,这套做法让滤波精度逼近优化类方法,但计算量又比图优化小很多。

第三个是运动畸变补偿。雷达单帧扫描是有时间戳的,一个旋转周期内雷达在运动,点云相对世界坐标系的坐标是“歪”的。FAST-LIO2利用IMU做反向传播(backward propagation),把一帧内各个点按时间戳对应的位姿重新投影到起始时刻的坐标系下,再做配准。这套流程纯LiDAR里程计也有类似做法,但FAST-LIO2因为紧耦合,畸变补偿用的运动先验来自IMU和滤波状态,所以更稳。

1.3 对比LIO-SAM、LOAM,该怎么选

很多人在选框架时会纠结LIO-SAM和FAST-LIO2。我说点个人看法。

LOAM系列是经典,但它把位姿估计拆成odometry和mapping两个节点,特征提取依赖线面特征,在结构化环境里很好用,一旦遇到植被、碎石这种无特征场景就容易拉胯。LIO-SAM是在LOAM的基础上加了因子图优化,支持回环检测(GTSAM、ScanContext等),所以它做出来的轨迹长期一致性更好,适合有大回环的场景,但代价是模型更复杂、依赖更多、计算更重。FAST-LIO2走的是滤波路线,没有显式回环,单帧计算很轻,地图是一棵增量树,跑起来CPU占用低,非常适合嵌入式、实时性要求高的平台。

怎么选?如果你要做园区巡检、无人机、需要轻量化部署,首选FAST-LIO2;如果你的场景有大量回环、希望后端能优化出漂亮的全局轨迹,可以看LIO-SAM或者FAST-LIO2加ScanContext回环的方案。两个都跑一遍,其实对这些框架的理解会一下子立体起来。

维度FAST-LIO2LIO-SAM
核心方法迭代误差状态卡尔曼滤波因子图优化
回环检测官方无,需自己接内置ScanContext
计算量低中等偏高
特征依赖无,原始点云直接配准依赖线面特征
典型场景实时性要求高、嵌入式大场景、带回环
上手难度较低中等

2. 动手前准备:环境搭建与依赖安装

2.1 系统与ROS版本怎么选最省心

FAST-LIO2官方支持ROS1,我推荐Ubuntu 20.04加ROS Noetic这个组合。为什么?因为默认源里的PCL是1.10、Eigen是3.3.7,正好满足FAST-LIO2的编译要求,几乎所有依赖都能用apt装完,不需要自己编译一堆老库。如果你用Ubuntu 18.04加Melodic也不是不行,但PCL版本偏低,编译时撞到Eigen对齐和C++标准问题的概率大不少。Ubuntu 22.04加ROS 2也能跑,但官方没有提供完整支持,需要自己改CMake或者依赖一些第三方移植,新手不建议一上来就折腾。

还有一点:尽量不要在虚拟机里跑FAST-LIO2的实时建图。虚拟机里USB设备透传和图形加速都是坑,跑数据集虽然勉强能行,但rviz会卡到怀疑人生。有条件就装物理机双系统,没条件就上Docker,镜像建议用ros:noetic-ros-base-focal然后自己按步骤装依赖。

2.2 依赖库逐个装:Eigen、PCL、livox_ros_driver

先装基础的Eigen和PCL,Ubuntu 20.04下两条命令就搞定:

sudo apt update sudo apt install libeigen3-dev libpcl-dev

装完之后建议看一眼Eigen版本,很多编译报错的根源其实是版本太低:

pkg-config --modversion eigen3 cat /usr/include/pcl-1.10/PCLConfig.cmake | grep PCL_VERSION

重点来了:livox_ros_driver必须单独装。FAST-LIO2的消息接口依赖livox_ros_driver里的livox_ros_driver/CustomMsg,所以这一个包没编译好,后面整个工程都编不过。推荐用源码方式,在你准备放FAST-LIO2的同一工作区里克隆并先编译:

cd ~/catkin_ws/src git clone https://github.com/Livox-SDK/livox_ros_driver.git cd ~/catkin_ws catkin_make source devel/setup.bash

注意这里有个很大的坑:Livox官方后来推出了livox_ros_driver2,和FAST-LIO2配套的driver1并不兼容。很多人机器上装了driver2,结果编译FAST-LIO2时报找不到livox_ros_driver/CustomMsg.h,排查半天发现是版本冲突。如果你不是搞Livox SDK二次开发,老老实实只用driver1就好。另外Sophus这个库FAST-LIO2官方仓库的ThirdParty目录里自带,编译时会一起编,不需要你手动安装,但如果你系统里恰好也装了一个Sophus,偶发的不兼容问题偶尔会出现,真遇到就先把系统里的Sophus卸了再编。

2.3 源码编译与ROS工作区配置

拿到源码并编译,步骤如下:

mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone https://github.com/hku-mars/FAST_LIO.git cd ~/catkin_ws catkin_make source devel/setup.bash

第一次编译会有点慢,因为ThirdParty里的Sophus也要一起编。等看到类似[100%] Built target fast_lio的输出就说明编译成功了。如果中间有报错,不要急着反复catkin_make去碰运气,先把报错信息贴到搜索里搜一下,九成以上是下面这几个问题:Eigen版本低、livox_ros_driver没source、C++标准冲突、PCL组件缺VTK依赖。

还有一个容易被忽略的细节:每次新开终端跑FAST-LIO2之前都要记得source ~/catkin_ws/devel/setup.bash,或者直接写进~/.bashrc,不然roslaunch fast_lio会提示找不到包。这个问题在不同终端里非常常见,尤其你习惯多终端分别source不同环境的时候。

2.4 launch文件里那些参数是什么意思

编完以后先别急着跑数据集,打开launch文件看看结构。以mapping_horizon.launch为例,这里对应的是Livox Horizon雷达,里面除了常规的bag_path、lid_topic、imu_topic之外,还有几组参数值得你逐个看:

<arg name="bag_path" default="/path/to/your_dataset.bag" /> <param name="lid_topic" type="string" value="/livox/lidar" /> <param name="imu_topic" type="string" value="/livox/imu" /> <param name="extrinsic_T" type="string" value="0.04165 0.02326 -0.0284" /> <param name="extrinsic_R" type="string" value="1 0 0 0 1 0 0 0 1" /> <param name="filter_size_surf" type="double" value="0.5" /> <param name="filter_size_map" type="double" value="0.5" />
  • bag_path:数据集bag文件的绝对路径,不改成自己的路径,直接跑就会报找不到文件。
  • lid_topic和imu_topic:雷达点云和IMU的topic名,不同数据集可能不一样,跑之前用rosbag info xxx.bag确认一下。
  • extrinsic_T和extrinsic_R:IMU到雷达的外参。这个必须和数据集实际情况一致,我见过只改路径不改外参、跑出来轨迹飞到天上的情况,就是从一套传感器的配置直接套到另一套上。
  • filter_size_surf和filter_size_map:体素滤波的叶子大小。数值越小保留点云越密,地图细节越多但计算量越大;数值越大跑得越快但地图越糊。官方数据集默认0.5通常没问题,真机点云密度不同可以再调。

跑数据集的时候,launch通常会调用rosbag play节点自动播放bag。如果没有自动播放也没关系,后面我会单独说手动启动的流程。

3. 用官方数据集把流程跑通

3.1 数据集怎么下载、选哪一个

FAST-LIO2官方README里放了几个测试数据集的下载地址(百度网盘和Google Drive都有),常见的有行空数据集、香港科技大学校园数据集、还有室内楼梯场景。我建议新手先跑行空数据集,因为场景不大、运动速度适中、点云质量也好,用默认参数就能出不错的效果。港科大校园那个场景大、走廊长,能体验到大场景下ikd-Tree增量地图的优势,但如果你外参配错或者IMU频率不对,漂移起来也会更明显。

下载的时候注意一下bag文件和launch的雷达型号要匹配。行空数据集应该是Horizon格式,港科大校园数据集也有对应的版本,别拿Avia的bag配Horizon的launch,topic名和点云格式都不一样,跑出来基本是废的。下载完以后推荐先跑一句:

rosbag info xingkong.bag

看一眼里面有哪几个topic、各有多少帧数据、时长多长。正常一个官方数据集通常就只有/livox/lidar和/livox/imu两个核心topic,偶尔会有别的,但这两个是FAST-LIO2必须的。

3.2 启动与可视化:rviz里该看哪些topic

确认数据集没问题后,修改launch里的bag_path为bag文件的绝对路径,然后启动:

roslaunch fast_lio mapping_horizon.launch

如果launch里没有自动播放bag,新开一个终端手动播放:

rosbag play xingkong.bag

想让它等launch先跑起来几秒、接收端就绪后再开始发数据,可以加个延时参数:

rosbag play -d 5 xingkong.bag

rviz可视化建议直接加载官方仓库提供的配置。FAST-LIO2源码的rviz目录下一般都带现成的配置,例如:

rviz -d ~/catkin_ws/src/FAST_LIO/rviz/fastlio.rviz

如果没有现成配置,跟着topic列表手动添加也行。几个重要topic:

  • /Odometry:里程计输出的位姿,rviz里用Odometry显示,能看到坐标系在动。
  • /path:轨迹线,这个是评估建图效果最直观的东西,路径是否平滑、是否闭合。
  • /cloud_registered:配准后并注册到全局地图的点云,实时显示建图结果。
  • /cloud_effected:当前帧里真正参与配准的有效点。

跑起来以后你会看到点云地图一帧一帧往外长,轨迹线跟着雷达运动延伸。如果一切正常,你就能体验到FAST-LIO2那种“没什么感知延迟”的流畅感。

3.3 判断建图效果:不是有地图就行

很多人跑完数据一看有地图就觉得成功了,这远远不够。判断一个LIO跑得好不好,我认为看三件事。

第一是轨迹回环是否闭合。如果数据集里有一段路是走回去的,看/path在回到起点时是否和原来轨迹重合。闭合误差大,说明状态估计在过程中累积了漂移,可能原因包括外参不准确、IMU噪声参数没调好、地图降采样太粗等。

第二看地图细节是否清晰。走廊里的墙面、地面边缘、柱子边缘应该干净利落。如果地图出现明显的双层墙、拖影,大概率是运动畸变补偿没做好或者外参误差导致前后帧点云对不上。

第三看CPU占用和帧率。用top观察fast_lio进程的CPU占用,正常跑数据集应该在30%到80%之间(取决于机器)。如果CPU直接满载,很可能是点云太密、地图增长过大或者线程参数不合适,后面我会讲怎么调。

3.4 调参入门:从数据集到自己雷达的第一步

官方数据集跑通只是第一步,真正要做自己的采集数据,需要把参数体系理解透。

首先是IMU参数。FAST-LIO2默认按200Hz IMU频率来设计,Livox雷达内置IMU通常是200Hz,这个一般不用改。但如果你用外置IMU,common.launch或mapping_*.launch里面的imu_rate、噪声密度、随机游走参数都要改成传感器手册上的真实值。很多人在自采数据上漂移严重,其实就是噪声参数还是官方默认。

其次是外参。自采数据前一定要做好IMU到雷达的外参标定,别自己拿尺子量一下就写进去。港大MaRS Lab有开源的livox_camera_lidar_calibration等工具,如果你只有雷达和IMU,也可以找lidar_imu_calib这类方案。标定完成后再把外参写进launch或yaml里,跑起来轨迹稳定得多。

最后是降采样参数。室内小场景,filter_size_surf=0.3左右能保留更多细节;室外大场景,0.5~0.8更合适,不然地图点太多内存会膨胀。具体看你的算力和场景规模,没有绝对最优。

4. 我记录下来的那些坑:常见问题排查实录

4.1 编译期报错:Eigen/PCL/livox driver三座大山

编译报错是最容易劝退新手的环节,但其实八成的编译问题都集中在几个固定组合上。

第一个是fatal error: livox_ros_driver/CustomMsg.h: No such file or directory。这个报错几乎可以确定是livox_ros_driver没编译成功或者没被source。检查方法很简单:先单独编译并source livox_ros_driver,然后再回到顶层工作区编译FAST-LIO2。另外确认自己装的是driver1而不是driver2。

第二个是Eigen相关的报错,比如Static assertion failed: YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES或者各种aligned_allocator报错。这通常是因为Eigen版本低于3.3。Ubuntu 20.04的apt源里Eigen 3.3.7基本没问题,如果是Ubuntu 18.04或者更老的系统,建议源码编译安装最新Eigen,并注意编译选项里的C++标准要用C++14或17。

第三个是VTK相关的链接错误,比如cannot find -lvtkCommonCore-7.1。这个一般出现在PCL安装不完整时。Ubuntu里重新把PCL相关依赖补齐:

sudo apt install libvtk6-qt-dev libvtk6-dev

或者干脆sudo apt install libpcl-dev再装一遍,把依赖拉全。

4.2 launch报错与topic不匹配

编译过了,运行时又会出现一波新问题。最常见的表现是launch启动正常,但rviz里没有点云、没有轨迹。

先别急,逐层排查。第一,用rostopic list确认当前有没有/livox/lidar和/livox/imu两个topic。如果没有,说明bag没播放成功或者topic名和launch里写的不一致。第二,用rostopic echo /livox/lidar -n 1看一帧数据能不能正常输出,确认数据类型匹配。第三,检查launch里lid_topic和imu_topic的字符串值和bag里的实际topic名是否完全一致,差一个斜杠都不行。

还有一类问题是时间戳。如果你发现rviz里点云是有的但一直不更新,或者轨迹卡住不动,多半是sim time没设置。FAST-LIO2一般建议用数据集时间戳,在播放bag前设置:

rosparam set use_sim_time true rosbag play --clock xingkong.bag

不过这个操作有时候会带来新的困惑:如果launch里某些节点的时间依赖有问题,反而会造成奇怪的延迟现象。我的经验是:先不设use_sim_time直接跑,如果出现时间错乱再反过来加。

4.3 运行卡顿、漂移、地图断层怎么办

跑着跑着地图开始拖影、漂移,这是状态估计不对,不是显示问题。最常见的原因有三个。

一个是外参不对。我见过有人拿Horizon的外参去跑Avia采集的数据,结果地图完全飞掉。外参这个东西必须精确到厘米和度级别,差个几厘米在远距离点云上就会被放大成巨大误差。

第二个是降采样参数和地图维护参数不合理。地图点越堆越多,ikd-Tree再高效也架不住几十GB的内存,跑着跑着开始卡,是正常的。FAST-LIO2在地图规模上做了一些控制,但如果你把filter_size_map设得太小,地图点密度爆炸,实时性就会掉。建议先用默认参数跑通,再根据自己场景调整。

第三个是退化环境。长直走廊、空旷停车场、隧道,这类场景缺少几何约束,Y轴方向的位置漂移几乎是必然的。FAST-LIO2没有后端优化,单纯靠前端的雷达和IMU约束,退化场景下漂移是物理规律,不是参数调不好。想解决这个问题,就要考虑加入回环检测、融合其他传感器(相机、UWB、GNSS),或者做运动约束。这里也说句公道话:任何纯LIO框架在退化场景都会漂,不是只FAST-LIO2这样。

4.4 部署到真机时的关键检查项

如果你跑完数据集准备上真机,下面的检查项是我实际部署时踩坑总结出来的。

第一,时间同步。雷达和IMU如果没有硬件同步,至少要保证软件时间戳的延迟在几十毫秒以内。检查方法是rostopic echo分别看两个topic的header时间戳,画出来看看延迟是否稳定。时间戳抖动大的话,运动畸变补偿会不准,地图会糊。

第二,坐标系和frame_id统一。真机上激光的frame_id、IMU的frame_id、base_link之间的关系要理清楚。FAST-LIO2输出的位姿是雷达坐标系到世界坐标系的变换,下游导航和规划如果用的坐标系不一致,定位结果再准也没用。

第三,雷达驱动参数。Livox雷达在纯自采时要注意点云频率、回波模式、扫描模式。不要用非重复扫描模式的数据去跑FAST-LIO2,官方支持的是标准扫描模式。这个看着不起眼,实际能折腾人一晚上。

下面把我遇到的一些典型问题和直接对策整理成表,方便你排查:

现象可能原因对策
编译找不到CustomMsg.hlivox_ros_driver未编译或版本不对单独编译source driver1
rviz没有点云topic名不匹配或bag未播放rosbag info核对topic名
轨迹发散飞掉外参错误或IMU频率设置错核对launch外参和IMU频率
地图拖影严重运动畸变补偿异常、时间戳不同步检查时间戳对齐、IMU参数
卡顿、CPU飙满地图点过多、降采样太小调大filter_size_map和surf
长走廊大漂移退化场景缺少约束加回环或融合其他传感器

另外有一个很多人忽略的小问题:launch里如果配置了pointcloud_to_pcd保存地图,边跑边存点云会占用大量磁盘IO,可能导致实时性下降。我通常会跑完后再用rosrun pcl_ros pointcloud_to_pcd /cloud_registered手动录一帧大地图,而不是一边跑一边存。

5. 跑通之后还能怎么玩

5.1 从纯雷达到雷达+相机:多传感器融合怎么接

FAST-LIO2跑通后,很多人会想给它加个摄像头,做视觉激光融合。这个方向港大MaRS Lab自己也有一系列工作,从FAST-LIVO到FAST-LIVO2,就是在FAST-LIO2的基础上加入视觉信息,实现视觉-激光-惯性紧耦合的里程计和建图。如果你只是想简单接一个相机做展示级别的融合,可以先把相机标定好,把视觉特征投影到雷达坐标系里做叠加显示,但这只是可视化,不是真正的融合。

真正合入视觉要做的事情比较多,光外参标定就涉及相机-IMU、相机-雷达两套外参。我的建议是先别急着融,把FAST-LIO2源码读透,理解状态估计和点云配准的流程,再去接触融合框架会顺很多。不然代码里一堆变量你根本分不清是雷达的还是视觉的,排错会非常痛苦。

5.2 在嵌入式平台(RK3588/Jetson)上部署的可行性

最近特别多人问RK3588这类ARM平台能不能跑FAST-LIO2。我可以明确说:能跑,但不能拿它和x86台式机直接比。FAST-LIO2本身不依赖GPU,核心计算是IKD-Tree搜索和卡尔曼滤波迭代,这两个都是CPU密集型的。在RK3588上,如果雷达点云频率不高、地图规模控制好,实时性是可能的,但你要做好几个准备:系统用Ubuntu 22.04或Debian系,装好ARM版本的ROS(建议大家优先用ROS 2或基于ROS 1的解决方案),PCL和Eigen的交叉编译要提前验证。相比之下,Jetson Orin系列因为是Ubuntu桌面生态,跑FAST-LIO2要顺滑很多。如果你有NVIDIA家的板子,优先用它做SLAM落地方案,RK3588更适合做视觉任务配合NPU使用。

这里多说一句:很多人被“嵌入式”三个字吓住,其实FPGA和MCU才是嵌式的苦海,RK3588和Jetson这种Linux板卡跟普通电脑编译没什么本质区别,就是把x86换成aarch64,依赖装好就行。真遇到问题,先去确认uname -a是aarch64还是x86_64,再决定下载哪个架构的预编译包。

5.3 给新手的学习路线建议

如果你是从零开始学SLAM,我建议的路线是:先把高翔的《视觉SLAM十四讲》啃到前七讲以上,把李群李代数、状态估计、非线性优化这些底子打好,再上手FAST-LIO2。不然你看到IESKF公式里的协方差矩阵更新,可能连符号都看不懂。

看完理论基础后,源码阅读顺序推荐这样:先读laserMapping.cpp的主线程流程,搞清楚run()里怎么等待点云、怎么触发处理;然后看IMU处理部分,理解状态预测怎么做的;再看点云预处理部分,理解运动补偿和降采样;最后再啃配准和更新的迭代过程。每一块代码都不长,但信息密度很高。

另外可以看看B站和知乎上许多人对FAST-LIO2的源码解析,不过我的经验是:视频看完是别人的,只有自己把launch参数改了、把bug排了、把地图跑崩了再修好,这些知识才是你的。

5.4 一点个人体会

我自己在跑FAST-LIO2的时候有一个印象很深的经历:第一次把官方数据集跑出完整地图时,觉得这框架太强了;后来在自采的园区数据上反复调整参数,发现地图偶尔还是会漂,才意识到SLAM这个领域其实没有“跑通就完事”这回事。FAST-LIO2把前端的很多问题解决得很好,但它不会替你解决传感器标定、时间同步、场景退化这些系统工程问题。

所以如果你刚开始学,不用追求一次把所有参数调到最优。先跑通,再慢慢改一个参数观察地图变化,比如把filter_size_surf从0.5改成0.2看地图细节变化,把外参故意加个几厘米偏差看轨迹怎么飘。这种“故意破坏再修复”的练习,比看任何教程都让你印象深刻。SLAM是一个魔鬼藏在细节里的方向,动手去踩坑,才是最快的路。

返回列表