4. 运动学模型

做机器人底盘,绕不开的就是运动学模型。说白了,就是搞清楚「轮子怎么转,机器人怎么动」这件事。差速驱动是两轮机器人最经典的结构,我最早接触它是在大学做智能车竞赛的时候,那时候还没意识到这东西有多重要,直到后来做AGV项目,才真正体会到——运动学模型没搞透,后面里程计、控制全是空中楼阁。

4.1 差速驱动结构

差速驱动,顾名思义,靠左右轮的速度差来实现转向。两个独立驱动的轮子,加上一个或两个万向轮做支撑,就构成了最基本的底盘结构。

我习惯把这种结构想象成「坦克转向」——左右履带速度不同,车体就会转弯。只不过轮式底盘更灵活,也更敏感。

核心参数:

  • 轮距(Wheelbase):左右轮中心之间的距离,记作 L
  • 轮半径:驱动轮的物理半径,记作 r
  • 左右轮转速:ω_L 和 ω_R,单位 rad/s

你想想看,如果左右轮转速一样,机器人就走直线。如果左轮比右轮快,机器人就向右转。这个直觉是对的,但具体怎么算,我们需要一套数学工具。

4.2 正运动学解算

正运动学,就是「已知轮速,求机器人速度」。这是里程计计算的基础,也是我调试底盘时最常调用的函数。

差速驱动的正运动学公式其实很简单:

v = (v_R + v_L) / 2
ω = (v_R - v_L) / L

其中:

  • v:机器人线速度(m/s)
  • ω:机器人角速度(rad/s)
  • v_R = ω_R * r:右轮线速度
  • v_L = ω_L * r:左轮线速度
  • L:轮距

嗯,这里要注意:v_R - v_L 的符号决定了转向方向。如果右轮比左轮快,差值为正,机器人逆时针旋转(从上方看)。

我的经验:在实际项目中,轮距 L 的测量误差对里程计影响很大。我曾经因为轮距量错了2毫米,导致机器人转一圈后位置偏差了十几厘米。建议用多次旋转标定法来精确测量轮距。

正运动学在ROS里通常放在 odometry 节点中。每次收到轮速编码器数据,就调用这个公式,然后积分得到位置和姿态。

4.3 逆运动学解算

逆运动学正好反过来——「已知目标速度,求左右轮速」。这是运动控制的核心,说白了就是告诉电机:「你要转多快」。

公式也很直观:

v_R = v + (ω * L) / 2
v_L = v - (ω * L) / 2

然后转换成轮子角速度:

ω_R = v_R / r
ω_L = v_L / r

举个例子:假设机器人想以 0.5 m/s 的速度前进,同时以 0.3 rad/s 的角速度左转,轮距 0.4m,轮半径 0.05m:

v_R = 0.5 + (0.3 * 0.4) / 2 = 0.56 m/s
v_L = 0.5 - (0.3 * 0.4) / 2 = 0.44 m/s

ω_R = 0.56 / 0.05 = 11.2 rad/s
ω_L = 0.44 / 0.05 = 8.8 rad/s

避坑指南:我曾经在逆运动学里忘记除以轮半径,直接把线速度发给电机驱动器,结果机器人原地打转。后来我养成了一个习惯——在代码里加一个单位检查函数,确保输入输出都是物理单位。

4.4 轮速与机器人速度转换

这个转换其实包含两个方向:

  1. 编码器 → 轮速 → 机器人速度(正运动学)
  2. 目标速度 → 轮速 → 电机控制(逆运动学)

在ROS中,我们通常用 geometry_msgs/Twist 消息来表示机器人速度,用 std_msgs/Float64 或自定义消息来表示轮速。

我习惯把转换逻辑封装成一个类,这样代码复用性高:

class DifferentialDriveKinematics:
    def __init__(self, wheel_radius, wheel_base):
        self.r = wheel_radius
        self.L = wheel_base
    
    def forward(self, w_left, w_right):
        """正运动学:轮速 -> 机器人速度"""
        v_left = w_left * self.r
        v_right = w_right * self.r
        v = (v_left + v_right) / 2.0
        omega = (v_right - v_left) / self.L
        return v, omega
    
    def inverse(self, v, omega):
        """逆运动学:机器人速度 -> 轮速"""
        v_right = v + (omega * self.L) / 2.0
        v_left = v - (omega * self.L) / 2.0
        w_right = v_right / self.r
        w_left = v_left / self.r
        return w_left, w_right

这个类我在好几个项目里都用过,从两轮平衡车到四轮差速底盘,核心逻辑都一样。

4.5 知识体系总览

为了让你更直观地理解这一章的内容,我画了一张流程图:

差速驱动运动学知识体系 差速驱动运动学 正运动学解算 逆运动学解算 轮速 → 机器人速度 目标速度 → 轮速 里程计计算 · 运动控制 · 仿真 v = (v_R + v_L)/2 ω = (v_R - v_L)/L v_R = v + ωL/2 v_L = v - ωL/2

这张图把正运动学和逆运动学的关系讲得很清楚。左边是「感知」方向——从轮速推算机器人状态;右边是「控制」方向——从目标速度反推轮速。两者构成了一个闭环。

4.6 实际项目中的注意事项

最后,分享几个我在实际项目中踩过的坑:

  • 轮距不是固定值:轮胎气压、负载变化都会影响有效轮距。我一般在每次启动时做一次标定。
  • 编码器分辨率:分辨率太低会导致低速时速度跳变。我建议至少每转500脉冲以上。
  • 控制频率:ROS中/cmd_vel的发布频率建议在20-50Hz,太低会导致运动不平滑。

差速驱动运动学看起来简单,但真正做好并不容易。把基础打牢,后面的里程计融合才能事半功倍。

小技巧:调试时可以在ROS中用 rqt_plot 实时观察左右轮速和机器人速度,能快速发现运动学模型中的问题。