☰
六轴与SCARA机械臂运动学仿真:从DH建模到Simulink闭环控制
2026/10/21 6:56:10 网站建设 项目流程

做机器人运动学仿真,最容易踩的第一个心态坑,就是觉得六轴和SCARA反正都是串联机械臂,运动学分析不过是DH参数表不同,一套MATLAB脚本改改参数就能互通。我最初也是这么干的,结果同一个逆解函数在六轴上迭代半天不收敛,拿到SCARA上又觉得杀鸡用牛刀。把六轴、SCARA两套构型的建模和运动控制完整跑过一遍之后,才意识到它们在数学结构上的差异比外观差异大得多——六轴本质上是一个空间耦合问题,SCARA则把平面定位和垂直升降解耦得干干净净。

我这篇文章就把这两套机器人放在 MATLAB/Simulink/Simscape 这套工具链里完整讲一遍:从DH参数建模、正运动学推导、逆解策略,到rigidBodyTree运动学模型、Simscape Multibody物理模型,最后落到Simulink里的轨迹规划和关节控制闭环。涉及具体代码、参数表格和调试过程中实实在在踩过的坑,适合正在做机械臂选型论证、毕设仿真或者准备上产线的自动化工程师参考。

1. 为什么把六轴和SCARA放进同一套分析框架

1.1 空间六自由度与"平面+垂直"的数学结构差异

六轴机械臂的关节轴线在空间里是不断变化的:底座轴垂直,肩轴水平,肘轴又跟着前臂倾斜,最后三个腕关节更是相互夹角交错。这意味着每动一个关节,末端的位置和姿态几乎同时被改变,逆解时位置和姿态强耦合,解不唯一,而且越靠近奇异位形,数值越不稳定。

SCARA则是另一种气质。它的前两个关节轴线完全平行,从数学上看,末端在XY平面上的位置只由大臂、小臂两个旋转角决定;第三个关节是纯粹的垂直平动,和XY平面完全解耦;第四个关节只负责绕垂直轴的姿态偏转。整个机构写成齐次变换矩阵时,α参数几乎全是0,矩阵里大片是零项,逆解可以一路消元干净利落地解出来。

打个不严谨但很好用的比方:六轴像是在三维空间里玩魔方,拧任何一个面都会同时改变多个色块;SCARA像是在写字板上画图,手里的画笔定位到某个坐标,再按下或者抬起笔尖,姿态最后单独转一下就行。数学上"自由度耦合"的差异,直接决定了后面建模和逆解时应该采用完全不同的策略。

1.2 共享的分析语言:DH参数与齐次变换

尽管构型差异大,运动学分析却可以用同一套语言:DH参数和齐次变换矩阵。每个连杆坐标系只需要4个参数描述——连杆长度a、连杆转角α、关节偏置d、关节角θ。其中a和α描述连杆本身的几何,d和θ描述相邻连杆在关节处的相对位置。旋转关节的θ是变量,平移关节的d是变量。

用这套语言的好处在于,正运动学永远可以机械地写成从基座到末端的矩阵连乘:

T_base_to_tool = T0_1 × T1_2 × ... × Tn-1_n

而逆运动学则是反过来求解这个矩阵方程里各关节变量。后续无论做轨迹生成、动力学补偿还是控制仿真,正解矩阵都是最底层的基础设施。所以你完全可以在同一套MATLAB函数库里分别建立六轴和SCARA的模型,算法框架不换,只是DH参数表和求解策略需要各走各路。

2. DH参数建模:坐标系怎么立、矩阵怎么算

2.1 MDH约定与两种构型的参数表

确定DH参数之前,先得说清楚我用的是哪种约定。目前业界常见的两种——标准DH和改进DH(MDH),坐标系的附着顺序不一样,同一个机械臂填出来的表完全不同。如果从某篇论文复制了一组DH参数,一定要先确认作者用的是哪个约定,否则正解矩阵出来的末端姿态可能差着一个90度旋转甚至一个轴的符号。

我这里统一用改进DH(MDH),这也是MATLAB和很多开源库底层习惯采用的约定。MDH里α和a是绕/沿前一坐标系X轴,θ和d是绕/沿当前坐标系Z轴。以常见的六轴球腕构型为参考,参数表长这样:

关节iθ_id_ia_{i-1}α_{i-1}
1θ1d100°
2θ20a1-90°
3θ30a20°
4θ4d4a3-90°
5θ50090°
6θ6d60-90°

后三个关节α非零且相邻轴保持交点,构成典型的球形手腕,这种结构让姿态部分可以解析处理。而SCARA由于轴线全部平行,MDH表非常稀疏:

关节iθ_id_ia_{i-1}α_{i-1}
1q1d100°
2q20L10°
30d3L20°
4q4000°

填表时最常犯的错是把第2行的a_{i-1}写成a_i,或者把SCARA第四轴的d4写成0时忘记末端工具高度已经由第三轴抬走了。我的习惯是每填完一行,就用手画一遍坐标系变换,确认Z_i的方向和X_i的指向与上一坐标系一致,这样能在源头拦住大量符号错误。

2.2 从DH到齐次变换矩阵的MATLAB实现

MDH相邻坐标系的变换矩阵公式是固定的,写成MATLAB函数就是下面这段:

function T = mdh_transform(a, alpha, d, theta) % MDH改进DH单步变换矩阵 % 输入:a-连杆长度, alpha-连杆转角, d-关节偏置, theta-关节角(弧度) T = [cos(theta), -sin(theta), 0, a; sin(theta)*cos(alpha), cos(theta)*cos(alpha), -sin(alpha), -sin(alpha)*d; sin(theta)*sin(alpha), cos(theta)*sin(alpha), cos(alpha), cos(alpha)*d; 0, 0, 0, 1]; end

有了单步变换,正运动学就是一个连乘循环:

% 六轴正运动学示例,dh_matrix的行分别是 [a alpha d theta] dh_matrix = [ 0, 0, 0.343, deg2rad(45); 0.05, -pi/2, 0, deg2rad(-30); 0.36, 0, 0, deg2rad(60); 0, -pi/2, 0.34, deg2rad(10); 0, pi/2, 0, deg2rad(20); 0, -pi/2, 0.08, deg2rad(-15); ]; T = eye(4); for i = 1:6 T = T * mdh_transform(dh_matrix(i,1), dh_matrix(i,2), dh_matrix(i,3), dh_matrix(i,4)); end disp(T(1:3, 4)); % 末端位置

跑一段典型关节角,把末端位置和模样画出来,看坐标是否落在合理范围,再结合SCARA同样算一次。这个"手工推导→脚本对拍"的验证习惯,能立刻暴露参数表里最隐蔽的问题。对于新手,我建议先用符号变量手推一遍正解表达式,比如SCARA的末端X坐标理论值就是 L1cos(q1)+L2cos(q1+q2),再用数值脚本核对,脑子和计算机两条路互相印证,出错概率低很多。

2.3 从DH表到rigidBodyTree:面向控制和仿真的模型形态

DH表适合推导和验算,但做控制和仿真,更推荐用MATLAB的 rigidBodyTree 模型。它不强制你用DH表,而是用一个个 rigidBody 和 rigidBodyJoint 搭出树状结构,每个关节标注类型(旋转还是平移)、轴线方向、以及相对父体的固定变换。这种方式更贴近机械臂的真实结构,也方便后续把质量、质心、惯量信息挂上去。

实际工程里我通常不手工逐关节搭建 rigidBodyTree,而是统一用URDF文件作为中间格式:先把DH参数转换成URDF文本,然后一次导入两条线:

robot = importrobot('six_axis.urdf'); % 运动学模型,用于验证和逆解 show(robot, homeConfiguration(robot)); % 快速可视化检查

URDF的好处是纯文本、可版本管理、可跨工具链复用。后面从运动学模型转到Simscape物理模型时,还是用同一个URDF做中转,保证运动学模型和物理模型在坐标系定义上完全一致。这块衔接做不好,后面Simscape仿真里会出现"运动学明明逆解正确,物理模型却飞出去"的怪现象。

3. 逆运动学:六轴走数值,SCARA走解析

3.1 六轴数值逆解的通用做法与多解处理

六轴逆解理论上可以用解析法,前提是满足球形手腕条件——后三个关节轴交于一点。工程里绝大多数通用六轴都满足这一点,所以手工推导还有机会。但现实操作中,我更愿意先用数值法跑通整个仿真链路,再回过头去优化解析解,因为数值解法对构型的容忍度更高,改参数也不用重推公式。

MATLAB的 Robotics System Toolbox 提供了现成的 inverseKinematics 类:

ik = inverseKinematics('RigidBodyTree', robot); weights = [0.25 0.25 0.25 1 1 1]; % 位置权重低,姿态权重高 initialGuess = homeConfiguration(robot); tform = [1 0 0 0.45; 0 1 0 0.12; 0 0 1 0.30; 0 0 0 1]; [config, solutionInfo] = ik('tool', tform, weights, initialGuess);

weights 数组的顺序对应末端位姿的X、Y、Z旋转和X、Y、Z平移。很多人随手把六个权重全设成1,结果姿态误差大或迭代震荡。通常位置方向给0.2左右,姿态方向给1,可以让求解器优先保证末端朝向正确,位置误差靠后期轨迹插值来兜底。initialGuess 的影响也很大,离真实解越近,收敛越快,陷入错误局部解的概率越低。工程上我用多初值并行试探,从随机构型里挑最终解:

bestCost = inf; for k = 1:30 q0 = randomConfiguration(robot); qs_k = ik('tool', tform, weights, q0); cost = solutionInfo.PoseErrorNorm; if cost < bestCost bestQ = qs_k; bestCost = cost; end end

挑出来的解还必须经过三道筛选:关节是否在限位内、相比当前关节位置变化是否最小、以及机械臂在这个位形下离奇异有多远。这样选出来的解才适合实际控制,而不是数学上正确但机构上没法执行的解。

3.2 SCARA解析逆解:几何关系直接写代码

SCARA的逆解比六轴简单太多,自己推一遍不留盲区。设大臂长度L1、小臂长度L2,末端XY坐标为(x,y),且当前末端姿态角要求为φ(第四轴输出角)。

先求第二个关节角。由余弦定理:

c2 = (x² + y² - L1² - L2²) / (2·L1·L2)

注意这个cos值必须落在[-1,1],否则目标点在SCARA工作空间之外,直接报错或者提示不可达。sin的符号决定肘部朝向,取正是小臂向上抬(elbow up),取负是小臂向下垂(elbow down),要根据实际臂结构选择:

function [q1, q2, d3, q4] = scara_ik(x, y, z, phi, L1, L2, z_home) r2 = x^2 + y^2; if r2 > (L1+L2)^2 || r2 < (L1-L2)^2 error('目标点在SCARA工作空间之外'); end c2 = (r2 - L1^2 - L2^2) / (2*L1*L2); c2 = max(-1, min(c2, 1)); % 数值保护 s2 = -sqrt(1 - c2^2); % 下肘解,如需要可改正号 q2 = atan2(s2, c2); q1 = atan2(y, x) - atan2(L2*s2, L1 + L2*c2); d3 = z_home - z; % 垂直方向,符号取决于Z轴正方向定义 q4 = phi - q1 - q2; % 末端姿态角是前三自由度叠加的剩余 end

这段代码里最容易被忽略的是 q4 的符号。SCARA末端绕垂直轴的总姿态角是 q1+q2+q4,如果机构定义第四个关节的正方向和前两个关节坐标系旋转方向一致,那这个公式成立;如果第四轴反装,q4 要取反。我先在正解里验证一遍公式,再写逆解,能少一个小时的排查时间。

3.3 逆解在仿真链路中的组织方式

把逆解嵌入整体仿真时,有两条路:一是笛卡尔轨迹离散成若干路径点,每点实时调用逆解,在Simulink里用MATLAB Function块封装;二是在离线脚本里把所有路径点先逆解完,把关节角时间序列存成表格,仿真时直接查表作为参考轨迹。

第二种方式调试更稳,因为它把几何求解和动态仿真解耦,逆解有问题时一眼就能定位。但工业上更常用第一种,因为要处理实时视觉引导、避开动态障碍物等场景。我的建议是:初版仿真用离线逆解表,先把控制环调通;再逐步把逆解搬进实时回路,毕竟控制问题优先,运动学问题应该被提前隔离。

4. 从rigidBodyTree到Simscape Multibody:物理仿真模型的搭建

4.1 为什么不能在纯Simulink数学仿真里收手

很多初学仿真的人把逆解输出直接接到理想关节驱动上,做了一个"关节跟踪"的数学仿真,然后再也做不下去了。原因是这个闭环里根本没有动力学:不管逆变解算出什么角度,Simulink里的积分器都假设关节瞬间到位,重力、惯性、关节耦合全部不存在。你验证的只是几何算法,不是控制系统。

Simscape Multibody 解决的就是这个问题。它把刚体、关节、力传感器、执行器这些物理对象搭出来,在Simulink里和普通控制算法模块直接相连。机械臂的质量、重力、摩擦力、关节力矩都会真实参与计算。对控制算法而言,Simscape模型就是一台虚拟样机,PID参数、前馈补偿、轨迹跟踪策略在虚拟机上调好了,才敢往真机上搬。

4.2 用URDF做中间格式:importrobot和smimport双线导入

搭建Simscape机械臂最省心的路径是用URDF。我先在URDF里把每个连杆的几何位置、关节类型、关节轴线、质量、质心、惯性张量全部定义好,然后用两个命令分别导入:

% 运动学模型,用于正逆解和轨迹规划 robotK = importrobot('six_axis.urdf'); % 生成Simscape Multibody模型 smimport('six_axis.urdf');

smimport 会在当前文件夹生成一个 Simscape 模型文件,还有一个包含URDF中质量惯性参数的MATLAB数据脚本。这个模型里的每个刚体都自动带上了对应惯量,关节之间用 Revolute Joint 或 Prismatic Joint 连接,Simscape 会自动把关节的力矩输入端口和角度测量端口引出来,方便接到控制器上。

URDF里最容易出问题的是 joint 的 origin 和 axis 定义。origin 决定关节在哪一位置附着,axis 决定旋转轴方向。如果axis写错了,比如SCARA的第三轴axis写成[0 0 0](零向量),导入后这个关节直接无法旋转或者报错;如果origin和实际几何差一个旋转,Simscape模型的样子和rigidBodyTree里显示的姿态就会对不上。我每写完一个URDF文件,都会先用 show(robotK) 把运动学模型画出来,确认基座方向、各关节零位状态都正常,再去smimport,这一步能避开后面一大半模型错乱问题。

4.3 Simscape模型的关键配置:惯量、初始状态和重力方向

URDF导入的Simscape模型只是骨架,真正跑仿真之前还有三件脏活要做。

第一件是惯量参数。URDF里如果没有填质量或惯性张量,导入后Simscape会给刚体一个默认的1kg质量和单位矩阵惯量。这种参数跑几何动作没问题,但一旦算动力学、重力补偿或者高速加减速,关节力矩曲线就完全不真实。没有实测惯量数据时,至少要根据连杆外形和材质估算一下:细长杆绕垂直方向惯量大,绕轴向惯量小。总的原则是宁可用粗糙但量级正确的估算,不要直接摆单位矩阵。

第二件是初始状态。Simscape模型里的每个关节都要设置初始位置和初始速度。我喜欢把初始位置设成 rigidBodyTree 的 homeConfiguration 对应角度,初始速度设0。这样运动学模型和物理模型从一开始就位形一致,不会出现仿真前0.1秒机械臂猛地砸到地上去的惨案。

第三件是重力。Simscape的基本力学环境默认有重力,但方向要看模型的原点设置。通常World Frame的Z轴朝上,重力就是[0 0 -9.81]。如果你的URDF里基座方向定义反了,整个机械臂会倒挂在世界坐标系里。跑之前先运行一次零输入仿真,看看机械臂在重力作用下能不能稳定停在初始位置附近,这一步能迅速暴露坐标系方向、初始状态、关节锁定的问题。

5. Simulink闭环:轨迹规划、逆解与控制的串联

5.1 关节空间与笛卡尔空间轨迹的选择

轨迹规划决定机械臂怎么动。关节空间规划最简单粗暴:给定起始角度和终止角度,直接生成每个关节从点A到点B的光滑时间序列。MATLAB里用 trapveltraj 就能做梯形速度曲线,也可以改用五次多项式保证加速度连续:

q0 = [0 -0.5 0.5 0 0.5 0]; qf = [0.4 0.2 0.1 0.3 0 -0.6]; [q, qd, qdd, t] = trapveltraj([q0; qf]', 200, 'EndTime', 2);

关节空间规划的缺点在于,机械臂末端走的是一条无法预知的曲线路径,中间可能碰到障碍物。笛卡尔空间规划则直接给定末端的直线或圆弧路径,用 transformtrajectory 在姿态之间做插值,注意姿态插值必须用四元数或旋转矩阵插值,绝不能直接对欧拉角做线性插值,否则末端姿态会在路径中间剧烈扭动。

笛卡尔路径算出来后,还要逐点做逆解。实际上逆解本身有计算量,如果路径点很多,我会把笛卡尔路径先离散成5-10ms间隔的点,然后调用上一节的多初值逆解函数,离线生成关节角时间序列。这样一个大路径下来,做到既平滑又可控,调试时也方便观察逆解在路径中间是否发生解跳变。

5.2 控制器结构:关节PID加静态重力前馈

有了参考轨迹,下面就是控制环。最简单的起步方案是每个关节一个PID,反馈实际角度和参考角度,输出力矩给Simscape关节。但这里有个现实问题:Simscape模型里重力是真实存在的,电机要持续输出力矩抵消臂杆重量。单纯PID靠误差项去扛重力,稳态误差会一直存在,而且在竖直臂构型上误差还不小。

所以实际系统我至少做一层前馈补偿:在每个关节的力矩指令里,加上当前构型下的估算重力矩。严格的计算力矩控制还需要惯性矩阵和科氏力矩阵,实现起来复杂一些。工程上可以先做一个静态重力补偿表:在Simscape模型里锁住每个关节到某个角度,测出各关节需要保持目标位置所需的力矩,或者直接用URDF里的质量参数算静态力矩,作为前馈函数。

完整控制结构在Simulink里的组织方式大概是:

  1. 参考轨迹源:离线表格或者实时生成的关节角、角速度序列
  2. 逆解模块(如果参考轨迹是笛卡尔空间则存在)
  3. 关节控制器:PID反馈 + 静态重力前馈
  4. 扭矩求和,输出给Simscape机械臂
  5. 从机械臂关节传感器读取实际角度和角速度,反馈回控制器

这里PID参数先按单位阶跃整定:Kp取能让关节快速响应但不过冲的值,Kd阻尼拉到临界阻尼的状态,Ki只负责消除残余稳态误差。注意六个轴耦合严重时,独立PID在高增益下会互相激发振荡,真遇到这种情况,先降增益,再加前馈,而不是继续堆PID参数。

5.3 仿真结果怎么看:跟踪误差和关节力矩是两把尺子

仿真跑完别急着收工,重点看两组曲线。第一组是各关节跟踪误差曲线,如果某个关节出现持续振荡或大超调,说明增益不合适或前馈没有覆盖该关节的负载变化。第二组是关节力矩曲线,正常情况下力矩应该平滑变化,出现快速抖动的力矩尖峰要么是轨迹加速度过大,要么是奇异位形导致某个关节承担了整个末端的力。

我还会额外看末端笛卡尔误差曲线,也就是把仿真输出的关节角取正解,和参考笛卡尔路径比较。这个误差是几何误差、逆解误差、控制误差的总和,能直观反映整个系统能不能端到端跑通。如果末端误差在5mm以内,对大多数搬运和装配仿真已经可用;想要更高精度,就得在逆解时提高位姿权重,单位置权重高的笛卡尔参考点尽量减少逆解偏差。

6. 运动学与仿真调试中的翻车现场

6.1 初始位姿对不上:Simscape模型第一秒就飞掉

这个问题我踩得最疼。把逆解得到的关节角作为参考轨迹输入Simscape,理论上机械臂应该平滑跟踪,结果仿真一开始,关节力矩瞬间冲到很大,机械臂直接甩到一个离谱位形。排查半天,最根本的原因是Simscape模型各关节初始位置仍然是0,而参考起点是某个较大角度,控制器在0.01秒内要追一个巨大的初始误差,自然猛烈输出。

处理手段有两个:一是严格设置Simscape关节初始状态和参考轨迹起点一致;二是在Simulink里给参考信号加一个斜坡启动或者指数平滑,让轨迹从当前实际位姿逐渐进入期望路径。第二个方法在真实设备上也是必须的,因为真实机器人永远只能从当前位置出发,不可能凭空跳到路径起点。

6.2 数值逆解不收敛与多解跳变

六轴数值逆解最常见的两种异常,一是初值离真解太远导致迭代发散,二是多解之间来回跳。前者好解决,多跑几组随机初值,选最小误差解;后者比较麻烦,因为即使每组解都正确,相邻两个路径点的解如果差了很大角度,机械臂就会突然"甩动"一下。我一般加一个最小变化量约束,把上一时刻的解作为当前时刻的偏置,只允许在当前解基础上往最近的方向跳。

具体实现就是在多初值筛选时,除了看逆解误差,再加一项关节角代价项,权重取当前关节空间解与上一时刻解的差向量范数。比如把总代价定为逆解误差范数加上0.3倍的关节变化量,这样稳定性和精度之间可以按需调节。SCARA很少遇到这种问题,解析解天然连续,前提是肘部朝向标志位保持一致,别在路径中间切换elbow up和elbow down。

6.3 求解器硬化:Simscape仿真步履蹒跚

Simscape Multibody 本质是多刚体动力学数值积分,模型里一旦存在大幅阻尼、刚性摩擦或者约束锁死,仿真步长会被Simulink自动压得非常小,表现为仿真速度极慢,比真实时间还慢很多倍。处理这种问题先把求解器检查一遍:变步长求解器通常选 ode15s 或 ode23t,在Simscape内部还可以开 Local Solver,把机械系统按内部步长积分,避免整个Simulink模型被迫收缩步长。

另外,关节摩擦和阻尼参数不要一开始就堆得很夸张。我见过很多人为了让机械臂静置时稳,把关节阻尼设成几百,结果机构变得极其僵硬,任何高增益控制都会激起数值振荡。合理做法是把阻尼控制在能稳定停住且不显著影响动态的区间,比如初值取个位数,再逐步加大到能压住静差即可。

6.4 欧拉角插值造成末端姿态翻车

做笛卡尔直线路径时,姿态路径点的插值如果直接对roll-pitch-yaw三个角做线性插值,末端坐标系在路径中间会莫名其妙地绕一个大圈,甚至看起来像机械臂在做奇怪的翻转。这是因为欧拉角表示在特定角度附近有跳变不连续。正确做法是用旋转矩阵或四元数做插值,MATLAB的 transformtrajectory 内部已经用四元数,但如果你自己写插值,务必先 roty 转成四元数序列,再 slerp。SCARA由于只有绕Z轴的姿态自由度,线性插值问题不大,但六轴完全不能偷懒。

我在实际做六轴笛卡尔轨迹时,习惯把每个路径点的姿态都转成四元数,中间插值仅对四元数做球面插值,最后再转回旋转矩阵,这样可以保证末端路径在姿态空间里始终走最短旋转路径。

6.5 逆向验证:把正解矩阵当作调试锚点

最后分享一个我坚持到现在的习惯:每次改完DH参数、URDF文件或者逆解函数,第一步永远是做正解验证——随机生成一组关节角,用同一个函数计算末端位姿,再和CAD模型或者自己手推的解析公式比对。正解是整条仿真链路的地基,地基偏了,后面所有逆解、轨迹、控制调得再好都是白搭。

以前调试一个SCARA仿真时,我一度以为控制参数有问题,末端定位总差一段。后来用正解矩阵核对才发现是DH表里第三轴的d3符号定义反了,垂直方向整段偏置。那次的教训让我养成了习惯:只要仿真现象不对劲,先怀疑运动学和坐标变换,再怀疑控制器,最后才怀疑求解器设置。

现在回头再看这套从运动学分析到物理仿真、再到控制闭环的完整流程,最强烈的体会是:SCARA的简单和六轴的复杂不是两个各说各话的话题,而是同一套分析框架在两种数学结构下的具体表现。真正把DH表手推一遍、再用MATLAB对拍一次之后,你不但会掌握这两种构型,还能把这一套方法迁移到其他更复杂的机械结构上。遇到构型先构型分析、再建模型、再控制,这条链路本身就比任何某个具体的公式值钱。

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

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

立即咨询