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
0 commit comments