
最近在调一台差速底盘移动机器人传感器配置很常见一个水平安装的单线激光雷达、一颗九轴IMU、两个轮子的编码器里程计。定位和建图跑的是hdl_graph_slam这套开源方案本身很成熟但真正让我崩溃的不是算法而是IMU、底盘车轮里程计、单激光雷达三者之间的外参标定。外参不准后面所有建图、定位全是白费功夫。这篇工作笔记就把我整个标定过程、踩过的坑和验证方法完整记录下来给同样在搞机器人外参校准的同学做个参考。1. 先搞清楚这套系统里三个传感器各自扮演什么角色1.1 hdl_graph_slam的传感器分工与数据流hdl_graph_slam是日本名古屋大学团队开源的3D SLAM方案虽然名字里带graph_slam但它对传感器配置的宽容度很高很多做室内移动机器人的团队都会把它改造适配到单线激光雷达上。在我的这套配置里三个传感器的角色是这样分的底盘车轮编码器输出的是2D里程计x、y方向位移加绕z轴的旋转角频率一般能到50Hz甚至100Hz短时间内非常稳定但在打滑或者地面不平的场景会迅速累积误差。IMU输出的是三轴角速度和线性加速度频率通常在100Hz到200Hz之间它的roll和pitch绝对可信yaw会漂移但短时相对变化很准。单线激光雷达输出的是2D平面内的激光扫描扫描匹配scan matching给出的相对位姿变化非常精准是整套建图定位的主心骨。在hdl_graph_slam的数据流里机器人底盘里程计和IMU负责提供高频先验位姿让激光扫描匹配有一个好的初始值激光数据本身通过NDT或者ICP与局部地图进行配准生成更精确的帧间位姿最后送入因子图优化后端再做回环检测和全局优化。这三个信号是互相补充的关系激光精度高但没有绝对朝向参考IMU提供了稳定的姿态参考但yaw会漂底盘里程计提供了平滑的位移参考但会打滑。外参标定的目标就是把这几个坐标系之间的刚性变换关系精确求出来让它们在时间同步的前提下能对齐到同一个空间上。1.2 外参标定到底在标什么坐标系变换的本质外参标定说白了就是求两个传感器坐标系之间的旋转变换R和平移变换t。激光雷达有它的坐标系通常x轴朝前、z轴朝上IMU也有自己的坐标系每个IMU的数据手册上都会画底盘的车轮里程计则工作在base_link或者base_footprint坐标系下。在ROS里所有这些坐标系最终靠tf数树串起来任何一个frame之间的变换错了下游节点直接起飞。我见过不少人觉得外参差个一两度没大碍这是最大的认知误区。用最简单的情况算笔账如果激光雷达相对底盘的yaw角标定误差是1度机器人直行10米激光点云构建出来的地图相对于真实墙面的横向偏差就是10×sin(1°)≈0.17米。这还没算里程计轮径误差、IMU安装倾斜这些叠加因素。在一个20米的走廊里走一圈回来地图偏出半米很正常。所以外参标定的精度直接决定建图回环能不能闭合、定位能不能稳定跟踪是所有上层功能的地基。2. 标定之前的准备工作硬件安装与底盘里程计预处理2.1 三个传感器的物理安装要点外参标定不是纯软件能解决的硬件安装方式很大程度上决定了标定的难度和工作量。我这次的做法是在机器人底座上焊了一个铝型材支架三个传感器全部固定在一个刚性平台上。这个点极其重要如果传感器之间存在弹性连接车辆震动后外参就变了标定结果再准也没有意义。安装时需要注意几个容易被忽略的细节激光雷达尽量水平安装让扫描平面平行于地面这样后续建图时地面的干扰小IMU的安装方向尽量与底盘坐标系对齐哪怕差个几度都没关系但一定要确保安装牢固不允许有微小晃动底盘车轮的编码器安装精度决定了里程计的原始质量链条传动或者皮带传动会引入间隙和形变能直连减速电机最好直连。另外三个传感器的线缆要走好避免在运动过程中拉扯导致传感器位置偏移。还有一个很多人不重视的点在记录数据之前用水平尺检查激光雷达顶面是否水平用倾角仪记录IMU安装座相对水平面的初始角度。这些物理信息在后面标定roll和pitch的时候可以用来互相验证防止软件标定结果出现方向性的错误。2.2 底盘轮式里程计的预处理轮径、编码器与轮距很多人一上来就做传感器外参标定结果发现怎么标都不对最后排查下来是底盘里程计本身的内参就是错的。轮式里程计的内参主要指三个量轮径、编码器每圈脉冲数、左右轮距。这三个量不正确里程计输出的位移和旋转就是错的拿错误里程计去标激光外参自然不会有好结果。轮径的测量建议用“滚动测量法”不要直接用卡尺量轮胎外径因为在自重下轮胎会压扁动态滚动半径和静置半径差别很大。我的做法是在平整地面上用粉笔画一条起点线推动机器人让两个轮子各滚10圈用卷尺量总距离除以10π得到实测轮径。这样做一次能同时验证编码器的每圈脉冲率是否和码盘标称一致。轮距的测量要分驱动方式差速底盘直接量左右轮接地点之间的垂直距离也就是轮子胎面中心面在横向上的间距。对于用增量式编码器加减速箱的底盘编码器脉冲计数和轮子转角之间的关系可以简单写成轮子转动角度(rad) 编码器脉冲数 / 编码器每转脉冲数 / 减速比 × 2π。左右轮转角差除以轮距就是底盘的旋转角速度左右轮速度平均值就是底盘平移线速度。把这些公式在代码里跑通用遥控器让机器人原地转一圈看里程计输出的累计旋转是否接近360度就能快速验证轮距和轮径是否正确。2.3 IMU的内参确认与数据检查IMU数据在使用前应该做一些基本检查否则容易把外参标定结果误导到错误方向。检查项目包括轴正负方向是否和ROS标准定义一致x向前、y向左或向右、z向上要按实际传感器的手册确认静止时加速度计的模长是否接近9.81静止时陀螺仪的零偏是否足够小以及rostopic的发布频率是否稳定。我这次用的IMU在数据手册里和ROS坐标系定义就有冲突手册里的y轴方向和ROS标准定义差了个负号。如果直接接入hdl_graph_slam不做修正ROS的tf系统会用错误数据去计算这种问题在标定时完全暴露不出来因为数据曲线看起来都是正常的只有跑建图时才会发现在某个方向上地图被系统性扭曲。所以建议在标定前先把三个轴的加速度和角速度录一段数据人为地朝已知方向晃动传感器核对数据变化方向是否符合预期。拿到原始数据后还要检查时间戳是否连续、是否存在乱序。IMU频率高对时间戳的一致性要求也高有个简单方法记录1万条消息看时间戳差值分布是否均匀如果存在明显跳变就要在驱动里做时间戳平滑处理。3. 底盘轮式里程计到激光雷达的外参标定3.1 手动量测初值不精确但能兜底在所有精细标定之前先用卷尺和角度尺手动量出一组外参初值这组值不要求非常精确但必须保证方向正确、量级不出错这样后续的自动标定才有合理的迭代起点。具体量测对象是激光雷达坐标系原点在底盘坐标系中的位置以及激光雷达朝向相对底盘朝向的旋转角。实际操作起来是这样的把机器人抬到一个平台上用线锤把激光雷达扫描中心投影到底盘平面上测量它到后轴中心差速底盘取两轮连线的中点的纵向距离和前向距离这就是x和y的平移量。z方向则直接量激光雷达扫描平面到底盘落地平面的高度。yaw角可以量激光雷达侧面与底盘侧面的平行度如果安装时用直角靠尺贴过这个角度误差应该在1度以内。量出来的初值记下来写进Urdf或者tf发布脚本里作为初始外参。这里有个经验不要等到标定完成才把外参灌进系统而是先用量测值把tf跑起来保证我们后续的标定脚本能够实时拿到准确的传感器数据。手动量测虽然粗糙但胜在靠谱它能帮你在后续算法标定出异常值时兜个底一眼看出结果是不是离谱。3.2 直线行驶标定法x/y偏置与yaw角接下来做一次直线行驶实验这个实验能把激光雷达相对底盘的yaw角粗标出来同时还能验证z偏置是否合理。操作方法是在机器人前方大约5到8米处垂直放一块大平板比如几块纸箱拼起来然后让机器人朝平板方向直线行驶2米左右期间记录激光扫描数据和底盘里程计数据。核心原理是当机器人沿底盘x方向直线运动时激光雷达扫描到的平板应该是垂直的也就是在激光坐标系下平板平面和激光x轴的夹角直接反映了激光雷达相对底盘的yaw装偏角。如果激光外参里yaw是0那么平板点云拟合出来的直线方向和激光x轴应该垂直一旦不垂直这个角度偏差就是需要补偿的yaw误差。用最小二乘法拟合点云里的直线取出直线法向量计算其与x轴的夹角就是我们要标定的yaw值。x和y偏置的标定稍微复杂一点但也可以用直线行驶加旋转组合完成。具体做法是让机器人原地旋转90度后再走一段直线通过对比底盘里程计给出的位移变化量和激光点云中参考物位置的相对变化构建方程组解出x、y偏置。公式推导本质上是刚体变换的坐标平移方程实际操作时直接写一段Python脚本用最小二乘法求解一个2×2线性系统即可。这个过程中最容易出的问题是直线行驶时车轮本身的行驶方向偏差与激光外参yaw耦合耦合在一起所以建议前后做两次反向行驶取平均抵消底盘开不直的系统误差。3.3 利用建图结果反查外参残差直线标定做完之后外参的粗值已经可以用了但离精细的精度要求还差一些。这时候我建议直接跑一次hdl_graph_slam建图然后从建图结果里反查外参残差这是一种工程上实用的细标定方法。具体做法是在一个特征丰富的室内环境里建图比如办公室走廊加房间的区域确保有大量垂直墙面、柱子、转角这些几何特征。建图完成之后把生成的地图点云用可视化工具打开先看墙壁的厚度和锐利度如果墙是双层甚至三层虚影说明外参还有问题。此时可以检查特定的残差模式如果机器人行驶方向上的墙出现重影最可能是激光x方向的外参偏差或者yaw残差如果转弯处地图出现扇形模糊通常是激光y方向外参偏差过大导致旋转中心不在激光坐标系原点。更精确一点的做法是把底盘里程计位姿和激光scan matching输出的位姿做时间对齐后用一段包含直线和转弯的数据计算两者transform的相对序列。理论上这段相对序列里旋转部分应该始终为零如果出现稳定的非零旋转就是外参旋转残差平移部分则体现外参平移残差。把这套残差序列用优化器Cerres或G2O做一次最小二乘拟合就能把外参精修到位。4. IMU到激光雷达的外参标定4.1 为什么IMU外参这么容易翻车IMU外参标定是整套系统里最容易翻车的环节原因是IMU和激光雷达都提供“姿态”信息但姿态定义存在歧义。激光雷达的姿态变化是通过scan matching得到的它的参考系是激光坐标系本身而IMU的姿态是相对世界坐标系的absolution朝向。两者之间只差一个固定的旋转外参但这旋转外参同时耦合了安装旋转和坐标定义不一致导致很多人在标定时区分不开。另外IMU外参中的roll和pitch与yaw对系统的影响方式完全不同。roll和pitch标定不准会让点云在重力方向上产生倾斜地图呈现出整体扭曲、越远越明显yaw标定不准会让IMU提供的角速度先验在水平面内转错方向导致激光匹配在快速旋转时发散。必须分别对待。还有一个隐藏坑IMU的安装通常不保证和底盘坐标系完全水平一旦有颠簸IMU测量的重力方向和对惯性量的分解就会出现偏差让融合滤波器把不存在的倾斜当作真实运动补偿掉造成点云整体扭转。所以IMU外参如果没有标定到位在移动机器人上直接表现就是建图稍微走远一点就开始扭麻花。4.2 静态对齐法重力方向定roll/pitchIMU外参的roll和pitch可以通过静态数据直接求出来原理非常直观机器人静止时IMU加速度计测量到的只有重力加速度方向竖直向下。如果IMU和底盘之间不存在roll和pitch安装角那么加速度计的读数应该是(0, 0, 9.81)在z向上的坐标系中。读数里出现了横向的分量就说明IMU相对底盘存在倾斜。把机器人放在一个尽量水平的平地上静止一段时间录制IMU加速度原始数据取平均值消除噪声。用平均值反算翻滚角roll atan2(acc_y, acc_z)pitch atan2(-acc_x, sqrt(acc_y² acc_z²))。把这两个角度作为外参旋转矩阵的R_x和R_y就可以把IMU的姿态对齐到底盘的重力方向。这里面要注意静态对齐法求的是IMU相对“重力垂直方向”的姿态而不是相对底盘机械坐标系的姿态。如果底盘本身放在斜坡上或者轮子气不平这两个概念会混在一起。所以操作时一定要找水平平台并且在前轮后轮都置零的情况下静置。通常做法是把机器人放在一块已知水平的桌面上或者用垫片把底盘调到水平保证静态对齐结果可信。4.3 动态标定旋转激励法简化版手眼标定roll和pitch求完之后剩下yaw。IMU的yaw外参求解要借助运动激励本质上是简化版的手眼标定在同一个时间段内IMU输出的姿态变化量和激光scan matching输出的姿态变化量它们之间只相差一个固定的旋转外参。实际操作时让机器人原地做一系列缓慢、大幅度旋转速度不要快角速度控制在每秒20度以内避免激光扫描畸变和IMU饱和。旋转角度要足够大累计转动应超过180度甚至360度覆盖充分的旋转激励。在旋转过程中同步录制IMU姿态四元数序列和激光scan matching输出位姿序列把两者的旋转增量序列对齐。求解时最直接的办法是把每一帧的相对旋转写成四元数构造一个最小二乘问题给定IMU相对旋转q_imu和激光相对旋转q_laser找一个固定四元数q_ex使得对每个时刻满足 q_ex ⊗ q_imu q_laser ⊗ q_ex。这是典型的手眼标定AX XB形式可以使用开源库中的经典解法比如Tsai方法求解。实际上因为只有yaw一个未知量加上前两步已经锁定了roll和pitch可以直接将两种旋转的角度增量序列做差取平均得到yaw偏置角不需要完整解矩阵更简单可靠。关键点在于绘图检查把IMU yaw角度和激光scan匹配yaw角度放在同一张图里旋转段应该保持平行如果两者之间存在一个常数偏置该偏置就是misyaw外参。此时还需要检查平行度是否随时间漂移如果漂移则说明IMU本身的yaw在旋转过程中有累计误差需要先检查IMU陀螺仪的零偏。5. hdl_graph_slam中的外参配置与效果验证5.1 参数文件里怎么填frame_id与tf配置外参标定完成后要正确地把这些值写进hdl_graph_slam和相关节点的参数配置里。以我这次实践为例ROS的tf树结构是map → odom → base_link → laser、base_link → imu_link。激光雷达和IMU相对底盘的tf由静态坐标变换发布节点发布漂移量就是用我们标定出的外参。在hdl_graph_slam的launch文件和相关的yaml参数文件中需要确认几个关键配置项。首先是输入topic的remapscan_matching_odometry节点订阅的是/scan或者/points_rawIMU节点订阅的是/imu/data_raw或/imu/data底盘里程计如果需要接入先验位姿需要把/odom正确remap给相应节点。其次是frame_id一致性激光雷达点云的frame_id要设置为标定对象对应的激光坐标系名称IMU消息的frame_id要和IMU的tf名称一致否则tf系统在查询变换时会直接报“unknown frame”根本跑不动。还要注意hdl_graph_slam里对地面去除的处理它原本是针对3D激光设计的有floor_detection节点来过滤地面点。单线激光雷达水平安装时激光扫描平面几乎和地面平行实际上扫描到的并不是完整的地面而是墙面脚线附近的高度层。此时应该把与地面相关的参数关掉或者直接不使用floor_detection节点避免它把墙面误判为地面点滤掉。同时校准时z轴方向的外参偏差对2D建图影响不大但对后续加装3D传感器或者做斜坡场景就很重要不能省。5.2 建图质量的几个验证指标外参标定得好不好跑一圈建图就能立刻看出来。我会在标定完成后做一组标准化的验证流程拿到几个关键指标来判断是否达到预期。第一个指标是地图中墙体的点云厚度。在理想情况下墙面应该是一个约等于激光雷达测距噪声2到3厘米的薄层如果墙体呈现扫描线宽方向的弥散说明外参标记不准或者存在震动。第二个指标是机器人回到起点时的回环闭合误差。实际做法是让机器人沿着一个形状跑一大圈回到起点等回环检测触发后看后端优化修正幅度。如果修正幅度超过20厘米而地图在闭合之前明显错位说明某个外参很大概率还有残差。第三个指标是旋转处的点云锐利度在有直角墙角的房间原地旋转180度查看墙角点云是否出现分叉或者圆角模糊。除此之外我还会用reflection matching的方式检查激光点云是否与imu朝向一致在浏览器里同时显示点云和IMU车体朝向箭头晃动机器人观察箭头和点云旋转是否保持同步。这项测试非常直观如果有延迟或相位差直接提示外参或时间戳问题。5.3 定位模式的切换与外参一致性hdl_graph_slam既能建图也能定位但要实现从建图到定位的平滑切换外参必须始终一致。换句话说建图和定位过程中激光雷达、IMU、底盘三者之间的相对关系不能变一旦变了地图得重建外参得重新标。在定位模式下我通常把scan matching的初值提供给ndt匹配同时用IMU和底盘融合的位姿作为预测来补偿激光匹配在重复场景下的退化问题。实际测试时用遥控器沿建图路径反向走一遍看看定位位姿是否紧贴地图墙线以及位姿是否出现跳动。如果反向走时位姿明显偏向一侧最常见原因就是外参yaw标定时用的行驶方向和多路径不完全一致底盘开不直导致的系统误差起了作用。这时需要做多方向行驶的记录来平均掉这些系统偏差。另外我养成了一个习惯在每次标定完外参后把三组值激光相对底盘、IMU相对底盘、底盘轮距轮径存入一个配置文件并打git tag出问题时可以直接回滚对比避免反复标定导致版本混乱。6. 常见问题与排查技巧实录6.1 建图出现重影或墙体分层这个现象几乎是外参问题最典型的表现。如果重影的距离和行驶速度成正比优先怀疑激光雷达相对底盘的x方向平移外参不准因为x偏置误差会导致激光位置时刻滞后或超前于真实位置。如果重影只出现在转弯段优先怀疑y方向平移外参因为旋转中心不在激光原点时转弯时激光点云会整体做圆弧偏移。处理方法是先回到第3.3节的反查步骤用优化器求解平移残差。有几次我偷懒跳过细标定直接跑长走廊结果地图两侧墙壁越来越厚最后走廊宽度比真实宽度大了20多厘米检查后才发现是激光y方向外参少了3厘米。这个数量级靠肉眼在CAD里看不出必须通过优化器求。6.2 机器人直行但地图斜着偏这种问题的根源大概率是yaw外参标定不准但也有可能是底盘的单侧轮径标定错误导致差速底盘本身上下直行时带了一个恒定转向角。区分方法很简单让机器人向前走5米再倒着走回原点如果地图前后两次轨迹重合说明是yaw外参如果不重合说明是轮径不一致或者底盘安装本身歪。针对这一现象我曾经吃过一次教训最开始用直线标定法求到的yaw外参是-1.2度但建图还是往右偏。后来发现是激光安装支架本身在碰撞中弯了0.5度测量簧片及支架的水平度后才发现重新校正了安装件再标定就正常了。所以出现方向性偏移时先检查机械结构是否变形再怀疑算法。6.3 旋转时点云出现“甩尾”拖影旋转时点云甩尾是IMU外参yaw和激光外参yaw两个都有问题的最典型症状。原因是机器人旋转时IMU了提供错误的旋转先验导致scan matching在旋转过程中的迭代收敛到错误局部极小值点云位置落在真实位置之后或者之前形成类似拖影的效果。排查办法是先固定激光外参单独调整IMU外参yaw观察甩尾方向是否变化。如果变化了说明IMU外参占主导如果没有变化说明激光外参占主导。这招在实战中非常有效两个参数可以交替迭代每次调整量为上次的一小半通常三四轮迭代就能收敛到不错的效果。另外要提醒旋转速度不要过快点云畸变本身就是甩尾的一个重要来源和IMU后端频率也有关系。6.4 记录数据时的几个习惯性操作标定效果好不好数据质量占一半。记录标定数据时有几个习惯特别值得养成首先是录数据前把传感器充分预热IMU尤其需要预热几分钟再录否则零偏漂移会把标定结果带偏其次是记录数据时使用rosbag把所有topic一起记录并且确保时间戳同步后面回放时可以反复调参测试最后是在标定过程中记录实验环境描述和操作动作比如“直线2米朝东、原地顺时针360度”这样后期分析数据时就能对照物理含义。还有一个奇葩但有效的技巧每次标定完成后我会拿高斯分布随机做十几组微扰动加到标定好的外参上让机器人重复一段固定路径看建图质量的退化方式。这一步能确认系统对外参误差的敏感方向帮你了解哪一项是必须精确标定的、哪一项差个几毫米没关系后续评故障时能快速锁定方向。我个人在实际操作中的体会是外参标定是一项系统工程三分算法七分数据机械安装的高度一致性比任何精巧的标定算法都重要。不要指望一步到位先配一个靠谱初值跑通流程再逐项精修每次只动一个量看清效果再动下一个这是最稳妥的路径。这套流程做完hdl_graph_slam建图定位的效果会立竿见影地图墙线锐利、回环闭合稳定、定位不再漂移。后续如果再换传感器或者改底盘只需照着这套方法重新标一遍即可整套流程二十分钟就能跑完。