
MID-360做FAST-LIO建图标定这关谁都绕不过去。网上教程很多但大部分都停在工具能跑通的层面真正到自己的设备上从环境配置到最终效果中间的坑一个接一个。这篇文章我把从零开始标定Mid-360和IMU、再到集成FAST-LIO的完整过程写清楚包括我实际踩过的坑和最终验证过的参数希望能帮你少折腾几个晚上。1. 先搞清楚为什么Mid-360必须做标定而且不能只做一次Mid-360作为Livox系列里少见的一款非重复扫描固态激光雷达视角能达到360度水平、59度垂直这个视场角让它在室内外建图、无人机和机器人导航里都很受欢迎。但正因为它的扫描方式是非重复式的点云和传统机械式雷达差异很大对位姿估计的精度要求更高——雷达和IMU之间的外参位置和姿态偏移如果不对FAST-LIO跑起来点云就是花的重影严重甚至直接发散。很多人会问出厂不是有外参吗 确实有官方的出厂标定给你一个初始值但这里有两个问题你安装Mid-360的支架、3D打印件、铝合金型材不可能保证和厂家标定时的安装姿态完全一致。哪怕偏了1度在10米外就是17厘米的误差建图完全没法看。IMU本身有零偏bias不同温度下、不同供电状态下零偏都会漂移。这是你IMU自身的问题和雷达无关但如果你不把IMU的零偏一起估计进去FAST-LIO的初始化就会一直抖动。所以这里的标定其实是两个层面的工作一是雷达和IMU之间的外参标定二是IMU内参零偏、尺度、安装误差的估计。成熟的做法是用标定工具把这两件事一起解出来然后把外参写进FAST-LIO的配置里。这里也顺带说一句网上经常有人问能不能跳过标定直接用官方参数对Mid-360这种固态雷达来说我不建议跳过。我用官方默认参数试过在室内小场景勉强能看一到走廊、楼道、空旷场地点云就开始分层越跑越歪。标定一次大概花半天时间收益是后面建图省心几个月这笔账很划算。注意如果你的雷达和IMU是刚性固定在一个板子上的标定一次可以管很长时间。但如果你的设备经常拆装、或者用了快拆结构每拆装一次就要重新标定别偷懒。2. 标定工具选型为什么我选择了li_calib而不是其他方案目前在Mid-360和IMU标定这个方向上常见的选择有三类第一类是港科大团队早期开源的livox_camera_lidar_calibration主要做的是相机和雷达联合标定也能做雷达和IMU但流程比较繁琐而且要设计的标定板非常讲究操作起来有点考验耐心。第二类是直接改FAST-LIO源码在跑建图的同时用后端优化去估计外参。这个方法的好处是不用单独做标定FAST-LIO会在线估计但坏处是一旦初始外参偏差太大优化很容易陷入局部最优而且它在线估计的外参没有地面真值可以参考你很难判断估计结果到底准不准。第三类是我最终采用的方案R3Live团队开源的li_calib工程GitHub上直接搜li_calib。它支持Livox系列雷达能够联合估计激光雷达到IMU的外参、IMU零偏、时间同步偏移time offset用滑动窗口做批量优化精度和鲁棒性都比较好。我用li_calib跑了三轮标定得到的外参转成FAST-LIO格式之后效果稳定。后面会详细说怎么转换。选li_calib还有两个很实际的理由它有完善的ROS封装launch文件直接起不需要改太多代码其次它对Mid-360的数据格式兼容性很好点云话题和IMU话题直接订阅就能跑省了很多格式适配的时间。2.1 标定前准备硬件连接、驱动安装、ROS环境先确认硬件清单和连接方式我手上的设备是这样一套Livox Mid-360 激光雷达接Type-C转USB到工控机一个IMU模块我这里用的是集成在NUC里的BMI088或者你外接的IMU也可以只要ROS话题里能发sensor_msgs/Imu消息就行一台装了Ubuntu 20.04的工控机ROS Noetic驱动安装这里有一个容易踩坑的点Livox的驱动分为livox_ros_driver2和旧版的livox_ros_driverMid-360必须用livox_ros_driver2。这个驱动可以通过Livox SDK 2.x编译ROS 1和ROS 2都支持但不要装错了和SDK 1.x绑定的旧版驱动。安装命令其实很简单# 下载livox_ros_driver2 git clone https://github.com/Livox-SDK/livox_ros_driver2.git cd livox_ros_driver2 # 如果你是ROS 1 Noetic ./build.sh ROS1装好之后建议直接用驱动里自带的launch文件测试看看能不能正常出点云source devel/setup.bash roslaunch livox_ros_driver2 rviz MID360.launch关于IMU如果你用的是Realsense或者其他自带IMU的设备需要先确认你的IMU话题的数据频率和数据单位。FAST-LIO和li_calib对IMU的数据格式要求比较严格角速度单位是rad/s加速度单位是m/s²Realsense里默认给的可能是带重力影响的原始读数这个在配置里一般不用额外处理但一定要确认消息里的协方差不是全零否则某些节点会拒绝接收。2.2 采集数据决定标定成败的隐藏细节很多人标定效果差问题不是工具不行而是采集数据的时候太随意。li_calib的标定结果好坏跟你采集的数据质量强相关。我的经验是标定用的数据要分两段采集一段留给初始化一段留给优化。具体操作准备一个纹理尽量丰富、但不要有大面积反光物体的环境。走廊交叉口、有柱子的大厅、堆了杂物的仓库都行。空旷的停车场就算了点云特征太少退化方向多优化容易飘。采集时让设备做充分激励运动不要只平移也不要只旋转要六自由度都动到。重点是多做快速旋转和俯仰动作让IMU的角速度和线速度有明显的激励这样才能把外参和零偏区分开。每次动作幅度大一点、速度快一点但别快到让点云产生运动畸变。Mid-360的非重复扫描在快速运动时点云畸变还是很明显的。采集时长建议2~3分钟中间不能长时间静止不动否则IMU零偏和重力方向会耦合解出来全是错的。采集数据可以用rosbag直接录rosbag record /livox/lidar /livox/imu -O calib_data.bag这里要注意Mid-360自带的IMU话题/livox/imu频率是200Hzlaser的点云频率是10Hz左右这个组合是正常的。但如果你是外接IMU需要确认IMU发布频率别低于100Hz否则标定时的时间同步网络会不太稳。另外如果你的IMU话题里还带磁力计比如九轴IMUli_calib里面一般只读加速度和角速度注意不要混了数据源。3. li_calib的配置与运行从launch文件到核心参数全解析li_calib的使用流程大体分三步改配置文件、起launch、看结果。先说拉代码和编译。建议在ROS工作空间里直接建一个子目录cd ~/catkin_ws/src git clone https://github.com/APRIL-ZJU/li_calib.git cd .. catkin_make编译过程中大概率会遇到一个问题缺少livox_ros_driver的头文件。这可能是因为你装的是livox_ros_driver2而li_calib的CMakeLists里面默认找的是旧版接口。解决办法有两个把li_calib里CMakeLists中find_package的livox_ros_driver改成livox_ros_driver2或者把包名/include路径手动加到include_directories里同时把MID360.yaml和livox_ros_driver2的消息类型适配一下。我实际操作时是直接改CMakeLists把依赖指向了livox_ros_driver2然后重新catkin_make一次通过。3.1 配置文件的几个关键参数li_calib的配置文件在config/目录下需要新建一个你自己的yaml。核心参数有几个common: bag_path: /path/to/your/calib_data.bag topic_lidar: /livox/lidar topic_imu: /livox/imu imu_frequency: 200.0 lidar_type: mid360 # 可选livox, velodyne, ouster等这里lidar_type是重中之重Mid-360的扫描模式和机械式雷达不一样你必须明确告诉它这是mid360否则后续的角点提取、特征匹配逻辑就不对。再往下是雷达和IMU之间初值的设置# 初始外参从livox_ros_driver2的launch里可以找到出厂外参 ext_R: - [0.9999, 0.0, 0.0174] - [0.0, 1.0, 0.0] - [-0.0174, 0.0, 0.9999] ext_t: - [0.0, 0.0, -0.04]初值不用太精确但方向不能错。意思是说你起码要知道IMU大概装在雷达的哪个方位距离大概多少厘米。如果初值给反了比如把IMU放在了雷达前面实际在后面非线性优化会很难收敛。时序偏移time offset这里也给一个初始值比如0.0后面网络会自己优化。3.2 标定流程的三个阶段数据读取、初始化、优化li_calib的launch一键启动后它会经历三个阶段第一阶段是数据读取和预处理。它从rosbag里读出雷达点云和IMU数据这里的耗时取决于你录了多久2分钟的数据大概要处理一会儿。期间你会看到它输出一段一段的帧信息如果中间有某段IMU数据缺失或者时间戳乱跳它会报警告建议重新采集。第二阶段是初始化。它主要是依赖IMU的旋转约束和重力方向来快速给出外参的粗略初始解。这一步输出之前程序会打印出估算的外参旋转矩阵和平移向量。第三阶段是滑动窗口非线性优化。它会用多帧雷达点云、IMU预积分、时序偏移一起做联合优化输出最终的外参、IMU零偏、时间偏移估计。这个过程一般在几百次迭代之后收敛。跑完之后在程序的输出目录里一般在output/下会生成的结果文件。重点看几个指标外参旋转矩阵**近似了**平移向量单位米时间偏移加速度计和陀螺仪的零偏如果优化过程中cost下降得不够或者最后残差仍然很大说明你采集的数据质量有问题或者初值给得太离谱。4. 踩坑实录我从环境配置到标定收敛遇到的问题排查链路这一节我想完整梳理一遍我在这个过程中实际遇到的那些让人抓狂的问题按出现顺序写方便你照着排查。4.1 问题一catkin_make编译报错找不到livox_ros_driver头文件这是很多人第一道坎。现象是编译到最后报fatal error: livox_ros_driver/CustomMsg.h: No such file or directory。根因是li_calib写的时候默认用的是livox_ros_driver旧版的消息类型而你装的是livox_ros_driver2两者虽然话题名字都一样但消息类型不同旧版是livox_ros_driver/CustomMsg新版是livox_ros_driver2/CustomMsg。我的排查和解决过程先确认我装的驱动仓库是livox_ros_driver2。打开li_calib的CMakeLists.txt找到对livox_ros_driver的find_package和include_directories改成livox_ros_driver2。同时看一下代码里有没有显式包含livox_ros_driver/CustomMsg.h的源文件把这些include也改成livox_ros_driver2/CustomMsg.h。如果有用到ROS消息类型定义比如在launch里remap保持消息类型一致。改完重新编译就通过了。这个问题本质上是版本适配问题本身没有技术难度但第一次搞容易卡住。4.2 问题二程序一启动就段错误第二次跑的时候launch文件能起来但一读取到rosbag里的点云数据就段错误退出。段错误的原因有很多我不能说一定是哪个但从我复现的情况来看最可能是rosbag里点云的消息类型和li_calib期望的不一致。当时我用的是livox_ros_driver2的launch文件录的包点云类型是livox_ros_driver2/CustomMsg但li_calib里处理的可能是老的消息格式。解决方案在li_calib的launch里增加一个remap把/livox/lidar重映射为它期望的话题名然后在代码里确认类型匹配。如果实在无法匹配还有一个办法是写一个转换节点把livox_ros_driver2/CustomMsg转换成sensor_msgs/PointCloud2再喂给li_calib。我最后是直接改了li_calib源码里的消息头让它可以接收PointCloud2这样就不依赖具体是哪个驱动版本了。改完之后段错误消失。4.3 问题三标定结果外参和初值没什么变化但残差很大这个情况很怪程序跑完了外参和初值几乎一样但cost居高不下。一看输出的点云地图明显是错位的。我当时的排查思路先确认IMU频率配置是否正确。li_calib的配置文件里有个imu_frequency默认是200如果你的IMU实际是100Hz但配了200时间戳对齐就会出错优化自然无法收敛。我当时外接IMU是200Hz但录数据的时候软件里实际发布频率没达到200导致时间对齐错乱。后来通过rostopic hz查看实际频率确认是200再重新跑问题解决。再看时间偏移初值如果IMU和雷达之间的时间同步本身有偏差初始化时的旋转约束会对不上。最后检查IMU的数据单位有些IMU输出的角速度是deg/s而不是rad/s这会导致优化结果完全错乱。排到最后我发现频率配置有误改过来重新标定效果立刻改善。这里也提醒一下采集数据时最好用rostopic hz确认一下实际发布频率不要只看参数文件里写的数字。4.4 问题四室内标定效果好但室外建图仍然有偏差这是我一开始比较困惑的。室内标定跑出来效果很好残差也很小但拿到室外空旷区域跑FAST-LIO点云还是出现轻微的错层。后来排查下来问题不是外参不准确而是IMU的零偏在室外环境因为温度变化发生了漂移。FAST-LIO在建图时虽然会在线估计IMU零偏但如果你给它的初始零偏偏差太大开始阶段还是会出现不稳定。解决方法在fast-lio的配置文件里把li_calib估计出来的加速度计零偏和陀螺仪零偏填进去作为初始值。这样在建图开始阶段状态估计器就有更好的起点后面的优化也不容易被带偏。这一步非常关键很多人只把外参转过去了却把零偏落下了导致标定效果打折扣。5. 从标定结果到FAST-LIO外参格式转换与配置修改标定完成只是第一步把结果正确集成到FAST-LIO里才是真正考验细心的环节。FAST-LIO的配置文件里要改三个东西外参雷达到IMU的旋转和平移、IMU零偏初始值、以及雷达的话题类型。5.1 外参格式的转换逻辑li_calib输出的是雷达到IMU的外参T_lidar_imu也就是把点从雷达坐标系变换到IMU坐标系的变换矩阵。而FAST-LIO的配置里通常给的也是lidar到IMU的外参格式类似common: lid_topic: /livox/lidar imu_topic: /livox/imu extrinsic_T: [0.0, 0.0, -0.04] extrinsic_R: [1, 0, 0, 0, 1, 0, 0, 0, 1]这里要特别注意FAST-LIO 2配置里的extrinsic_R是旋转矩阵按行优先展开的列表和li_calib输出的3x3矩阵形式不同。直接把矩阵写进去很容易出错。我习惯先写一个小脚本把li_calib输出的旋转矩阵和平移向量解析出来然后按FAST-LIO要求的格式打印import numpy as np # 从li_calib输出拷贝过来的矩阵 R np.array([[...]]) # 3x3 t np.array([...]) # 3x1 R_list R.flatten().tolist() t_list t.flatten().tolist() print(extrinsic_R:, R_list) print(extrinsic_T:, t_list)这样转出来之后直接粘贴到FAST-LIO的yaml里就好。5.2 修改FAST-LIO的配置文件以FAST-LIO2为例配置文件一般在config/目录下比如mid360.yamlcommon: lid_topic: /livox/lidar imu_topic: /livox/imu time_sync_en: true extrinsic_T: [0.0, 0.0, -0.04] extrinsic_R: [1, 0, 0, 0, 1, 0, 0, 0, 1]注意time_sync_en这个参数如果你的数据里雷达和IMU的时间戳是不同步的建议打开它是FAST-LIO内部做时间同步的开关。如果标定出的时间偏移比较大这会明显提升效果。另外FAST-LIO的预处理模块需要根据你的雷达类型做配置。Mid-360在FAST-LIO里通常直接用livox_ros_driver2的点云话题但它内部的特征提取只对部分点云生效所以如果建图时出现点云稀疏、或者特征点提取过少可以适当调整point_filter_num每隔几个点取一个参与计算Mid-360的默认值是2到3这个值太大点云太稀太小计算量大具体看你的CPU。5.3 首次启动FAST-LIO的测试方法和判定标准配置改好之后不要直接在真实场景上跑先用之前录的rosbag回放一遍看看SLAM能不能正常初始化、点云能否收敛。判断标准有两条初始化阶段启动后大概几秒钟内程序会打印IMU初始化完成此时地平面应该逐渐清晰不至于散架。点云对齐情况跑一段走廊或房间回看RVIZ里的点云地图如果边缘锐利、没有重影说明外参基本准确如果点云边缘模糊、不同帧之间错位说明外参还有问题需要重新标定或检查转换格式。我实测下来如果外参中的旋转误差小于0.5度平移误差小于1厘米FAST-LIO建图效果就很理想了如果误差再大一点建图就会偶尔出现漂移累积。6. 建图实测与参数调优点位精度和稳定性验证标定集成完成后真正验证效果还是要到真实场景里建图。我在室内走廊、室外园区分别跑了FAST-LIO和标定前的效果对比非常明显。6.1 室内场景走廊和房间建图室内环境我选了一段大概30米长的走廊两侧有房间门、灭火器箱、墙面上的疏散指示牌纹理比较丰富。手持设备慢慢走过去边走边轻微左右摆动模拟实际使用时的运动模式。标定前走完一圈回来看点云地图走廊墙壁明显有重影靠门的位置还会出现点云拉丝这是外参不准IMU零偏漂移的典型表现。标定后同样的路线走一遍点云地图的墙线很清晰房间门边缘完整10米远的墙面误差控制在几个厘米以内。配合FAST-LIO自带的回环检测功能如果接了回环的话整体轨迹闭合效果不错。6.2 室外场景空旷位置的退化问题室外场景比室内难很多尤其是在空旷的场地点云特征少SLAM容易在平移方向上退化。我发现即使标定准确FAST-LIO在空地直行时还是会有缓慢漂移。分析下来有两个原因一是Mid-360的非重复扫描模式在远距离上的点数密度下降导致特征提取量不足二是IMU在长距离匀速运动时的零偏变化会逐渐累积位置误差。解决思路有三个层面把FAST-LIO里的point_filter_num适当调小比如从3调到2增加参与匹配的点数在建图时尽量做非匀速运动避免长时间匀速直行给IMU更多的加速度激励如果条件允许加上一个UWB或者GPS的观测做位置约束。我实测下来即使不做额外传感器融合只要标定准确并适当调参Mid-360加FAST-LIO在室外小范围一个足球场大小建图闭环误差也能控制在0.5米以内这个结果对多数巡检和测绘需求来说够用了。6.3 参数调优的几个经验值这里分享几个我在不同场景下试过比较稳的参数组合配置在FAST-LIO的yaml里参数室内小场景室外大场景备注point_filter_num22~33可以降CPU但特征少时慎用max_iteration23~4室外退化多多迭代几次更稳time_sync_entruetrue时间戳不一致时必开extrinsic_T标定所得标定所得每次换装重新标定lidar_type按驱动配置按驱动配置Mid-360要确认用mid360类型我个人的习惯是每次启动前先跑一小段看RVIZ里的点云是否稳定再开始正式建图一旦发现点云开始发飘立刻停下来检查外参和配置不要硬扛着跑完再处理浪费时间。7. 往后扩展标定结果如何在其他SLAM系统里复用标定得到的外参不只服务于FAST-LIO别的SLAM系统也都能用只是配置格式略有不同。这里顺带说一下怎么迁移。LIO-SAM它的外参配置在params.yaml里需要的是extrinsicRot9个元素和extrinsicTrans3个元素单位是米。把li_calib的结果按同样的矩阵展开方式填进去就行。LIO-SAM对IMU零偏的配置是通过imuAccNoise、imuGyrNoise这些噪声参数间接实现的不直接给零偏初始值但外参必须准确。LIO-Livox这是港大开源的专门针对Livox雷达的LIO方法配置外参的位置在config/下的yaml里和FAST-LIO格式比较接近直接把FAST-LIO里的extrinsic_R和extrinsic_T粘过去基本能用。R3LIVE同样基于livox雷达它的外参配置格式更复杂一些除了雷达到IMU的外参还要配置雷达坐标系和相机坐标系的关系。如果你只做雷达和IMU标定把IMU相关的外参填进去相机相关的部分可以先不动。RTK-GPS组合如果后面你打算做地图和GPS融合还需要知道IMU到GPS天线相位中心的外参这个不能靠雷达标定获得需要单独量测或者用专业工具标定别搞混了。外参迁移的时候一定要统一坐标系的方向约定。比如FAST-LIO约定extrinsic_T是从lidar坐标系到IMU坐标系的平移而有些系统约定的是IMU到lidar的变换差一个负号。这一点不确认好直接复制过去就会出问题。每次迁移完我建议都在RVIZ里做一次合成点云叠加检查把同一帧点云用外参变换到IMU坐标系下和IMU坐标系的坐标轴对齐确认点云没有翻转、没有明显偏移再做整个系统联调。写在最后的一点个人体会标定这件事本质上是在做传感器之间的时间-空间-运动联合配准。很多人觉得它就是一个跑工具、改配置的体力活但实际上它对数据的采集质量、初值的设置合理性、参数转换的严谨性都有要求。我在这个过程里最大的体会是工具本身不复杂复杂的是你如何判断结果是对的。所以我的建议是不要只盯着残差值看多花时间在RVIZ里观察点云对齐情况多在不同场景下做验证。只有当你多次、多场景都能稳定复现同一个外参结果时你才真正有理由相信这个标定是可靠的。这个项目做到后面你得到的不仅仅是一组外参数字而是一套完整的数据质量检查习惯和调试方法论。这套东西在之后做相机、IMU、雷达多传感器融合时会一直用得上。