激光SLAM这块,FAST_LIO系列算是这两年被讨论得最多的方案之一。我最早接触它是在一个手持建图的项目里,当时用LOAM系列跑室内走廊,漂移和实时性都不太理想,后来换到FAST_LIO,同样的数据跑下来轨迹闭合明显好了不少。但说实话,从零把环境搭起来、把两个版本都跑通、再做出有意义的对比,中间踩的坑远比想象中多——依赖版本冲突、点云话题对不上、外参标定偏差、地图保存格式不兼容,每一个都能卡你半天。这篇就把我从头搭FAST_LIO和FAST_LIO2的完整过程、两个版本的核心差异、以及实测下来的性能表现,按我自己的操作顺序讲清楚。适合刚上手激光惯性里程计、想快速跑通并理解背后逻辑的朋友,也适合已经在用但想搞清楚两个版本到底差在哪的人。
1. 先把FAST_LIO和FAST_LIO2的定位搞清楚
动手之前得先明白这两个东西是什么关系,不然很容易在选型上走弯路。很多人以为FAST_LIO2是FAST_LIO的简单升级版,直接装新的就行,实际上两者的设计目标和适用场景有明确区别。
1.1 两个版本共享的核心思路
FAST_LIO全称是Fast LiDAR-Inertial Odometry,本质是一个紧耦合的激光惯性里程计。它把激光点云和IMU数据放在一个统一的迭代扩展卡尔曼滤波框架里做状态估计,而不是像早期一些方案那样先做激光里程计再和IMU松耦合。紧耦合的好处是IMU的高频输出能在激光帧间隔内持续约束姿态,激光帧到来时又反过来修正IMU的漂移,两者互相兜底。
它最核心的一个设计是直接法配准。传统LOAM系列会先提取角点和面点特征,再拿特征去做匹配,特征提取这一步本身就丢信息,而且在结构化程度低的环境里(比如树林、空旷场地)特征提取质量很差。FAST_LIO跳过了显式特征提取,直接用原始点云构建残差,配合它自己维护的ikd-Tree增量式kd树做最近邻搜索。ikd-Tree支持增量插入和删除,地图更新时不用重建整棵树,这是它能做到实时的一个关键。
1.2 FAST_LIO2到底改了什么
FAST_LIO2在第一个版本基础上做了几处实质性改动,我按影响程度排一下。
第一是配准残差模型的调整。FAST_LIO2引入了更细的点面残差处理方式,对平面点的判定更严格,在退化场景(比如长直走廊、隧道)里的鲁棒性有提升。我实测在一条约80米的直走廊里,FAST_LIO跑下来末端有可见的横向漂移,FAST_LIO2明显收敛得更好。
第二是对固态激光雷达的适配。FAST_LIO2在代码层面更好地支持了非重复扫描模式的雷达(比如一些中短距固态雷达),点云组织方式和运动补偿逻辑都做了对应处理。如果你手上是这类雷达,直接上FAST_LIO2更省事。
第三是地图管理和内存占用。FAST_LIO2对ikd-Tree的维护策略做了优化,长时间建图时内存增长更平缓。我跑一个约15分钟的室内数据集,FAST_LIO峰值内存到过2.3G左右,FAST_LIO2在同样数据下大概1.6G。
| 对比维度 | FAST_LIO | FAST_LIO2 |
|---|---|---|
| 残差模型 | 基础点面残差 | 更严格的平面判定 |
| 退化场景鲁棒性 | 一般 | 较好 |
| 固态雷达适配 | 需手动改 | 原生支持更好 |
| 长时间建图内存 | 增长较快 | 增长平缓 |
| 社区活跃度 | 维护减少 | 相对活跃 |
提示:如果你用的是传统机械式多线雷达(16线、32线这类),两个版本都能跑,差异不会特别夸张;如果是固态雷达或者对退化场景要求高,优先FAST_LIO2。
2. 环境搭建:依赖版本才是真正的拦路虎
环境搭建这一步,网上教程一大把,但真正照着做能一次跑通的不多。问题几乎都出在依赖版本上。ROS的版本、PCL的版本、Eigen的版本,任何一个对不上,编译阶段就报一堆看不懂的模板错误。
2.1 系统与ROS版本的选择
我建议直接用Ubuntu 20.04 + ROS Noetic这套组合。原因很实际:Noetic是ROS1最后一个长期支持版本,PCL默认是1.10,Eigen是3.3.7,这两个版本和FAST_LIO系列的代码兼容性最好。如果你用Ubuntu 18.04 + Melodic,PCL是1.8,部分API对不上,需要改代码;用Ubuntu 22.04的话ROS1支持就麻烦了,得考虑ROS2版本,而FAST_LIO的ROS2分支成熟度参差。
安装ROS Noetic按官方流程走就行,桌面完整版:
sudo apt update sudo apt install ros-noetic-desktop-full装完之后记得source环境,并且把source命令写进.bashrc,不然每开一个新终端都要手动source一次,很容易忘。
2.2 关键依赖的安装与版本核对
FAST_LIO依赖的主要库有:PCL、Eigen、Sophus、livox_ros_driver(如果用Livox雷达)。逐个说。
PCL和Eigen在装ROS桌面版时基本都带上了,但一定要核对版本:
# 查看PCL版本 pcl_version=$(pkg-config --modversion pcl_common 2>/dev/null || echo "未找到") echo "PCL: $pcl_version" # 查看Eigen版本 grep -E "define EIGEN_(WORLD|MAJOR|MINOR)_VERSION" /usr/include/eigen3/Eigen/src/Core/util/Macros.hNoetic下正常应该是PCL 1.10、Eigen 3.3.7。如果Eigen版本不对,Sophus编译会直接失败。
Sophus是李群李代数的库,FAST_LIO用它做位姿表示和优化。装的时候注意要用非模板版本,模板版本和FAST_LIO的代码接口对不上:
git clone https://github.com/strasdat/Sophus.git cd Sophus git checkout 1.0.0 mkdir build && cd build cmake .. make -j4 sudo make install这里git checkout 1.0.0很关键,master分支的接口变过,直接编译FAST_LIO会报找不到某些成员函数。
livox_ros_driver只有你用Livox系列雷达才需要。装的时候注意它和ROS版本的对应,Noetic要用对应的分支。装完记得把driver的launch文件路径记下来,后面跑数据要用。
2.3 编译FAST_LIO时的常见报错与处理
创建工作空间,把源码放进去:
mkdir -p ~/fastlio_ws/src cd ~/fastlio_ws/src git clone https://github.com/hku-mars/FAST_LIO.git cd FAST_LIO git checkout main然后回到工作空间根目录编译:
cd ~/fastlio_ws catkin_make编译阶段最常见的三个报错,我列一下和处理方式。
报错一:找不到Sophus头文件。说明Sophus没装好或者装到了非标准路径。检查/usr/local/include/sophus是否存在,没有的话重新装Sophus,装完sudo ldconfig刷新一下库缓存。
报错二:Eigen相关的模板报错,一堆no matching function。九成是Eigen版本不对。Noetic下如果之前手动装过别的Eigen版本,可能覆盖了系统自带的,需要把多余的卸掉,保证/usr/include/eigen3是3.3.7。
报错三:PCL的pcl::PointCloud相关报错。通常是PCL版本和代码里用的API不匹配。FAST_LIO的main分支适配的是PCL 1.10,如果你系统里是1.8,需要改代码里用到的新API。
注意:编译前先
source /opt/ros/noetic/setup.bash,否则catkin_make找不到ROS的cmake配置,会报一堆找不到catkin的错。
FAST_LIO2的编译流程基本一样,把仓库换成FAST_LIO2的地址即可。两个可以放在同一个工作空间的不同包目录下,但包名不能冲突,注意看各自的package.xml里的名字。
3. 跑通第一个数据集:从数据到地图的完整链路
环境搭好只是第一步,真正跑起来才是见真章的地方。我建议第一个测试用官方提供的示例数据集,别急着上自己的雷达,先把链路跑通。
3.1 数据准备与话题核对
FAST_LIO需要的输入话题主要有两个:激光点云话题和IMU话题。官方数据集一般会提供bag包,跑之前先用rosbag info看一下里面的话题名:
rosbag info your_dataset.bag重点看两个话题名,比如常见的/livox/lidar和/livox/imu,或者/velodyne_points和/imu/data。然后去FAST_LIO的配置文件里核对,配置文件在config/目录下,比如avia.yaml、velodyne.yaml。
配置文件里几个关键字段:
lid_topic:激光话题名,必须和bag里一致imu_topic:IMU话题名,必须一致extrinsic_T和extrinsic_R:雷达和IMU之间的外参,平移和旋转
外参这一项是新手最容易忽略的。官方配置文件里的外参是针对特定雷达和IMU组合标定的,如果你用自己的设备,外参不对,跑出来的轨迹会歪得离谱。外参必须自己标定,或者至少确认你的雷达和IMU的相对位置和官方配置一致。
3.2 启动流程与RViz观察要点
跑数据集的完整流程分三步,开三个终端。
终端一,启动roscore:
roscore终端二,启动FAST_LIO:
cd ~/fastlio_ws source devel/setup.bash roslaunch fast_lio mapping_avia.launch终端三,播放bag:
rosbag play your_dataset.bag --clock--clock这个参数别漏,它让bag里的时间戳和ROS时间同步,不加的话RViz里可能看不到点云。
RViz里重点观察三样东西。一是点云是否正常显示,如果一片空白,八成是话题名对不上或者外参有问题。二是轨迹是否连续,如果轨迹出现跳变或者断裂,通常是IMU数据有问题或者时间戳不同步。三是地图是否逐渐成形,正常跑起来地图会随着移动一点点累积出来。
3.3 地图保存与格式转换
跑完之后地图要保存下来。FAST_LIO提供了保存服务,在RViz里或者用命令行调用:
rosservice call /laser_mapping/save_map "resolution: 0.1 destination: '/home/user/map.pcd'"保存出来的是PCD格式的点云地图。如果后续要用在导航或者别的工具里,可能需要转成别的格式。PCD转PLY可以用pcl的工具:
pcl_pcd2ply map.pcd map.ply提示:保存地图前先确认建图已经稳定,如果轨迹还在漂,保存下来的地图会有重影。判断方法是看回环处点云是否重合,重合度好说明建图质量可以。
4. 两个版本实测对比:数据说话
跑通之后就该做对比了。我用了三个场景的数据:一个室内办公室(约200平米,有桌椅隔断)、一条长直走廊(约80米)、一个半室外场景(有玻璃幕墙和柱子)。每个场景分别用FAST_LIO和FAST_LIO2跑,记录轨迹精度、实时性和内存占用。
4.1 轨迹精度对比
精度这块我用的是回到起点的闭合误差作为主要指标,因为绝对精度没有真值不好评,闭合误差相对客观。
| 场景 | FAST_LIO闭合误差 | FAST_LIO2闭合误差 |
|---|---|---|
| 室内办公室 | 约0.15m | 约0.12m |
| 长直走廊 | 约0.45m | 约0.18m |
| 半室外场景 | 约0.30m | 约0.22m |
室内办公室两个版本差距不大,因为场景结构化程度高,特征丰富,两个版本都能处理好。长直走廊差距最明显,FAST_LIO的横向漂移肉眼可见,FAST_LIO2靠更严格的平面约束把漂移压下去了。半室外场景因为玻璃幕墙会产生一些无效点,两个版本都受一定影响,但FAST_LIO2稍好。
4.2 实时性与资源占用
实时性我用的是单帧处理耗时和CPU占用率。测试机器是i7-10700 + 32G内存。
| 指标 | FAST_LIO | FAST_LIO2 |
|---|---|---|
| 平均单帧耗时 | 约28ms | 约32ms |
| CPU峰值占用 | 约65% | 约72% |
| 峰值内存 | 约2.3G | 约1.6G |
| 建图15分钟后内存 | 约2.3G | 约1.6G |
有意思的是FAST_LIO2单帧耗时反而略高,因为它残差计算更细,但内存控制明显更好。如果你的平台内存紧张,FAST_LIO2的优势就体现出来了。单帧耗时那几毫秒的差距,在10Hz雷达下基本感知不到。
4.3 退化场景的表现差异
退化场景是区分两个版本的关键。我专门在长直走廊里做了往返测试,走廊两侧是平整墙面,几乎没有纵向特征。
FAST_LIO在走廊中段开始出现横向漂移,走到尽头时轨迹已经偏离实际位置约0.4米,返回起点时闭合误差累积到0.45米左右。FAST_LIO2在同样路径下,横向漂移被明显抑制,闭合误差控制在0.18米。
原因在于FAST_LIO2对平面点的判定更严格,在只有墙面这种大平面时,它能更准确地约束横向自由度。而FAST_LIO的残差模型在这种情况下约束不够,横向就飘了。
注意:退化场景下即使FAST_LIO2表现更好,也不代表可以完全依赖。如果走廊特别长(超过100米),建议配合其他约束手段,比如加入已知的平面约束或者用回环检测。
5. 踩过的坑与排查思路
这部分是我觉得最有价值的内容,因为网上教程很少讲这些。每个坑我都按"现象—排查—解决"的顺序讲,方便你复现排查思路。
5.1 点云话题对不上导致RViz空白
现象:启动launch、播放bag,RViz里Fixed Frame设对了,但点云就是不显示。
排查:先rostopic list看当前有哪些话题,再rostopic hz /your_lidar_topic看有没有数据在发。如果话题存在但没数据,说明bag里的话题名和实际发布的不一致,或者bag播放有问题。如果话题有数据但RViz不显示,检查配置文件里的lid_topic是否和实际话题名完全一致,注意大小写和斜杠。
解决:改配置文件里的lid_topic,重新编译(改yaml不用编译,但改launch要重新source)。这个坑我踩过两次,都是因为话题名里多了或少了一个斜杠。
5.2 IMU时间戳不同步导致轨迹跳变
现象:轨迹跑着跑着突然跳一下,或者整体漂移很大。
排查:用rostopic echo /your_imu_topic看IMU消息的header.stamp,和激光消息的时间戳对比。如果两者时间基准不一致(比如一个用系统时间,一个用雷达内部时间),就会出问题。
解决:确保IMU和激光的时间戳来自同一时间源。如果是自己的设备,检查驱动配置里时间戳的设置。有些雷达驱动默认用雷达内部时钟,需要改成用ROS时间。
5.3 外参不准导致地图重影
现象:建出来的地图有明显重影,同一个墙面出现两层。
排查:先确认外参是不是用的官方默认值。如果是,大概率不准。外参需要根据你的雷达和IMU实际安装位置标定。
解决:标定外参有几种方式,简单的是用卷尺量雷达和IMU的相对位置,得到平移量;旋转量如果两者安装方向一致可以设为单位矩阵。要求高的话用专门的标定工具做联合标定。我自己的经验是,平移量量准了,旋转量在安装规整的情况下用单位矩阵,效果已经够用。
5.4 长时间建图内存暴涨
现象:跑十几分钟后程序变卡,最后可能崩掉。
排查:用top或htop看内存占用曲线,如果是持续上涨不回落,说明地图点云在无限累积。
解决:FAST_LIO2在这方面做了优化,如果还在用FAST_LIO,可以手动限制地图范围,或者定期清理远处点云。另外检查ikd-Tree的配置参数,有些参数控制树的平衡和清理策略,调一下能缓解。
6. 选型建议与进阶方向
跑完这一轮,我对两个版本的使用场景有了比较清晰的判断。
6.1 什么情况选哪个版本
如果你的雷达是传统机械式多线雷达,场景结构化程度高,对内存不敏感,FAST_LIO完全够用,代码更简单,改起来也方便。如果你用的是固态雷达,或者场景里有大量退化区域(长走廊、隧道、大平面),或者平台内存紧张,直接上FAST_LIO2。
还有一个实际考虑是社区维护。FAST_LIO2的更新相对活跃,遇到问题更容易找到解决方案。FAST_LIO虽然经典,但维护节奏慢下来了。
6.2 可以继续往下做的几件事
跑通基础版本之后,有几个方向可以深入。一是加入回环检测,FAST_LIO本身不带回环,长时间建图累积误差不可避免,可以外挂一个回环模块,比如用Scan Context做地点识别。二是多传感器融合,把轮式里程计或者视觉加进来,在退化场景下多一层约束。三是地图后处理,建完的PCD地图可以做滤波、降采样、分割,方便后续用于导航或者三维重建。
我自己下一步打算试试把回环加进去,因为纯里程计跑大场景还是吃力。另外外参标定这块也想做得更规范一些,现在靠量尺寸终究粗糙,准备用联合标定的方式再精调一遍。
整体用下来,FAST_LIO系列的门槛主要在环境搭建和外参标定这两步,跨过去之后跑起来其实挺顺。两个版本没有绝对的好坏,关键看你的雷达类型和场景特点。我个人的习惯是先用FAST_LIO2跑一遍看效果,如果场景简单再考虑换FAST_LIO省点资源。这套流程走下来,从零到跑通大概需要半天到一天,主要时间花在依赖排查上,编译本身很快。