☰
UR5机械臂Simscape仿真与PID轨迹跟踪控制实践
2026/10/21 17:00:47 网站建设 项目流程

最近在调一套UR5机械臂的PID轨迹跟踪控制仿真项目,六自由度机械臂,用Simscape搭建物理仿真环境。整个项目踩了一圈下来,发现最有意思的部分反而不是PID本身,而是从DH参数一路走到物理仿真闭环这一段路。项目最开始的需求很直接:要求在关节空间做轨迹跟踪,末端轨迹要平滑,控制算法用PID,仿真环境用Simscape Multibody,最后还要能提供完整DH参数表。

这篇文章就把这套系统的完整落地过程整理出来。从方案选型、DH参数推演、Simscape建模,到PID控制律设计和参数整定,再到实际调试中踩过的坑,全部展开讲。适合正在做机械臂运动控制仿真的人参考,尤其是想验证PID控制算法、又不想一开始就上实体机的朋友。

1. 项目整体设计思路:Why Simscape物理仿真

1.1 仿真方案怎么选:纯运动学、物理仿真还是直接上实物

机械臂控制算法验证,一般有三条路。第一条路是在MATLAB里直接写运动学模型,用解析公式计算正逆解,然后跑一个纯数学层面的控制回路。这种方案速度快、调试方便,但有一个致命缺陷:它默认机械臂是完全理想的,没有重力,没有关节摩擦,没有惯性耦合,连杆之间也没有动力学的相互影响。PID参数在这种环境里调出来的结果,放到真机上基本不具备参考性,因为真实机械臂反馈的动态特性远比你想象中复杂。

第二条路就是本项目采用的方案:Simscape Multibody物理仿真。Simscape不是用公式推导机械臂运动,而是把整个机械臂建模为一组刚体、关节、约束和力元,底层用多体动力学求解器实时计算每个刚体的位置、速度和受力。重力、关节摩擦、连杆惯性、科氏力、各关节之间的动力学耦合都会被纳入计算。你的PID控制器面对的不是一个解析模型,而是一个需要求解器“硬算”的物理系统,这个体验非常接近真实样机。

第三条路是直接上实物,但这牵扯到电气接线、安全保护、通信配置、机械限位等一系列问题。对于前期控制算法验证阶段,没有太大必要,调试成本和风险都高。

三者对比下来,Simscape物理仿真的性价比最高,也是目前比较主流的选择。它让你在不需要碰真机的前提下,把PID控制器调到一个足够好的状态,后期再迁移到实物上,通常只需要微调。

1.2 整体架构与数据流

这套系统的整体架构,我画了一条清晰的数据流,整个Simulink模型就是按这条数据流搭出来的:

  • 轨迹规划层:给定各关节的起点和终点,在关节空间生成光滑的期望轨迹,输出期望位置和期望速度。
  • 控制层:接收期望位置、期望速度和实际位置、实际速度的误差,通过PID控制律输出关节力矩指令。
  • 物理层:Simscape机械臂模型接收关节力矩指令,基于刚体动力学计算实际响应,输出实际关节角度、角速度。
  • 反馈回路:实际位置和速度反馈给控制层,形成闭环。
轨迹规划 → PID控制器 → Simscape机械臂模型 → 传感器反馈 → 轨迹规划(闭环)

这个架构的优点是分层清晰,每一层都可以独立调试。先单独验证轨迹规划层的输出曲线是否光滑,再单独验证Simscape模型在阶跃力矩下是否正常响应,最后才把PID控制器接入系统做联合调试。如果一次性把整个系统丢上去跑,出了问题根本没法定位是轨迹规划的问题、控制器的问题还是建模的问题。

另外还有一个值得说的地方:控制层的设计我选择了关节空间PID,而不是任务空间PID。关节空间PID的反馈源是各关节编码器数据,控制律独立作用于每个关节,逻辑简单、稳定可靠,工程上用得最普遍。任务空间控制(比如阻抗控制、力位混合控制)虽然末端精度更高,但依赖完整的动力学模型和雅可比矩阵,系统复杂度和调试难度都显著上升。对于本项目的需求——验证轨迹跟踪能力——关节空间PID足够胜任,也更符合“先把地基打牢”的思路。

2. DH参数与运动学建模:整套系统的基准线

2.1 DH参数表:为什么每个项目第一件事都是定它

做机械臂控制,DH参数表是整套系统的基准线。正运动学靠它,雅可比矩阵靠它,Simscape建模时的关节轴线对齐也靠它,轨迹规划时的逆解同样靠它。如果DH参数表是错的,后面所有环节全是错的,而且错误会以非常隐蔽的方式出现——机械臂可能动起来看着正常,但末端位置永远是偏的。

DH参数一般分标准DH(SDH)和修正DH(MDH)两种约定。UR系列机械臂的URDF文件使用的是MDH约定,所以我整个项目也统一采用MDH,避免在模型导入时出现坐标系偏差。下面这套参数是从项目模型推导出的参考值,单位是米和弧度,可作为项目实践的参照表:

关节 id (m)a (m)alpha (rad)theta 初始 (rad)
10.08920pi/20
20-0.4250-pi/2
30-0.39200
40.10930pi/2-pi/2
50.094750-pi/20
60.0823000

注意表中的theta初始是机械臂处于竖直零位姿态时的关节角偏移,这个偏移在做轨迹规划时必须加进去,否则你规划的“零角度”和Simscape模型里的“零角度”对不上。这一条我一开始就忽略了,导致第一版仿真里机械臂末端静止在一个奇怪的位置,排查了很久。

2.2 正运动学验证:从DH参数到末端位姿

拿到DH参数之后,第一件事不是急着建Simscape模型,而是先写一个正运动学函数,验证参数表是否正确。标准做法是把每个关节的变换矩阵写出来,然后连乘得到末端位姿矩阵。

下面是项目中用的MATLAB正运动学验证函数:

function T = dh_transform(d, a, alpha, theta) % MDH约定下的单关节变换矩阵 T = [cos(theta), -sin(theta)*cos(alpha), sin(theta)*sin(alpha), a*cos(theta); sin(theta), cos(theta)*cos(alpha), -cos(theta)*sin(alpha), a*sin(theta); 0, sin(alpha), cos(alpha), d; 0, 0, 0, 1]; end

然后用它依次连乘六个关节的变换矩阵:

% DH参数(MDH)—— 按上表填入 d = [0.0892, 0, 0, 0.1093, 0.09475, 0.0823]; a = [0, -0.425, -0.392, 0, 0, 0]; alpha = [pi/2, 0, 0, pi/2, -pi/2, 0]; theta = [0, 0, 0, 0, 0, 0]; % 零位 T06 = eye(4); for i = 1:6 T06 = T06 * dh_transform(d(i), a(i), alpha(i), theta(i)); end % 提取末端位置 pos = T06(1:3, 4); disp(pos);

把零位角度代入计算,末端位置大约是 (-0.817, -0.1093, 0.0768) 米,也就是机械臂在水平方向完全展开时的末端坐标。这个数值可以跟机械臂的几何尺寸互相印证:大臂 0.425 米,小臂 0.392 米,再加上末端偏移量,长度上是吻合的。如果这一步算出来位置明显不符合几何常识,那就要回头检查DH参数表,不要贸然往下走。

提示:正运动学验证这一步虽然简单,但因为过于基础,很多人直接跳过。我在项目里吃过亏——跳过验证直接建模,后续PID轨迹跟踪时末端轨迹始终偏离期望曲线,查了很久才发现是某个角度偏移的符号搞反了。

2.3 从DH参数到Simscape:坐标系的微妙关系

DH参数和Simscape模型之间有一个容易忽视的对应关系:DH参数里的关节转角theta对应的是绕当前坐标系Z轴的旋转,但在Simscape Multibody里,关节转动轴的朝向是由两个刚体之间的连接框架决定的。也就是说,你在Simscape模型里定义joint时要保证旋转轴的方向、位置和DH参数表中的关节坐标系的Z轴完全一致。

用URDF文件导出的Simscape模型,这个对应关系在理想情况下会自动保持,因为URDF本身包含了完整的关节轴位置和方向信息。但问题是URDF文件里的坐标系定义可能和你的DH参数约定不完全一致(URDF的坐标系和DH坐标系的定义规则并不天然相同),这时就要手动修正。

我的做法是:导入模型后,逐个检查每个关节的转动轴方向矢量,和DH参数表里对应关节坐标系Z轴比对。比对方法很简单——在Simscape模型里给关节一个正的小角度,观察下游连杆的运动方向是否符合预期。这一步虽然有点土,但非常有效,比对着坐标变换矩阵烧脑强多了。

3. Simscape物理仿真环境搭建:从URDF导入到可驱动的模型

3.1 建模方案:URDF导入还是手工搭建

Simscape Multibody里搭机械臂模型有两条路:一是利用三维软件(比如SolidWorks)画好机械臂模型后导出URDF,再用MATLAB的smimport命令导入;二是在Simscape Multibody模板里手工添加连杆和关节模块,逐个配置几何外形、质量和坐标系。

两条路的差别很明显:

对比项URDF导入手工搭建
建模工作量低,主要花在URDF生成上高,每个连杆都要单独配置
几何精度高,直接来自三维模型低,通常用简化几何体
惯性参数可从三维软件自动算出需要手动估算
坐标系对齐继承URDF,但仍需校对完全自己定义,可控性高
适用场景已有三维模型,追求真实度快速验证算法,对视觉效果要求不高

我用的是URDF导入方案。原因很简单:Simscape物理仿真的核心价值在于动力学真实性,而动力学真实性依赖准确的惯性张量和质心位置。这些参数从三维模型直接计算比手工估算靠谱得多。URDF导入后,每个连杆的质量、质心、惯性张量都已经配置好,后续只需要核对数据是否合理就行。

3.2 导入后模型骨架的整理与配置

smimport命令导入URDF后,MATLAB会生成一个包含刚体、关节、坐标系变换的Simscape模型骨架图。但骨架图离“能跑的控制仿真模型”之间还有几步关键配置。

第一步是清理无效的坐标系框架。URDF文件里会有很多link节点和可视化mesh,导入后Simscape模型里会有大量用于挂载mesh的坐标系框架,这些框架在动力学仿真中并不承担功能,但会大大增加模型图的可读性负担。我的做法是保留关节坐标系和质心坐标系,把纯可视化用的框架隐藏掉。

第二步是关节类型的检查与修正。URDF里revolute关节会被Simscape转换成旋转关节,prismatic关节转换成移动关节,fixed关节转换成刚体变换框架。这一步通常不会出问题,但要注意revolute关节如果URDF里没有定义limits,Simscape导入后可能不会自动生成关节限位模块。没有关节限位,仿真中PID一旦发散,机械臂会像面条一样疯狂旋转,画面极其惨烈。

第三步是添加机械环境模块。Simscape Multibody模型必须有一个Mechanical Environment模块来定义重力、维度等信息。URDF导入生成的模型通常会自动带一个,但默认重力方向是标准世界坐标系的负Z轴,要确认这和你机械臂基座的安装朝向一致。

第四步是惯性参数的核对。URDF导入后,每个连杆的质量和惯性张量来自三维软件的自动计算。我的建议是抽查几个关键连杆的质量是否合理,比如大臂连杆质量应该在10kg量级,小臂在5kg量级。如果发现某个连杆质量只有0.01kg,那大概率是三维软件里单位换算出了问题(比如毫米和米的混乱),需要手动修正。

3.3 关节驱动与测量接口的配置

模型骨架整理完之后,下一步就是给关节加驱动和测量接口,让Simscape模型能和Simulink控制器交互。

在Simscape Multibody里,关节默认是自由的,它不会自己动,必须通过Joint Actuator模块施加力矩或运动驱动。对于力矩控制场景,我选择在关节的Motion端口接Joint Actuator,输入类型设置为力矩,这样PID控制器的输出就能直接接到驱动模块上。

测量端口则用Joint Sensor模块,它会实时输出关节角度、角速度、角加速度。把传感器输出的角度和角速度反馈给PID控制器,系统闭环就打通了。每个关节都需要独立配置一套驱动和测量模块,六个关节就是六个通道,在Simulink模型里最好用Bus方式打包传输,否则连线会密到让人崩溃。

求解器配置方面,Simscape物理模型推荐的求解器是ODE15s(变步长刚性求解器)或ODE23t。默认的ode45在无摩擦、无接触的简单模型上跑得动,但机械臂多体动力学里存在大量刚性约束,ode45容易把仿真步长压到极小,仿真速度会慢得让人怀疑人生。我的实际配置是:求解器用ODE15s,最大步长设置0.01秒,相对容差1e-3,这样既保证了精度,又不会因为步长过大导致数值发散。

注意:PID控制器的采样时间和Simscape物理求解器的步长是两个独立的量。控制器采样时间我设置为1ms,物理求解器步长由ODE15s自动调整。两者之间的数据交互由Simulink自动处理,但不要在PID控制器里使用连续时间模块直接处理物理信号,否则会产生大量细小的仿真步,拖垮仿真速度。

4. PID轨迹跟踪控制实现:从理论公式到能跑的Simulink模型

4.1 轨迹规划:期望轨迹从哪来

PID轨迹跟踪的前提是有一套光滑的期望轨迹。轨迹规划有两种思路:关节空间规划和笛卡尔空间规划。本项目要求的是关节空间轨迹跟踪,所以我的轨迹规划器直接在各关节角度空间中工作。

关节空间轨迹规划最简单可控的方式是五次多项式插值。五次多项式的好处是位置、速度、加速度全程连续,没有突变,机械臂在启停瞬间不会产生冲击。给定起止角度、起止速度和起止加速度(通常全部为零或仅速度为指定值),五次多项式就能唯一确定:

function [q_des, qd_des, qdd_des] = quintic_trajectory(q0, q1, t0, t1, t) % 五次多项式轨迹规划 % q0: 起点角度, q1: 终点角度, t0: 起点时间, t1: 终点时间, t: 当前时刻 dt = t1 - t0; s = (t - t0) / dt; % 归一化时间多项式系数 a0 = q0; a1 = 0; a2 = 0; a3 = 10 * (q1 - q0); a4 = -15 * (q1 - q0); a5 = 6 * (q1 - q0); % 位置、速度、加速度 q_des = a0 + a1*s + a2*s^2 + a3*s^3 + a4*s^4 + a5*s^5; qd_des = (a1 + 2*a2*s + 3*a3*s^2 + 4*a4*s^3 + 5*a5*s^4) / dt; qdd_des = (2*a2 + 6*a3*s + 12*a4*s^2 + 20*a5*s^3) / dt^2; end

把这条轨迹生成函数放到一个MATLAB Function模块里,输入当前仿真时间和目标关节角,输出期望角度和期望速度,然后送进PID控制器,就完成了轨迹规划层的搭建。

4.2 PID控制律设计方案

关节空间PID控制律的标准形式是力矩输出。每个关节的控制器独立工作,计算期望位置与实际位置的误差、期望速度与实际速度的误差,然后通过比例、积分、微分三个环节的加权输出最终关节力矩指令。

对于六自由度机械臂,纯粹的P、I、D三个环节在大部分情况下可以跟踪得不错,但想要更好的轨迹跟踪效果,重力补偿前馈是必须加的。机械臂在静止或低速运动时,重力矩是最大的干扰项。PID要完全靠反馈去抵消重力误差,比例项会拉得非常高,导致系统刚性和噪声放大。正确做法是在PID输出上叠加一个基于当前关节角的重力补偿力矩:

function tau = pid_controller(qd, qd_dot, q, q_dot, Kp, Ki, Kd, gravity_torque) % 关节空间PID + 重力补偿前馈 persistent integral_err; if isempty(integral_err) integral_err = zeros(size(q)); end err = qd - q; % 位置误差 err_dot = qd_dot - q_dot; % 速度误差 integral_err = integral_err + err * dt; % 积分项累计 % PID输出 + 重力补偿 tau = Kp * err + Ki * integral_err + Kd * err_dot + gravity_torque(q); tau = saturate_torque(tau, tau_max); % 力矩限幅 end

积分项在机械臂控制里要特别小心一个情况:积分饱和。只要轨迹跟踪持续存在误差,积分项会不断累积,直到输出力矩达到饱和。当误差方向反转时,这种累积的积分力矩可能导致严重的超调。我的处理方式是加抗积分饱和逻辑:当输出到达力矩限幅时,冻结积分项的增长。这是仿真阶段容易忽略、但实机调试中极其关键的环节。虽然本项目的仿真环境里不会烧坏电机,但积分饱和带来的超调和振荡会让你误判PID参数的好坏。

4.3 PID参数整定的实操经验

PID参数整定是这套系统里最“艺术”的部分。Simscape物理仿真和纯数学仿真的整定体验完全不同——因为动力学耦合的存在,你会发现调整一个关节的PID参数,会导致另一个关节的跟踪误差也跟着变化。这不是玄学,而是机械臂多体动力学中关节间惯性耦合和科氏力的正常体现。

我的整定顺序是:先单独整定每个关节的PID参数,再做整机联调微调。单关节整定很简单:只让一个关节运动,其他关节锁死,观察阶跃响应曲线,先调比例项再调微分项最后加积分项。比例系数从小到大缓慢增加,观察系统是否会振荡;出现振荡后略微回落,然后加入微分项抑制超调;最后加入积分项消除稳态误差。

下面这组参数是项目中调出来的一个参考值,不同关节的负载和惯量差别较大,数值有明显差异。注意这只是参考,具体参数需要针对你的模型重新整定。

关节KpKiKd备注
关节13001.020基座关节,负载惯量大,Kp不宜过高
关节24001.525大臂关节,重力影响显著
关节33501.222小臂关节,和关节2耦合较强
关节41500.810腕部关节,转动惯量小,数值偏低
关节51200.58腕部关节
关节6800.35末端关节,惯量最小,响应最快

整定过程中的一个重要经验是:不要追求完美的无误差跟踪。机械臂轨迹跟踪的误差可以控制在非常小的范围内(末端位置误差毫米级),但在仿真里硬把所有误差压到零,一定会带来力矩输出的高频抖动。物理仿真和真机一样,控制器输出的力矩信号如果高频率波动,是非常不健康的状态,它意味着你正在和数字噪声对抗,而不是和物理模型对抗。

5. 常见问题与排查技巧实录

5.1 仿真发散或不收敛

调试过程中最让人头疼的问题是仿真发散。现象一般是:模型刚开始跑挺正常,中途某个关节角度突然冲到一两千弧度,Simulink报错或者画面直接“飞掉”。

排查下来主要有三个原因:

第一是求解器配置不当。前面说过,物理模型不要用ode45,换ODE15s能解决大部分中段发散问题。如果在某个接触瞬间仍然发散,可以进一步把最大步长调小(比如0.001秒)。

第二是关节摩擦参数设置过大。URDF导入的模型默认摩擦可能为零,但如果你手动添加了摩擦模型,库伦摩擦系数过大时,关节会出现“粘滑振荡”现象,数值上表现为力矩高频切换,最终导致求解器发散。建议库伦摩擦力矩不要超过该关节额定力矩的5%。

第三是控制器在初始时刻输出了过大力矩。比如轨迹规划的起点和机械臂实际初始位置不一致时,PID的误差项会瞬间产生巨大输出,轻则仿真警告,重则直接发散。解决办法是让轨迹规划的起点匹配机械臂模型的初始关节角,或者在控制器输出端加一个1秒左右的斜坡限幅。

5.2 末端轨迹偏差大

整机联调时发现末端轨迹偏差大,先不要急着调PID参数。我踩过几次坑之后总结出一套排查顺序:

先看轨迹规划的输出是否包含期望加速度。很多人在PID控制器里只用了期望位置和期望速度,但期望加速度其实构成了前馈项的核心。虽然纯PID配置不需要加速度前馈,但如果系统响应偏慢,加速度前馈能显著改善跟踪误差。当期望轨迹曲率较大(比如快速转弯)时,缺失加速度前馈会导致系统在弯道处持续滞后。

再看重力补偿是否准确。Simscape模型里的重力补偿力矩是基于当前关节角计算的,确认这个函数的输出符号和方向与模型的期望一致。方向反了的情况下,P项会被重力补偿大幅抵消,系统会出现一种“怎么调Kp都不够硬”的诡异手感。

最后再看摩擦补偿。如果你的模型配置了关节摩擦,建议在控制器里也加入相应的摩擦前馈项,否则轨迹跟踪会一直存在一个固定大小的偏置误差,表现为低速时误差明显、高速时误差变小。

5.3 参数整定的一个小技巧

如果六个关节同时联调,PID参数之间会互相干扰,新手很容易陷入“调哪个关节都没调好”的泥潭。这里分享一个很实用的技巧:联调时只关注一个关键关节的跟踪误差曲线,比如关节2(负载最大、重力影响最明显的关节)。先把其他关节的PID放在一个保守的档位,专注调好关节2,然后再依次调下一个关节。这样每次只面对一个主要矛盾,整定过程会清晰很多。

对应到Simulink模型的操作是:在关节2的PID控制器输出端加一个Scope,同时在关节2的期望轨迹和实际轨迹反馈上做误差监视。当误差曲线在目标轨迹上平滑跟随、误差带窄而稳定时,说明当前参数已经足够好。这时候再切换去调下一个关节,最后回归整机验证。

常见问题现象排查重点可行解法
仿真中途发散关节角度突然飞掉,报错求解器、摩擦系数、初始力矩换ODE15s,减小摩擦,加斜坡限幅
末端轨迹滞后跟踪曲线跟不上期望加速度前馈、重力补偿符号增加前馈项,检查重力方向
低速精度差低速时误差明显大于高速摩擦力矩补偿、积分项强度增加摩擦前馈,适当加大Ki
力矩高频振荡力矩输出信号毛刺多Kp过大或Kd过大,积分饱和降低增益,增加抗积分饱和
整机联调互相干扰调好一个关节另一个变差动力学耦合单关节逐个整定,最后整机微调

整套项目做完,我最大的感触是:Simscape物理仿真里最难的不是PID参数本身,而是让模型真实到足以让PID参数有价值。DH参数表推演、坐标系对齐、惯性参数核对、摩擦模型配置——这些看似跟控制算法无关的“苦力活”,恰恰决定了一套仿真系统能不能真的反映物理世界。控制算法仿真从来都不是“我把PID接上去就完事”的简单事,它需要你从头到尾对自己搭建的模型有完整的掌控。希望这篇文章能让你少走一些弯路,把时间花在真正有意思的算法调试上。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询