1. 项目概述:这套组合到底能解决什么问题
我最早接触Mid-360和FAST-LIO2这个组合,是在做室内机器人的高精度定位建图时被逼出来的。当时先用单线激光雷达做过一遍二维建图,效果在小场景里还行,一到走廊、玻璃墙、楼梯口这种场景就各种飘;后来换成深度相机做视觉SLAM,光照一变化又歇菜。直到把Mid-360这颗混合固态激光雷达和FAST-LIO2这套紧耦合里程计算法搭在一起,才算真正把“点云采集→实时位姿估计→全局地图生成”这条链路跑通。
先说结论:Mid-360提供了360°水平视场、带IMU的紧凑型点云采集方案,FAST-LIO2则把雷达点云和IMU数据做了紧耦合融合,输出高频、低漂移的里程计和增量式全局地图。这套组合最典型的应用场景包括室内外巡检机器人的定位导航、AGV的自主行走、测绘级手持建图设备,以及需要快速生成三维点云地图的工程项目。无论你是做SLAM算法研究、机器人开发还是测绘数据处理,这篇文章都能给你一条完整的、可复现的技术路线。
我会从硬件特性、算法原理、环境搭建、数据采集、点云后处理到问题排查,把整个流程掰开揉碎讲清楚,尽量还原实际操作中你会遇到的每一步。
2. 核心原理拆解:FAST-LIO2是如何做到高精度的
2.1 紧耦合与迭代误差状态卡尔曼滤波
FAST-LIO2全称是FAST-LIO(Fast LiDAR-Inertial Odometry)的第二个版本,核心框架是一个迭代误差状态卡尔曼滤波器(IESKF)。它做的事可以粗略理解为:用IMU做高频运动预测,用激光点云做低频测量更新,两类数据互相纠正,最终输出一个准确的六自由度位姿。
这里的关键词是“紧耦合”。松耦合的做法是雷达和IMU各自算各自的,最后再融合;紧耦合则是在滤波器的状态向量里直接包含IMU的误差状态,而激光雷达的配准残差直接被用来更新这个状态。这样做的好处是,即使激光雷达在某个时刻因为场景退化(比如对着白墙或者空旷场地)提供不了有效约束,IMU依然能撑住短时间的位姿估计,不会立刻发散。
我当初第一次跑通FAST-LIO2时有个很直观的感受:它不像传统LOAM那样需要手工提取角点和面点,而是直接用原始点云或降采样后的点云做scan-to-map匹配。这带来两个直接好处:一是省掉了特征提取环节对场景结构的假设,二是实现起来更简单,泛化性更好。
2.2 直接配准与ikd-tree增量地图
FAST-LIO2在配准策略上有一项很重要的改进:它不再像第一版那样先提取特征点再配准,而是把当前帧点云与全局地图做直接配准,并通过ikd-tree维护一个增量式的全局地图。
ikd-tree你可以理解成“动态更新的KD-tree”。传统的KD-tree建好后如果往里加新点,通常要整棵树重建,代价很高;ikd-tree支持增量式插入、删除和动态平衡,所以FAST-LIO2可以一边建图一边把新扫描到的点并入地图,同时维持较快的最近邻搜索速度。这也是FAST-LIO2在CPU占用、内存增长方面比很多算法表现好的重要原因。
直接配准意味着每个有效点都可以作为约束参与位姿优化,而不是只依赖提取出来的少数特征。在环境结构丰富的地方,约束点越多,位姿收敛就越稳。代价是计算量更大,所以实际使用中通常会设置降采样滤波参数,比如把每帧点云降采样到0.3米到0.5米分辨率,减少参与配准的点数。
2.3 影响最终精度的三大因素
把FAST-LIO2跑起来很容易,跑得准却需要几个条件都到位。我总结出三个最影响最终建图精度的因素。
第一是外参标定精度。IMU坐标系到雷达坐标系的旋转和平移必须准确,尤其是旋转矩阵。你可以把外参想象成两个传感器之间的“骨头关节”,只要偏差一点点,滤波器就会把IMU的加速度、角速度投影到错误的方向上,长时间运行累积误差会非常明显。Mid-360内置的IMU出厂时有一些近似外参,但真要追求高精度,建议自己标一遍。
第二是场景退化程度。激光雷达里程计在几何结构自相似或者约束不足的环境里会遇到退化(degeneracy),比如很长的笔直走廊、大面积白墙、空旷广场。此时雷达提供的约束在某个方向上几乎是失效的,滤波器主要靠IMU积分在撑,误差会随时间缓慢增长。
第三是运动激励是否充足。IMU外参和陀螺仪偏置的收敛需要足够的角速度和线加速度激励。启动时如果一直静止不动或者只做匀速平移,IMU的偏置就不容易被观测出来。实操中我会建议刚启动后做几个缓慢的“8字”或俯仰、横滚动作,帮助滤波器完成初始收敛。
3. 实操准备:环境搭建与参数配置
3.1 硬件安装与IMU外参标定
Mid-360的水平视场是360°,垂直视场约为-7°到52°,但它在正上方存在一个盲区,安装时要注意不要遮挡住有效视场。我见过不少人把雷达装在高处朝下扫地面,结果把上方大半个视场全浪费了。比较合理的装法是让雷达尽量保持水平,或者稍微倾斜几度,确保能看到前后左右和地面。
Mid-360内置了一颗BMI088六轴IMU。如果你直接买的是带IMU版本,理论上可以用出厂外参启动,但我实测下来,不同批次的设备会有些差异,尤其是安装应力可能让IMU相对雷达发生微小偏移。追求毫米级建图精度的话,建议用lidar_imu_calib这类工具重新标定外参,流程大概是录制一段充分激励的rosbag,然后跑一遍标定程序,输出旋转和平移矩阵。
标定过程中有一点容易被忽略:录制bag时要让雷达和IMU都有足够的数据重叠时间,并且运动要包含旋转、加速、减速,让各个轴都被充分激励。如果只是拿着设备慢慢走一圈,标定结果可能很差。另外,IMU的采样率设置要在200Hz左右,太低会降低标定结果的可信度。
3.2 驱动安装与FAST-LIO2源码编译
Mid-360配套的驱动是livox_ros_driver2,它同时支持ROS1和ROS2。这里我以ROS1 Noetic环境为例,如果你用的是Ubuntu 20.04,流程如下。
先安装依赖:
sudo apt-get install ros-noetic-catkin python3-catkin-tools mkdir -p ~/fastlio_ws/src cd ~/fastlio_ws/src git clone https://github.com/Livox-SDK/livox_ros_driver2.git编译驱动时需要注意,livox_ros_driver2默认可能只编译ROS1或ROS2版本,需要根据你的环境指定。我用的方式是先编译驱动,再编译FAST-LIO2源码。FAST-LIO2的仓库在HKUST-Aerial-Robotics/Fast-LIO2,拉到src目录下后一起编译:
cd ~/fastlio_ws catkin_make source devel/setup.bash如果你用的是Ubuntu 18.04 + Melodic,或者Ubuntu 22.04 + ROS2,编译前建议先看一下仓库的README,确认依赖版本。我自己在Melodic和Noetic上都编过,基本没啥大坑,唯一容易出问题的是PCL和Eigen版本,如果系统里同时装了OpenCV的多版本,偶尔会有冲突,需要把相关库路径理清楚。
3.3 launch文件关键参数解读
FAST-LIO2的launch文件一般在config目录下,里面最关键的是两个部分:雷达topic配置和滤波器参数配置。
先看launch文件里Mid-360相关的字段:
<arg name="rviz" default="true" /> <arg name="pointcloud_topic" default="/livox/lidar" /> <arg name="imu_topic" default="/livox/imu" />这两个topic分别对应livox_ros_driver2发布的点云话题和IMU话题。如果你的设备发布的是自定义话题名,需要改成实际值。然后到yaml配置文件里看几个关键参数:
common.lid_topic: 点云话题,要与launch一致common.imu_topic: IMU话题preprocess.filter_size_surf: 每帧点云的降采样体素大小,单位米,常用0.3到0.5preprocess.filter_size_map: 全局地图的降采样分辨率,同样常用0.3到0.5preprocess.blind: 近距离盲区过滤,Mid-360建议设为0.3米左右preprocess.scan_line: 扫描线数量,Mid-360可配置,一般保持默认preprocess.time_scale: 时间戳缩放,一般不需要动preprocess.timestamp_unit: 时间戳单位,通常为0(秒)publish.pcd_save_enable: 是否保存点云地图publish.pcd_save_freq: 自动保存地图的频率,-1表示不自动保存ikdtree.estd_opts: 增量地图维护相关参数,一般不用改fov,n_ scans: 雷达视场角和扫描线相关参数
还有一个很关键的外参配置,在yaml文件的calib部分:
calib: extrinsic_est_enable: true extrinsic_rot: [1, 0, 0, 0, 1, 0, 0, 0, 1] # 3x3旋转矩阵展平 extrinsic_trans: [0, 0, 0] # 平移向量这里的extrinsic_est_enable表示是否在运行中继续在线优化外参。我的经验是:如果已经做过离线标定,建议把这个设为false,让滤波器把精力放在位姿估计上;如果外参完全不确定,可以先设为true跑一段,等位姿收敛后再改回false重新跑一遍正式建图。
4. 数据采集与地图生成全流程
4.1 数据采集规范与实操要点
在正式建图前,数据采集的质量直接决定最终地图质量。很多朋友一上来就手持设备来回跑,结果地图里出现大量重影和偏移,然后就怀疑算法不行。其实大多数时候是数据采集没做好。
我的数据采集规范是这几条:
- 启动后先静止3到5秒,让IMU完成初始对准。
- 然后缓慢做几个“8字”或俯仰动作,帮助滤波器估计陀螺仪和加速度计偏置。
- 正式行走时保持匀速、缓慢,避免急停急转。Mid-360帧率通常在10Hz左右,太快运动会造成帧间点云畸变,虽然IMU可以补偿一部分,但大剧烈运动仍然会降低配准质量。
- 遇到长走廊、空旷场地时,尽量沿中间行走,不要贴墙太近,也不要长时间直视空旷区域。
- 尽量走回环路线,让终点和起点重合。虽然FAST-LIO2没有闭环检测,但回环可以减少累计漂移对整体地图的影响。
还有一点是关于激光照射表面的:Mid-360测距在黑色物体、玻璃、镜面和强反光表面都会有问题。黑色物体吸收激光容易丢点,玻璃会穿透或反射,这些区域在地图里会形成空洞或错误点。尽量在数据采集前清理路径上的玻璃和镜面障碍,不现实的话,就在后处理里把这些区域裁剪掉。
4.2 从运行建图到保存pcd地图
环境配置没问题后,启动建图只需要两步。
先启动雷达驱动:
roslaunch livox_ros_driver2 msg_Mid360.launch再启动FAST-LIO2:
roslaunch fast_lio mapping_mid360.launch如果一切正常,rviz里会实时显示当前点云和不断累积的全局地图。此时你能看到绿色或彩色的点云随着设备移动不断延伸,同时界面上会打印当前帧的配准耗时、IMU状态等信息。
FAST-LIO2默认并不会自动把地图存下来。要注意看launch文件里publish部分的参数。如果需要建图结束后手动保存,推荐这样操作:
rosservice call /pcl_save_path "save_path: '/your/path/map.pcd'" rosservice call /pcl_save_map或者如果想要结束里程计进程,Ctrl+C之前让它自动保存,就把launch里的pcd_save_enable设为true,pcd_save_freq设为0或1,这样建图过程中或结束时会在当前目录生成pcd文件。
我第一次跑的时候就是因为没设置保存参数,整个地图只活在rviz里,一关进程全没了,后来翻源码才找到这两个service。这个细节非常容易踩坑。
4.3 点云后处理与多段地图拼接
FAST-LIO2输出的pcd文件一般比较“原始”,点云密度不均、有少量离群点、还可能包含动态物体的残留。所以我通常会做几步后处理。
第一步是降采样。用PCL工具、CloudCompare或者Python的open3d都可以。我习惯用CloudCompare,因为可视化方便。对地图做体素降采样,把点间距统一到0.05米左右,既保留细节又控制文件大小。
第二步是去离群点。用统计滤波(SOR)把稀疏的孤立点滤掉,参数一般设置近邻点数为20左右,标准差倍数2.0到3.0。这一步对后续点云配准和网格化都很有帮助。
第三步是多段地图拼接。如果你把一个大场景分几段建图,最后再用ICP或NDT配准拼接。FAST-LIO2的全局地图本身是基于全局坐标系,理论上多段地图直接拼接就行,但因为累计漂移,实际接缝处会有偏差。我一般用手动选点粗配准,再用ICP精配准。CloudCompare里这两个操作都有现成功能。
这里补充一个实用技巧:如果分多段建图,每段建图开始时最好从同一个起点出发,或者保证相邻两段有足够的重叠区域,这样可以大幅降低后续拼接难度。
5. 常见问题与排查技巧实录
5.1 建图飘移与地图分层
建图飘移是FAST-LIO2实战中最常遇到的问题。表现是地图越到后面越歪,或者同一面墙上出现两个平行面,也就是所谓的地图分层。
原因主要有四类。
第一类是外参不准确。如果你用的是Mid-360内置IMU但没有做额外标定,那么IMU与雷达之间的旋转和平移误差会直接累积到整体轨迹里。解决办法就是按前面说的重新标定,然后把extrinsic_est_enable设为false后重跑。
第二类是初始位姿未收敛。如果启动后立刻开始走动,滤波器还没来得及估计出准确的IMU偏置,轨迹会从一开始就带着偏差。解决办法是启动后静止几秒,再做一些激励动作。
第三类是场景退化。长直走廊、空旷场地会让雷达在前进方向或竖直方向缺乏有效约束,此时地层分层尤其明显。解决办法是控制运动速度,避免在退化环境中长时间直线行走,尽量增加侧向或上下方向的结构特征。
第四类是里程计累计漂移。FAST-LIO2本身没有回环检测,长时间运行必然会有缓慢漂移。如果建图范围很大,我更建议分段建图再拼接,或者使用带回环的改进版本,比如FAST-LIO-SC或FAST-LIO2结合SC-PGO。
我实际踩过最深的一个坑是:手持设备快速旋转时出现明显分层,停下来检查发现是IMU数据时间戳和点云时间戳存在偏差,导致测量值被错误关联。如果你也遇到类似问题,可以检查驱动和算法里的时间戳单位是否匹配,必要时做时间同步。
5.2 rviz不显示点云与TF异常
这是新手最容易卡住的问题。rviz里看不到点云,通常先检查三个地方。
先看话题有没有发布:
rostopic list rostopic hz /livox/lidar rostopic hz /livox/imu如果话题没有数据,问题在驱动端,检查雷达是否正常供电、网线或USB是否连接。Mid-360默认使用以太网口,需要配置好静态IP或DHCP。
如果话题有数据,但是rviz里看不到,再去查frame_id。FAST-LIO2发布的地点和点云会带有坐标系,rviz中必须把Global Fixed Frame设置成camera_init或者代码里的主坐标系,否则点云会出现在错误位置甚至不显示。
第三个检查点是TF树。运行:
rosrun rqt_tf_tree rqt_tf_tree确认所有坐标系是否连续。如果缺少某个TF,rviz里会出现红色警告,这时候要去看launch文件里有没有正确发布livox_frame到base_link或者camera_init的变换。
还有个小问题,rviz里点云显示太稀疏,可能与rviz的PointSize或点位密度设置有关,调大PointSize到2或3即可。
5.3 点云质量差与地图过密怎么办
点云质量差的表现多种多样:点云有残影、表面粗糙、出现不规则点簇。
残影通常来自运动物体。建图时如果有人走过,或者有车辆移动,这些动态物体就会被扫入地图,形成拖影。处理方式是在后处理阶段手动裁剪,或者在采集时尽量清场。
表面粗糙可能是因为降采样体素设得太小,导致全局地图包含过多噪声点。适当增大filter_size_surf和filter_size_map到0.5米左右,可以让地图更平滑,但会损失细节。平衡值需要根据实际场景调试。
地图过密或者点云文件过大,主要解决办法是体素降采样。我常用CloudCompare的Subsample功能,把点间距设为0.05米到0.1米,文件可以从几百MB降到几十MB,同时精度损失很小。
另外,PCL库里也封装好了现成工具:
pcl_voxel_grid input.pcd output.pcd -leaf 0.05,0.05,0.05这个命令在降采样时很好用,后面再配合pcl_outlier_removal做去噪,整个点云后处理流程基本就闭环了。
5.4 多传感器时间同步与CPU负载问题
如果你在建图的同时还要采集其他传感器数据,比如相机或者RTK,时间同步就变得很重要。FAST-LIO2默认假设雷达和IMU的话题时间戳是同步的,如果两者延迟较大,位姿估计会周期性跳动。最简单的检查方法是用rostopic echo查看两个话题最新消息的时间戳差,一般要求偏差在几毫秒以内。偏差大的话,可以用message_filters做近似时间同步,或者在驱动层统一时间源。
CPU负载高是另一个常见问题。如果建图时CPU占用接近100%,可以先调大降采样体素,减小参与配准的点数;再检查是不是地图维护得太密,造成ikd-tree搜索开销过大。如果硬件性能有限,也可以降低发布频率或减小地图保存频率。
我在实际工程中还遇到过一个问题:跑了很久之后程序突然崩溃,查看日志发现是ikd-tree内存增长导致内存溢出。这个通常是因为建图范围太大,点云数量达到数千万级别。解决办法是提前做好规划,大场景分段建图,或者在代码里增加地图裁剪逻辑,只保留当前位置附近一定范围内的点。
6. 经验总结:这套流程还能往哪个方向扩展
写到最后,我想分享一点个人体会。Mid-360加FAST-LIO2这套组合的魅力在于,它把此前需要昂贵测绘设备和专业SLAM工程师才能完成的建图任务,压缩到了一个小小的手持或机载设备里,并且代码全部开源,算法细节可解释、可修改、可复现。
从实际工程角度看,这套流程跑通只是起点。后续你可以在此基础上扩展的内容很多:比如给FAST-LIO2加上回环检测模块,解决大规模场景的累积漂移问题;或者把输出地图无缝导入到move_base导航框架里,实现机器人的自主导航;还可以把生成的pcd地图转换成八叉树地图或栅格地图,适配不同的下游任务。
我最后的建议是:不要只满足于把demo跑起来,一定要亲手改动几次参数,观察地图质量的变化;亲手录制几段不同场景的bag,看看算法在退化环境里的表现;再把地图导出到CloudCompare里做几次后处理,体会从“点云”到“可用地图”的全过程。只有把每个环节都亲手摸一遍,你才算真正掌握了这套工具链。