车辆运动学模型:自行车模型(Bicycle Model)推导、运动学约束、前轮驱动与四轮驱动模型
各位同学,今天我们聊一个非常经典的话题——自行车模型。说实话,我在做车辆控制的前几年,一直觉得这玩意儿太简单了,不就是两个轮子嘛。直到有一次在实车测试中,我用了一个过于复杂的模型,结果算出来的控制量根本跑不动,最后发现——嗯,自行车模型其实够用了。
为什么叫“自行车模型”?
你想想看,一辆真正的自行车,前轮转向,后轮驱动。我们把四轮汽车简化成两个轮子,前轮代表转向轮,后轮代表驱动轮。说白了,就是把左右轮合并到中心线上。
这样做的好处是什么?
- 忽略横向载荷转移——左右轮的差异被平均化
- 忽略轮胎侧偏特性——假设车轮纯滚动
- 只保留几何关系——位置、航向角、速度
我在项目中遇到过这样的情况:用自行车模型做路径跟踪,在低速场景下(比如泊车、园区低速巡航),效果出奇的好。但上了高速,轮胎开始打滑了,这模型就不太灵了。记住,自行车模型是运动学模型,不是动力学模型。
自行车模型的推导
我们来看核心推导。假设车辆是一个刚体,前后轮都是纯滚动,没有侧向滑动。那么车辆的运动状态可以用三个量描述:
- x:车辆后轴中心位置的x坐标
- y:车辆后轴中心位置的y坐标
- θ:车辆的航向角(车头朝向与x轴夹角)
前轮转角记为 δ,轴距为 L。
那么,后轴中心的速度方向,一定是沿着后轮朝向的。后轮不能侧滑,所以速度方向就是车身的朝向。于是有:
ẋ = v * cos(θ)
ẏ = v * sin(θ)
θ̇ = (v / L) * tan(δ)
这就是最经典的自行车模型运动学方程。你看,三个方程,简洁明了。
核心要点:θ̇ 的推导来自于几何关系——前轮转向时,车辆绕瞬时旋转中心做圆周运动。旋转半径 R = L / tan(δ),角速度 ω = v / R = v * tan(δ) / L。
运动学约束
自行车模型隐含了两个重要的运动学约束:
- 非完整约束:车辆不能横向移动。也就是说,速度方向必须与车身朝向一致。数学表达为:ẋ * sin(θ) - ẏ * cos(θ) = 0。
- 转向约束:前轮转角 δ 有物理极限,一般乘用车在 ±30° 到 ±40° 之间。我见过一些新手直接把 δ 设到 45°,结果仿真里车原地打转——现实中根本做不到。
注意:非完整约束意味着车辆不能像人一样横着走。你倒车入库时,需要来回调整方向,就是因为这个约束在起作用。我曾经在自动泊车项目中,因为忽略了非完整约束,规划出来的路径根本不可执行——车没法直接平移进车位。
前轮驱动 vs 四轮驱动模型
自行车模型本身不区分驱动方式。但实际控制中,驱动方式会影响速度 v 的控制方式。
| 驱动方式 | 控制输入 | 特点 |
|---|---|---|
| 前轮驱动 | 前轮转速 + 前轮转角 | 加速时前轮易打滑,转向与驱动耦合 |
| 后轮驱动 | 后轮转速 + 前轮转角 | 转向与驱动解耦,操控性好 |
| 四轮驱动 | 四个轮速 + 前轮转角 | 牵引力大,但模型复杂 |
在自行车模型框架下,我们通常把驱动方式简化为:
- 前轮驱动:速度 v 由前轮转速决定,但前轮同时负责转向。这时候要注意,如果前轮转角很大,再猛加速,前轮很容易失去抓地力。我调试过一个前驱的物流小车,在急转弯时加速,车头直接推出去——这就是转向不足。
- 四轮驱动:速度 v 由四个轮子共同决定。在自行车模型中,我们通常假设四个轮子的转速一致,或者用一个等效的驱动轮来表示。但实际中,四驱车的扭矩分配会影响车辆的横摆响应。
我的建议:如果你刚开始做车辆控制,先用后轮驱动的自行车模型。为什么?因为转向和驱动解耦,调试起来简单。等把路径跟踪搞明白了,再考虑前驱或四驱带来的耦合效应。
代码实现示例
下面是一个简单的自行车模型仿真代码,用Python写的。我习惯用这种方式快速验证控制算法:
import numpy as np
class BicycleModel:
def __init__(self, L=2.5, dt=0.01):
self.L = L # 轴距
self.dt = dt # 时间步长
self.x = 0.0
self.y = 0.0
self.theta = 0.0
def step(self, v, delta):
# 运动学更新
self.x += v * np.cos(self.theta) * self.dt
self.y += v * np.sin(self.theta) * self.dt
self.theta += (v / self.L) * np.tan(delta) * self.dt
# 角度归一化到 [-pi, pi]
self.theta = np.arctan2(np.sin(self.theta), np.cos(self.theta))
return self.x, self.y, self.theta
# 使用示例
car = BicycleModel(L=2.5)
for t in range(100):
x, y, theta = car.step(v=1.0, delta=0.1)
print(f"t={t*0.01:.2f}s: x={x:.2f}, y={y:.2f}, theta={theta:.2f}")
这段代码很简单,但足够用来测试你的控制算法了。我曾经用这个模型配合纯跟踪算法,在仿真里跑出了完美的圆形轨迹——当然,实车测试时又是另一回事了。
避坑指南
最后,分享几个我踩过的坑:
- 我曾经在仿真中把时间步长设得太大(0.1秒),结果车辆轨迹出现明显的锯齿。后来改成0.01秒,问题解决。记住,运动学模型对离散化误差很敏感。
- 我曾经忽略了角度归一化,结果航向角越积越大,最后控制算法直接崩溃。θ 一定要保持在 [-π, π] 范围内。
- 我曾经在实车测试时,发现自行车模型预测的轨迹和实际轨迹偏差很大。后来一查,是轮胎气压不足导致滚动半径变了。嗯,模型再准,也架不住物理世界的不确定性。
好了,自行车模型就讲到这里。下一章我们会在这个模型基础上,加入轮胎动力学,变成更完整的动力学模型。到时候你会发现,自行车模型虽然简单,但它是理解更复杂模型的基础。