ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于二自由度横摆动力学的MPC路径跟踪自适应参数调节

基于二自由度横摆动力学的MPC路径跟踪自适应参数调节

做了快三年路径跟踪控制,我一开始迷信MPC,到现在反而对它是又爱又恨。爱的是,基于二自由度横摆动力学的MPC模型足够简洁,却能把侧向动力学和路径跟踪误差揉进一个优化问题里,理论底子扎实;恨的是,当你真的拿它去跑任意路径跟踪时,固定一组权重参数根本撑不住所有场景,只能老老实实做自适应参数调节。这篇文章就围绕“自适应参数调节的自动驾驶控制系统——基于二自由度横摆动力学的MPC任意路径跟踪研究”这个方向,把我踩过坑、验证过的思路完整写出来。适合正在做路径跟踪控制器、天天被权重和时域调参折磨的工程师,也适合想从公式走向实车的学生。

1. 固定权重的MPC为什么在任意路径上“时灵时不灵”

1.1 权重矩阵决定的不是“好坏”,是“取舍”

MPC的代价函数一旦写出来,控制器的性格基本就定了。横向偏差权重给得大,路径贴得紧,但转向动作容易发贼;航向误差权重给得大,车头朝向跟得稳,大曲率弯道又容易出现内切或外抛;控制增量权重给得大,转向平滑、执行器喜欢,但跟踪误差会明显变大。

固定权重的问题不是某个系数选得不对,而是“取舍关系”在变。低速大曲率场景下,车本来就开不快,你希望它咬着参考线走,这时候横向偏差权重不够,车辆会明显切弯;可同一组参数上到高速,参考线曲率不大,车辆对横摆角速度误差非常敏感,这时候如果横向偏差权重还那么大,前轮稍微偏一点,控制器就会猛烈修正,横摆角速度响应严重超调。我见过很多demo在园区里跑得不错,一上高速测试就画龙,根因基本都在这。

固定权重在单一工况里可以调到“足够好”,但任意路径跟踪意味着曲率、车速、附着条件都在变,控制器的“性格”必须跟着变。这也是自适应参数调节最朴素的动机:让权重矩阵、预测时域、约束边界随着工况动态调整,而不是一套参数打天下。

1.2 横摆角速度误差:固定权重最容易遗忘的自由度

很多初版MPC只盯着横向偏差和航向偏差,忽略了一个关键状态——横摆角速度误差。二自由度模型把整车简化成两个自由度:侧向速度 v_y 和横摆角速度 γ。路径跟踪误差方程里,航向误差的导数是 γ - v_x·κ(κ是参考曲率),也就是说横摆角速度是连接“车辆横摆响应”和“参考路径变化率”的桥梁。

如果代价函数里不包含对横摆角速度误差的惩罚,控制器就只知道航向偏了多少,不知道这个偏航速率是不是还在继续恶化。我在某封闭测试场做过对比:固定权重下,参考曲率突变时,航向误差看着不大,但横摆角速度已经超调到 25°/s 以上,车尾明显外摆。把横摆角速度误差权重自适应提上来之后,超调直接压到 10°/s 以内。二自由度模型的价值就在这里——它把横摆这个自由度显式表达出来了,参数调节就应该用它。

1.3 自适应参数不是玄学,是给控制器排序

我从一开始就反对把自适应参数做得花里胡哨。实际工程里最可靠的做法不是在线学习、不是模糊推理,而是基于物理量标定出调度关系:纵向车速 v_x 决定整体激进程度,参考曲率 κ 决定跟踪精度和控制增量的相对权重,附着系数 μ 决定约束边界和软约束松弛量。

这套逻辑本质上是在不同工况下给控制器不同的“优先级”。低速大曲率,精度优先;高速小曲率,稳定优先;低附着路面,安全优先。后面所有权重表、插值逻辑、平滑策略,都是围绕这个优先级展开的。理解了这个动机,再看具体公式就不会晕。

2. 二自由度横摆动力学模型:怎么把整车简化成“自行车”

2.1 自由度到底哪两个,简化了什么

二自由度模型把车辆当成一辆“自行车”——前轴和后轴各自合并成中间的一个车轮,只保留侧向平动和横摆转动两个自由度。它忽略垂向、侧倾、俯仰,也忽略左右载荷转移。对路径跟踪控制来说,这套假设在常规驾驶工况下误差足够小,关键是物理结构极清晰:

m( \dot{v}_y + v_x \gamma ) = 2C_f \alpha_f + 2C_r \alpha_r \ I_z \dot{\gamma} = 2l_f C_f \alpha_f - 2l_r C_r \alpha_r

其中 m 是整车质量,I_z 是绕Z轴的转动惯量,l_f、l_r 是质心到前、后轴距离,C_f、C_r 是前、后轴等效侧偏刚度。前轮侧偏角 α_f 和后轮侧偏角 α_r 写成:

\alpha_f = \delta - \frac{v_y + l_f \gamma}{v_x} \ \alpha_r = - \frac{v_y - l_r \gamma}{v_x}

这里 δ 是前轮转角。注意:侧偏刚度乘了2,表示一根车轴合并了两个车轮。实际标定时,C_f、C_r 不是直接量出来的,而是通过稳态圆周实验或仿真数据辨识得到。我用的初始标定值大致是 m=1500kg、I_z=2600kg·m²、l_f=1.2m、l_r=1.4m,在这个基础上做MPC模型。

2.2 侧偏刚度线性化假设和它的失效边界

二自由度模型最脆弱的假设是侧偏力与侧偏角成正比,也就是 C_f、C_r 是常数。真实轮胎侧偏特性在小侧偏角范围内近似线性,但侧偏角超过大约 4°~6° 后,侧偏力增长速度变缓,进入饱和区。假设还在线性段,控制器就会以为还能输出更大的侧向力,实际已经到附着极限了。

“任意路径跟踪”最容易撞上这个边界:连续急弯、紧急避障、湿滑路面,侧偏角很容易超线性区。解决思路是线性时变MPC(LTV MPC),每个控制周期重新线性化一次模型,把当前工作点附近的等效侧偏刚度更新进去。更实用的做法是给侧偏角加约束,同时把附着系数估计折算到侧偏刚度上:低附着路面直接把等效刚度乘一个 0.6~0.8 的衰减系数。

我个人的经验是:线性假设可以留,但必须知道自己正在靠近边界。MPC的约束和自适应权重里要留出余量,不要等到轮胎饱和了才收敛。

2.3 路径跟踪状态扩展:把车道偏差写进预测模型

纯二自由度模型只描述车辆本身的横摆响应,要跟踪路径,还得把车辆相对参考线的误差状态引进来。常用的是横向偏差 e_y 和航向偏差 e_ψ,并假设航向偏差是小角度:

\dot{e}y = v_y + v_x e\psi \ \dot{e}_\psi = \gamma - v_x \kappa

其中 κ 是参考路径在当前位置的曲率。这个公式非常关键:参考曲率 κ 出现在预测模型里,作为已知的干扰项。很多实现把 κ 漏了,等于在转弯时让MPC靠误差反馈去“追”参考线,稳态横向偏差去不掉。

把车辆状态和路径跟踪误差状态合并,得到连续状态空间方程 \dot{x} = A_c x + B_c δ + d_c,状态取 x = [v_y, γ, e_y, e_ψ]^T,参考曲率放在 d_c 里。离散化我用零阶保持加 20ms 采样周期,实际代码里直接用前向欧拉也能跑,但20ms采样下欧拉法和零阶保持的差别不大,关键在于采样周期和求解器时延要匹配。

3. 自适应参数调节到底在调什么:代价函数权重解析

3.1 代价函数的每一项对应一个物理诉求

把MPC的代价函数展开,去掉矩阵符号的迷惑性,它其实就四件事:横向偏差希望多小、航向偏差希望多小、横摆角速度误差希望多小、控制动作希望多平缓。写成:

J = \sum_{k=0}^{N-1} \left( \mathbf{e}(k)^T \mathbf{Q}(k) \mathbf{e}(k) + \mathbf{u}(k)^T \mathbf{R}(k) \mathbf{u}(k) + \Delta \mathbf{u}(k)^T \mathbf{R}_d \Delta \mathbf{u}(k) \right)

其中 \mathbf{e} 是误差状态向量,\mathbf{Q} 是误差权重矩阵,\mathbf{R} 是控制量权重,\mathbf{R}_d 是控制增量权重。\mathbf{u} 直接惩罚转向角大小,\mathbf{R}_d 惩罚转向角变化率。这俩要分开理解:R大,前轮转角整体偏小,过弯像“含着走”;R_d大,转角变化平缓,但遇上连续弯道会显得迟钝。

自适应调节就是动态改 Q(k)、R_d(k)。方向很明确:低速大曲率,把 e_y 和 e_ψ 的权重抬上去,把控制增量权重压下来,让转向跟手;高速小曲率,把横摆角速度误差和控制增量权重抬上去,宁可有一点点跟踪偏差,也要避免画龙和激振。具体数值不是拍脑袋,我后面给出了一套可启动的表。

3.2 车速和曲率两维查表:最可靠的自适应调度逻辑

我用的是两维查表加线性插值,调度变量取纵向车速 v_x 和参考曲率 κ。核心函数是这个思路:

def compute_weights(vx, kappa_ref, mu_est, table_speed, table_qy, ...): # 先按车速查基础权重 qy_base = interp_linear(vx, table_speed, table_qy) qpsi_base = interp_linear(vx, table_speed, table_qpsi) qgamma_base = interp_linear(vx, table_speed, table_qgamma) rd_base = interp_linear(vx, table_speed, table_rd) # 再用曲率修正横向偏差权重 kappa_scale = 1.0 + 3.0 * abs(kappa_ref) qy_adaptive = qy_base * kappa_scale rd_adaptive = rd_base / max(0.5, math.sqrt(abs(kappa_ref) * 10.0 + 1.0)) # 附着系数打折 slip_factor = 0.6 + 0.4 * mu_est qy_adaptive *= slip_factor qgamma_adaptive = qgamma_base * (2.0 - slip_factor) return qy_adaptive, qpsi_adaptive, qgamma_adaptive, rd_adaptive

注意曲率项的物理逻辑:曲率越大,参考航向变化越快,必须更紧地抓住横向偏差,否则入弯晚、出弯外抛;同时要减小控制增量惩罚,让转向系统敢快点打方向。这两件事必须联动,只调一个会失衡。

车速和曲率查表看似简单,但要处理两个工程细节:一是查表间隔不能太粗,我按10km/h一个点标定,覆盖20到120km/h;二是曲率必须先平滑滤波,否则参考线毛刺会让权重跟着抖。后面还会专门讲权重平滑的问题。

3.3 预测时域、约束边界和权重一起联动

自适应参数调节不只调权重,预测时域 N 也要跟着车速变。我用的规则是保持预测物理时间 T_horizon 在 1.2 到 2.0 秒之间,再除以采样周期得到 N:

N = \max\left(N_{\min}, \text{round}\left(\frac{T_{\text{horizon}}(v_x)}{T_s}\right)\right)

低速时 T_horizon 取小一些,避免预测范围太长导致优化问题“过度思考”;高速时 T_horizon 取大一些,提前看到远处大曲率弯道。N 每次改变会导致QP规模变化,求解时间不稳,所以我把 N 离散成几个档位,而不是连续变化。

约束边界同样要自适应:低速大转角场景,转向角约束可以放宽到 ±35°;高速时收紧到 ±20°,防止紧急变道时驾驶员吓一跳。横向加速度约束按附着系数折算,干燥沥青 3m/s²,湿滑路面压到 1.8m/s²。松弛变量的惩罚权重跟着约束松紧同步缩放,保证QP始终有解。权重、时域、约束三者一起联动,控制器才不会出现“权重说要激进,约束却不让动”的自我矛盾。

4. 任意路径跟踪:从参考路径点到控制指令的完整闭环

4.1 参考路径预处理:曲率平滑比路径拟合更重要

任意路径跟踪的输入不是一条光滑曲线,而是一堆离散点。高精地图、融合定位给出来的点,短距离内往往有噪声。如果不做预处理,MPC预测出来的未来航向参考会异常跳变,控制器会在直道上莫名其妙地修正方向盘。

我先做重采样,把点距统一到 0.5m 左右;然后用三次样条或者B样条拟合,得到连续路径;再计算每个点的航向 ψ_ref 和曲率 κ。曲率计算要用数值微分加滤波,比如五点差分公式。这里最容易踩坑的是:航向能直接用点坐标差分,曲率是航向的导数,噪声会被放大一次,所以曲率滤波的截止频率要比航向滤波低很多。

投影方面,MPC预测用的参考线是在Frenet坐标系下逐步向前推进的。为了快速找到车辆当前在参考线上的投影点,我用KD-Tree做粗搜索,再在当前索引附近做小范围精搜索。实际运行中,车辆速度高时投影点弧长要预报一点点,补偿控制周期内的移动量,否则误差状态总是滞后半拍。

4.2 单控制周期的LTV MPC流程

任意路径跟踪的LTV MPC,每个周期要做下面几件事:

  1. 获取车辆状态(侧向速度、横摆角速度、位置、航向),估计或读取纵向车速和附着系数;
  2. 把当前点投影到参考线,得到 e_y、e_ψ,并向后取预测时域内的参考点序列,记录每个点对应的 κ 和 ψ_ref;
  3. 计算自适应权重和预测时域 N,更新约束;
  4. 基于当前工作点更新 A、B、d 矩阵,构造QP;
  5. 调用嵌入式QP求解器,得到最优控制增量序列;
  6. 只取第一拍控制量,发送给转向执行器,其余丢弃。

核心是第2步:参考曲率序列是逐点不同的,不是常数。高速冲进一个弯道,控制器看到的前方曲率是渐增的,预测模型里每一行干扰项都不一样。如果还用定常参考模型,MPC在弯道里的前瞻性就没了。代码骨架大致是这样:

def mpc_control_step(state, ref_path, vehicle_param, current_vx, mu_est): # 投影并生成参考序列 arcs, kappa_seq, psi_ref_seq = ref_path.project_and_sample(state, horizon_len, current_vx) ey_start, epsi_start = ref_path.compute_lateral_errors(state) # 自适应参数 qy, qpsi, qgamma, rd = compute_weights(current_vx, kappa_seq[0], mu_est) N = compute_horizon_len(current_vx) # 建立线性时变预测矩阵(省略矩阵拼装细节) A_dyn, B_dyn, d_ref = build_ltv_matrices(vehicle_param, current_vx, kappa_seq, Ts) # 求解QP,取第一拍 delta_u_opt = solve_qp(A_dyn, B_dyn, d_ref, ey_start, epsi_start, qy, qpsi, qgamma, rd, constraints) return delta_u_opt # 只发送第一拍

这个流程看着简单,真正难的是矩阵拼装和索引对齐,多一个维度错位,控制效果就会非常诡异。建议用单元测试把参考序列和预测矩阵的行列关系锁死。

4.3 实时性:20ms控制周期是怎么压下来的

MPC的实时性瓶颈在QP求解。我之前用内点法求解器,20ms周期内偶尔会超时,尤其是在N比较大、约束又多的时候。后来换到ADMM类的嵌入式求解器,单次求解普遍能在3到8ms内完成,加上矩阵刷新和参考线处理,整体控制周期能稳定压到20ms以内。

压实时性的几个关键手段:一是矩阵预先分配,不在控制周期内动态申请内存;二是把参考线投影做成增量式,不用每周期全量重算;三是对QP设置最大迭代次数,即使没完全收敛也拿当前最优解出去,控制器天然有鲁棒性。

时延补偿也要做。从状态采样到控制指令输出,经过求解、总线传输、执行器响应,总时延大约 30 到 50ms。如果不补偿,高速时转向相位滞后,表现为弯道外抛。我的做法是:预测模型里把状态向前推一拍,模拟30ms之后的状态作为当前起点;执行器模型的纯滞后用一阶惯性加死区时间近似,塞进预测方程里。这一步对高速任意路径跟踪的稳定性影响极大。

4.4 约束冲突与软约束:自适应参数的最后一公里

MPC相比LQR最大的工程优势就是能处理约束,但约束处理不好也是翻车重灾区。硬约束在某些极端工况下会让QP无解,比如前方曲率急剧增大,预测时域内需要超过转向速率限制才能跟住路径。如果直接把转向速率设成硬约束,求解器报错,控制器直接退出。

我的处理是把所有执行器约束都做成软约束,加入松弛变量 \epsilon:

J_{\text{soft}} = J + \rho |\epsilon|^2

\rho 要设成比状态权重高一个量级,让松弛量在正常情况下几乎为0,只在极端情况下被激活。转向角约束用 ±35° 硬机械限位+软约束双重保护;转向速率约束用 ±30°/s 的软约束;横向加速度约束按附着系数自适应。这样自适应参数在工作点边缘剧烈变化时,控制器仍然能给出合理控制指令,而不是崩溃。

5. 实测工况结果与调参血泪

5.1 三组对比:固定权重 vs 自适应权重

在封闭测试场和仿真平台上,我跑了三类典型工况:180°回头弯、高速S弯、紧急变道。对比的核心指标是最大横向偏差、横摆角速度峰值和控制量高频抖动次数。

工况控制策略最大横向偏差横摆角速度峰值控制量抖动次数/100s
180°回头弯 40km/h固定权重0.46m24°/s37
180°回头弯 40km/h自适应权重0.21m13°/s6
高速S弯 80km/h固定权重0.33m19°/s52
高速S弯 80km/h自适应权重0.18m9°/s9
紧急变道 60km/h固定权重0.51m27°/s74
紧急变道 60km/h自适应权重0.29m17°/s15

当然这些数字和具体车辆参数强相关,不能直接搬走,但趋势是一致的:自适应权重主要赢在“横摆角速度峰值”和“抖动次数”,也就是赢在稳定裕量上。横向偏差也改善明显,但不如稳定性改善那么夸张。

5.2 三个最常踩的坑

坑一:权重跳变导致转向指令跳变。查表插值如果只在车速维度做,曲率突然升高时横向偏差权重跟着曲率突变,控制器会瞬间“变性格”,方向盘出现一次明显冲击。对策是给所有调度输出加一阶低通滤波,时间常数取 0.15 到 0.3 秒,让权重平滑过渡。我一开始图省事没加,高速进弯时方向盘抖到手麻。

坑二:漏了参考曲率前馈。二自由度MPC预测模型里如果没有按每个预测步的 κ 计算航向误差变化,直道没问题,稳态过弯时横向偏差会稳定在一个偏大的值,怎么调权重都压不下去。解决方法是把参考曲率作为已知干扰项放进预测模型,同时可以做前馈转角项 \delta_{ff} = L \cdot \kappa(L是轴距)叠加到MPC输出上,能明显减轻反馈负担,但这种前馈要经过标定,不能盲目加。

坑三:附着系数估计不准,自适应反而帮倒忙。μ 估计值跳动很快时,约束和权重同步变化,控制器会出现间歇性振颤。我加了一阶惯性滤波和变化率限制,让 μ 在 1 秒内最多变化 0.2。低附着工况宁可保守一点,也不要让参数跟着噪声走。

5.3 一套能启动的自适应参数初始值

给一组可参考的启动值,注意这是针对中型轿车、采用前轮转向、二自由度单车模型的MPC。实际部署一定要重新标定。

车速区间e_y权重基准e_ψ权重基准γ误差权重基准控制增量权重预测时域N横向加速度约束
0~30km/h8.04.01.50.6122.5m/s²
30~60km/h5.06.03.01.2153.0m/s²
60~90km/h3.08.06.02.5182.5m/s²
90km/h以上1.510.010.04.0202.0m/s²

这套初始值的取向很明显:高速时横摆角速度误差权重远高于横向偏差权重,控制增量权重也加大,牺牲一点跟线精度换稳定性。低速时反过来,权重向跟踪精度倾斜。曲率修正项和附着打折项按 4.2 节的方式叠加。

拿这套参数上车的步骤是:先固定工况逐个标定查表点,再叠加曲率修正,最后开自适应调节和软约束。不要第一次就把所有自适应逻辑全打开,否则出问题根本定位不了是权重、模型、还是参考线的问题。

最后说一点个人体会:二自由度横摆动力学模型加MPC的组合,理论门槛不算低,但真正决定系统好不好用的,往往是参数自适应这一圈“脏活”。权重表、平滑策略、约束软硬、附着修正,哪一项偷懒,实车都会立刻给你脸色看。做这套东西,耐心比聪明重要,先让控制器在简单工况下做到“不吓人”,再去追求性能上限。我踩过最深的坑就是急着调参数,忽略了预测模型里参考曲率的一致性,结果花了两周排查一个“玄学”问题,最后发现只是矩阵里一行索引错了。希望这篇能帮你少走点弯路。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进