拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

机器人运动学滑模变结构控制:Simulink仿真设计与抖振抑制实践

机器人运动学滑模变结构控制:Simulink仿真设计与抖振抑制实践

滑模变结构控制这名字听着唬人,但在机器人运动学仿真里,它其实是个特别“直接”的控制思路——说白了就是设计一条误差收敛的“滑模面”,然后用不连续的切换控制把系统状态“按”到这条面上,再沿着面滑到零点。我当年第一次在Simulink里把二连杆机械臂的运动学模型和滑模控制器接起来时,看到示波器里那条误差曲线稳稳收敛,才真正理解课本上那句“对参数摄动和外部扰动具有鲁棒性”是什么意思。这篇就围绕“机器人运动学控制 + Simulink仿真模型 + 滑模变结构控制”三件事展开,把建模、控制器设计、仿真实操和踩坑经验一次讲透。适合刚接触滑模控制的研究生、做毕业设计的本科生,以及想快速验证控制算法的工程师。

1. 先搞清楚机器人运动学模型

1.1 为什么从运动学入手

很多人一上来就怼动力学方程,结果被惯性矩阵、科氏力、重力项搞得焦头烂额。滑模控制虽然是鲁棒控制里的常客,但学习路径上完全可以先从运动学层面切入。运动学只研究关节角度与末端位置之间的映射关系,不涉及力/力矩与加速度的因果,模型形式简单,控制目标也直观——就是让末端或关节角度精确跟踪期望轨迹。在这个层面上把滑模设计的逻辑跑通,再去碰动力学,会轻松得多。

从工程角度看,机器人运动学控制场景也很常见:视觉引导的末端定位、关节空间轨迹跟踪、冗余机械臂的运动规划等,本质上都需要先解决“让关节角度按期望曲线走”的问题。所以用二连杆机械臂作为仿真对象,既保留了多轴耦合的特征,又不会像六轴机械臂那样把雅可比矩阵推导变成灾难。等你把二连杆的运动学滑模控制吃透,换成其他构型只是换一套正解公式而已。

1.2 二连杆机械臂的运动学方程

我采用最常见的平面二连杆模型,两个连杆长度分别为 (L_1)、(L_2),关节角度为 (\theta_1)、(\theta_2)。末端位置 ((x, y)) 由正运动学给出:

[ x = L_1 \cos(\theta_1) + L_2 \cos(\theta_1 + \theta_2) ] [ y = L_1 \sin(\theta_1) + L_2 \sin(\theta_1 + \theta_2) ]

对时间求导,得到末端速度与关节角速度的关系:

[ \dot{x} = -L_1 \sin(\theta_1)\dot{\theta}_1 - L_2 \sin(\theta_1 + \theta_2)(\dot{\theta}_1 + \dot{\theta}_2) ] [ \dot{y} = L_1 \cos(\theta_1)\dot{\theta}_1 + L_2 \cos(\theta_1 + \theta_2)(\dot{\theta}_1 + \dot{\theta}_2) ]

写成矩阵形式就是 (\dot{\mathbf{p}} = \mathbf{J}(\boldsymbol{\theta}) \dot{\boldsymbol{\theta}}),其中 (\mathbf{J}) 是雅可比矩阵。运动学控制的目标通常是:给定期望末端轨迹 (\mathbf{p}_d(t)),求关节角速度指令 (\dot{\boldsymbol{\theta}})。如果只用逆雅可比 (\dot{\boldsymbol{\theta}} = \mathbf{J}^{-1}(\dot{\mathbf{p}}_d + \mathbf{K}\mathbf{e})),那是经典的“运动学PID”,但面对模型误差和扰动时跟踪性能会打折。滑模控制在这里的用法,就是针对跟踪误差设计鲁棒控制器,不依赖精确的逆雅可比。

在Simulink里搭模型时,不少教程喜欢直接用积分模块把 (\dot{\boldsymbol{\theta}}) 变成 (\boldsymbol{\theta}),再用角度计算末端位置。我建议把这些运算封装进一个“正运动学子系统”,输入关节角度,输出末端位置和雅可比矩阵,这样后期换三连杆、换球坐标都很方便。模块层面,用Fcn模块或MATLAB Function都可以,但MATLAB Function写雅可比更清晰,还能顺便输出条件数以观察奇异性。

2. 滑模变结构控制的核心思路

2.1 滑模面的设计

滑模控制的设计分两步:选滑模面,定控制律。先说滑模面。对于关节角度跟踪问题,定义误差 (e = \theta_d - \theta),常见的线性滑模面为:

[ s = \dot{e} + \lambda e ]

其中 (\lambda > 0)。这个面的物理意义很直观:如果系统状态能保持在 (s = 0) 上,那么 (\dot{e} = -\lambda e),误差指数收敛到零,收敛速度由 (\lambda) 决定。你可以把 (s) 理解成“误差空间的综合指标”,它同时包含位置误差和速度误差。当 (s) 不为零时,控制器要驱动系统让 (s) 趋向零,这个过程叫“到达阶段”;一旦 (s = 0),就进入“滑模阶段”。

之所以说滑模控制“对匹配扰动不敏感”,是因为在滑模面上系统运动由滑模面方程决定,原有的动力学参数被“替换”了。当然,前提是控制增益能克服扰动上界,否则系统会被扰动推出滑模面。这个“上界”的概念在设计符号函数增益时特别关键,后面细说。

2.2 趋近律与抖振抑制

光让 (s = 0) 还不够,得规定 (s) 怎么走向零。最粗暴的做法是用符号函数:

[ \dot{s} = -\eta ,\text{sgn}(s) ]

对应控制律里会出现 (\eta ,\text{sgn}(s)) 这样的切换项。这种“指数趋近律”简单,但会导致一个经典问题——抖振。因为符号函数在零附近高速切换,理想状态下是无限频率,实际离散仿真里就会表现为高频振荡,反映在关节角度曲线上就是毛刺或极限环。很多初学者第一次跑仿真,看见角度曲线抖得像心电图,第一反应是模型错了,其实只是符号函数增益太大。

抑制抖振的常规方法有几种:

  • 用饱和函数 (\text{sat}(s/\phi)) 代替 (\text{sgn}(s)),在边界层内做线性过渡,代价是牺牲一点收敛精度。
  • 用超螺旋算法等高阶滑模,本质是让切换项作用在 (s) 的高阶导数上,抖振大幅减弱,但参数调节复杂些。
  • 适当调小切换增益 (\eta),只要能覆盖模型误差和扰动的上界就行,没必要给得过大。

我个人在做运动学仿真时,先用饱和函数把逻辑跑通,再换成符号函数对比抖振差异,这个对比过程本身就是学习滑模控制最好的教材。你可以把饱和函数边界层厚度 (\phi) 设成 0.01~0.05,增益 (\eta) 先设个保守值,比如 0.5,然后在仿真里一点点加。

2.3 为什么要用“趋近律”而不是直接设计控制输入

运动学模型的输入是关节角速度 (\dot{\boldsymbol{\theta}}),不是力矩。所以控制律的形式不能照搬动力学里的 (u = \tau)。这里需要用“运动学级”的虚拟控制量 (v = \dot{\boldsymbol{\theta}}_c),把它当作关节角速度指令。我们设计:

[ \dot{\boldsymbol{\theta}}_c = \mathbf{J}^{-1}\left(\dot{\mathbf{p}}_d + \lambda \mathbf{e} + \eta ,\text{sgn}(s)\right) ]

其中 (\mathbf{e} = \mathbf{p}_d - \mathbf{p}) 是末端位置误差,(s = \dot{\mathbf{e}} + \lambda \mathbf{e})。这块设计逻辑是:如果用 (\dot{\boldsymbol{\theta}}_c) 驱动真实机械臂,那么末端速度会趋近期望速度,误差沿滑模面收敛。在Simulink里,这个 (\dot{\boldsymbol{\theta}}_c) 通常不能直接作为物理关节速度输入,需要再串一个底层速度环,或者直接把 (\dot{\boldsymbol{\theta}}_c) 当作指令给理想速度源。做运动学级仿真时,我用的是“积分器+理想速度驱动”:把 (\dot{\boldsymbol{\theta}}_c) 积分得到实际角度,再反馈给正运动学模块,这样简单且能看清控制器核心性能,不掺动力学干扰。

当然,这种理想化模型忽略了很多执行器特性,但它作为学习载体非常合适——你可以单独评估滑模控制的鲁棒性,比如给雅可比矩阵加5%的参数偏差,看误差是否还能收敛,这就比纯粹的PID更能体现滑模优势。

3. Simulink仿真模型搭建全流程

3.1 模型架构与模块选型

整个Simulink模型分四块:轨迹生成、滑模控制器、被控对象(正运动学+雅可比)、信号观测。我从一个大框架说起,你按这个结构搭不容易乱。

轨迹生成模块:我用MATLAB Function生成圆形轨迹,圆心 ((0.6, 0.4)),半径 0.1,角频率 0.5 rad/s,仿真时长 10 秒。输出期望末端位置 (\mathbf{p}_d) 和期望速度 (\dot{\mathbf{p}}_d)。也可以在Constant模块里用Clock和表达式实现,但MATLAB Function最好改参数。

滑模控制器模块:输入期望位置、期望速度、实际位置、实际角度,输出 (\dot{\boldsymbol{\theta}}_c)。这个模块内部用MATLAB Function实现雅可比计算、误差计算、趋近律和控制律。注意雅可比矩阵可能奇异,二连杆在某些位形下 (\det(\mathbf{J}) = 0),需要在函数里加个判断,如果行列式绝对值小于阈值,就用伪逆或阻尼最小二乘。常见做法是加个参数 (\epsilon):

[ \mathbf{J}^+ = \mathbf{J}^T(\mathbf{J}\mathbf{J}^T + \epsilon \mathbf{I})^{-1} ]

这个 (\epsilon) 设成 0.01 左右,能避免仿真中途因奇异而报NAN。

被控对象模块:理想速度源就是两个积分器,输入 (\dot{\boldsymbol{\theta}}_c),输出实际关节角度 (\boldsymbol{\theta}),反馈给控制器和正运动学。如果想更贴近真实,可以在这个积分器前加一阶惯性环节模拟执行器延迟,但学习阶段别加,先看纯运动学下的控制效果。

信号观测模块:用Scope观察末端位置跟踪、关节角度曲线、误差和滑模面 (s)。建议把误差和 (s) 单独放一个Scope,方便看收敛速度。

3.2 机器人运动学子系统实现

我习惯把正运动学封装成一个子系统,内部用MATLAB Function写:

function [pos, J] = fk_2link(theta, L1, L2) % 正运动学 q1 = theta(1); q2 = theta(2); x = L1*cos(q1) + L2*cos(q1+q2); y = L1*sin(q1) + L2*sin(q1+q2); pos = [x; y]; % 雅可比矩阵 J = [-L1*sin(q1)-L2*sin(q1+q2), -L2*sin(q1+q2); L1*cos(q1)+L2*cos(q1+q2), L2*cos(q1+q2)]; end

输入是 (\theta_1)、(\theta_2) 合成的一个向量信号,用Vector Concatenate模块或直接两路输入到MATLAB Function都行。输出pos和J。注意MATLAB Function里不要用全局变量,参数通过对话框传递。运行时长度参数 (L_1 = 0.5),(L_2 = 0.4),单位米。

这里有个容易踩的坑:MATLAB Function默认输出类型会被推断,如果初始化时没有给输出变量赋值,Simulink可能报“输出未定义”。所以在函数开头最好先写一行 (\text{pos} = zeros(2,1); J = zeros(2,2);),或者用coder.extrinsic调用不了,就直接在代码里给默认值。

3.3 滑模控制器子系统实现

控制器的MATLAB Function写法大概是这样:

function [theta_dot_cmd] = smc_controller(pd, pd_dot, p_current, theta, L1, L2, lambda, eta, phi) % pd: 期望位置2x1, pd_dot: 期望速度2x1, p_current: 实际位置2x1 % theta: 关节角2x1 [~, J] = fk_2link(theta, L1, L2); e = pd - p_current; edot = pd_dot - J * theta_dot_current; % 注意这里需要当前关节角速度 s = edot + lambda * e; % 滑模面 % 饱和函数替代符号函数 sat_s = min(1, max(-1, s / phi)); % 阻尼最小二乘逆 Jt = J'; JtJ = J * Jt + 0.01 * eye(2); Jinv = Jt * (JtJ \ eye(2)); % 控制律 theta_dot_cmd = Jinv * (pd_dot + lambda * e + eta * sat_s); end

这里隐含一个依赖:需要当前关节角速度 (\dot{\boldsymbol{\theta}})。我们的被控对象是理想积分器,所以 (\dot{\boldsymbol{\theta}}) 正好等于 (\dot{\boldsymbol{\theta}}_c),也就是控制器的输出。这就形成一个代数环:控制器输出决定实际速度,实际速度又反馈到控制器计算。Simulink会报警告“代数环”,虽然在小步长下能跑,但最好显式消除。

消除代数环的办法是:把积分器输出的状态 (\boldsymbol{\theta}) 反馈给控制器,但在控制器里用差分近似关节速度,比如 (\dot{\theta}[k] = (\theta[k] - \theta[k-1]) / h),通过Memory模块或Unit Delay实现。这样可以打破代数环,代价是速度估计有一点延迟和噪声。运动学仿真中这个噪声可接受。更优雅的方案是在被控对象里加一个一阶惯性滤波,但学习阶段我建议用Unit Delay近似,简单实用。

另一个更直接的办法:既然被控对象是积分器,控制器输出就是速度,那就别把“当前速度”当反馈,直接用期望速度的误差做滑模面。末端位置误差 (e) 是位置量,其导数可以从期望速度减去“当前速度”,但我们可以把滑模面定义为:

[ s = \dot{\mathbf{p}}_d - \dot{\mathbf{p}} + \lambda e ]

其中 (\dot{\mathbf{p}} = \mathbf{J} \dot{\boldsymbol{\theta}})。如果控制器输出 (\dot{\boldsymbol{\theta}}_c) 直接等于被控对象速度,那么 (\dot{\mathbf{p}} = \mathbf{J}\dot{\boldsymbol{\theta}}_c)。代入控制律会得到关于 (\dot{\boldsymbol{\theta}}_c) 的隐式方程。所以还是得打破代数环。我在实践中用如上Unit Delay估计速度方案,效果稳定。

3.4 参数设置与仿真配置

仿真步长选择很关键。滑模控制带符号函数切换时,如果步长太大,控制器输出在几个步长之间反复跳变,误差曲线会呈现锯齿状。我推荐用变步长ode45,最大步长设 (0.001) 秒,相对误差 (1e-4)。如果用的是饱和函数,可以放宽到 (0.005) 秒。

控制器参数我试用过一组不错的初始值:(\lambda = 3),(\eta = 0.8),(\phi = 0.05)。仿真10秒,期望轨迹是半径0.1米的圆。初始关节角度可以从末端位置反解,也可以直接设 (\theta_1 = 0.5),(\theta_2 = 0.8) 开始,让控制器自己收。注意期望轨迹的起始点最好和机械臂实际末端位置一致,否则初始误差很大,符号函数增益可能让速度指令瞬间饱和,出现超调。我一般用MATLAB脚本先算初始关节角对应末端位置,把期望轨迹的起点移到那里,比如自定义轨迹函数:

[ x_d = 0.6 + 0.1\cos(0.5t - \phi_0) ] [ y_d = 0.4 + 0.1\sin(0.5t - \phi_0) ]

其中 (\phi_0) 由初始末端位置的极角决定,这样初始误差接近零。

仿真配置里还要注意解法器是否支持信号代数环。用Unit Delay后应该没有代数环警告,如果有,可以再插入一个Memory模块在反馈路径上。模型里还建议把所有Scope数据记录到工作区,用logsout方便后续分析。

4. 仿真结果分析与调试

4.1 跟踪效果怎么看

仿真跑完,先看末端位置跟踪曲线。把期望圆和实际轨迹画在一张图里,如果轨迹重叠得比较好,说明跟踪精度高。然后看关节角度曲线,理想情况下是平滑曲线,不应有高频分量。最后看误差曲线 (e_x)、(e_y),稳态误差应该在 (10^{-3}) 量级。

还有一个关键指标是滑模面 (s) 的收敛过程。如果设计正确且增益合适,(s) 会在很短时间(比如0.1秒)内从初始值衰减到零,随后一直在零附近小幅波动。这个波动幅度取决于饱和函数边界层 (\phi) 和扰动,如果波动太大,说明增益设置不合理或者速度估计噪声大。

4.2 抖振问题与参数调节经验

最典型的问题是:用符号函数时,关节速度指令呈高频切换,角度曲线有毛刺。这时候不要急着加大 (\lambda),先检查 (\eta) 是否过大。(\eta) 的物理意义是“对抗扰动的强度”,如果模型精确、无扰动,(\eta) 只需要大于系统名义部分的误差上界。在运动学级仿真里,唯一的扰动是数值误差和速度估计误差,(\eta) 设成 0.2~0.5 通常足够。把 (\eta) 调到 2 以上,抖振会非常明显,除非你故意要观察抖振。

第二个常见问题是初始误差大导致速度指令饱和。我在控制器中加过饱和模块,限制 (\dot{\theta}_c) 幅值在 3 rad/s 以内,否则仿真早期速度会飙到几十,数值发散。这个限幅不影响稳态性能,但能显著提高仿真稳定性。

第三个问题是速度估计用Unit Delay引入的相位滞后。滞后会导致滑模面计算不准确,误差稳态值可能达不到理论精度。解决方法是在控制器里对估计的角速度做一阶低通滤波,或者用Kalman滤波的简化版。不过对于学习项目,Unit Delay足够让你理解问题所在。

5. 常见问题速查与避坑清单

5.1 高频报错与解决

  • 代数环警告:反馈路径插入Unit Delay或Memory模块,注意采样时间要与信号一致。
  • MATL AB Function输出未定义:函数开头给输出赋零值。
  • 仿真速度极慢:积分步长太小或控制器里有高频切换,可改用饱和函数并适当增大最大步长。
  • 末端轨迹发散:多半是雅可比逆接近奇异或初始误差太大,改用阻尼最小二乘逆,并做速度限幅。
  • Scope显示没有信号:检查信号线是否连错,以及MATLAB Function是否设置成了“每步更新”而不是“每帧更新”,如果是变步长仿真,最好把Scope采样时间设为“继承”。

5.2 独家实战心得

我做完这个项目后最大的体会是:学习滑模控制不能只背趋近律公式,一定要亲手在Simulink里改变 (\lambda)、(\eta)、(\phi),观察误差和滑模面的变化。建议你做一个对比实验:其他参数不变,把 (\eta) 从 0.1 调到 2,看误差收敛速度变快但抖振变强,然后把符号函数换成饱和函数,再看抖振被抑制但稳态误差略增大。这个过程10分钟就能完成,但比读十遍论文都有用。

另一个心得是,运动学级滑模控制只是入门,真正的工业应用中,滑模控制更多用在动力学层或电机电流环。但是你把运动学模型下的滑模设计逻辑理清后,再去看“滑模变结构控制”的经典文献,很多符号就不会那么吓人了。比如文献里的 (u = u_{eq} + u_{sw}),等效控制项在运动学级就对应把 (s) 的导数置零求出的控制量,切换项对应 (\eta \text{sgn}(s))。这套对应关系搞明白,滑模控制就算真正入门了。

最后再分享一个小技巧:仿真结束后,用MATLAB命令窗口运行plot(logsout)可以快速查看所有记录信号。如果你准备写报告或论文,建议把误差均方根值也计算一下,用rms(e_x)就能得到,这个指标比肉眼观察更有说服力。按照上面的步骤搭好模型,参数可以先按我给的初始值跑一遍,然后再改动各项参数观察效果。相信我,亲手调过 (s) 曲线之后,“滑模”这两个字就再也不会让你犯怵了。

返回列表