做控制的人一定绕不开一个经典场景:同一个被控对象,模型参数随着工况慢慢变了,或者根本就没法精确建模,可是你还要求它维持同样的控制精度。早期我处理这类问题只会用固定增益PID,调好了在某个工况下跑得很漂亮,工况一变就拉胯,后来被现实反复教育之后,才认真把自适应控制和学习控制整套思路补了一遍。这篇博文就围绕“自适应控制与学习控制”这个主题,把原理、设计、调参和踩坑经历一次性讲清楚。
这个主题适合刚进入控制算法方向的研究生,也适合做运动控制、机器人、电机驱动的工程师。你不需要把数学啃得特别深,但要对稳定性、收敛性这些基本概念有直觉。看完这篇,你能理解为什么自适应控制能“在线改参数”,学习控制为什么能在重复任务里“一次比一次准”,以及两者到底是什么关系、怎么选型、怎么融合。
1. 整体设计思路:为什么自适应控制和学习控制经常被放在一起讲
1.1 两者解决的是不同维度的问题
我见过很多人把自适应控制和学习控制混为一谈,其实是两套思路。自适应控制的核心是“在线辨识+在线修正”,本质是把模型参数的估计误差当成控制设计的一部分。假设被控对象是 (y = \theta^T \phi) 这种线性参数化形式,其中 (\theta) 未知,那么控制器会在运行过程中不断用输入输出数据去估计 (\theta),再用当前估计值计算控制量。这套逻辑适合参数未知但基本恒定、或者缓慢漂移的场景,比如机械臂负载变化、电机电阻随温度升高而增大。
学习控制则属于前馈类方法,典型代表是迭代学习控制ILC。它依赖任务的重塑性:每轮运行结束后,用本轮误差修正下一轮的指令输入。举个例子,流水线机械臂每一次都走同一条轨迹:第一次轨迹偏差3毫米,把偏差曲线记录下来,叠加到下一次的指令里,第三次偏差就能压到0.5毫米以下。它不关心对象模型到底是什么样的,只要系统在多次运行里保持一致,误差就会在迭代域上收敛。
放到一个更大的框架里看,自适应更像是“用模型在线逼近不确定性”,学习则更像是“用数据直接修正指令”。前者需要设计者给出参数化模型结构,后者甚至不需要模型结构,但对参考轨迹的重复性要求很高。很多实际系统同时具备模型不确定和任务重复两个特性,所以经常把两者结合使用。这也是为什么各类控制专题里总把自适应控制和学习控制绑在一章里讲。
1.2 选型判断依据:先看不确定性,再看任务形态
在项目开始时,我建议先回答两个问题。第一,不确定参数是否可以用有限维向量描述?如果能,比如质量、阻尼、摩擦系数,那么自适应控制是更稳妥的方案。第二,任务是否高度重复?机械臂拾放、晶圆搬运、印刷对辊压合,这类每次轨迹几乎不变的任务,用迭代学习控制效果极好。
两者的边界在很多时候是动态的。如果任务的重复性很好,但每次负载还会缓慢变化,那么用ILC能快速消除重复性误差,但非重复性扰动依然要靠反馈控制去兜底,这时候自适应参数估计又有用。设计上可以先建一个高带宽PD反馈,再用ILC做前馈校正,最后让自适应去处理慢变参数。这个主从结构我在多个模拟项目中验证过,收敛速度和稳态精度都优于单用任何一套方案。
一个容易被忽略的细节是:自适应控制会改变控制器的动态特性,对系统辨识信号有持续激励的要求;ILC则要求每次迭代的初态一致,否则误差会在迭代域里混入非重复分量。选型之前务必确认现场是否满足这些前提。否则会出现理论收敛、实际发散的诡异情况。
2. 核心原理拆解:把自适应和学习控制的数学机制讲清楚
2.1 自适应控制:李雅普诺夫告诉你怎么调参数
自适应控制按设计路线分为两类:模型参考自适应控制MRAC和自校正控制STC。我个人在运动控制中更多用MRAC,因为它对动态响应品质有直接约束。其思想很直观:人为构造一个期望的参考模型 (y_m),比如一个阻尼比为0.8、带宽为5Hz的二阶系统,然后设计控制律让真实对象 (y) 尽量去追踪 (y_m),同时在线调整可调参数。
推导时最关键是构造李雅普诺夫函数。取误差 (e = y - y_m),参数估计误差 (\tilde{\theta} = \theta - \hat{\theta}),构造:
[ V = \frac{1}{2} e^2 + \frac{1}{2\gamma} \tilde{\theta}^2 ]
其中 (\gamma > 0) 是自适应增益。对时间求导,并设计合适的控制律和自适应律,让 (\dot{V} \le -k e^2 \le 0),就能同时保证误差收敛和参数估计值有界。自适应律的标准形式是:
[ \dot{\hat{\theta}} = -\gamma e \cdot \phi ]
这里 (\phi) 是误差对参数的回归量。符号别记错了,我在推导时经常因为正负号导致参数越调越离谱,最后发现是自适应方向反了。实际调试中,如果发现参数估计朝着相反方向跑,优先检查这个公式。
MRAC的优势是算法框架统一,无论对象是电机还是机械臂,都能套进去。难点在于参考模型带宽怎么选、自适应增益怎么调。定得太激进,参数估计会振荡甚至激发未建模动态;定得太保守,参数收敛又慢,用户等不起。这个问题我放在第4章专门讲。
2.2 迭代学习控制:在迭代域上做收敛分析
迭代学习控制的直观理解就是“用上一轮的误差修下一轮的输入”。最简单的P型ILC更新律是:
[ u_{k+1}(t) = u_k(t) + L \cdot e_k(t) ]
其中 (k) 是迭代次数,(L) 是学习增益,(e_k) 是第 (k) 次运行的误差。收敛性条件是 (|1 - L P| < 1),这里的 (P) 是被控对象在相应频率上的传递函数。这个条件意味着:学习增益的方向不能错,大小要在一定范围内。实际中系统模型不完全准确,所以这个条件只能近似判断,但至少能用来做定性的方向筛选。
ILC最大的价值在于它能处理非平滑、包含高频分量的轨迹。模型参考自适应对高频成分通常有带宽限制,ILC则可以通过多轮学习把前馈指令逐步逼近真实逆模型的输出。因为每轮运行之后都可以离线处理误差信号,加滤波器、相位补偿都相对从容。
实际工程里,ILC版本很多,常见的有P型、D型、PD型,还有高阶ILC和Q滤波ILC。我最常用的是带Q滤波的P型:
[ u_{k+1}(t) = Q(t) \cdot (u_k(t) + L \cdot e_k(t)) ]
Q一般是零相位低通滤波器,用来截掉学习更新里的高频噪声,代价是最高可学习频率被限制在滤波带宽内。这个滤波器参数如果没设计好,要么出现高频抖振,要么学习精度上限受限。
2.3 两者融合:先用自适应稳定系统,再用学习打磨精度
结合方式我多次采用如下结构的控制律:
[ u = \underbrace{K_p e + K_d \dot{e}}{\text{反馈}} + \underbrace{\hat{\theta}^T \phi(x)}{\text{自适应前馈}} + \underbrace{u_{ILC}}_{\text{学习前馈}} ]
第一项反馈保证基本稳定和抗扰动能力;第二项自适应部分补偿模型参数不确定性,比如重力项、摩擦项;第三项ILC负责减少剩余重复性误差。三者角色完全不同,反馈管“当下绷得住”,自适应管“模型补得准”,学习管“重复误差清得掉”。
我在做这种融合时,一般先把自适应回路闭合,让它收敛到合理范围,再加入ILC。如果一开始就把三条回路全打开,调试时很难区分误差到底是谁没调好。分步投入,每次只引入一个变量,定位问题会容易很多。
3. 实操过程:一个单关节机械臂的自适应与学习控制示例
3.1 对象建模与问题设定
为了把上面这些原理落到可复现的例子上,我设计了一个单关节机械臂模型。动力学方程为:
[ J \ddot{q} + B \dot{q} + D \cdot \mathrm{sign}(\dot{q}) = u ]
其中 (J) 是转动惯量,(B) 是粘滞摩擦系数,(D) 是库仑摩擦幅值。仿真中 (J) 和 (B) 被设为未知量,(D) 直接给定一个粗糙估计值。目标是让机械臂角位置 (q) 跟踪一条五次多项式插值轨迹,从零到90度,全程5秒,最大速度限制在每秒45度。
这里故意把 (J)、(B) 做未知处理,是为了复现“负载变化导致惯量改变”的典型工况。如果你在做电机控制,可以把 (J) 理解成折算到电机轴上的总惯量,(B) 理解成阻尼系数。参数未知不意味着无解,而是要求控制器里必须有一个在线估计模块。
3.2 模型参考自适应控制设计步骤
第一步,选择参考模型。期望闭环表现为二阶系统:
[ \frac{q_m(s)}{q_{ref}(s)} = \frac{\omega_n^2}{s^2 + 2\zeta\omega_n s + \omega_n^2} ]
取 (\omega_n = 8),(\zeta = 0.8),这样跟踪响应大约0.5秒内能跟上指令,超调量小于百分之五。参考模型不能选得太激进,否则真实对象输入会饱和。
第二步,设计控制律。假设我们暂时忽略库仑摩擦,把控制输入写成:
[ u = \hat{J} a_r + \hat{B} \dot{q} ]
其中 (a_r) 是辅助加速度信号。为了让误差动态收敛,把辅助加速度设计成:
[ a_r = \ddot{q}{ref} + 2\zeta\omega_n (\dot{q}{ref} - \dot{q}) + \omega_n^2 (q_{ref} - q) ]
第三步,推导自适应律。令回归量 (\phi = [a_r, \dot{q}]^T),参数估计 (\hat{\theta} = [\hat{J}, \hat{B}]^T),自适应律为:
[ \dot{\hat{J}} = -\gamma_1 \cdot s \cdot a_r,\quad \dot{\hat{B}} = -\gamma_2 \cdot s \cdot \dot{q} ]
这里的 (s) 是复合误差信号,通常取 (s = \dot{e} + \lambda e),(\lambda > 0)。我用 (\lambda = 5),(\gamma_1 = \gamma_2 = 0.5) 起步。这个设计从李雅普诺夫函数出发,可以证明闭环误差最终收敛到零。
第四步,在仿真里跑通后,再叠加库仑摩擦补偿项 (D \cdot \mathrm{sign}(\dot{q}))。因为摩擦是符号函数形式,无法直接做在线估计,我用了离线辨识得到的固定值做前馈,剩下的误差交给反馈项去吸收。实际跑下来,稳态误差能控制在0.3度以内,比纯PD控制大约改善了60%。
3.3 迭代学习控制设计步骤
在同一台机械臂上,如果轨迹是完全重复的,我再用ILC进一步压低跟踪误差。准备一个初始指令 (u_0),直接沿用上一节的自适应控制器输出。在每次运行结束后记录误差曲线 (e_k(t)),更新下一轮指令:
[ u_{k+1}(t) = u_k(t) + L \cdot e_k(t) ]
仿真中的学习增益取 (L = 0.4)。系统采样周期为1ms,轨迹时长5秒,每条误差曲线有5000个点。ILC更新前对误差信号做零相位低通滤波,截至频率30Hz。
从第1次到第6次迭代,最大跟踪误差从2.1度降到0.25度;第10次迭代后稳定在0.12度。这里发现一个很有意思的现象:如果在ILC前面不加Q滤波,第5次迭代后误差虽然还在降,但控制指令已经开始显露高频振荡,到第8次以后会出现明显的高频噪声共振。加滤波之后,收敛速度稍微慢了一点,但控制指令平滑得多,实际系统里也更安全。
3.4 融合控制最终效果
把自适应和ILC叠加后,我记录了三种方案在同一轨迹下的跟踪误差峰值:
| 方案 | 最大跟踪误差 | 收敛到稳定所需时间 |
|---|---|---|
| 固定PD | 3.5度 | 无(稳态存在偏置) |
| 纯自适应MRAC | 0.6度 | 约2秒估计收敛 |
| 自适应+ILC | 0.15度 | 8次迭代后 |
需要说明的是,ILC对非重复扰动无能为力。我特意在第10次迭代后在仿真里加了一个随机力矩干扰,ILC无法抑制这部分误差,但自适应反馈把干扰峰值压制得远好于固定PD。最终结论:自适应给系统提供了基础稳定性和抗扰能力,学习控制负责把重复误差磨掉。两者配合,是典型的“粗调加精修”思路。
4. 参数整定与工具链:自适应增益、学习增益和滤波器怎么调
4.1 自适应增益 (\gamma) 的整定原则
自适应增益是自适应控制调试里最微妙的参数。(\gamma) 太小,参数估计收敛慢,误差会在很长一段时间内保持高位;(\gamma) 太大,参数估计波动剧烈,甚至会把未建模动态激发出来。
我的经验是用“倍数试探法”:从一个保守值开始,比如0.1,观察估计参数收敛曲线。如果估计值波形平滑,持续朝着一个方向趋近,没有振荡,则逐步翻倍到系统出现明显振荡,再回退到振荡值的四分之一作为最终设定。这个方法不精细,但非常高效。在仿真环境里可以直接暴力扫描;在现场环境里,我建议保守一点,多留稳定裕量。
在模型参考自适应里,有一个常见的坑:参考模型带宽太高,自适应增益又大,系统会产生参数交叉耦合。比如转动惯量估计值和高频噪声产生了相关,导致 (J) 的估计曲线不收敛而是持续漂移。碰到这种情况,我会先降低 (\omega_n),再调 (\gamma)。带宽和 (\gamma) 在某种意义上是一对跷跷板,你要找到同时让误差收敛和参数平滑的中间值。
4.2 学习增益 (L) 的整定与收敛判据
ILC的学习增益选择,理论判据是 (\lvert 1 - L P \rvert < 1)。实际中 (P) 不精确已知,我用两种方式处理。一种是在仿真里扫描不同的 (L),观察误差范数的迭代曲线。如果误差单调下降,说明 (L) 方向正确且幅度合适;如果误差增大,说明方向错了或者增益过大。另一种做法是相邻迭代差法:先跑一个低增益 (L=0.1),看每次误差下降的幅度,近似估计出系统的正负向,再放大增益。
实践中 (L) 的合适区间通常落在0.3到0.8之间。低于0.1,收敛太慢;高于1.0,非常容易发散。我见过有人把 (L) 调到1.2后系统直接跑飞的,因为忽略了对象在谐振频率附近的增益峰值。 (L) 对高频分量特别敏感,因为对象在高频段通常增益低、相位滞后大,误差里带高频分量的修正量会被严重放大。所以我的惯例是:先定Q滤波频带,再定 (L),这个顺序不要反。
4.3 Q滤波与零相位处理
Q滤波在我项目里承担两个任务:一是压掉误差信号里的高频噪声,二是限制学习频率带宽,防止对象谐振模态被激励。很多实用ILC论文里都会强调这一点,现场更有体会:噪声一旦进入学习回路,迭代几次后指令里就会长出一层“毛刺”。
我通常把Q设计成截至频率为目标轨迹最大有效频率3倍的低通滤波器。比如轨迹最大速度出现在中段,对应基频约1Hz,轨迹主要能量集中在10Hz以内,Q就取30Hz。如果对象存在20Hz的结构谐振,Q就必须降到15Hz以下。零相位滤波的做法是:先对信号正向滤波,再反向滤波一次,这样相位滞后为零。MATLAB里用filtfilt函数即可。
在实时系统里没法用零相位滤波,这时可以用因果滤波器并补偿相位滞后。ILC更新属于离线环节的,这里我们坚守零相位原则。如果必须在线做学习更新,就得用相位补偿器把滞后补回来,否则误差会越学越大。
5. 常见问题与排查技巧实录
5.1 参数估计持续漂移,没有收敛趋势
这个现象我遇到得最多,尤其是在做MRAC而没有持续激励时。参数估计漂移的根源是回归量 (\phi) 的激励不够充分。如果你让机械臂只做一个等速运动,(\ddot{q}) 恒为0,那么 (J) 就很难被辨识出来,估计值会停在初值附近或者缓慢漂移。解决办法是给参考轨迹注入足够的动态成分,加入加速减速段,让各个方向的回归量都被激活。
更隐蔽的情况是:参数本身在变化,但自适应律没有跟踪上。这时候不能一味加大 (\gamma),而要考虑给自适应律增加遗忘因子,让历史数据的影响随时间逐步衰减。带遗忘因子的递推估计公式里,遗忘因子取0.98到0.995之间。太小的遗忘因子会让估计值对噪声过于敏感。
5.2 迭代学习发散,误差一轮比一轮大
ILC发散的原因无外乎四个:学习增益方向错误、增益过大、相位补偿不当、Q滤波频带太宽。排查时我建议按顺序检查。先看误差的符号有没有反:把误差取负号跑一轮,比较误差范数,如果反向之后误差仍然变大,说明问题不在方向。再看相位:如果误差的极值位置和执行力的极值位置有明显时间差,就需要做相位补偿。
在这个环节里我发现一种非常隐蔽的故障,初态不一致。每次启动机械臂,初始位置都有微小偏差,这个偏差会在每次迭代里被当成重复性误差去学习,结果指令修正方向是错的。解决方法是加一个“初始位置对齐检查”,在开始ILC迭代之前,先让系统停在初始位置并确认到位,再开始轨迹跟踪。
5.3 学习收敛后出现高频抖振
高频抖振通常在ILC迭代后期出现:跟踪误差看似已经很小,但控制指令开始持续振荡。这是因为学习在把重复性误差压向零的同时,也把测量噪声逐步复制进了前馈信号。噪声在频域上分布非常宽,高频分量幅度不高,但经过学习增益一次一次放大,最终占据主导。
对策是加强Q滤波,或者把学习更新中误差信号的差分项去掉。我在一次机械臂项目中把Q从30Hz降到20Hz,抖振的峰值从几十毫伏下降到噪声底附近,代价是最终跟踪误差从0.12度变成0.16度。这个权衡在工程上完全值得。
5.4 仿真通过,实物现场失败的常见差异
仿真里一切都很完美,一上实物就发散,这是很多学生项目组都经历过的。“仿真和实物的差了一个世界”,主要是实物有采样噪声、执行器饱和、通信延迟以及未建模摩擦。自适应控制对未建模动态尤其敏感,因为高增益的参数估计会把高频不确定性当成参数去补偿,反而恶化系统。
我给入手的建议是:实物调试前先要验证基础反馈回路,确认闭环带宽足够、相位裕量充足,再启用自适应回路。启用自适应回路后的前几次运行必须手动降低增益,观察估计值波动。同时把执行器饱和考虑到控制律里,可以采用抗饱和设计,保证输出在饱和时积分项不过度累计。常见做法是设定一个输出限制,当输出逼近限幅时冻结参数更新。这个细节在全文里是我最想让你记住的工程点之一。
6. 最后分享一点个人项目体会
做自适应控制和ILC这些年,我觉得最关键的转变是放弃“一套控制打天下”的想法。固定结构的控制器到底能力的边界在哪里,你一定要心里有数。自适应适合处理模型参数的慢变,学习适合处理周期性误差,两者都要在反馈回路做好的前提下才有效果。如果你的基础PD回路相位裕量就不够,加上自适应或学习只会放大本来的问题,而不会创造奇迹。
另外一点是关于调试顺序:先仿真、再半实物、再全实物,每一步都只增加一个变量。我在很多项目里都践行这个原则,比如先把MRAC单独调好,确认参数估计曲线平滑之后,再叠加ILC迭代修轨迹,整体推进速度反而更快,因为出了问题你知道锚点在哪。参数试探时要养成记录习惯,把每次调整的内容、观察到的现象和时间点记录下来,形成调参日志。遇到复发问题时直接翻日志,比自己凭记忆回忆可靠得多。
最后再给大家一个我在实际项目里屡试不爽的小技巧:在仿真阶段,可以把自适应增益调到正常运行值的5倍,故意逼出振荡,观察这时候系统如何表现。这个“极限试探”能帮你提前发现未建模动态的激励频率和耦合趋势。知道边界在哪,正常参数区间内你会非常安心。控制系统的魅力在于它永远有时间域和参数域的权衡,那个你亲手调出来的平衡点,才是你真正学到的东西。