简介:一套面向机器人学习与研究者的机械臂轨迹规划资料包,聚焦MATLAB机器人工具箱中的直线轨迹与圆弧轨迹生成方法,适用于需要掌握关节空间规划、理解逆运动学与插值原理的入门及进阶用户。包内包含完整SolidWorks三维模型、MATLAB轨迹规划程序及运动学分析报告,可辅助从模型到代码的对照学习。资源共36个文件,涵盖28个sldprt零件、4个sldasm装配体、3个.m脚本及1个docx报告,包体大小10.22MB,模型用于结构展示,脚本提供可直接运行的规划示例,报告梳理理论推导与参数设置。目前已有9548人学习下载,适合以实际机械臂模型为参考,系统走通直线与圆弧轨迹规划全流程的用户。借助完整模型、程序与文档,读者能从正/逆运动学、速度约束到轨迹插值逐步展开分析,快速形成可复用、可扩展的实验思路。
1. matlab机器人工具箱做机械臂轨迹规划:直线与圆弧,别等画出来再改
机械臂直线轨迹和圆弧轨迹规划,难点不在正逆解,而在“把末端位置约束在一条直线/一段圆弧上”。很多人第一次做直线规划时,顺手用关节空间插值函数,动画里看末端走的是大弧线,折腾半天才发现轨迹规划要回到笛卡尔空间重做。用 matlab机器人工具箱做这件事,套路其实很固定:先在任务空间生成带加减速的路径点,再逐点做逆运动学,拿到关节序列后驱动模型验证;SW模型用来核对几何外观和关节坐标系朝向,matlab程序负责把轨迹可复现地算出来,报告则把每一步的参数和偏差记录留档。这篇文章从直线轨迹讲到圆弧轨迹,再把 SW模型导入、逆解不收敛这类翻车点一起说清楚,适合正在做机器人课程设计或机械臂应用方案的开发者。
2. 直线轨迹规划:从起点到终点的目标位移,落到机械臂关节角
2.1 为什么末端直线必须在笛卡尔空间插值:关节空间和任务空间的本质区别
直线轨迹规划里最常见的错误,是在关节空间做插值。关节空间里每个关节从初始角平滑运动到目标角,看起来每个关节都很顺滑,但正运动学是一种非线性映射,多关节同时转动的合成结果,末端在三维空间里画出来的是一条复杂曲线,不是直线。换句话说,关节角的变化很漂亮,不代表末端轨迹满足工艺要求。焊接、涂胶、码垛这类场景要求的是末端路径严格走直线,所以约束必须定义在笛卡尔空间,也就是任务空间。
任务空间做直线轨迹规划的流程分三步:先确定起点位姿和目标位姿,接着在两点之间按时间生成一系列中间位姿,最后对每个中间位姿做逆运动学求关节角。中间位姿的生成要解决两个问题:一是位置插值,保证平移部分沿直线走;二是速度轮廓,避免起步和结束的瞬间速度突变。常见做法是用梯形速度曲线或S型速度曲线生成归一化位移序列,再把这个序列传给位姿插值函数,这样末端速度就是先匀加速、再匀速、最后匀减速,机械臂动作不会前后一顿一顿。
这也就是为什么不能直接用均匀分布的位移点。均匀等距听起来简单,但每个点之间的位移差恒定,相当于全程匀速,起点和终点的加速度理论上无限大,真实机械臂根本跟不住。用 matlab机器人工具箱做这件事,一般先把位移比例序列算出来,再逐点构造位姿矩阵,最后统一逆解。整个流程里,最容易被忽略的是逆解连续性:相邻路径点上的关节角必须平滑过渡,如果某个点逆解跳到一个完全不同的构型,动画里就是关节猛甩一下。所以后续代码里我用上一时刻的关节角作为当前逆解的初始猜测值,这是让关节序列连续的一个很实用的习惯。
2.2 直线轨迹生成的Matlab代码:梯形速度加SE(3)插值,逐点逆解
下面这段代码是最小可复现版本,机器人对象假设已经用工具箱里的 SerialLink 类创建好,命名为 myrobot,D-H参数和关节限位都已设置完毕。轨迹起始位姿和终止位姿用工具箱的 transl 和 rpy2tr 构造,前者写平移量,后者写旋转量。
% 直线轨迹规划:任务空间插值 + 逐点逆解 steps = 80; % 轨迹点数,越大路径越密 dt = 0.01; % 时间步长,用于后续速度计算 T0 = transl(0.30, 0, 0.25) * rpy2tr(0, pi/2, 0); % 起始位姿 T1 = transl(0.55, 0.20, 0.40) * rpy2tr(0, pi/2, pi/4); % 终止位姿 s = lspb(0, 1, steps); % 梯形速度曲线,返回归一化位移 Ttraj = zeros(4, 4, steps); % 存放中间位姿矩阵序列 for i = 1:steps Ttraj(:,:,i) = trinterp(T0, T1, s(i)); % SE(3)线性插值 end q = zeros(steps, 6); % 关节角矩阵,6自由度机械臂 q(1,:) = myrobot.ikine(T0, 'mask', [1 1 1 1 1 1]); % 起点逆解 for i = 2:steps q(i,:) = myrobot.ikine(Ttraj(:,:,i), ... 'q0', q(i-1,:), 'mask', [1 1 1 1 1 1]); % 用上一时刻角做初始猜测 end逻辑说明:lspb 生成从 0 到 1 的位移比例序列,起止段速度为零,中间段匀速,这是梯形速度曲线的标准用法。trinterp 在 4×4 齐次变换矩阵之间做插值,平移部分线性插值,旋转部分使用球面线性插值,所以末端位置严格走在两点连线上,旋转姿态也是平滑过渡。ikine 是工具箱的数值逆解函数,第 2 行到第 8 行是为了避开奇异位形而做的逐点求解。
参数说明:steps 决定路径密度,直线轨迹 50 到 100 点足够,点数越多速度曲线越平滑,但逆解次数线性上涨,实时性差的电脑会开始卡顿。mask 控制末端哪些自由度参与逆解,6 自由度机械臂全开写成六个 1;如果机械臂末端只有 5 个自由度,必须把对应轴位置改成 0,否则逆解会在一个不存在自由度的方向上反复迭代,收敛得很慢。q0 是当前路径点的初始关节角猜测值,传上一时刻的关节角可以让相邻两个路径点的逆解结果保持连续,避免关节角跳变。这里有一个细节:如果起始位姿本身就接近奇异,ikine 第一帧就可能失败,需要先用 myrobot.ikine(T0) 单独验证一次,再进入循环。
2.3 直线轨迹验证:直线度和速度连续性用什么数字盯住
轨迹算完不等于做完,验证环节至少要盯两个数:末端实际轨迹和理论直线的最大偏差,以及关节速度曲线的光滑程度。末端实际轨迹不能直接看动画,要通过正运动学把关节角序列映射回末端位置再对比。
% 验证末端是否走直线,并计算直线度偏差 t_theory = squeeze(transl(Ttraj)); % 理论路径位置,3×steps 矩阵 t_actual = myrobot.fkine(q); % 正运动学,返回4×4×steps t_actual = transl(t_actual); % 提取实际末端位置 % 逐点取偏差向量的模,再取最大偏差 delta = t_actual - t_theory; max_dev = max(vecnorm(delta, 2, 1)); disp(['最大直线度偏差: ', num2str(max_dev), ' m']); % 关节速度连续性检查 qd = diff(q) / dt; % 数值差分近似关节速度 max_joint_vel = max(abs(qd(:))); figure; plot(qd); grid on; % 画所有关节速度曲线这里我没有在第一行给 Ttraj 做转置处理,是因为 transl 返回的是 3×steps 的矩阵,每列对应一个路径点,方向正确。max_dev 通常是逆解的数值误差累计,理想情况下在 1e-6 量级;如果超过 1e-3,说明逆解迭代精度不够或者目标位姿已经越过了奇异区域,这时需要调 ikine 的容差参数,比如 tol 改小到 1e-10,或者把 steps 提高让路径点更密。关节速度曲线如果出现明显的尖刺,基本就是某一帧逆解跳到了别的构型,回到上一段代码里检查 q 序列相邻两行的差值,差值特别大的那一行就是问题帧。
3. 圆弧轨迹规划:三点定弧,从几何计算到关节空间的完整落地方案
3.1 圆弧轨迹的几何基础:圆心、半径、方向和三点定圆的稳定算法
圆弧轨迹和直线轨迹最大的差别,是路径不再由两个端点唯一确定,需要三个不共线的点。三个点定义一段空间圆弧,此时必须先把圆心和半径算出来,才能在圆弧上密集生成路径点。三个不共线的点能确定一个平面,圆心在这个平面上,并且到三个点的距离相等,也就是同时落在三条边的中垂面上。常见的数值做法是把这个几何约束写成线性方程组一次解出。
三个点里如果有两点过于靠近,或者三点接近共线,圆心会飘到很远,轨迹计算直接失真,所以做圆弧轨迹前要先判断三点是否满足基本几何条件。判断方式很简单:法向量长度小于某个阈值就说明接近共线,直接报错返回。下面这段代码给出圆心求解的稳定写法,用的是最小二乘解而不是手工推导的解析公式,处理任意空间姿态的三点圆弧都不需要额外旋转坐标平面。
% 三点定圆:求空间圆弧的圆心 C 和半径 r P1 = [0.40; 0.10; 0.30]; % 圆弧起点 P2 = [0.45; 0.20; 0.35]; % 圆弧中间点 P3 = [0.35; 0.25; 0.32]; % 圆弧终点 n = cross(P2 - P1, P3 - P1); % 圆弧平面法向量,判别三点是否共线 if norm(n) < 1e-6 error('三点接近共线,无法确定空间圆弧'); end A = [2*(P2-P1)'; 2*(P3-P1)'; n']; % 两个中垂面方程 + 三点所在平面方程 b = [norm(P2)^2 - norm(P1)^2; ... norm(P3)^2 - norm(P1)^2; ... n' * P1]; C = A \ b; % 圆心坐标,3×1向量 r = norm(P1 - C); % 圆弧半径说明一下这个方程组的来源。第一个方程来自 |P2 - C|^2 = |P1 - C|^2,展开后就是 2*(P2-P1)·C = |P2|^2 - |P1|^2,第二个方程同理。第三个方程是平面约束 n·(C - P1) = 0,保证圆心落在三点所在的平面上。用 A\b 不是 inv(A)*b,数值上更稳定,是解线性方程组的通用习惯。这里的 n 没有归一化也没关系,方程组右侧第三行已经用 n'*P1 做了对应缩放,不影响方程组的一致性。
计算 C 之后,圆弧半径 r 取 P1 到 C 的距离就够,不需要对三个点都算一遍取均值,因为方程组已经强制三个点到 C 的距离相等了。这个步骤完成后,圆心和半径是后续所有路径点生成的基础,如果 SW模型里圆弧特征对应的几何尺寸能和这里的 r 对上,说明输入数据没给错。
3.2 圆弧路径点生成代码:局部坐标系下做角度插值,避免三维旋转混乱
圆心算出来之后,下一步是在圆弧上按角度生成密集路径点。实现上有两种常见做法:直接在全局坐标系里用atan2算角度,或者在圆弧平面建立局部坐标系,把三维圆弧降成二维圆再插值。我一般用局部坐标系,原因是在全局坐标系里对三个点求角度,很容易被坐标轴方向的投影干扰,尤其是当圆弧平面不平行于任何坐标平面时,角度计算容易出符号错误。
局部坐标系的构建方式是以 P1-C 为 x 轴,以平面法向量为 z 轴,y 轴由叉积补全。这个坐标系把圆弧变成 xOy 平面上的一个标准圆,角度插值就退化成二维问题,最后再把生成的路径点转换回全局坐标即可。这里有一个需要小心的知识点:圆弧有顺时针和逆时针两种方向,还有优弧和劣弧的区别。判断方向不能只看起点和终点的角度差,而要看中间点 P2 落在哪一侧,这就是很多人写出来的圆弧轨迹会突然画一个大圈的原因。
% 在局部坐标系中生成圆弧路径点 u = (P1 - C) / r; % 局部x轴基向量 w = n / norm(n); % 局部z轴基向量,即法向量归一化 v = cross(w, u); % 局部y轴基向量 Rl = [u'; v'; w']; % 世界->局部 的旋转矩阵,3×3 p1 = Rl * (P1 - C); % 三点变换到局部坐标系的xOy平面 p2 = Rl * (P2 - C); p3 = Rl * (P3 - C); th1 = atan2(p1(2), p1(1)); % 起点角度 th2 = atan2(p2(2), p2(1)); % 中间点角度,用于判断圆弧走向 th3 = atan2(p3(2), p3(1)); % 终点角度 % 根据中间点确定旋转方向,并处理跨 ±π 的情况 if th2 > th1 if th3 > th2 th_end = th3; % 逆时针,终点角直接使用 else th_end = th3 - 2*pi; % 逆时针跨过 π,角度减去一整圈 end else if th3 < th2 th_end = th3; % 顺时针 else th_end = th3 + 2*pi; % 顺时针跨过 -π end end steps = 60; theta = linspace(th1, th_end, steps); % 角度等差序列 arc_pts = zeros(3, steps); % 存放圆弧路径点,世界坐标系 for i = 1:steps local_pt = [r * cos(theta(i)); r * sin(theta(i)); 0]; arc_pts(:,i) = C + Rl' * local_pt; % 局部转世界 end逻辑说明:Rl 的每一行是局部坐标系的基向量,所以 Rl * (P1-C) 把全局坐标转换到局部坐标。Rl 是正交矩阵,从局部回到世界用 Rl' 乘以局部坐标向量即可,不需要单独写逆矩阵。th1、th2、th3 分别对应三个点在局部坐标系里的极角,判断顺序用的是 th2 和 th1 的相对大小,而不是 th3 和 th1 的相对大小,这是为了确定真实旋转方向。如果 th2 大于 th1 说明从起点到中间点是逆时针走,此时终点角度如果比中间点小,说明弧线跨过了 +π 边界,th_end 要减 2π 再插值。这个跨边界的处理是圆弧轨迹里最容易写错的地方,不加这一步,跨边界时 linspace 会从 th1 反向一路插过去,画出来的直接是补弧。
参数说明:steps 这里设置成 60,圆弧一般比直线更需要密一点,因为在相同角度间隔下,半径越大实际弧长越长,末端线速度在每个区间里并不完全均匀。如果需要时间同步或速度可调,还要额外把 theta 序列换成等弧长序列,或者先算弧长再按弧长规划速度,这个属于圆弧轨迹的进阶玩法,在避坑章里再展开。
3.3 圆弧位姿序列与逆解:姿态固定和姿态随动的两条实现路线
圆弧上的每个点都只是一个位置,要把路径点变成机械臂能执行的轨迹,还必须给每个路径点配一个姿态。姿态怎么给,取决于工艺要求,常见的是两种:姿态全程固定,或者姿态随圆弧切线方向旋转。姿态固定适合点胶、喷涂这类要求工具方向始终垂直于工件表面的场景,代码实现最简单,直接把一个恒定旋转矩阵右乘到每个路径点上。
姿态固定做法的代码段如下,R0 是基准姿态矩阵,按你的工具安装方向设定。如果机械臂末端法兰坐标系和工具坐标系之间有安装转角,需要在 R0 前面左乘工具安装补偿矩阵,这个细节漏掉的话,末端看起来会整个歪着走。
% 圆弧路径生成位姿序列,姿态全程固定 R_fix = rpy2tr(0, pi/2, 0); % 固定姿态,按实际需要修改 T_arc = zeros(4, 4, steps); for i = 1:steps T_arc(:,:,i) = transl(arc_pts(:,i)') * R_fix; end % 逐点逆解,q0 用上一帧关节角保证连续 q_arc = zeros(steps, 6); q_arc(1,:) = myrobot.ikine(T_arc(:,:,1), 'q0', myrobot.getpos(), 'mask', ones(1,6)); for i = 2:steps q_arc(i,:) = myrobot.ikine(T_arc(:,:,i), 'q0', q_arc(i-1,:), 'mask', ones(1,6)); end第一种实现的关键参数是 R_fix 本身,它除了包含姿态,还决定了圆弧路径点在世界坐标里的朝向一致性。如果 R_fix 和 arc_pts 的几何位置方向差得太多,ikine 很容易在某一段圆弧上不收敛,因为姿态要求和平移要求同时压在同一个运动学链上。第二种姿态随动做法,是逐点计算弧线上的切线方向,把切线方向作为工具的 x 轴或 z 轴,再用法向量作为约束补全旋转矩阵。这种做法的特点是末端在圆弧上每个点的姿态都不一样,姿态平滑变化,适合焊缝跟踪这类需要工具始终对齐焊缝法线的任务。为了不把篇幅拖长,这里只给思路:对 arc_pts 逐列做一阶差分得到切线方向,切线与法向量 n 叉积得到第三个基向量,三个基向量组成旋转矩阵,再拼成齐次矩阵。需要注意切线的方向要统一,否则姿态会在某个点附近突然翻转 180°,那也是圆弧规划里很经典的一个坑。
4. 机械臂轨迹规划避坑指南:SW模型导入、逆解翻车与圆弧方向反了的排查思路
4.1 SW模型导入后机械臂尺寸差了1000倍,轨迹全飞了
现象:SW模型导入仿真环境后,机械臂看起来异常庞大,或者末端轨迹点完全不在模型表面附近,轨迹线在空间里飘着。此时不管怎么调整轨迹参数,机械臂都碰不到目标位置。
原因:SW建模时默认长度单位是毫米,而 matlab机器人工具箱做运动学计算时一律按米走。模型几何尺寸如果是毫米数值,导入后相当于整个机械臂放大了1000倍,D-H参数按米设置,两者自然对不上,轨迹和模型表面相差十万八千里。
解决:常见做法是导入SW模型文件时先把几何顶点坐标统一除以 1000。例如读取STL网格数据后,把 vertices 字段整体除以 1000,再重新构造模型显示对象。另一种做法是在SW里导出模型之前把文档单位直接改成米,但很多装配体是从元件库拖出来的,源文件单位不一定统一,改起来容易漏件。我自己的习惯是在导入后统一处理几何顶点,不动原始模型文件,这样做可重复性好,换一台机械臂的SW模型时不会重复踩同样的单位坑。
4.2 ikine逆解中途不收敛,关节角序列突然乱跳
现象:直线轨迹和圆弧轨迹的前几十个路径点都正常,突然在某一帧报出逆解失败警告,或者不报错但关节角序列出现一个很大的突变,动画里机械臂像被甩了一下。
原因:多数情况是目标位姿穿越了机械臂的奇异位形,比如腕部中心接近某个关节轴延长线附近,雅可比矩阵退化为奇异,数值迭代失去稳定。另一个常见原因是逆解的初始猜测值给得离真实解太远,迭代收敛到了另一个分支。
解决:第一步把上一时刻的关节角作为 q0 传入当前位置的逆解,这是消除跳变最直接的手段。第二步检查奇异。用雅可比矩阵的条件数做预判,在求解循环里对每个路径点计算 jacob0,奇异值最小值低于阈值时跳过该点或者调整姿态。第三步检查 mask 设置,如果机械臂实际自由度少于6,mask 里多余的1必须改成0,否则逆解会在不存在的自由度方向上空转,误差一直压不下去。
4.3 圆弧方向画反了,短弧走成了长弧
现象:三个点定义了一个90度的圆弧,但机械臂末端画出来的轨迹是270度的大半圈,而且方向是反的。
原因:圆弧方向判断只用了起点和终点的角度差,没有看中间点 P2 的位置。linspace(th1, th3, steps) 默认沿着角度数值增大的方向插值,如果真实圆弧需要经过角度减小的方向,或者需要跨过±π边界,这种写法就会把补弧当成目标弧。
解决:用中间点 th2 判断方向,规则是:若 th2 大于 th1 则为逆时针,否则为顺时针。跨±π时先对终点角度加或减一整圈,再进入 linspace。这个判断逻辑在 3.2 节的代码里已经完整写了。排查圆弧轨迹问题最有效的办法是把生成的三个原始点、圆心和实际轨迹画在同一个三维图里,直接看有没有经过 P2。轨迹没有经过 P2 而是绕了另一端,基本可以断定是角度方向判断出了问题。
4.4 圆弧轨迹末端抖动,速度曲线像锯齿
现象:仿真动画里机械臂在圆弧末端附近来回小幅度晃动,关节速度曲线不是平滑过渡,而是类似于锯齿的波动,末端实际轨迹也不光滑。
原因:圆弧路径点之间是等角度间隔的,圆周上的线速度等于角速度乘以半径,等角度间隔不意味着等弧长,末端线速度其实是波动的。同时,如果逆解容差设置得太大,每个路径点上的位姿误差不统一,叠加起来就会表现出末端抖动。
解决:把直线和圆弧路径点进一步细化,steps 提高到100以上,让相邻点之间角度变化更小。然后把 ikine 的容差参数调小,比如 tol 设置到 1e-10 或 1e-12,换取更一致的位姿精度。如果抖动集中在末端附近,还要检查是否因为终点姿态和路径切线方向不一致,工具坐标系在末端被强行扭了一下。
5. 轨迹规划的结果怎么验收:把理论轨迹和实际轨迹贴在一起看
运动学仿真动画只是给人看的,真正要确认轨迹能不能用,要把理论路径和实际末端路径叠加画在一张图上,逐项检查偏差和速度曲线。这个阶段我习惯做三个验证:末端路径偏差检查、关节速度连续性检查、逆解成功率统计。
第一项是末端路径偏差,调用正运动学把关节序列转成末端位置序列,再和理论直线或圆弧逐点做差,取最大模长。这里建议把偏差值写进报告里,因为它是轨迹规划算法精度的直接证据。第二项是关节速度连续性,对关节角序列做差分,除以时间步长得到近似速度,观察曲线有没有明显尖刺。尖刺意味着某一帧的关节角跳变,说明逆解在那个点附近发生了分支切换。第三项是逆解成功率,也就是收敛帧数占总帧数的比例,理想状态是100%,只要出现一帧失败,整个轨迹就不能直接输出给下位机。
我把验证数据和可接受范围汇总成一张表,方便写报告时直接抄:
| 验证项 | 计算方式 | 参考阈值 |
|---|---|---|
| 末端直线/圆弧最大偏差 | max(vecnorm(实际位置-理论位置)) | < 1e-3 m |
| 关节速度尖刺 | max(abs(diff(q)/dt)) 出现孤立大值 | 不超过均值的10倍 |
| 逆解成功率 | 收敛帧数 / 总帧数 | 100% |
| 圆弧半径误差 | 实际路径点与圆心距离减理论半径 | < 1e-3 m |
上述四个数字在轨迹规划报告里是必须出现的,比截图更有说服力。我在做圆弧轨迹时还有一个习惯,就是不只在动画里看末端走弧线,而是把 arc_pts 点集导出来和理论圆弧直接对比,这样能确认几何计算环节无误,后续逆解导致的偏差才能单独分离出来排查。做机械臂轨迹规划,最怕的就是几何计算和运动学求解混在一起出问题,分不清是哪一个环节导致末端偏移,分步验证是这类问题最好的后悔药。
我早期做第一个直线轨迹Demo时完全没做偏差验证,直接上仿真模型,结果机械臂末端在终点附近抖得厉害,还以为逆解算法有问题,查了很久才发现是关节空间和任务空间混用了。后来养成习惯:无论直线还是圆弧,先画理论轨迹,再把实际轨迹叠上去,两个轨迹贴在一起才有信心继续往下做。做轨迹规划,很多时候不是公式拦住人,而是验证顺序没做对。希望帮到你。
本文还有配套的精品资源,点击获取