基于MPC的自适应巡航控制(ACC)设计与仿真实践
1. 项目概述为什么我想自己写一套MPC-ACC控制器最近在做一个车辆纵向控制相关的项目核心就是围绕“基于MPC的自适应巡航控制”展开。先说人话自适应巡航控制ACC就是让车子能自动跟着前车走前车慢我也慢前车快我也快没前车的时候就回到自己设定的巡航速度。传统的ACC大多是基于PID或者线性二次型调节器LQR做的效果也不错但一旦遇到前车急刹、旁边车道突然切入这种复杂工况约束处理就很别扭。所以我这次直接用MPC——也就是模型预测控制来重新设计整个ACC控制器。MPC最核心的优点就一句话它能“看一步走一步”通过滚动优化在一段未来时域内同时平衡跟车精度、舒适性和安全性而且约束条件可以直接写死在优化问题里不像PID那样要靠限幅器或者逻辑切换去强行保护。这篇文章我想完整记录一下这套系统的设计思路、建模方法、控制器推导、仿真验证过程以及我在调参和工程化时踩过的一些坑。适合正在做车辆纵向控制、智能驾驶决策规划的人参考尤其是学生或者刚接触MPC的工程师。你要是有PID版本的ACC经验看这篇会更有感觉如果完全没接触过我也尽量把每个环节的背景讲清楚保证你能跟上。2. 从动力学模型到间距策略控制器设计的“地基”MPC这种算法的特点决定了它对被控对象的数学模型依赖很大。模型不要求多复杂但要能反映系统的主要动态特性而且要适合在嵌入式平台上快速求解。这一节我从建模开始一层一层把控制器的输入输出关系理清楚。2.1 车辆纵向动力学建模思路这里我采用的是一种在ACC工程实践中非常常见、也好用的分层架构上层是MPC轨迹规划与跟踪控制器输出期望加速度下层是执行器控制把期望加速度换算成节气门开度或者制动压力。这样分层的理由是油门制动执行器本身的非线性很强如果全部塞进MPC模型里问题会变得很难解工程上很少这么干。在建立MPC内部模型时取三个核心状态量x1是间距误差也就是当前实际车距d减去期望车距d_desx2是相对车速即前车车速v_lead减去自车车速v_hostx3是自车车速v_host。控制输入u是期望加速度a_des。这个模型忽略了发动机和刹车的具体惯性时间常数直接用一阶惯性环节近似纵向执行器的延迟响应时间常数取0.3秒到0.5秒之间。这个值我是实际标定出来的不同的车差别很大电动车响应快一些燃油车靠传动系统延迟会明显一些。离散化采用前向欧拉法采样周期取0.1秒这样在车速控制器里是比较常见的配置。模型的输出就是状态本身不需要额外设计观测矩阵。这个模型很“瘦”但它抓住了影响ACC控制品质的三个关键量距离误差、速度差和自车速度足够了。2.2 间距策略与约束条件怎么选期望车距d_des是ACC控制器最关键的参考量它不能是一个恒定值这在前车低速或者停车时会造成危险。我采用的是固定时距策略CTHd_des d0 tau * v_host其中d0是停车时的最小安全距离我取2米也就是堵车跟停时两车之间留下的余量tau是时距系数单位是秒一般在0.8到2.2秒之间。时距越大跟车距离越远安全性越高但容易被别的车频繁加塞时距太小近距离跟车会让人紧张。我在仿真里取1.2秒这个值介于保守和激进之间。基于这个间距策略我能写出第一个约束车距必须始终大于最小安全距离。这个约束其实包含了动态的量因为d_des本身随v_host变化。约束条件还包括加速度约束舒适性层面一般限制在-3到2米每二次方秒。这个范围对应一般城市道路的舒适制动和正常加速。再一个约束是车速范围下限0上限可以是道路限速或者用户设定的巡航速度。这些都是硬约束MPC在求解时就必须严格满足绝对不能越界。2.3 参数选择采样时间、预测时域、控制时域我在这套系统里用的采样周期是0.1秒原因有三个一是车辆纵向控制本身对延迟不敏感到毫秒级0.1秒足够完成一次优化解算和数据更新二是这个周期和大部分车辆CAN总线发送周期匹配实用性好三是预测时域可以在合理范围内取得更长获得更好的前瞻性。预测时域Np取20步对应2秒的预测窗口。控制时域Nc取5步对应0.5秒的优化自由度。为什么Np取20而Nc取5呢预测时域太短控制器就会“鼠目寸光”临近约束了才反应太长则会大幅增加决策变量的维数导致计算量激增。控制时域没必要等于预测时域因为对未来较远时刻的控制量精确求解意义不大反而会增加QP问题的复杂度所以只优化前0.5秒的控制序列之后的控制量保持最后一步不变就足够了。这些参数不是拍脑袋定的我先用几组典型工况做了灵敏度测试发现Np小于15时面对前车急减速距离误差会明显偏大Np大于30时实时性开始变差。最终2秒预测窗口是一个比较均衡的选择。你可以根据自己的计算平台性能进行调整但逻辑上需要先做这种灵敏度分析再定参数而不是直接照搬别人的一套数值。3. MPC控制器设计与求解把“踩多少刹车”变成一个数学问题模型建立后下一步就是把控制目标转化为一个能在每个周期实时求解的优化问题。这也是MPC最“劝退”新手的地方公式一多就劝退。但拆开来看核心就三个事代价函数怎么写、约束怎么变成标准形式、求解器怎么调。3.1 代价函数设计跟踪性、舒适性、经济性如何平衡ACC控制从控制目标上可以拆成三层诉求距离跟踪间距误差要尽量小不能离前车太远那样会不断被加塞速度跟踪自车车速要平滑逼近前车车速或者说在定速巡航模式下逼近设定巡航速度舒适性和经济性期望加速度的幅值不能太“躁”最好还能抑制加速度的变化率也就是加加速度jerk。我把这三个目标加权成一个累计代价函数形式是J Σ(w1 * 间距误差平方) Σ(w2 * 相对速度平方) Σ(w3 * 自车车速与设定车速之差平方) Σ(r1 * 期望加速度平方) Σ(r2 * 加速度变化量平方)其中前三项是状态代价后两项是控制代价。w和r是权重我最终调试出的一组比较均衡的数值是w11.0w20.5w30.8r10.1r20.3。这个权重的含义是距离误差偏差1米带来的代价等于加速度0.1米每二次方秒持续作用的代价之和这样比例下来才能保证距离偏差不会演变成追尾风险同时又不会让控制量因权重过大而显得畏首畏尾。特别强调一下r2这一项它惩罚的是两拍之间的控制增量Δu。这是抑制控制量抖动的关键。如果没有这一项你会在仿真里看到期望加速度在相邻周期之间来回跳实测到车上就是油门和刹车频繁切换乘员感觉非常差而且执行器寿命也会缩短。3.2 约束条件建模与规范化把约束写成适合求解器处理的矩阵不等式形式是这步的重点。这里最需要注意的是约束里的耦合项。比如最小车距约束它同时涉及多个状态量甚至涉及控制量本身因为期望车距里含有当前车速。更常见的做法是把距离约束表达成关于间距误差的线性不等式x1(ki) -x1_safe(i)其中x1_safe是根据不同预测步数换算来的安全间距误差阈值。同理加速度约束是直接对u做上下限限制因为它本身就是优化变量车速约束则是对状态量x3的线性限制。所有的约束组合成一个统一的线性不等式系统A_ineq * U ≤ b_ineq其中U是未来Nc步的控制量序列。这样做以后整个优化问题就变成一个标准凸二次规划QP问题数学性质和求解器实现都非常成熟。3.3 二次规划求解与实时实现二次规划问题的标准求解形式是min 0.5 * U^T * H * U f^T * U其中H由预测模型矩阵和代价权重矩阵计算而来f则包含当前状态反馈项。我在仿真验证阶段用的是MATLAB的MPC工具箱做快速原型验证它会自动把模型和代价函数转成QP形式并求解。到了工程实现阶段就需要在C代码里嵌入一个QP求解器。我实测过几个开源求解器OSQP和qpOASES表现比较可靠。OSQP的数值稳定性好适用于约束较多的情况qpOASES的求解速度快代码体积小更适合资源紧张的嵌入式环境。在2GHz的Cortex-A系列处理器上Np20、Nc5时单次求解时间大概在1到3毫秒之间远小于0.1秒的采样周期实时性完全没问题。这一节的技术方案如果用一句话总结就是把驾驶意图翻译成一个约束极值问题然后交给数值算法去解。关键不是会调API而是理解H矩阵和f向量里每一项的物理含义否则后期调参会非常痛苦。4. 仿真验证先在一个简单的仿真平台里跑通逻辑MPC控制器设计完没法直接上车实测必须先在仿真环境里验证逻辑正确性和参数合理性。我用的方法是先建一个简化的交通场景在Simulink里把自车模型、前车模型、传感器和控制器全部组装起来然后跑几个典型工况。4.1 仿真场景设计与验证流程我设计了三个仿真场景分别覆盖ACC最典型的三种情况。第一个是定速巡航场景前方没有车自车从静止加速到设定的巡航速度80公里每小时然后保持匀速。这个场景验证的是MPC的速度跟踪能力如果控制器在速度收敛过程中出现明显的超调或者来回震荡就说明速度项权重或者预测时域需要调整。第二个是跟车减速场景前车以60公里每小时匀速行驶自车从80公里每小时接近前车MPC需要提前减速并保持期望时距。这个场景重点验证防碰撞约束和跟踪性能之间的平衡。第三个是前车紧急制动场景前车突然以最大制动减速度停车看自车能否安全停下且不剧烈冲击。建好模型后我把每个仿真场景的结果记录成间距曲线、车速曲线和加速度曲线考察三个指标最大间距误差、最大制动减速度、以及稳态时的车距误差收敛值。4.2 仿真结果与核心指标分析从仿真结果来看MPC-ACC控制器在三个场景里都表现出了比较理想的性能。在定速巡航场景里自车以约1.2米每二次方秒的加速度平滑提速约17秒后达到设定车速并稳定车速超调量不到2%。在跟车减速场景里自车会在前车距离还比较远时就开始温和减速减速过程非常线性没有出现急刹点头的情况稳态时距误差能够收敛到0.3米以内。在紧急制动场景里自车能够保持最小车距大于1.8米没有碰撞风险但制动减速度达到约-3.5米每二次方秒这已经接近舒适性边界了说明在极端工况下安全约束确实会主动牺牲一定舒适性来换取安全余量。这些结果自己在工程里可以用一个简易的评估表记录下来每个场景记录指标、目标值和实测值便于后续快速定位问题是出在哪个环节。4.3 和传统PID控制器的对比结果为了验证MPC是否真的带来了收益我在同一套仿真模型里实现了一个PID版ACC作为对照组PID参数也在同样工况下做了整定优化。对比结果很有意思。在温和工况下PID的效果其实和MPC差距不大稳态误差都能收敛得很好。差异主要体现在两个地方第一是约束处理。当面临前车紧急制动时PID版的加速度输出会短暂冲出舒适边界甚至逼近执行器极限而MPC由于把加速度约束写死在了优化问题中输出被严格限制在设定范围内反应是“提前”和“克制”的。第二是控制量的平滑性。PID在切换控制模式时会产生明显的控制量突变MPC则因为代价函数中带有Δu惩罚项整个控制过程平滑得多。这组对照实验让我对MPC的工程价值有了更直观的理解MPC不是数据上压倒性的胜利而是在“安全边界内优化”这件事上结构性地比PID更适合自动驾驶场景。5. 实际工程中的坑与调试经验算法仿真跑通了离真正能用还差很远。我把这几个月攒下来的调试经验和踩坑经历整理一下。很多坑是资料里不会明说的但遇到的时候特别浪费时间。5.1 突出问题模型失配与参数鲁棒性我遇到的第一坑是模型失配。MPC性能高度依赖内部模型但实际车辆的执行器响应受温度、载重、坡度影响很大。比如我仿真里用的执行器时间常数是0.4秒实际车辆在不同挡位下的响应时间可能偏差一倍。实测中最直接的表现就是仿真里一切完美实车测试时车速响应滞后距离误差始终压不下去。解决思路是给系统加扰动补偿也就是在状态预测时引入一个扰动项用于补偿建模误差和外部干扰同时在代价函数里增加针对扰动的鲁棒性调参自由度。另一个务实的做法是不要把执行器模型参数定得太“精确”给MPC的内部模型加一点保守的延迟控制器就会更“怂”一点实际表现反而更稳。5.2 求解器不稳定与数值处理第二个坑是QP求解器在极限工况下的数值稳定性问题。当约束密集且状态接近边界时H矩阵可能病态求解器会偶尔报错或者直接返回不可行解。这一个问题让我连续排查了三天。最后发现是两个原因叠加造成的一是状态变量的量纲差异太大。车速是30米每秒量级间距误差是米量级加速度是米每二次方秒量级直接放进优化问题会导致H矩阵条件数很差。解决方案是归一化把每个状态除以一个特征尺度让它们在数值上都在0.1到10之间。二是预测时域长的时候模型预测矩阵的条件数会指数增长这时需要加一个很小的正则化项到H矩阵上把矩阵“撑”得更健康一些。5.3 模式切换与目标切换的平滑策略第三个坑是模式切换冲击。ACC系统通常有两种模式定速巡航模式和跟车模式。当前方车道从无车变为有车或者前车变道离开时控制目标会发生跳变如果直接切换控制器的代价函数输出的期望加速度很容易跳变。我的解决方案是引入一个平滑过渡层当模式切换条件满足时不是立即切换到新的目标而是将新目标与旧目标做时间上的线性插值过渡时间约0.5到1秒。这样的效果是在模式切换过程中车辆就像驾驶员在温和地改变意图不会出现突然的顿挫感。同理在一个目标前车丢失、需要切换到另一个目标前车的场景里目标切换逻辑也要做滞后确认防止目标短暂丢失导致的频繁切换。5.4 关于量产落地的一些想法最后聊聊这套技术实际的量产前景。MPC-ACC相比传统PID-ACC优势在约束处理和全局优化上确实很明显这也是这几年智能驾驶域控制器算力不断变强之后越来越多的厂商重新审视MPC工程化价值的原因。但它的落地瓶颈也很现实标定参数多不同车型需要重新优化权重QP求解器需要通过功能安全认证周期很长控制效果对传感器数据质量和状态估计精度非常敏感。从工程角度我建议先做“小步快跑”式的落地先在高端车型或者某个特定功能上用MPC做ACC积累数据和应用经验再推广到更多产品线。纯粹的MPC ACC可能不是最终答案MPC与学习方法的结合、或者带学习能力的自适应MPC会是这个方向上一个更有潜力的演进路线。这套系统我目前还在持续迭代最近在尝试把参考轨迹生成模块从固定时距策略改成考虑驾驶员风格的变时距策略也在测试把决策规划和控制统一到一个优化框架里的可能性。MPC这个工具在车辆纵向控制里最大的魅力在于它给了你一个优雅的数学框架去表达各种复杂的约束和优先级而不是靠堆各种if else逻辑。我相信在算力持续升级的背景下它是ACC乃至整个纵向运动控制的主流方向之一。