鲁棒Tube MPC工程实践:从不变集计算到在线优化的避坑指南
发布时间:2026/10/22 4:03:24 锦皓数字建站

简介这份资源围绕管模型预测控制Tube-MPC展开面向控制工程、自动化方向的学习者与研究者帮助理解并实现不确定性与扰动下的鲁棒控制策略。压缩包共15个文件以10个.m源码文件为主辅以2个.md说明文档、2张jpg示意图及1个.gitignore整体约176KB体积轻便。源码涵盖线性系统建模、Tube模型预测控制、普通MPC、最优控制器与图形绘制等模块示例部分提供扰动不变集、Tube-MPC、MPC及最优控制等多个可运行脚本便于对照理解内层反馈控制与外层优化调度的配合方式。目前已有1986人学习下载适合希望从理论过渡到代码实践、掌握鲁棒tube构建与约束处理的读者参考。1. 鲁棒 tube MPC 到底在解决什么从一次轨迹抖动说起去年帮一个做移动机器人底盘的团队排查问题时遇到一个很典型的现象标称 MPC 在仿真里跑得漂漂亮亮一上实车横向误差就开始周期性抖动遇到地面摩擦变化或者负载偏移直接冲出约束边界。控制器本身没写错模型也没建错问题出在“标称模型”和“真实系统”之间那道永远填不平的缝。鲁棒 tube MPCtube model predictive control就是冲着这道缝来的它不指望把模型建得绝对准而是承认扰动存在然后给标称轨迹套一根“管子”只要真实状态始终待在管子里约束就永远满足。这套方法适合谁做底盘、机械臂、无人机、过程控制这类“模型有误差、扰动有界、约束不能破”的场景尤其是那些被标称 MPC 的玄学抖动折磨过的工程师。它不便宜计算量比标称 MPC 大但换来的是可证明的鲁棒性——这在安全相关场合值这个价。2. tube MPC 的核心构造标称系统、误差系统与不变集2.1 为什么不能直接给标称 MPC 加个扰动项很多人第一反应是既然有扰动那我在预测模型里加一项 ( w_k ) 不就行了问题在于MPC 的约束是对预测轨迹逐点施加的而扰动是实时未知的。你在优化时假设的扰动序列和实际跑出来的扰动序列不可能一致约束满足就成了概率事件。tube MPC 的思路是把问题拆开让标称系统去“探路”规划一条满足约束的标称轨迹同时离线算出一个误差不变集保证真实状态与标称状态的偏差永远被这个集合包住。这样在线优化只需要管标称轨迹约束收紧的量由不变集提前确定。形式化地考虑离散线性系统[ x_{k1} A x_k B u_k w_k,\quad w_k \in \mathcal{W} ]其中 ( \mathcal{W} ) 是紧凸的扰动集通常取多面体或椭球。把状态和控制写成标称部分加误差[ x_k \bar{x}_k e_k,\quad u_k \bar{u}_k K e_k ]这里 ( K ) 是预先设计的辅助反馈增益作用是让误差系统稳定。误差动态变成[ e_{k1} (ABK) e_k w_k ]只要 ( ABK ) 是 Schur 稳定的误差就会收敛到一个鲁棒正不变集 ( \mathcal{Z} )满足 ( (ABK)\mathcal{Z} \oplus \mathcal{W} \subseteq \mathcal{Z} )。这个 ( \mathcal{Z} ) 就是“tube”的横截面。2.2 约束收紧把鲁棒性翻译成标称约束有了 ( \mathcal{Z} )原始约束 ( x \in \mathcal{X},\ u \in \mathcal{U} ) 就可以翻译成对标称轨迹的收紧约束[ \bar{x}_k \in \mathcal{X} \ominus \mathcal{Z},\quad \bar{u}_k \in \mathcal{U} \ominus K\mathcal{Z} ]其中 ( \ominus ) 是 Pontryagin 差。这一步是整个 tube MPC 最关键的工程动作它把“不确定性”提前折算成了“约束余量”。在线优化时你只需要解一个确定性的标称 MPC[ \min_{\bar{u}0,\dots,\bar{u}{N-1}} \sum_{k0}^{N-1} \ell(\bar{x}_k,\bar{u}_k) V_f(\bar{x}_N) ][ \text{s.t.}\quad \bar{x}_{k1} A\bar{x}_k B\bar{u}_k ][ \bar{x}_k \in \mathcal{X} \ominus \mathcal{Z},\quad \bar{u}_k \in \mathcal{U} \ominus K\mathcal{Z},\quad \bar{x}_N \in \mathcal{X}_f ]终端集 ( \mathcal{X}_f ) 需要是标称系统在收紧约束下的不变集通常取最大不变集或者一个简单的多面体近似。2.3 最小可复现实现用 Python 搭一个 tube MPC 骨架下面这段代码用cvxpy搭一个离散双积分模型的 tube MPC扰动集取多面体不变集用简单的缩放近似。实际工程中不变集要用 MPT3 或类似工具离线算这里为了可复现用对角缩放矩阵近似。import numpy as np import cvxpy as cp # 离散双积分模型采样时间 0.1s dt 0.1 A np.array([[1.0, dt], [0.0, 1.0]]) B np.array([[0.5 * dt**2], [dt]]) # 扰动集|w| 0.02多面体 w_max 0.02 # 辅助反馈增益 K用 LQR 算 Q_lqr np.diag([10.0, 1.0]) R_lqr np.array([[0.1]]) # 简化手调一个稳定增益实际用 dlqr K np.array([[-3.0, -2.0]]) A_cl A B K # 近似不变集用缩放矩阵 Z diag(z1, z2) # 满足 (ABK)Z ⊕ W ⊆ Z这里直接给一个保守值 z1, z2 0.05, 0.08 Z np.diag([z1, z2]) # 约束位置 |x1| 1.0速度 |x2| 0.5控制 |u| 1.0 x1_max, x2_max, u_max 1.0, 0.5, 1.0 # 收紧后的约束 x1_tight x1_max - z1 x2_tight x2_max - z2 u_tight u_max - np.abs(K np.array([z1, z2])) # MPC 参数 N 20 nx, nu 2, 1 def solve_tube_mpc(x0, x_ref): x cp.Variable((nx, N 1)) u cp.Variable((nu, N)) cost 0 constraints [x[:, 0] x0] for k in range(N): cost cp.quad_form(x[:, k] - x_ref, np.diag([10.0, 1.0])) cost 0.1 * cp.quad_form(u[:, k], np.eye(nu)) constraints [x[:, k 1] A x[:, k] B u[:, k]] constraints [cp.abs(x[0, k]) x1_tight] constraints [cp.abs(x[1, k]) x2_tight] constraints [cp.abs(u[0, k]) u_tight] # 终端约束 constraints [cp.abs(x[0, N]) x1_tight] constraints [cp.abs(x[1, N]) x2_tight] prob cp.Problem(cp.Minimize(cost), constraints) prob.solve(solvercp.OSQP, warm_startTrue) if prob.status ! cp.OPTIMAL: return None, None return u[:, 0].value, x.value # 仿真 x np.array([0.8, 0.3]) x_ref np.array([0.0, 0.0]) for t in range(100): u0, x_pred solve_tube_mpc(x, x_ref) if u0 is None: print(MPC 求解失败) break # 真实系统带扰动 w np.random.uniform(-w_max, w_max, size(nx,)) x A x B u0 w if t % 10 0: print(ft{t}, x{x}, u{u0})这段代码的逻辑说明Z是不变集的近似实际应该用(ABK)Z ⊕ W ⊆ Z迭代求解最大不变集x1_tight、x2_tight、u_tight是收紧后的约束在线优化只解标称系统K是辅助反馈实际控制量是 ( u \bar{u} K(x - \bar{x}) )代码里为了简洁只输出了标称控制真实部署时要把这一项加上。参数方面z1、z2越大越保守约束收紧越多可行域越小N越大计算越重但终端约束可以放松Q_lqr、R_lqr影响K进而影响不变集大小需要和约束收紧量一起调。提示不变集计算是 tube MPC 最容易被低估的一步。用近似缩放矩阵能跑通 demo但上实车必须用精确的多面体不变集否则鲁棒性没有保证。3. 从离线不变集到在线优化工程落地的四个关键参数3.1 扰动集 ( \mathcal{W} ) 怎么定宁大勿小但别离谱扰动集是 tube MPC 的输入不是输出。它来自你对系统的认知摩擦系数变化范围、负载波动、传感器噪声、执行器死区。常见做法是先做系统辨识把残差统计出来取 3σ 或者包络。但血泪经验是扰动集宁大勿小因为一旦真实扰动超出 ( \mathcal{W} )不变集假设就崩了约束可能被突破。但也不能离谱否则收紧后的约束直接空集MPC 无解。我一般会先取一个保守值跑仿真看约束收紧后还剩多少可行域再逐步收紧扰动集。3.2 辅助增益 ( K ) 的选型LQR 不是唯一答案( K ) 的作用是让误差系统快速收敛到不变集。最常用的是 LQR因为求解方便且能平衡误差收敛速度和控制量。但 LQR 只考虑二次代价不考虑不变集大小。有些场景下用 ( H_\infty ) 或者极点配置能让不变集更小从而减少约束收紧量扩大可行域。实际选型时我会先试 LQR如果收紧后可行域太小再换 ( H_\infty ) 或者手动调极点。注意 ( K ) 一旦确定不变集和约束收紧量就固定了在线优化不再改变。3.3 预测时域 ( N ) 与终端集可行性和计算量的平衡( N ) 越大标称 MPC 的可行域越大但计算量线性增长。tube MPC 的在线部分和标称 MPC 一样所以 ( N ) 的选择逻辑相同。终端集 ( \mathcal{X}_f ) 需要是收紧约束下的不变集通常取最大不变集或者一个简单的多面体。如果终端集太小可行域会缩水如果太大递归可行性没有保证。常见做法是离线算一个椭圆或者多面体终端集在线只加终端约束。计算量方面OSQP这类一阶求解器在 ( N20 ) 时单次求解在毫秒级嵌入式平台也能跑。3.4 约束收紧量在线查表还是实时计算约束收紧量 ( \mathcal{X} \ominus \mathcal{Z} ) 和 ( \mathcal{U} \ominus K\mathcal{Z} ) 可以离线算好在线直接查表。但如果 ( \mathcal{Z} ) 是多面体Pontryagin 差可能产生很多面在线查表会占内存。工程上常用近似用外接椭球或者简单多面体包住 ( \mathcal{Z} )然后收紧量用解析式算。另一种做法是实时计算但会增加在线负担。我一般会离线算好收紧量存成查找表或者解析式在线只做简单加减。参数作用调大后果调小后果扰动集 ( \mathcal{W} )定义不确定性范围约束收紧多可行域小鲁棒性无保证辅助增益 ( K )误差收敛速度控制量增大可能饱和不变集变大收紧多预测时域 ( N )优化视野计算量增大可行域小短视终端集 ( \mathcal{X}_f )保证递归可行可行域缩水递归可行性无保证4. 避坑与排查tube MPC 落地时最容易翻车的五个点4.1 现象仿真没问题实车约束被突破原因扰动集 ( \mathcal{W} ) 设小了真实扰动超出范围不变集假设失效。或者不变集计算用了近似实际 ( \mathcal{Z} ) 比设计值大。解决先录实车数据统计残差包络重新定 ( \mathcal{W} )不变集用精确多面体算法重算别用缩放矩阵糊弄。4.2 现象MPC 频繁无解原因约束收紧太多可行域空集。常见于扰动集过大或者 ( K ) 选得不好导致不变集过大。解决检查收紧后的约束是否还有可行点如果空集先减小 ( \mathcal{W} ) 或者换 ( K )也可以放松终端约束用软约束代替硬约束。4.3 现象控制量抖动严重原因辅助反馈 ( K ) 增益过大误差被快速放大到控制量上。或者在线优化时没有加控制量变化率约束。解决调小 ( K )或者在代价函数里加 ( \Delta u ) 惩罚检查实际控制量 ( u \bar{u} K(x - \bar{x}) ) 是否饱和。4.4 现象计算时间超标原因( N ) 太大或者不变集多面体面数太多导致约束数量爆炸。解决减小 ( N )用终端集代替长时域不变集用外接椭球近似减少约束面数换用一阶求解器如OSQP或者ADMM。4.5 现象标称轨迹和真实轨迹偏差越来越大原因误差系统不是渐近稳定或者 ( ABK ) 的特征值接近单位圆。解决检查 ( ABK ) 的谱半径确保小于 1如果系统有积分环节考虑增广状态或者换 ( K ) 设计方法。5. 进阶技巧用 tube MPC 做参考轨迹跟踪的工程习惯5.1 参考轨迹也要收紧很多人只记得收紧状态和控制约束忘了参考轨迹本身也可能不可达。如果参考轨迹超出了收紧后的约束MPC 会拼命追但追不上导致控制量饱和。正确做法是参考轨迹先过一遍收紧约束不可达的部分做投影或者重新规划。我一般会在参考轨迹生成器里加一层收紧约束检查确保 ( x_{\text{ref}} \in \mathcal{X} \ominus \mathcal{Z} )。5.2 用 tube 宽度做故障检测tube 的横截面 ( \mathcal{Z} ) 是误差的界。如果实际误差持续接近 ( \mathcal{Z} ) 的边界说明系统可能出了故障或者扰动集设小了。可以拿 ( |e_k| ) 和 ( \mathcal{Z} ) 的支撑函数做比较超过阈值就报警。这个技巧在底盘上很实用能提前发现轮胎气压不足或者地面附着力变化。5.3 在线更新扰动集固定扰动集在场景变化时会过于保守。进阶做法是用递推最小二乘或者集合成员滤波在线估计扰动集然后实时更新收紧量。但注意在线更新会破坏递归可行性证明需要加额外的安全逻辑。我一般只在慢变场景下用快变场景还是固定扰动集加保守设计。5.4 一个验证习惯蒙特卡洛跑 1000 次设计完 tube MPC别只看一条轨迹。用蒙特卡洛在扰动集内随机采样跑 1000 次统计约束违反次数和最大偏差。如果 1000 次里有一次违反说明不变集或者扰动集有问题。这个习惯帮我抓过好几次不变集计算的 bug比看理论证明快得多。注意蒙特卡洛验证时扰动采样要覆盖 ( \mathcal{W} ) 的顶点和边界不能只采内部点。多面体扰动的极值通常出现在顶点。最后说个我自己的教训早期做 tube MPC 时总觉得不变集算一次就一劳永逸结果换了个负载扰动集变了不变集没更新实车直接冲出去。后来养成习惯每次改机械结构或者换执行器第一件事就是重新辨识扰动集、重算不变集。这个习惯比任何调参技巧都值钱。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。