移动机器人——运动模型做移动机器人有个很朴素的问题你知道轮子转了多少圈可机器人到底跑到哪儿了姿态转了多少方向偏没偏要回答这些就必须先建立起机器人的运动模型。运动模型是整个移动机器人系统的地基。SLAM里的里程计预测、路径规划里的状态约束、底盘控制里的速度解算全都建立在运动模型之上。模型建得准后面一切算法都能事半功倍模型建得糙哪怕你上了激光雷达、视觉SLAM、各种高级控制器系统也会因为状态预测和实际偏差过大而抖动、跑飞甚至直接把墙撞了。这篇文章我从实际做机器人的角度把运动模型这件事从头到尾拆一遍坐标系怎么定、差速底盘怎么建模、阿克曼底盘为什么不能原地转、麦克纳姆轮的运动学方程怎么解以及这些模型在真实系统里怎么落地、有哪些坑。不管你是刚入门做毕设还是已经在调自己的机器人底盘这篇内容应该都能给你一些直接的参考。1. 运动模型到底在解决什么问题先理清一个基本概念运动模型本质上是用数学语言描述“机器人怎么动”。1.1 运动学模型和动力学模型的区别很多人会把运动学模型和动力学模型混在一起但它们解决的问题完全不是一回事。运动学模型研究的是“运动本身”的几何和时序关系不关心产生运动的原因。它回答的问题是给定轮子的转速、转角机器人整体会以什么速度、什么方向移动给定两轮的速度差机器人转弯半径是多少动力学模型则要更进一步考虑“力”。它回答的问题是给电机施加多大的扭矩轮子能产生多大的加速度机器人质量、惯性矩、地面摩擦力、轮胎形变这些因素怎么影响运动在机器人开发中绝大多数时候我们用运动学模型就够用了。因为移动机器人速度一般不快动力学效应没有车那么明显而且底盘驱动板通常有内环速度闭环你发给电机的速度指令电机响应的时间常数很小运动学模型加上一个很小的延迟就能描述得很好。但如果你做的是高速移动比如竞速机器人、全向足球机器人或者机器人在斜坡、沙滩这类非结构化地面跑那动力学模型就不能忽视了。要让机器人不侧滑、不翻车必须引入加速度和力的约束。1.2 从“轮子转”到“机器人动”的映射运动模型要解决的核心问题就一句话怎么把底盘层的信息映射成机器人在空间中的位姿变化。这句话拆开看有三个层面输入层轮子的转速、转向角这是底盘编码器或者电机驱动板能直接给到的数据。映射层通过底盘的结构几何关系把轮子转速合成到机器人本体的线速度和角速度上。这是运动学建模的核心工作。输出层机器人位姿位置x、y和朝向θ的变化率。这一步实际上已经进入了位姿积分就是里程计的来源。我见过不少新手只写了第三步也就是直接对速度做积分完全跳过了第二步的几何映射。这样做的结果是底盘一旦有结构参数不准确比如轮距量错了整个系统就会累积误差而且你还很难排查——因为代码逻辑看着没错问题出在物理参数上。所以在正规的底盘驱动和导航架构里运动学解算是独立的一层必须把轮速到机器人速度的转换单独拎出来做后续的位姿积分、路径跟踪、状态估计都只依赖这一层输出的机器人速度不直接碰轮速。1.3 模型精度和实时性的权衡还有一点非常关键运动模型不是越精细越好。现实中影响机器人运动的因素非常多轮胎形变、地面摩擦、悬挂游隙、负载偏移全建模进去理论上是可能的但工程上完全没必要。为什么因为你要在实时性、计算量、精度三者之间找平衡点。实际的SLAM系统里运动模型输出的值通常不是最终结果后面还会跟着激光雷达/视觉观测、卡尔曼滤波更新、回环检测修正。运动模型提供的是一个预测初值这个预测不需要100%准但需要“稳定、可重复”——即误差的模式相对固定方便滤波器去补偿。打个比方运动模型就像你在黑暗中用手电筒照路不需要照得雪亮但光束的偏移方向得是稳定的你才能根据它调整方向。如果手电筒忽左忽右乱晃你反而会不知道往哪走。所以实际项目中最常用的还是简化的刚体运动学模型把机器人看成刚体轮子看成纯滚动、无滑动的约束体用几何关系建立输入到输出的映射。简单、够用、可调试这才是工程上的正确选择。2. 先定坐标系建模前的必备功课任何运动模型的第一步都是定义坐标系。这一步看起来基础但坐标系定义混乱导致的bug我见过太多。2.1 世界坐标系与机器人坐标系的区别机器人运动学里涉及两个基本的坐标系。世界坐标系也叫全局坐标系/地图坐标系固定在地面上通常用 (X_W)、(Y_W) 表示用来描述机器人在环境中的绝对位置。这个坐标系是SLAM建图、导航规划的基准。机器人坐标系也叫机体坐标系/局部坐标系固定在机器人本体上通常把机器人中心作为原点前进方向作为 (X_R) 轴正方向左侧为 (Y_R) 轴正方向逆时针旋转为角度正方向。所有传感器测量到的数据最初都是在这个坐标系下的。为什么要区分这两个坐标系因为底盘编码器给的数据直接反应的是机器人坐标系下的运动——你读到的轮速快慢是“机器人自己感觉到的速度”但导航要用的位置是“机器人在世界坐标系下的绝对位姿”。从机器人坐标系的局部运动换算到世界坐标系的全局运动中间要过一层旋转。2.2 旋转矩阵和航向角约定机器人从局部坐标系到世界坐标系的转换在二维平面内只涉及一个旋转角θ也就是机器人的航向角heading。这个角度通常定义成机器人前进方向与世界坐标系X轴的夹角逆时针为正。给定机器人在自身坐标系下的速度 (v_x)、(v_y)纵向速度、横向速度通过旋转矩阵转换到世界坐标系[ \dot{X}_W v_x\cos\theta - v_y\sin\theta ] [ \dot{Y}_W v_x\sin\theta v_y\cos\theta ]这两个公式是里程计积分的基础务必理解而不是死记硬背。这里要提醒一个很多教程不会提的细节角度制单位一致性。ROS里默认角度是弧度但很多IMU硬件输出的是度编码器积分用的又是弧度。单位不一致会导致机器人直线走歪、转弯半径完全不对。我做个快速排查的技巧如果机器人模型在仿真里正常上真机却转弯乱转先把所有角度统一成弧度试试。2.3 用ROS的TF树管理坐标系在实际项目中我们不手动维护这些坐标变换矩阵而是用专门的坐标变换库来管理。ROS里的TFTransform Frame系统就是干这个的。它维护一颗坐标变换树map→odom→base_link→base_laser每两个相邻坐标系之间都有一个变换关系。你的激光雷达数据在base_laser坐标系下要变成地图坐标系下的点云TF树会帮你完成连续变换。这样做的好处是每个传感器、每个执行器都在自己的坐标系下工作谁的数据出错了直接在TF树里检查对应节点的变换就行不用把所有传感器的数据都换算到一个坐标系里。我建议所有做机器人的朋友从第一天起就养成TF树管理的习惯。即使是自制的小底盘项目也把坐标系定义清楚后面增加传感器、改结构会省很多事。3. 差速驱动模型机器人底盘最常见的运动模型差速驱动是移动机器人中最经典、最常用的一种底盘结构。室内巡检机器人、扫地机器人、仓库AGV基本都是差速底盘或它的变种。理解差速模型的本质也就理解了机器人运动学的核心。3.1 底盘结构和速度关系推导差速底盘的基本结构是左右两个独立驱动的轮子驱动轮外加一个或多个从动轮万向轮通过控制左右轮速度差来实现转向。定义(v_L)左轮线速度m/s(v_R)右轮线速度m/s(d)左右轮间距m通常取两轮接地中心点之间的距离(v_c)机器人中心点线速度m/s(\omega)机器人角速度rad/s它们之间的关系是[ v_c \frac{v_L v_R}{2} ] [ \omega \frac{v_R - v_L}{d} ]这两条公式就是差速模型的核心。从这两个方程可以直观看出差速底盘的运动特性两边速度相同机器人直线走两边速度相反大小相等机器人原地旋转一快一慢机器人走弧线。转弯半径的计算式为[ R \frac{v_c}{\omega} \frac{d(v_L v_R)}{2(v_R - v_L)} ]当左右轮速差趋近于0时转弯半径无穷大对应直线当 (v_R -v_L) 时转弯半径为0对应原地旋转。3.2 正运动学与逆运动学的实际用法差速模型的正运动学是从轮速到机器人速度的方向。典型应用是里程计从编码器读回左右轮的转速乘上轮子半径得到线速度然后代入上面的公式得到 (v_c) 和 (\omega)再对时间积分得到位姿变化。逆运动学则相反是从你期望的机器人速度解算出左右轮的目标速度。这是底盘控制的核心导航算法算出机器人该以什么线速度和角速度走底盘驱动板就要把这两个目标值转换成左右轮速[ v_R v_c \frac{\omega d}{2} ] [ v_L v_c - \frac{\omega d}{2} ]这里有个实操要点给电机控制器发送的速度指令通常是“轮子的目标线速度”或者“目标转速”。而电机驱动板内部还有一个速度环用来跟踪你给的目标速度。所以整套链条是路径规划给出机器人的目标速度 → 逆运动学解算成左右轮目标速度 → 电机驱动板速度环跟踪 → 编码器反馈实际轮速 → 正运动学合成机器人实际速度 → 里程计更新位姿。3.3 差速底盘的运动约束为什么它不能横着走差速底盘有一个很重要的运动学约束机器人只能沿着它当前朝向的方向运动或者做旋转不能横向平移。这个约束叫非完整约束nonholonomic constraint。打个比方你开的汽车就是一个典型的非完整约束系统你可以前进、后退、转弯但不能像螃蟹一样横着移进停车位必须通过一系列的前进后退打方向才能停进去。从数学角度讲差速底盘在机器人坐标系下横向速度 (v_y) 恒等于0。这看起来是个简单的等式但它给运动规划带来了很大的限制路径规划器生成的路径必须满足机器人可执行的约束曲率连续、不能有横向跳变否则机器人根本无法跟踪。这也是为什么在做差速机器人的路径规划时要使用带有车辆运动学约束的规划算法比如Hybrid A*、RRT*加平滑优化而不是简单的直线规划加B样条。理解了模型约束的根源就理解了算法选型的依据。3.4 从轮速到位姿里程计的积分过程里程计的本质是对运动学方程做数值积分。这个过程通常是这样的读取编码器计数增量换算成左右轮在采样周期内的移动距离 (\Delta s_L)、(\Delta s_R)。根据公式计算机器人本体的位移增量 (\Delta s (\Delta s_L \Delta s_R)/2) 和角度增量 (\Delta\theta (\Delta s_R - \Delta s_L)/d)。用上一时刻的姿态更新当前姿态[ x_{t1} x_t \Delta s \cos(\theta_t \Delta\theta/2) ] [ y_{t1} y_t \Delta s \sin(\theta_t \Delta\theta/2) ] [ \theta_{t1} \theta_t \Delta\theta ]这个公式采用的是“中间角积分法”比直接用上一时刻的角度做积分要更精确因为它在角度变化较大的情况下误差更小。里程计虽然简单但误差是累积的每个周期的微小误差会不断叠加长时间运行后位姿漂移会非常明显。所以实际SLAM系统中里程计只作为运动预测源最终定位结果还是靠激光匹配或者视觉回环来修正。4. 阿克曼转向模型汽车底盘的几何学说完了差速再来看另一种常见底盘阿克曼转向。市面上绝大多数汽车、快递配送小车、部分室外巡检机器人用的都是这种结构。4.1 为什么汽车转弯时四个轮子转角不一样如果你观察过汽车转弯会发现一个有趣的现象转弯时四个轮子不是都指向同一个方向的内侧轮转角比外侧轮转角更大。这是为了让四个轮子在转弯时都能绕同一个瞬时转向中心ICR做纯滚动。如果四个轮子转角都一样轮胎就会在转弯时产生侧滑既磨损轮胎又让车辆难以控制。阿克曼转向几何的核心公式是[ \cot\delta_o - \cot\delta_i \frac{B}{L} ]其中 (\delta_i) 是内侧轮转角(\delta_o) 是外侧轮转角(B) 是轮距(L) 是轴距。实际底盘设计会让转向梯形近似满足这个关系。但要注意低速行驶时阿克曼几何的误差影响不明显高速时则需要精确的转向几何加上悬架系统的配合。4.2 自行车模型两轮合并的简化方法阿克曼底盘的运动学分析可以简化为“自行车模型”。这个模型把左右前轮合并成一个“虚拟前轮”左右后轮合并成一个“虚拟后轮”整车就简化成了两个轮子的自行车。自行车模型的运动学方程是假设前轮转角为 (\delta)后轴中点的速度为 (v)那么[ \dot{x} v\cos\theta ] [ \dot{y} v\sin\theta ] [ \dot{\theta} \frac{v}{L}\tan\delta ]也就是说车辆航向角的变化率即角速度与前轮转角的正切成正比与轴距成反比。这个模型为什么在工程中如此流行因为它足够简单同时精确捕捉了车辆低速转弯时的核心几何关系。路径规划、纯跟踪控制Pure Pursuit、MPC等算法都建立在自行车模型之上。4.3 转弯半径和航向角变化率的计算由自行车模型可以看到低速转弯时车辆的瞬时转弯半径为[ R \frac{L}{\tan\delta} ]当 (\delta0) 时车辆直行转弯半径无穷大当 (\delta) 增大转弯半径减小(\delta) 接近90度时转弯半径接近轴距L。但实际中前轮转角到不了90度一般能到30到40度就算比较大转向角了所以阿克曼底盘的最小转弯半径通常是轴距的数倍。阿克曼底盘无法原地旋转这是它和差速底盘最大的区别。在做导航规划时要给阿克曼机器人设置最小转弯半径约束规划出来的路径必须是车辆动力学可行路径。我自己做过一个户外巡检小车项目用的就是阿克曼底盘。当时直接把差速机器人的全局路径规划拿过来了结果路径上出现很多原地转弯的轨迹车根本走不出来。后来换成基于自行车模型的Hybrid A*规划才真正跑顺。这段经历让我深刻体会到选型之前先想清楚运动模型比什么都重要。4.4 阿克曼底盘的逆运动学与速度控制阿克曼底盘的执行指令通常是前轮转角和后轮转速。逆运动学要解决的是给定车辆期望速度和期望转弯半径或曲率解算出转向角。在实际控制中常用的是预瞄控制Pure Pursuit在规划路径上找一个预瞄点根据预瞄点相对于车辆当前姿态的角度偏差计算出目标转弯半径再通过自行车模型反推前轮转角。这个算法的参数只有一个预瞄距离调参非常直观是工程上最常用的轨迹跟踪方法之一。5. 全向运动模型麦克纳姆轮与全向轮差速和阿克曼是典型的“非完整约束”底盘特点是不能全方向平移。而全向移动底盘打破了这一限制可以让机器人“横着走”在狭窄空间有巨大优势。5.1 麦克纳姆轮的运动学方程麦克纳姆轮Mecanum Wheel是目前最流行的全向移动方案。每个轮子外圈装有一圈成45度角的自由辊子当轮子转动时地面的摩擦力被辊子的自由滚动分解产生沿辊子轴线方向的分力。4个麦克纳姆轮按照特定的布局安装常见的是X型布局通过组合每个轮子的速度可以让机器人实现前后、左右、斜向以及原地旋转。麦克纳姆轮底盘的正运动学假设轮子编号为左前、右前、左后、右后轮速分别为 (v_1, v_2, v_3, v_4)机器人的速度为 (v_x)纵向、(v_y)横向、(\omega)角速度那么[ v_1 v_x - v_y - \omega(ab) ] [ v_2 v_x v_y \omega(ab) ] [ v_3 v_x v_y - \omega(ab) ] [ v_4 v_x - v_y \omega(ab) ]其中 (a) 是机器人中心到前/后轮的水平距离(b) 是机器人中心到左/右轮的纵向距离。这四个方程中(ab) 可以合并成一个参数 (L)通常称为“轮速合成半径”。运动学解算时关键就在这个参数要标定准。逆运动学就是把上面方程反过来解给定目标 (v_x, v_y, \omega)解出四个轮子各自的目标速度。5.2 全向轮与麦克纳姆轮的选择除了麦克纳姆轮还有一种常见的全向轮Omni Wheel它的辊子方向与轮面垂直通常是90度轮子转动产生主方向的驱动力同时可以被动地沿辊子轴线方向滑动。8字布局、三轮全向底盘都是基于全向轮的。两种全向方案的对比麦克纳姆轮的辊子与轮轴成45度移动时辊子会产生斜向分力所以每个轮子都有“驱动力”和“侧滑力”的混合对控制精度要求更高。全向轮的推动效率比麦克纳姆轮高一些因为它没有斜向分力的损耗但全向轮的辊子通常直径较小承载能力和越障能力比麦克纳姆轮差。麦克纳姆轮对地面平整度较敏感地面有一点点坑洼就觉得“跳动”全向轮在大载荷下辊子容易磨损。如果做的是室内平面环境、需要频繁侧移的机器人我一般推荐麦克纳姆轮因为承载能力和市场成熟度都更好。如果做的是轻量级机器人比赛全向轮布局特别是三轮全向更灵活控制也更简单。5.3 全向底盘的控制注意点全向底盘虽然运动灵活但对控制器的要求也更高。核心问题在于轮子与细小辊子的接触是断续的轮子转动时会有轻微的速度脉动这会在低速时导致底盘抖动。解决这个问题的常见做法是在驱动层做速度闭环并且给速度环一个合适的低通滤波。另外调参时要注意麦克纳姆轮的摩擦力特性跟地面材质关系很大光滑地面上更容易打滑需要适当降低加速度上限。6. 运动模型在SLAM、控制与仿真里的应用模型不是停留在纸面的公式。真正体现模型价值的地方是在系统的各个环节把它用起来。6.1 在SLAM中作为运动预测源SLAM系统通常是“预测-更新”框架。运动模型负责预测机器人在下一时刻可能在哪里然后传感器观测对预测结果进行修正。以扩展卡尔曼滤波EKF做融合为例运动模型给出机器人的预测位姿同时给出协方差矩阵的预测。协方差的大小反映了运动模型的不确定性——模型越准协方差增长越慢最终融合出的定位结果就越好。这里有一个很多人没意识到的问题运动模型的噪声参数直接决定了滤波器对传感器观测的信任程度。如果你把运动模型噪声设得很小滤波器就会过度信任里程计对激光观测的修正反应迟钝导致定位滞后反之噪声设得太大定位结果会跟着传感器噪声剧烈跳动。调参的核心是让运动模型和传感器观测的不确定性匹配。6.2 在路径跟踪控制中的角色控制环节离不开逆运动学。路径跟踪控制器的本质是根据当前位姿和目标路径的偏差计算出期望的机器人速度指令然后通过逆运动学解算成各个轮子的速度。差速底盘这里比较简单直接算出 (v_c) 和 (\omega) 就完了。阿克曼底盘则要额外做转向角的解算通常用纯跟踪或者Stanley控制器。全向底盘则要同时考虑三个通道的速度解算。我做路径跟踪印象最深的一个教训是控制频率不够高时离散化误差会很大。比如控制频率只有10Hz转完一个弯路径就是锯齿状的跟踪精度和舒适度都差。把控制频率提到50Hz以上效果立刻就不一样了。所以底盘底层通信尽量用高频率接口这个对控制质量的影响非常大。6.3 仿真测试中模型的关键作用在把代码部署到真机之前仿真测试是必须的。而仿真有没有意义完全取决于运动模型真不真实。我见过很多人用gazebo仿真直接把轮速设置成底盘速度忽略了轮子打滑、地面摩擦、惯性等效应结果仿真里跑得飞起一上真机就不行了。这种仿真是无效的甚至是有害的——它给你一种“系统是对的”的错觉。正确做法是仿真环境里显式地建立轮子和地面的接触模型比如gazebo的轮胎模型并给轮速到机器人速度的转换加上延迟和噪声。这样仿真里的表现才接近真机才能在仿真阶段就暴露底层问题。7. 实测调参中常见的坑与避坑指南最后分享一些实际做项目时踩过的坑。这些内容教科书里不会写但调试时几乎天天遇到。7.1 轮距标定误差比你想象的大差速底盘的轮距 (d) 是核心参数但这个参数非常容易量不准。很多机械图纸标注的轮距是“两轮中心距离”但实际有效轮距是“两轮接地中心点之间的距离”考虑轮胎变形后有效轮距会比设计值小一点点。这个误差影响有多大如果轮距标大了里程计算出来的旋转角度会比实际小机器人走直线的时候舵机会修正过头表现为走S形轨迹。标小了则反过来。我自己常用的标定方法让机器人原地旋转若干圈比如5圈对比里程计计算的总角度和实际角度可以用IMU或者外部测量量角。如果差10%就把轮距参数修正10%。这个方法简单粗暴但很有效。7.2 轮子半径的一致性问题左右轮直径即使出厂一致在不同负载下胎压/形变量也会不一样导致左右轮有效半径有差异。这个差异最直接的表现是机器人明明下达了直线指令实际却走成一个大曲率弧线。排查方法是让机器人在平整地面上直行10米记录终点横向偏移量。如果有明显偏移先检查左右轮胎压、磨损情况再考虑修正左右轮速的比例系数。7.3 打滑是运动模型的终极敌人运动学模型的前提是轮子纯滚动、无滑动。一旦打滑模型就完全失效了。三种最常见的打滑场景急加速或急减速时驱动力超过地面摩擦极限轮子空转或拖滑。转向时速度过高离心力导致侧滑。经过光滑地面瓷砖、大理石、雨后钢板摩擦系数骤降。处理打滑的思路是软硬结合。硬的手段限制加速度上限、降低最大速度、增加底盘重量提高正压力。软的手段在状态估计中加入打滑检测发现里程计和IMU数据出现明显背离时降低对里程计的信任权重。7.4 编码器数据的时间戳对齐还有一个系统层面的坑编码器数据和IMU数据的时间戳没有对齐会导致融合算法出差。高速运动时即使几毫秒的时间偏差也会产生明显的位置误差。解决方法是统一所有传感器数据进入同一个时间同步机制或者使用带硬件时间戳的高端传感器再在算法层做时间插值。我在实践中遇到一个很典型的案例EKF融合时里程计和IMU总是对不上以为是噪声参数的问题折腾了好几天最后发现是ROS的时间戳没有统一到同一个时基上两条数据流的延迟差了将近30ms。修好时间戳后之前所有看似“玄学”的故障全部消失。这个问题非常隐蔽排查优先级建议提到IMU校准前面。8. 手把手搭建一个差速底盘的完整运动模型讲完理论用具体例子把整套流程走一遍。这里我以最常见的两轮差速底盘为例串起从硬件接口到里程计发布的完整步骤。8.1 参数测量和代码结构动手写代码前先把底盘的物理参数量清楚左右轮中心距多次测量取平均值精度尽量到毫米。车轮实际直径测量时给轮胎施加正常工作载荷用卷尺绕车轮一周测周长再除以π比直接量直径更准。编码器每转脉冲数结合减速比和编码器线数换算。轮子转速到线速度的换算系数 (K \pi \times D / \text{每转脉冲数})单位是“米/脉冲”。代码结构建议保持简洁分层operator/ ├── config/ │ └── robot_params.yaml # 轮距、轮径、脉冲换算系数等 ├── include/ │ └── motion_model.hpp # 运动模型类声明 ├── src/ │ ├── motion_model.cpp # 正/逆运动学实现 │ └── odometry_node.cpp # 里程计节点发布到ROS └── launch/ └── base_control.launch8.2 正逆运动学核心代码示例下面给一个C里正运动学和逆运动学核心实现的参考不含ROS依赖可以直接看懂逻辑。// 正运动学由左右轮速计算机器人速度 void MotionModel::forward_kinematics( double wheel_speed_l, wheel_speed_r, double vel_x, double vel_z) { // 左右轮线速度直接由编码器换算得出 // wheel_speed_l/r 单位是 m/s vel_x (wheel_speed_l wheel_speed_r) / 2.0; vel_z (wheel_speed_r - wheel_speed_l) / wheel_track_; // 注意右-左 } // 逆运动学由机器人目标速度解算左右轮速 void MotionModel::inverse_kinematics( double vel_x, double vel_z, double cmd_l, double cmd_r) { cmd_l vel_x - vel_z * wheel_track_ / 2.0; cmd_r vel_x vel_z * wheel_track_ / 2.0; }代码很简单但有三个细节必须注意第一角速度公式中的符号方向。如果θ正方向定义为逆时针机器人向左转那么右轮速度大于左轮时角速度为正所以是“右减左”除以轮距。方向定义反了的话机器人转弯方向会完全相反。第二逆运动学解算中速度符号的含义。如果 (v_x0, \omega0)那么左右轮速分别是一个正一个负大小相等对应原地逆时针旋转。第三关于 (vel_z) 的单位。很多底盘驱动板对转速的输入单位是rpm如果你习惯用rad/s需要做 (rpm \omega \times 60 / (2\pi)) 的换算。这个换算出错导致的问题非常隐蔽速度异常时先查这里。8.3 里程计积分与发布里程计积分的核心逻辑就是前面说的“中间角积分”公式。写成伪代码如下void updateOdometry(double delta_s_l, double delta_s_r) { // 左右轮位移增量米 double delta_s (delta_s_l delta_s_r) / 2.0; double delta_theta (delta_s_r - delta_s_l) / wheel_track_; // 更新位姿这里用中间角度更精确 double mid_theta theta_ delta_theta / 2.0; x_ delta_s * cos(mid_theta); y_ delta_s * sin(mid_theta); theta_ delta_theta; // 归一化角度到 [-π, π] theta_ atan2(sin(theta_), cos(theta_)); }发布时如果是在ROS里需要同时发布两个东西odom消息和TF变换。这里有个经常踩的坑是TF树的坐标方向odom和base_link之间的变换必须和odom消息保持一致否则后续的定位、导航就全乱了。正常情况下可以先用 /odom 话题的位姿同时向 /tf 发布对应的变换。但要注意如果你后面还有 EKF 或 robot_localization 节点来做多传感器融合通常要设置成只让融合节点发TF不让里程计节点发TF避免TF冲突。9. 扩展思路不同底盘模型的统一抽象最后聊一个后续深入会遇到的话题不同底盘的运动模型虽然形式不同但有很多共通的地方可以在代码层面做统一抽象。差速底盘、阿克曼底盘、全向底盘的共同点是它们都可以提供一个正运动学接口从轮速到机器人速度和一个逆运动学接口从机器人速度到轮速。区别只在于输入参数维度不同、约束条件不同、机器人的自由度不同而已。我推荐做底盘抽象类定义好接口让不同底盘各自实现。这样做的好处有两个一个是上层导航算法全局规划、轨迹跟踪、状态估计可以完全不用关心底盘类型其实不行因为阿克曼的曲率约束、全向的自由度差异会影响规划但这个影响可以在规划层通过参数配置解决。另一个更重要当你更换底盘类型时底层的驱动和上层的算法可以各自独立迭代不用为了换底盘重写一整套系统。在ROS 2的生态里ros2_control框架就提供了这种抽象思路硬件接口层只管收发轮速和指令控制器层通过运动学库解算目标速度再加上配置好的底盘参数一套代码可以适配多种底盘结构。用一句话总结我的体会运动模型不是一道做完就完事的数学题它是一个会贯穿项目始终的底层组件。一开始花时间把参数标定做对、把代码结构理清爽后面SLAM、导航、控制每一步都会顺很多反过来如果这块地基打得不稳后面遇到的所有问题都会让你怀疑人生。搞懂你手头机器人的运动模型值得成为你开始一切上层开发的第一件事。