三自由度机械臂看起来不算复杂但真正做控制的时候你会发现这东西比想象中难伺候。关节之间强耦合动力学模型里全是非线性项负载一变或者参数一偏常规PID就露馅了。我这段时间一直在折腾三自由度机械臂的自适应神经网络控制用Matlab跑完整套仿真从控制器设计到代码实现把整个链路走了一遍。这篇就把我的思路、踩过的坑和能直接用的代码框架整理出来给同样在做机械臂自适应控制的朋友一个参考。1. 为什么三自由度机械臂需要自适应神经网络控制1.1 三自由度机械臂的动力学到底难在哪里先看三自由度机械臂的动力学模型标准形式是这个M(q)q̈ C(q,q̇)q̇ G(q) F(q̇) τM是惯性矩阵C是科里奥利力和离心力矩阵G是重力项F是摩擦力。每个符号都不是省油的灯——M矩阵是3x3的里面的元素取决于三个关节的角度而且非对角线元素不为零也就是说关节1加速时会牵连关节2和关节3这就是工程上常说的耦合。更要命的是C矩阵里面包含速度的平方项和交叉乘积项。你把机械臂快速挥一下离心力和科里奥利力会突然变得非常大这种非线性的剧烈变化用简单的线性控制根本压不住。再加上重力项G随着姿态变化关节在某个位置可能需要输出很大的力矩来保持静止换个姿态又可能完全不需要。这些因素叠加在一起导致三自由度机械臂的动力学呈现强非线性、强耦合、参数时变的特性。1.2 PID控制解决不了的实际问题很多人一开始都会用PID或者计算力矩法。计算力矩法的前提是你有精确的M、C、G模型通过反馈线性化把系统变成一堆解耦的双积分器然后配PD外环。听起来很完美但实操中问题很明显建模误差永远存在。摩擦力参数、连杆质心位置、转动惯量任何一个不准确反馈线性化就做不彻底。负载变化。机械臂末端抓了不同重量的东西等效到各个关节的参数全变了。你按空载模型设计好的控制律在满载时跟踪误差会明显变大。摩擦力的不确定性。库仑摩擦、粘滞摩擦、Stribeck效应这些非线性项很难精确建模而且随着温度和磨损漂移。PD控制就更不用说了纯线性反馈对周期性轨迹跟踪始终存在相位滞后和稳态误差对时变负载几乎没有应对能力。我实测过一组数据纯PD控制在空载工况下跟踪正弦轨迹误差还能看一旦末端加上负载误差立刻翻几倍而且不会自己消掉。1.3 自适应神经网络控制解决的本质问题自适应神经网络控制的核心思想很简单不跟你斤斤计较模型参数直接在线上逼近那个说不清楚的动力学项。RBF神经网络有一种性质叫万能逼近理论上只要隐层节点够多、中心布置合理它可以以任意精度逼近任意连续函数。这意味着我不需要精确知道M、C、G的具体数值只需要让神经网络去学习为了让机械臂跟踪期望轨迹关节应该补多少力矩这个函数关系。未知参数随负载变化怎么办自适应律在线调节神经网络权值负载变了权值自己跟着变。所以在工程上这条路线解决的是你不知道的东西太多但又想让系统在变化中保持性能的问题。三自由度机械臂刚好是这种方案的典型应用场景——模型非线性足够强、参数不确定性足够明显、计算量也不像六轴七轴那么夸张。2. 控制器设计RBF网络、滑模误差面和自适应律的搭配2.1 每个关节独立一个RBF网络而不是一个大网络刚开始我也考虑过一个6维甚至更多维输入的大RBF网络统一逼近整个系统的未知动力学。后来实际做起来发现不划算。三自由度机械臂三个关节虽然耦合但每个关节的动力学残差还是主要取决于本关节的状态和期望运动跨关节的信息有一部分可以归入耦合项里面处理。所以更实用的做法是每个关节独立配置一个小RBF网络。这样每个网络输入维度低节点数可以控制在一个合理的范围计算量小实机运行的时候压力也小。三个网络并行更新互不干扰某个关节出了问题也方便单独排查。这个做法在理论上有充分的支撑因为RBF网络的权值自适应律是按关节拆分的每个关节的Lyapunov函数分量独立分析最后叠加证明系统稳定性即可。2.2 滑模误差面和带鲁棒项的控制律我不直接用e qd - q作为反馈变量做简单的PD前馈而是先定义一个滑模误差面s ė Λe其中Λ是对角正定矩阵e是关节角度跟踪误差ė是角速度跟踪误差。s这个量相当于把位置误差和速度误差组合在一起只要s收敛到零附近位置和速度误差就同时被控制住了。这个处理在很多自适应控制文献里都有目的有两个一是降低系统阶数把二阶跟踪问题转化成一阶调节问题二是让误差动态具有类似PD控制的形式但设计起来更灵活。控制律采用这个结构τ Kp·e Kd·ė ŴᵀH(x) - ρ·tanh(s/δ)前两项是线性反馈保证基础稳定性第三项是RBF神经网络的输出用来逼近系统未知动力学最后一项是鲁棒项用tanh来抑制神经网络逼近误差和外部扰动。这里用tanh而不是sign是因为sign会带来控制量高频抖振实机上会激发机械结构的高频模态必死。tanh是连续函数参数δ用来控制过渡带的斜率等效于给符号函数做了一个平滑近似。2.3 自适应律的设计逻辑与参数取舍自适应律我用的是带σ修正的形式Ẇ Γ·(H·s - σ·W)这行公式里面信息量很大。Γ是学习率对角阵决定权值调整的速度H是RBF网络的基函数输出s是滑模误差σ是修正系数。为什么要加σ修正早期我做仿真的时候用不带修正的纯积分形式结果发现只要轨迹激励不充分权值就会慢慢漂移越来越大最后控制力矩剧烈振荡。加了σ修正之后权值更新会有一个向零收缩的倾向有效抑制了权值漂移。代价是稳态跟踪误差会稍微大一点点但换来的是系统的鲁棒性和实用性这笔账太划算了。参数如何选学习率Γ太大会导致控制量高频抖动太小则适应负载变化太慢。σ修正系数通常取学习率的1/10到1/50。整体上参数调节要从纯PD开始确认基础控制稳定了再逐步打开网络部分。3. 仿真三连轨迹跟踪、负载突变、参数摄动3.1 仿真实验平台与参数设置我用Matlab的m脚本和函数搭建了整个仿真控制周期取1毫秒。机械臂构型按常见的RRR串联关节臂处理三个连杆长度和质量参照小型教学机械臂的量级选取。被控对象动力学中包含重力、科里奥利力、摩擦力和电机驱动器限幅环节。核心参数我整理成了一张表方便直接对照参数取值说明Kpdiag(80, 60, 40)位置增益关节越靠近基座越大Kddiag(25, 18, 12)速度增益Λdiag(8, 8, 8)滑模面参数决定误差收敛带宽Γdiag(0.1, 0.08, 0.06)网络权值学习率σdiag(0.01, 0.01, 0.01)σ修正系数ρ0.5鲁棒项幅值δ0.05tanh平滑参数RBF节点数每关节200随机中心布置基函数宽度b0.5所有节点统一3.2 工况一正弦轨迹跟踪三个关节分别跟踪不同频率、不同幅值的正弦轨迹。这是最基础的验证场景考察的是控制器在常规工况下的跟踪精度。纯PD控制做同样的轨迹跟踪误差曲线会呈现明显的周期性起伏幅值大约在0.1到0.2弧度级别这是因为PD反馈无法完全补偿重力项和高速度下的科里奥利力。加入RBF自适应补偿之后初始几个周期权值还在调整误差出现一些波动但大约3到5秒之后误差稳定收敛到0.02弧度以内比纯PD提升了一个数量级。这个结果说明神经网络确实学到了需要补偿的那部分力矩。3.3 工况二末端负载突变在t8秒时末端突然加上一块负载等效到关节1的转动惯量增量比较大关节2和关节3的重力矩也发生突变。这个场景最能体现自适应的价值。纯PD控制在负载突变的瞬间误差猛增因为它的反馈增益是固定的无法适应新的动力学特性。PDRBF这一组在突变瞬间误差同样被冲了一下但随后权值快速调整大概1秒到2秒时间误差重新收敛到小范围。需要注意的细节是学习率如果太小重新收敛可能要5秒以上学习率太大收敛快但权值会振荡控制力矩噪声大。所以学习率的选择要综合看适应速度和控制平稳性两方面的要求。3.4 工况三动力学参数摄动与摩擦加倍仿真里把被控对象的转动惯量上调30%同时把摩擦系数改为原来的两倍但控制器内部完全不知道这些变化。这种情况相当于模型严重失配。结果很有意思加入RBF网络后控制器的跟踪性能几乎不受影响因为网络把这个未知的额外摩擦和惯量变化都吸收进逼近函数里面了。如果只用PD跟踪误差明显增大而且由于摩擦是单向的会出现很明显的稳态偏差。这个实验证明了一个核心结论自适应神经网络控制的价值主要在于应对你无法精确预知的变化而对已知模型做精确前馈并不能带来额外的性能优势。4. Matlab代码实现核心模块与调参经验4.1 整体程序架构我把整个仿真切分成四个模块各管各的改动起来清楚引导脚本设置参数、生成期望轨迹、运行主循环、画图。控制器函数输入当前状态和期望运动输出控制力矩和权值导数。动力学函数三自由度机械臂的被控对象模型含M、C、G、摩擦力。积分器四阶Runge-Kutta推进状态。这里最关键的一点是控制器函数内部完全不需要知道被控对象的M、C、G。控制器的代码里只有PD反馈、RBF网络和自适应律。被控对象动力学是被控对象的秘密控制器只能通过输出力矩和作用后的状态来间接学习它。这个边界保持得越清晰从仿真往实物迁移的时候越少心理障碍。4.2 控制器核心代码这是每个关节独立执行的控制器部分我按行解释它干了什么function [tau, dW] nn_controller(qd_i, dqd_i, ddqd_i, q_i, dq_i, W, p) % 滑模误差面 e qd_i - q_i; de dqd_i - dq_i; s de p.lambda * e; % 构造RBF网络输入包含期望运动与实际状态 x [qd_i; dqd_i; ddqd_i; q_i; dq_i]; % 输入归一化这一步非常重要 x_norm (x - p.x_mean) ./ p.x_std; % 计算高斯基函数输出 % p.c 是节点中心矩阵尺寸 m x 5 H exp(-sum((x_norm - p.c).^2 ./ (2 * p.b^2), 2)); % m维列向量 H H(:); % 控制律 tau_nn W * H; tau p.kp * e p.kd * de tau_nn - p.rho * tanh(s / p.delta); % 自适应律带sigma修正 dW p.Gamma * (H * s - p.sigma * W); end几个容易出错的地方我单独提醒归一化那一步容易漏。RBF的输入尺度如果差很多比如角度是0到1的级别角速度是0到5的级别期望加速度是0到10的级别直接用原始值会导致基函数对不同维度的变化响应完全失衡。我在调试时把x_mean和x_std设为每个输入量的运行均值和标准差效果立竿见影。H的计算要用逐行距离的平方除以2b²这个写法是标准的。维度搞错是这类代码最常见的bug建议先跑一个小维度的测试确认矩阵尺寸对得上。鲁棒项前面的负号不要丢它的作用是抵抗逼近误差符号反了系统必发散。4.3 仿真主循环和动力学积分主循环用Runge-Kutta四阶积分控制周期固定为1毫秒。期望轨迹在引导脚本中生成并事先算好速度和加速度。for k 1:length(t)-1 for i 1:3 [tau(i), dW(:,i)] nn_controller(qd(i,k), dqd(i,k), ddqd(i,k), ... q(i,k), dq(i,k), W(:,i), p); end % 被控对象动力学推进 ddq robot_dynamics(q(:,k), dq(:,k), tau); [q(:,k1), dq(:,k1)] rk4_step(q(:,k), dq(:,k), tau, Ts); % 权值更新按一阶欧拉即可 W W Ts * dW; end这里有一个细节权值更新用一阶欧拉就够了因为自适应律本质上是慢变量控制周期1毫秒已经远快于权值变化的时间尺度。但状态积分不能用一阶欧拉误差会积累必须用RK4。我最初偷懒所有积分都用欧拉结果轨迹跟踪误差里出现了一个和步长相关的系统性偏差换成RK4立刻消失。4.4 调参顺序一个参数一个参数来我踩过最大的坑是一开始就同时调Kp、Kd、Λ、Γ好几个参数结果系统发散了根本不知道是哪个参数导致。后来总结出一套固定顺序的调试流程先把RBF网络部分禁用Γ设为零只留PD反馈加鲁棒项把Kp和Kd调到PD跟踪粗稳。这一步的标准是系统不发散、误差在可观察范围。逐步增大Λ。Λ决定滑模误差面的带宽太大会放速度噪声太小则误差收敛慢。从很小的学习率慢慢往上升观察权值曲线是否平滑收敛。如果权值振荡剧烈停下来降Γ。加入σ修正抑制权值漂移通常取Γ的十分之一到二十分之一。最后做负载突变测试重点观察突变后重新收敛的时间。按这个顺序来每一步的问题都可以单变量排查不会出现全乱了之后无从下手的情况。5. 从仿真到实机比调参更值得注意的几个陷阱5.1 控制周期、限幅与饱和仿真里力矩限幅往往被忽略但真实驱动器必然有最大输出电流和力矩饱和。三关节机械臂做高速运动的时候关节力矩很容易顶到限幅此时自适应律还在试图增大网络输出权值会朝着错误的方向积累。我建议仿真阶段就加入力矩饱和环节饱和后给权值更新加一个冻结逻辑当控制量在限幅边界持续一段时间且跟踪误差没有改善时暂停对应关节的权值更新。这个逻辑在工程中很简单但对防止饱和诱发的权值漂移非常有效。5.2 微分噪声与权值漂移仿真中速度信号是干净的但实机上用的编码器微分出来的角速度噪声非常大。滑模误差面s里面包含ė项这个噪声会直接进入自适应律相当于给权值更新注入高频扰动。仿真中再完美的参数到实机上都可能因为这一点直接发散。解决办法无非三条路速度信号加低通滤波用位置环差分加上观测器估计或者把自适应律的学习率在高速时适当降低。实机调试时优先采用第二种用一个简单的状态观测器估计角速度噪声对自适应律的影响会小得多。5.3 先纯PD后开NN这条规矩救了我很多次我自己的习惯是任何改动都分两步走先验证底层反馈控制再叠加自适应。实机上每次改完机械结构或者换了负载我都会先跑到纯PD模式确认基础闭环稳定。然后再把Γ从零开始缓慢增加同时监看权值的范数曲线。一旦权值范数出现单调增长的苗头立刻停止增加学习率排查输入归一化或者激励是否充分。这个流程看起来保守但保住了很多次实验。自适应系统最怕的问题不是初始发散而是慢性的权值漂移——你盯着误差曲线看半天好像挺好回头一看权值已经大得不正常了下一秒钟有可能直接失稳。养成看权值范数的习惯比只看跟踪误差重要得多。三自由度机械臂的自适应神经网络控制从原理到代码再到实机调试每一个环节都有值得投入精力的细节。这个方向做好了对后续做六轴机械臂、移动机器人甚至柔性系统控制都有帮助。至少我现在回头看这套RBF网络加σ修正自适应律加鲁棒项的组合在未知动力学逼近这个命题上依然是工程落地最友好的方案之一。
阅读完成 · 觉得有帮助?