第一次听同事说“模型预测控制就是暴力破解”的时候,我整个人是有点懵的。后来自己在一个小车底盘项目里把MPC从公式码到真车轮上,才明白这话其实说得相当准:它不用什么高深的手解公式来给出控制律,而是靠着实时数值优化这个“蛮力手段”,把未来几步系统状态硬生生往前推出来,再每一周期重新选一次最优。这个思路放到车辆路径跟踪上,就是用模型去预演未来,算清楚转向、加速、刹车到底该怎么配合。这篇文章就是围绕模型预测控制从状态方程到轮上执行这条线,把原理、代码、调参和上车遇到的问题一次性聊透。想快速在自己工程里用上MPC,或者想搞清楚它和普通PID差别的人,应该能从中拿到不少可以直接抄作业的东西。
1. 项目核心思路:用算力换设计的“暴力”控制器
1.1 从预测到优化:MPC这三个字到底说了什么
模型预测控制,英文Model Predictive Control,三个关键词:模型、预测、控制。模型就是把被控对象的运动规律写成数学式;预测是拿这个模型,从当前状态出发,把未来一段时间的状态轨迹算出来;控制是把“未来轨迹”放到一个目标函数里做优化,找出一串输入,让系统从当前状态尽可能贴近期望轨迹。每算完一次,只执行第一个输入,下一个采样时刻重新再来一遍,这叫滚动优化。
这个流程放在车辆上就很好理解。你想让一辆车沿着目标轨迹走,你先要知道车当前的位置、车速、航向角,用一个简化的车辆模型算出如果接下来10步分别打不同方向、给不同油门,车会走到哪儿;然后给优化问题加约束,比如转向角不能超过某个物理极限、加速度不能超过舒适值;优化求解器会尽量找一组输入,既让车贴合目标轨迹,又别撞上约束边界。每次只执行第一步,下个周期重新算。所以MPC实际上是把“控制量怎么设计”这道题,变成了“每一步在线解一道带约束的优化题”。
从算法结构看,MPC的每个控制周期都包含四个动作:采集当前状态、用模型预测未来一段时间的响应、求解优化问题得到控制序列、只执行序列里的第一个量。这四个动作循环往复,窗口像车轮一样向前滚动。这也是它和传统控制最大的区别:传统控制是看到误差才反应,MPC是提前预测误差然后主动规避。
1.2 为什么它被称为“暴力破解”
传统PID像打牌高手,靠经验出牌;MPC更像算力玩家,把未来可能出现的多种情况全部列出来,用数值方法找最优。在控制理论里一直有“解析法”和“数值法”的分野。解析法追求公式闭式解,比如LQR可以在满足一定条件下直接算出一个状态反馈矩阵;MPC则不太追求这种“一步到位”的漂亮公式,而是老老实实把有限时域的优化问题摆出来,交给求解器去算。只要模型够准、算力够快,就能在每一拍里得到满足所有约束的控制序列。这个“大算量加穷举式优化”的思路,放在工程圈子常被调侃为暴力。
注意,这里说的“破解”不是破解密码,也不是任何网络攻击相关的东西,纯粹是说用算力硬解优化问题,别往别处联想。这种“暴力”有代价:当控制周期短、预测时域长时,每周期要求的计算量会明显上升。过去很多嵌入式控制器算不动,MPC只能在流程工业这种慢系统上跑;现在车规级芯片算力上来了,这种控制方法才真正能上轮子。这也是标题里“从数学到车轮”的意义:数学原理五十年前就有了,是算力和实现手段把它搬到了实时底盘控制里。
1.3 不是所有控制系统都适合上MPC
虽然文章在讲MPC多好用,但我一直建议先冷静评估:你的系统到底需不需要它。MPC的价值主要体现在三件事:多个输入输出之间互相牵扯、系统有明确的约束限制、控制品质要求高。比如车辆的横向纵向协同控制,既要跟线又要把速度压住,转向执行器又有物理限位,这种场景给PID调出来会非常痛苦,因为变量互相干扰,约束没法显式处理。MPC则可以在一套优化框架里把横纵向、限位、平顺性都揉进去。
但如果你的对象是一个简单的温度控制回路,或者一台原本PID就控制得很好的电机驱动器,上MPC反而麻烦:建模成本高、调参维度多、在线计算又占算力,最后效果可能和PID差不多,甚至更差。我的经验是先画个表问自己:被控对象非线性明显吗?执行器有没有硬约束?多变量耦合严重吗?计算硬件够不够?如果这些问题回答都是“否”,PID或前馈加反馈可能是更理智的选择。
这里顺手放个对比,方便判断:
| 维度 | 传统PID | 模型预测控制 |
|---|---|---|
| 对模型依赖 | 低,靠误差驱动 | 高,需要较准预测模型 |
| 多变量耦合 | 需要手动解耦 | 优化框架内自然处理 |
| 约束处理 | 靠限幅和防饱和,不精确 | 显式建模,可精确处理 |
| 计算开销 | 很低 | 高,需要实时求解优化问题 |
| 调参直觉 | 比例、积分、微分三个系数 | 权重矩阵、时域长度、约束权重 |
2. 核心数学原理拆解:从状态方程到滚动优化
2.1 先搭一个能用的预测模型
MPC的一切基础是预测模型。车辆控制里最常用的有两类,一类是低速场景的运动学模型,一类是高速或大幅转向场景的动力学模型。低速模型假设轮胎不打滑,把车辆当成一个刚体,用位置、航向和速度来描述:状态变量里一般取 [x, y, psi, v],其中psi是航向角、v是纵向车速;控制变量取 [a, delta],a是加减速,delta是前轮转角。连续时间运动学方程是:
dx/dt = v * cos(psi) dy/dt = v * sin(psi) dpsi/dt = v * tan(delta) / L dv/dt = a
其中L是轴距。这个模型不复杂,但它抓住车辆运动最核心的几何关系。MPC要用的是离散状态方程,所以一般在每个控制周期做离散化,得到一个形如x(k+1) = A x(k) + B u(k)的线性时变模型。在车辆路径跟踪中,通常还要对参考轨迹做线性化,把误差状态当成状态量,让MPC在局部小偏差范围内工作。
模型越复杂,预测越准,但代价是后续优化问题很可能从线性二次规划变成非线性规划,求解难度和耗时完全不是一个量级。工程上常见的做法是先用力学关系建模,再用实测数据做系统辨识修正模型的参数,比如转向响应延迟、轮胎侧偏刚度,最终得到一个“够用但不复杂”的模型。我实际写代码时是先写一个多状态的运动学模型,丢进仿真里跑,跑得差不多再用实测数据修正。
2.2 预测时域、控制时域与滚动优化
MPC里有两个核心时域参数:预测时域Np和控制时域Nc。Np指每一拍优化时往前看多少个采样周期,Nc指在这Np步里允许控制输入变化多少个周期。Nc之后的控制量一般保持最后一个值不变。这个设计很实用,因为控制自由度数如果和预测步数一样多,求解器要找的自由度就很多,算起来慢,完全没必要;实际上远处几步的控制量对当前性能影响小,让它们保持恒定就好。
从状态方程可以很容易地写递推。假设x(k+1) = A x(k) + B u(k),从k=0时刻状态x0出发,Np=3、Nc=1时,预测序列是:
x1 = A x0 + B u0 x2 = A x1 + B u0 = A^2 x0 + A B u0 + B u0 x3 = A x2 + B u0 = A^3 x0 + A^2 B u0 + A B u0 + B u0
控制时域Nc=1意味着u1和u2都被固定等于u0。如果Nc=2,则u1可以独立选择,递推里就要把B u1的项单独留出来。把这些预测方程堆叠成矩阵形式,整个Np步的状态预测就可以写成一个线性表达式:X = Phi x0 + Gamma U,其中Phi和Gamma完全由A、B和Np、Nc决定。这一步非常关键,因为优化问题的变量就从所有状态点变成了控制序列U,维度大幅下降。我在代码实现里,也正是靠预先算出Phi和Gamma,让每个周期只做矩阵乘法和求解二次规划,不用现场一点一点递推。
滚动优化就是在每个采样时刻,用最新的状态x0作为初值重新计算U,执行U中第一个量,然后丢弃其余的。这就是为什么“滚动”二字特别形象:窗口不断向前滚,但每一时刻只做当下事。控制周期到的时候,无论上一个解算完没算完,都必须拿最新状态重新来一次,这是工程落地时的一个关键约束。
2.3 约束条件怎么进优化问题
MPC的一大卖点就是约束处理。转向执行器有最大转角,车速不能倒车或者不能超过路面条件,横纵向加速度要考虑舒适性,这些都可以写成优化约束。以转向系统为例,不等式约束通常是delta_min <= delta <= delta_max和-rate_max <= d(delta)/dt <= rate_max。第二个约束是控制增量约束,在优化变量U里体现为相邻两步的差值限制,也就是把u(k) - u(k-1)写成矩阵形式作为约束。
约束有两种:硬约束和软约束。硬约束就是不可突破的物理约束,比如转向机构限位,突破了会造成机械损伤;软约束是针对一些优先级别没那么高的边界,比如舒适性加速度,允许在极端情况下稍微超一点,但在目标函数里给一个大的惩罚系数。用术语说,就是引入松弛变量epsilon,让原来的g(x,u) <= 0变成g(x,u) <= epsilon,同时目标函数里加上rho * ||epsilon||^2。这个技巧几乎是工程MPC的标配,因为真实世界充满不确定性,模型预测和实际总会有偏差,如果所有约束都写成硬约束,一旦某个预测状态略越界,优化器直接报“无可行解”,控制器瞬间失去输出,这在车上比控制误差更危险。
我踩过最狠的一次坑就是某次把所有约束都设成硬约束,仿真里好好的,一接上真实执行器,因为转向角反馈有噪声,偶尔预测值越界一个微小量,优化器直接罢工,控制指令掉零。后来用软约束加小惩罚,问题瞬间消失。所以只要你不是在写快速原型Demo,建议默认就上软约束框架。
2.4 从手推公式到标准二次规划
目标函数写法比较多,我常用的形式是:
J = sum_{k=0}^{Np-1} (y_ref(k) - y(k))^T Q (y_ref(k) - y(k)) + sum_{k=0}^{Nc-1} delta_u(k)^T R delta_u(k)
第一项让系统输出靠近参考轨迹,第二项让控制量变化不要太猛。Q和R是权重矩阵,Q大则跟踪优先,R大则平顺优先。把这个目标函数结合预测方程和约束,经过一次整理,就变成标准二次规划(QP)问题:
min 0.5 * z^T H z + c^T z s.t. L <= A_ineq * z <= U z_min <= z <= z_max
这里z是待优化的控制序列或者控制增量序列,Hessian矩阵H由Q、R和Gamma矩阵组成,约束矩阵A_ineq由控制约束、增量约束堆叠而来。一旦变成这个标准形式,就可以丢给现成的QP求解器在几毫秒内解出来。
我很建议每个想深入MPC的人都亲手推一遍这个变换,哪怕是写个5步的小例子,把H和约束矩阵手算出来,很多调用优化器时容易看不明白的矩阵维度问题会恍然大悟。真正工程上,因为预测模型常是时变的,H和约束矩阵每个周期都要重新更新,参数化计算要有严格的矩阵尺寸检查,这也是后面实车调试最常出bug的地方。
3. 从仿真到实车的完整实操流程
3.1 工具链怎么选,才能不白踩坑
先捋一下工具链:做原型验证用什么、做产品落地用什么、最后落到轮子上用什么。
原型阶段最推荐Python,本身简单,生态里有现成的优化库和科学计算库,写一个简化MPC大概几十行就能跑起来,特别适合验证预测模型、调Q和R、看趋势。很多开源的二次规划求解器都提供Python接口,可以直接拿来试。产品阶段基本要转到C++,因为实时性要求高,内存动态分配要避免,Python解释器和对象开销都可能拖后腿。往嵌入式控制器上移植时,还要考虑求解器能不能在目标芯片上跑,耗时是否在控制周期内。
选求解器我一般比较看重四点:是否开源、能否处理稀疏矩阵、是否有嵌入式版本、社区是否活跃。稀疏矩阵处理尤其重要,MPC求出来的H矩阵通常是大而稀疏的,稠密算法会很慢,稀疏算法能有效减少计算和内存占用。仿真阶段建议把车辆模型和控制器分开写,控制器只管算控制量,把“车辆”当成一个独立的被控对象模块,后面接真实车的时候,只需要把被控对象替换成传感信号和执行器命令,控制器代码几乎不用动,这是最舒服的架构。
3.2 第一个能跑的MPC:Python最小实现
我写一段尽量简单但完整的MPC代码。用最朴素的线性模型,只调一个老牌求解器,重点是让你看清MPC的骨架。
import numpy as np # 这里调用常用的数值优化库,下面用 minimize 做演示 from scipy.optimize import minimize # 离散模型: x1 = x0 + v0*dt, v1 = v0 + a0*dt dt = 0.1 A = np.array([[1.0, dt], [0.0, 1.0]]) B = np.array([[0.0], [dt]]) # 初始状态和参考状态 x0 = np.array([0.0, 0.0]) x_ref = np.array([10.0, 0.0]) Np = 10 # 预测时域 Nc = 3 # 控制时域 Q = np.eye(2) * 2.0 R = np.array([[0.1]]) def predict(U): # 按Nc之后控制量保持不变的规则展开状态轨迹 x = x0.copy() xs = [] for k in range(Np): u = U[min(k, Nc-1)] x = A @ x + B.flatten() * u xs.append(x) return xs def cost(U): xs = predict(U) e = np.array([x - x_ref for x in xs]) c = 0.0 for k in range(Np): c += e[k].T @ Q @ e[k] if k < Nc: c += U[k].T @ R @ U[k] return c res = minimize(cost, np.zeros(Nc), method='SLSQP', bounds=[(-2.0, 2.0)] * Nc) print("最优控制序列:", res.x) print("执行第一步:", res.x[0])这段代码没有用QP求解器的稀疏结构,纯粹是为了把“预测-优化-执行”三件事讲清楚。你可以看到predict函数完成了滚动预测,cost函数把跟踪误差和控制代价合成一个标量,minimize完成带约束优化。实际项目里我不会用这种方法,因为它每周期要重复做很多矩阵运算,而且通用数值优化器没有利用QP的凸性,慢而且不稳;但它用于学习和调试模型权重非常方便,调参时知道趋势了再换正式求解器,效率高很多。
3.3 二次规划代码怎么落到实车上
固定预测模型的标准MPC,矩阵Phi、Gamma、H和约束矩阵基本上可以离线算好框架,在线只需要更新当前状态、参考轨迹和约束边界。以增量形式的MPC为例,决策变量选控制增量序列,目标函数写成:
J = ||Gamma * delta_u - (x_ref - Phi * x_k)||_Q^2 + ||delta_u||_R^2
把平方项展开整理,就得到Hessian矩阵H = Gamma^T Q Gamma + R和线性项系数c = ...。因为Q、R不变,如果模型是线性时不变的,H甚至可以离线和硬件在环之前预先计算好。在线部分只做:更新x_k和参考轨迹,算一次c,调用求解器,取第一个控制量。这个流程非常规整,非常适合嵌入式软件实现。
代码上我建议维护一个固定大小的预分配矩阵,不要让求解器动态分配内存;求解器如果要传稀疏矩阵,就预先分配好索引结构,每次只更新数值即可。这样做之后,同样的Np=30、Nc=10的问题,很多实车代码可以把单周期耗时间压到几毫秒以内,给上层规划留出余量。还有一点:接上真实车以后不要再每次打印整个控制序列,日志只记录关键状态和控制量,不然日志系统反而挤占控制周期。
3.4 仿真、硬件在环与真车标定的三个台阶
直接从软件仿真跳实车是新手最容易犯的错误,中间至少应该隔一个硬件在环环境。
第一级是离线仿真。用简单的车辆模型和控制器闭环跑起来,验证能不能跟踪目标轨迹、约束是否被满足、权重是否让控制量抖动。这时候还没有真实执行器延迟,结果往往偏乐观。第二级是硬件在环,把控制器代码放到实际的嵌入式控制板或快速原型平台上,车辆模型继续留在电脑里实时运行,接上真实传感器信号模拟。这一级能发现很多代码层面的问题:内存占用、函数执行时间、中断优先级、通信延迟。第三级是实车测试,先在低速、开阔场地跑直线、跑弯道,记录数据,再逐步上复杂工况。每次改动参数只改一个,不要一次动好几个。
我在实车阶段吃过一个亏:仿真里模型的采样周期是固定常数,但实车上通过任务调度和控制周期之间可能有微小的时序抖动,导致模型预测的时间和实际执行时间对不齐,表现为轨迹跟踪出现周期性抖动。后来解决办法是在控制器里记录实际时间戳,用实际采样间隔去更新模型,而不是默认采样周期。这个细节不写下来,后面几乎必踩。
4. 参数调优:让控制器从能跑变成好用
4.1 预测时域和控制时域怎么给初始值
预测时域Np直接决定“眼光”的长短。Np太小,控制器只顾眼前,系统容易激进甚至震荡,因为优化器看不到远处的减速需求;Np太大,预测轨迹很长,计算量和保守程度都会上来,某些工况下控制响应变得迟钝。Np的选择一般以采样周期为基准,让Np覆盖系统主要动态过程。对车辆底盘控制,采样周期如果50Hz,预测时域在20到40之间就比较常见,也就是说看去0.4到0.8秒。这个初值可以先根据车辆0到期望速度的响应时间估一个值,再通过仿真逐步缩短或加长。
控制时域Nc是控制自由度的数量。Nc小,优化器可选择空间小,结果接近“把前几步控制策略固定成某种形状”,好处是计算轻、结果稳;Nc大,控制器更灵活,可以把轨迹跟得更紧,但自由度变大也让控制指令序列更易跳动,同时求解变量多了。一般从Nc等于Np的1/3到1/4开始,看结果再调。我的习惯是先固定Nc等于5或10,调Np,确定大方向后再优化Nc;一次只动一个参数,否则变量交叉影响很难定位问题。
4.2 权重矩阵Q和R背后的物理意义
Q和R是MPC里最“玄”但最有物理意义的参数。Q矩阵对角线元素代表对应状态变量跟踪误差的优先级。比如横向位置误差权重给大,车会优先把位置跟准;航向误差权重给大,车会更注意姿态对齐。R矩阵代表控制增量代价,给大控制变化幅度会被压住,也就是让方向盘和油门动作更平滑。
调Q和R的经验顺序比较重要,我会把R先定下来,因为控制平滑性最容易观察。R太大,跟踪误差会明显变大,车转弯时候慢吞吞;R太小,控制指令高频跳动,执行器寿命和舒适性都受影响。把R调到既不抖又能承受的边界后,再提升Q放大跟踪精度。Q也不能无限大,因为目标函数里Q和R是相对关系,一味加大Q会再次诱发抖动。一个非常实用的技巧是把Q和R都写成一个基础标量乘以单位阵,先调一个比例,再逐个状态微调。相比直接面对一堆大矩阵,这样调参快得多,也方便记录历史参数。
4.3 约束设置的技巧和“软约束”问题
约束设置更像是在画安全边界。转向角上限直接抄车辆手册的机械极限,但控制器实际运行时要留2%到5%的余量,因为传感器噪声和模型误差会真实干扰求解。增量约束,比如最大的转向角变化率,决定了方向盘操作的“性格”,设得太紧车会很僵,太松则不够稳重。我常用一个折中:用软约束加惩罚系数来限制增量,正常情况不碰边界,紧急时允许短暂超出。
软约束里的松弛变量是工程必备,但松弛变量权重要大,大到一般工况下等于零,只在极限工况发挥作用。如果惩罚系数设小了,你会发现控制器会“故意”借用松弛空间,让车辆长期贴着约束边界跑,控制品质下降。我一般把松弛惩罚系数设为比Q对角线大一到两个数量级,再仿真看它会不会频繁启用。还有一个容易忽略的是约束的时序:预测时域里,前几步约束要严格一点,后几步可以适当放松,因为远处状态的预测误差本来就大,约束压太死容易造成求解不可行。
4.4 实车调参时最容易翻车的几个细节
实车和仿真差得最明显的是延时和噪声。执行器从指令发出到真正动作有延迟,比如转向电机可能延迟几十毫秒;MPC预测的是当前状态下的未来,如果执行层一直滞后,预测就容易“失效”。常见补救方案有两个:一是预测模型里加入延迟状态,把真实执行器响应建进模型;二是参考轨迹上对控制指令进行预瞄,用未来一点的参考点来弥补滞后。两种方案我都试过,延迟建模更通用,但需要标定延迟参数。
传感器噪声也很麻烦,尤其是位置和航向角。如果直接把带噪声的状态丢进MPC,优化器会对噪声放大,控制输出高频抖动。实践里通常在MPC上游加一级滤波,但不能滤太狠,否则相位延迟过大,反而破坏控制器稳定性。能直接用高精度传感器最好,否则要花时间折中滤波参数。最后,控制器和调度策略要约定一个安全保护:当求解器返回失败或超时,控制量怎么处理?我的做法是维持上一个有效控制量,同时让车辆触发降级模式,千万不要在无解时强行输出零,那在高速上会是灾难。
5. 常见问题与排查手记
5.1 求解失败:优化器说没有可行解怎么办
用MPC的人基本都见过“找不到可行解”的报错。第一次遇到时第一反应是约束太紧,但实际原因可能有好几种:约束之间本身冲突,比如既要求车在1秒内跨过一段距离,又要求加速度上限不超过某个物理极限,这组约束在物理上就是无解的;状态估计给出的初始状态已经超出约束边界,比如转向角传感器初始读数大于上限,优化器一开始就找不到可行域;还有可能是数值问题,比如矩阵病态、约束矩阵行冲突。
我的排查顺序是:先看当前状态x0是否本身越界,再看参考轨迹是不是过于激进,然后把硬约束一步步放宽,找到哪一组约束组合引发了冲突。代码上建议把约束边界打印出来,对比当前状态值,很多问题一眼就能看出来。工程实践证明,给MPC框架加软约束是解决不可行问题最系统的手段,把可能冲突的约束都换成软约束加惩罚项,优化器就总能交出解,只是需要代价较大地避让而已。
5.2 模型失配:仿真里稳,上车就抖
仿真里一切正常,实车一跑就抖,最常见的原因就是模型失配。车辆实际的转向响应、轮胎非线性、悬架侧倾都和简化的运动学模型对不上,这很正常。模型失配的表现有几种:跟踪误差持续有偏、控制指令高频抖动、或者系统小幅振荡。处理手段首先是提高模型的准确度,比如把执行器响应延迟、一阶惯性环节加进模型,用实验数据进行参数辨识,让模型和真实系统的稳态特性对齐。
如果还抖,还可以考虑在目标函数中加入对控制增量的惩罚,或者降低Q权重,让控制器对模型误差不那么“较真”。控制器本质上是在信模型和信反馈之间找平衡,模型不准时就应该更信反馈,手段就是缩短预测时域、减小跟踪权重,或者干脆加一层反馈校正,用当前实际输出和模型预测输出的差去修正下一步预测。工程实践中这个修正量虽然不大,却能显著缓解实车抖动。
5.3 实时性不够:代码优化的一点点心得
实时性不足的典型症状是控制周期里CPU占用率过高,经常出现一个求解周期远超设定值。第一步优化不是换求解器,而是看有没有做无意义的重复计算:每个周期都在原地构造全新的矩阵,有些矩阵只要模型不变就不应该动;能用预计算就预计算。第二步是减少动态内存分配,在C++代码里尽量避免频繁申请释放内存和容器的动态扩容,固定大小数组在栈上或者初始化时一次性分配好。第三,矩阵运算尽量用稀疏结构,不要用稠密矩阵去做大维度的乘法。
第四,如果预测时域已经压到成本极限还是超时,就该在控制器层面降级:把Np缩短,或者降低控制周期。还有一种很实用的做法:当参考轨迹比较平稳时,可以隔几个周期才重新计算一次控制序列,这样不仅能节省算力,反而是利用零阶保持让控制更平滑。不过这种降级策略必须配合状态监测,一旦误差变大要立刻恢复全频率计算。
5.4 经验速查表
| 症状 | 最可能原因 | 快速处理 |
|---|---|---|
| 无可行解 | 约束冲突/状态越界 | 打印约束状态,加软约束 |
| 控制量高频抖动 | Q权重过大、R过小、噪声大 | 加大R、加滤波、检查传感延迟 |
| 响应太慢 | Np太长或Q太小 | 缩短Np、提高跟踪权重 |
| 上车后稳态偏差 | 模型失配 | 系统辨识修正模型 |
| 实车出现周期性抖动 | 采样时序抖动/执行延迟 | 使用实际时间戳、建模延迟 |
| 求解超时 | 矩阵重复构造、内存抖动 | 预计算矩阵、固定内存分配 |
这张表是我实际调试时总结出来的,不能说覆盖全部场景,但绝大多数新手现场出的问题都能归到这六类里。排查的速度很大程度上取决于你有没有把日志打清楚,所以调试期宁愿多打一点数据,也不要图省事。
最后再说点个人体会。用MPC这几年下来,我最大的感受是:它把控制工程师的工作从“调三个增益”变成了“建模、求解、调权重、建约束”四件事,上限比PID高很多,但坑也成倍增长。尤其是从仿真到上车那一步,永远不要相信仿真里的完美结果,多给模型留余量、多给约束留软空间、多给求解器留算力。如果看完这篇文章你想动手试,我的建议是先拿一个简单模型在软件环境里跑通,再从代码里一个个改参数,慢慢体会每个量对响应的影响。等到你在实车上看到MPC真的把一个弯道稳稳跟住,那种“数学到了轮子上”的感觉,还是很值得的。