当前位置: 首页 > news >正文

Matlab机器人工具箱使用5 轨迹规划

参考视频:【MATLAB机器人工具箱10.4 机械臂仿真教学(未完结)】 https://www.bilibili.com/video/BV1q44y1x7WC/?p=6&share_source=copy_web&vd_source=2c56c6a2645587b49d62e5b12b253dca

写在前面:

插值算法在《机器人学导论》(约翰J克雷格著)第145页,如果没看过也没关系,下面我们会一起快速复习一遍。

本节内容很丰富,逻辑连贯一脉相承,需要2-3小时的理解和实操时间,极其不建议在课间或上课阅读,不被打断的思路很重要。

下面是本节的逻辑链,看不懂也没关系,等看完之后我们还会一起过一遍。

首先我们明确了轨迹规划的任务,包括了空间规划时间规划,使用的方法是插值法
接着我们复习了书上最简单的关节空间的三项式插值,理解了最基本的原理。
接着我们一起学习了时间上是如何控制的,linspace负责控制开始结束和插值点数,
lspb、tpoly负责将其映射到坐标上,完成时间上的插值;
然后我们学习了一个通用的插值方式——mtraj,他负责多维的插值控制,可以选择@空间映射函数。
接着我们学习了笛卡尔空间的空间规划器——trinterp和ctraj
最后我们发现,当仿真涉及姿态的变换时,前面这些方法都行不通,这是因为笛卡尔空间的连续性经过逆解后无法推得关节空间的连续性,也就是逆解对连续没有传递性。
因此我们想出来用jtraj直接在关节空间插值,彻底解决了这个难题。

轨迹规划复习速通

轨迹规划就是给定时间初末位姿,计算过程中的轨迹、速度、加速度,以给下位机控制。

轨迹规划包括两个维度的规划——时间和空间,首先要进行空间的规划,从理综楼到食堂如何走?
接着规划下楼走得快走得慢,大路走得快走得慢,食堂上楼走得快走得慢。

轨迹规划的两大核心:空间 vs 时间

目标:让机械臂末端从位姿 P1 平滑移动到 P2

这需要三个步骤:

步骤任务所需函数
1️⃣ 空间路径规划定义“怎么走”:从 P1 到 P2 的空间路径ctraj 或 trinterp
2️⃣ 时间节奏控制定义“走多快”:慢启动 → 快 → 慢停止tpoly / lspb / linspace
3️⃣ 逆运动学求解 + 可视化把空间轨迹转成关节角,驱动机器人ikine / plot

一般空间规划我们通过封装的函数实现(ctraj、trinterp、mtraj、jtraj),重点讨论的是时间上如何规划

下面举一个最简单的规划方式——三项式插值
因为时间是影响加速度,也就是力的最重要因素,设想:

假设是直线插值,那么在初末状态的速度加速度就是无限大,是不可能实现的,因此考虑将速度轨迹弯曲一些,使得导数(加速度)小一些。

于是有了三项式插值,但是这样初末的加速度还是有可能超过硬件限制,因此增加最高次项,使得速度轨迹、加速度轨迹更加平滑。

至于为什么是奇数次插值,是因为我们解决多项式插值的时候使用参数对应的方式求解,一个x次多项式有x+1个系数,通过初末状态的约束解出系数,而约束是初末的位置、速度、加速度,他们是成对出现的,因此插值都是奇数次插值。

下面是在关节空间内进行的三次多项式插值,如果是在笛卡尔空间中,直接把θ替换为x即可。

比如对于三次多项式,约束条件就是:
1.初始时刻关节变量θ(0)=θ0  终点时刻关节变量θ(t)=θt

2.初末速度连续

3.(五次多项式要求加速度也连续)

那么由三次多项式插值公式就能得到:



接下来要通过这个式子和前面设定的四条约束解出参数a。

解得:

这样,插值表达式就可以完全由初末状态的约束表达了。输入任意时刻t,都能计算出每个关节的瞬时角度了。

Matlab实现

时间控制部分

我们再次明确:让机械臂末端从位姿 P1 平滑移动到 P2

这需要三个步骤:

空间路径规划->时间插值控制->逆解+可视化

我们先介绍几种常见时间控制插值算法,这些方法你可能没听过,但不要紧,现在只是让你知道有这些函数,是什么?至于是如何实现的,下面会讲。

对比三种“节奏”控制方式(插值方式)

节奏类型代码效果
匀速s = linspace(0,1,51)机器人匀速走,启停有冲击
S形平滑t=linspace(0,3,51); s=tpoly(0,1,t);慢启动 → 快 → 慢停止
梯形速度t=linspace(0,3,51); s=lspb(0,1,t);加速 → 匀速 → 减速

linspace是一个均匀时间轴生成器,他会生成一个数组,在t0-t1这段时间中均匀插入n个时间节点,这些时间节点就是用于计算逆解的时间点。

但聪明的你意识到刚刚学到过线性插值效果不行。

于是考虑如何对时间进行五项式插值

我们定义了一个函数映射,

P = tpoly(x1, x2, t)

这个函数就是我们之前推导的三项式插值的拓展版——五项式插值。(推导用的关节坐标系,把θ换为笛卡尔坐标系的坐标即可构建这个映射)

“重新参数化”时间轴

想象你有一根均匀的时间轴:

t = [0.0, 0.1, 0.2, ..., 3.0]   ← 均匀分布

你想让机器人“慢启动 → 快 → 慢停止”,就不能直接用这些 t 值去线性推进进度

于是你用 tpolyt 重新映射成一个新的进度 s

s = tpoly(0,1,t) → [0.0, 0.001, 0.008, ..., 0.992, 0.999, 1.0]
原始时间轴 t (均匀):
|----|----|----|----|----|----|----|----|----|----|
0    0.3         1.0               2.0         3.0被 tpoly "扭曲" 成 s(t):
|    |     |           |                 |     |    |
0   0.01  0.1                           0.9  0.99  1.0↖ S形曲线:开头密,中间疏,结尾密 ↗

tpoly 就是一个“时间扭曲器”(Time Warper),把“均匀时间”扭曲成“S形进度”

这样,我们就得到了一个五项式插值。


同理,你也想到了,不仅可以用tpoly来映射,还有可以用lspb来映射。

lspb(x1, x2, t) 将时间向量 t 通过一个“梯形速度”剖面,平滑地“映射”或“扭曲”到从 x1x2 的值域上。

tpoly 是“S形扭曲”,lspb 是“梯形速度扭曲”,他能尽可能长时间保持最大速度。




接下来,我们来看下这些函数如何实现的?

单个维度的时间控制——线性插值:linspace

插值linspace函数

"linspace" 这个名称来源于 "linear space" 的缩写,意味着该函数生成的是线性分布的点。

基本用法

以下是一个通用的例子:

  • 起始值:ta
  • 结束值:tb
  • 点的数量:n

调用 linspace(ta, tb, n) 将返回一个数组,包含从 ta 到 tb 之间的 n 个等间隔数值。

因此t就是一个拥有n个插值点的数组。这里意味着从ta到tb间均匀插入n个时间点。

这个函数决定了整个运动控制的时间从何时开始,何时结束,有几次插值。

单个维度的时间控制——五次多项式插值:tpoly

这是一个非常强大的插值生成器,他能生成位置、速度、加速度的插值函数

主要有两种参数模板:

✅ 形式1:使用时间向量(推荐用于真实时间仿真)
[P, dP, ddP] = tpoly(q0, qf, t);

这种形式q0是起始坐标,qf是终点坐标,t是时间向量,允许自定义时序插值。比如我们希望在0-3秒内均匀时间点插值,那么可以这样写(见注释):

t = linspace(0, 3, 51);           % 在 0 到 3 秒内,取 51 个时间点
[P, dP, ddP] = tpoly(q0, qf, t);  % 从 q0 到 qf,在 3 秒内完成

上面是我们刚刚提到的“映射为五项式”的形式,tpoly还提供另一种形式:

✅ 形式2:指定采样点数(常用于归一化进度生成)

这种形式没有t向量,意味着它将在1秒内完成,无法像时间向量一样来调控采样时序。

[P, dP, ddP] = tpoly(q0, qf, N, a0, af);

此外,要强调的是,matlab允许函数返回多个值,你可以选择性接受。

我们给定在0~2秒内进行51次插值,也就是每0.04秒执行一次插值。

单个维度的时间控制——混合曲线插值:lspb

同上,只是把插值映射函数改为了lspb。


我们的机器人是在多维空间中运作的,上文这些时间控制仅用于单个维度,因此我们还需要扩展到多个维度的控制——

多维轨迹规划=mtraj+@插值方法

很好理解,mtraj相当于对各个维度都采用@XX这种插值控制方式,比如我们刚学的lspb或tpoly。

p = mtraj(@tpoly, p0, pf, t);

此时不用一个维度一个维度写tpoly/lspb的具体参数了,但依然需要传入时间轴t,决定了花多久允许完整个过程。mtraj 会把时间向量 t 传给每一个 @tpoly,让它们在指定的时间点上完成插值。

🔹 参数1:@f —— “时间规划器”:每个维度怎么随时间变化?

参数控制什么?常见值
@f位置如何随时间变化

@tpoly:五次多项式(S形)

@lspb:梯形速度


🔹 参数2:p0 和 pf —— 起点和终点的坐标+姿态(向量)

参数控制什么?例子
p0起点的多维值

[0.7, -0.5, 0] / [0, 0]

pf终点的多维值

[0.7, 0.5, 0.5] / [pi/2, pi/4]


🔹 参数3:t —— 时间轴:在哪些时间点上计算轨迹?

参数控制什么?例子
t时间点序列,表示“在哪些时刻计算位置”t = linspace(0, 2, 51) / t = 0:0.04:2

比如下面,使用多维轨迹插值函数mtraj,选用插值处理方法为@tpoly五项式插值,第四参数传入时间轴,第二三参数是初末位置。很好理解。


这个不属于时间/空间规划,只是作为扩展。为了逻辑连贯,你可以先跳过。

多段轨迹规划

mstraj函数用于处理多端轨迹规划问题,他有7个参数,其中QDMAX和TSEG是冲突参数,只能指定其一。

1. WP (Waypoints)

  • 含义:轨迹中的节点。

2. QDMAX (Maximum Velocity)【与下面参数冲突】

  • 含义:最大速度限制。

3. TSEG (Segment Times)【与上面参数冲突】

  • 含义:每个轨迹段的持续时间。

4. Q0 (Initial Position)

  • 含义:初始位置。

5. DT (Sampling Time)

  • 含义:采样时间间隔。

6. TACC (Acceleration Time)

  • 含义:加速和减速时间。

7. OPTIONS (Optional Parameters)

  • 含义:其他可选参数。

P1代表以wp为路径节点,最大速度置为空,两段路径的花费时间分别是2和1s,Q0初始位置为空,默认为WP的(0,0),间隔为0.04s,加速时间为0

P2代表以wp为路径节点,最大速度置为空,两段路径的花费时间分别是2和1s,Q0初始位置为空,默认为WP的(0,0),间隔为0.04s,加速时间为0.5

显然,图一加速时间为0,因此存在拐点,加速度瞬间从2变到-2,是不合实际的。
而图二的加速时间是0.5s,可以看到拐点前后有大约0.25s的弯曲,此时加速度就是连续的了。


之前我们已经完成了时间规划与插值了,接下来要完成空间规划以及在之前的时间插值点计算变换矩阵的操作了。

★ 三维空间的位置轨迹规划

欢迎来到真正的正文!

在真正进行规划的时候要有这样的意识:尽管在笛卡尔空间中轨迹是连续的,可能在关节空间内,关节变量并非连续的!因此,下面从笛卡尔空间插值讲解到关节空间插值的解决方案。

题目:演示从P1到P2位置的插值流程,包括模型描述、轨迹规划与逆运动学求解以及轨迹可视化。

基础不带插值的代码如下,对P1,P2分别转化为变换矩阵,再乘以trotx(180)。因为默认工具坐标系与基坐标系共轴,因此是朝上的,我们尽量从上方靠近目标点,也就是朝下的,要乘以trotx(180)。你可以删去试试。

%% 定义五自由度机械臂
L(1) = Link('revolute','d',0.216,'a',0,'alpha',pi/2);
L(2) = Link('revolute','d',0,'a',0.5,'alpha',0,'offset',pi/2);
L(3) = Link('revolute','d',0,'a',sqrt(0.145^2+0.42746^2),'alpha',0, 'offset', -atan(427.46/145));
L(4) = Link('revolute','d',0,'a',0,'alpha',pi/2,'offset', atan(427.46/145));
L(5) = Link('revolute', 'd', 0.258, 'a', 0, 'alpha', 0);Five_dof = SerialLink(L, 'name', '5-dof');
Five_dof.base = transl(0, 0, 0.28);%% 生成笛卡尔空间轨迹
P1 = [0.7, -0.5, 0];
P2 = [0.7, 0.5, 0.5];T1=transl(P1)*trotx(180);
T2=transl(P2)*trotx(180);q1=Five_dof.ikunc(T1);
q2=Five_dof.ikunc(T2);Five_dof.plot(q1);
pause;
Five_dof.plot(q2);

我们来做空间轨迹规划吧,实际上,具体如何做已经不需要我们完成了,matlab的机器人工具箱提供了封装好的函数,我们只要会用即可。

空间规划有两种形式,一种是在笛卡尔空间做空间插值,另一种是在关节空间内做。

笛卡尔空间规划

法一:mtraj笛卡尔空间内插值,并在各点转化为变换矩阵,接着对各点计算逆解,得到关节变量变化。

具体步骤分析
1. P1/P2 到 Traj
  • 使用 mtraj 函数生成从起始点 P1 到目标点 P2 的平滑轨迹 Traj。这一步确保了在笛卡尔空间中的轨迹是平滑和连续的。
2. Traj 到 T
  • 使用 transl 函数将轨迹中的每个位置点转换为齐次变换矩阵 T
3. T 到 Qtraj
  • 使用 ikunc 函数根据齐次变换矩阵 T 计算出对应的关节角度 Qtraj。这一步是关键,因为逆运动学求解可能会引入不连续性
运行代码

这里利用mtraj规划器,采用tpoly五项式的空间插值方式,采用均分时间的速度控制方式

%% 定义五自由度机械臂
L(1) = Link('revolute','d',0.216,'a',0,'alpha',pi/2);
L(2) = Link('revolute','d',0,'a',0.5,'alpha',0,'offset',pi/2);
L(3) = Link('revolute','d',0,'a',sqrt(0.145^2+0.42746^2),'alpha',0, 'offset', -atan(427.46/145));
L(4) = Link('revolute','d',0,'a',0,'alpha',pi/2,'offset', atan(427.46/145));
L(5) = Link('revolute', 'd', 0.258, 'a', 0, 'alpha', 0);Five_dof = SerialLink(L, 'name', '5-dof');
Five_dof.base = transl(0, 0, 0.28);%%
P1 = [0.7, -0.5, 0];
P2 = [0.7, 0.5, 0.5];
t = linspace(0, 2, 51);
Traj = mtraj(@tpoly, P1, P2, t);n = size(Traj, 1);
T = zeros(4, 4, n);for i = 1:nT(:, :, i) = transl(Traj(i, :)) * trotx(180);
endQtraj = Five_dof.ikunc(T);Five_dof.plot(Qtraj, 'trail', 'b');
Five_dof.plot(Qtraj, 'movie', 'trail.gif');
核心代码
Traj = mtraj(@tpoly, P1, P2, t);n = size(Traj, 1);
T = zeros(4, 4, n);for i = 1:nT(:, :, i) = transl(Traj(i, :)) * trotx(180);
end

这里用mtraj使用五项式插值的空间插值方式得到了插值矩阵Traj,然后对每个Traj进行逆解,得到变换矩阵数组T,并把z轴转到下面。

运行效果

关节变量变化

小技巧:运行节

%%是分节符,比如接下来我需要绘制关节变量的变化趋势,不需要重头执行,而是可以在前面代码最后“追加节”

在上面代码的最后追加以下内容:

%%
hold onplot(t, Traj(:, 1), '.-', 'linewidth', 1);
plot(t, Traj(:, 2), '.-', 'linewidth', 1);
plot(t, Traj(:, 3), '.-', 'linewidth', 1);grid on
legend('x', 'y', 'z');
xlabel('time');
ylabel('position')

点击最后这段代码,会在列选出现蓝色条,代表选中当前节了

点击“运行节”,就只会运行选中部分的代码:


小技巧:执行所选内容

“运行节”是一种方案,假如我们只是要运行一行(或多行)呢?
这个时候可以选中,然后按“F9”。
或者选中所需要运行的内容,右键,点击“在命令行窗口中执行所选内容”

因此“运行节”的操作也可以:

选中需要运行的内容

按“F9”或点击“在命令行窗口中执行所选内容”

关节变量轨迹

以上“运行节”和“运行所选内容”都能得到这张图:由于是在笛卡尔空间中做的插值,因此xyz三维上都是连续的。

法二:位姿插值函数trinterp

🔹 参数1:T1 和 T2 —— 起点和终点的“完整姿势”
🔹 参数2:M —— 选用的空间插值函数

比如看下面,

运行代码
%% 定义五自由度机械臂
L(1) = Link('revolute','d',0.216,'a',0,'alpha',pi/2);
L(2) = Link('revolute','d',0,'a',0.5,'alpha',0,'offset',pi/2);
L(3) = Link('revolute','d',0,'a',sqrt(0.145^2+0.42746^2),'alpha',0, 'offset', -atan(427.46/145));
L(4) = Link('revolute','d',0,'a',0,'alpha',pi/2,'offset', atan(427.46/145));
L(5) = Link('revolute', 'd', 0.258, 'a', 0, 'alpha', 0);Five_dof = SerialLink(L, 'name', '5-dof');
Five_dof.base = transl(0, 0, 0.28);%%
P1 = [0.7, -0.5, 0];
P2 = [0.7, 0.5, 0.5];
T1=transl(P1)*trotx(180);
T2=transl(P2)*trotx(180);t = linspace(0, 2, 50);T_interp = trinterp(T1, T2, t/2);  % 直接对两个位姿插值Qtraj = Five_dof.ikunc(T_interp);Five_dof.plot(Qtraj, 'trail', 'b');
Five_dof.plot(Qtraj, 'movie', 'trinterp_trail.gif');
核心代码
t = linspace(0, 2, 50);T_interp = trinterp(T1, T2, t/2);  % 直接对两个位姿插值
运行效果

运动曲线

为了看出选用的插值函数M到底对运动曲线有什么影响,我们在后面也添上这段代码

%%P_liner = transl(T_interp);
hold onplot(t, P_liner(:, 1), '.-', 'linewidth', 1);
plot(t, P_liner(:, 2), '.-', 'linewidth', 1);
plot(t, P_liner(:, 3), '.-', 'linewidth', 1);grid on
legend('x', 'y', 'z');
xlabel('time');
ylabel('position');

由于上面代码用的普通的线性插值,因此笛卡尔空间的运动曲线都是线性的

我们试试用tpoly看看会不会呈现不一样的效果:

把这一句:

T_interp = trinterp(T1, T2, t/2);  % 直接对两个位姿插值

替换为:

T_interp = trinterp(T1, T2, tpoly(0,2,50)/2);  % 直接对两个位姿插值

重新运行这一节,然后运行绘图那一节:

显然我们的五项式插值使得运动曲线变弯了,M作为可以任意选择的时间插值函数,就是matlab模块化的特征。

法三:笛卡尔轨迹插值函数ctraj

同上,基本是一样的,把上文trinterp替换为ctraj即可。

运行代码
%% 定义五自由度机械臂
L(1) = Link('revolute','d',0.216,'a',0,'alpha',pi/2);
L(2) = Link('revolute','d',0,'a',0.5,'alpha',0,'offset',pi/2);
L(3) = Link('revolute','d',0,'a',sqrt(0.145^2+0.42746^2),'alpha',0, 'offset', -atan(427.46/145));
L(4) = Link('revolute','d',0,'a',0,'alpha',pi/2,'offset', atan(427.46/145));
L(5) = Link('revolute', 'd', 0.258, 'a', 0, 'alpha', 0);Five_dof = SerialLink(L, 'name', '5-dof');
Five_dof.base = transl(0, 0, 0.28);%%
P1 = [0.7, -0.5, 0];
P2 = [0.7, 0.5, 0.5];
T1=transl(P1)*trotx(180);
T2=transl(P2)*trotx(180);t = linspace(0, 2, 50);T_ctraj = ctraj(T1, T2, t/2);  % 直接对两个位姿插值Qtraj = Five_dof.ikunc(T_ctraj);Five_dof.plot(Qtraj, 'trail', 'b');
Five_dof.plot(Qtraj, 'movie', 'ctraj_trail.gif');
核心代码

把前面的trinterp替换为笛卡尔插值ctraj即可

t = linspace(0, 2, 50);T_ctraj = ctraj(T1, T2, t/2);  % 直接对两个位姿插值
运行效果

关节变量变化

和上文一样,把T_trinterp替换为T_ctraj即可

%%P_liner = transl(T_ctraj);
hold onplot(t, P_liner(:, 1), '.-', 'linewidth', 1);
plot(t, P_liner(:, 2), '.-', 'linewidth', 1);
plot(t, P_liner(:, 3), '.-', 'linewidth', 1);grid on
legend('x', 'y', 'z');
xlabel('time');
ylabel('position');

同理,如果把:

T_ctraj = ctraj(T1, T2, t/2);  % 直接对两个位姿插值

替换为:

T_ctraj = ctraj(T1, T2, tpoly(0,2,50)/2);  % 直接对两个位姿插值

依然可以得到弯曲的图像。


至此,对于轨迹规划对于位置的处理主体全部结束。

接下来我们会学习如何处理姿态的轨迹规划。




★ 三维空间的姿态轨迹规划

我们继续,

对于姿态的处理,和位置其实一样,依然可以用最朴素的方式,把初末状态的姿态也用tr2rpy转化为rpy角,然后用mtraj+@XX的方式得到姿态的变换矩阵,再求逆,得到关节变量。

但是,问题这时候出现了!

机械臂以一种极其扭曲抽象怪异猎奇不适不安恐惧的轨迹和姿态走到了终点。

从命令行我们也能看出,好几处位姿到达奇异点,导致关节变量突变,这是极其容易损坏机械臂的。

这是因为,在笛卡尔空间规划路径,再通过逆解映射到关节空间。即使末端轨迹连续,但由于逆解不唯一,可能导致关节角度突变。

我们再试试trinterp:

以及ctraj:

我们可以得出结论:trinterpctraj 是在笛卡尔空间插值的,因此它们也无法保证关节空间的连续性或最优性。

至于视频中up为何能实现直线旋转移动过去我也没有复现出来。应该是修改了角度。

下面这个是按照这个参数设置的,效果不错:

rpy1_base = [0, 150, 30];
rpy2_base = [90, 200, 190];

完整代码:

%% 定义五自由度机械臂
L(1) = Link('revolute','d',0.216,'a',0,'alpha',pi/2);
L(2) = Link('revolute','d',0,'a',0.5,'alpha',0,'offset',pi/2);
L(3) = Link('revolute','d',0,'a',sqrt(0.145^2+0.42746^2),'alpha',0, 'offset', -atan(427.46/145));
L(4) = Link('revolute','d',0,'a',0,'alpha',pi/2,'offset', atan(427.46/145));
L(5) = Link('revolute', 'd', 0.258, 'a', 0, 'alpha', 0);Five_dof = SerialLink(L, 'name', '5-dof');
Five_dof.base = transl(0, 0, 0.28);%% 设置初始和目标位姿(z轴朝下)
P1 = [0.7, -0.5, 0];
P2 = [0.7, 0.5, 0.5];rpy1_base = [0, 150, 30];
rpy2_base = [90, 200, 190];T1_orient = rpy2tr(deg2rad(rpy1_base)) ;
T2_orient = rpy2tr(deg2rad(rpy2_base)) ;T1 = transl(P1) *trotx(180)* T1_orient;
T2 = transl(P2) *trotx(180)* T2_orient;%% ✅ 正确使用 trinterp
s = linspace(0, 1, 51);                    % 进度参数 [0,1]
T_traj = trinterp(T1, T2, s);              % SE(3) 插值%% 逆解与可视化
q_traj = Five_dof.ikunc(T_traj);figure;
Five_dof.plot(q_traj, 'trail', 'r');
title('Correct: trinterp with s ∈ [0,1]');
Five_dof.plot(q_traj, 'movie', 'ctraj_trail.gif');

解决关节空间内突变问题

解决方案呢?

本质上说,如果在笛卡尔空间就进行轨迹规划,那么之后才会进行对应关节空间求解,这是很容易造成关节空间不连续的突变的。 而如果先把初末位姿直接先求逆解,得到关节空间的初末位姿再在关节空间进行轨迹规划,就能避免这个问题

恭喜你,发现了

对变换矩阵进行插值的函数——

关节空间插值规划器jtraj

运行代码
%% 定义五自由度机械臂
L(1) = Link('revolute','d',0.216,'a',0,'alpha',pi/2);
L(2) = Link('revolute','d',0,'a',0.5,'alpha',0,'offset',pi/2);
L(3) = Link('revolute','d',0,'a',sqrt(0.145^2+0.42746^2),'alpha',0, 'offset', -atan(427.46/145));
L(4) = Link('revolute','d',0,'a',0,'alpha',pi/2,'offset', atan(427.46/145));
L(5) = Link('revolute', 'd', 0.258, 'a', 0, 'alpha', 0);Five_dof = SerialLink(L, 'name', '5-dof');
Five_dof.base = transl(0, 0, 0.28);P1 = [0.7, -0.5, 0];
P2 = [0.7, 0.5, 0.5];rpy1_base = [0, 150, 30];
rpy2_base = [90, 200, 190];T1_orient = rpy2tr(deg2rad(rpy1_base));
T2_orient = rpy2tr(deg2rad(rpy2_base));T1 = transl(P1) * trotx(180) * T1_orient;  % 注意:pi 弧度 = 180°
T2 = transl(P2) * trotx(180) * T2_orient;% 1. 求起终点关节角(可加初值避免跳解)
q1 = Five_dof.ikunc(T1);
q2 = Five_dof.ikunc(T2);% 2. 关节空间插值
s = linspace(0, 1, 51);
q_traj = jtraj(q1, q2, s);  % jtraj使用五次多项式轨迹规划,全程平滑% 3. 可视化
figure;
Five_dof.plot(q_traj, 'trail', 'g', 'movie', 'jtraj_smooth.gif');
title('jtraj: No More Jumps! Smooth & Safe Motion');
核心代码
s = linspace(0, 1, 51);
q_traj = jtraj(q1, q2, s);  % jtraj使用五次多项式轨迹规划,全程平滑
运行效果

飘柔,纵享新丝滑!

这个是因为,

我们先把初末位姿转化为变换矩阵,然后对其逆解得到初末的关节变量,然后对关节变量进行插值,这就使得关节变量连续可微。

写在最后

这节课内容非常多,你可能需要3-4小时来实操和消化,尤其是在笛卡尔空间插值和在关节空间插值二者的区别和效果的理解上。

首先我们明确了轨迹规划的任务,包括了空间规划和时间规划,使用的方法是插值法;
接着我们复习了书上最简单的关节空间的三项式插值,理解了最基本的原理。
接着我们一起学习了时间上是如何控制的,linspace负责控制开始结束和插值点数,
lspb、tpoly负责将其映射到坐标上,完成时间上的插值;
然后我们学习了一个通用的插值方式——mtraj,他负责多维的插值控制,可以选择@空间映射函数。
接着我们学习了笛卡尔空间的空间规划器——trinterp和ctraj。
最后我们发现,当仿真涉及姿态的变换时,前面这些方法都行不通,这是因为笛卡尔空间的连续性经过逆解后无法推得关节空间的连续性,也就是逆解对连续没有传递性。
因此我们想出来用jtraj直接在关节空间插值,彻底解决了这个难题。

你太棒了!


文章转载自:

http://Tb17lVge.zLzpz.cn
http://G4graPH6.zLzpz.cn
http://U157RTmM.zLzpz.cn
http://nwpIqmaD.zLzpz.cn
http://RgGKcGNw.zLzpz.cn
http://scv0Ujcs.zLzpz.cn
http://o1KAUeVg.zLzpz.cn
http://fsflWAfs.zLzpz.cn
http://LrRpeYjN.zLzpz.cn
http://V8072gEn.zLzpz.cn
http://w7MwO1KH.zLzpz.cn
http://KxPfAIAo.zLzpz.cn
http://Mhpu3bre.zLzpz.cn
http://c8w7fhtn.zLzpz.cn
http://0J5MXPFs.zLzpz.cn
http://tAjd1e0o.zLzpz.cn
http://CSu2Cr5N.zLzpz.cn
http://4d0hjNnV.zLzpz.cn
http://yCPBpunC.zLzpz.cn
http://sOazQYGz.zLzpz.cn
http://o36xMS2K.zLzpz.cn
http://bBnNTkrZ.zLzpz.cn
http://lcJuIBKZ.zLzpz.cn
http://qVUR6hyD.zLzpz.cn
http://D7mJq8GZ.zLzpz.cn
http://MhkzhcjD.zLzpz.cn
http://R9Z8QDIr.zLzpz.cn
http://DxjZAJbk.zLzpz.cn
http://uGvlzfwJ.zLzpz.cn
http://omhXyDuH.zLzpz.cn
http://www.dtcms.com/a/375925.html

相关文章:

  • 【git】Git 大文件推送失败问题及解决方案
  • ctfshow-web入门-php特性(二)
  • CSP认证练习题目推荐 (1)
  • MySQL 命令
  • MyBatis操作数据库——进阶
  • huggingFace学习之编码工具
  • 人工智能期末复习(部分)
  • 【Pytorch】2025 Pytorch基础入门教程(完整详细版)
  • Cookie 与 Session 的关系详解
  • Java微服务架构拆分:边界原则的实战破局与多场景案例解析
  • expect脚本详解
  • 交通识别摄像头以及带AI算法
  • SpringMVC通过注解实现全局异常处理
  • Linux基础知识(四)
  • 向量化与嵌入模型:RAG系统背后的隐形英雄
  • 你知道zip()和zip(*)怎么用吗?
  • 工业领域企业CRM常用的有哪些系统?
  • Git cherry-pick 与分支重置技术实现代码健全性保障下的提交记录精简
  • 【Nginx 运维实战】版本替换:强制 vs 平滑升级全解析
  • HTTPS加解密流程解析
  • Android 升级minSdkVersion 导致 包体积变大的处理
  • Linux系统 Python3.12版本连接达梦数据库dmPython和django_dmPython
  • 零知开源——ESP32驱动OV7670摄像头实现简易照相机系统
  • 前端开发工具trae的使用
  • Coze源码分析-资源库-创建插件-前端源码-核心组件
  • 数据集成平台怎么选?从ETL到CDC再到iPaaS的全景对比
  • 【Linux基础】Linux系统配置IP详解:从入门到精通
  • 2025版基于springboot的企业考勤管理系统
  • 【计算机毕业设计选题】2025-2026年计算机毕业设计选题经验与项目推荐
  • Python数据处理管道完全指南:从基础到高并发系统实战