|
a |
|
b/URBasic/kinematic.py |
|
|
1 |
''' |
|
|
2 |
Python 3.x library to control an UR robot through its TCP/IP interfaces |
|
|
3 |
Copyright (C) 2017 Martin Huus Bjerge, Rope Robotics ApS, Denmark |
|
|
4 |
|
|
|
5 |
Permission is hereby granted, free of charge, to any person obtaining a copy of this software |
|
|
6 |
and associated documentation files (the "Software"), to deal in the Software without restriction, |
|
|
7 |
including without limitation the rights to use, copy, modify, merge, publish, distribute, |
|
|
8 |
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software |
|
|
9 |
is furnished to do so, subject to the following conditions: |
|
|
10 |
|
|
|
11 |
The above copyright notice and this permission notice shall be included in all copies |
|
|
12 |
or substantial portions of the Software. |
|
|
13 |
|
|
|
14 |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
|
|
15 |
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|
|
16 |
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL "Rope Robotics ApS" BE LIABLE FOR ANY CLAIM, |
|
|
17 |
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
|
18 |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
19 |
|
|
|
20 |
Except as contained in this notice, the name of "Rope Robotics ApS" shall not be used |
|
|
21 |
in advertising or otherwise to promote the sale, use or other dealings in this Software |
|
|
22 |
without prior written authorization from "Rope Robotics ApS". |
|
|
23 |
''' |
|
|
24 |
__author__ = "Martin Huus Bjerge" |
|
|
25 |
__copyright__ = "Copyright 2017, Rope Robotics ApS, Denmark" |
|
|
26 |
__license__ = "MIT License" |
|
|
27 |
|
|
|
28 |
import ikpy as ik |
|
|
29 |
import numpy as np |
|
|
30 |
import sympy as sp |
|
|
31 |
import math |
|
|
32 |
import scipy |
|
|
33 |
from scipy import linalg |
|
|
34 |
from URBasic.manipulation import * |
|
|
35 |
|
|
|
36 |
pi = np.pi |
|
|
37 |
|
|
|
38 |
|
|
|
39 |
# Disable the logging stream from ikpy |
|
|
40 |
# ik.logs.manager.removeHandler(ik.logs.stream_handler) |
|
|
41 |
|
|
|
42 |
|
|
|
43 |
def Forwardkin_manip(joints, rob='ur10'): |
|
|
44 |
''' |
|
|
45 |
This function solves forward kinematics, it returns pose vector |
|
|
46 |
''' |
|
|
47 |
M, Slist = Robot_parameter_screw_axes(rob) |
|
|
48 |
thetalist = joints |
|
|
49 |
fk = FKinFixed(M, Slist, thetalist) |
|
|
50 |
return np.round(Tran_Mat2Pose(Tran_Mat=fk), 4) |
|
|
51 |
|
|
|
52 |
|
|
|
53 |
def Invkine_manip(target_pos, init_joint_pos=[0, 0, 0, 0, 0, 0], rob='ur10', tcpOffset=[0, 0, 0, 0, 0, 0]): |
|
|
54 |
''' |
|
|
55 |
A numerical inverse kinematics routine based on Newton-Raphson method. |
|
|
56 |
Takes a list of fixed screw axes (Slist) expressed in end-effector body frame, the end-effector zero |
|
|
57 |
configuration (M), the desired end-effector configuration (T_sd), an initial guess of joint angles |
|
|
58 |
(thetalist_init), and small positive scalar thresholds (wthresh, vthresh) controlling how close the |
|
|
59 |
final solution thetas must be to the desired thetas. |
|
|
60 |
''' |
|
|
61 |
M, Slist = Robot_parameter_screw_axes(rob) |
|
|
62 |
wthresh = 0.001 |
|
|
63 |
vthresh = 0.0001 |
|
|
64 |
# T_sd = Pose2Tran_Mat(pose=target_pos) |
|
|
65 |
T_target = Pose2Tran_Mat(pose=target_pos) |
|
|
66 |
T_tcp = Pose2Tran_Mat(pose=tcpOffset) |
|
|
67 |
T_sd = np.matmul(T_target, np.linalg.inv(T_tcp)) |
|
|
68 |
thetalist_init = init_joint_pos |
|
|
69 |
|
|
|
70 |
ik_init = np.round(IKinFixed(Slist, M, T_sd, thetalist_init, wthresh, vthresh), 3) |
|
|
71 |
ik = ik_init[-1][:] # choose the closest solution |
|
|
72 |
|
|
|
73 |
error = [] |
|
|
74 |
for kk in ik_init: |
|
|
75 |
out = [] |
|
|
76 |
for ii in range(6): |
|
|
77 |
k = np.round((kk[ii] - init_joint_pos[ii]) / 2 / np.pi) |
|
|
78 |
out.append(kk[ii] - k * 2 * np.pi) |
|
|
79 |
# change them to numpy array for np.sum operation |
|
|
80 |
init_joint_pos = np.array(init_joint_pos) |
|
|
81 |
out = np.array(out) |
|
|
82 |
error.append(np.abs(np.sum(init_joint_pos - out))) |
|
|
83 |
|
|
|
84 |
ix = error == np.min(error) |
|
|
85 |
ix = np.where(ix == True)[0][0] |
|
|
86 |
ik = ik_init[ix][:] # choose the closest solution |
|
|
87 |
|
|
|
88 |
out = [] |
|
|
89 |
for ii in range(6): |
|
|
90 |
k = np.round((ik[ii] - init_joint_pos[ii]) / 2 / np.pi) |
|
|
91 |
out.append(ik[ii] - k * 2 * np.pi) |
|
|
92 |
|
|
|
93 |
# error = (pi+ik-init_joint_pos)%(2*pi)-pi |
|
|
94 |
|
|
|
95 |
# print('***************************************************************************') |
|
|
96 |
# print('Pose : [{: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}]'.format(*target_pos)) |
|
|
97 |
# print('Init q: [{: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}]'.format(*init_joint_pos)) |
|
|
98 |
# print('---------------------------------------------------------------------------') |
|
|
99 |
# print(ik_init) |
|
|
100 |
# print('---------------------------------------------------------------------------') |
|
|
101 |
# # print(error) |
|
|
102 |
# # print('---------------------------------------------------------------------------') |
|
|
103 |
# print('Joints Candidate: [{: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}]'.format(*ik)) |
|
|
104 |
# print('Joints Returned: [{: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}]'.format(*out)) #init_joint_pos+error)) |
|
|
105 |
# print('***************************************************************************') |
|
|
106 |
|
|
|
107 |
return out |
|
|
108 |
# return init_joint_pos+error |
|
|
109 |
|
|
|
110 |
|
|
|
111 |
def rotate_tcp(gradient_vec=[0, 0, 0]): |
|
|
112 |
''' |
|
|
113 |
Convert gradient vector to axis angle vector |
|
|
114 |
|
|
|
115 |
Parameters: |
|
|
116 |
gradient_vec (3D float): [dx, dy, dz] displacement in x, y, z |
|
|
117 |
|
|
|
118 |
Return value: |
|
|
119 |
axis vector (3D float): [rx, ry, rz] |
|
|
120 |
|
|
|
121 |
Exampel: |
|
|
122 |
Rotate 5deg around x axis and 10 deg around y axis |
|
|
123 |
dz = 0.2 |
|
|
124 |
dy = np.tan(10/180*np.pi)*dz |
|
|
125 |
dx = np.tan(5/180*np.pi)*dz |
|
|
126 |
|
|
|
127 |
r = rotate_tcp(gradient_vec=[dx,dy,dz]) |
|
|
128 |
''' |
|
|
129 |
|
|
|
130 |
v_0 = [0, 0, 1] # this is the UR zero degree angle in the base frame |
|
|
131 |
v_in_u = gradient_vec / np.linalg.norm(gradient_vec) |
|
|
132 |
|
|
|
133 |
v1_u = v_in_u / np.linalg.norm(v_in_u) |
|
|
134 |
v2_u = v_0 / np.linalg.norm(v_0) |
|
|
135 |
rot_angle = np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0)) |
|
|
136 |
|
|
|
137 |
min_angle = 0.01 |
|
|
138 |
|
|
|
139 |
if rot_angle < min_angle: |
|
|
140 |
rotation_vec = [0, 0, 0] |
|
|
141 |
elif rot_angle > np.pi - min_angle: |
|
|
142 |
rotation_vec = [0, -np.pi, 0] |
|
|
143 |
else: |
|
|
144 |
vec_norm = np.cross(v_0, v_in_u) |
|
|
145 |
vec_norm = vec_norm / np.linalg.norm(vec_norm) |
|
|
146 |
rotation_vec = vec_norm * rot_angle |
|
|
147 |
|
|
|
148 |
return rotation_vec |
|
|
149 |
|
|
|
150 |
|
|
|
151 |
def Robot_parameter_screw_axes(rob='ur10'): |
|
|
152 |
''' |
|
|
153 |
This function defines robot with fixed screw axes(used in manipulation.py) |
|
|
154 |
rob='ur5' : ur5 |
|
|
155 |
rob='ur10' : ur10 |
|
|
156 |
rob='ur3e' : ur3e |
|
|
157 |
https://www.universal-robots.com/how-tos-and-faqs/faq/ur-faq/actual-center-of-mass-for-robot-17264/ |
|
|
158 |
''' |
|
|
159 |
if str(rob).lower() == 'ur5': |
|
|
160 |
M_ur5 = [[1, 0, 0, -.81725], [0, 0, -1, -.19145], [0, 1, 0, -.0055], [0, 0, 0, 1]] |
|
|
161 |
S1_ur5 = [0, 0, 1, 0, 0, 0] |
|
|
162 |
S2_ur5 = [0, -1, 0, .089159, 0, 0] |
|
|
163 |
S3_ur5 = [0, -1, 0, .089159, 0, .425] |
|
|
164 |
S4_ur5 = [0, -1, 0, .089159, 0, .81725] |
|
|
165 |
S5_ur5 = [0, 0, -1, .10915, -.81725, 0] |
|
|
166 |
S6_ur5 = [0, -1, 0, -.0055, 0, .81725] |
|
|
167 |
Slist_ur5 = [S1_ur5, S2_ur5, S3_ur5, S4_ur5, S5_ur5, S6_ur5] |
|
|
168 |
return M_ur5, Slist_ur5 |
|
|
169 |
elif str(rob).lower() == 'ur10': |
|
|
170 |
M_ur10 = [[1, 0, 0, -1.1843], [0, 0, -1, -0.2561], [0, 1, 0, 0.0116], [0, 0, 0, 1]] |
|
|
171 |
S1_ur10 = [0, 0, 1, 0, 0, 0] |
|
|
172 |
S2_ur10 = [0, -1, 0, .1273, 0, 0] |
|
|
173 |
S3_ur10 = [0, -1, 0, .1273, 0, .612] |
|
|
174 |
S4_ur10 = [0, -1, 0, .1273, 0, 1.1843] |
|
|
175 |
S5_ur10 = [0, 0, -1, .16394, -1.1843, 0] |
|
|
176 |
S6_ur10 = [0, -1, 0, 0.01165, 0, 1.1843] |
|
|
177 |
Slist_ur10 = [S1_ur10, S2_ur10, S3_ur10, S4_ur10, S5_ur10, S6_ur10] |
|
|
178 |
return M_ur10, Slist_ur10 |
|
|
179 |
elif str(rob).lower() == 'ur3e': |
|
|
180 |
M_ur3e = [[1, 0, 0, -0.45675], [0, 0, -1, -0.22315], [0, 1, 0, 0.06650], [0, 0, 0, 1]] |
|
|
181 |
S1_ur3e = [0, 0, 1, 0, 0, 0] |
|
|
182 |
S2_ur3e = [0, -1, 0, .15185, 0, 0] |
|
|
183 |
S3_ur3e = [0, -1, 0, .15185, 0, .24355] |
|
|
184 |
S4_ur3e = [0, -1, 0, .15185, 0, 0.45675] |
|
|
185 |
S5_ur3e = [0, 0, -1, .13105, -0.45675, 0] |
|
|
186 |
S6_ur3e = [0, -1, 0, 0.06655, 0, 0.45675] |
|
|
187 |
Slist_ur3e = [S1_ur3e, S2_ur3e, S3_ur3e, S4_ur3e, S5_ur3e, S6_ur3e] |
|
|
188 |
return M_ur3e, Slist_ur3e |
|
|
189 |
else: |
|
|
190 |
print('Wrong robot selected') |
|
|
191 |
return False |
|
|
192 |
|
|
|
193 |
|
|
|
194 |
def Robot_DH_Numerical(rob='ur10', joint=[0, 0, 0, 0, 0, 0]): |
|
|
195 |
''' |
|
|
196 |
This function returns the DH parameter of a robot |
|
|
197 |
rob='ur5' : ur5 |
|
|
198 |
rob='ur10' : ur10 |
|
|
199 |
joint: the robot joint vectors |
|
|
200 |
''' |
|
|
201 |
j = joint |
|
|
202 |
if str(rob).lower() == 'ur5': |
|
|
203 |
dh_ur = np.matrix([ |
|
|
204 |
[0, pi / 2, 0.089159, j[0]], |
|
|
205 |
[-0.425, 0, 0, j[1]], |
|
|
206 |
[-0.39225, 0, 0, j[2]], |
|
|
207 |
[0, pi / 2, 0.10915, j[3]], |
|
|
208 |
[0, -pi / 2, 0.09465, j[4]], |
|
|
209 |
[0, 0, 0.0823, j[5]]]) |
|
|
210 |
return dh_ur |
|
|
211 |
elif str(rob).lower() == 'ur10': |
|
|
212 |
dh_ur = np.matrix([ |
|
|
213 |
[0, pi / 2, 0.1273, j[0]], |
|
|
214 |
[-0.612, 0, 0, j[1]], |
|
|
215 |
[-0.5723, 0, 0, j[2]], |
|
|
216 |
[0, pi / 2, 0.163941, j[3]], |
|
|
217 |
[0, -pi / 2, 0.1157, j[4]], |
|
|
218 |
[0, 0, 0.0922, j[5]]]) |
|
|
219 |
return dh_ur |
|
|
220 |
else: |
|
|
221 |
print('Wrong robot selected') |
|
|
222 |
return |
|
|
223 |
|
|
|
224 |
|
|
|
225 |
def Robot_DH_Symbol(rob='ur10'): |
|
|
226 |
''' |
|
|
227 |
This function returns the DH parameter of a robot |
|
|
228 |
rob='ur5' : ur5 |
|
|
229 |
rob='ur10' : ur10 |
|
|
230 |
''' |
|
|
231 |
# set up our joint angle symbols (6th angle doesn't affect any kinematics) |
|
|
232 |
q = [sp.Symbol('q%i' % ii) for ii in range(6)] |
|
|
233 |
if str(rob).lower() == 'ur5': |
|
|
234 |
dh_ur = np.matrix([ |
|
|
235 |
[0, pi / 2, 0.089159, q[0]], |
|
|
236 |
[-0.425, 0, 0, q[1]], |
|
|
237 |
[-0.39225, 0, 0, q[2]], |
|
|
238 |
[0, pi / 2, 0.10915, q[3]], |
|
|
239 |
[0, -pi / 2, 0.09465, q[4]], |
|
|
240 |
[0, 0, 0.0823, q[5]]]) |
|
|
241 |
return dh_ur |
|
|
242 |
elif str(rob).lower() == 'ur10': |
|
|
243 |
dh_ur = np.matrix([ |
|
|
244 |
[0, pi / 2, 0.1273, q[0]], |
|
|
245 |
[-0.612, 0, 0, q[1]], |
|
|
246 |
[-0.5723, 0, 0, q[2]], |
|
|
247 |
[0, pi / 2, 0.163941, q[3]], |
|
|
248 |
[0, -pi / 2, 0.1157, q[4]], |
|
|
249 |
[0, 0, 0.0922, q[5]]]) |
|
|
250 |
return dh_ur |
|
|
251 |
else: |
|
|
252 |
print('Wrong robot selected') |
|
|
253 |
return |
|
|
254 |
|
|
|
255 |
|
|
|
256 |
def TransMatrix_DH_Symbol(rob='ur10', joint_num=6): |
|
|
257 |
''' |
|
|
258 |
This function gives the transfer matrix of robot(DH method) |
|
|
259 |
rob='ur5' : ur5 |
|
|
260 |
rob='ur10' : ur10 |
|
|
261 |
joint_num: the transform matrix for joint_num (from 1 to 6) |
|
|
262 |
''' |
|
|
263 |
T = [] |
|
|
264 |
# set up our joint angle symbols (6th angle doesn't affect any kinematics) |
|
|
265 |
q = [sp.Symbol('q%i' % ii) for ii in range(joint_num)] |
|
|
266 |
dh_ur = Robot_DH_Symbol(rob) |
|
|
267 |
for ii in range(joint_num): |
|
|
268 |
# descriptions terms in dh_ur |
|
|
269 |
# dh_ur[:,0] = a or r |
|
|
270 |
# dh_ur[:,1] = alpha |
|
|
271 |
# dh_ur[:,2] = d |
|
|
272 |
# dh_ur[:,3] = theta (q) |
|
|
273 |
T.append(sp.Matrix([[sp.cos(dh_ur[ii, 3]), -sp.sin(dh_ur[ii, 3]) * sp.cos(dh_ur[ii, 1]), |
|
|
274 |
sp.sin(dh_ur[ii, 3]) * sp.sin(dh_ur[ii, 1]), sp.cos(dh_ur[ii, 3]) * dh_ur[ii, 0]], |
|
|
275 |
[sp.sin(dh_ur[ii, 3]), sp.cos(dh_ur[ii, 3]) * sp.cos(dh_ur[ii, 1]), |
|
|
276 |
-sp.cos(dh_ur[ii, 3]) * sp.sin(dh_ur[ii, 1]), sp.sin(dh_ur[ii, 3]) * dh_ur[ii, 0]], |
|
|
277 |
[0, sp.sin(dh_ur[ii, 1]), sp.cos(dh_ur[ii, 1]), dh_ur[ii, 2]], |
|
|
278 |
[0, 0, 0, 1] |
|
|
279 |
])) |
|
|
280 |
if joint_num == 1: |
|
|
281 |
return T[0] |
|
|
282 |
elif joint_num == 2: |
|
|
283 |
return T[0] * T[1] |
|
|
284 |
elif joint_num == 3: |
|
|
285 |
return T[0] * T[1] * T[2] |
|
|
286 |
elif joint_num == 4: |
|
|
287 |
return T[0] * T[1] * T[2] * T[3] |
|
|
288 |
elif joint_num == 5: |
|
|
289 |
return T[0] * T[1] * T[2] * T[3] * T[4] |
|
|
290 |
elif joint_num == 6: |
|
|
291 |
return T[0] * T[1] * T[2] * T[3] * T[4] * T[5] |
|
|
292 |
else: |
|
|
293 |
print('Wrong joint number input') |
|
|
294 |
return |
|
|
295 |
|
|
|
296 |
|
|
|
297 |
def TransMatrix_DH_Numerical(rob='ur10', joint=[0, 0, 0, 0, 0, 0]): |
|
|
298 |
''' |
|
|
299 |
This function gives the transfer matrix of robot(DH method) |
|
|
300 |
rob='ur5' : ur5 |
|
|
301 |
rob='ur10' : ur10 |
|
|
302 |
joint: the robot joint vectors |
|
|
303 |
''' |
|
|
304 |
T = [] |
|
|
305 |
dh_ur = Robot_DH_Numerical(rob, joint) |
|
|
306 |
for ii in range(6): |
|
|
307 |
# descriptions terms in dh_ur |
|
|
308 |
# dh_ur[:,0] = a or r |
|
|
309 |
# dh_ur[:,1] = alpha |
|
|
310 |
# dh_ur[:,2] = d |
|
|
311 |
# dh_ur[:,3] = theta |
|
|
312 |
T.append(np.matrix([[np.cos(dh_ur[ii, 3]), -np.sin(dh_ur[ii, 3]) * np.cos(dh_ur[ii, 1]), |
|
|
313 |
np.sin(dh_ur[ii, 3]) * np.sin(dh_ur[ii, 1]), np.cos(dh_ur[ii, 3]) * dh_ur[ii, 0]], |
|
|
314 |
[np.sin(dh_ur[ii, 3]), np.cos(dh_ur[ii, 3]) * np.cos(dh_ur[ii, 1]), |
|
|
315 |
-np.cos(dh_ur[ii, 3]) * np.sin(dh_ur[ii, 1]), np.sin(dh_ur[ii, 3]) * dh_ur[ii, 0]], |
|
|
316 |
[0, np.sin(dh_ur[ii, 1]), np.cos(dh_ur[ii, 1]), dh_ur[ii, 2]], |
|
|
317 |
[0, 0, 0, 1] |
|
|
318 |
])) |
|
|
319 |
return np.round(T[0] * T[1] * T[2] * T[3] * T[4] * T[5], 4) |
|
|
320 |
|
|
|
321 |
|
|
|
322 |
def Jacobian_Symbol(rob='ur10', joint_num=6): |
|
|
323 |
''' |
|
|
324 |
This function returns a 6*6 symbolic jacobian matrix |
|
|
325 |
Tx: transfermation matrix |
|
|
326 |
''' |
|
|
327 |
# set up our joint angle symbols (6th angle doesn't affect any kinematics) |
|
|
328 |
q = [sp.Symbol('q%i' % ii) for ii in range(joint_num)] |
|
|
329 |
|
|
|
330 |
Tx = TransMatrix_DH_Symbol(rob, joint_num) |
|
|
331 |
J = [] |
|
|
332 |
# calculate derivative of (x,y,z) wrt to each joint, linear velocity |
|
|
333 |
for ii in range(joint_num): |
|
|
334 |
J.append([]) |
|
|
335 |
J[ii].append(sp.simplify(Tx[0, 3].diff(q[ii]))) # dx/dq[ii] |
|
|
336 |
J[ii].append(sp.simplify(Tx[1, 3].diff(q[ii]))) # dy/dq[ii] |
|
|
337 |
J[ii].append(sp.simplify(Tx[2, 3].diff(q[ii]))) # dz/dq[ii] |
|
|
338 |
# orientation part of the Jacobian (compensating for orientations) |
|
|
339 |
J_orientation = [ |
|
|
340 |
[0, 0, 1], # joint 0 rotates around z axis |
|
|
341 |
[1, 0, 0], # joint 1 rotates around x axis |
|
|
342 |
[1, 0, 0], # joint 2 rotates around x axis |
|
|
343 |
[1, 0, 0], # joint 3 rotates around x axis |
|
|
344 |
[0, 0, 1], # joint 4 rotates around z axis |
|
|
345 |
[1, 0, 0]] # joint 5 rotates around x axis |
|
|
346 |
# add on the orientation information up to the last joint |
|
|
347 |
for ii in range(joint_num): |
|
|
348 |
J[ii] = J[ii] + J_orientation[ii] |
|
|
349 |
return J |
|
|
350 |
|
|
|
351 |
|
|
|
352 |
def Jacobian_Numerical(rob='ur10', joint=[0, 0, 0, 0, 0, 0]): |
|
|
353 |
''' |
|
|
354 |
This function returns the numerical result of Jacobian |
|
|
355 |
joint: joint vector |
|
|
356 |
J is from Jacobian_Symbol |
|
|
357 |
''' |
|
|
358 |
q0 = joint[0] |
|
|
359 |
q1 = joint[1] |
|
|
360 |
q2 = joint[2] |
|
|
361 |
q3 = joint[3] |
|
|
362 |
q4 = joint[4] |
|
|
363 |
q5 = joint[5] |
|
|
364 |
if str(rob).lower() == 'ur5': |
|
|
365 |
J = np.matrix([[0.0823 * np.sin(q0) * np.sin(q4) * np.cos(q1 + q2 + q3) - 0.09465 * np.sin(q0) * np.sin( |
|
|
366 |
q1 + q2 + q3) + 0.425 * np.sin(q0) * np.cos(q1) + 0.39225 * np.sin(q0) * np.cos(q1 + q2) + 0.0823 * np.cos( |
|
|
367 |
q0) * np.cos(q4) + 0.10915 * np.cos(q0), |
|
|
368 |
0.0823 * np.sin(q0) * np.cos(q4) + 0.10915 * np.sin(q0) - 0.0823 * np.sin(q4) * np.cos( |
|
|
369 |
q0) * np.cos(q1 + q2 + q3) + 0.09465 * np.sin(q1 + q2 + q3) * np.cos(q0) - 0.425 * np.cos( |
|
|
370 |
q0) * np.cos(q1) - 0.39225 * np.cos(q0) * np.cos(q1 + q2), 0, 0, 0, 1], |
|
|
371 |
[0.425 * np.sin(q1) * np.cos(q0) + 0.0823 * np.sin(q4) * np.sin(q1 + q2 + q3) * np.cos( |
|
|
372 |
q0) + 0.39225 * np.sin(q1 + q2) * np.cos(q0) + 0.09465 * np.cos(q0) * np.cos(q1 + q2 + q3), |
|
|
373 |
0.425 * np.sin(q0) * np.sin(q1) + 0.0823 * np.sin(q0) * np.sin(q4) * np.sin( |
|
|
374 |
q1 + q2 + q3) + 0.39225 * np.sin(q0) * np.sin(q1 + q2) + 0.09465 * np.sin(q0) * np.cos( |
|
|
375 |
q1 + q2 + q3), |
|
|
376 |
-0.0823 * np.sin(q4) * np.cos(q1 + q2 + q3) + 0.09465 * np.sin(q1 + q2 + q3) - 0.425 * np.cos( |
|
|
377 |
q1) - 0.39225 * np.cos(q1 + q2), 1, 0, 0], |
|
|
378 |
[0.0823 * np.sin(q4) * np.sin(q1 + q2 + q3) * np.cos(q0) + 0.39225 * np.sin(q1 + q2) * np.cos( |
|
|
379 |
q0) + 0.09465 * np.cos(q0) * np.cos(q1 + q2 + q3), |
|
|
380 |
0.0823 * np.sin(q0) * np.sin(q4) * np.sin(q1 + q2 + q3) + 0.39225 * np.sin(q0) * np.sin( |
|
|
381 |
q1 + q2) + 0.09465 * np.sin(q0) * np.cos(q1 + q2 + q3), |
|
|
382 |
-0.0823 * np.sin(q4) * np.cos(q1 + q2 + q3) + 0.09465 * np.sin(q1 + q2 + q3) - 0.39225 * np.cos( |
|
|
383 |
q1 + q2), 1, 0, 0], |
|
|
384 |
[(0.0823 * np.sin(q4) * np.sin(q1 + q2 + q3) + 0.09465 * np.cos(q1 + q2 + q3)) * np.cos(q0), |
|
|
385 |
(0.0823 * np.sin(q4) * np.sin(q1 + q2 + q3) + 0.09465 * np.cos(q1 + q2 + q3)) * np.sin(q0), |
|
|
386 |
-0.0823 * np.sin(q4) * np.cos(q1 + q2 + q3) + 0.09465 * np.sin(q1 + q2 + q3), 1, 0, 0], |
|
|
387 |
[-0.0823 * (1.0 * np.sin(q0)) * np.sin(q4) - 0.0823 * np.cos(q0) * np.cos(q4) * np.cos( |
|
|
388 |
q1 + q2 + q3), |
|
|
389 |
0.0823 * (1.0 * np.cos(q0)) * np.sin(q4) - 0.0823 * np.sin(q0) * np.cos(q4) * np.cos( |
|
|
390 |
q1 + q2 + q3), - 0.0823 * np.sin(q1 + q2 + q3) * np.cos(q4), 0, 0, 1], |
|
|
391 |
[0, 0, 0, 1, 0, 0]]) |
|
|
392 |
elif str(rob).lower() == 'ur10': |
|
|
393 |
J = np.matrix([[0.0922 * np.sin(q0) * np.sin(q4) * np.cos(q1 + q2 + q3) - 0.1157 * np.sin(q0) * np.sin( |
|
|
394 |
q1 + q2 + q3) + 0.612 * np.sin(q0) * np.cos(q1) + 0.5723 * np.sin(q0) * np.cos(q1 + q2) + 0.0922 * np.cos( |
|
|
395 |
q0) * np.cos(q4) + 0.163941 * np.cos(q0), |
|
|
396 |
0.0922 * np.sin(q0) * np.cos(q4) + 0.163941 * np.sin(q0) - 0.0922 * np.sin(q4) * np.cos( |
|
|
397 |
q0) * np.cos(q1 + q2 + q3) + 0.1157 * np.sin(q1 + q2 + q3) * np.cos(q0) - 0.612 * np.cos( |
|
|
398 |
q0) * np.cos(q1) - 0.5723 * np.cos(q0) * np.cos(q1 + q2), 0, 0, 0, 1], |
|
|
399 |
[0.612 * np.sin(q1) * np.cos(q0) + 0.0922 * np.sin(q4) * np.sin(q1 + q2 + q3) * np.cos( |
|
|
400 |
q0) + 0.5723 * np.sin(q1 + q2) * np.cos(q0) + 0.1157 * np.cos(q0) * np.cos(q1 + q2 + q3), |
|
|
401 |
0.612 * np.sin(q0) * np.sin(q1) + 0.0922 * np.sin(q0) * np.sin(q4) * np.sin( |
|
|
402 |
q1 + q2 + q3) + 0.5723 * np.sin(q0) * np.sin(q1 + q2) + 0.1157 * np.sin(q0) * np.cos( |
|
|
403 |
q1 + q2 + q3), |
|
|
404 |
-0.0922 * np.sin(q4) * np.cos(q1 + q2 + q3) + 0.1157 * np.sin(q1 + q2 + q3) - 0.612 * np.cos( |
|
|
405 |
q1) - 0.5723 * np.cos(q1 + q2), 1, 0, 0], |
|
|
406 |
[0.0922 * np.sin(q4) * np.sin(q1 + q2 + q3) * np.cos(q0) + 0.5723 * np.sin(q1 + q2) * np.cos( |
|
|
407 |
q0) + 0.1157 * np.cos(q0) * np.cos(q1 + q2 + q3), |
|
|
408 |
0.0922 * np.sin(q0) * np.sin(q4) * np.sin(q1 + q2 + q3) + 0.5723 * np.sin(q0) * np.sin( |
|
|
409 |
q1 + q2) + 0.1157 * np.sin(q0) * np.cos(q1 + q2 + q3), |
|
|
410 |
-0.0922 * np.sin(q4) * np.cos(q1 + q2 + q3) + 0.1157 * np.sin(q1 + q2 + q3) - 0.5723 * np.cos( |
|
|
411 |
q1 + q2), 1, 0, 0], |
|
|
412 |
[(0.0922 * np.sin(q4) * np.sin(q1 + q2 + q3) + 0.1157 * np.cos(q1 + q2 + q3)) * np.cos(q0), |
|
|
413 |
(0.0922 * np.sin(q4) * np.sin(q1 + q2 + q3) + 0.1157 * np.cos(q1 + q2 + q3)) * np.sin(q0), |
|
|
414 |
-0.0922 * np.sin(q4) * np.cos(q1 + q2 + q3) + 0.1157 * np.sin(q1 + q2 + q3), 1, 0, 0], |
|
|
415 |
[-0.0922 * (1.0 * np.sin(q0)) * np.sin(q4) - 0.0922 * np.cos(q0) * np.cos(q4) * np.cos( |
|
|
416 |
q1 + q2 + q3), |
|
|
417 |
0.0922 * (1.0 * np.cos(q0)) * np.sin(q4) - 0.0922 * np.sin(q0) * np.cos(q4) * np.cos( |
|
|
418 |
q1 + q2 + q3), - 0.0922 * np.sin(q1 + q2 + q3) * np.cos(q4), 0, 0, 1], |
|
|
419 |
[0, 0, 0, 1, 0, 0]]) |
|
|
420 |
return J |
|
|
421 |
|
|
|
422 |
|
|
|
423 |
def RotatMatr2AxisAng(Matrix): |
|
|
424 |
''' |
|
|
425 |
Convert the rotation matrix to axis angle |
|
|
426 |
''' |
|
|
427 |
R = Matrix |
|
|
428 |
theta = np.arccos(0.5 * (R[0, 0] + R[1, 1] + R[2, 2] - 1)) |
|
|
429 |
e1 = (R[2, 1] - R[1, 2]) / (2 * np.sin(theta)) |
|
|
430 |
e2 = (R[0, 2] - R[2, 0]) / (2 * np.sin(theta)) |
|
|
431 |
e3 = (R[1, 0] - R[0, 1]) / (2 * np.sin(theta)) |
|
|
432 |
axis_ang = np.array([theta * e1, theta * e2, theta * e3]) |
|
|
433 |
return axis_ang |
|
|
434 |
|
|
|
435 |
|
|
|
436 |
def AxisAng2RotaMatri(angle_vec): |
|
|
437 |
''' |
|
|
438 |
Convert an Axis angle to rotation matrix |
|
|
439 |
AxisAng2Matrix(angle_vec) |
|
|
440 |
angle_vec need to be a 3D Axis angle |
|
|
441 |
''' |
|
|
442 |
theta = math.sqrt(angle_vec[0] ** 2 + angle_vec[1] ** 2 + angle_vec[2] ** 2) |
|
|
443 |
if theta == 0.: |
|
|
444 |
return np.identity(3, dtype=float) |
|
|
445 |
|
|
|
446 |
cs = np.cos(theta) |
|
|
447 |
si = np.sin(theta) |
|
|
448 |
e1 = angle_vec[0] / theta |
|
|
449 |
e2 = angle_vec[1] / theta |
|
|
450 |
e3 = angle_vec[2] / theta |
|
|
451 |
|
|
|
452 |
R = np.zeros((3, 3)) |
|
|
453 |
R[0, 0] = (1 - cs) * e1 ** 2 + cs |
|
|
454 |
R[0, 1] = (1 - cs) * e1 * e2 - e3 * si |
|
|
455 |
R[0, 2] = (1 - cs) * e1 * e3 + e2 * si |
|
|
456 |
R[1, 0] = (1 - cs) * e1 * e2 + e3 * si |
|
|
457 |
R[1, 1] = (1 - cs) * e2 ** 2 + cs |
|
|
458 |
R[1, 2] = (1 - cs) * e2 * e3 - e1 * si |
|
|
459 |
R[2, 0] = (1 - cs) * e1 * e3 - e2 * si |
|
|
460 |
R[2, 1] = (1 - cs) * e2 * e3 + e1 * si |
|
|
461 |
R[2, 2] = (1 - cs) * e3 ** 2 + cs |
|
|
462 |
return R |
|
|
463 |
|
|
|
464 |
|
|
|
465 |
def Rotat2TransMarix(Rota_Matrix, pose): |
|
|
466 |
''' |
|
|
467 |
convert the rotation matrix and pose to transformation matrix |
|
|
468 |
''' |
|
|
469 |
tran_mat = np.zeros((4, 4)) |
|
|
470 |
tran_mat[:3, :3] = Rota_Matrix[:3, :3] |
|
|
471 |
tran_mat[3, 3] = 1 |
|
|
472 |
tran_mat[:3, 3] = pose[:3] |
|
|
473 |
return tran_mat |
|
|
474 |
|
|
|
475 |
|
|
|
476 |
def Pose2Tran_Mat(pose): |
|
|
477 |
''' |
|
|
478 |
Convert an pose to a transformation matrix |
|
|
479 |
AxisAng2Matrix(pose) |
|
|
480 |
''' |
|
|
481 |
rot_mat = AxisAng2RotaMatri(pose[-3:]) |
|
|
482 |
tran_mat = Rotat2TransMarix(rot_mat, pose) |
|
|
483 |
return tran_mat |
|
|
484 |
|
|
|
485 |
|
|
|
486 |
def Tran_Mat2Pose(Tran_Mat): |
|
|
487 |
''' |
|
|
488 |
Convert a transformation matrix to pose |
|
|
489 |
''' |
|
|
490 |
pose = np.zeros([6]) |
|
|
491 |
pose[:3] = Tran_Mat[:3, 3] |
|
|
492 |
Rota_mat = np.zeros([3, 3]) |
|
|
493 |
Rota_mat[:3, :3] = Tran_Mat[:3, :3] |
|
|
494 |
angle_vec = RotatMatr2AxisAng(Rota_mat) |
|
|
495 |
pose[-3:] = angle_vec |
|
|
496 |
return pose |
|
|
497 |
|
|
|
498 |
|
|
|
499 |
def cmpleate_rotation_matrix(start_vector): |
|
|
500 |
''' This function make rotation matrix where the first column is the |
|
|
501 |
input vector. |
|
|
502 |
''' |
|
|
503 |
|
|
|
504 |
a = np.matrix(start_vector) |
|
|
505 |
a = a / np.linalg.norm(a) |
|
|
506 |
U, s, Vh = linalg.svd(a, full_matrices=True) |
|
|
507 |
|
|
|
508 |
Vh[0] = a # to ensure that the virst vector is not -a |
|
|
509 |
Vh[2] = np.cross(a, Vh[1]) |
|
|
510 |
Vh = np.transpose(Vh) |
|
|
511 |
return np.array(Vh) |
|
|
512 |
|
|
|
513 |
|
|
|
514 |
def Inverse_kin(target_pos, init_joint_pos=[0, 0, 0, 0, 0, 0], tcpOffset=[0, 0, 0, 0, 0, 0]): |
|
|
515 |
''' |
|
|
516 |
Find the inverse kinematics |
|
|
517 |
target_pos = the target pos vector |
|
|
518 |
init_joint_pos (optional) = the initial joint vector |
|
|
519 |
''' |
|
|
520 |
# Define a robot from URDF file |
|
|
521 |
my_chain = ik.chain.Chain.from_urdf_file('URDF/UR5.URDF') |
|
|
522 |
# Convert pos to transfer matrix |
|
|
523 |
# Mar = Pose2Tran_Mat(target_pos) |
|
|
524 |
|
|
|
525 |
T_target = Pose2Tran_Mat(pose=target_pos) |
|
|
526 |
T_tcp = Pose2Tran_Mat(pose=tcpOffset) |
|
|
527 |
Mar = np.matmul(T_target, np.linalg.inv(T_tcp)) |
|
|
528 |
|
|
|
529 |
# Inverse kinematics |
|
|
530 |
if len(init_joint_pos) < 6: |
|
|
531 |
return None |
|
|
532 |
else: |
|
|
533 |
joint_init = init_joint_pos.copy() |
|
|
534 |
# add a [0] at the base frame |
|
|
535 |
joint_initadd = np.zeros([7]) |
|
|
536 |
joint_initadd[1:] = joint_init[:] |
|
|
537 |
ikin = my_chain.inverse_kinematics(target=Mar, initial_position=joint_initadd.copy()) |
|
|
538 |
|
|
|
539 |
print('***************************************************************************') |
|
|
540 |
print('Pose: [{: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}]'.format(*target_pos)) |
|
|
541 |
print('---------------------------------------------------------------------------') |
|
|
542 |
print(ikin) |
|
|
543 |
print('---------------------------------------------------------------------------') |
|
|
544 |
print('Joints Returned: [{: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}, {: 06.3f}]'.format(*ikin[1:])) |
|
|
545 |
print('***************************************************************************') |
|
|
546 |
|
|
|
547 |
return ikin[1:] |
|
|
548 |
|
|
|
549 |
|
|
|
550 |
def Forward_kin(joint): |
|
|
551 |
''' |
|
|
552 |
Find the forward kinematics |
|
|
553 |
''' |
|
|
554 |
# Define a robot from URDF file |
|
|
555 |
my_chain = ik.chain.Chain.from_urdf_file('URDF/UR5.URDF') |
|
|
556 |
# add a [0] in joint anlges, due to the defination of URDF |
|
|
557 |
joint_new = np.zeros([7]) |
|
|
558 |
joint_new[1:] = joint[:] |
|
|
559 |
fk = my_chain.forward_kinematics(joint_new) |
|
|
560 |
# convert transfer matrix to pos |
|
|
561 |
axis_ang = Tran_Mat2Pose(fk) |
|
|
562 |
return axis_ang |
|
|
563 |
|
|
|
564 |
|
|
|
565 |
def Vektor_from_Base_to_TCP(vectorBase, axisangle): |
|
|
566 |
""" |
|
|
567 |
Function to calculate the rotation of a vector with an axis angle. This function can be used to transform a vector from the base coordinate system to the tcp coordinate system. |
|
|
568 |
(To go from tcp to Base use -1*le as input) |
|
|
569 |
|
|
|
570 |
Parameters: |
|
|
571 |
vectorBase (np.array, 3*1): the vector to be rotated |
|
|
572 |
axisangle (np.array, 3*1): the axis angle between the base and the tcp |
|
|
573 |
""" |
|
|
574 |
# calculating the rotation angle by finding the length of the axis angle |
|
|
575 |
angle = axisangle[0] * axisangle[0] + axisangle[1] * axisangle[1] + axisangle[2] * axisangle[2] |
|
|
576 |
angle = np.sqrt(angle) |
|
|
577 |
# Defining the unit rotation angle |
|
|
578 |
eRot = axisangle / angle |
|
|
579 |
# calculation of the tcp vector using Rodrigues' rotation formula |
|
|
580 |
vectorBase = np.array(vectorBase) |
|
|
581 |
vectorTCP = np.cos(angle) * vectorBase + np.sin(angle) * np.cross(eRot, vectorBase) + (1 - np.cos(angle)) * np.dot( |
|
|
582 |
eRot, vectorBase) * eRot |
|
|
583 |
return vectorTCP |