
聊一个大半年前就欠下的学习笔记。当时我在Apollo平台上验证控制算法默认配置是横向LQR配纵向PID常规城区低速场景跑得非常顺。直到有一次在仿真里做高速双移线问题来了车辆进第二个弯时纵向控制器还在按参考速度给油横向控制器为了追线已经把方向盘打到接近极限两个控制器在轮胎抓地力极限上互相较劲车子直接甩了出去。也就是从那天起我开始认真研究横纵向耦合控制最后把方案收敛到了MPC上。这篇笔记就是那个阶段从建模、仿真到算法落地的完整记录适合正在接触Apollo控制模块、或者想搞清楚MPC怎么处理横纵向耦合问题的朋友尤其是那些已经在解耦控制器上吃过亏、想往极限工况再走一步的工程师。1. 为什么要研究横纵向耦合控制先说结论不是所有场景都需要横纵向耦合控制但一旦到了轮胎附着极限附近解耦控制很容易变成“各管各的”最后谁也管不好。1.1 解耦控制在极限工况下的瓶颈Apollo默认控制架构大家应该都熟悉。Planning模块输出一条带速度、加速度、曲率信息的轨迹Control模块里横向控制器负责跟踪路径纵向控制器负责跟踪速度两套控制器独立计算互不通信。横向LQR拿到参考轨迹的横向偏差和航向偏差输出前轮转角纵向PID拿到速度误差输出油门或制动踏板量。这种架构在常规场景下没有任何问题。车辆行驶在中低速、良好路面横向控制产生的侧向加速度不大纵向控制也不会做出剧烈加减速两个控制器的输出范围离轮胎极限很远耦合效应弱到可以忽略。一旦工况变得极限事情就不一样了。拿我踩过的那个高速双移线场景来说参考速度80km/h第二个弯道曲率比较大。纵向控制器看到当前速度低于参考速度继续给油车辆在弯道中加速侧向加速度需求跟着增大前轮需要更大的侧向力。但轮胎的总抓地力是有上限的纵向加速已经占用了一部分附着力剩余能给横向用的越来越少。横向LQR没有感知到轮胎纵向力在“抢资源”只看到横向偏差越来越大于是把方向盘越打越深直到前轮侧偏角超过线性区车辆推头冲出车道。问题本质不是某个控制器调得不好而是两个控制器在物理层面共享同一个轮胎附着力约束却在算法层面完全不知道对方的存在。1.2 耦合效应的三个物理层面横纵向耦合不是说说的概念它体现在三个非常具体的物理层面。先说运动学层面。路径的曲率本身就给纵向速度设置了上限。学过车辆动力学都知道稳态过弯时侧向加速度约等于v_x²除以曲率半径。当曲率固定时速度越快需要的侧向加速度越大。一旦侧向加速度需求超过轮胎能提供的极限车辆就失控了。这个约束在Planning里通常会考虑但Planning用的是一套简化模型到了控制这一层真实车辆的响应误差会累积。如果控制器不做横纵向协调就很难在极限边缘守住这个约束。再说动力学层面。这就是轮胎摩擦椭圆的问题。轮胎能提供的合力受μF_z限制纵向力F_x和横向力F_y各自的分量必须满足F_x² F_y² ≤ (μF_z)²。加速时F_x增大留给F_y的余量就变小弯道中的转向能力随之下降。反过来转弯时F_y占用大量附着力此时再强行制动前轮很容易抱死导致失去转向能力。这个约束在解耦控制里没有任何一个控制器会去显式建模。最后是车辆状态层面。纵向加速度会引起轴荷转移。急加速时前轴载荷降低、后轴载荷增加前后轮侧偏刚度随之改变车辆转向特性会向不足转向方向偏移。急减速时相反前轴载荷增加车辆趋向过多转向。这意味着同一个横向控制器在加速和制动工况下面对的车辆动态特性是完全不同的。LQR的增益矩阵如果固定不变就只能在一种工况下表现最优其它工况只能靠鲁棒性硬扛。这三个层面叠加起来就是极限工况下解耦控制失控的完整物理图景。要处理好这个问题就必须让一个统一的控制器同时看到横向和纵向的状态在优化过程中自动协调转向和加减速这就是横纵向耦合MPC的动机。2. MPC基础与Apollo控制模块现状在说耦合MPC之前先把MPC本身的基本逻辑过一遍然后看看Apollo默认控制模块是怎么组织的最后再聊切入点。2.1 MPC三要素预测模型、滚动优化、反馈校正MPC不是个新东西它的核心思想概括起来就是在当前时刻基于系统模型预测未来N步的状态在满足约束的前提下求一个最优控制序列但只执行第一步下一时刻重新来一遍。这个框架由三个部分组成。预测模型负责回答“如果我现在这么控制未来系统会怎样”。对车辆控制来说预测模型就是车辆动力学方程精度直接决定控制效果上限。滚动优化负责回答“从当前状态出发未来N步内怎么做最好”这是个带约束的优化问题求解出最优控制序列。反馈校正负责消除模型误差和扰动带来的偏差因为模型不可能完全准确预测的结果和真实状态会有差距所以每个控制周期要基于最新测量的状态重新求解形成一个闭环。可以用下棋来类比。普通反馈控制像是在走一步看一步只关注当前这一步的偏差。MPC则像是走一步想三步不仅看当前这步怎么走还要考虑后面几步怎么走才能整体最优。而且每走一步都会重新评估全局这就是滚动优化的含义。2.2 Apollo默认横纵向控制架构以常见的Apollo 6.0/7.0版本为例。控制模块入口在modules/control内部按控制器类型组织。横向控制器用的是LQR状态包含横向偏差、横向偏差变化率、航向偏差、航向偏差变化率输出前轮转角并带一个曲率前馈项用于补偿稳态误差。纵向控制器用的是级联PID结构外环是位置/速度环内环是加速度/油门环同时还结合了标定表来估计油门和制动的执行量。这个架构在实际工程中表现很成熟。LQR在车辆模型线性化点上做最优状态反馈计算量极小实时性极好。PID更是简单可靠调参经验丰富。问题只在于横向控制器把纵向速度当成时变参数一条轨迹上不同点的速度变化会影响LQR的增益但LQR不会主动去改变速度来帮助横向控制纵向控制器更是完全不关心横向偏差的状态除非收到上游规划的限制否则它就只顾自己的速度目标。所以严格来说Apollo默认没有真正的横纵向耦合控制。它有一些前馈项比如横向控制器的曲率前馈包含车速项这算是一种弱耦合但远远不是让两个控制器协同优化。2.3 在Apollo上做耦合MPC的切入点在Apollo上做横纵向耦合MPC有几个天然的有利条件。代码结构上控制模块是插件化的可以仿照已有的LatController、LonController实现一个新的MpcController在control_conf.pb.txt里配置启用。数据流上Localization提供车辆位姿和速度Planning提供参考轨迹Chassis提供车辆底盘反馈信号这些全部现成不需要额外适配。更重要的一个切入点是Apollo的仿真环境。SimControl可以在没有实车的情况下验证控制器DreamView提供场景可视化还能通过Scenario工具配置双移线、麋鹿测试这类标准测试场景。这意味着可以在不碰代码底层、不碰硬件的情况下把耦合MPC的算法逻辑完整验证一遍。我的建议是不要一上来就动Apollo的C代码。先在MATLAB或Python里把MPC算法原型验证好模型参数用手头车辆的数据然后用Apollo的参考轨迹作为输入跑离线对比确认效果优于解耦控制之后再移植到C里。工程上少了这一步直接改控制模块代码调试周期会拉得特别长而且很难区分是算法问题还是代码集成问题。3. 横纵向耦合MPC建模详解这是整篇笔记的核心。建模的好坏直接决定控制器能不能用误差大的模型会让MPC做出荒谬的预测——在极限工况下这很危险。所以这一章我按模型选型、约束建模、代价函数、数值处理四个层次来写。3.1 车辆模型选型与状态设计横纵向耦合MPC首先要选一个同时包含横向和纵向状态的车辆模型。这里有两类选择运动学模型和动力学模型。运动学自行车模型假设轮胎无侧偏车辆运动满足几何约束。它形式简单适合低速泊车、园区接驳这类场景但到了中高速轮胎侧偏不可忽略运动学模型的精度就不够了。动力学自行车模型将轮胎侧偏纳入建模是当前学术界和工程界做横纵向耦合MPC最常用的模型。在Apollo的场景里如果目标是城区中低速运动学模型足够如果目标覆盖高速工况必须上动力学模型。我建议直接上手动力学模型因为后面想扩展到极限工况时模型底子是现成的不用推倒重来。动力学自行车模型把车辆简化为前后两个轮子忽略左右轮差异只考虑车辆的横向、纵向和横摆三个自由度。在耦合MPC中状态向量建议这样设计[ x [s, e_y, e_\psi, v_x, v_y, \omega, \delta]^T ](s)沿参考线的弧长(e_y)车辆质心到参考线的横向偏差(e_\psi)车辆航向与参考线航向的偏差(v_x)纵向速度(v_y)侧向速度(\omega)横摆角速度(\delta)前轮转角控制输入向量可以定义为[ u [a_{x_des}, \dot{\delta}]^T ]其中(a_{x_des})是期望纵向加速度(\dot{\delta})是前轮转角变化率。把(\dot{\delta})作为控制量而不是直接控制(\delta)是为了在代价函数里对转向平顺性做约束避免MPC给出跳变的转向指令。模型的动力学方程如下这些方程是核心中的核心。基于Frenet坐标系的横向偏差和航向偏差变化率为[ \dot{e}y v_x \sin(e\psi) v_y \cos(e_\psi) ]小角度假设下简化为[ \dot{e}y \approx v_x e\psi v_y ][ \dot{e}_\psi \omega - \kappa(s) v_x ]其中(\kappa(s))是参考路径在弧长(s)处的曲率。这个式子意味着车辆沿曲线路径行驶时航向角的变化率等于横摆角速度减去参考路径本身的航向变化率。耦合的关键正在这里——(v_x)同时出现在横向偏差方程和航向偏差方程中纵向速度直接决定横向偏差的动态特性。纵向、横向和横摆三个自由度的动力学方程为[ \dot{v}_x a_x v_y \omega ][ \dot{v}y \frac{F{yf} F_{yr}}{m} - v_x \omega ][ \dot{\omega} \frac{l_f F_{yf} - l_r F_{yr}}{I_z} ]轮胎侧偏力在线性区可以表示为[ F_{yf} -C_f \alpha_f, \quad F_{yr} -C_r \alpha_r ]前轮和后轮的侧偏角为[ \alpha_f \frac{v_y l_f \omega}{v_x} - \delta, \quad \alpha_r \frac{v_y - l_r \omega}{v_x} ]注意这里(v_x)出现在分母上。如果车速趋近于零侧偏角会趋于无穷大模型数值上会爆炸所以实现时必须对(v_x)做下限保护一般设(v_x \geq 0.1 m/s)才行。纵向方程中(a_x)是期望加速度但实际作用在车辆上的纵向力还要克服滚动阻力和空气阻力。如果模型里要精确一点纵向方程可以写成[ m\dot{v}x F_x - F{roll} - F_{aero} ][ F_{roll} c_r m g, \quad F_{aero} \frac{1}{2} \rho C_d A v_x^2 ]在这一版模型里纵向速度(v_x)是状态量而不是参数这就是横纵向耦合在数学上的实质。转向和加减速通过同一个动力学方程互相影响MPC在滚动优化中会自然地把这种影响纳入决策。3.2 约束建模摩擦椭圆与执行器限制MPC一个核心优势是能直接在优化问题里嵌入约束。横纵向耦合MPC最重要的约束就是摩擦椭圆。轮胎的附着力不是无限的。某个轮胎能提供的最大摩擦力受(\mu F_z)限制(\mu)是路面附着系数(F_z)是轮胎垂直载荷。纵向力和横向力必须满足[ F_x^2 F_y^2 \leq (\mu F_z)^2 ]这不是线性约束直接放进QP里会比较麻烦。工程上常用的处理方式是线性化或多边形近似。先做多边形近似把摩擦圆用内接正六边形或正八边形代替。这种做法实现简单求解快适合前期验证。缺点是边界比真实摩擦圆保守因为多边形内接于圆实际用到的附着力比理论极限略小但换来的是约束线性、QP可以直接求解。更精细的做法是在每个控制周期的工作点附近做一阶线性化。假设当前工作点的纵向力是(F_{x0})那么剩余的横向附着力上限可以线性近似为[ F_{y_max} \approx \sqrt{(\mu F_z)^2 - F_{x0}^2} ]然后把线性化后的约束加入QP。这种做法精度高但要注意工作点变化大时线性化误差会积累必要时在几步之内重新线性化。执行器约束相对直接。前轮转角有物理极限一般乘用车转向范围在±35度左右方向盘转角还要乘上转向传动比。转向角变化率也要限制EPS电机响应速度有限。纵向加速度受发动机/电机的动力上限和制动系统能力限制不同车速下能提供的最大加速度和最大制动减速度各不相同。这些约束都可以从标定数据里查表得到。除执行器约束外还可以加舒适性约束。比如纵向jerk限制在±2 m/s³以内侧向加速度限制在某个值以下。MPC的好处是这些约束可以按需加上代价是约束越多求解越慢实际使用时要权衡。3.3 代价函数设计与QP转化有了模型和约束下一步就是定义什么叫做“控制得好”。代价函数就是把控制目标量化。横纵向耦合MPC的代价函数需要同时包含横向偏差、航向偏差、速度跟踪误差、控制量幅值和控制量变化率。一个典型的形式是[ J \sum_{i1}^{N} \left[ e_y(i)^T Q_y e_y(i) e_\psi(i)^T Q_\psi e_\psi(i) (v_x(i) - v_{ref}(i))^2 Q_v a_x(i)^T R_a a_x(i) \delta(i)^T R_\delta \delta(i) \right] ][\sum_{i0}^{N-1} \left[ \Delta \delta(i)^T R_{\Delta\delta} \Delta \delta(i) \Delta a_x(i)^T R_{\Delta a} \Delta a_x(i) \right] ]这里(Q_y)是横向偏差权重(Q_\psi)是航向偏差权重(Q_v)是速度跟踪权重(R_a)、(R_\delta)是控制量幅值惩罚(R_{\Delta\delta})、(R_{\Delta a})是控制量变化率惩罚。代价函数里权重矩阵的设计是门艺术。最核心的原则是量纲一致。横向偏差单位是米数值一般在0.01到0.5之间航向偏差单位是弧度数值一般小于0.1速度误差单位是米每秒数值可能到几米每秒。如果直接把这三个量放在同一个代价函数里而不做归一化数值大的项就会主导优化结果。比如速度误差的数值远大于航向偏差如果不做处理MPC会拼命压制速度误差而忽略航向偏差导致横向跟踪变差。解决办法有两个。一是做归一化把各项除以该变量的最大允许值让所有项都落在相近的数量级。二是通过权重调节把不同数量级拉到同一个水平线上。我比较推荐归一化因为权重本身反映的是控制优先级不应该承担量纲换算的任务。转换到标准QP形式时把未来N步的控制输入和状态拼成一个大的决策向量(Z)整个代价函数可以写成[ \min_Z \quad \frac{1}{2} Z^T H Z g^T Z ][ \text{s.t.} \quad L_b \leq A Z \leq U_b ]其中(H)矩阵由(Q)和(R)拼装而成(A)矩阵编码了状态转移约束和执行器约束。这个QP问题可以用OSQP、qpOASES这类开源求解器求到最优解。3.4 线性化、离散化与数值处理动力学模型是非线性的而每一帧的MPC求解需要在线性化后的模型上进行。标准做法是在当前工作点对非线性方程做泰勒展开保留一阶项得到线性时变模型[ x(k1) A_k x(k) B_k u(k) d_k ]其中(A_k)是状态矩阵(B_k)是控制矩阵(d_k)是线性化残差。由于工作点每帧都在变化所以每个控制周期都要重新计算一次(A_k)、(B_k)。离散化方法我推荐零阶保持或者前向欧拉。零阶保持的精度更高实现也简单对采样时间在10到50毫秒的车辆控制来说完全够用。数值处理上有几个坑值得注意。一个是(v_x)在分母上的项低速时必须做下限保护。另一个是线性化点要选择当前的实际状态而不是参考轨迹上的名义状态否则模型误差会叠加。还有一点是矩阵的数值条件数刚度和质量、惯量的量级差距很大构建(A_k)矩阵时建议先做归一化条件数不能太离谱否则QP求解器迭代次数会剧增甚至收敛失败。4. 实操从仿真到实车的落地步骤建模完成后最关键的环节是把控制器跑起来。这一章记录我在Apollo和外部仿真环境里做验证时整理的完整实操流程。4.1 快速搭建验证环境我的建议分成三步走Python原型验证、Apollo仿真验证、实车/硬件在环验证。Python原型验证阶段推荐用casadi或者cvxpy配合OSQP。cvxpy建模直观适合快速验证代价函数和约束casadi更灵活适合后面扩展到非线性MPC时用。车辆模型用第3章的动力学自行车模型参数取一台典型中型轿车的数值参数数值单位整车质量 (m)1600kg横摆转动惯量 (I_z)2500kg·m²质心到前轴距离 (l_f)1.20m质心到后轴距离 (l_r)1.45m前轮侧偏刚度 (C_f)80000N/rad后轮侧偏刚度 (C_r)90000N/rad路面附着系数 (\mu)0.85-采样时间 (T_s)0.05s轨迹直接用Apollo Planning的输出格式生成一条带曲率和速度信息的参考线。在离线回放模式下把参考轨迹输入给MPC控制器看它能否在满足加速度和转角约束的前提下跟踪轨迹。Python验证跑通之后再进Apollo环境。在modules/control/controller目录下新增mpc_controller目录实现mpc_controller.h和mpc_controller.cc继承Controller基类重写Init、ComputeControlCommand和Reset方法。求解器用OSQPApollo代码库里已经有OSQP的依赖不需要额外引入。4.2 调试流程与调参顺序调参顺序是新手最容易搞乱的部分。一上来就想把横向偏差、速度误差、控制平顺性同时调好基本都会失败。我的经验是分阶段调。第一阶段先调横向跟踪。把纵向速度跟踪权重设为零让MPC只负责横向跟踪。给定一个中等速度的参考轨迹调节(Q_y)、(Q_\psi)让横向偏差收敛。此时如果轨迹跟踪还发散一定不是MPC的问题而是车辆模型参数错了或者坐标转换有bug先排查这两项再继续。第二阶段加纵向速度跟踪。把(Q_v)从小到大慢慢加观察速度跟踪误差和横向偏差的变化。此时应该能直观地看到耦合效应加大(Q_v)之后MPC为了让速度更贴近参考值会牺牲一部分横向跟踪精度在弯道处出现可容忍的横向偏差。这正是横纵向耦合控制应该有的行为它是在找全局最优而不是局部最优。第三阶段加控制量变化率惩罚。此时如果方向盘指令有抖动就加大(R_{\Delta\delta})。如果纵向加速度频繁跳变就加大(R_{\Delta a})。记住一个原则(R_{\Delta\delta})和(R_{\Delta a})不是越大越好太大以后控制器会变得迟钝弯道里响应慢反而导致跟踪误差变大。以刚好消除抖振为最合适的值。最后阶段加摩擦椭圆约束并验证极限工况。把摩擦椭圆约束加进QP重新跑高速双移线和麋鹿测试对比解耦控制器的表现。这一步能看到耦合MPC的差异——在轮胎附着极限附近加摩擦约束的MPC会有更平滑的轨迹并且不会出现“一边全力加速一边猛打方向”的失控情况。4.3 关键参数参考表与初始值下面给出一组经过仿真验证的初始参数值可以作为调参的起点参数初始值调整方向说明预测时域 (N)20车速越高N应适当减小否则求解负担大采样时间 (T_s)20~50ms控制频率实车一般用50ms与Apollo控制周期一致(Q_y)100横向偏差权重跟踪精度不足时增大(Q_\psi)50航向偏差权重通常小于(Q_y)(Q_v)10速度跟踪权重纵向优先级高时增大(R_\delta)1000转向角惩罚抖动时增大(R_a)100加速度惩罚舒适性优先时增大(R_{\Delta\delta})100转向率惩罚消除方向盘抖动(R_{\Delta a})50加速度变化率惩罚平滑纵向冲击前轮转角约束±0.6 rad注意不同车型的转向机极限不同转向率约束±0.5 rad/s防止方向盘突变预测时域的选择值得单独说一下。(N20)配合50ms采样时间预测长度是1秒。这个长度对高速工况来说略短但对低速城区工况是够用的。如果车速在25m/s以上建议把采样时间降到20ms这样同样的预测时域能覆盖1秒以上的前方路径否则MPC看不到足够的曲率变化预测优势就发挥不出来。还要注意一点N太大带来的问题不仅仅是求解变慢。预测时域过长模型误差累积严重远期预测本来就不准反而会引入噪声。所以MPC不是预测越长越好要跟模型精度和工况匹配。4.4 执行器延迟补偿实车和仿真最大的差异之一就是执行器延迟。转向系统从指令到实际转角响应一般有100到200毫秒的纯延迟制动系统更夸张响应延迟可能达到200到300毫秒。这个延迟在解耦控制里影响还不算致命因为LQR的反馈增益有相位余量。但在MPC里如果不处理延迟预测模型和实际情况在时间上就对不齐——MPC在时刻(k)计算的控制量要等到(kd)才能作用到系统上而MPC预测时假设控制量立即生效。处理办法是延迟补偿。在预测模型里加上一个执行器动态的近似把纯延迟建模为一阶惯性环节或者保留几个采样周期的延迟状态。具体做法是在状态向量里保留之前的控制指令历史预测时把控制量延迟若干步再作用到车辆模型上。另一种工程上更简单的方法是测量延迟的统计值在输入侧做时间对齐把当前时刻的参考轨迹前移延迟时间再给到MPC。这个做法简单有效但要求延迟时间相对稳定。5. 常见问题与排查技巧实录这一章把我在调试过程中遇到的典型问题整理成速查表每个问题都给出排查思路和解决办法。这些问题都不是教科书上会讲的全部来自实际踩坑。5.1 求解器超时怎么办MPC求解超时是最常见也最让人头疼的问题。现象是控制周期不稳定有的周期求到了解有的周期算不完控制器输出跳变。排查思路从三个方向入手。第一看QP问题的数值条件。如果(H)矩阵条件数很大OSQP总会卡在几百上千次迭代里可以把eps_abs和eps_rel适当放宽从默认的1e-6放宽到1e-4或1e-3对车辆控制来说精度完全够。第二看预测时域和约束数量。如果N超过30约束数量超过上百个实时求解压力很大试着缩小N或者减少约束。第三利用热启动。OSQP支持传入上一帧的最优解作为初始值车辆控制中相邻两帧的最优解变化不大热启动能显著减少迭代次数。这三个手段一起上求解时间一般能压到几毫秒以内。5.2 轨迹跟踪发散的原因排查轨迹跟踪发散通常不是MPC算法本身的问题而是前面的环节出了问题。我把排查顺序固定下来每次遇到发散都按这个顺序走。第一步检查模型参数和坐标变换。这是最常见也最隐蔽的坑。比如航向偏差的处理如果参考线航向没有换算到同一个坐标系或者曲率正负号搞反MPC会朝着错误的方向优化。第二步检查线性化点。如果线性化用的状态和实际状态偏差太大线性模型的预测就会失真导致控制量方向错误。第三步检查v_x下限保护。低速工况下如果v_x趋近于零侧偏角计算会爆炸这时候MPC的预测会出现荒谬的结果。第四步回头检查权重。如果横向偏差权重设得过大会导致控制量饱和车辆在弯道里反复振荡。还有一个很隐蔽的问题参考轨迹分辨率太低。Apollo Planning输出的轨迹点间隔从10到50厘米不等如果曲率信息没有做平滑滤波相邻点的曲率跳变会让MPC的预测模型频繁切换工作点表现为轨迹跟踪不稳定。处理办法是对参考轨迹做插值和曲率平滑。5.3 控制量抖振与执行器延迟抖振的本质是控制量在相邻周期之间来回跳变。产生原因多数是权重设置不合理——(R_{\Delta\delta})和(R_{\Delta a})太小MPC对控制增量的惩罚不够导致控制量在各个周期之间剧烈变动。解决办法是逐渐加大这两个权重直到抖振消失。另一种导致抖振的原因是传感器噪声。位置和速度噪声直接进入MPC的状态输入优化结果就会把噪声放大。建议在MPC输入端先对状态做一阶低通滤波或者直接用Apollo的定位融合输出而不是用原始传感器数据。执行器延迟导致的振荡容易被误诊。现象是方向盘指令看起来合理但实车响应有明显滞后表现为过弯时转向不足然后控制器加大转角延迟后车辆突然转向过多形成振荡。这种情况加再多的权重都没用必须在模型里加延迟补偿。5.4 摩擦椭圆约束在优化中反复振荡加摩擦椭圆约束后有一个很有意思的现象MPC在每个控制周期的解都贴近摩擦圆的边界但不同周期的解在边界上来回跳。原因是线性化工作点判断不准确或者线性化后约束的边界随工作点变动太剧烈。我的做法有两个。一是给摩擦椭圆约束留一定的安全余量不要使用理论极限的100%而是用80%到90%。二是对线性化点做平滑处理不要直接用当前瞬时状态而是用上一时刻的最优预测状态。这样约束边界在相邻周期之间变化更平滑QP解的连续性会好很多。最后说两句个人体会这套横纵向耦合MPC做下来最深的感受是解耦控制不是不行而是它的失效模式比较隐蔽——日常生活中一切正常到了极限工况才发现两个控制器在互相拉扯。横纵向耦合MPC的引入不是为了让常规工况表现得更好而是让车辆在轮胎附着极限附近仍然有一个明确的、可预测的行为边界。我的另一个体会是如果重来一遍我会花更多时间在模型标定和参数辨识上而不是在求解器选型上折腾。MPC的上限由模型精度决定优化算法只是把模型里已经存在的物理规律求出来。模型参数里前轮侧偏刚度、后轮侧偏刚度、整车质量和转动惯量这四个值对控制效果的影响比任何调参技巧都大。这组参数如果是从同款车上测试得到的MPC的表现会出乎意料地好如果是从网上随便抄的调参可能调到怀疑人生。最后再分享一个小技巧。做仿真对比时不要只对比横向偏差和速度误差的数值曲线把MPC的QP双变量对偶变量输出拉出来看看。当某个约束处于激活状态时双变量会明显变大。这个信息可以用来判断控制器当前到底是被哪个约束在制约——是转向极限、加速度极限还是摩擦椭圆极限。知道约束在哪里激活有助于定位控制瓶颈比反复调权重高效得多。