本文为书籍 Introduction to Humanoid Robotics 的汉化, 主要借助翻译器 DeepL.
另外, 原书有管贻生教授的译作版本:《仿人机器人》(清华大学出版社, 2007年). 强烈推荐.
6 动力学仿真 (Dynamic Simulation)
图 6.1 展示了仿人机器人 HRP-2P 的摔倒实验. 通过进行动态模拟, 我们可以在实际进行此类实验之前预测机器人何时会落地以及落地的力度. 这也是一种强大的工具, 可用于开发摔倒控制方法, 以最大限度地减少触地冲击力, 并开发耐用的硬件.
本章旨在展示动态模拟的理论和实践. 首先, 我们将推导一个旋转物体在零重力空间中的运动方程. 通过开发该问题的模拟器, 我们将对动态模拟有一个直观的了解. 在接下来的章节中, 我们将通过引入平移, 重力和与环境的接触力来开发一个完整的刚体模拟器. 我们的技术模拟了一个旋转的陀螺, 这是令人印象深刻的三维动态运动之一.
机器人的动态模拟可以表述为由关节连接的多个刚体. 在本章末尾, 我们将概述 Featherstone 开发的一种高效算法.
6.1 旋转刚体的动力学
我们首先推导刚体绕其质心旋转的运动方程, 然后解释基于该方程的模拟程序. 在本节中, 我们假设刚体的质心静止在世界坐标系原点处.
6.1.1 欧拉运动方程
让我们回顾一下第 3 章学到的动力学基础知识. 物体的动量
同样, 物体的角动量
在给定角速度向量
朝向
其中,
这些就是我们在第 3 章学到的内容.
现在我们可以推导出刚体的旋转方程. 将 (6.2) 和 (6.3) 代入 (6.1), 我们得到
利用旋转基本方程
最后, 用 (6.3) 代替惯性张量, 我们就得到了下式, 即欧拉方程
6.1.2 刚体旋转仿真
欧拉方程比牛顿方程复杂一些. 为了理解其本质, 让我们做一个简单的仿真.
假设一个尺寸为 0.1
假定角加速度和速度
仿真结果如图 6.2 所示. 在没有外力作用的情况下, 我们看到物体以一种复杂的方式旋转. 图 6.3 的上图显示了角速度从初始值
就像这次仿真一样, 一般来说, 三维空间中的浮动刚体旋转方式比较复杂, 没有固定的旋转轴. 角速度的变化由 (6.5) 给出, 在外部力矩为零的情况下, 角加速度不为零. 角加速度的来源是惯性张量的变化, 即旋转引起的质量分布的变动.
我们可能需要利用这种旋转来清理环绕地球运行的太空碎片, 这些碎片可能会对未来的太空飞船造成伤害.
图 6.4 和 6.5 显示了仿真旋转物体的 Matlab 代码.
图 6.4 EulerDynamics.m 计算欧拉方程
1
2
3
4
5function L = EulerDynamics(j)
global uLINK
I = uLINK(j).R * uLINK(j).I * uLINK(j).R'; % Inertia tensor
L = I * uLINK(j).w; % Angular momentum
uLINK(j).dw = I(-cross(uLINK(j).w, L)); % Euler's equation图 6.5 自由刚体旋转的模拟代码. 有关 MakeRigidBody 和 ShowObject 子程序, 请参见第 6.6.2 节.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18global uLINK
lx = 0.1; ly = 0.4; lz = 0.9; % Depth, Width, Height [m]
mass = 36.0; % Mass [kg]
MakeRigidBody(1, [lx ly lz], mass);% Create rigid body
uLINK.p = [0.0, 0.0, 0]'; % Initial position [m]
uLINK.R = eye(3); % Initial posture
uLINK.w = [1, 1, 1]'; % Initial angular velocity [rad/s]
Dtime = 0.02; % Integration time [s]
EndTime = 5.0; % End of simulation [s]
time = 0:Dtime:EndTime;
figure
AX = [-0.5 0.5]; AY = [-0.5 0.5]; AZ = [-0.5 1.0]; % 3D view area
for n = 1:length(time)
L = EulerDynamics(1); % Euler's equation
uLINK(1).R = Rodrigues(uLINK(1).w, Dtime) * uLINK(1).R; % Rodrigues
uLINK(1).w = uLINK(1).w + Dtime * uLINK(1).dw; % Euler-method
ShowObject; % Show object
end
6.2 空间速度
6.2.1 刚体速度
在机器人学中, 我们使用两种不同的方法来表示刚体在三维空间中的平移速度.
(A) 参考点速度: 在刚体上设置一个适当的参考点 (如质心或关节中心) , 则其在世界坐标系中的速度
被视为刚体的速度. 对于参考点 的位置, 刚体上任意点 的速度取值为 (B) 空间速度: 以下向量被视为刚体的平移速度 [30]
如图 6.6 所示, 在给定的刚体瞬时状态下, 无论
如何选择, 我们都能得到唯一的 . 因此, 我们可以将 视为刚体的固有平移速度. 在世界坐标系中, 以速度 运动的刚体上的点 的速度由以下公式给出 由
组成的六维向量称为刚体的空间速度[30, 101].
通常, 刚体的平移速度用 (A) 表示. 事实上, 在第 2 章中, 我们以局部坐标系原点为参考点, 用 (A) 定义了平移速度.
另一方面, 通过使用 (B) 中的空间速度, 加速度的处理大大简化, 并最终实现了本节末将讨论的 Featherstone 快速动力学计算. 因此, 我们使用 (B) 中描述的方法来表示刚体运动.
6.2.2 整合空间速度
在本节中, 我们将解释一种通过对给定的空间速度进行积分来更新位置和朝向的方法. 不幸的是, 这种计算方法有点复杂. 让我们将给出以空间速度
其中,
如果
矩阵指数
为了简化这个无穷级数, 我们首先对空间速度进行归一化处理, 使角速度的范数变为 1
由此, 我们可以得出以下方程
更详细的推导, 请参见 Murray, Li 和 Sastry 的教科书[101] (第 39-42 页) .
如果角速度
当刚体在时间
方程 (6.12), (6.13) 和 (6.14) 可以编码成 Matlab 程序, 如图 6.7 所示. 程序中引入了一个新变量 uLINK.vo, 用于保存空间速度的线性部分
图 6.8 显示了图 6.7 所示程序计算出的刚体在恒定空间速度下的运动情况.
图 6.7 SE3exp.m 根据空间速度更新位置和朝向
1
2
3
4
5
6
7
8
9
10
11
12
13
14function [p2, R2] = SE3exp(j, dt)
global uLINK
norm_w = norm(uLINK(j).w);
if norm_w < eps
p2 = uLINK(j).p + dt * uLINK(j).vo;
R2 = uLINK(j).R;
else
th = norm_w*dt;
wn = uLINK(j).w/norm_w; % normalized vector
vo = uLINK(j).vo/norm_w;
rot = Rodrigues(wn, th);
p2 = rot * uLINK(j).p +(eye(3)-rot)*cross(wn, vo) + wn * wn' * vo * th;
R2 = rot * uLINK(j).R;
end
6.3 刚体动力学
本节将讨论三维空间中刚体的动力学和仿真方法.
6.3.1 牛顿-欧拉方程
众所周知, 刚体动力学可分为质心 (CoM) 的平移和围绕质心的旋转. 因此, 三维空间中的刚体动力学由质心的牛顿方程和围绕质心的欧拉方程给出. 这些方程称为牛顿-欧拉方程, 其式如下
其中,
6.3.2 空间速度的动力学
让我们用空间速度重写牛顿-欧拉方程. 假设我们有一个刚体, 其 CoM 速度为
求导得
由 (6.18) 和 (6.17) 可得, CoM 的加速度为
将其代入牛顿方程 (6.15), 我们就得到了空间速度表示下的平移运动方程
另一方面, 作用在惯性体上的力
将欧拉方程 (6.16) 和 (6.20) 代入 (6.21), 我们可以得到空间速度表示下的旋转动力学方程
(6.20) 和 (6.22) 这两个看起来令人讨厌的方程式可以组织成下面的矩阵方程. 这是使用空间速度的刚体运动方程
矩阵
此外, 六维向量
注意, 刚体的动量和角动量计算公式为
6.3.3 基于空间速度的刚体仿真
通过使用空间速度的刚体运动方程 (6.23), 我们可以计算出在给定力和力矩
图 6.9 显示了根据该方程
仿真的空间速度
与其使用空间速度和 (6.26), 有些人可能更喜欢使用原始的牛顿-欧拉方程 (6.15) 和 (6.16) 来进行此类单刚体仿真. 尽管如此, 请耐心等待第 6.4 节, 在该节中, 多体系统的计算将显示空间速度表示法的优势.
图 6.11 列出了部分用于仿真的 Matlab 代码. 引入了一个新变量 uLINK.dvo, 用于保存空间加速度
图 6.11 SE3dynamics.m 刚体运动方程
1
2
3
4
5
6
7
8
9
10
11
12
13
14function [P,L] = SE3dynamics(j)
global uLINK
w_c = uLINK(j).R * uLINK(j).c + uLINK(j).p; % Center of mass
w_I = uLINK(j).R * uLINK(j).I * uLINK(j).R'; % Inertia tensor
c_hat = wedge(w_c);
Iww = w_I + uLINK(j).m * c_hat * c_hat';
Ivv = uLINK(j).m * eye(3);
Iwv = uLINK(j).m * c_hat;
P = uLINK(j).m * (uLINK(j).vo + cross(uLINK(j).w,w_c)); % Lin. momentum
L = uLINK(j).m * cross(w_c,uLINK(j).vo) + Iww * uLINK(j).w; % Ang. momentum
pp = [cross(uLINK(j).w,P); cross(uLINK(j).vo,P) + cross(uLINK(j).w,L)];
a0 = -[Ivv, Iwv'; Iwv, Iww] pp; % Spatial acceleration
uLINK(j).dvo = a0(1:3);
uLINK(j).dw = a0(4:6);
6.3.4 陀螺仿真
基于以上讨论, 让我们仿真一个旋转的陀螺, 它在三维空间中表现出刚体的一种非常有趣的行为.
作用在陀螺上的力有 (1) CoM 上的重力
第二个力只在陀螺位于地面上时才起作用. 其垂直分力可以通过弹簧-阻尼系统计算, 水平摩擦力可以通过以下方法计算
其中,
这些力在世界坐标系原点周围产生的力矩
有关计算的更多信息, 请参见第 6.6.1 节.
上述力的产生过程如图 6.12 所示.
图 6.12 TopForce.m: 作用在陀螺上的力和力矩
1
2
3
4
5
6
7
8
9
10
11function [f,t] = TopForce(j)
global uLINK G Kf Df
w_c = uLINK(j).R * uLINK(j).c + uLINK(j).p; % center of mass
f = [0 0 -uLINK(j).m * G]'; % gravity
t = cross(w_c, f); % gravity moment around the origin
if uLINK(j).p(3) < 0.0 % the top is contacting
v = uLINK(j).vo + cross(uLINK(j).w,uLINK(j).p); % contacting speed
fc = [-Df*v(1) -Df*v(2) -Kf*uLINK(j).p(3)-Df*v(3)]';
f = f + fc;
t = t + cross(uLINK(j).p, fc);
end
以适当的初始角速度模拟陀螺在 1G 重力下下落的情况如图 6.13 所示. 我们可以观察到旋转轴上端以圆周运动的形式出现的偏振.
仿真代码如图 6.14 所示. 空间加速度通过 (6.26) 计算, 空间速度通过以下方式更新
图 6.14 仿真旋转陀螺的 Matlab 代码. 它还显示了仿真陀螺的动画效果. 有关 MakeTop 和 ShowObject 子程序, 请参见第 6.6.2 节.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27global uLINK G Kf Df
G = 9.8;
Kf = 1.0E+4; Df = 1.0E+3; % Floor stiffness[N/m] viscosity[N/(m/s)]
r = 0.2; a = 0.05; c = 0.2; % Top radius, thickness, shaft length/2 [m]
MakeTop(1, r,a,c);
uLINK(1).p = [0 0 0.3]'; % Initial position [m]
uLINK(1).R = Rodrigues([1 0 0],pi/50); % Initial posture
uLINK(1).vo = [0 0 0]'; % Initial speed [m/s]
uLINK(1).w = [0 0 50]'; % Initial spin [rad/s]
Dtime = 0.002;
EndTime = 2.0;
time = 0:Dtime:EndTime;
figure
frame_skip = 3;
AX=[-0.2 0.4]; AY=[-0.3 0.3]; AZ=[0 0.8]; % 3D view area
for n = 1:length(time)
[f,tau] = TopForce(1); % External force
[P,L] = SE3dynamics(1,f,tau); % Acceleration
[uLINK.p, uLINK.R] = SE3exp(1, Dtime); % Update configuration
uLINK(1).w = uLINK(1).w + Dtime * uLINK(1).dw; % Update ang. velocity
uLINK(1).vo = uLINK(1).vo + Dtime * uLINK(1).dvo; % Update lin. velocity
if mod(n,frame_skip) == 0
ShowObject; % Show the top
end
end
根据 (6.14) 使用图 6.7 中的程序更新陀螺的位置和朝向. 同时显示计算出的陀螺运动.
6.4 链节系统的动力学
在本节中, 我们将仿人机器人视为由多个刚体组成的链节系统, 对其动力学进行研究. 由于每个刚体的行为如上所述, 我们可以通过对它们进行一致的积分来获得整个系统的动力学特性.
6.4.1 带加速度的正向运动学
首先, 我们研究了由一个关节连接的一对刚体, 它代表了仿人机器人的最小元素.
假设空间中的链节 1 通过旋转接头与链节 2 相连, 如图 6.15 所示. 当链节 1 静止时, 以
在第 6.2 节的空间速度表示法中, 链节 2 的线速度为
其中
由于我们假设链节 1 是静止的, 因此
公式 (6.28) 和 (6.27) 给出了链节 2 相对于链节 1 的相对速度
当链节 1 具有空间速度
下面, 我们使用以下符号来简化方程
其中,
通过求导 (6.30), 我们可以得到空间加速度的传播规则
其中
由于采用了空间速度表示法, 我们可以得到这个简单的方程. 当我们使用参考点的常规速度时, 我们需要更复杂的加速度传播规则[99].
假设我们知道机器人躯干的位置和朝向, 空间速度和空间加速度. 那么, 如果所有关节的角度, 速度和加速度也已知, 我们就可以通过应用 (6.30) 和 (6.31) 计算所有链节的空间速度和空间加速度, 即从躯干向四肢末端计算. 如图 6.16 所示, 使用递归算法可以很容易地进行计算.
图 6.16 计算所有链节的空间速度和加速度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23function ForwardAllKinematics(j)
global uLINK G
if j == 0 return; end
if j ~= 1
mom = uLINK(j).mother;
%% Position and orientation
uLINK(j).p = uLINK(mom).R * uLINK(j).b + uLINK(mom).p;
uLINK(j).R = uLINK(mom).R * Rodrigues(uLINK(j).a, uLINK(j).q);
%% Spatial velocity
sw = uLINK(mom).R * uLINK(j).a; % axis vector in world frame
sv = cross(uLINK(j).p, sw); % p_i x axis
uLINK(j).w = uLINK(mom).w+ sw * uLINK(j).dq;
uLINK(j).vo = uLINK(mom).vo + sv * uLINK(j).dq;
%% Spatial acceleration
dsv = cross(uLINK(mom).w, sv) + cross(uLINK(mom).vo, sw);
dsw = cross(uLINK(mom).w, sw);
uLINK(j).dw = uLINK(mom).dw+ dsw * uLINK(j).dq + sw * uLINK(j).ddq;
uLINK(j).dvo = uLINK(mom).dvo + dsv * uLINK(j).dq + sv * uLINK(j).ddq;
uLINK(j).sw = sw; % store h1 and h2 for future use
uLINK(j).sv = sv;
end
ForwardAllKinematics(uLINK(j).sister); % Propagate to sister
ForwardAllKinematics(uLINK(j).child); % Propagate to child
6.4.2 链节系统的反向动力学
接下来我们考虑作用在每个链节上的力和力矩. 为了做好准备, 让我们用空间速度向量
其中运算符
图 6.17 显示了作用在链节
环境直接作用在链节
通过重写该方程, 我们可以得到一个递推方程, 给出力和力矩的传播情况
当链节
通过图 6.18 中的递归算法实现了对这些方程的编程. 当链节系统有分支时, 该程序可以正常运行.
图 6.18 反向动力学代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24function [f,t] = InverseDynamics(j)
global uLINK
if j == 0
f = [0,0,0]';
t = [0,0,0]';
return;
end
c = uLINK(j).R * uLINK(j).c + uLINK(j).p; % Center of mass
I = uLINK(j).R * uLINK(j).I * uLINK(j).R'; % Inertia tensor
c_hat = hat(c);
I = I + uLINK(j).m * c_hat * c_hat';
P = uLINK(j).m * (uLINK(j).vo + cross(uLINK(j).w,c)); % Momentum
L = uLINK(j).m * cross(c,uLINK(j).vo) + I * uLINK(j).w; % Ang.momentum
f0 = uLINK(j).m * (uLINK(j).dvo + cross(uLINK(j).dw,c)) + cross(uLINK(j).w,P);
t0 = uLINK(j).m * cross(c,uLINK(j).dvo) + I * uLINK(j).dw + cross(uLINK(j).vo,P) + cross(uLINK(j).w,L);
[f1,t1] = InverseDynamics(uLINK(j).child); % Force and moment form child
f = f0 + f1;
t = t0 + t1;
if j ~= 1
uLINK(j).u = uLINK(j).sv' * f + uLINK(j).sw' * t; % Joint torque
end
[f2,t2] = InverseDynamics(uLINK(j).sister); % Force and moment from sister
f = f + f2;
t = t + t2;
本节所示的计算称为反向动力学. 通过前馈反动力学计算出的关节力矩, 我们可以实现快速, 精确的机器人运动. 这种控制技术称为计算力矩法. 不过, 要应用计算力矩法, 第一链节必须固定在地面上, 这样才能产生任意力和力矩. 工业机械臂的情况就是如此.
作为仿人机器人的基础链节, 机器人躯干并不是固定在地面上的, 因此无法保证机器人能够获得所需的力和力矩来保持所需的身体姿态. 如果运动模式不当, 机器人躯干的位置和朝向就会偏离预期. 这可以通过积分躯干加速度来仿真. 这是我们将在下一节讨论的正向动力学仿真的一种特殊变化. 在仿人机器人项目 (HRP) 开发的 OpenHRP 动态仿真器中, 这被称为高增益模式仿真 [31]. 在很多情况下, 这种仿真足以保证计划行走模式的稳定性.
6.4.3 链节系统的正向动力学
图 6.19 显示仿真结果, 其中 HRP-2 的所有关节力矩都设为零, 机器人瘫落到地面上.
仿真时, 机器人会受到来自环境的力和力矩以及自身关节力矩的作用, 从而完成各种运动. 计算机器人在给定关节力矩和外力作用下的运动称为正向动力学. 在本节中, 我们将根据前几节所学的知识, 解释正向动力学的基本计算方法.
一般来说, 由于躯干在三维空间中被视为自由链节, 因此具有
其中,
其中
如果已知
这就是正向动力学的目标.
现在, 让我们定义一个函数
比较 (6.38) 和 (6.40) 可以发现,
接下来, 我们假设有一个
上式左侧表示矩阵
得到
图 6.20 给出了一段 Matlab 代码, 该代码基于单位向量法计算物体的空间加速度和关节加速度. 计算
图 6.20 基于单位向量法的正向动力学
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18nDoF = length(uLINK)-1+6;
A = zeros(nDoF,nDoF);
b = InvDyn(0);
for n = 1:nDoF
A(:,n) = InvDyn(n) - b;
end
% add motor inertia
for n = 7:nDoF
j = n-6+1;
A(n,n) = A(n,n) + uLINK(j).Ir * uLINK(j).gr^2;
end
u = [0 0 0 0 0 0 u_joint(2:end)']';
ddq = A(-b + u);
uLINK(1).dvo = ddq(1:3);
uLINK(1).dw = ddq(4:6);
for j = 1:length(uLINK)-1
uLINK(j+1).ddq = ddq(j+6);
end
虽然单位向量法易于理解和编程, 但当机器人关节数量增加时, 其性能会迅速下降. 第一个问题是惯性矩阵的计算方法. 对于有
第二个也是更本质的问题是求解 (6.39), 这是一个庞大的线性方程组. 虽然已知有 Gauss-Jordan 消元或 LU 分解等高效算法 [136], 但其耗时总是与
6.4.4 Featherstone 方法
假设如图 6.21 所示, 有两个链节通过一个漂浮在三维空间中的旋转接头相连. 假定我们已经知道链节 1 的空间加速度, 我们希望推导出给定力矩
根据加速度, 我们可以利用运动方程计算出必要的力和力矩.
此外, 关节力矩
将 (6.43) 和 (6.44) 代入该方程, 我们就可以求解出关节加速度了
根据这一方程, 我们可以立即计算出给定关节力矩
但是, 只有当链节 2 是最外层链节时, 我们才能使用 (6.46). 如果从链节 2 开始有额外的链节, 如图 6.22 所示, (6.44) 将不再有效.
使用 (6.46) 的一种方法是引入一个新的惯性张量
Featherstone 指出, 铰接体的惯性可以通过递推方程计算得出
偏置力也可以用类似的公式计算.
假设我们已经计算了铰接体惯性和所有链节的偏置力. 将 (6.47) 和 (6.43) 代入 (6.45), 我们得到
即用给定的关节力矩直接计算关节加速度的方程. 这就是 Featherstone 理论的核心.
总之, 正向动力学的计算可通过以下三个步骤进行.
- 计算从主体链节到外部链节的所有链节的位置, 朝向和空间速度 (正向运动学) .
- 计算铰接体惯性和从最外侧链节到主体链节的所有链节的偏置力.
- 根据 (6.49) 计算关节加速度, 根据 (6.43) 计算从躯干链节到外部链节的链节空间加速度.
由于每一步所需的时间与关节数
6.5 本节的背景材料
17 至 18 世纪, 牛顿, 欧拉和其他科学家建立了物体运动的基本理论. 然而, 这并不是研究的终点.
事实上, 大约二十年前, 一位本科生试图仿真一个具有十二自由度的双足机器人, 于是他开始手工计算运动方程. 他花了整整一个暑假的时间, 用了整整一个笔记本来记下计算出的方程. 当时, 有一些商业仿真软件可以处理复杂的机械系统, 但这些软件非常昂贵, 而且专门用于称为工程工作站的计算机, 其价格令人望而却步. 此外, 即使使用这样的软件, 仿真一个简单的双足机器人走几步路也需要几个小时!
本章介绍的高效, 优雅的动态计算方法极大地改变了这种状况. 这些算法是由机器人和航空工程研究人员在 20 世纪 80 年代和 90 年代开发的. 目前, 最先进的技术可以实现实时动力学仿真. 此外, 研究人员仍在努力改进, 他们最近提出了基于并行计算的
6.6 附录
6.6.1 力和力矩的处理
在本节中, 所有运动方程都在世界坐标系中表示, 因此力和力矩必须相对于世界坐标系来书写. 例如, 即使是作用在物体运动中心点上的重力, 我们也必须考虑它绕世界坐标系原点的力矩. 虽然这看起来很复杂, 但我们可以正确计算多刚体之间的相互作用.
将力和力矩转换到世界坐标系的基本规则如下.
- 规则 1: 作用在点
上的力 相对于世界坐标系转换为力 和力矩 (图 6.23(a)) . - 规则 2: 作用在点
上的力矩 与相对于世界坐标系的 是相同的 (图 6.23(b)) .
一般来说, 当力
我们可能会认为它们是显而易见的, 但我们往往会在这类计算中犯一个奇怪的错误. 图 6.24 所示的测验可能有助于理解这个问题.
6.6.2 子程序
图 6.25 ShowObject.m: 显示对象的动画
1
2
3
4
5
6
7
8
9vert = uLINK(1).R * uLINK(1).vertex; % rotation
for k = 1:3
vert(k,:) = vert(k,:) + uLINK(1).p(k); % translation
end
newplot
h = patch('faces',uLINK(1).face','vertices',vert','FaceColor',[0.5 0.5 0.5]);
axis equal; view(3); grid on; xlim(AX); ylim(AY); zlim(AZ);
text(0.25, -0.25, 0.8, ['time=',num2str(time(n),'%5.3f')])
drawnow图 6.26 MakeRigidBody.m: 设置刚体及其参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20function MakeRigidBody(j, wdh, mass)
global uLINK
uLINK(j).m = mass; % mass
uLINK(j).c = [0 0 0]'; % center of mass
uLINK(j).I = [ 1/12*(wdh(2)^2 + wdh(3)^2) 0 0;
0 1/12*(wdh(1)^2 + wdh(3)^2)0;
0 0 1/12*(wdh(1)^2 + wdh(2)^2)] * uLINK.m; % inertia tensor
uLINK(j).vertex = 0.5*[
-wdh(1) -wdh(2) -wdh(3);
-wdh(1) wdh(2) -wdh(3);
wdh(1) wdh(2) -wdh(3);
wdh(1) -wdh(2) -wdh(3);
-wdh(1) -wdh(2) wdh(3);
-wdh(1) wdh(2) wdh(3);
wdh(1) wdh(2) wdh(3);
wdh(1) -wdh(2) wdh(3);
]'; % vertex points
uLINK(1).face = [
1 2 3 4; 2 6 7 3; 4 3 7 8; 1 5 8 4; 1 2 6 5; 5 6 7 8;
]'; % polygons图 6.27 MakeTop.m: 设置陀螺及其参数
1
2
3
4
5
6
7
8
9
10
11
12
13function MakeTop(j, r,a,c)
global uLINK
[vertex1,face1] = MakeZcylinder([0 0 c]',r,a); % shape of disk
[vertex2,face2] = MakeZcylinder([0 0 c]',0.01,2*c); % shape of shaft
uLINK(j).vertex = [vertex1 vertex2];
face2 = face2 + size(vertex1,2);
uLINK(j).face = [face1 face2];
density = 2.7E+3; % density of aluminum [kg/m^2]
uLINK(j).m = pi*r^2*a*density; % mass of the disk [kg]
uLINK(j).I = [ (a^2 + 3*r^2)/12 0 0;
0 (a^2 + 3*r^2)/120;
0 0 r^2/2] * uLINK.m; % inertia tensor of the disk
uLINK(j).c = [0 0 c]'; % center of mass图 6.28 MakeZcylinder.m: 创建圆柱体形状
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19function [vert,face] = MakeZcylinder(pos, radius,len)
a = 10; % regular polygon for circle
theta = (0:a-1)/a * 2*pi;
x = radius*cos(theta);
y = radius*sin(theta);
z1 = len/2 * ones(1,a);
z2 = -z1;
vert= [x x 0 0;
y y 0 0;
z1 z2 len/2 -len/2]; % vertices
for n = 1:3
vert(n,:) = vert(n,:) + pos(n);
end
face_side = [1:a; a+1:2*a; a+2:2*a a+1; 2:a 1];
face_up = [1:a; 2:a 1];
face_up(3:4,:) = 2*a+1; % index of up center
face_down = [a+2:2*a a+1; a+1:2*a];
face_down(3:4,:) = 2*a+2; % index of down center
face = [face_side face_up face_down];图 6.29 InvDyn.m: 用单位向量法进行反向动力学计算
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19function ret = InvDyn(j)
global uLINK
uLINK(1).dvo = [0 0 0]';
uLINK(1).dw = [0 0 0]';
if j >= 1 & j <= 3
uLINK(1).dvo(j) = 1;
elseif j >= 4 & j <= 6
uLINK(1).dw(j-3) = 1;
end
for n = 1:length(uLINK)-1
if n == j-6
uLINK(n+1).ddq = 1;
else
uLINK(n+1).ddq = 0;
end
end
ForwardAllKinematics(1);
[f,tau] = InverseDynamics(1);
ret = [f',tau',uLINK(2:end).u]';