我花了两天把FAST-LIO跑通的经历,让我决定写这篇东西。这两天里踩的坑,比过去写业务代码一年都多:不是编译报错,就是雷达IP不对,好不容易编译过了,一启动就段错误崩掉。很多刚入门激光雷达SLAM的朋友,其实第一道坎根本不在算法本身,而是不知道怎么把FAST-LIO这个激光雷达-惯性里程计框架在ROS环境里稳稳当当地跑起来。这篇博文就是基于我自己在ROS Noetic上部署FAST-LIO的完整过程,把环境准备、源码编译、launch文件配置、mid360雷达适配、建图实操到点云地图保存这些关键环节全部拆开讲一遍,顺手把我踩过的坑、查过的源码、试过的参数都记录在案,给你一条能直接照着走的路。
那这个内容适合谁看呢?主要是三类人:一是刚入手固态激光雷达(尤其是livox mid360)想做建图的新手;二是已经用别的2D雷达跑过cartographer,想往3D雷达SLAM进阶的同学;三是被网上各种ROS安装教程带偏了、系统环境已经一团乱麻的兄弟。无论你是想验证传感器能不能用,还是想快速搭一套激光雷达-惯性里程计的融合建图方案,这篇文章都能帮你少走弯路。
1. 部署前的环境准备与技术选型
1.1 为什么选择FAST-LIO而非传统LOAM系算法
先说结论:在固态激光雷达+IMU融合建图这个场景里,FAST-LIO是当前ROS1生态里我用过最省心的紧耦合方案,没有之一。
LOAM系列(包括A-LOAM、LEGO-LOAM)当年确实神,但它们的架构是基于旋转式机械雷达设计的,对点云畸变矫正和特征提取有很强的假设。到了固态雷达时代,比如mid360这种非重复扫描的棱镜式雷达,点云分布方式完全变了,LOAM系的表现会明显下滑。FAST-LIO把雷达点云和IMU数据放进一个迭代误差状态卡尔曼滤波(IESKF)框架里紧耦合,直接在原起点云上做配准,不需要像LOAM那样单独提边缘点和平面点,这种思路天然适合固态雷达稀疏且分布不均匀的点云。实测下来,在同样的走廊场景里,A-LOAM跑几步就飘,FAST-LIO能稳稳贴住地面。
而且FAST-LIO对IMU的依赖不只是当作运动补偿工具,它把IMU状态写进了滤波器,这意味着在雷达退化场景——比如长直走廊、空旷大厅——惯性信息能兜底,这个特性对建图稳定性非常关键。如果你后面要换雷达、换IMU,FAST-LIO的launch文件里参数结构也足够清晰,改起来不至于满头问号。
1.2 Ubuntu与ROS版本怎么匹配最省事
这是新手最容易被坑的地方。FAST-LIO官方源码支持的ROS版本很宽,但从我实际编译体验来看,Ubuntu 20.04 + ROS Noetic是舒适度最高的组合,没有之一。
为什么这么说?因为FAST-LIO依赖的livox_ros_driver、livox_ros_driver2这些雷达驱动,在Noetic上有成熟的预编译支持,网上现成的教程和报错案例也最全。Ubuntu 18.04 + Melodic虽然理论上也行,但PCL和Eigen版本偏老,编译时容易撞上奇怪的模板报错。Ubuntu 22.04 + ROS Humble也可以跑,但要走livox_ros_driver2的新架构,API有变动,很多东西得自己适配,新人会非常痛苦。
如果你是纯新手,系统还没装ROS,我强烈建议你重装Ubuntu 20.04,然后用国内源镜像装Noetic。装ROS那一步,网上很多人推“鱼香ROS一键安装”,我自己也试过,确实快,一条命令装完ROS核心,省去了一堆源配置的折腾。不过要注意,一键脚本只解决ROS本体安装,不解决后面雷达驱动和FAST-LIO的依赖冲突,所以关键还是把系统版本和ROS版本选对。如果你非要留在Ubuntu 22.04,至少做好折腾两三天的心态准备。
1.3 依赖库版本与编译顺序的硬性约束
FAST-LIO的核心依赖有三个:Eigen、PCL、livox_ros_driver。这三个的版本和编译顺序都有讲究,乱来大概率会编译报错。
- Eigen:FAST-LIO代码里用了大量Eigen的块操作和矩阵运算,建议直接装系统源里的libeigen3-dev,版本3.3.7以上即可,不需要自己源码编译最新版,反而容易跟PCL的Eigen版本冲突。
- PCL:Noetic自带的PCL 1.10完全够用,不需要额外编译,如果你之前为了折腾某个项目手动编译过PCL,建议在新环境里装完先查一下
pcl_version,免得FAST-LIO链接到错误版本。 - livox_ros_driver:这个是重头戏。官方FAST-LIO仓库默认适配的是livox_ros_driver,但对于mid360用户,更推荐用livox_ros_driver2,因为mid360在driver2里支持更完整的点云格式配置。装驱动的时候有个细节:driver2编译时会生成
livox_ros_driver2这个包名,跟老版livox_ros_driver不一样,后面launch文件里引用的名字要对应上,否则会报找不到package。
编译顺序上,我建议严格按照下面的顺序来:先装Eigen和PCL,再编译livox_ros_driver2,最后编译FAST-LIO。这个顺序是为了保证FAST-LIO在cmake搜索依赖时能找到正确版本,如果先编译FAST-LIO再装驱动,那FAST-LIO的CMakeLists里find_package(catkin REQUIRED COMPONENTS livox_ros_driver2)就会失败,你只能在中间反复加环境变量碰运气。
2. 源码编译与雷达驱动适配详解
2.1 FAST-LIO源码拉取与工作空间搭建
环境准备好了,接下来是拉源码。先创建catkin工作空间,注意不要用sudo,普通用户权限就够:
mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone https://github.com/hku-mars/FAST_LIO.git cd ~/catkin_ws catkin_make这里有个坑:FAST-LIO默认分支是面向livox_ros_driver的,如果你用的是mid360且想走driver2,建议直接看FAST-LIO的README里关于livox_ros_driver2的说明,里面要求你改CMakeLists.txt里的包名引用,并且在launch文件里用driver2的节点名。不夸张地说,我见过不少人都卡在这一步,编译报错提示找不到livox_ros_driver2包,但实际就是没改CMakeLists。
还有一个容易忽略的点:catkin_make之前,确认~/.bashrc里的ROS环境变量已经source了,比如source /opt/ros/noetic/setup.bash。如果你用了zsh,记得把环境变量也加到~/.zshrc,否则编译时rosdep相关的命令会找不到。
编译过程中如果报错提示找不到某些头文件,别急着瞎改代码,先用rospack find确认对应功能包是否存在。比如报eigen3/Eigen/Core: No such file,大概率是Eigen没装或者路径没配好。一条sudo apt install libeigen3-dev就能解决的事,不需要去翻源码。
2.2 mid360专用驱动livox_ros_driver2的配置要点
livox_ros_driver2和旧版驱动的最大区别在于它引入了一个config目录,里面有各型号雷达的json配置文件。mid360的配置文件里可以直接设置扫描频率、点云密度、坐标系朝向等参数,比老驱动用launch参数硬撸清晰得多。
在安装driver2之前,先看看自己的雷达是网口连接还是USB连接。mid360默认走网口,默认IP是192.168.1.1xx,具体看雷达标签。这个IP必须和你的电脑网卡IP在同一个网段,否则连不上。举个实际例子:我手里的mid360默认IP是192.168.1.102,那我电脑的网卡IP就得设成192.168.1.100,子网掩码255.255.255.0,网关不用管。很多新手在这步栽跟头,我见过最典型的场景是折腾半天改雷达IP,结果发现网线压根没插到笔记本的千兆网口上,或者插到了USB转网口的百兆扩展坞里,点云数据直接被带宽卡死。
驱动编译本身不复杂:
cd ~/catkin_ws/src git clone https://github.com/Livox-SDK/livox_ros_driver2.git cd ~/catkin_ws catkin_make编译完以后,第一次连接雷达时可以用roslaunch livox_ros_driver2 rviz MID360.launch测试,如果RViz里能出现点云,说明驱动链路通了大半。这个launch文件里面读的配置文件是config/MID360_config.json,里面有个host_ip字段,要改成你电脑的IP,否则雷达会把点云数据发给错误的地址,现象就是驱动节点显示已连接但就是没有点云话题输出。这是我第二次踩坑的地方,改完IP立刻正常。
2.3 点云话题与坐标系的统一问题
FAST-LIO订阅的话题名一般是/livox/lidar,IMU话题是/livox/imu,但这只对mid360的默认配置成立。如果你用的雷达不同,或者驱动launch文件里改了话题名,那必须在FAST-LIO的launch文件里同步修改。
知道为什么容易乱吗?因为FAST-LIO官方仓库里的示例launch是给livox_ros_driver准备的,话题名是/livox/lidar和/livox/imu,但driver2的默认话题名也是这两个。当你把两个包混在一起编译后,话题名恰好一致时会正常工作,可一旦用了driver2的录像包重放,或者改了雷达ID,话题名就可能出现/livox/lidar_0这种带后缀的情况,FAST-LIO自然就收不到数据了。
排查方法很简单:驱动节点跑起来以后,用rostopic list看一下实际输出的点云和IMU话题名,再对照FAST-LIO的launch文件里pointcloud_topic和imu_topic两个参数,必须严格一致。这个话题名不一致的问题,在fast-lio运行后RVIZ界面黑屏、无点云显示的报错排查中占了一半以上的比例。
3. launch文件解析与核心参数调优
3.1 FAST-LIO自带的launch参数逐项拆解
FAST-LIO的launch文件实际上是整个系统能否稳定运行的关键。很多人编译通过、驱动也正常,但一跑建图就飘,根本原因就是launch参数没调对。这里我把用mid360建图最关心的几个参数拿出来逐项说明,都在FAST_LIO/launch/mapping_mid360.launch这个文件里。
<arg name="rviz" default="true" /> <arg name="pointcloud_topic" default="/livox/lidar" /> <arg name="imu_topic" default="/livox/imu" /> <arg name="set_config_file" default="$(find fast_lio)/config/mid360.yaml" />rviz:默认是true,启动后自动打开RViz可视化。如果你的电脑性能吃紧,或者只想跑后台数据,可以改成false,但调试阶段建议保留,观察点云和轨迹最直观。pointcloud_topic和imu_topic:上面已经说过,必须和实际发布的话题名对应。涉及到雷达驱动和IMU是否能被FAST-LIO感知的问题。set_config_file:指向FAST-LIO的yaml配置文件,mid360的配置在这里。这个文件是重头戏,里面参数很多,但真正需要动的不多,关键是lidar_type、imu_en、point_filter_num这几个。
再看yaml里几个核心参数:
common: lidar_type: 1 imu_en: true scan_line: 4 point_filter_num: 6lidar_type为1表示livox系列雷达,这是FAST-LIO里livox适配的开关。如果你用其他雷达,这个值要改成对应的类型。scan_line对mid360来说写4就行,因为mid360虽然等效扫描线不多,但FAST-LIO并不依赖这个值做特征提取。point_filter_num是点云抽稀参数,每N个点取一个,数值越大,参与计算的原始点越少、CPU负担越小,但建图精度也会下降。我用mid360时把它调成2-6之间,室内小场景用6基本够,室外大场景调到2更稳。
IMU参数在preprocess和imu段里:
preprocess: lidar_type: 1 scan_line: 4 blind: 2.0 imu: imu_en: true imu_rate: 200blind是近距离盲区阈值,把雷达近处过于密集且不可靠的点过滤掉,mid360设置2.0米比较合适,太大会丢掉墙上的特征,太小会引入雷达自身的噪声点。imu_rate是IMU频率,mid360内置IMU是200Hz,这个值务必和实际IMU输出频率一致,不一致的表现就是建图轨迹缓慢漂移,肉眼看不出来但跑一大圈回到原点时会发现闭合差很大。
3.2 坐标系外参标定的实操建议
FAST-LIO把激光雷达和IMU的安装外参写死在yaml里,初装时可以不那么精确,但外参和实际偏差过大会导致地图分层。mid360这种自带IMU的雷达,外参基本是单位矩阵,也就是雷达坐标系和IMU坐标系重合。自己组装雷达+独立IMU的,就必须标定外参。
简单说下我的做法:先把雷达和IMU刚性固定,保证二者之间没有相对位移。然后跑一小段有旋转和直线运动的数据,录成rosbag,再用lidar_align这类外参标定工具离线算。注意标定时要人为制造足够的旋转激励,只在原地平移标出来的外参不可信。
外参不准的典型症状是:静止时点云对齐良好,一运动起来地图边缘出现重影或分层。如果你确认雷达和IMU的物理安装没有松动,但建图就是飘,先怀疑外参。外参的旋转和平移量写在哪?在yaml文件里的extrinsic_rotation和extrinsic_translation,通常是3x3矩阵和3x1向量,从标定工具的结果直接抄进去即可。
3.3 点云频率、带宽和CPU负载的平衡
mid360在驱动里默认是10Hz扫描,点云点数在30万左右每秒。FAST-LIO的实时性取决于CPU算力、点云抽稀比例、配准迭代次数三者之间的平衡。
我在一台八代i7笔记本上实测,point_filter_num=6时CPU占用在60%到80%之间,建图帧率能稳定在8到10Hz左右。如果把point_filter_num改大,比如12,CPU占用降下来了,但建图精度肉眼可见下降,转角和门框处会有明显拉花。如果你用的是工控机或者老笔记本,建议先用4到6之间的值跑一遍小场景,观察CPU和内存占用,再决定要不要调大抽稀比例。
还有一个容易忽略的带宽问题。mid360是网口雷达,如果你把点云话题原样发布出去,同时又在同一台电脑上跑FAST-LIO,千兆网口问题不大。但要是电脑用了无线网络,或者网口被其他数据占满,雷达点云会出现丢包,FAST-LIO的表现是轨迹跳变。这种情况优先检查有线连接和交换机,而不是调算法参数。
4. 激光雷达-惯性里程计建图实操与地图保存
4.1 从驱动到建图的全流程快速验证
所有配置就位后,先不要急着扛着设备跑大场景,我们做一次最小化验证。
先启动驱动:
roslaunch livox_ros_driver2 rviz MID360.launch确认RViz里能看到点云,并且rostopic hz /livox/lidar输出频率在10Hz左右,rostopic hz /livox/imu输出频率在200Hz左右。这两路数据的频率正常,才说明传感器链路可靠。
然后启动FAST-LIO:
roslaunch fast_lio mapping_mid360.launch启动后RViz里会多出FAST-LIO的Map点云和Odometry轨迹。拿雷达对着天花板和墙壁静止晃一晃,观察点云是否和驱动RViz里显示的一致,再看Odometry的轨迹是否随设备移动而伸缩。如果轨迹和实际运动方向背离,基本是外参错误或者IMU方向问题。
这一步验证通过后,就可以拿设备在房间里慢慢走一圈,记录建图效果。FAST-LIO在室内小场景通常不需要额外的回环检测就能保证低漂移,但你走得越快、场景特征越少,漂移风险越高。我建议第一圈尽量贴墙走,让雷达多看到一些墙角和门的特征,后面再放开速度。
4.2 录制rosbag与离线建图的操作细节
在很多实际工程场景里,我们不想扛着设备现场调参,而是把传感器数据录下来,回办公室慢慢处理。这就需要rosbag录制。录制命令很简单:
rosbag record /livox/lidar /livox/imu -O scene01.bag但有个细节:rosbag record默认不记录tf和odom这类高频小消息,但对FAST-LIO离线建图来说,只需要点云和IMU就够。录的时候注意磁盘空间,mid360半小时的数据量轻松超过10GB,建议录之前检查一下磁盘剩余。
离线重放建图的话,先启动FAST-LIO节点,再播放bag:
roslaunch fast_lio mapping_mid360.launch rosbag play scene01.bag播放bag时有个容易踩的坑:bag里记录的时间戳是录制时的真实时间,而rosbag play默认按原时间轴播放,如果你中途暂停过,FAST-LIO的IMU预积分会跳变,导致建图出现断层。解决办法是用rosbag play --clock并勾选launch文件里的use_sim_time,但这个操作复杂且容易引入新问题。我的建议是录制时一气呵成,别中途停,播放时也别用暂停功能,尽量让IMU流是连续的。
4.3 点云地图的保存与pcd格式输出
FAST-LIO运行过程中,RViz里看到的地图只是实时可视化的结果,并不会自动保存。想拿到能够用于后续导航或展示的完整点云地图,需要订阅FAST-LIO发布的/cloud_registered话题,里面是已经配准到世界坐标系下的点云。
保存地图最常用的是pcl_ros里的pointcloud_to_pcd工具:
rosrun pcl_ros pointcloud_to_pcd input:=/cloud_registered这个工具会持续把点云写入当前目录下的pcd文件,文件名带时间戳。问题在于它会一直写,直到节点被Ctrl+C终止,中间会产生大量文件。想保存最终地图,有两个办法。
办法一:等FAST-LIO跑完,在RViz里把地图话题取消再勾选一次,让Rviz重新订阅一帧完整点云,然后用RViz右上角“File→Save as Image”之类的方式保存,这只能存图不能存点云。
办法二更适合拿到高质量pcd:自己写一个ROS节点订阅/cloud_registered,按下Ctrl+C时保存一帧完整点云为pcd文件。如果不想写代码,也可以用pcl_ros的另一个工具bag_to_pcd,从rosbag里提取点云帧。但不管哪种方式,都建议建图结束后保持雷达静置一两秒,让滤波器收敛,再保存场景地图,这样得到的pcd边缘更干净。
保存pcd后,可以用CloudCompare或者pcl_viewer打开查看:
pcl_viewer scene.pcd如果发现地图有轻微倾斜或者漂移,回查外参和IMU参数;如果只是点云密度不均匀,那是盲区和抽稀导致的正常现象。
5. 高频问题排查与避坑经验总结
5.1 雷达连接与IP配置的常见故障
这一节是写给用mid360和新手的。雷达连接问题占了FAST-LIO部署故障的一半,而且症状千奇百怪:驱动启动后报错、点云话题不刷新、RViz黑屏等等,最后排查下来十有八九是网络没通。
- 现象1:
roslaunch livox_ros_driver2后没有报错,但rostopic hz /livox/lidar输出为0。先检查网线连接和网卡IP,确保与雷达IP同网段。用ping 192.168.1.102测一下,如果ping不通,大概率是IP配置问题,而不是驱动问题。 - 现象2:ping通了,但点云依然没有。看看是否在驱动的json配置文件里改了雷达IP,但电脑IP没同步改,或者改了两处的IP不在同一子网。更隐蔽的是:mid360默认广播域是192.168.1.x,如果你电脑的IP是192.168.2.x,即便你设置了路由,雷达的UDP广播也过不来。
- 现象3:雷达在RViz里显示的点云有断续。如果横向转动雷达时点云连续,纵向转动时点云跳跃,大概率是雷达和电脑之间网络拥塞。不要用百兆网口或USB转网口,直接用主板上的千兆口,网线也尽量用短线。
很多教程会教你直接改雷达本身IP,但是mid360这代雷达支持通过驱动配置软件去改。实际操作中,如果电脑端IP能改,我更建议先改电脑端IP来匹配雷达默认地址。只有当一台电脑需要接多台雷达时,才去改雷达自身IP。
5.2 FAST-LIO编译和运行时的经典报错
这里挑三个我在部署过程中遇到的高频报错来剖析,基本覆盖了绝大多数编译运行问题。
报错一:fatal error: livox_ros_driver2/LivoxLidarConfig.h: No such file or directory。这个就是没改CMakeLists.txt,导致fast_lio编译时找不到driver2的头文件。解决办法是把FAST_LIO/CMakeLists.txt里所有出现livox_ros_driver的地方改成livox_ros_driver2,再重新catkin_make。但要注意,find_package(catkin REQUIRED COMPONENTS livox_ros_driver2)和add_executable里的链接库名都要同步改,别只改一半。
报错二:Error: Invalid laser type!。这个直接写在FAST-LIO源码里,意思是yaml配置里的lidar_type值不对。mid360应填1,如果是livox系列填1,如果是旋转式雷达填其他对应值。很多人编译没问题,但一启动就报这个,就是yaml没改对。
报错三:编译时PCL相关的模板报错,比如no matching function for call to ‘pcl::PointCloud<pcl::PointXYZINormal>::push_back’。这多半是PCL版本混了,比如系统自带的PCL和你手动编译的PCL头文件路径冲突。检查一下echo $CMAKE_PREFIX_PATH,如果包含了你手动安装的PCL路径,把它清理干净,用系统源里的PCL就好。
5.3 建图漂移问题与IMU标定技巧
建图漂移是FAST-LIO最大的痛点,但漂移未必是算法问题,很多时候是数据质量或传感器标定问题。
- 第一种漂移:设备静止时,地图点云在雷达坐标系里不动,但里程计轨迹在缓慢移动。这种通常是IMU零偏没校准好,或者IMU话题频率不对。mid360内置IMU的零偏通常在出厂时标定过,如果不是自己拆机过,不太容易出问题。更多情况是
imu_rate填错了,比如实际IMU输出100Hz,配置里却写了200Hz,滤波器的时间戳对不上,轨迹自然会飘。 - 第二种漂移:建图过程中地图整体在旋转或者打弯。这种通常外参不正确,特别是IMU和雷达之间的旋转外参。解决办法是重新做外参标定,标定时的运动要多包含旋转,纯平移的数据不适合标定旋转外参。
- 第三种漂移:地图在场景环境退化区域发生跳变,比如长直走廊。这时候FAST-LIO靠IMU撑着,如果IMU也有漂移,会出现轨迹慢慢偏到墙上。这属于算法局限,可以通过在场景中增加特征点来缓解,比如贴一些图案或摆几个箱子和椅子,给雷达制造可配准的特征。
如果你懒得做完整的外参标定,至少可以把mid360的IMU和雷达外参写成单位矩阵,然后跑一段数据看看轨迹是否反转。轨迹反转基本是外参的旋转矩阵方向错了,把外参矩阵取负或者交换轴序再去试。这个方法粗暴但不失为一种快速验证手段。
5.4 数据录制、回放与性能监控的实用技巧
最后聊点平时不被人提但很实用的技巧。数据录制建议开一个专门的终端,提前写一个别名或者脚本,把rosbag record参数固定下来,避免每次现敲漏掉话题。我自己的录制脚本一般是:
rosbag record /livox/lidar /livox/imu -O $(date +%Y%m%d_%H%M%S).bag回放时如果出现播放速率跟不上,不要加-r 2这种加速参数,FAST-LIO对IMU流的时间敏感,加速播放会让IMU预积分崩掉。宁可等它慢慢播放,也不要为了省时间破坏数据流。
性能监控方面,用htop看CPU和内存是最直观的。如果CPU长期100%,说明抽稀参数太小或点云频率过高。这时候调大point_filter_num,不要想着换更强的电脑——在车上和机器人上,CPU资源本来就紧,调参比换硬件更实际。
另外,如果你打算把FAST-LIO的输出接入到后续的导航或者路径规划里,记得保存好里程计话题/Odometry和点云地图。FAST-LIO本身不输出占据栅格地图,你需要自己用octomap或者cartographer的2D投影库把pcd转成栅格地图,这一块我也踩过坑,但那是另一个话题了。
6. 写在最后:从能跑到跑好的几个进阶方向
FAST-LIO跑通只是第一步,真正让它成为可靠工具还需要一些后续工作。我个人建议按这个顺序来完善你的系统:
第一,把雷达驱动、FAST-LIO节点、录制脚本整理成一套可复用的launch文件,参数固化下来。别每次都手动启动三四个终端,容易漏。第二,练好用rosbag离线调参的工作流。现场建图一旦失败,重跑一遍数据又快又安全,比在现场反复试错高效十倍。第三,如果要在实际机器人上长期跑,考虑加入回环检测后处理。FAST-LIO本身是里程计,大场景长时间运行会有累计漂移,配合回环检测或因子图优化,精度会更接近工程可用的标准。
从更长远看,ROS 2生态下的激光雷达SLAM工具链正在成熟,FAST-LIO也有相应的ROS 2版本。但我个人的经验是,在传感器驱动和算法社区的成熟度上,ROS 1的Noetic版本目前依然是最平滑的起点。德尔塔机器人上用mid360跑FAST-LIO,和在扫地机器人底盘上跑,环境和资源差异很大,但核心的部署思路是一样的:先把传感器链路打通,再做标定,最终才轮到调参。
如果你跟我一样,也是从零开始接触固态激光雷达和惯性里程计,希望这篇实战记录能让你少踩几个坑。毕竟,我踩过的坑已经够多了,你踩新的就好。