车辆运动学模型:从几何到状态方程
各位同学,今天我们来聊聊无人车路径跟踪里最基础、也最核心的一块——车辆运动学模型。说实话,我刚开始做无人驾驶那会儿,总觉得运动学模型太简单,不就是个几何关系吗?直到有一次在园区测试,车辆在低速转弯时出现了明显的跟踪偏差,排查了半天才发现是模型简化过头了。嗯,从那以后,我对运动学模型的每个推导细节都不敢马虎。
说白了,运动学模型就是描述车辆怎么动的数学工具。它不考虑力、质量、惯性这些动力学因素,只关注几何约束下的运动关系。对于低速场景(比如园区物流、自动泊车),运动学模型已经足够精确;对于高速场景,我们才需要引入动力学模型。今天这一讲,我们重点攻克三个知识点:自行车模型、阿克曼转向几何、以及状态方程的建立。
核心观点: 运动学模型是路径跟踪的"底层语言"。你模型建得准,控制器才能控得稳。我见过太多同学一上来就调PID参数,结果模型本身就有问题,调来调去都是白费功夫。
2.1 自行车模型:把四轮简化成两轮
先问大家一个问题:一辆四轮汽车,在低速转弯时,四个轮子的转向角一样吗?
答案是否定的。前轮左右两个轮子的转角其实不一样——内侧轮转角更大,外侧轮转角更小。这是为了满足阿克曼转向几何的要求。但如果我们直接对四轮建模,状态变量太多,控制器设计会变得非常复杂。
所以,我们引入一个经典简化:自行车模型。
自行车模型的核心思想很简单:把车辆的前后轴分别合并成一个虚拟的轮子。前轮代表转向轮,后轮代表驱动轮。这样一来,四轮车就变成了一个两轮自行车。我个人习惯用这个模型做路径跟踪的初步设计,因为它抓住了车辆运动的核心几何关系,又足够简洁。
自行车模型的假设条件如下:
- 车辆在平坦路面上行驶,忽略垂向运动
- 轮胎侧偏角为零(即轮胎方向与速度方向一致)
- 车辆为刚体,不考虑悬架变形
- 低速行驶,忽略离心力影响
你看,这些假设其实挺强的。但实际项目中,只要车速低于5m/s,这些假设基本成立。我曾经在自动泊车项目里用这个模型,效果出奇的好。
下面我用SVG画一张自行车模型的几何关系图,方便大家理解:
从图中可以看到,后轮方向固定(不转向),前轮可以偏转一个角度 δ。轴距 L 是前后轮之间的距离。当车辆转弯时,所有轮子绕同一个圆心 O 做圆周运动。这个圆心位于后轮轴线的延长线上。
根据几何关系,转弯半径 R 与轴距 L、前轮转角 δ 的关系是:
R = L / tan(δ)
这个公式太重要了。我当年做路径跟踪时,每次调参都要回头看看这个公式——它决定了车辆的最小转弯半径,也就决定了路径的曲率上限。
实战技巧: 实际车辆的前轮转角 δ 通常有物理限制,比如 ±35°。代入公式可以算出最小转弯半径。如果你的参考路径曲率超过了这个极限,控制器再怎么调也跟不上的。我在一个园区项目中就踩过这个坑,路径规划给的弯太急,跟踪误差直接炸了。
2.2 阿克曼转向几何:让四个轮子各司其职
刚才的自行车模型把四轮简化成两轮,但实际车辆的前轮左右转角是不同的。这就引出了阿克曼转向几何。
阿克曼转向几何的核心思想是:车辆转弯时,所有轮子的转向中心必须交于一点。这样才能保证轮子纯滚动,没有滑动摩擦。
具体来说,对于前轮转向的车辆:
- 内侧前轮转角 δi 大于外侧前轮转角 δo
- 后轮不转向,但左右后轮的转速不同(差速器的作用)
- 四个轮子的速度方向都垂直于轮子到圆心 O 的连线
阿克曼几何的数学关系如下:
cot(δ_o) - cot(δ_i) = w / L
其中,w 是轮距(左右轮之间的距离),L 是轴距。δo 是外侧轮转角,δi 是内侧轮转角。
你想想看,如果左右轮转角一样,会怎么样?
嗯,那样的话,内侧轮和外侧轮的转弯半径不同,但转角相同,必然导致其中一个轮子产生滑动摩擦。低速时还好,高速时轮胎磨损严重,而且车辆稳定性会变差。
我在做自动代客泊车项目时,发现车辆在狭窄车位里反复揉库,轮胎磨损特别快。后来检查发现,是阿克曼几何的标定参数偏了。重新标定后,问题就解决了。所以,阿克曼几何不是理论上的花架子,它直接影响车辆的实际表现。
| 参数 | 符号 | 典型值 | 说明 |
|---|---|---|---|
| 轴距 | L | 2.5~3.0 m | 前后轴之间的距离 |
| 轮距 | w | 1.5~1.8 m | 左右轮之间的距离 |
| 最大转角 | δmax | 30°~40° | 前轮最大转向角 |
| 阿克曼率 | η | 0.8~1.0 | 实际阿克曼与理想阿克曼的比值 |
注意: 实际车辆的阿克曼几何往往不是完美的。受悬架、转向机构变形的影响,阿克曼率 η 通常小于 1.0。这意味着内侧轮的转角比理论值略小。在高速过弯时,这种偏差会被放大,导致车辆出现不足转向或过度转向。我曾经在高速测试中遇到过不足转向导致车辆推头的情况,差点冲出赛道。所以,模型里最好留一个阿克曼率的修正参数。
2.3 车辆状态方程建立:从几何到微分方程
好了,有了自行车模型和阿克曼几何的基础,我们终于可以建立车辆的运动学状态方程了。
状态方程描述的是车辆状态随时间的变化规律。对于运动学模型,我们关心的状态变量通常包括:
- x:车辆在大地坐标系下的横坐标
- y:车辆在大地坐标系下的纵坐标
- θ:车辆的航向角(车头方向与 x 轴的夹角)
- v:车辆的速度(沿车头方向)
- δ:前轮转角
状态方程的形式是:
dx/dt = v * cos(θ)
dy/dt = v * sin(θ)
dθ/dt = v * tan(δ) / L
这个方程组看起来简单,但内涵丰富。我来逐条解释一下:
- dx/dt 和 dy/dt:速度 v 在 x 和 y 方向上的投影。说白了,就是车往哪个方向走,就把速度分解到两个坐标轴上。
- dθ/dt:航向角的变化率,也就是车辆的横摆角速度。它等于 v * tan(δ) / L。注意,这里的分母是轴距 L,所以轴距越长,同样的转角产生的横摆角速度越小——大车转弯更"迟钝"。
你可能会问:为什么横摆角速度公式里没有出现阿克曼几何的轮距 w?
问得好。这是因为自行车模型已经将左右轮合并了,所以轮距 w 被隐含地"平均"掉了。如果你需要更精确的模型,可以引入阿克曼率 η 来修正前轮转角:
δ_effective = η * δ_command
其中 δ_command 是控制器输出的转角指令,δ_effective 是实际作用到自行车模型上的等效转角。
下面我用SVG画一个状态方程的逻辑流程图:
在实际代码中,我们通常用离散化的方式来实现状态方程。比如用欧拉法:
// 离散化状态更新(欧拉法)
double dt = 0.01; // 控制周期 10ms
void updateState(double v, double delta, double &x, double &y, double &theta) {
// 计算导数
double dx = v * cos(theta);
double dy = v * sin(theta);
double dtheta = v * tan(delta) / L;
// 积分更新
x += dx * dt;
y += dy * dt;
theta += dtheta * dt;
// 航向角归一化到 [-π, π]
theta = atan2(sin(theta), cos(theta));
}
这段代码我用了很多年,简单可靠。但要注意几个细节:
- 控制周期 dt:不能太大,否则积分误差会累积。我一般用 10ms,对于低速场景足够了。
- 航向角归一化:θ 会随着时间累积,如果不做归一化,数值会越来越大,影响后续计算。
- tan(δ) 的奇点:当 δ 接近 ±90° 时,tan(δ) 会趋于无穷大。实际中 δ 有限制,但代码里最好加个限幅保护。
个人经验: 如果你用欧拉法发现跟踪精度不够,可以试试四阶龙格-库塔法(RK4)。我在一个高精度泊车项目中,用 RK4 替代欧拉法后,跟踪误差从 5cm 降到了 1cm 以内。代价是计算量大了 4 倍,但对于现代嵌入式处理器来说,完全不是问题。
最后,我想强调一点:运动学模型虽然简单,但它是整个路径跟踪系统的基石。你后面学到的纯跟踪算法、Stanley 方法、MPC 控制器,本质上都是在求解这个状态方程的反问题——给定目标路径,反推出需要的控制输入 v 和 δ。
所以,请务必把这一节的内容吃透。我当年花了整整一周时间,手推了不下 50 遍状态方程,才真正理解每个参数的含义。现在回想起来,那段时间的投入非常值得。
好了,这一讲就到这里。记住:模型是控制的上限,算法只是逼近这个上限的手段。模型建不好,后面的一切都是空中楼阁。