不管你是做机械臂轨迹跟踪、无人机姿态控制还是电机调速,只要跟“滑模控制”打过交道,大概率会碰上一个绕不开的名字:终端滑模,也就是 Terminal Sliding Mode。这个词在论文里出镜率极高,但说实话,很多教程一上来就甩出一堆分数幂和奇异分析的公式,看完只记住了“终端滑模能有限时间收敛”,至于它到底怎么把“渐近收敛”变成“有限时间收敛”、为什么会有一个让人头大的奇异问题、实际调参时到底该动哪个参数——反而没几个人讲清楚。
我最早接触 Terminal 滑模是在做高精度转台控制的时候。传统线性滑模虽然鲁棒性很强,但误差收敛速度在接近零点时会越来越慢,尤其是系统存在稳态扰动时,那个误差就“吊”在那里,看着着急。后来换成终端滑模,收敛速度肉眼可见地提升了一个档次。这篇文章我就用大白话加必要的数学,把终端滑模这件事掰开揉碎讲清楚:它解决了什么问题、核心公式怎么推、参数怎么调、哪些坑我替你已经踩过了。适合刚接触非线性控制的研究生,也适合像我一样在工程里被“精度差”和“抖振”反复折磨的工程师。
1. Terminal滑模到底在解决什么问题
1.1 线性滑模的“终点”问题
先花点时间回顾一下传统滑模控制的基本逻辑。对一个二阶系统来说,最常见的线性滑模面长这样:
$$ s = c e + \dot{e} $$
其中 (c>0),(e) 是跟踪误差。滑模控制的思路就是设计控制律,让系统状态先到达滑模面 (s=0),然后“滑”到原点。一旦系统进入滑模面,( c e + \dot{e} = 0 ) 就是一个一阶线性微分方程,解出来:
$$ e(t) = e(0) e^{-ct} $$
到这里问题就来了:指数函数只会在 ( t \to \infty ) 的时候趋近于零,也就是说,理论上要无限长时间误差才能完全收敛到零点。工程上更实际的情况是,当误差很小的时候,( \dot{e} = -c e ) 给出的收敛速度会变得非常慢——误差从1收敛到0.1可能很快,但从0.001收敛到0.0001需要等待更长的时间。
很多做精密控制的同学应该深有体会:滑模控制改完之后,鲁棒性确实好了,扰动一来系统也能扛住,但就是最后那一点稳态误差,怎么调 (c) 都像在炖老火汤——慢得让人没脾气。把 (c) 调大呢,又会导致滑模趋近阶段控制力过大,抖振加剧,甚至激发未建模动态。这就是线性滑模面的一个结构性限制,它的收敛速率是“越接近目标越慢”的指数形式。
1.2 终端滑模的“有限时间”承诺
终端滑模的想法很直接:既然线性滑模面上误差收敛是渐近的,那能不能把滑模面设计成非线性的,让系统在滑模面上运动时,误差能在有限时间内到达零点呢?答案就是引入分数幂项。
传统的终端滑模面通常写为:
$$ s = \dot{e} + \beta e^{q/p} $$
其中 (\beta > 0),(p > q),而且 (p、q) 取正奇数。关键在于指数 (q/p) 小于1。当系统在滑模面 (s=0) 上运动时:
$$ \dot{e} = -\beta e^{q/p} $$
这个微分方程的解法和线性情况完全不同。分离变量积分一下:
$$ \int_{e(0)}^{0} e^{-q/p} de = -\beta \int_{0}^{t_r} dt $$
左边积分出来是 ( \frac{p}{p-q} |e(0)|^{1-q/p} ),所以收敛时间:
$$ t_r = \frac{p}{\beta(p-q)} |e(0)|^{1-q/p} $$
这是一个有限值。也就是说,状态从初始位置 (e(0)) 出发,会在确定的时间 (t_r) 内准确到达零点。这个性质称为“有限时间收敛”,也正是终端滑模名字里“Terminal”的由来——它有一个明确的终点。
为什么指数 (q/p<1) 能带来有限时间收敛?关键在收敛速度的表达上。当误差 (e) 很小时,( e^{q/p} ) 比 ( e ) 要大得多。举个例子,(e=0.001) 时,(e) 本身是0.001,但 ( e^{3/5} ) 大约是0.0158,比0.001大了15倍多。所以在接近原点的区域,终端项提供的“恢复速度”远高于线性项。这就像线性滑模是一辆匀速靠近停车线的车,而终端滑模是带着刹车后段反而加速的效果,越靠近目标反而越“猛”。
1.3 一句话理解终端滑模
如果让我用一句话概括:终端滑模就是在滑模面里塞进一个分数幂的非线性项,使得系统状态一旦上滑模面,它的收敛速度不再是恒定的指数速率,而是会根据当前位置自动调整——离目标越近,等效增益越高,从而在有限时间内完成收敛。
但要提醒的是,这个改动看起来只是把指数从1换成了 (q/p),实际上引发了一连串连锁反应:奇异性问题、参数取值范围限制、符号函数的处理、离散化稳定性……每一项都能让你在仿真和实验中多掉几根头发。后面几章我逐个拆解。
2. 终端滑模的核心原理:从相平面到分数阶幂次
2.1 几何直觉:相平面里的“漏斗”
理解终端滑模最好的工具是相平面。想象横轴是误差 (e),纵轴是误差导数 (\dot{e})。传统线性滑模面 (s = ce + \dot{e} = 0) 在相平面上是一条固定斜率的直线。状态沿这条直线滑向原点时,轨迹的角度是恒定的,速度按指数衰减。
终端滑模面 (s = \dot{e} + \beta e^{q/p} = 0) 在相平面上则是通过原点的一条曲线。当 (e) 比较大的时候,这条曲线的斜率接近垂直还是水平,取决于 (q/p) 的具体取值;但在 (e \to 0) 的邻域内,由于指数 (q/p<1),曲线在原点的切线斜率趋近于无穷大——这意味着系统的轨迹在接近原点时几乎是以“竖直向下”的方式扎进去的。
这种几何结构意味着什么?相平面上的速度矢量里,横轴分量对应 (\dot{e}),纵轴分量对应 (\ddot{e})。在原点附近,终端滑模要求的 (\dot{e} = -\beta e^{q/p}) 给出的速度远大于线性情形,所以状态在很短的时间内就能“穿”过最后一小段距离到达原点。从能量的角度理解,终端项的引入相当于在原点附近构造了一个“深漏斗”,把状态快速吸进去。
2.2 传统终端滑模的奇异问题
前面介绍了传统终端滑模面:
$$ s = \dot{e} + \beta e^{q/p}, \quad 0 < q/p < 1 $$
现在要推导控制律。设一个简单的二阶系统:
$$ \ddot{x} = u + d(t), \quad |d(t)| \le D $$
跟踪误差 (e = x - x_d),误差动力学为:
$$ \ddot{e} = u - \ddot{x}_d + d $$
设计控制律 (u = \ddot{x}_d - \beta \frac{q}{p} e^{q/p - 1} \dot{e} - k \cdot \text{sign}(s))。其中第二项是等效控制项,用来抵消滑模面自身动态;第三项是鲁棒项,用来克服扰动。
问题出在第二项里的 ( e^{q/p - 1} )。由于 (q/p - 1 < 0),当误差 (e=0) 但 (\dot{e} \neq 0) 时,这一项会趋于无穷大。也就是说,系统状态一旦在某个瞬间满足“误差为零但误差变化率不为零”,控制量就会瞬间爆炸。这个现象在文献里叫“奇异问题”或“奇异性”。
奇异问题不是理论上的杞人忧天。仿真中如果把步长设小一点、扰动输入稍微陡峭一点,很容易复现控制量突然飙到十万级甚至更大的场景。在实物上,这样的控制量轻则饱和限幅、重则损坏执行器。很多刚上手终端滑模的同学第一版仿真就跑出这种结果,然后一度怀疑是不是自己推导错了——其实不是推导错,是方法本身的固有限制。
2.3 非奇异终端滑模:绕开那个雷
解决奇异的思路之一是把滑模面里分数幂的位置换一下。文献中比较经典的“非奇异终端滑模面”可以写成:
$$ s = e + \frac{1}{\beta} \dot{e}^{m/n}, \quad 1 < m/n < 2 $$
其中 (m、n) 取正奇数,(m > n)。这次分数幂落在 (\dot{e}) 上,而且指数大于1。当滑模面 (s=0) 时,可以得到:
$$ \dot{e} = -\beta^{,n/m} e^{,n/m} $$
同样能达到有限时间收敛,因为 (n/m < 1)。关键在于求导时,控制律中会出现 (\dot{e}^{m/n - 1}),由于 (m/n - 1 > 0),即使 (\dot{e}=0),该项也为零而不是发散,奇异问题被自然绕开了。
这里有个细节要留意。( \dot{e}^{m/n} ) 在 (\dot{e}<0) 时怎么计算?严格来说,任意实数幂对负数底数是没定义的。但因为 (m、n) 都是奇数,( \dot{e}^{m/n} = \sqrt[n]{(\dot{e})^m} ),开奇数次方根在实数域有意义。工程代码里更稳妥的写法是用分段函数 ( \text{sign}(\dot{e}) |\dot{e}|^{m/n} ) 来替代,避免各种数值库对负数幂的报错或被拖入复数运算。这一点我后面会在第四章再强调,因为实际编码时真的太容易踩了。
2.4 快速终端滑模:想快还要更快
普通终端滑模虽然保证了有限时间收敛,但在离平衡点较远的时候,收敛速度反而不一定比线性滑模快。因为当 (e) 很大时,( e^{q/p} ) 小于 (e),终端项提供的“吸引力”就弱了。为了解决这个问题,有人提出了快速终端滑模面:
$$ s = \dot{e} + \alpha e + \beta e^{q/p}, \quad \alpha, \beta > 0, 0 < q/p < 1 $$
这个设计很有意思:它在线性项之外再叠加一个终端项。当状态远离原点时,( \alpha e ) 线性项主导,保证较快的到达速度;当状态接近原点时,高阶小量 ( e^{q/p} ) 重新占据主导(因为在零点附近它远大于线性项),确保有限时间收敛。相当于把两者的优点都拿了过来。
不过要泼一盆冷水:快速终端滑模在多数情况下依然存在奇异问题,因为控制律推导时对 ( e^{q/p} ) 求导依然会出现负指数项。实际工程中如果非要用快速终端滑模,常见做法是引入边界层,或者把终端部分改写为饱和形式,在 (e) 进入小邻域时切换回线性形式。也可以结合非奇异设计,构造“快速非奇异终端滑模面”,但表达式会繁琐很多,参数也更多。先跑通基础的,再根据实际需要迭代,这是更务实的路径。
2.5 三类滑模面参数对比
为了更直观,我把常见的三种终端滑模面放在一张表里对比。
| 滑模面类型 | 表达式 | 收敛特性 | 主要优点 | 主要问题 |
|---|---|---|---|---|
| 线性滑模 | (s = ce + \dot{e}) | 渐近收敛 | 设计简单,无奇异 | 收敛慢,理论无穷时间 |
| 终端滑模 | (s = \dot{e} + \beta e^{q/p}) | 有限时间 | 收敛速度可调,在零点附近快 | 存在奇异问题 |
| 非奇异终端滑模 | (s = e + \frac{1}{\beta}\dot{e}^{m/n}) | 有限时间 | 无奇异,控制量平滑 | 形式稍复杂,参数多一个 |
| 快速终端滑模 | (s = \dot{e} + \alpha e + \beta e^{q/p}) | 有限时间且远场快 | 全局收敛速度快 | 奇异问题仍在,参数整定略繁琐 |
3. 实操设计:从滑模面到控制律的完整流程
3.1 一个能跑的仿真例子
说了这么多原理,来点实际的。我给一个工程设计中最常用的二阶系统设置,并完整演示非奇异终端滑模的推导与仿真参数。这个套路我已经在多个项目里验证过,拿过来改一改就能用。
被控对象选:
$$ \ddot{x} = u + d(t) $$
其中 (u) 是控制输入,(d(t)) 是有界扰动,这里就取 (d(t) = 2\sin(5t)),幅值有界且变化不那么温柔,能看出控制器的鲁棒性。目标轨迹:
$$ x_d = \sin(t) $$
误差 (e = x - x_d),误差动态:
$$ \ddot{e} = u + d(t) + \sin(t) $$
我们希望设计 (u),让 (e) 和 (\dot{e}) 在有限时间内收敛到零。设计非奇异终端滑模面:
$$ s = e + \frac{1}{\beta} \dot{e}^{m/n} $$
取 (m=5, n=3),这样 (m/n \approx 1.667),位于设计区间 ((1,2)) 中。(\beta) 先取8,后续再调。
3.2 非奇异终端滑模控制律推导
对滑模面求导:
$$ \dot{s} = \dot{e} + \frac{m}{n\beta} \dot{e}^{m/n - 1} \ddot{e} $$
把误差动态代入:
$$ \dot{s} = \dot{e} + \frac{m}{n\beta} \dot{e}^{m/n - 1} [u + d(t) + \sin(t)] $$
为了让 (\dot{s} = -k \cdot \text{sign}(s)),可以解出控制律:
$$ u = -\sin(t) - \frac{n\beta}{m} \dot{e}^{2 - m/n} - k \cdot \text{sign}(s) $$
其中第一项是对目标轨迹加速度的前馈补偿。第二项是等效控制的核心,用于确保一旦到达滑模面就不再离开。第三项是鲁棒项,用来克服扰动 (d(t))。
这里 (\dot{e}^{2 - m/n} = \dot{e}^{1/3}),指数为正数,所以没有奇异风险。但可以注意一下,由于 (m/n > 1),(2 - m/n < 1),当 (\dot{e}) 为负数时,不能直接在计算机里用 (\dot{e}^{1/3}) 的浮点幂运算来实现,这点在仿真代码里要格外小心。
具体数值仿真参数如下表:
| 参数 | 数值 | 说明 |
|---|---|---|
| (m) | 5 | 滑模面分数幂分子 |
| (n) | 3 | 滑模面分数幂分母 |
| (m/n) | 1.667 | 保证非奇异 |
| (\beta) | 8 | 影响滑模面收敛速度 |
| (k) | 3 | 鲁棒项增益 |
| 采样周期 | 0.001 s | 离散仿真步长 |
| (d(t)) | (2\sin(5t)) | 有界扰动 |
3.3 趋近律与抖振抑制
上面的推导用的是最基础的等速趋近律 (\dot{s} = -k \cdot \text{sign}(s))。等速趋近最大的问题就是抖振:符号函数在高频切换,控制量在滑模面两侧快速震荡,反映到执行器上就是尖锐的噪音和发热。
工程上最常用的改进有两个方向。第一个是“边界层”法,把符号函数替换成饱和函数:
$$ \text{sat}(s) = \begin{cases} \text{sign}(s), & |s| > \Delta \ s/\Delta, & |s| \le \Delta \end{cases} $$
其中 (\Delta) 是边界层厚度。边界层内控制量连续变化,不再高频切换,抖振显著降低。但代价是稳态精度会有折损,因为边界层内部的等效控制无法严格把状态约束在滑模面上。(\Delta) 越大越平滑、精度越差;(\Delta) 越小越精确、但越接近符号函数的抖振。我实践中习惯取 (\Delta = 0.01 \sim 0.05),再根据仿真结果微调。
第二种更“滑”的做法是用连续函数 (\frac{s}{|s|+\delta}) 代替符号函数,从本质上避免了切换不连续。(\delta) 是一个小的正常数,比如0.01。这种方式实现简单,效果和边界层法类似,两者可以交叉验证。
一个我从实际项目里总结的经验:不要一上来就追求高增益 (k),那样只是用更大的控制力去压制扰动,代价是抖振越来越剧烈。更好的顺序是先把边界层或连续化参数调好,让控制量平滑下来,再逐步增大 (k) 来增强鲁棒性。当然,如果系统运行工况较复杂、扰动幅值变化大,也可以考虑自适应调节 (k) 或使用扰动观测器。终端滑模加上扰动观测器是个不错的组合,但那是更复杂的话题了。
3.4 参数整定经验和调试顺序
参数整定是终端滑模落地时最“玄学”又最关键的环节。对于非奇异终端滑模面,核心参数就三个:(\beta)、(m/n) 和 (k)(再加上边界层相关参数)。我每次从零开始调的时候,基本都按下面这个顺序操作。
先固定分数幂 (m/n)。为了有限的收敛时间,(m/n) 只要落在 ((1,2)) 之间就行。从直观上说,(m/n) 越接近2,收敛速度越快,但等效控制项里 (\dot{e}^{2-m/n}) 的指数越小(例如 (m/n=9/5=1.8) 时指数是0.2),在 (\dot{e}) 较小的时候控制量变化会非常剧烈,数值上也不友好。如果 (m/n) 太接近1,比如 (7/6\approx1.167),那它就退化得越来越像线性滑模,有限时间的优势就不明显了。我常用的是 (5/3) 或 (7/5),效果都不错。
接着调 (\beta)。(\beta) 在很大程度上决定了误差收敛的“着急程度”。(\beta) 越大,滑模面越陡峭,收敛越快,但控制量峰值也会更大,系统的带宽要求更高。(\beta) 太小则收敛偏慢,甚至接近线性滑模的体验。我习惯用仿真扫参:保持 (k) 不变,把 (\beta) 从2翻到16,观察误差收敛时间与控制量峰值,选择一个折中值。
最后调 (k)。(k) 的作用是克服有界扰动。理论上只要 (k > D),就能保证滑模到达条件。但工程上由于采样离散化、未建模动态等因素,我会留出至少50%的余量。注意不要一次把 (k) 拉到很大,否则抖振和噪声会成倍放大。
提示:上面这些参数不是一劳永逸的。同样的控制器从仿真移植到实物,通常需要重新整定一遍,因为摩擦、惯量、执行器饱和这些因素都会改变系统的实际特性。仿真只能作为初值参考。
4. 常见问题与排查技巧实录
4.1 控制量爆发的奇异现象
传统终端滑模在仿真中最容易遇到的诡异情况就是控制量突然跳到天文数字。我之前带过一个学生做快速终端滑模仿真,控制律里有个 (e^{q/p-1}) 项,误差一过零点,控制量瞬间变成了1e8。他一开始以为是数值积分的bug,后来才知道这是奇异问题。
排查思路其实很简单:在代码里加一个判断,看控制量爆发的瞬间,系统状态是不是满足 (e \approx 0) 且 (\dot{e} \neq 0)。如果是,基本可以确认是奇异问题。解决手段有两种:一是换成非奇异终端滑模面,从根本上消除负指数项;二是保留传统终端滑模面,但在 (e) 过零点的小邻域内将等效控制项强制限幅,或切换到饱和形式。第一种是我个人更推荐的做法。
另外还要注意,即使在非奇异终端滑模中,如果 (m/n) 选择不当,比如选成了 (m/n < 1),那实际上你又在用一个传统终端滑模面,只是形式变了,奇异还是会回来。建议每次写完滑模面,都检查一下控制律里所有指数的取值范围,在注释里标清楚哪些指数必须大于零、哪些必须小于零——这个小习惯能节约大量排查时间。
4.2 抖振调不动怎么办
抖振是滑模控制的“招牌副作用”。终端滑模里由于分数幂项的存在,系统状态在零点附近的收敛极其猛烈,控制量往往比线性滑模更“躁”。有几次我在示波器上看到控制量就像一把梳子,频率高、幅值也不小,电机跟着嗡嗡响。
如果边界层法和连续化都试过了,抖振还是很明显,我通常会检查三个地方。第一,离散化步长是不是太大了。仿真步长0.01秒和0.001秒的结果可能完全不同,抖振往往在步长偏大时更容易被激励。第二,符号函数切换项的增益 (k) 是不是偏大了。理论上 (k>D) 就行,很多同学习惯性地把 (k) 调到很大,以为“更强鲁棒性”,实际上只会让控制量在滑模面两侧撞得更狠。先试着把 (k) 降到扰动上界的1.2到1.5倍,看抖振是否明显改善。第三,如果系统本身有测量噪声,那么 (s) 的计算本身就带噪,符号函数会把噪声也一并放大。这时候滤波器就派上用场了,但要注意滤波延时对滑模稳定性的影响,一般质量好的无相移滤波器或低通滤波器配合小步长是首选。
4.3 负数分数幂的代码陷阱
这里必须多说几句,因为我在各种代码里见过无数种花式踩坑。比如在 Python 里直接写( -0.008 ) ** ( 5.0/3 ),会得到一个复数,因为浮点数幂运算遵循的是实数域指数法则,对负数底数不友好。如果接着把这个复数传给控制量,整个系统很快就乱了。
靠谱的做法是写一个工具函数:
def frac_power(x, p, q): # p, q are positive odd numbers return math.copysign(abs(x) ** (p/q), x)或者将分数幂拆成开方运算,例如x ** (5./3)可以写成(x**5) ** (1./3),但前提是你对数值库的开方函数足够了解。我自己更倾向用copysign那版,简洁且不会出幺蛾子。这个工具函数在传统终端滑模和非奇异终端滑模里都能用,建议直接封装成公共函数,整个项目共用。
4.4 参数速查与调试建议表
最后把调试过程中常用的建议整理成一张速查表,方便大家照着排查。
| 现象 | 可能原因 | 排查手段与建议 |
|---|---|---|
| 控制量瞬间爆炸 | 传统终端滑模奇异 | 换非奇异终端滑模,或加限幅/边界层 |
| 稳态误差始终存在 | 边界层太厚或 (k) 不足 | 减小 (\Delta),增大 (k) 到扰动量1.5倍左右 |
| 抖振严重 | (k) 过大或步长过大 | 降低 (k),减小仿真步长,改用连续化趋近 |
| 输出出现复数或NaN | 负数分数幂计算错误 | 使用copysign(abs(x)**(p/q), x)函数 |
| 收敛速度不够快 | (\beta) 偏小 | 增大 (\beta),观察控制量峰值,取折中 |
| 高频振荡 | 未建模动态放大 | 加前级滤波器,适当降低 (m/n),减轻控制器带宽 |
如果是做实物实验,我额外还有几条建议。第一,控制量必须加饱和限幅,防止启动瞬时控制量冲击执行器。第二,滑模面的初值尽量做归一化或缩放,避免误差量纲差异导致数值问题。第三,调试时先让系统停在零位附近,用小扰动验证收敛,再逐步加大跟踪轨迹的幅值。每一步都确认稳定了再前进,比一次性追求大范围稳定要安全得多。
我个人在实际操作中还有一个习惯:把终端滑模的收敛时间表达式当作一个设计公式用,而不是仅仅当作理论分析。比如设计任务要求误差在0.5秒内收敛到零,那我就用 (t_r) 的表达式反推需要的 (\beta) 值,再在这个值附近做微调。这比盲目试参高效很多。另外,终端滑模再好也只是控制器设计的一部分,它解决的是“收敛速度”和“鲁棒性”的平衡问题,采样率、执行器带宽、传感器噪声这些工程因素仍然需要一并考虑,否则再漂亮的理论也难在实物上发挥出应有的效果。