
1. 这个项目到底在干什么先把外参标定的价值和难度讲透如果你手里正好有一台Livox Avia或者是刚入坑多传感器融合SLAM的新手那你大概率迟早会遇到“激光雷达和IMU外参没标好”这个问题。前面折腾了半天建图漂移、定位发散排除了算法参数问题之后最后发现罪魁祸首居然是雷达和IMU之间的位姿关系压根就不对。这件事我踩过太多次所以看到lidar_imu_init这个工具的时候我第一时间就把它纳入自己的标准流程了。lidar_imu_init是HKUST Aerial Robotics Group开源的一套雷达惯性联合初始化工具它干的事非常聚焦在没有任何外部标定板、也不需要手工量测的前提下通过一段运动激励估算出Livox Avia这类固态激光雷达与IMU之间的外参包括旋转矩阵和平移向量同时还能给出比较可靠的时间偏移同步。放在过去我们要么用lidar_align跑几个小时要么用那些依赖标定间的工具折腾一下午还不一定收敛。而lidar_imu_init的思路和效果在社区里口碑相当稳定。这篇东西适合谁看如果你已经在跑FAST-LIO、LIO-SAM、Point-LIO这类雷达惯性系统但发现自己每次换设备、重装传感器都要重新标定一次或者你刚把Avia固定在载具上下一步就要做多传感器融合那么这里的内容就是奔着你去的。我会把从环境准备、数据采集、参数配置到最终验证的全流程拆开讲把那些文档里没写清楚的坑都标出来。大家别小看这一步外参精度直接决定你后面整个系统的上限。旋转外参差个一两度建图到远处就会糊成一片平移外参偏差几厘米跑了长距离之后地图分层、回环错位都是家常便饭。而lidar_imu_init这个工具可以帮你把这个误差压到很小的范围而且整个流程跑通之后下次再标就是十几分钟的事。2. 为什么选lidar_imu_init工具对比和方案选型分析2.1 主流标定工具到底差在哪在lidar_imu_init出现之前社区里常用的方案无非是这么几类。一类是lidar_align这个工具确实经典但你必须给它一段包含丰富旋转和位移激励的数据而且它对初始化值非常敏感一个不小心优化就掉进局部极小值。更麻烦的是它没有对Livox雷达做专门适配点云格式处理起来很别扭跑一次标定动辄几个小时实在不够效率。另一类做法是手工标定拿卷尺量位置、用量角器估角度。这种方法在实验桌上做精度还过得去但一旦设备装到车顶、装在机器人腹部激光雷达和IMU往往深藏在结构内部你根本没法直接量。而且手工量出来的角度精度往往止步于几度以内对SLAM这种高精度需求来说远远不够。还有一类是所谓的“联合在线标定”比如在跑FAST-LIO的框架里顺便估计外参。这样做的局限性在于它依赖系统本身已经正常运转如果初始外参错得太离谱系统的初始化阶段就直接崩了根本不会给你在线标定的机会。这就回到lidar_imu_init的优势上来了。它走的是“先离线、后在线”的路线先用离线初始化给出一组可用的外参和相对时间偏移然后你再把它作为初值融合进任何雷达惯性系统。这种做法不仅稳定而且可复现性很强。它的核心原理是利用点云的几何特征与IMU预积分之间的约束关系把外参、重力向量、速度、时间偏移一起放进一个优化问题里去求解。比起那些只优化旋转变量的工具它把“时间同步”也一起解决了这对Avia这类非重复扫描雷达来说帮助非常大。2.2 lidar_imu_init的核心思路为什么适合Livox AviaLivox Avia这个传感器比较特殊。它不是机械式旋转雷达而是固态/半固态的棱镜扫描方案扫描轨迹呈花瓣状点云分布是中心密、边缘稀。市面上那些为Velodyne、Ouster设计的标定工具很多并不理解Avia的扫描模式特征提取时容易把噪声当成有效点标定效果自然差。lidar_imu_init在设计上对Livox的点云特性做过多轮适配它在特征提取和分帧上考虑了花状扫描的分布规律因此用在这个传感器上的效果会比通用工具好很多。另外一个很关键的适配点在于Livox的IMU问题。Avia本身自带一个BMI088 IMU很多人图省事直接用机身内置IMU和雷达做外参标定其实这里面有个隐含假设内置IMU坐标系和雷达坐标系的关系是出厂标定好的。但现实是不同批次的Avia出厂装配存在一致性差异有些机器的内置IMU外参偏差能有1到2度。如果追求更高的精度你应该把自研载具上的主IMU与Avia进行标定而不是默认用机身内置IMU。lidar_imu_init对这两种模式都支持我后面会在数据采集部分具体说怎么切换。简单总结一下我的选型结论如果你手头是Livox系列雷达想尽快获得一套可靠的外参用于FAST-LIO、Point-LIO等系统lidar_imu_init是目前成本最低、收益最直接的选择。它不需要标定板不需要昂贵设备不需要你手动量测唯一需要的就是你按照正确的动作采集一段高质量数据。而采集数据这件事恰恰是很多人最后标定失败的重灾区。3. 环境准备依赖、编译和Livox驱动配置3.1 依赖工具清单与版本避坑先把环境说清楚。lidar_imu_init基于ROS1开发官方推荐在Ubuntu 16.04或18.04下使用我自己目前在Ubuntu 18.04 ROS Melodic环境下跑得非常稳。Ubuntu 20.04 ROS Noetic环境下我也试过编译能过但有些依赖需要手动调整。如果你不是非用Noetic不可我建议老老实实装一个18.04的环境专门用来做标定省去和依赖打架的时间。除了ROS本体之外你还需要下面这些依赖项Ceres Solver必须安装建议1.14.0版本。太老的版本缺少一些接口太新的版本可能因为Eigen版本冲突导致编译报错。Eigen3一般系统会自带注意版本不要低于3.3。Livox ROS Driver官方驱动需要和你手里的Avia固件版本匹配。livox_repub这是一个话题重发工具用于把Livox的点云和IMU数据按时间对齐后重新发布标定过程中的时间同步依赖它。编译顺序上建议先装好Ceres再编译livox_repub最后再编译lidar_imu_init本体。如果你把顺序搞反了CMake在找Ceres的时候经常会报一个莫名其妙的“Could not find a package configuration file”错误我遇到过不止一次。3.2 Livox驱动与点云话题的坑Livox Avia连接电脑之后先不要急着跑lidar_imu_init先把驱动调通确认点云话题正常输出。用Livox官方驱动时你要注意一个点默认的lidar话题名是/livox/lidarIMU话题名是/livox/imu。这两个话题在后面对齐中都要用到。还有个非常容易踩的坑是Livox的通信模式。Avia支持LAN和USB两种连接方式默认是DHCP自动获取IP。如果你用静态IP必须在/lib/livox_lidar_config.json里正确配置雷达的IP地址和子网掩码。很多人在这一步卡住点云话题就是不出数据最后发现是电脑防火墙把UDP包拦了或者IP不在同一网段。我的经验是直接关掉防火墙再试一次能省下半小时排查时间。驱动正常之后打开rviz看一眼前方点云确认雷达没有“晕车”现象。Livox的点云里偶尔会出现一些杂散噪声点尤其是在环境光照变化剧烈的场景这些点在后面标定过程中会被当作特征直接影响优化结果。一个简单的做法是在采集数据时选择纹理丰富的室内环境避免空旷走廊和纯白墙面。3.3 编译lidar_imu_init的完整流程环境准备阶段我习惯按这四步走你们可以直接照抄创建并初始化catkin工作空间。mkdir -p ~/lidar_imu_calib_ws/src cd ~/lidar_imu_calib_ws/src git clone https://github.com/hku-mars/lidar_imu_init.git git clone https://github.com/Livox-SDK/livox_repub.git编译前先装Ceres。Ceres依赖很多我自己用apt安装总是版本不对后来都是直接源码编译。源码编译的时候记得加上Eigen的路径。git clone https://github.com/ceres-solver/ceres-solver.git cd ceres-solver git checkout 1.14.0 mkdir build cd build cmake .. make -j8 sudo make install回到工作空间编译整个工程。cd ~/lidar_imu_calib_ws catkin_make source devel/setup.bash如果你的编译过程中报错“fatal error: livox_lidar/CustomMsg.h: No such file or directory”那是livox_repub没有正确找到自定义消息类型需要先把Livox SDK安装好并且确认livox_repub里的CMakeLists.txt引用的头文件路径正确。编译完打一个基本的功能测试运行下面这个launch确认节点能起来roslaunch lidar_imu_init livox_avia.launch如果能看到类似“Waiting for lidar data...”的提示说明整个环境链路是通的。到这一步环境准备就彻底搞定了。别看这节内容不多我敢说至少三分之一的人最后标定失败不是因为算法不工作而是环境这里就埋了雷。4. 数据采集决定标定成败的隐形环节4.1 采集之前的硬件姿态检查很多人拿到lidar_imu_init之后第一反应是“工具我都装好了直接录个包跑一下不就行了”。结果就是标定结果发散或者给出的外参一眼假。我后面查来查去90%的情况都出在数据采集环节上。这里把数据采集的关键点掰开揉碎讲清楚。先看硬件姿态。lidar_imu_init官方文档里明确要求雷达在采集过程中要绕至少两个正交轴做旋转运动。也就是说你不能只是把设备放在桌上平移也不能只在一个方向上转圈。最好把设备拿在手里做类似“∞字形”的空间运动同时绕滚转、俯仰、偏航三个方向都有明显的角速度变化。这种运动模式能在IMU预积分和点云配准之间形成足够强的可观性约束优化问题的收敛性会大大提升。反过来如果你放在桌面上慢悠悠地平移或者放在云台上只做水平旋转那么雷达坐标系和IMU坐标系之间的旋转外参就几乎不可观算法只能勉强收敛到一组看起来合理、实际偏差很大的结果。采集运动时动作幅度要适中。太大容易把设备甩脱手太小则激励不足。我的经验是让设备的线速度保持在0.5到1.5米每秒之间角速度不要低于每秒30度每个方向的旋转持续3秒以上。整体采集时长控制在60到90秒之间不要录太短太短会引入过多初始化噪声也不要太长长了之后IMU零偏漂移会累积后期优化求解起来很吃力。4.2 使用内置IMU还是外部IMUAvia自带IMU所以很多人采集时直接录/livox/imu话题。但还是那句话如果你最终系统里用的是外部IMU比如载具的主惯导或者自选的工业级IMU那标定时就必须用外部IMU的话题而不是Avia自带的。外部IMU连接方式上我建议如果有条件把外部IMU的坐标轴尽量和Avia的坐标轴大致对齐偏差控制在30度以内。lidar_imu_init的初始化求解器虽然是全局的但如果初始值偏差太大还是有概率收敛到错误的局部解。你可以先粗略手工安装把“大概朝向”确定下来再交给工具做精标定。这一步别偷懒工具能帮你解决的是一两度以内的精标定而不是帮你把装反了的传感器猜出来。如果你只有一个Avia手头实在没有外部IMU那就老老实实标定雷达与内置IMU的外参。但要注意一点内置IMU和雷达的时间同步是通过驱动来维护的驱动版本不同可能带来几毫秒的时间偏移。lidar_imu_init会估算时间偏移但我仍然建议你在录数据之前升级到最新稳定版Livox驱动减少隐藏的固定延迟。4.3 数据录制规范与现场注意事项数据录制的命令其实很简单rosbag record /livox/lidar /livox/imu -O avia_imu_calib.bag如果用的是外部IMU把采集命令改成rosbag record /livox/lidar /your_imu_topic -O avia_external_imu_calib.bag录制过程中我有几个习惯可以分享给你。第一是尽量选一个特征丰富的环境最好能看到走廊转角、桌椅边缘、墙上的管道和消防栓这类有明显线性结构的物体这些特征对雷达点云的帧间配准非常友好。第二是不要站在同一个位置把所有动作做完适当走动一下改变设备相对于周围环境的距离和视角这样能增加点云约束的多样性。第三是动作切换之间不要急停急起让每个动作平滑过渡和拍摄视频时防抖是一个逻辑激变运动会在IMU预积分中引入不可预测的高频噪声。现场还有一个容易被忽略的问题人和周围物体不要离得太近。雷达扫描中如果出现快速运动的人腿和手臂会产生大量不匹配点对对配准的精度影响很大。最好让其他人暂时退出扫描区域或者保证设备运动过程中人和设备保持2米以上的距离。数据录完之后回放之前先检查一下话题时间戳。一个常见的问题是/livox/lidar和/livox/imu的时间戳不同步或者话题频率异常。你可以用rostopic hz /livox/lidar和rostopic hz /livox/imu分别看一眼雷达话题频率应该在10Hz左右IMU话题频率在200Hz附近。如果IMU频率只有100Hz甚至更低多半是驱动配置有问题建议先排查再继续。5. 配置文件与实操流程一步一步跑通标定5.1 config.yaml里的参数怎么看环境通、数据采集完接下来就是实际操作。lidar_imu_init的配置都在config文件夹下的yaml文件里。拿Livox Avia的launch来说它默认加载config/avia.yaml里面主要分为两部分。一部分是话题名称定义另一部分才是核心参数。先把话题名对应好这步比较简单。接下来重点关注下面几个参数point_filter_distance点云预处理时的距离滤波阈值默认值通常设为2.0意思是舍弃距离雷达2米以内的点。这个参数是为了滤除雷达噪声和近距离干扰点但如果你在狭小空间采集设得太大会把有效特征滤掉。我的建议是先从默认值开始跑如果发现收敛结果不佳再尝试调小。intensity_filterLivox点云带有强度信息这个参数可以过滤掉强度过低的点。它本质上是配合环境特征来用的。室内白墙强度低但也不是完全无效不能一刀切。max_iteration优化最大迭代次数。默认值一般在100左右。如果标定结果看起来还有优化空间可以适当增大到200但太大意义不大反而增加耗时。time_offset时间偏移初始值。如果你的bag是同一时间戳体系下录的这里设置为0.0就行。如果摄像头、雷达、IMU用的是不同时钟源建议把初始值设置成一个大致的经验偏移比如10毫秒可以加快收敛。配置文件的修改我建议一次只改一个参数改完跑一遍看看效果不要同时动多个。因为优化问题里参数之间有耦合效应同时改多个你根本不知道是哪一项起了作用、哪一项起了反作用。5.2 启动标定并查看初始结果配置改好之后标定流程分两步。第一步打开launch启动标定节点和可视化窗口第二步回放bag数据。# 终端1 roslaunch lidar_imu_init livox_avia.launch # 终端2 rosbag play avia_imu_calib.bag启动launch之后rviz窗口中会显示当前点云和标定过程的可视化反馈。你需要关心的是左下角的控制台输出那里会实时打印当前优化的残差和时间偏移估计。如果你的bag数据质量不错初始收敛会在前10秒内快速完成。我自己跑的时候通常在bag播放的5秒左右外参旋转和平移的估计值就会趋于稳定之后优化过程只是做一些精调。如果你看到外参数值在整个回放过程中持续剧烈跳动说明初始化没成功数据有问题或者配置不对。结果输出在标定完成后的终端日志里同时工作目录下会生成标定后的yaml文件。这个文件里就是最终的外参结果包括旋转四元数或者旋转矩阵以及平移向量。我习惯把结果输出保存一份命名格式是“日期_传感器配置_external.yaml”方便后面追溯。拿到结果后不要急着直接投入使用先做一个简单的合理性检查。拿平移向量来说你的Avia和IMU如果安装距离在10厘米以内输出的平移量应该大致在这个量级差出个一倍以上基本就有问题。旋转外参也一样如果初始安装大致对齐旋转角度应该在几度到十几度之间突然给你输出一个七八十度的角度基本可以判定为收敛失败。5.3 结果验证用FAST-LIO跑一遍实测标定结果出来之后最靠谱的验证方式是直接把外参配置进FAST-LIO或者Point-LIO系统里跑一段真实数据对比建图质量。如果在长走廊场景下地图不发散、不重影墙角线清晰回环处对齐良好那说明标定结果是可用的。我个人的做法是标定完之后再做一次“交叉验证”拿着同一组外参分别用不同的bag数据跑两次FAST-LIO。如果两次的建图和轨迹误差都在可接受范围内说明这组外参不是过拟合某一组数据的产物。这个习惯帮我揪出过好几组“看似收敛、实则骗人”的标定结果。如果验证过程中发现点云有轻微拖影先不急着重新标定可以试着在FAST-LIO的配置里把外参微调一下。微调的方向主要是旋转量先以0.1度为步长调整再配合平移量的0.01米步长做精细优化。这种方式比重新标定更快但它只能做增量修正如果偏差太大还是老老实实重新采数据。5.4 雷达固定不动的特殊情况怎么处理还有一种场景在无人车和机器人上很常见雷达被刚性固定在底盘上IMU也固定在底盘内部整台车只能在现场运动。如果你没法像手持设备那样做出大幅度的空间旋转动作也不用太担心。你可以把整车开到户外安全区域做几个“8字绕桩”动作同时猛打方向盘制造横摆角速度再穿插几次急加速和急刹车制造纵向加速度。这种运动方式虽然不如手持旋转那么丰富但对于雷达和IMU之间接近于“纯刚体安装”的场景已经足够。实际标定效果也很好我帮朋友标过一辆差速底盘的机器人就是用车轮快速转向和前后俯仰来产生激励最终标出来的外参在后续建图中表现良好。要注意的是车辆或者机器人行驶路面尽量选平整、没有明显颠簸的地方。颠簸路面产生的高频震动会被IMU记录下来给预积分项带来很大的噪声优化效果会打折扣。6. 常见问题与排错实录踩过的坑都给你列全6.1 标定结果发散、外参跳变这是出现频率最高的问题。现象是跑bag的过程中终端打印的外参数值一直不收敛甚至在某一刻突然变成一个很离谱的值。排查思路从数据源头开始先看雷达点云话题有没有明显丢帧再看IMU频率是否正常最后看数据过程中是否出现过剧烈碰撞或者设备脱手。这些情况都会导致优化求解器崩溃。如果数据没问题再检查是不是初始外参给得太离谱特别是旋转外参超过90度的情况建议手动把初始值改到更接近真实的值。数据采集过程中如果出现设备在手中滑动、固定螺丝松动也会导致标定结果发散。机械连接的松动会让雷达和IMU之间的外参在数据录制过程中发生变化这种情况再厉害的算法也救不回来只能重新紧固设备再来一次。6.2 时间偏移估计异常如果你发现优化器给出来的时间偏移是一个毫秒级别的大数比如几十毫秒甚至上百毫秒那要警惕了。正常的雷达和IMU时间偏移应该在10毫秒以内。出现大时间偏移有两种可能。一种是你录数据时确实使用了不同时钟源导致时间戳基准不一致。另一种情况就比较麻烦了可能是Livox驱动输出点云的时间戳本身不稳定驱动内部存在缓冲区机制时间戳跳跃比较严重。解决方法是升级Livox SDK到最新版本或者检查你的工控机在录数据时是否有过重的CPU负载导致话题回调滞后。我遇到过一次比较隐蔽的情况bag录制过程中同时跑着另一个占用大量CPU的节点导致雷达话题回调被卡顿。ROS的bag在话题时间戳正常的情况下会把所有消息按时间戳对齐但回调延迟本身的抖动已经影响到了点云帧内各个点的时间一致性。后来我用htop看了一下CPU占用发现已经逼近100%清理了多余节点之后再录数据时间偏移问题直接消失。6.3 编译和环境相关的问题编译问题看起来不致命但能卡住你一整天。最常见的两个坑一个是Ceres和Eigen版本冲突具体表现是编译过程中出现一堆“no matching function for call to”的模板错误。解决方法是统一使用Ceres 1.14.0和Eigen 3.3系列千万别让系统里同时存在多个Eigen版本尤其是通过conda或者pip引入的。另一个是livox_repub编译报错找不到livox_lidar的自定义消息。这个问题通常是因为只克隆了livox_repub而没有完整安装Livox SDK。解决办法很简单回到Livox官方驱动仓库把整个SDK和驱动一起编译安装。还有一个容易被忽略的问题如果你是在Noetic环境下编译代码里有些ROS1 API已经废弃或者变名编译告警和错误会多一些。我的建议是标定环境专门用一个Ubuntu 18.04虚拟机或者Docker容器来搭不要和日常开发环境混在一起。6.4 外参标定结果与真实值存在恒定偏差有时候标定结果看起来完全收敛数值也在合理范围但跑FAST-LIO的时候发现地图还是有一点点模糊或者轻微分层。这种现象通常不是算法问题而是你标定的参考坐标系和最终使用时的参考坐标系不一致。常见的情况是你标定时雷达坐标系用的是Livox的默认定义但FAST-LIO里配置的雷达坐标系是经过某种旋转后的自定义坐标系。这两个坐标系如果不一致标出来的外参在另一个系统中当然不成立。我建议在标定前就统一坐标系定义把Livox默认的坐标系和算法里用的坐标系关系提前搞清楚。另外还有一种情况如果你在户外强光条件下采集Livox的强度值会受到阳光干扰点云中某些点的强度值不稳定导致intensity_filter误滤掉一部分有效特征。实测下来傍晚或者阴天环境下采集的数据标定精度最高。这个结论我在不同地点测过多次基本稳定。7. 一些关于实践的补充建议标定这件事一次做对比反复折腾效率高得多。我把自己平时跑的流程再给你串一遍先确认环境和工具链没问题再检查硬件连接和坐标系定义然后带着明确意识去采集数据最后通过标定结果和建图验证双重校验。整个流程熟练之后从拿到新设备到获得可靠外参通常一小时内就能搞定。如果你想把标定的结果做得更细还可以对同一组外参做多次标定取平均值作为最终结果。我习惯同一组数据跑三遍观察每次结果之间的离散程度。离散度大说明标定条件不理想离散度小说明结果可信度高。尤其是旋转外参的俯仰角三次结果偏差超过0.3度的话我就会重新采集数据而不是死磕一组结果。关于时间同步我还想多说一句。lidar_imu_init给出的时间偏移是当前系统状态下的估计值如果你后面换了工控机、换了USB接口、调整了驱动版本时间偏移很可能也会变化。所以不要标完一次就一劳永逸系统环境有变动时抽出十分钟重新标定一次成本很低却能避免很多后面的疑难杂症。另外如果你用的是双雷达方案比如一台Avia加一台Mid-360记得先用这个工具分别标定每台雷达与IMU的外参再拿两台雷达之间的公共视野做一次交叉验证。不要想当然认为同一型号出厂一致不同设备之间的安装误差总归是存在的分开标定再校验是最稳妥的思路。最后再分享一个小技巧。标定的bag文件不要采集完就删连同当时的配置文件和标定输出结果一起存档。后期如果你想换一种算法框架重新建图或者排查某个偶然出现的定位发散问题这份存档能帮你省掉再采一次数据的麻烦。我的项目目录里专门有一个calib_records文件夹按日期和传感器组合命名长期积累下来就是一套非常有价值的经验库。希望这份指南能帮你顺利跨过外参标定这道门槛。这套流程我自己用了很长时间从最初折腾一下午到现在十分钟跑完中间的坑基本都写在上面了。你照着走应该不会再被外参标定拦住。