3. 差速底盘运动学模型:左右轮独立驱动原理
聊到移动机器人,差速底盘绝对是最经典的结构之一。我个人习惯把它叫做「两轮差速」——两个驱动轮各自独立,再加一个或两个万向轮撑着。说白了,就是靠左右轮的速度差来实现转向。
你想想看,如果左右轮速度一样,车就走直线。如果左边快右边慢,车就往右拐。反过来,左边慢右边快,就往左拐。极端情况,左右轮速度大小相等、方向相反——原地转圈。这就是差速底盘最核心的思想。
核心要点:差速底盘没有专门的转向机构,转向完全由左右轮的速度差产生。
3.1 左右轮独立驱动原理
我在项目中遇到过不少新手,上来就问:「为什么不用舵机转向?」嗯,差速底盘的优势在于结构简单、成本低、控制灵活。你只需要两个电机,两个驱动器,一个控制器,就能让机器人满屋子跑。
左右轮独立驱动,意味着每个轮子都有自己的电机和编码器。控制器给左右轮分别发速度指令,编码器反馈实际转速。这里有个坑——我曾经在调试时发现,两个同样的电机,给同样的PWM,转速居然不一样。为什么?
原因很简单:电机本身有制造公差,地面摩擦也不均匀,电池电压波动也会影响。所以,闭环控制是必须的。我建议至少用PID做速度闭环,否则运动学算得再准,实际跑起来也是歪的。
| 驱动方式 | 左轮速度 | 右轮速度 | 底盘运动 |
|---|---|---|---|
| 直线前进 | v | v | 向前直行 |
| 右转 | v + Δv | v - Δv | 向右转弯 |
| 左转 | v - Δv | v + Δv | 向左转弯 |
| 原地旋转 | +ω | -ω | 绕中心旋转 |
3.2 线速度与角速度推导
好,现在我们来推公式。别怕,其实很简单。
先定义几个参数:
- vL:左轮线速度
- vR:右轮线速度
- L:左右轮间距(轮距)
- v:底盘中心的线速度
- ω:底盘绕中心旋转的角速度
底盘中心的线速度,其实就是左右轮速度的平均值:
v = (vL + vR) / 2
角速度呢?想想看,左右轮速度差会导致底盘旋转。轮距L越大,同样的速度差产生的角速度越小。公式是:
ω = (vR - vL) / L
这里要注意符号约定。我习惯定义:逆时针旋转为正。所以如果右轮比左轮快,ω为正,底盘逆时针转。嗯,这个约定在ROS里也是通用的。
个人经验:轮距L的测量要精确。我曾经用卷尺量,误差5mm,结果机器人走10米就偏了30度。后来我用游标卡尺量,再跑直线就好多了。建议L的测量误差控制在1mm以内。
3.3 前向运动学公式
前向运动学,说白了就是「已知左右轮速度,求底盘怎么动」。上面两个公式合起来就是完整的前向运动学模型:
v = (vL + vR) / 2
ω = (vR - vL) / L
写成矩阵形式更清晰:
[ v ] [ 1/2 1/2 ] [ vL ]
[ ω ] = [ -1/L 1/L ] [ vR ]
这个2x2矩阵就是前向运动学矩阵。你给它左右轮速度,它吐出底盘的速度和角速度。
有了v和ω,我们还能进一步推算底盘的位置变化。假设dt时间内,底盘移动了:
Δx = v * cos(θ) * dt
Δy = v * sin(θ) * dt
Δθ = ω * dt
这就是航迹推演(Odometry)的基础。我在做AGV项目时,就是靠这个公式推算位置,配合编码器数据,精度能做到厘米级。
注意:航迹推演有累积误差。轮子打滑、地面不平、编码器分辨率不够,都会让误差越来越大。我曾经在瓷砖地面上跑,误差每小时累积超过1米。后来加了IMU做融合,才压住误差。
3.4 知识体系结构图
下面这张图,是我梳理的差速底盘运动学知识体系。你可以把它当作本章的「地图」:
3.5 代码实现示例
最后,给一个简单的C语言实现。我在STM32上跑过类似的代码,效果不错:
// 差速底盘前向运动学计算
typedef struct {
float v; // 线速度 (m/s)
float omega; // 角速度 (rad/s)
} ChassisState;
ChassisState forwardKinematics(float vL, float vR, float wheelTrack) {
ChassisState state;
state.v = (vL + vR) / 2.0f;
state.omega = (vR - vL) / wheelTrack;
return state;
}
// 航迹推演更新
void updateOdometry(float vL, float vR, float wheelTrack, float dt) {
ChassisState state = forwardKinematics(vL, vR, wheelTrack);
// 更新位姿
robot.x += state.v * cos(robot.theta) * dt;
robot.y += state.v * sin(robot.theta) * dt;
robot.theta += state.omega * dt;
// 角度归一化到 [-PI, PI]
if (robot.theta > M_PI) robot.theta -= 2 * M_PI;
if (robot.theta < -M_PI) robot.theta += 2 * M_PI;
}
避坑指南:我曾经在角度归一化上吃过亏。如果不做归一化,theta会一直累加,浮点数精度问题会导致角度漂移。另外,dt要用定时器精确测量,不要用delay——那玩意儿不准。
好了,差速底盘运动学就聊到这儿。核心就是两个公式、一个矩阵、一段代码。你动手写一遍,跑一跑,比看十遍都管用。
公众号:蓝海资料掘金营,微信deep3321