JOVANA
Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

向前看:LQR、最优控制与 MPC

与其手动调增益,不如写下一个代价——力气与误差的权衡——让数学算出最佳控制,甚至同时尊重各种限制。

从拧旋钮到写下目标

在前面的台阶,你靠手动调控制器——把某个增益往上推一点,看它晃,再推回去。对一个电机这样做没问题,但当机器人有许多互相牵扯的关节时,这会让人精疲力竭。最优控制把问题反了过来:与其拨弄旋钮,不如写下你真正想要的东西,让数学把最能实现它的控制器交给你。

首先,你把机器人写成一个状态空间模型:它用一份紧凑的账本记下机器人的状态(每个关节的位置和速度),以及今天的状态加上你施加的控制如何滚动成明天的状态。这与逆动力学背后的想法相同——一个描述机器如何运动的模型——只是写成了适合控制的形式。

然后你写下一个代价——一个你希望越小越好的数字。它通常在两样你永远无法兼得的东西之间权衡:跟踪误差(你离想要的设定值有多远)和控制力气(电机有多吃力)。想要紧跟目标?就重罚误差。想要一个温柔、省电的机器人?就重罚力气。你的意图,就活在这个代价里。

LQR:闭式解出的最佳线性反馈

当模型是线性的、代价是二次型的——误差的平方加上力气的平方——这个问题就有一个优美而精确的答案。它叫线性二次型调节器,简称 LQR。「二次」是说一切都被平方,正是这一点让数学能一次干净地解出来;「调节器」是说它把状态推回零(或推向你的目标)。

LQR 交给你的,是一个增益矩阵 K。控制律就是 u = −Kx:测出完整状态 x,乘以 K,那就是你的指令。这是全状态反馈——每个关节的指令都可以依赖其他所有关节的位置和速度,而这种耦合,正是给每个关节单独手调一个 PID 回路永远无法完全捕捉的。

你仍然要拧的旋钮,是两个权重矩阵,通常叫 Q 和 R。Q 是你对状态误差的惩罚力度,R 是你对控制力气的惩罚力度。把 Q 调大,机器人变得凶猛利落,但电机很吃力;把 R 调大,它变得沉稳省力,却对跟踪更懒散。你不再一个一个地猜增益——你在调两个旋钮,它们表达的是同一个诚实的权衡,而增益会自动算出来。

MPC:规划一小段,行动,再重复

LQR 很出色,却在一点上是「盲」的:它没有「极限」的概念。如果数学这么说,它会毫不犹豫地要求超过电机所能提供的扭矩。模型预测控制,简称 MPC,通过提前思考来解决这个问题——像下棋的人那样,每次只想几步。

  1. 预测:在这一刻,用模型把机器人向前模拟一小段时间——比如未来 1–2 秒——试一组候选的动作序列。
  2. 优化:在这些序列中搜索,找出代价最低的那一组——跟踪最好、力气最省——同时遵守你写成硬性规则的约束。
  3. 行动:只执行这个计划的第一步,其余的全部丢掉。
  4. 重复:一个时间步之后,再次测量真实状态,把整件事重做一遍——正是这种不断重新规划,让 MPC 对意外保持稳健。

它的超能力,就在第二步的最后那个词:约束。你可以把铁律告诉 MPC:电机在扭矩上限处饱和、关节不能弯过机械限位、足式机器人的脚必须留在支撑区内、无人机不能倾斜超过安全角度。PID 回路是在事后与执行器饱和搏斗,而 MPC 干脆从不规划一个它根本做不出来的动作。

如果你觉得这和轨迹优化像表亲,没错——MPC 本质上就是在每一个控制时间步都从头解一个小小的轨迹优化问题,每秒解上几十甚至几百次。

如何取舍,以及它们出现在哪里

取舍主要关乎代价——这次是计算代价。LQR 离线把它的数学解一次,然后永远只跑一个简单的矩阵乘法:飞快、每步几乎免费,但它一条约束都顾不上。MPC 在线、每一步都重解一次优化:能力强得多,却既吃算力,又依赖一个可信的模型。

于是,当机器人待在已知工作点附近、约束很少咬人时,工程师就选 LQR——让四旋翼悬停、让倒立摆稳住,那些每一微秒都要紧的快速内环。而当极限就是全部关键时,他们就选 MPC——让足式机器人在崎岖地形上落脚而不翻倒、让自动驾驶车在车流中穿行同时尊重加速度和车道边界、让无人机紧贴推力极限激进飞行。

两种方法都假设你能看到完整状态 x,但真实传感器只给你它的一部分。这道缺口由状态估计器填补——一个状态观测器或卡尔曼滤波器——它从测量中重建出缺失的状态,再喂进去。最优控制和好的估计,是同一台机器的两半;下一条主线,将探索估计这一半。

loop every tick:
    x  = estimate_state()            # from sensors
    plan = optimize(model, cost,
                    constraints,     # torque, joint, safety limits
                    horizon = N)     # simulate N steps ahead
    u  = plan.first_move             # apply only step 1
    send_to_motors(u)
    # next tick: re-measure, re-plan from scratch
MPC 循环的伪代码:估计、在约束下对一段时域优化、只执行第一步,下一时间步再全部重来。