Diff of /URBasic/kinematic.py [000000] .. [c1b1c5]

Switch to unified view

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