21 import copy, time, math
22 import numpy
as np, general_python
as genpy
24 from interval
import interval, inf, imath
27 from math_tools
import general_math
as genmath
28 from math_tools.geometry import trigonometry
as trig, trajectory
as trajlib, geometry
as geo
37 default_ql = drc*np.array([-130.0, 70.0 , -180.0, - 131.0, -180.0, -130.0, -180.0])
38 default_qh = drc*np.array([ 30.0, 170.0, 44.0, - 8.6, 180.0, 0.00, 180.0])
40 default_W = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
44 This class provides a parametric representation of the kinematics of PR2 arm
45 The position, orientation and the Jacobian can be expressed in terms of DH parameters and sine and cosine of the joint angles
46 It uses sympy as a tool for symbols algebra
50 from sympy
import Symbol, simplify
54 c = [Symbol(
'c' + str(i))
for i
in range(n)]
55 s = [Symbol(
's' + str(i))
for i
in range(n)]
56 a = [Symbol(
'a0'), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
57 d = [0.0, 0.0, Symbol(
'd2'), 0.0, Symbol(
'd4'), 0.0, 0.0]
58 alpha = [- math.pi/2, math.pi/2, - math.pi/2, math.pi/2, - math.pi/2, math.pi/2, 0.0]
60 ca = [math.cos(alpha[i])
for i
in range(n)]
61 sa = [math.sin(alpha[i])
for i
in range(n)]
63 for i
in range(len(ca)):
64 ca[i] = genmath.round(ca[i])
65 sa[i] = genmath.round(sa[i])
68 self.
A = [np.array([[ c[i], -ca[i]*s[i], sa[i]*s[i], a[i]*c[i] ],
69 [ s[i], ca[i]*c[i], -sa[i]*c[i], a[i]*s[i] ],
70 [ 0 , sa[i] , ca[i] , d[i] ],
71 [ 0 , 0 , 0 , 1 ]])
for i
in range(n)]
74 self.
B = [np.array([[ c[i], s[i], 0 , 0 ],
75 [ -ca[i]*s[i], ca[i]*c[i], sa[i] , -d[i]*sa[i] ],
76 [ ca[i]*s[i], -sa[i]*c[i], ca[i] , -d[i]*ca[i] ],
77 [ 0 , 0 , 0 , 1 ]])
for i
in range(n)]
80 self.
R = [np.array([[ c[i], -ca[i]*s[i], sa[i]*s[i]],
81 [ s[i], ca[i]*c[i], -sa[i]*c[i]],
82 [ 0 , sa[i] , ca[i] ]])
for i
in range(n)]
85 self.
T = np.copy(self.
A)
87 self.
T[i + 1] = np.dot(self.
T[i],self.
A[i + 1])
90 T_d = np.array([[ Symbol(
'r11'), Symbol(
'r12') , Symbol(
'r13') , Symbol(
'px') ],
91 [ Symbol(
'r21'), Symbol(
'r22') , Symbol(
'r23') , Symbol(
'py') ],
92 [ Symbol(
'r31'), Symbol(
'r32') , Symbol(
'r33') , Symbol(
'pz') ],
95 self.
x_d = T_d[0:3, 3]
96 self.
R_d = T_d[0:3, 0:3]
99 "p_W" denotes the position vector of the wrist joint center
100 "R_W" denotes the orientation of the gripper (Endeffector Orientation)
107 "p_EF_W" denotes the position of the arm endeffector (end of the gripper) relative to the wrist joint center
108 in the coordinates system of the right gripper.
111 self.
p_EF_W = np.array([0.0, 0.0, Symbol(
'd7')])
113 self.
H = np.copy(self.
T)
114 self.
H[n - 1] = np.copy(T_d)
118 self.
H[n - i - 2] = np.dot(self.
H[n - i - 1], self.
B[n - i - 1])
121 [ 0 , 0 , -2*d[2]*d[4]*s[3] , 0 , 0 , 0 ],
122 [0 , - 2*c[2]*s[2]*s[3]**2 , Symbol(
'e23') , 0 , 0 , 0 ],
123 [Symbol(
'e31') , d[4]*Symbol(
's321') , Symbol(
'e33') , 0 , 0 , 0 ],
124 [Symbol(
'e41') , Symbol(
'e42') , Symbol(
'e43') , 0 , - s[5] , 0 ],
125 [Symbol(
'e51') , Symbol(
'e52') , 0 , c[4]*s[5] , c[5]*s[4] , 0 ],
126 [Symbol(
'e61') , Symbol(
'e62') , Symbol(
'e63') , 0 , Symbol(
'c65') , - Symbol(
's65') ]])
128 self.
div_phi_err = sympy.Matrix([Symbol(
'e10') , 0 , 0 , Symbol(
'e40') , Symbol(
'e50') , Symbol(
'e60') ])
131 J3 = - Symbol(
'e10')/e[0,2]
132 J2 = - e[1,2]*J3/e[1,1]
133 J1 = - (e[2,1]*J2 + e[2,2]*J3)/e[2,0]
134 J5 = - (Symbol(
'e40') + e[3,0]*J1 + e[3,1]*J2 + e[3,2]*J3)/e[3,4]
135 J4 = - (Symbol(
'e50') + e[4,0]*J1 + e[4,1]*J2 + e[4,4]*J5)/e[4,3]
136 J6 = - (Symbol(
'e60') + e[5,0]*J1 + e[5,1]*J2 + e[5,2]*J3 + e[5,3]*J4 + e[5,4]*J5)/ e[5,5]
138 self.
RJ = sympy.Matrix([J1,J2,J3,J4,J5,J6])
153 def __init__(self, ql = default_ql, qh = default_qh, W = default_W):
154 assert (len(ql) == 7)
and (len(qh) == 7),
"Error from " + __name__ +
": Given arrays ql and qh must have 7 elements"
184 self.
qm = (qh + ql)/2
199 self.
w[i] = math.sqrt(W[i])
209 qi = trig.angle_standard_range(qi)
210 if abs(qi - self.
ql[i]) < genmath.epsilon:
212 if abs(qi - self.
qh[i]) < genmath.epsilon:
215 return ((qi <= self.
qh[i])
and (qi >= self.
ql[i]))
222 for i
in range(0, 7):
223 if not genmath.equal(self.
w[i], 0.0):
231 return trig.angles_standard_range(self.
q - self.
qm)*self.
w
240 The correction of joints is always restricted by joint limits and maximum feasible joint speed
241 If you want to move the joints in a desired direction, how much are you allowed to move?
242 This function returns a feasible interval for the stepsize in the given direction.
243 The joint direction of change must be multiplied by a scalar value in this range so that the applied changes
250 if not genmath.equal(direction[i], 0.0):
251 if (self.
w[i] != 0.0):
252 a = (self.
ql[i] - self.
q[i])/direction[i]
253 b = (self.
qh[i] - self.
q[i])/direction[i]
254 etta_l.append(genmath.sign_choice(a, b, direction[i]))
255 etta_h.append(genmath.sign_choice(b, a, direction[i]))
257 a = dt*max_speed/direction[i]
258 etta_l.append(genmath.sign_choice(-a, a, direction[i]))
259 etta_h.append(genmath.sign_choice( a,-a, direction[i]))
261 if (etta_l == [])
or (etta_h == []):
264 return (max(etta_l), min(etta_h))
271 This function sets the robot joint configuration to the given "qd"
272 This function should not be called by the end user.
273 Always use function "set_config" in class PR2_ARM()
276 print "set_config error: Number of input elements must be 7"
280 for i
in range(0, 7):
281 if genmath.equal(self.
w[i], 0.0):
284 self.
q[i] = trig.angle_standard_range(qd[i])
286 self.
c = [math.cos(self.
q[i])
for i
in range(0,7)]
287 self.
s = [math.sin(self.
q[i])
for i
in range(0,7)]
289 [s0, s1, s2, s3, s4, s5, s6] = self.
s
290 [c0, c1, c2, c3, c4, c5, c6] = self.
c
297 [s20,s21, s22, s210] = self.
s2_mult1
299 self.
s3_mult1 = s3*np.array([s0, s1, s2, s10, s20, s21, s22, s3,s210])
300 [s30, s31, s32, s310, s320, s321, s322, s33,s3210] = self.
s3_mult1
302 self.
c0_mult = c0*np.array([s0,s1,s2,s10,s20,s21,s30,s31,s32,s321])
303 [c0s0,c0s1,c0s2,c0s10,c0s20,c0s21,c0s30,c0s31,c0s32,c0s321] = self.
c0_mult
305 self.
c1_mult = c1*np.array([c0, s0, s1, s2, s3, s10, s20,s30,s32, s320])
306 [c10, c1s0, c1s1, c1s2, c1s3, c1s10, c1s20,c1s30,c1s32,c1s320] = self.
c1_mult
309 self.c2_mult = c2*np.array([c0,c1,c2,c10,s0,s1,s2,s3,s10,s20,s30,s31,s310, c1s30,c0s31])
310 [c20,c21,c22,c210,c2s0,c2s1,c2s2,c2s3,c2s10,c2s20,c2s30,c2s31,c2s310,c21s30,c20s31] = self.c2_mult
312 self.c3_mult = c3*np.array([c0,c1,c2,c3, s0,s1,s2,s3,s10,s20,s21,s30,c10,c20,c21,c210,c2s0,c2s10])
313 [c30,c31,c32,c33,c3s0,c3s1,c3s2,c3s3,c3s10,c3s20,c3s21,c3s30,c310,c320,c321,c3210,c32s0,c32s10] = self.c3_mult
315 self.s0_mult = s0*np.array([c21,c31,c321])
316 [c21s0,c31s0,c321s0] = self.s0_mult
318 self.s1_mult2 = s1*np.array([c10,c20,c30, c32,c320])
319 [c10s1,c20s1,c30s1, c32s1,c320s1] = self.s1_mult2
321 self.s2_mult2 = s2*np.array([c10,c20,c30, c32,c310])
322 [c10s2,c20s2,c30s2, c32s2,c310s2] = self.s2_mult2
324 self.s3_mult2 = s3*np.array([c10, c20, c30, c21, c210,s32])
325 [c10s3, c20s3, c30s3, c21s3, c210s3,s332] = self.s3_mult2
327 self.cs_mult = [c10*s32, c31*s20, s5*s4]
328 [c10s32, c31s20, s54] = self.cs_mult
330 self.c5_mult = c5*np.array([c4, s4, s5])
331 [c54, c5s4, c5s5] = self.c5_mult
333 self.s6_mult = s6*np.array([s4, s5, c4, c5, c54, s54])
334 [s64, s65, c4s6, c5s6, c54s6, s654] = self.s6_mult
336 self.c6_mult = c6*np.array([c4, c5, s4, s5, c54, s54])
337 [c64, c65, c6s4, c6s5, c654, C6s54] = self.c6_mult
341 Do not set any other environmental variables here
346 print "Error from PR2_ARM.set_config(): Given joints are not in their feasible range"
348 if qd[i] > self.
qh[i]:
349 print "Joint No. ", i ,
" is ", qd[i],
" greater than maximum: ", self.
qh[i]
350 if qd[i] < self.
ql[i]:
351 print "Joint No. ", i ,
" is ", qd[i],
" lower than minimum: ", self.
ql[i]
360 (qq, dd) = trig.closest_angle_metric(self.
q[i], q[i])
390 def __init__(self, a0 = 0.1, d2 = 0.4, d4 = 0.321, ql = default_ql, qh = default_qh, W = default_W, run_magiks = False):
421 l2 = d2**2 + d4**2 - a0**2
423 assert l2 > 0,
"Error from " + __name__ +
"Constructor: Invalid dimensions or DH parameters"
425 self.
l = math.sqrt(l2)
433 d22_plus_d44 = d2*d2 + d44
434 foura00d44 = 4*a00*d44
435 alpha = - Q2/foura00d44
438 self.
additional_dims = [Q, Q2, d42, d44, a00, d22_plus_d44, foura00d44, alpha]
442 self.
l_ew = [0.0, 0.0, d4]
479 from magiks.magiks_core import inverse_kinematics
as iklib, manipulator_library
as manlib
480 cs = manlib.manip_config_settings(
'PR2ARM', joint_mapping =
'TM')
481 cs.ql = np.copy(self.config.ql)
482 cs.qh = np.copy(self.config.qh)
483 es = iklib.eflib.Endeffector_Settings()
484 iks = iklib.Inverse_Kinematics_Settings(algorithm =
'JPI')
485 self.
ik = iklib.Inverse_Kinematics(cs, manlib.PR2ARM_geometry_settings, es, iks)
507 print arm.wrist_position()
508 print arm.wrist_orientation()
511 permit = self.ik.set_config(qd)
and self.config.set_config(qd)
513 permit = self.config.set_config(qd)
532 def set_target(self, target_position, target_orientation):
534 assert genmath.equal(np.linalg.det(target_orientation), 1.0)
535 self.
xd = target_position
536 self.
Rd = target_orientation
538 self.ik.set_target([target_position], [geo.Orientation_3D(target_orientation)])
540 [Q, Q2, d42, d44, a00, d22_plus_d44, foura00d44, alpha] = self.
additional_dims
542 sai = math.atan2(self.
xd[0], self.
xd[1])
543 r2 = self.
xd[0]**2 + self.
xd[1]**2
544 ro2 = r2 + self.
xd[2]**2
545 R2 = ro2 - d22_plus_d44 + a00
547 alpha, betta and gamma are selected so that w^2 * (1 - v^2) = alpha*v^2 + betta*v + gamma
550 T2 = R2**2 - 4*a00*r2
551 betta = - 2*R2*Q/foura00d44
552 gamma = - T2/foura00d44
563 X = self.
a0*self.config.c[0] + self.config.c[0]*self.
d2*self.config.s[1]
564 Y = self.
a0*self.config.s[0] + self.
d2*self.config.s[0]*self.config.s[1]
565 Z = self.config.c[1]*self.
d2
566 return np.array([X,Y,Z])
573 Returns the cartesian coordiantes of the origin of the wrist. The origin of the wrist is the wrist joint center
576 [s0, s1, s2, s3, s4, s5, s6] = self.config.s
577 [c0, c1, c2, c3, c4, c5, c6] = self.config.c
578 [s10] = self.config.s1_mult1
579 [s30, s31, s32, s310, s320, s321, s322, s33,s3210] = self.config.s3_mult1
580 [c0s0,c0s1,c0s2,c0s10,c0s20,c0s21,c0s30,c0s31,c0s32,c0s321] = self.config.c0_mult
581 [c20,c21,c22,c210,c2s0,c2s1,c2s2,c2s3,c2s10,c2s20,c2s30,c2s31,c2s310,c21s30,c20s31] = self.config.c2_mult
582 [c30,c31,c32,c33,c3s0,c3s1,c3s2,c3s3,c3s10,c3s20,c3s21,c3s30,c310,c320,c321,c3210,c32s0,c32s10] = self.config.c3_mult
583 [c10s1,c20s1,c30s1, c32s1,c320s1] = self.config.s1_mult2
584 [c10s3, c20s3, c30s3, c21s3,c210s3,s332] = self.config.s3_mult2
586 X = c0*self.
a0 + c0s1*self.
d2 + (c30s1 + c210s3 - s320)*self.
d4
588 Y = s0*self.
a0 + s10*self.
d2 + (c3s10 + c0s32 + c21s30)*self.
d4
590 Z = c1*self.
d2 + (c31 - c2s31)*self.
d4
602 [s0, s1, s2, s3, s4, s5, s6] = self.config.s
603 [c0, c1, c2, c3, c4, c5, c6] = self.config.c
604 [s10] = self.config.s1_mult1
605 [s20,s21, s22, s210] = self.config.s2_mult1
606 [c0s0,c0s1,c0s2,c0s10,c0s20,c0s21,c0s30,c0s31,c0s32,c0s321] = self.config.c0_mult
607 [c10, c1s0, c1s1, c1s2, c1s3, c1s10, c1s20,c1s30,c1s32,c1s320] = self.config.c1_mult
608 [c20,c21,c22,c210,c2s0,c2s1,c2s2,c2s3,c2s10,c2s20,c2s30,c2s31,c2s310,c21s30,c20s31] = self.config.c2_mult
609 [c21s0,c31s0,c321s0] = self.config.s0_mult
610 [c10s2,c20s2,c30s2, c32s2,c310s2] = self.config.s2_mult2
611 [c10s32, c31s20, s54] = self.config.cs_mult
612 [s64, s65, c4s6, c5s6, c54s6, s654] = self.config.s6_mult
613 [c64, c65, c6s4, c6s5, c654, C6s54] = self.config.c6_mult
615 R03 = np.array([[-s20 + c210, -c0s1, -c2s0 - c10s2],
616 [c0s2 + c21s0, -s10, c20 - c1s20],
619 R47 = np.array([[-s64 + c654, -c6s4 - c54s6, c4*s5],
620 [c4s6 + c65*s4, c64 - c5*s64, s54],
623 R34 = np.array([[ c3, 0, s3 ],
634 def in_target(self, norm_precision = 0.01):
636 return self.ik.in_target()
648 return copy.copy(self.
F)
657 [r31, r32, r33]] = self.
Rd
659 [s0, s1, s2, s3, s4, s5, s6] = self.config.s
660 [c0, c1, c2, c3, c4, c5, c6] = self.config.c
662 [s10] = self.config.s1_mult1
663 [s20,s21, s22, s210] = self.config.s2_mult1
664 [s30, s31, s32, s310, s320, s321, s322, s33,s3210] = self.config.s3_mult1
665 [c0s0,c0s1,c0s2,c0s10,c0s20,c0s21,c0s30,c0s31,c0s32,c0s321] = self.config.c0_mult
666 [c10, c1s0, c1s1, c1s2, c1s3, c1s10, c1s20,c1s30,c1s32,c1s320] = self.config.c1_mult
667 [c20,c21,c22,c210,c2s0,c2s1,c2s2,c2s3,c2s10,c2s20,c2s30,c2s31,c2s310,c21s30,c20s31] = self.config.c2_mult
668 [c30,c31,c32,c33,c3s0,c3s1,c3s2,c3s3,c3s10,c3s20,c3s21,c3s30,c310,c320,c321,c3210,c32s0,c32s10] = self.config.c3_mult
669 [c21s0,c31s0,c321s0] = self.config.s0_mult
670 [c10s1,c20s1,c30s1, c32s1,c320s1] = self.config.s1_mult2
671 [c10s2,c20s2,c30s2, c32s2,c310s2] = self.config.s2_mult2
672 [c10s3, c20s3, c30s3, c21s3, c210s3,s332] = self.config.s3_mult2
673 [c10s32, c31s20, s54] = self.config.cs_mult
674 [c54, c5s4, c5s5] = self.config.c5_mult
675 [s64, s65, c4s6, c5s6, c54s6, s654] = self.config.s6_mult
676 [c64, c65, c6s4, c6s5, c654, C6s54] = self.config.c6_mult
678 [Q, Q2, d42, d44, a00, d22_plus_d44, foura00d44, alpha] = self.
additional_dims
682 self.
E = np.zeros((7,7))
689 self.
E[2,2] = - 2*c2*s332
690 self.
E[2,3] = - 2*alpha*c3s3 - betta*s3 - 2*c3*s322
692 self.
E[3,1] = - self.
d2*s1 - (c3*s1 + c2*c1*s3)*self.
d4
693 self.
E[3,2] = s321*self.
d4
694 self.
E[3,3] = - (c1s3 + c32s1)*self.
d4
696 self.
E[4,1] = r13*(- c20*s31 + c310) + r23*(- c2s310 + c31s0) - r33*(c3s1 + c21*s3)
697 self.
E[4,2] = - r13*(c2s30 + c10s32) + r23*(c20s3 - c1s320) + r33*s321
699 self.
E[4,3] = r13*(- c3s20 + c3210 - c0s31) + r23*(c30s2 + c321s0 - s310) + r33*(- c1s3 - c32s1)
702 self.
E[5,1] = r13*c0s21 - r23*s210 + r33*c1s2
703 self.
E[5,2] = r13*(s20 - c210) - r23*(c0s2 + c21s0) + r33*c2s1
704 self.
E[5,4] = - c4*s5
705 self.
E[5,5] = - c5*s4
707 self.
E[6,1] = r11*(- c20s31 + c310) + r21*(- c2s310 + c31s0) - r31*(c3s1 + c21s3)
708 self.
E[6,2] = - r11*(c2s30 + c10s32) + r21*(c20s3 - c1s320) + r31*s321
709 self.
E[6,3] = r11*(- c3s20 + c3210 - c0s31) + r21*(c30s2 + c321s0 - s310) - r31*(c1s3 + c32s1)
714 self.
F[1] = 2*self.
a0*(s0*self.
xd[0] - c0*self.
xd[1])
715 self.
F[4] = r13*(- c0s32 - c21s30 - c3s10) + r23*(- s320 + c210s3 + c30s1)
716 self.
F[5] = r13*(-c20 + c1s20) - r23*(c2s0 + c10s2)
717 self.
F[6] = - r11*(c0s32 + c21s30 + c3s10) + r21*(- s320 + c210s3 + c30s1)
719 return copy.copy(self.
E)
735 if genmath.equal(E[1,3],0.0)
or genmath.equal(E[2,2],0.0)
or genmath.equal(E[3,1],0.0)
or genmath.equal(E[4,5],0.0)
or genmath.equal(E[5,4],0.0)
or genmath.equal(E[6,6],0.0):
738 self.
JRJ = np.zeros(7)
741 self.
JRJ[3] = - F[1]/E[1,3]
742 self.
JRJ[2] = - E[2,3]*self.
JRJ[3]/E[2,2]
743 self.
JRJ[1] = - (E[3,2]*self.
JRJ[2] + E[3,3]*self.
JRJ[3])/E[3,1]
745 self.
JRJ[5] = - (F[4] + np.dot(E[4,1:4],self.
JRJ[1:4]))/E[4,5]
747 self.
JRJ[4] = - (F[5] + E[5,1]*self.
JRJ[1] + E[5,2]*self.
JRJ[2] + E[5,5]*self.
JRJ[5])/E[5,4]
748 self.
JRJ[6] = - (F[6] + np.dot(E[6,1:6],self.
JRJ[1:6]))/E[6,6]
751 return copy.copy(self.
JRJ)
754 def grown_phi(self, eta, k = 0.99, respect_js = False):
756 grows the redundant parameter by eta (adds eta to the current phi=q[0] and returns the new value for phi
757 1 - this function does NOT set the configuration so the joint values do not change
758 2 - if the grown phi is not in the feasible interval Delta, it will return the closest point in the range with a safety coefficient k so that
759 new phi = old phi + eta : if eta in Delta
760 new phi = old phi + k*Delta_h : if eta > Delta_h
761 new phi = old phi + k*Delta_l : if eta < Delta_l
767 assert len(Delta) > 0
769 while (j < len(Delta)):
770 if 0.0
in interval(Delta[j]):
775 return self.config.q[0] + eta
777 return self.config.q[0] + k*dh
780 return self.config.q[0] + k*dl
797 int_c.append(imath.cos(interval(self.config.q[i])))
798 int_s.append(imath.sin(interval(self.config.q[i])))
800 int_c.append(imath.cos(interval([self.config.ql[i], self.config.qh[i]])))
801 int_s.append(imath.sin(interval([self.config.ql[i], self.config.qh[i]])))
803 int_s10 = int_s[1]*int_s[0]
804 int_s32 = int_s[3]*int_s[2]
805 int_s31 = int_s[3]*int_s[1]
806 int_s320 = int_s32*int_s[0]
808 int_c21 = int_c[2]*int_c[1]
809 int_c31 = int_c[3]*int_c[1]
810 int_c0s1 = int_c[0]*int_s[1]
811 int_c30s1 = int_c[3]*int_c0s1
812 int_c0s32 = int_s32*int_c[0]
813 int_c21s3 = int_c21*int_s[3]
814 int_c21s30 = int_c21s3*int_s[0]
815 int_c210s3 = int_c21s3*int_c[0]
816 int_c2s31 = int_s31*int_c[2]
817 int_c3s10 = int_s10*int_c[3]
819 int_X = int_c[0]*interval(self.
a0) + int_c0s1*interval(self.
d2) + (int_c30s1 + int_c210s3 - int_s320)*interval(self.
d4)
821 int_Y = int_s[0]*interval(self.
a0) + int_s10*interval(self.
d2) + (int_c3s10 + int_c0s32 + int_c21s30)*interval(self.
d4)
823 int_Z = int_c[1]*interval(self.
d2) + (int_c31 - int_c2s31)*interval(self.
d4)
825 return [int_X, int_Y, int_Z]
832 q = np.copy(self.config.q)
853 keep_q = np.copy(self.config.q)
857 e = self.config.midrange_error()
860 print "Iteration : ", counter
861 print "Redundant Parameter : ", self.config.q[0]
862 print "Objective Function : ", self.config.objective_function()
865 print "No Jacobian! Optimum phi = ", self.config.q[0]
869 if genmath.equal(den, 0.0):
871 print "Division by Zero! Optimum phi = ", self.config.q[0]
873 Delta_phi = - np.dot(P.T, e) / den
874 old_err = self.config.objective_function()
879 print "No solution for the updated phi! Optimum phi = ", self.config.q[0]
884 print "Solution found but not feasible! This should not happen. Optimum phi = ", self.config.q[0]
888 print "A better phi is found : ", new_phi
890 new_err = self.config.objective_function()
892 if new_err > old_err - 0.01:
894 print "Error not reduced any more. Optimum phi: ", self.config.q[0]
897 counter = counter + 1
904 def moveto_optimal(self, max_speed = genmath.infinity, step_time = 0.1):
906 q0 = np.copy(self.config.q)
907 err = self.config.objective_function()
909 e = self.config.midrange_error()
913 if genmath.equal(den, 0.0):
914 genpy.show(
'Division by Zero! Optimum phi = ' + str(self.config.q[0]), self.
silent)
917 delta_phi = - np.dot(P.T, e) / den
918 phi = self.
grown_phi(delta_phi, respect_js =
True)
928 genpy.show(self.
silent,
"Endeffector not in target !")
938 (phi_l, phi_h) = genmath.accommodating_interval(phi, PS)
940 assert (phi < phi_h)
and (phi > phi_l)
945 stay_up = (phi_up < phi_h)
946 stay_down = (phi_down > phi_l)
949 phi_up = phi_up + increment
956 phi_down = phi_down - increment
962 if not (stay_up
or stay_down):
973 return self.ik.ik_direction()
975 q0 = np.copy(self.config.q)
976 if self.
goto_target(phi = phi, optimize = optimize):
978 return trig.angles_standard_range(q - q0)
988 speed_limit = abs(speed_limit)
989 q0 = np.copy(self.config.q)
990 (el, eh) = self.config.joint_stepsize_interval(direction = direction, max_speed = max_speed, delta_t = time_step)
1002 if self.ik.moveto_target():
1008 q0 = np.copy(self.config.q)
1010 jdir = self.
ik_direction(phi = self.config.q[0], optimize = optimize)
1012 if np.linalg.norm(jdir) > 0.0001:
1013 (el, eh) = self.config.joint_stepsize_interval(direction = jdir, max_speed = self.
max_js, dt = self.
dt)
1027 def goto_target(self, phi = None, optimize = False, show = False):
1029 Finds the inverse kinematic solution for the given redundant parameter phi
1030 is phi is not feasible, the solution corresponding to the closest phi is returned.
1031 If argument optimize is True, the solution will be optimized
1032 so that the joint values will be as close as possible to self.config.qm
1033 If phi is not given, current q[0] will be selected as phi
1035 The new joint angles will be set if all the kinematic equations are satisfied.
1036 All kinematic parameters will be updated.
1039 if self.ik.goto_target():
1042 self.ik.set_config(self.config.q)
1043 print "\n Magiks could not find a solution ! \n"
1047 phi = self.config.q[0]
1051 print "Permission Set for phi = ", PS
1052 print "Initial phi = ", phi
1057 print "The target is out of workspace! No solution found."
1061 phi = genmath.closest_border(phi, PS, k = 0.01)
1063 print "Phi is not in PS"
1064 print "Closest phi in PS:", phi
1069 print phi,
" is not a feasible phi. No solution found"
1072 print "The target is out of workspace! No solution found."
1075 print "Next phi: ", self.config.q[0]
1079 print "Not expected to see. Solution exists but not feasible!"
1091 Finds all the feasible solutions of the Inverse Kinematic problem for given redundant parameter "phi"
1092 "phi" is the value of the first joint angle "q[0]"
1093 This function does NOT set the configuration so the joints do not change
1095 if not self.config.joint_in_range(0, phi):
1096 print "IK_config error: Given theta0 out of feasible range"
1104 [Q, Q2, d42, d44, a00, d22_plus_d44, foura00d44, alpha] = self.
additional_dims
1107 u = c0*self.
xd[0] + s0*self.
xd[1]
1108 v = (2*self.
a0*u - R2)/Q
1111 A = self.
d2 + v*self.
d4
1113 if genmath.equal(v, 1.0):
1117 In this case, a singularity happens
1119 elif (v > 1.0)
or (v < -1.0):
1124 tt3 = trig.arccos(v)
1127 theta3 = (2*i - 1)*tt3
1128 if self.config.joint_in_range(3,theta3):
1129 s3 = math.sin(theta3)
1133 T34 = genkin.transfer_DH_standard( 0.0 , math.pi/2, 0.0, 0.0, theta3)
1136 w2 = (alpha*v2 + betta*v + gamma)/(1 - v2)
1137 if genmath.equal(w2, 1.0):
1139 elif genmath.equal(w2, 0.0):
1142 print "IK_config error: w^2 is negative, This should never happen! Something is wrong!"
1148 while (m < 2)
and (
not ((w == 0.0)
and (m == 1))):
1153 tt2 = trig.arcsin(s2)
1156 theta2 = trig.angle_standard_range(math.pi*(1 - j) + (2*j - 1)*tt2)
1157 if self.config.joint_in_range(2, theta2):
1158 c2 = math.cos(theta2)
1163 R1 = math.sqrt(A**2 + F**2)
1164 sai1 = math.atan2(F,A)
1165 R1_nul = genmath.equal(R1, 0)
1167 z_R1 = self.
xd[2]/R1
1168 flg = (z_R1 < 1.0)
and (z_R1 > - 1.0)
1173 tt1 = trig.arccos(self.
xd[2]/R1)
1176 theta1 = (2*k - 1)*tt1 - sai1
1177 if self.config.joint_in_range(1, theta1):
1178 s1 = math.sin(theta1)
1179 c1 = math.cos(theta1)
1181 As1Fc1 = self.
a0 + A*s1 + F*c1
1182 X = c0*As1Fc1 - E*s0
1183 Y = s0*As1Fc1 + E*c0
1188 u4 = self.
d2+ c3*self.
d4
1189 u1 = self.
a0 + u3*c1 + u4*s1
1190 AA = np.array([[alpha*d44, d44*betta - 2*d42 , - self.
d2**2 + d44*(gamma -1)],
1191 [0.0 , 2*self.
xd[2]*self.
d4 , 2*self.
xd[2]*self.
d2],
1192 [- d44*(1+alpha) , -betta*d44 , - self.
xd[2]**2 + d44*(1-gamma) ]])
1193 lnda = np.array([c1*c1, c1, 1.0])
1194 vvct = np.array([v*v, v, 1.0])
1196 if vecmat.equal(self.
xd, [X,Y,Z]):
1198 R03 = np.array([[c20*c1 - s20, -c0*s1, -c2s0 - c1*c0*s2],
1199 [c0s2 + c1*c2*s0, -s1*s0, c20 - c1*s20],
1200 [-c2*s1, -c1, s2*s1 ]])
1202 R04 = np.dot(R03, R34)
1203 R47 = np.dot(R04.T, self.
Rd)
1204 tt5 = trig.arccos(R47[2,2])
1207 theta5 = (2*l - 1)*tt5
1208 if self.config.joint_in_range(5, theta5):
1209 s5 = math.sin(theta5)
1210 c5 = math.cos(theta5)
1211 if genmath.equal(s5,0):
1212 assert genmath.equal(R47[2,0], 0)
1216 In this case, only sum of theta4 + theta6 is known
1224 theta6 = trig.arcsincos(s6, c6)
1225 theta4 = trig.arcsincos(s4, c4)
1227 assert genmath.equal(R47[1,0] , c4*s6 + c5*c6*s4)
1228 assert genmath.equal(R47[1,1] , c4*c6 - c5*s4*s6)
1229 assert genmath.equal(R47[0,0] , -s4*s6 + c4*c5*c6)
1230 assert genmath.equal(R47[0,1] , -c6*s4 - c4*c5*s6)
1232 assert self.config.joint_in_range(4, theta4)
1233 assert self.config.joint_in_range(6, theta6)
1235 solution_set.append(np.array([phi, theta1, theta2, theta3, theta4, theta5, theta6]))
1238 solution_set.append(np.array([phi, theta1, theta2, theta3, self.config.q[4], self.config.q[5], self.config.q[6]]))
1247 Finds the solution of the Inverse Kinematic problem for given redundant parameter "phi"
1248 In case of redundant solutions, the one corresponding to the lowest objective function is selected.
1249 property ofuncode specifies the objective function:
1250 ofuncode = 0 (Default) the solution closest to current joint angles will be selected
1251 ofuncode = 1 the solution corresponding to the lowest midrange distance is selected
1252 This function does NOT set the configuration so the joints do not change
1256 if len(solution_set) == 0:
1262 for i
in range(0, len(solution_set)):
1263 solution = solution_set[i]
1265 delta = np.linalg.norm(trig.angles_standard_range(solution - self.config.q))
1267 P = trig.angles_standard_range(solution - self.config.qm)*self.config.w
1268 delta = np.dot(P.T,P)
1270 print "IK_config error: Value ",self.
ofuncode,
" for argument ofuncode is not supported"
1273 if delta < delta_min:
1277 return solution_set[i_min]
1279 def ts_project(self, js_traj, phi_start = 0.0, phi_end = None):
1281 projects the given jointspace trajectory into the taskspace
1282 The phase starts from phi_start and added by delta_phi in each step.
1283 if at any time the joint values are not feasible, the process is stopped.
1287 phi_end = js_traj.phi_end
1289 ori_traj = trajlib.Orientation_Trajectory_Polynomial()
1290 pos_traj = trajlib.Trajectory_Polynomial()
1291 if phi_end > js_traj.phi_end:
1292 phi_end = js_traj.phi_end
1297 if (phi > phi_end)
or genmath.equal(phi, phi_end, epsilon = 0.1*self.
dt):
1300 js_traj.set_phi(phi)
1301 if self.
set_config(js_traj.current_position):
1303 ori_traj.add_point(phi - phi_start, geo.Orientation_3D(self.
wrist_orientation()))
1306 return (pos_traj, ori_traj)
1308 def js_project(self, pos_traj, ori_traj = None, phi_start = 0.0, phi_end = None, relative = True, traj_capacity = 2, traj_type = 'regular'):
1310 projects the given taskspace pose trajectory into the jointspace using analytic inverse kinematics.
1311 The phase starts from phi_start and added by self.dt in each step.
1312 at any time, if a solution is not found, the process stops
1314 self.config.qm = 0.5*(self.config.ql + self.config.qh)
1315 keep_q = np.copy(self.config.q)
1317 if ori_traj ==
None:
1318 ori_traj = trajlib.Orientation_Path()
1320 ori_traj.add_point(pos_traj.phi_end, geo.Orientation_3D(self.
wrist_orientation()))
1323 phi_end = min(pos_traj.phi_end, ori_traj.phi_end)
1325 if (phi_end > pos_traj.phi_end)
or (phi_end > ori_traj.phi_end):
1326 phi_end = min(pos_traj.phi_end, ori_traj.phi_end)
1328 if traj_type ==
'regular':
1329 jt = trajlib.Trajectory(dimension = 7, capacity = traj_capacity)
1330 elif traj_type ==
'polynomial':
1331 jt = trajlib.Trajectory_Polynomial(dimension = 7, capacity = traj_capacity)
1333 assert False,
"\n Unknown Trajectory Type \n"
1337 jt.pos_max = self.config.qh
1338 jt.pos_min = self.config.ql
1341 pos_traj.set_phi(phi)
1342 ori_traj.set_phi(phi)
1347 self.
set_target(pos_traj.current_position, ori_traj.current_orientation[
'matrix'])
1350 jt.add_position(0.0, pos = self.config.q)
1357 if (phi > phi_end)
or genmath.equal(phi, phi_end, epsilon = 0.1*self.
dt):
1361 pos_traj.set_phi(phi)
1362 ori_traj.set_phi(phi)
1363 p = p0 + pos_traj.current_position
1364 self.
set_target(p, ori_traj.current_orientation.matrix())
1366 self.config.qm = np.copy(self.config.q)
1372 jt.add_position(phi = phi - phi_start, pos = np.copy(self.config.q))
1376 if traj_type ==
'polynomial':
1380 self.config.qm = 0.5*(self.config.qh + self.config.ql)
1386 ers =
'Joint values computed from magiks are not feasible'
1387 assert self.
set_config(self.ik.q), genpy.err_str(__name__, self.__class__.__name__, sys._getframe().f_code.co_name, ers)
1391 This function finds and returns the set from which q0 is allowed to be chosen so that
1392 joint angles q0 , q2 and q3 in the analytic solution to the inverse kinematic problem are in their range.
1393 Consider that being q0 in the permission set, does not guarantee that all q0, q2 and q3 are in their ranges, but
1394 it means that if q0 is out of permission set, one of the joints q0, q2 or q3 will definitely be out of their
1396 In other words, q0 being in perm. set, is a necessary but not sufficient condition for three joints
1397 q0, q2 and q3 to be in their range.
1398 Permission set is broader than "confidence set" which ensures all q0, q2 and q3 to be in range.
1399 (has both necessary and sufficient conditions)
1400 The output depends on the defined joint limits and the desired endeffector pose but does not depend
1401 on the current position of the joints.
1403 if self.
Phi !=
None:
1407 [Q, Q2, d42, d44, a00, d22_plus_d44, foura00d44, alpha] = self.
additional_dims
1411 int_theta1 = interval([self.config.ql[1],self.config.qh[1]])
1412 int_lnda = imath.cos(int_theta1)
1413 int_lnda2 = int_lnda**2
1415 AA = np.array([[alpha*d44, d44*betta - 2*d42 , - self.
d2**2 + d44*(gamma -1)],
1416 [0.0 , 2*self.
xd[2]*self.
d4 , 2*self.
xd[2]*self.
d2],
1417 [- d44*(1+alpha) , -betta*d44 , - self.
xd[2]**2 + d44*(1-gamma) ]])
1419 int_alpha = interval(AA[0,0])*int_lnda2 + interval(AA[1,0])*int_lnda + interval(AA[2,0])
1420 int_betap = interval(AA[0,1])*int_lnda2 + interval(AA[1,1])*int_lnda + interval(AA[2,1])
1421 int_gamma = interval(AA[0,2])*int_lnda2 + interval(AA[1,2])*int_lnda + interval(AA[2,2])
1423 (alpha_l, alpha_h) = int_alpha[0]
1424 (betap_l, betap_h) = int_betap[0]
1425 (gamma_l, gamma_h) = int_gamma[0]
1427 Vp_1l = genmath.solve_quadratic_inequality(- alpha_l, - betap_l, -gamma_l)
1428 Vp_1h = genmath.solve_quadratic_inequality( alpha_h, betap_h, gamma_h)
1429 Vn_1l = genmath.solve_quadratic_inequality(- alpha_l, - betap_h, -gamma_l)
1430 Vn_1h = genmath.solve_quadratic_inequality( alpha_h, betap_l, gamma_h)
1432 V1 = (Vp_1l & Vp_1h & interval([0.0,1.0])) | (Vn_1l & Vn_1h & interval([-1.0,0.0]))
1436 int_theta2 = interval([self.config.ql[2],self.config.qh[2]])
1437 int_w = imath.sin(int_theta2)**2
1442 V2l = genmath.solve_quadratic_inequality(alpha + wl, betta, gamma - wl) & interval([-1.0, 1.0])
1443 V2h = genmath.solve_quadratic_inequality(- alpha - wh, - betta, wh - gamma) & interval([-1.0, 1.0])
1451 int_theta3 = interval([self.config.ql[3],self.config.qh[3]])
1452 V3 = imath.cos(int_theta3)
1460 denum = 2*self.
a0*math.sqrt(r2)
1462 b = 2*self.
d2*self.
d4/denum
1466 for i
in range(0, nv):
1467 Ui = interval(a) - interval(b)*interval(V[i])
1470 zl = trig.arcsin(uli)
1471 zh = trig.arcsin(uhi)
1473 B1 = trig.standard_interval(zl - sai, zh - sai)
1474 B2 = trig.standard_interval(math.pi- zh - sai, math.pi- zl - sai)
1476 Phi1_3 = Phi1_3 | B1 | B2
1480 Phi0 = interval([self.config.ql[0], self.config.qh[0]])
1482 self.
Phi = genmath.connect_interval(Phi0 & Phi1_3)
1488 Updates the feasible interval for the growth of the redundant parameter according to
1489 the specified joint limits and the current value of the joints
1491 if self.
Delta ==
None:
1495 for i
in range(0, 7):
1496 if (
not genmath.equal(J[i], 0.0))
and (
not genmath.equal(self.config.w[i], 0.0)):
1497 d1 = (self.config.ql[i] - self.config.q[i])/J[i]
1498 d2 = (self.config.qh[i] - self.config.q[i])/J[i]
1499 dli1 = genmath.binary_choice(d1,d2,J[i])
1500 dhi1 = genmath.binary_choice(d2,d1,J[i])
1505 dli2 = genmath.binary_choice(- d, d, J[i])
1506 dhi2 = genmath.binary_choice( d, - d, J[i])
1514 if genmath.equal(dli1, 0.0):
1516 if genmath.equal(dhi1, 0.0):
1522 self.
Delta = self.
Delta & interval([dli1, dhi1]) & interval([dli2, dhi2])
1523 if len(self.
Delta) == 0:
1524 print "Error: self.Delta is empty:"
1526 print "interval([dli1, dhi2]): ", interval([dli1, dhi1])
1527 print "interval([dli1, dhi2]): ", interval([dli2, dhi2])
Rd
A rotation matrix specifying the desired endeffector orientation for the IK problem.
def all_joints_in_range
This function is used to check if all values of the given joint array are in their feasibility range...
Delta
Delta A variable of type Interval() containing the feasible interval for the growth of redundant para...
def elbow_position
Use this function to get the current position of the elbow joint center.
def moveto_optimal
Moves the joints within the solution manifold towards optimum configuration.
JRJ
A numpy array containing the Joint Redundancy Jacobian of the arm.
def objective_function
Use this function to find the current value of the objective function.
def in_target
Use this function to check if the endeffector is in the target pose or not.
def set_config
Sets the robot configuration to the desired given joint values.
def closest_feasible_phi
This function should be used when given redundant parameter is within the given permission set (PS) ...
qh
A numpy array of size 7 containing the upper bounds of the arm joints.
def joint_stepsize_interval
This function gives an interval for the magnitude of the arm joint angles correction vector...
def set_config
Use this function to set the joint configuration to the given desired values.
q
A numpy array of size 7 containing the current values of the joints.
a0
A float specifying the value of in the DH parameters of the arm.
qm
A numpy array of size 7 containing a set of reference values for the joint angles.
config
An instance of class PR2_ARM_CONFIGURATION() containing the jointspace properties and methods of the ...
xd
A numpy vector of size 3 specifying the desired endeffector position for the IK problem.
def pose_metric
Use this function to get the displacement between the actual and desired wrist poses The metric retur...
orientation_respected
A boolean specifying if orientation of the endeffector should be respected or not in finding the Inve...
def permission_set_position
ql
A numpy array of size 7 containing the lower bounds of the arm joints.
Contains properties and methods managing the kinematics of the PR2 robot arm.
def optimal_config
Finds the optimal value for the redundant parameter that minimizes the cost function and returns the...
def __init__
The Class Constructor:
w
A numpy array of size 7 containing the weights of each joint in the objective function.
q_dot
A numpy array of size 7 containing the current velocities of the joints.
wrist_position_vector
An numpy array of size 3 containing the position of the wrist joint center w.r.t. ...
def set_target
Sets the endeffector target to a desired position and orientation.
def midrange_error
Use this function to get the midrange error vector.
ofuncode
An integer between 0 and 1 specifying the objective function code.
def joint_redundancy_jacobian
Use this function to get the Joint Redundancy Jacobian vector of the arm.
def wrist_orientation
Use this function to get the current orientation of the gripper(Endeffector).
def div_theta_err
protected
d2
A float specifying the value of in the DH parameters of the arm.
Contains properties and methods regarding the PR2 arm joint-space.
wrist_orientation_matrix
A numpy matrix representing the orientation of the endeffector (gripper) w.r.t.
Phi
Phi A variable of type Interval() containing the feasible interval for the redundant parameter or th...
def ik_direction
Solves the position based inverse kinematics and returns a direction in the jointspace towards the so...
def restore_config
returns the current configuration and sets the given configuration.
def joint_in_range
This function is used to check if a given value for specific joint is in its feasibility range...
q_ddot
A numpy array of size 7 containing the current accelerations of the joints.
def closest_config_metric
protected
d4
A float specifying the value of in the DH parameters of the arm.
def position_permission_workspace
Use this method to get the permission range of x, y and z of the endeffector.
def wrist_position
Use this function to get the current position of the wrist joint center.
def __init__
The Class Constructor:
def feasible_joint_stepsize
Given a direction for joint correction and a joint speed limit, this function returns the maximum fea...