Skip to content

Commit 203c833

Browse files
authored
Merge pull request #56 from dqrobotics/updating_to_20_04
Adding DQ_SerialManipulatorDH
2 parents 5c4fc94 + 004fad6 commit 203c833

7 files changed

+265
-11
lines changed

@DQ/mtimes.m

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
% Bruno Vihena Adorno - [email protected]
2626

2727
function res = mtimes(a,b)
28-
if ~isa(a,'DQ');
28+
if ~isa(a,'DQ')
2929
a = DQ(a);
3030
end
31-
if ~isa(b,'DQ');
31+
if ~isa(b,'DQ')
3232
b = DQ(b);
3333
end
3434
primary = QuaternionMultiplication(a.q(1:4),b.q(1:4));

robot_modeling/DQ_SerialManipulator.m

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
end
7070

7171
methods
72-
function obj = DQ_SerialManipulator(A,type)
72+
function obj = DQ_SerialManipulator(A,convention)
7373
if nargin == 0
7474
error('Input: matrix whose columns contain the DH parameters')
7575
end
@@ -90,7 +90,7 @@
9090
if nargin==1
9191
obj.convention='standard';
9292
else
93-
obj.convention=type;
93+
obj.convention=convention;
9494
end
9595

9696
%For visualisation
+246
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
% Concrete class that extends the DQ_SerialManipulator using the
2+
% Denavit-Hartenberg parameters (DH)
3+
%
4+
% Usage: robot = DQ_SerialManipulatorDH(A)
5+
% - 'A' is a 4 x n matrix containing the Denavit-Hartenberg parameters
6+
% (n is the number of links)
7+
% A = [theta1 ... thetan;
8+
% d1 ... dn;
9+
% a1 ... an;
10+
% alpha1 ... alphan;
11+
% type1 ... typen]
12+
% where type is the actuation type, either DQ_SerialManipulatorDH.JOINT_ROTATIONAL
13+
% or DQ_SerialManipulatorDH.JOINT_PRISMATIC
14+
% - The only accepted convention in this subclass is the 'standard' DH
15+
% convention.
16+
%
17+
% If the joint is of type JOINT_ROTATIONAL, then the first row of A will
18+
% have the joint offsets. If the joint is of type JOINT_PRISMATIC, then the
19+
% second row of A will have the joints offsets.
20+
%
21+
% DQ_SerialManipulatorDH Methods (Concrete):
22+
% get_dim_configuration_space - Return the dimension of the configuration space.
23+
% fkm - Compute the forward kinematics while taking into account base and end-effector's rigid transformations.
24+
% plot - Plots the serial manipulator.
25+
% pose_jacobian - Compute the pose Jacobian while taking into account base's and end-effector's rigid transformations.
26+
% pose_jacobian_derivative - Compute the time derivative of the pose Jacobian.
27+
% raw_fkm - Compute the FKM without taking into account base's and end-effector's rigid transformations.
28+
% raw_pose_jacobian - Compute the pose Jacobian without taking into account base's and end-effector's rigid transformations.
29+
% set_effector - Set an arbitrary end-effector rigid transformation with respect to the last frame in the kinematic chain.
30+
% See also DQ_SerialManipulator.
31+
32+
% (C) Copyright 2020 DQ Robotics Developers
33+
%
34+
% This file is part of DQ Robotics.
35+
%
36+
% DQ Robotics is free software: you can redistribute it and/or modify
37+
% it under the terms of the GNU Lesser General Public License as published
38+
% by the Free Software Foundation, either version 3 of the License, or
39+
% (at your option) any later version.
40+
%
41+
% DQ Robotics is distributed in the hope that it will be useful,
42+
% but WITHOUT ANY WARRANTY; without even the implied warranty of
43+
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44+
% GNU Lesser General Public License for more details.
45+
%
46+
% You should have received a copy of the GNU Lesser General Public License
47+
% along with DQ Robotics. If not, see <http://www.gnu.org/licenses/>.
48+
%
49+
% DQ Robotics website: dqrobotics.github.io
50+
%
51+
% Contributors to this file:
52+
% Murilo M. Marinho - [email protected]
53+
54+
classdef DQ_SerialManipulatorDH < DQ_SerialManipulator
55+
properties
56+
type
57+
end
58+
59+
properties (Constant)
60+
% Joints that can be actuated
61+
% Rotational joint
62+
JOINT_ROTATIONAL = 1;
63+
% Prismatic joint
64+
JOINT_PRISMATIC = 2;
65+
end
66+
67+
methods
68+
function obj = DQ_SerialManipulatorDH(A,convention)
69+
% These are initialized in the constructor of
70+
% DQ_SerialManipulator
71+
%obj.convention = convention;
72+
%obj.n_links = size(A,2);
73+
%obj.theta = A(1,:);
74+
%obj.d = A(2,:);
75+
%obj.a = A(3,:);
76+
%obj.alpha = A(4,:);
77+
obj = obj@DQ_SerialManipulator(A(1:4,:),convention);
78+
79+
if nargin == 0
80+
error('Input: matrix whose columns contain the DH parameters')
81+
end
82+
83+
if(size(A,1) ~= 5)
84+
error('Input: Invalid DH matrix. It should have 5 rows.')
85+
end
86+
87+
% Add type
88+
obj.type = A(5,:);
89+
end
90+
91+
function x = raw_fkm(obj,q,to_ith_link)
92+
% RAW_FKM(q) calculates the forward kinematic model and
93+
% returns the dual quaternion corresponding to the
94+
% last joint (the displacements due to the base and the effector
95+
% are not taken into account).
96+
%
97+
% 'q' is the vector of joint variables
98+
% 'to_ith_link' defines until which link the raw_fkm will be
99+
% calculated.
100+
%
101+
% This is an auxiliary function to be used mainly with the
102+
% Jacobian function.
103+
if nargin == 3
104+
n = to_ith_link;
105+
else
106+
n = obj.n_links;
107+
end
108+
109+
x = DQ(1);
110+
111+
for i=1:n
112+
x = x*dh2dq(obj,q(i),i);
113+
end
114+
end
115+
116+
function x = fkm(obj,q,to_ith_link)
117+
% FKM(q) calculates the forward kinematic model and
118+
% returns the dual quaternion corresponding to the
119+
% end-effector pose. This function takes into account the
120+
% displacement due to the base's and effector's poses.
121+
%
122+
% 'q' is the vector of joint variables
123+
% 'to_ith_link' defines up to which link the fkm will be
124+
% calculated. If to_ith_link corresponds to the last link,
125+
% the method DOES NOT take into account the transformation
126+
% given by set_effector. If you want to take into account
127+
% that transformation, use FKM(q) instead.
128+
129+
if nargin == 3
130+
x = obj.reference_frame*obj.raw_fkm(q, to_ith_link); %Takes into account the base displacement
131+
else
132+
x = obj.reference_frame*obj.raw_fkm(q)*obj.effector;
133+
end
134+
end
135+
136+
function dq = dh2dq(obj,q,ith)
137+
% For a given link's Extended DH parameters, calculate the correspondent dual
138+
% quaternion
139+
% Usage: dq = dh2dq(q,ith), where
140+
% q: joint value
141+
% ith: link number
142+
143+
if nargin ~= 3
144+
error('Wrong number of arguments. The parameters are joint value and the correspondent link')
145+
end
146+
147+
%The unoptimized standard dh2dq calculation is commented below
148+
%if obj.type(ith) == obj.JOINT_ROTATIONAL
149+
% % If joint is rotational
150+
% h1 = cos((obj.theta(ith)+q)/2.0)+DQ.k*sin((obj.theta(ith)+q)/2.0);
151+
% h2 = 1 + DQ.E*0.5*obj.d(ith)*DQ.k;
152+
%else
153+
% % If joint is prismatic
154+
% h1 = cos(obj.theta(ith)/2.0)+DQ.k*sin(obj.theta(ith)/2.0);
155+
% h2 = 1 + DQ.E*0.5*(obj.d(ith)+q)*DQ.k;
156+
%end
157+
%h3 = 1 + DQ.E*0.5*obj.a(ith)*DQ.i;
158+
%h4 = cos(obj.alpha(ith)/2.0)+DQ.i*sin(obj.alpha(ith)/2.0);
159+
%dq = h1*h2*h3*h4;
160+
161+
% The optimized standard dh2dq calculation
162+
% Store half angles and displacements
163+
half_theta = obj.theta(ith)/2.0;
164+
d = obj.d(ith);
165+
a = obj.a(ith);
166+
half_alpha = obj.alpha(ith)/2.0;
167+
168+
% Add the effect of the joint value
169+
if obj.type(ith) == obj.JOINT_ROTATIONAL
170+
% If joint is rotational
171+
half_theta = half_theta + (q/2.0);
172+
else
173+
% If joint is prismatic
174+
d = d + q;
175+
end
176+
177+
% Pre-calculate cosines and sines
178+
sine_of_half_theta = sin(half_theta);
179+
cosine_of_half_theta = cos(half_theta);
180+
sine_of_half_alpha = sin(half_alpha);
181+
cosine_of_half_alpha = cos(half_alpha);
182+
183+
% Return the optimized standard dh2dq calculation
184+
dq = DQ([
185+
cosine_of_half_alpha*cosine_of_half_theta
186+
187+
sine_of_half_alpha*cosine_of_half_theta
188+
189+
sine_of_half_alpha*sine_of_half_theta
190+
191+
cosine_of_half_alpha*sine_of_half_theta
192+
193+
-(a*sine_of_half_alpha*cosine_of_half_theta) /2.0...
194+
- (d*cosine_of_half_alpha*sine_of_half_theta)/2.0
195+
196+
(a*cosine_of_half_alpha*cosine_of_half_theta)/2.0...
197+
- (d*sine_of_half_alpha*sine_of_half_theta )/2.0
198+
199+
(a*cosine_of_half_alpha*sine_of_half_theta) /2.0...
200+
+ (d*sine_of_half_alpha*cosine_of_half_theta)/2.0
201+
202+
(d*cosine_of_half_alpha*cosine_of_half_theta)/2.0...
203+
- (a*sine_of_half_alpha*sine_of_half_theta )/2.0
204+
]);
205+
end
206+
207+
function w = get_w(obj,ith)
208+
if obj.type(ith) == obj.JOINT_ROTATIONAL
209+
w = DQ.k;
210+
else
211+
w = DQ.E*DQ.k;
212+
end
213+
end
214+
215+
function J = raw_pose_jacobian(obj,q,to_ith_link)
216+
% RAW_POSE_JACOBIAN(q) returns the Jacobian that satisfies
217+
% vec(x_dot) = J * q_dot, where x = fkm(q) and q is the
218+
% vector of joint variables.
219+
%
220+
% RAW_POSE_JACOBIAN(q,ith) returns the Jacobian that
221+
% satisfies vec(x_ith_dot) = J * q_dot(1:ith), where
222+
% x_ith = fkm(q, ith), that is, the fkm up to the i-th link.
223+
%
224+
% This function does not take into account any base or
225+
% end-effector displacements and should be used mostly
226+
% internally in DQ_kinematics
227+
228+
if nargin < 3
229+
to_ith_link = obj.n_links;
230+
end
231+
x_effector = obj.raw_fkm(q,to_ith_link);
232+
233+
x = DQ(1);
234+
J = zeros(8,to_ith_link);
235+
236+
for i = 0:to_ith_link-1
237+
w = obj.get_w(i+1);
238+
z = 0.5*Ad(x,w);
239+
x = x*obj.dh2dq(q(i+1),i+1);
240+
j = z * x_effector;
241+
J(:,i+1) = vec8(j);
242+
end
243+
end
244+
245+
end
246+
end

robots/Ax18ManipulatorRobot.m

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,16 @@
2828
ax18_DH_d = [0.167 0 0 0.1225 0]; % d
2929
ax18_DH_a = [0 0.159 0.02225 0 0.170]; % a
3030
ax18_DH_alpha = [-pi/2 0 -pi/2 -pi/2 0]; % alpha
31+
ax18_DH_type = repmat(DQ_SerialManipulatorDH.JOINT_ROTATIONAL,1,5);
3132

3233
ax18_DH_matrix = [ ax18_DH_theta;
3334
ax18_DH_d;
3435
ax18_DH_a;
3536
ax18_DH_alpha;
37+
ax18_DH_type;
3638
]; % D&H parameters matrix for the arm model
3739

38-
ax = DQ_SerialManipulator(ax18_DH_matrix,'standard'); % Defines robot model using dual quaternions
40+
ax = DQ_SerialManipulatorDH(ax18_DH_matrix,'standard'); % Defines robot model using dual quaternions
3941
end
4042
end
4143
end

robots/BarrettWamArmRobot.m

+4-2
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@
2929
wam_DH_d = [0, 0, 0.55, 0, 0.3, 0, 0.0609];
3030
wam_DH_a = [0, 0, 0.045, -0.045, 0, 0, 0];
3131
wam_DH_alpha = pi*[-0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0];
32+
wam_DH_type = repmat(DQ_SerialManipulatorDH.JOINT_ROTATIONAL,1,7);
3233
wam_DH_matrix = [wam_DH_theta;
3334
wam_DH_d;
3435
wam_DH_a;
35-
wam_DH_alpha];
36+
wam_DH_alpha;
37+
wam_DH_type];
3638

37-
wam = DQ_SerialManipulator(wam_DH_matrix,'standard');
39+
wam = DQ_SerialManipulatorDH(wam_DH_matrix,'standard');
3840
end
3941
end
4042
end

robots/KukaLwr4Robot.m

+4-2
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@
3232
kuka_DH_d = [0.310, 0, 0.4, 0, 0.39, 0, 0];
3333
kuka_DH_a = [0, 0, 0, 0, 0, 0, 0];
3434
kuka_DH_alpha = [pi/2, -pi/2, -pi/2, pi/2, pi/2, -pi/2, 0];
35+
kuka_DH_type = repmat(DQ_SerialManipulatorDH.JOINT_ROTATIONAL,1,7);
3536
kuka_DH_matrix = [kuka_DH_theta;
3637
kuka_DH_d;
3738
kuka_DH_a;
38-
kuka_DH_alpha];
39+
kuka_DH_alpha;
40+
kuka_DH_type];
3941

40-
ret = DQ_SerialManipulator(kuka_DH_matrix,'standard');
42+
ret = DQ_SerialManipulatorDH(kuka_DH_matrix,'standard');
4143
end
4244
end
4345
end

robots/KukaYoubot.m

+4-2
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,14 @@
4040
arm_DH_d = [ 0.147, 0, 0, 0, 0.218];
4141
arm_DH_a = [ 0, 0.155, 0.135, 0, 0];
4242
arm_DH_alpha = [pi2, 0, 0, pi2, 0];
43+
arm_DH_type = repmat(DQ_SerialManipulatorDH.JOINT_ROTATIONAL,1,5);
4344
arm_DH_matrix = [arm_DH_theta;
4445
arm_DH_d;
4546
arm_DH_a;
46-
arm_DH_alpha];
47+
arm_DH_alpha;
48+
arm_DH_type];
4749

48-
arm = DQ_SerialManipulator(arm_DH_matrix,'standard');
50+
arm = DQ_SerialManipulatorDH(arm_DH_matrix,'standard');
4951
base = DQ_HolonomicBase();
5052

5153
include_namespace_dq

0 commit comments

Comments
 (0)