简介:面向机械臂智能控制方向的高校本科生与硕士生,该压缩包围绕双关节机械臂的自适应模糊反演控制方法,提供了一套可直接运行的Matlab仿真实现,适用于智能控制、自适应控制及机器人技术等方向的课题研究。包内共9个文件,以4个.m脚本和1个Simulink模型(.mdl)为核心:.m脚本依次实现被控对象建模、模糊隶属度函数设计、控制器构建与结果绘图,.mdl模型则展示完整闭环仿真结构;另附3张仿真结果图和1份文字说明,便于对照曲线验证控制效果。资源整体仅472KB,却涵盖了从模型搭建到结果分析的完整链路;.m函数采用模块化编程,便于移植到其他机械臂模型或修改控制器参数。支持Matlab 2014/2019a/2021a多个版本,说明文档中提供了运行方法与基本排错提示,可帮助读者快速复现。目前已有538人学习下载,适合用于课程设计、实验报告或毕业设计的前期验证与二次开发。
1. 双关节机械臂的自适应模糊反演控制,先把理论框架立起来
双关节机械臂轨迹跟踪的真正难点,不是“多一个关节”,而是参数不确定。惯性矩阵、科里奥利项、重力项只要有质量或杆长不准,计算力矩法就会从指数收敛退化成带静差的 PD 控制。自适应模糊反演控制想解决的就是这件事:反演负责把二阶非线性系统拆成两个递推误差面,保证控制器结构稳定;模糊系统在线逼近模型里说不清的那部分动力学;自适应律让参数不靠离线辨识就自己更新。它适合负载变化、末端质量未知、模型参数不准的机械臂场景。对做机械臂控制仿真、复现自适应控制论文的工程师和研发人员来说,把下面的推导和 MATLAB 脚本对照着看,会比只跑压缩包里的结果图更有收获。
2. 双关节机械臂动力学模型与模糊反演控制的问题提法
2.1 两连杆刚性机械臂的矩阵形式与参数不确定性
最常见的最小复现场景是平面两连杆刚性机械臂,所有质量集中在连杆末端,动力学写成标准矩阵形式:
$M(q)\ddot{q} + C(q,\dot{q})\dot{q} + G(q) = \tau + d$
其中 $q=[q_1,q_2]^T$ 是两个关节角,$M(q)$ 是 $2\times2$ 对称正定惯性矩阵,$C(q,\dot{q})$ 是科里奥利/离心项矩阵,$G(q)$ 是重力项,$\tau$ 是关节力矩,$d$ 是外部扰动。按集中质量假设取 $m_1,m_2,l_1,l_2,g$ 这组参数,$M,C,G$ 的显式表达式为:
$M(q)=\begin{bmatrix} (m_1+m_2)l_1^2+m_2l_2^2+2m_2l_1l_2\cos q_2 & m_2l_2^2+m_2l_1l_2\cos q_2 \ m_2l_2^2+m_2l_1l_2\cos q_2 & m_2l_2^2 \end{bmatrix}$
$C(q,\dot{q})=\begin{bmatrix} -m_2l_1l_2\sin q_2,\dot{q}_2 & -m_2l_1l_2\sin q_2(\dot{q}_1+\dot{q}_2) \ m_2l_1l_2\sin q_2,\dot{q}_1 & 0 \end{bmatrix}$
$G(q)=\begin{bmatrix} (m_1+m_2)gl_1\cos q_1+m_2gl_2\cos(q_1+q_2) \ m_2gl_2\cos(q_1+q_2) \end{bmatrix}$
这套式子是“被控对象”,控制器里不允许直接出现真实的 $m_1,m_2$。很多初学实现把 $M,C,G$ 既当模型又当控制器的一部分,那其实是计算力矩法,不是自适应控制。这里要区分清楚:仿真里用真实参数给被控对象,模糊系统逼近的则是控制力矩 $\tau$ 要抵消的那部分复合未知项。
需要特别提醒的是 $C$ 矩阵的取法并不是唯一的。这里采用满足 $\dot{M}=C+C^T$ 的形式,即 $\dot{M}-2C$ 是反对称矩阵。这个属性在后面稳定性分析中会让 $z_2^T(\dot{M}-2C)z_2=0$,是反演设计里最常用的一个手法。如果从别的论文里直接抄一个不同形式的 $C$ 矩阵,但沿用这里的稳定性推导,多出来的项会让闭环分析对不上。仿真复现时先检查 $C$ 矩阵是否满足这个关系。
2.2 控制目标与反演设计的误差变量
控制目标是让关节角 $q$ 跟踪一条充分光滑的参考轨迹 $q_d(t)$,跟踪误差 $z_1=q-q_d$ 最终进入原点附近的小邻域,同时控制力矩保持在合理范围。自适应模糊反演的基本思路是分两步,不直接对 $q$ 设计力矩,而是先设计一个虚拟控制:
$\alpha_1 = \dot{q}_d - K_1 z_1$
其中 $K_1$ 是正定增益矩阵。这里把 $\dot{q}_d-K_1z_1$ 当作“希望 $\dot{q}$ 具备的形式”。如果 $\dot{q}$ 真的等于 $\alpha_1$,那么 $z_1'=-K_1z_1$,跟踪误差指数收敛。但 $\dot{q}$ 不会自动等于 $\alpha_1$,二者之差定义为:
$z_2 = \dot{q} - \alpha_1$
于是 $z_1' = z_2 - K_1 z_1$。控制目标从“让 $q$ 直接跟踪 $q_d$”转成“让 $z_2$ 尽快收敛到零”。只要 $z_2\to 0$,$z_1$ 就指数趋近零。这一步把二阶系统的控制问题拆成两个一阶误差面的递推,这就是反演控制名称的由来。
第二个误差面 $z_2$ 表达式中包含 $\alpha_1$ 的导数,而 $\alpha_1$ 含 $z_1$ 和 $q_d$,所以要计算:
$\dot{\alpha}_1 = \ddot{q}_d + K_1^2 z_1 - K_1 z_2$
这里用的是 $\dot{z}_1=z_2-K_1z_1$。公式中的 $K_1^2z_1$ 项常被初学实现漏掉,漏掉后虚拟控制导数不完整,仿真里误差会出现振荡却不收敛。这是我拿到这类代码后第一优先检查的位置。
为什么不用传统的线性参数化自适应?标准模型参考自适应反演要求 $M,C,G$ 满足线性参数化(LP)条件,即未知动力学可以写成回归矩阵 $Y(q,\dot{q})$ 乘常数未知向量 $\theta$。纯刚体模型下这个条件成立,但一旦加入摩擦、死区、非线性负载,LP 结构就被破坏。模糊系统恰好不依赖这种结构:只要被逼近函数充分光滑,模糊基函数就能在紧集内任意逼近,配合自适应律在线调整权值。这是“自适应模糊反演”而不是“标准自适应反演”的核心理由。
3. 自适应模糊反演控制器的分步推导
3.1 从误差动力学看控制器必须补偿什么
把第二个误差面求导,代入机械臂动力学。因为 $\dot{q}=z_2+\alpha_1$,展开后得到:
$M\dot{z}_2 = \tau - W - Cz_2 + d$
其中未知复合项为:
$W = C\alpha_1 + G + M\dot{\alpha}_1$
这一项包含了模型参数和虚拟控制导数,正是控制器需要精确补偿、但实际又不知道的部分。取李雅普诺夫函数 $V=\frac12 z_1^Tz_1+\frac12 z_2^TMz_2$,求导后利用 $z_1'=z_2-K_1z_1$ 和 $\dot{M}=C+C^T$:
$V' = -z_1^TK_1z_1 + z_1^Tz_2 + z_2^T(\tau - W + d)$
如果 $W$ 已知,取 $\tau^* = W - z_1$ 就能消掉交叉项 $z_1^Tz_2$,得到 $V'=-z_1^TK_1z_1+z_2^Td$,在有界扰动下闭环一致终极有界。问题是 $W$ 里藏着真实 $M,C,G$,控制器拿不到。模糊系统要补上的就是这个“孔”。
3.2 用模糊逻辑系统在线逼近未知复合项
采用乘积推理机、单值模糊器、中心平均解模糊化的标准模糊系统。对每个输入变量定义若干高斯隶属函数,输入向量 $x\in\mathbb{R}^n$,第 $r$ 条规则的模糊基函数为:
$\varphi_r(x)=\dfrac{\prod_{i=1}^{n}\mu_{i,j_{r,i}}(x_i)}{\sum_{r=1}^{R}\prod_{i=1}^{n}\mu_{i,j_{r,i}}(x_i)+\varepsilon}$
其中 $R=\prod_i N_i$ 为规则总数,$N_i$ 是第 $i$ 个输入的隶属函数个数,$\varepsilon$ 是防除零的小常数。于是 $W$ 的两个分量分别用两个模糊系统逼近:
$\hat{W}_i(x)=\theta_i^T\varphi(x),\quad i=1,2$
$\theta_i$ 是 $R$ 维权值向量,也就是自适应参数。这里输入 $x$ 选什么,直接决定规则数。如果严格按“把所有状态和跟踪信号都放进去”的做法,取 $x=[q_1,q_2,\dot{q}_1,\dot{q}_2,z_1,z_2]$ 六个变量,每个变量分 3 个隶属函数,规则数是 $3^6=729$,每个 $\theta_i$ 就有 729 维;如果每个变量分 5 个,规则数膨胀到 15625 条,普通笔记本做变步长积分会非常慢。
工程代码里常见做法是先降维。下面这套实现把模糊输入取成四个误差信号 $x=[z_{1,1},z_{1,2},z_{2,1},z_{2,2}]$,每个变量 3 个高斯隶属函数,规则数压到 $3^4=81$,再用自适应律在线补足输入选择受限带来的额外逼近误差。代价是理论上只能说逼近误差有界,最终稳态误差界会比全状态输入时略大,但换来的是代码能跑、调参直观。对复现论文实验来说,这个折中很实用。
3.3 自适应律与李雅普诺夫稳定性结论
控制器取:
$\tau = \hat{W} - z_1$
也就是用模糊输出替代理想控制律里的 $W$,同时保留 $-z_1$ 项用于抵消第一个误差面交叉项。把 $\theta_i$ 的最优逼近权值记为 $\theta_i^*$,逼近误差 $w_i=W_i-\theta_i^{T}\varphi$ 有界 $|w_i|\le \bar{w}_i$。定义参数误差 $\tilde{\theta}_i=\theta_i-\theta_i^$,自适应律采用带 σ 修正的形式:
$\dot{\theta}i = \Gamma_i\big(z{2,i}\varphi(x) - \sigma_i\theta_i\big),\quad i=1,2$
$\Gamma_i$ 是正定学习率矩阵,实现中取标量乘单位阵;$\sigma_i>0$ 是漏项系数。σ 修正项的作用是防止参数在持续激励不足时无限漂移,工程仿真里必须加,不加就会出现“误差已经收敛但 $|\theta|$ 缓慢线性增长”的典型现象。
把控制器和自适应律代入 $V$ 的导数,利用 $\tilde{\theta}^T\theta=\frac12(|\tilde{\theta}|^2+|\theta|^2-|\theta^*|^2)$ 整理得到:
$V'\le -z_1^TK_1z_1 - \frac{\sigma}{2}|\tilde{\Theta}|^2 + \frac{\sigma}{2}|\Theta^*|^2 + |z_2|(\bar{w}+\bar{d})$
其中 $\bar{d}$ 是扰动上界,$|\tilde{\Theta}|^2=|\tilde{\theta}_1|^2+|\tilde{\theta}_2|^2$。这个不等式说明:当 $V$ 足够大时 $V'$ 为负,闭环信号有界,跟踪误差一致终极有界。注意结论不是“误差收敛到零”,而是“收敛到原点的可调邻域”,邻域大小由 $K_1$、σ、模糊逼近误差上界和扰动上界共同决定。仿真里看到 ±0.01 rad 量级的稳态误差,大概率是设计内行为,而不是代码写错了。
3.4 实现时自适应参数放进状态向量
实现中 $\theta_1,\theta_2$ 不能作为全局变量放在导数函数里更新,否则 ode45 的变步长机制会破坏每一步“状态-参数”的同步,结果不可复现。常见做法有两个:一是把 $\theta$ 作为扩展状态,$X=[q;\dot{q};\theta_1;\theta_2]$,直接交给 ode45,但状态维度会到 $4+2R$,R 大时变步长积分变慢;二是自写固定步长 RK4,每一步同时更新 $q,\dot{q},\theta_1,\theta_2$。下面采用第二种,R=81 时状态维度 166,RK4 固定步长足够稳,代码也容易逐行看懂。
4. MATLAB 仿真实现:脚本结构、运行方法与结果曲线
4.1 文件组成与最小运行命令
这类压缩包一般包含主脚本、被控对象模型、模糊基函数、参考轨迹和结果图。文件命名可能不同,按职责替换即可。这里整理一套可直接运行的版本:
| 文件 | 职责 |
|---|---|
main_backstepping.m | 主脚本,设置参数、积分、绘图 |
plant_and_control.m | 被控对象 + 控制器 + 自适应律,返回导数 |
fuzzy_basis.m | 计算归一化模糊基函数 |
build_mf.m | 生成高斯隶属函数中心与宽度 |
two_link_model.m | 两连杆真实被控对象动力学 |
ref_traj.m | 参考轨迹及其一阶二阶导数 |
rk4_step.m | 固定步长四阶龙格库塔单步积分 |
运行方法:把所有.m文件解压到同一目录,MATLAB 当前路径切换到该目录,命令行输入main_backstepping回车,或者打开主脚本直接点“运行”。R2016b 之后的版本都不需要额外工具箱。如果直接运行报“未定义函数”,第一反应是当前路径没切对,不是代码问题。中文注释在老版本 Windows MATLAB 里可能出现乱码,把.m文件另存为 UTF-8 或 GBK 即可。
4.2 主脚本与核心控制函数
主脚本里先设参数,再初始化状态,最后循环积分:
%% 主脚本:双关节机械臂自适应模糊反演控制 clear; clc; close all; % 被控对象真实参数(控制器不知道这些值) params.m1 = 1.0; params.m2 = 1.0; params.l1 = 1.0; params.l2 = 1.0; params.g = 9.8; % 控制与自适应参数 params.K1 = diag([5, 5]); params.K2 = diag([5, 5]); params.gamma = 20; % 学习率 params.sigma = 0.01; % sigma修正系数 % 模糊系统:4个输入,每个3个高斯隶属函数 nMF = 3; params.xrange = [-1 1; -1 1; -2 2; -2 2]; % z1_1,z1_2,z2_1,z2_2 量程 [params.c, params.sig] = build_mf(params.xrange, nMF); params.R = nMF^4; % 规则数 = 81 % 固定步长 RK4 积分 dt = 0.005; T = 10; t = 0:dt:T; N = length(t); X = zeros(4 + 2*params.R, N); X(1:4, 1) = [0.2; -0.3; 0; 0]; % 初始 q1, q2, dq1, dq2 X(5:end, 1) = 0; % 自适应参数从零开始 % 记录控制量与误差 tau = zeros(2, N-1); z1_rec = zeros(2, N-1); z2_rec = zeros(2, N-1); for k = 1:N-1 [~, tau(:,k), z1_rec(:,k), z2_rec(:,k)] = ... plant_and_control(t(k), X(:,k), params); X(:,k+1) = rk4_step(@(tt,xx) plant_and_control(tt,xx,params), ... t(k), X(:,k), dt, params); end参数含义:K1决定第一个误差面的收敛速度,K2决定第二个误差面的阻尼,gamma是自适应学习率,sigma是参数漂移抑制系数。8自己体会:循环里多调一次plant_and_control只是为了记录力矩和误差,实际积分只取第一个返回值,代码是慢了一点,但每一步状态与参数完全对齐。
核心函数plant_and_control.m同时完成三件事:计算控制器、计算被控对象动力学、计算自适应律:
function [dX, tau, z1, z2] = plant_and_control(t, X, params) % X = [q1; q2; dq1; dq2; theta1; theta2] q = X(1:2); dq = X(3:4); theta1 = X(5:4+params.R); theta2 = X(5+params.R:end); [qd, dqd, ddqd] = ref_traj(t); z1 = q - qd; alpha1 = dqd - params.K1 * z1; % 虚拟控制 z2 = dq - alpha1; % 模糊输入取误差信号,计算基函数 x_fuzzy = [z1; z2]; phi = fuzzy_basis(x_fuzzy, params.c, params.sig); % 模糊系统输出两个关节的 W_hat Theta = [theta1'; theta2']; % 2 x R W_hat = Theta * phi; % 2 x 1 % 控制力矩:tau = W_hat - z1 tau = W_hat - z1; % 被控对象:M(q)ddq + C(q,dq)dq + G(q) = tau + d [M, C, G] = two_link_model(q, dq, params); d_pert = [0.2*sin(3*t); 0.2*cos(3*t)]; % 外部扰动 ddq = M \ (tau + d_pert - C*dq - G); % 自适应律:带 sigma 修正 dtheta1 = params.gamma * (z2(1)*phi - params.sigma*theta1); dtheta2 = params.gamma * (z2(2)*phi - params.sigma*theta2); dX = [dq; ddq; dtheta1; dtheta2]; end逻辑顺序是:先算误差面和虚拟控制,再用模糊基函数得到 $\hat{W}$,组合出力矩,然后把力矩送进被控对象求 $\ddot{q}$,最后用 $z_2$ 和基函数更新自适应参数。注意tau = W_hat - z1里的-z1不能省,它是反演设计里抵消交叉项的关键。模糊基函数fuzzy_basis.m中每个输入的高斯隶属函数宽度直接取该变量量程的 60% 除以隶属函数间距,量程设太窄会让基函数迅速饱和,这一点在第五章继续讲。
4.3 仿真参数与结果判读
按上面的参数组合,参考轨迹取 $q_d=[\sin t;\cos t]$,初始关节角偏差 $[0.2;-0.3]$,加入幅值 $0.2$ 的正弦扰动。仿真结果通常表现为:前 0.5 到 1 秒内两个关节角快速跟上参考轨迹,跟踪误差进入 $10^{-2}$ rad 量级;控制力矩连续且没有高频抖振,幅值在几十 N·m 量级,具体取决于K1、K2。如果力矩曲线出现锯齿状振荡,先降低gamma或加大sigma,而不是怀疑模糊系统写错了。
绘图代码中主要看三类曲线:$q_1,q_2$ 与参考轨迹的对比、跟踪误差 $z_1$、控制力矩 $\tau$。跟踪误差曲线最容易暴露问题:如果误差单调收敛后稳定,说明控制器与自适应律配合正常;如果误差在零附近做等幅振荡,多半是gamma过大导致参数抖动;如果误差收敛后缓慢漂移,优先查sigma是否太小。
%% 结果绘图 q1 = X(1,:); q2 = X(2,:); [qd1, qd2] = ref_traj(t); figure; subplot(2,1,1); plot(t, q1, 'b', t, qd1, 'r--', 'LineWidth', 1.2); legend('q_1', 'q_{1d}'); xlabel('t/s'); ylabel('q_1/rad'); subplot(2,1,2); plot(t, q2, 'b', t, qd2, 'r--', 'LineWidth', 1.2); legend('q_2', 'q_{2d}'); xlabel('t/s'); ylabel('q_2/rad'); figure; plot(t(1:end-1), z1_rec(1,:), 'r', t(1:end-1), z1_rec(2,:), 'b', 'LineWidth', 1.2); legend('z_{1,1}', 'z_{1,2}'); xlabel('t/s'); ylabel('跟踪误差/rad');ref_traj.m返回三行输出,分别对应位置、速度、加速度,这在plant_and_control里一次取齐。以后换参考轨迹时只需要改这个文件,控制器不用动。如果想把误差收敛再压一个量级,可以同时增大K1、K2并适当提高gamma,但要留意力矩幅值会同步上升。
5. 调参边界与验证技巧:自适应模糊反演控制器的可靠跑法
5.1 先用“关自适应”做对照实验
判断模糊项是否真正生效,最直接的办法是做一组对照:在plant_and_control里加一个开关enable_adapt,关闭时令dtheta1=0; dtheta2=0,此时控制器退化成“固定模糊权值的反演控制”,误差主要靠K1、K2的 PD 性质压住。同一参考轨迹下先关自适应跑一遍,再开自适应跑一遍,对比 $z_1$ 曲线。如果两条曲线差别很小,说明模糊项基本没起作用,隶属函数量程或输入选择可能有问题;如果差别明显,说明自适应确实在补偿 $W$。这个实验 5 分钟出结果,比盯着误差曲线猜快得多。
5.2 隶属函数量程与学习率的边界
隶属函数量程是最容易被忽略的坑。先用一次开环或初值实验记录四个模糊输入的 min 和 max,再把params.xrange的上下限设为该范围的 1.2 倍。量程太窄时,误差信号一超出范围,所有高斯隶属函数输出同时接近 0,归一化后 $\varphi$ 趋向均匀分布,模糊逼近失效;量程太宽时,高斯函数重叠区太大,基函数对输入变化不敏感,收敛速度明显下降。学习率gamma从 10 起步,每次乘 2,观察 $z_2$ 或力矩是否出现高频振荡。gamma过大时参数更新步长过大,力矩曲线会变得毛糙。sigma一般取 0.001 到 0.1 之间,太大相当于给参数加阻尼,稳态误差变大;太小则 $|\theta|$ 可能出现缓慢漂移。
5.3 换参考轨迹验证泛化性
把ref_traj.m里的正弦轨迹换成频率不同或带过渡段的轨迹,比如 $q_d=[0.5\sin(2t);0.3\cos(1.5t)]$,同时把params.xrange按新轨迹的误差范围同步调整。如果跟踪仍然稳定,说明模糊自适应项不是过拟合到某条特定轨迹。如果换了轨迹后误差变大,优先检查模糊输入量程,而不是怀疑反演设计。最后一个实用技巧:把dt从 0.005 减小到 0.001 重新跑一遍,若误差曲线发生明显变化,先怀疑积分步长,而不是控制器。
本文还有配套的精品资源,点击获取