3. 车辆运动学模型

各位同学,大家好。今天我们聊一个非常基础但又极其重要的内容——车辆运动学模型。说实话,我在刚入行那会儿,总觉得运动学模型太简单,不就是个几何关系嘛。直到有一次在实车测试中,因为模型精度不够,导致车辆在泊车时蹭到了路沿……嗯,从那以后,我再也不敢小看这个“简单”的模型了。

3.1 为什么需要运动学模型?

你想想看,自动驾驶系统要控制车辆,总得知道车接下来会怎么动吧?运动学模型就是干这个的。它描述了车辆在不考虑力和力矩的情况下,纯粹由几何约束决定的运动关系。

说白了,运动学模型回答三个问题:

  • 车现在在哪儿?(位置)
  • 车头朝哪儿?(航向角)
  • 打方向盘后,车会怎么走?(运动趋势)

我个人习惯把运动学模型比作“车辆的骨架”,动力学模型则是“肌肉和神经”。做规划控制时,我们先用骨架搭好框架,再考虑肌肉的力量。这样分层处理,问题会清晰很多。

3.2 自行车模型(Bicycle Model)

这是最经典的简化模型。为什么叫自行车模型?因为它把四轮车辆等效成两轮——前轮和后轮各一个,就像自行车一样。

核心假设:

  • 车辆左右对称,左右轮转角相同
  • 忽略车辆的侧倾和俯仰
  • 轮胎无侧偏(纯滚动)
  • 车辆在平面内运动

我在项目中遇到过一个问题:用自行车模型做路径跟踪,结果在低速时效果很好,一上高速就偏差很大。后来发现,高速时轮胎侧偏不可忽略,这时候就得用动力学模型了。所以记住:自行车模型适用于低速场景(一般 < 10 m/s)。

自行车模型的运动学方程如下:

状态变量:
  x  : 车辆后轴中心 x 坐标
  y  : 车辆后轴中心 y 坐标
  θ  : 车辆航向角(车头朝向与 x 轴夹角)
  δ  : 前轮转角
  v  : 车辆纵向速度

运动学方程:
  dx/dt = v * cos(θ)
  dy/dt = v * sin(θ)
  dθ/dt = v * tan(δ) / L
  其中 L 为轴距(前后轮距离)

这里有个细节要注意:dθ/dt 就是横摆角速度。你想想看,如果 δ=0,车直行,横摆角速度就是0。如果 δ 很大,转弯半径就小,横摆角速度就大。这个关系在规划中非常常用。

3.3 阿克曼转向模型(Ackermann Steering Model)

自行车模型假设左右轮转角相同,但实际车辆不是这样的。真实车辆转弯时,内侧轮转角比外侧轮大,这样才能保证所有车轮绕同一个圆心转动——这就是阿克曼转向原理。

阿克曼转向几何关系:

cot(δ_out) - cot(δ_in) = T / L

其中 δ_out 为外侧轮转角,δ_in 为内侧轮转角,T 为轮距,L 为轴距。

实际中,我们通常用等效前轮转角 δ 来近似:δ ≈ (δ_in + δ_out) / 2

我曾经在调试自动泊车功能时,发现车辆总是停偏。排查了半天,最后发现是阿克曼转向的补偿没做好。内侧轮和外侧轮的转角差如果不考虑,泊车轨迹会偏差十几厘米——这在狭窄车位里就是灾难。

阿克曼转向模型和自行车模型的关系是这样的:

对比项 自行车模型 阿克曼转向模型
车轮数量 等效2轮 实际4轮
左右轮转角 相同 不同(满足阿克曼几何)
适用场景 规划、控制算法设计 精确轨迹计算、实车标定
计算复杂度 低 中

在实际工程中,我建议:做规划算法时用自行车模型,做控制执行时用阿克曼模型。这样既保证了效率,又兼顾了精度。

3.4 状态空间表示

有了运动学方程,我们怎么在计算机里表示它?答案是状态空间模型。

状态空间表示说白了就是:把系统写成 x_dot = f(x, u) 的形式。

对于自行车模型:

状态向量:x = [x, y, θ, δ, v]^T
控制输入:u = [δ_dot, a]^T  (前轮转角速度、加速度)

状态方程:
  x_dot = v * cos(θ)
  y_dot = v * sin(θ)
  θ_dot = v * tan(δ) / L
  δ_dot = u[0]
  v_dot = u[1]

为什么要把系统写成状态空间形式?因为后续的模型预测控制(MPC)、线性二次型调节器(LQR)等算法,都直接基于状态空间模型。你想想看,如果连状态方程都写不出来,后面的控制算法根本没法用。

注意:状态空间模型中的状态变量必须是最小完备集。什么意思?就是这些变量足以描述系统的全部运动状态,且没有冗余。比如,如果你已经知道 x, y, θ,就不需要再单独存一个“车头方向向量”了。

3.5 离散化方法

计算机是离散的,而车辆运动是连续的。所以我们需要把连续的运动学方程离散化。

常用的离散化方法有三种:

  1. 欧拉法(Euler Method):最简单,但精度一般
  2. 龙格-库塔法(Runge-Kutta):精度高,计算量稍大
  3. 零阶保持法(ZOH):假设控制输入在采样间隔内不变

我个人最常用的是欧拉法,因为它在大多数规划场景中已经够用了。代码实现如下:

// 欧拉法离散化
// dt: 采样时间间隔
// x_k: 当前状态
// u_k: 当前控制输入

function discreteStep(x_k, u_k, dt) {
    // 计算导数
    dx = v_k * cos(theta_k);
    dy = v_k * sin(theta_k);
    dtheta = v_k * tan(delta_k) / L;
    ddelta = u_k[0];
    dv = u_k[1];
    
    // 更新状态
    x_next = x_k + dx * dt;
    y_next = y_k + dy * dt;
    theta_next = theta_k + dtheta * dt;
    delta_next = delta_k + ddelta * dt;
    v_next = v_k + dv * dt;
    
    return [x_next, y_next, theta_next, delta_next, v_next];
}

经验之谈:采样时间 dt 的选择很关键。dt 太大,离散化误差大;dt 太小,计算量太大。我一般取 dt = 0.05s(20Hz)作为基准,然后根据场景调整。高速场景用更小的 dt,低速场景可以适当放大。

3.6 本章知识体系

为了让大家更直观地理解本章的知识结构,我画了一张图:

车辆运动学模型知识体系 自行车模型 阿克曼转向模型 状态空间表示 核心内容 • 等效两轮模型 • 低速场景适用 • 忽略轮胎侧偏 核心内容 • 内外轮转角不同 • 绕同一圆心转动 • 实车标定必备 核心内容 • x_dot = f(x, u) • 最小完备状态集 • 控制算法基础 离散化方法 欧拉法 | 龙格-库塔法 | 零阶保持法 应用:MPC / LQR / 路径规划 / 轨迹跟踪

从这张图可以看出,自行车模型和阿克曼模型是运动学描述的两种方式,状态空间表示是它们的数学抽象,而离散化方法则是连接连续模型和数字计算机的桥梁。最终,这些知识都服务于上层控制算法。

3.7 避坑指南

最后,分享几个我踩过的坑:

我曾经犯过的错误:

  • 直接用自行车模型做高速路径跟踪,结果车辆剧烈振荡——后来加了动力学补偿才解决
  • 离散化时 dt 取得太大(0.1s),导致轨迹出现锯齿——改成 0.05s 后就好了
  • 状态空间表示中漏掉了 δ 这个状态,导致控制量无法约束——这个bug查了我两天

嗯,今天就讲到这里。运动学模型虽然基础,但它是整个规划控制算法的基石。希望大家课后能动手写一下代码,把自行车模型离散化,然后做个简单的圆周运动仿真。你会发现,理论到实践之间,还有不少细节需要打磨。