MAGIKS  1.1
Manipulator General Inverse Kinematic Solver
 All Classes Namespaces Files Functions Variables Pages
pr2_arm_kinematics.py
Go to the documentation of this file.
1 ## @file PR2_arm_kinematics.py
2 # @brief Contains specific functions that define all geometric and kinematic parameters for PR2 robot arm
3 # @author Nima Ramezani Taghiabadi
4 #
5 # PhD Researcher
6 # Faculty of Engineering and Information Technology
7 # University of Technology Sydney (UTS)
8 # Broadway, Ultimo, NSW 2007, Australia
9 # Phone No. : 04 5027 4611
10 # Email(1) : nima.ramezani@gmail.com
11 # Email(2) : Nima.RamezaniTaghiabadi@uts.edu.au
12 # @version 6.0
13 #
14 # Last Revision: 10 July 2015
15 
16 '''
17 Changes from ver 5.0:
18 
19 '''
20 
21 import copy, time, math
22 import numpy as np, general_python as genpy
23 
24 from interval import interval, inf, imath
25 from sets import Set
26 
27 from math_tools import general_math as genmath
28 from math_tools.geometry import trigonometry as trig, trajectory as trajlib, geometry as geo
29 from math_tools.algebra import vectors_and_matrices as vecmat
30 from magiks.magiks_core import general_magiks as genkin
31 
32 drc = math.pi/180.00
33 
34 #default_ql = drc*np.array([-130.0, 70.0 , -180.0, 0.0, -180.0, 0.0, -180.0])
35 #default_qh = drc*np.array([ 40.0, 170.0, 44.0, 130.0, 180.0, 130.0, 180.0])
36 
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])
39 
40 default_W = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
41 
43  '''
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
47  '''
48  def __init__(self):
49  import sympy
50  from sympy import Symbol, simplify
51 
52  n = 7
53 
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]
59 
60  ca = [math.cos(alpha[i]) for i in range(n)]
61  sa = [math.sin(alpha[i]) for i in range(n)]
62 
63  for i in range(len(ca)):
64  ca[i] = genmath.round(ca[i])
65  sa[i] = genmath.round(sa[i])
66 
67  # A[i] transfer matrix from link i-1 to i according to standard DH parameters:
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)]
72 
73  # B[i] transfer matrix from link i to i-1 or B[i] = inv(A[i])
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)]
78 
79  # R[i] rotation matrix from link i-1 to i according to standard DH parameters:
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)]
83 
84  # T[i] transfer matrix from link -1(ground) to i
85  self.T = np.copy(self.A)
86  for i in range(n-1):
87  self.T[i + 1] = np.dot(self.T[i],self.A[i + 1])
88 
89  # Desired Pose:
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') ],
93  [ 0 , 0 , 0 , 1 ]])
94 
95  self.x_d = T_d[0:3, 3]
96  self.R_d = T_d[0:3, 0:3]
97 
98  '''
99  "p_W" denotes the position vector of the wrist joint center
100  "R_W" denotes the orientation of the gripper (Endeffector Orientation)
101  '''
102  self.T_W = self.T[6]
103  self.p_W = self.T_W[0:3, 3]
104  self.R_W = self.T_W[0:3, 0:3]
105 
106  '''
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.
109  '''
110 
111  self.p_EF_W = np.array([0.0, 0.0, Symbol('d7')])
112 
113  self.H = np.copy(self.T)
114  self.H[n - 1] = np.copy(T_d)
115 
116  # H[i] transfer matrix from link -1(ground) to i calculated from inverse transform
117  for i in range(n-1):
118  self.H[n - i - 2] = np.dot(self.H[n - i - 1], self.B[n - i - 1])
119 
120  self.div_theta_err = sympy.Matrix([
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') ]])
127 
128  self.div_phi_err = sympy.Matrix([Symbol('e10') , 0 , 0 , Symbol('e40') , Symbol('e50') , Symbol('e60') ])
129 
130  e = self.div_theta_err
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]
137 
138  self.RJ = sympy.Matrix([J1,J2,J3,J4,J5,J6])
139 
140 
141 ## @brief Contains properties and methods regarding the PR2 arm joint-space.
142 # This class has methods and properties for managing the joint-space of a PR2 robot arm.
143 # It contains the joint position, velocity and acceleration values and joint limits.
145  ## The Class Constructor:
146  # @param ql A numpy array of size 7 containing the lower bounds of the arm joints
147  # @param qh A numpy array of size 7 containing the upper bounds of the arm joints
148  # @param W A numpy array of size 7 containing the weights of each joint in the objective function.
149  #
150  # The joint weights will be used in the optimization of redundancy.
151  # If the weight of a joint is 0, the joint is considered as unlimited.
152  # This means the value of that joint does not need to be in a specific range.
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"
155  ## A numpy array of size 7 containing the current values of the joints.
156  # This property should not be manipulated by the user. Use method Set_Config() to change this property.
157  # The joints are in the following order:
158  # q[0] : Shoulder Pan Joint,
159  # q[1] : Shoulder Lift Joint,
160  # q[2] : Upper Arm Roll Joint,
161  # q[3] : Elbow Flex Joint,
162  # q[4] : Forearm Roll Joint,
163  # q[5] : Wrist Flex Joint,
164  # q[6] : Wrist Roll Joint
165  self.q = (qh + ql)/2
166 
167  ## A numpy array of size 7 containing the current velocities of the joints.
168  self.q_dot = np.zeros(7)
169 
170  ## A numpy array of size 7 containing the current accelerations of the joints.
171  self.q_ddot = np.zeros(7)
172 
173  ## A numpy array of size 7 containing the lower bounds of the arm joints
174  self.ql = ql
175 
176  ## A numpy array of size 7 containing the upper bounds of the arm joints
177  self.qh = qh
178 
179  ## A numpy array of size 7 containing a set of reference values for the joint angles.
180  #
181  # This parameter can be used as reference joint values for redundancy optimization.
182  # The redundancy will be used to set the joints as close as possible to these reference values.
183  # This property is by default set as the middle of joint ranges.
184  self.qm = (qh + ql)/2
185 
186  ## A numpy array of size 7 containing the weights of each joint in the objective function.
187  #
188  # The joint weights will be used in the optimization of redundancy.
189  # If the weight of a joint is 0, the joint is considered as unlimited.
190  # This means the value of that joint does not need to be in a specific range.
191  self.w = np.zeros(7)
192 
193  ##
194  # \b Note:
195  # --------
196  # Only ql, qh, qm and W can be manipulated by the user.
197 
198  for i in range(0,7):
199  self.w[i] = math.sqrt(W[i])
200 
201  # sets all angles to the midrange by default
202  self.set_config(self.qm)
203 
204  ## This function is used to check if a given value for specific joint is in its feasibility range
205  # @param i An integer between 0 to 6 specifying the joint number to be checked
206  # @param qi A float parameter specifying the value for the i-th joint
207  # @return A boolean: True if the given joint angle qi is in feasible range for the i-th joint (within the specified joint limits for that joint)
208  def joint_in_range(self,i, qi):
209  qi = trig.angle_standard_range(qi)
210  if abs(qi - self.ql[i]) < genmath.epsilon:
211  qi = self.ql[i]
212  if abs(qi - self.qh[i]) < genmath.epsilon:
213  qi = self.qh[i]
214 
215  return ((qi <= self.qh[i]) and (qi >= self.ql[i]))
216 
217  ## This function is used to check if all values of the given joint array are in their feasibility range
218  # @param qd A numpy array of size 7 containing the values to be checked
219  # @return A boolean: If The given joints "qd" are out of the range specified by properties: ql and qh, returns False, otherwise returns True
220  def all_joints_in_range(self, qd):
221  flag = True
222  for i in range(0, 7):
223  if not genmath.equal(self.w[i], 0.0):
224  flag = flag and self.joint_in_range(i, qd[i])
225  return flag
226 
227  ## Use this function to get the midrange error vector
228  # @param None
229  # @return A numpy array of size 7 containing the weighted deviations of the joints from their midrange values
230  def midrange_error(self):
231  return trig.angles_standard_range(self.q - self.qm)*self.w
232 
233  ## This function gives an interval for the magnitude of the arm joint angles correction vector.
234  # @param direction A numpy array of size 7 specifying the direction of change
235  # @param max_speed A float parameter specifying the maximum feasible speed for a joint change. (Set by infinity by default)
236  # @param delta_t The step time in which the change(correction) is to be applied.
237  # @return An instance of type <a href="http://pyinterval.googlecode.com/svn/trunk/html/index.html">Interval()</a>
238  def joint_stepsize_interval(self, direction, max_speed = genmath.infinity, dt = 0.001):
239  '''
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
244  are feasible.
245  '''
246  etta_l = []
247  etta_h = []
248 
249  for i in range(7):
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]))
256 
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]))
260 
261  if (etta_l == []) or (etta_h == []):
262  return (0.0, 0.0)
263  else:
264  return (max(etta_l), min(etta_h))
265 
266  ## Use this function to set the joint configuration to the given desired values.
267  # @param qd A numpy array of size 7 containing the desired joint values to be set
268  # @return A boolean: True if the given joints are in range and the configuration is set, False if not
269  def set_config(self, qd):
270  '''
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()
274  '''
275  if not len(qd) == 7:
276  print "set_config error: Number of input elements must be 7"
277  return False
278 
279  if self.all_joints_in_range(qd):
280  for i in range(0, 7):
281  if genmath.equal(self.w[i], 0.0):
282  self.q[i] = qd[i]
283  else:
284  self.q[i] = trig.angle_standard_range(qd[i])
285 
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)]
288 
289  [s0, s1, s2, s3, s4, s5, s6] = self.s
290  [c0, c1, c2, c3, c4, c5, c6] = self.c
291  ## protected
292  self.s1_mult1 = [s1*s0]
293  [s10] = self.s1_mult1
294 
295  ## protected
296  self.s2_mult1 = s2*np.array([s0, s1, s2, s10])
297  [s20,s21, s22, s210] = self.s2_mult1
298 
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
301 
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
304 
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
307 
308  # \cond
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
311 
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
314 
315  self.s0_mult = s0*np.array([c21,c31,c321])
316  [c21s0,c31s0,c321s0] = self.s0_mult
317 
318  self.s1_mult2 = s1*np.array([c10,c20,c30, c32,c320])
319  [c10s1,c20s1,c30s1, c32s1,c320s1] = self.s1_mult2
320 
321  self.s2_mult2 = s2*np.array([c10,c20,c30, c32,c310])
322  [c10s2,c20s2,c30s2, c32s2,c310s2] = self.s2_mult2
323 
324  self.s3_mult2 = s3*np.array([c10, c20, c30, c21, c210,s32])
325  [c10s3, c20s3, c30s3, c21s3, c210s3,s332] = self.s3_mult2
326 
327  self.cs_mult = [c10*s32, c31*s20, s5*s4]
328  [c10s32, c31s20, s54] = self.cs_mult
329 
330  self.c5_mult = c5*np.array([c4, s4, s5])
331  [c54, c5s4, c5s5] = self.c5_mult
332 
333  self.s6_mult = s6*np.array([s4, s5, c4, c5, c54, s54])
334  [s64, s65, c4s6, c5s6, c54s6, s654] = self.s6_mult
335 
336  self.c6_mult = c6*np.array([c4, c5, s4, s5, c54, s54])
337  [c64, c65, c6s4, c6s5, c654, C6s54] = self.c6_mult
338 
339  self.mid_dist_sq = None
340  '''
341  Do not set any other environmental variables here
342  '''
343  # \endcond
344  return True
345  else:
346  print "Error from PR2_ARM.set_config(): Given joints are not in their feasible range"
347  for i in range(7):
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]
352 
353  return False
354 
355  ## protected
356  def closest_config_metric(self, q):
357  dist = 0
358  cc = np.zeros(7)
359  for i in range(7):
360  (qq, dd) = trig.closest_angle_metric(self.q[i], q[i])
361  dist = dist + dd
362  cc[i] = qq
363  return (cc, dd)
364 
365  ## Use this function to find the current value of the objective function
366  # @param None
367  # @return A float containing the current value of the objective function
368  # (deviation from midrange). This objective function depends on the values of the joints
370  if self.mid_dist_sq == None:
371  e = self.midrange_error()
372  self.mid_dist_sq = np.dot(e.T,e)
373  return self.mid_dist_sq
374 
375 ## @brief Contains properties and methods managing the kinematics of the PR2 robot arm.
376 # This class contains all properties and methods required for forward and inverse kinematic computations and kinematic control of the arm
377 class PR2_ARM():
378 
379  ## The Class Constructor:
380  # @param a0 A float specifying the value of /f$ a_0 /f$ in the DH parameters of the arm
381  # @param d2 A float specifying the value of /f$ d_2 /f$ in the DH parameters of the arm
382  # @param d4 A float specifying the value of /f$ d_4 /f$ in the DH parameters of the arm
383  # @param ql A numpy array of size 7 containing the lower bounds of the arm joints
384  # @param qh A numpy array of size 7 containing the upper bounds of the arm joints
385  # @param W A numpy array of size 7 containing the weights of each joint in the objective function.
386  #
387  # The joint weights will be used in the optimization of redundancy.
388  # If the weight of a joint is 0, the joint is considered as unlimited.
389  # This means the value of that joint does not need to be in a specific range.
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):
391 
392  ## A boolean specifying if orientation of the endeffector should be respected or not in finding the Inverse Kinematic solution
393  self.orientation_respected = True
395  self.silent = True
396 
397  ## An instance of class PR2_ARM_CONFIGURATION() containing the jointspace properties and methods of the arm
398  self.config = PR2_ARM_Configuration(ql = ql, qh = qh, W = W)
399 
400  ## A \f$ 3 \times 3 \f$ rotation matrix specifying the desired endeffector orientation for the IK problem.
401  # Recommended not to be set directly. Always use function set_target() to change this property.
402  self.Rd = None
403 
404  ## A numpy vector of size 3 specifying the desired endeffector position for the IK problem.
405  # Recommended not to be set directly. Always use function set_target() to change this property.
406  self.xd = None
407 
408  ## A float specifying the value of \f$ a_0 \f$ in the DH parameters of the arm
409  self.a0 = a0
410 
411  ## A float specifying the value of \f$ d_2 \f$ in the DH parameters of the arm
412  self.d2 = d2
413 
414  ## A float specifying the value of \f$ d_4 \f$ in the DH parameters of the arm
415  self.d4 = d4
417  self.dt = 0.01
418  self.max_js = 2.0 # (Rad/sec)
419  self.max_ja = 100.0 # (Rad/sec^2)
420 
421  l2 = d2**2 + d4**2 - a0**2
422 
423  assert l2 > 0, "Error from " + __name__ + "Constructor: Invalid dimensions or DH parameters"
425  self.l = math.sqrt(l2)
426 
427  d42 = d4*d2
428  Q = -2*d42
429  Q2 = Q**2
430  d44 = d4**2
431  a00 = a0**2
432 
433  d22_plus_d44 = d2*d2 + d44
434  foura00d44 = 4*a00*d44
435  alpha = - Q2/foura00d44
436 
437  ## protected
438  self.additional_dims = [Q, Q2, d42, d44, a00, d22_plus_d44, foura00d44, alpha]
439 
440  ## protected
441  self.l_se = [0.0, - d2, 0.0]
442  self.l_ew = [0.0, 0.0, d4]
443 
444  ## An integer between 0 and 1 specifying the objective function code
445  self.ofuncode = 0
446 
447  ## An numpy array of size 3 containing the position of the wrist joint center w.r.t. the shoulder pan joint center in torso coordinate system
448  # Recommended to be read only. Calling function wrist_position() changes the value of this property.
449  self.wrist_position_vector = None
450 
451  self.in_target_flag = None
452 
453  ## A \f$ 3 \times 3 \f$ numpy matrix representing the orientation of the endeffector (gripper) w.r.t. the torso
454  # Recommended to be read only. Calling function wrist_orientation() changes the value of this property.
455  self.wrist_orientation_matrix = None
456 
457  ## A numpy array containing the \b Joint Redundancy Jacobian of the arm.
458  # The Joint Redundancy Jacobian represents the derivatives of the joints w.r.t. the redundant parameter
459  # \f[
460  # J_{ij} = \frac {\partial \theta_i }{\partial \phi_j}
461  # \f]
462  self.JRJ = None
463 
464  ## protected
465  self.E = None
466 
467  ## protected
468  self.F = None
469 
470  ## Phi A variable of type <a href="http://pyinterval.googlecode.com/svn/trunk/html/index.html">Interval()</a>
471  ## containing the feasible interval for the redundant parameter \f$ \phi \f$ or the first joint angle (Shoulder Pan Joint)
472  self.Phi = None
473 
474  ## Delta A variable of type <a href="http://pyinterval.googlecode.com/svn/trunk/html/index.html">Interval()</a>
475  # containing the feasible interval for the growth of redundant parameter (\f$ \Delta \phi \f$)
476  self.Delta = None
477 
478  if run_magiks:
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)
486  self.magiks_running = True
487  else:
488  self.magiks_running = False
490  self.use_magiks = False
491 
492  # Sets the target initially as the endeffector pose corresponding to the midrange joint configuration:
493  self.set_target(self.wrist_position(), self.wrist_orientation())
494 
495  ## Sets the robot configuration to the desired given joint values
496  # @param qd A numpy array of 7 elements containing the values of the given joints
497  # @return A boolean: True if the given configuration is successfully set, False if the given configuration is not successfully set.
498  # (If False is returned, the configuration will not chenge)
499  def set_config(self, qd):
500  '''
501  Example:
502 
503  arm = PR2_ARM()
504  qd = np.zeros(7)
505  arm.set_config(qd)
506  print arm.config.q
507  print arm.wrist_position()
508  print arm.wrist_orientation()
509  '''
510  if self.magiks_running:
511  permit = self.ik.set_config(qd) and self.config.set_config(qd)
512  else:
513  permit = self.config.set_config(qd)
514 
515  if permit:
516  self.wrist_position_vector = None
517  self.wrist_orientation_matrix = None
518  self.in_target_flag = None
519  self.JRJ = None
520  self.E = None
521  self.F = None
522  self.Delta = None
523  return True
524  else:
525  return False
526 
527  ## Sets the endeffector target to a desired position and orientation.
528  # @param target_position A numpy array of 3 elements specifying the desired endeffector position
529  # @param target_orientation A \f$ 3 \times 3 \f$ numpy rotation matrix representing the desired endeffector orientation
530  # @return A boolean: True if the given pose is successfully set, False if the given pose is not successfully set because of an error
531  # (If False is returned, properties self.xd and self.RD will not chenge)
532  def set_target(self, target_position, target_orientation):
533 
534  assert genmath.equal(np.linalg.det(target_orientation), 1.0)
535  self.xd = target_position
536  self.Rd = target_orientation
537  if self.use_magiks:
538  self.ik.set_target([target_position], [geo.Orientation_3D(target_orientation)])
539 
540  [Q, Q2, d42, d44, a00, d22_plus_d44, foura00d44, alpha] = self.additional_dims
541 
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
546  '''
547  alpha, betta and gamma are selected so that w^2 * (1 - v^2) = alpha*v^2 + betta*v + gamma
548  '''
549 
550  T2 = R2**2 - 4*a00*r2
551  betta = - 2*R2*Q/foura00d44
552  gamma = - T2/foura00d44
553 
554  self.Phi = None
555  self.Delta = None
557  self.target_parameters = [r2, ro2, R2, T2, alpha, betta, gamma, sai]
558 
559  ## Use this function to get the current position of the elbow joint center.
560  # @param None
561  # @return A numpy vector of size 3 containing the cartesian coordinates of the elbow joint center w.r.t. the shoulder pan joint in the torso CS.
562  def elbow_position(self):
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])
567 
568  ## Use this function to get the current position of the wrist joint center.
569  # @param None
570  # @return A numpy vector of size 3 containing the cartesian coordinates of the wrist joint center w.r.t. the shoulder pan joint in the torso CS.
571  def wrist_position(self):
572  '''
573  Returns the cartesian coordiantes of the origin of the wrist. The origin of the wrist is the wrist joint center
574  '''
575  if self.wrist_position_vector == None:
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
585 
586  X = c0*self.a0 + c0s1*self.d2 + (c30s1 + c210s3 - s320)*self.d4
587 
588  Y = s0*self.a0 + s10*self.d2 + (c3s10 + c0s32 + c21s30)*self.d4
589 
590  Z = c1*self.d2 + (c31 - c2s31)*self.d4
591 
592  self.wrist_position_vector = np.array([X, Y, Z])
593 
594  return copy.copy(self.wrist_position_vector)
595 
596  ## Use this function to get the current orientation of the gripper(Endeffector).
597  # @param None
598  # @return A \f$ 3 \times 3 \f$ numpy rotation matrix containing the current orientation of the gripper w.r.t. the torso.
599  def wrist_orientation(self):
600 
601  if self.wrist_orientation_matrix == None:
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
614 
615  R03 = np.array([[-s20 + c210, -c0s1, -c2s0 - c10s2],
616  [c0s2 + c21s0, -s10, c20 - c1s20],
617  [-c2s1, -c1, s21]])
618 
619  R47 = np.array([[-s64 + c654, -c6s4 - c54s6, c4*s5],
620  [c4s6 + c65*s4, c64 - c5*s64, s54],
621  [-c6s5, s65, c5]])
622 
623  R34 = np.array([[ c3, 0, s3 ],
624  [ s3, 0, -c3 ],
625  [ 0, 1, 0 ]])
626 
627  self.wrist_orientation_matrix = np.dot(np.dot(R03, R34), R47)
628 
629  return copy.copy(self.wrist_orientation_matrix)
630 
631  ## Use this function to check if the endeffector is in the target pose or not.
632  # @param norm_precision A float specifying the required precision for the norm of both position and orientation error
633  # @return A boolean: True if the norm of differences between the actual and desired poses of the endeffector are smaller than \a norm_precision, False if not.
634  def in_target(self, norm_precision = 0.01):
635  if self.use_magiks:
636  return self.ik.in_target()
637  else:
638  if self.in_target_flag == None:
639  self.in_target_flag = vecmat.equal(self.xd, self.wrist_position(), epsilon = norm_precision) and vecmat.equal(self.Rd, self.wrist_orientation(), epsilon = norm_precision)
640  return self.in_target_flag
641  ## protected
642  def div_phi_err(self):
643  '''
644  '''
645  if self.F == None:
646  self.div_theta_err()
647 
648  return copy.copy(self.F)
649 
650  ## protected
651  def div_theta_err(self):
652  '''
653  '''
654  if self.E == None:
655  [[r11, r12, r13],
656  [r21, r22, r23],
657  [r31, r32, r33]] = self.Rd
658 
659  [s0, s1, s2, s3, s4, s5, s6] = self.config.s
660  [c0, c1, c2, c3, c4, c5, c6] = self.config.c
661 
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
677 
678  [Q, Q2, d42, d44, a00, d22_plus_d44, foura00d44, alpha] = self.additional_dims
679 
680  [r2, ro2, R2, T2, alpha, betta, gamma, sai] = self.target_parameters
681 
682  self.E = np.zeros((7,7))
683  self.F = np.zeros(7)
684 
685  self.E[0,0] = 1.0
686 
687  self.E[1,3] = - Q*s3
688 
689  self.E[2,2] = - 2*c2*s332
690  self.E[2,3] = - 2*alpha*c3s3 - betta*s3 - 2*c3*s322
691 
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
695 
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
698 
699  self.E[4,3] = r13*(- c3s20 + c3210 - c0s31) + r23*(c30s2 + c321s0 - s310) + r33*(- c1s3 - c32s1)
700  self.E[4,5] = s5
701 
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
706 
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)
710  self.E[6,5] = c65
711  self.E[6,6] = - s65
712 
713  self.F[0] = -1.0
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)
718 
719  return copy.copy(self.E)
720 
721  ## Use this function to get the Joint Redundancy Jacobian vector of the arm.
722  # Since the robot arm has 7 DOF, there is only one redundant parameter.
723  # In this case, the \em Joint Redundancy Jacobian (JRJ) is a vector of 7 elements:
724  # \f[
725  # J_i = \frac {\partial \theta_i }{\partial \phi}
726  # \f]
727  # This function should be called when the endeffector is in target. Otherwise, the output will not be correct.
728  # @param None
729  # @return A numpy vector of size 7 containing the derivative of each joint w.r.t. the redundant parameter $f \phi $f
730  def joint_redundancy_jacobian(self):
731  if self.JRJ == None:
732 
733  E = self.div_theta_err()
734  F = self.div_phi_err()
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):
736  return None
737  else:
738  self.JRJ = np.zeros(7)
739 
740  self.JRJ[0] = 1.0
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]
744 
745  self.JRJ[5] = - (F[4] + np.dot(E[4,1:4],self.JRJ[1:4]))/E[4,5]
746  #J[5] = - (F[4,0] + F[4,1]*J[1] + F[4,2]*J[2] + F[4,3]*J[3])/F[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]
749  #F60*J0 + F61*J1 + F62*J2 + F63*J3 + F64*J4 + F65*J5 + F66*J6 = 0 ==> J6 = - (F60 + F61*J1 + F62*J2 + F63*J3 + F64*J4 + F65*J5)/ J66
750 
751  return copy.copy(self.JRJ)
752 
753  ## protected
754  def grown_phi(self, eta, k = 0.99, respect_js = False):
755  '''
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
762  '''
763  Delta = self.delta_phi_interval(respect_js = respect_js)
764 
765  # if Delta contains more than one interval, then we need to find which interval contains zero
766 
767  assert len(Delta) > 0
768  j = 0
769  while (j < len(Delta)):
770  if 0.0 in interval(Delta[j]):
771  (dl,dh) = Delta[j]
772  j = j + 1
773 
774  if eta in Delta:
775  return self.config.q[0] + eta
776  elif eta >= dh: # if zero is not in any of the intervals, this line will raise an error because dh is not defined
777  return self.config.q[0] + k*dh
778  else:
779  assert eta <= dl # eta must now be smaller than Delta_l
780  return self.config.q[0] + k*dl
781 
782  ## Use this method to get the permission range of x, y and z of the endeffector.
783  # If the desired position for the endeffector(wrist joint center) is outside the permission range, then there is definitely no solution for the IK problem.
784  # The inverse of this conditional statement is not necessarily true.
785  # @param fixed An array of booleans of size 4, specifying if the corresponding joint is fixed or free
786  # The array size is 4 because only the first four joints (\f$ q_0, q_1, q_2, q_3 \f$) influence the position of the EE
787  # @return an array of 3 intervals, corresponding to x, y and z
788  def position_permission_workspace(self,fixed):
789  '''
790  Example:
791  '''
792  int_c = []
793  int_s = []
794 
795  for i in range(0,4):
796  if fixed[i]:
797  int_c.append(imath.cos(interval(self.config.q[i])))
798  int_s.append(imath.sin(interval(self.config.q[i])))
799  else:
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]])))
802 
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]
807 
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]
818 
819  int_X = int_c[0]*interval(self.a0) + int_c0s1*interval(self.d2) + (int_c30s1 + int_c210s3 - int_s320)*interval(self.d4)
820 
821  int_Y = int_s[0]*interval(self.a0) + int_s10*interval(self.d2) + (int_c3s10 + int_c0s32 + int_c21s30)*interval(self.d4)
822 
823  int_Z = int_c[1]*interval(self.d2) + (int_c31 - int_c2s31)*interval(self.d4)
824 
825  return [int_X, int_Y, int_Z]
826 
827  ## returns the current configuration and sets the given configuration.
828  # This function is used to restore the saved old configuration
829  # @param q_old A numpy vector of size 7 containing the arm joint values to be set
830  # @return A numpy vector of size 7 containing the current joint values
831  def restore_config(self, q_old):
832  q = np.copy(self.config.q)
833  assert self.set_config(q_old)
834  return q
835 
836  ## Use this function to get the displacement between the actual and desired wrist poses
837  # The metric returns sum of the norms of position difference Nd Frobenus norm of the orientation difference.
838  # \f[
839  # d(x, x_d) = \Sigma_{i = 1}^{3}(x_i - x_{di})^2 + \Sigma_{i = 1}^{3} \Sigma_{j = 1}^{3}(r_{ij} - r_{dij})^2
840  # \f]
841  # @param None
842  # @return A scalar value
843  def pose_metric(self):
844  d = np.linalg.norm(self.xd - self.wrist_position())
845  d += np.linalg.norm(self.Rd - self.wrist_orientation())
846  return d
847 
848  ## Finds the optimal value for the redundant parameter \f$ \phi \f$ that minimizes the cost function and returns the
849  # joints corresponding with optimal redundant parameter value. This function does not change the object configuration.
850  # @param show If True, the values of redundant parameter and the objective function are printed on the console
851  # @return A numpy vector of size 7 containing the optimal arm joint values
852  def optimal_config(self, show = False):
853  keep_q = np.copy(self.config.q)
854  counter = 0
855  while True:
856  J = self.joint_redundancy_jacobian()
857  e = self.config.midrange_error()
858  if show:
859  print
860  print "Iteration : ", counter
861  print "Redundant Parameter : ", self.config.q[0]
862  print "Objective Function : ", self.config.objective_function()
863  if J == None:
864  if show:
865  print "No Jacobian! Optimum phi = ", self.config.q[0]
866  return self.restore_config(keep_q)
867  P = self.config.w*J
868  den = np.dot(P.T, P)
869  if genmath.equal(den, 0.0):
870  if show:
871  print "Division by Zero! Optimum phi = ", self.config.q[0]
872  return self.restore_config(keep_q)
873  Delta_phi = - np.dot(P.T, e) / den
874  old_err = self.config.objective_function()
875  new_phi = self.grown_phi(Delta_phi)
876  q = self.IK_config(new_phi)
877  if q == None:
878  if show:
879  print "No solution for the updated phi! Optimum phi = ", self.config.q[0]
880  return self.restore_config(keep_q)
881 
882  if not self.set_config(q):
883  if show:
884  print "Solution found but not feasible! This should not happen. Optimum phi = ", self.config.q[0]
885  return self.restore_config(keep_q)
886 
887  if show:
888  print "A better phi is found : ", new_phi
889 
890  new_err = self.config.objective_function()
891 
892  if new_err > old_err - 0.01:
893  if show:
894  print "Error not reduced any more. Optimum phi: ", self.config.q[0]
895  return self.restore_config(keep_q)
896 
897  counter = counter + 1
898 
899  ## Moves the joints within the solution manifold towards optimum configuration. The optimization is based on the defined cost function.
900  # The joint change respects given joint speed limit
901  # @parameter max_speed A scalar float value specifying the maximum joint speed in Radians per second. The default is infinity
902  # @step_time A scalar float value specifying time to reach or step time. The default value is 0.1 sec.
903  # @return A boolean: True if successfuly reduced the cost function, False if not
904  def moveto_optimal(self, max_speed = genmath.infinity, step_time = 0.1):
905  if self.in_target():
906  q0 = np.copy(self.config.q)
907  err = self.config.objective_function()
908  J = self.joint_redundancy_jacobian()
909  e = self.config.midrange_error()
910 
911  P = self.config.w*J
912  den = np.dot(P.T, P)
913  if genmath.equal(den, 0.0):
914  genpy.show('Division by Zero! Optimum phi = ' + str(self.config.q[0]), self.silent)
915  return False
916 
917  delta_phi = - np.dot(P.T, e) / den
918  phi = self.grown_phi(delta_phi, respect_js = True)
919 
920  q = self.IK_config(phi)
921  if q != None:
922  if self.set_config(q):
923  return True
924 
925  return False
926 
927  else:
928  genpy.show(self.silent, "Endeffector not in target !")
929  return False
930 
931  ## This function should be used when given redundant parameter \f$ \phi \f$ is within the given permission set (PS)
932  # and yet there is no IK solution for it. The neighborhood of \f$ \phi \f$ is searched for a feasible IK solution.
933  # @parameter phi A scalar float specifying the desired value of the redundant parameter \f$ \phi \f$ (No Default value set)
934  # @parameter PS A list of variables of type interval. It can be the output of function
935  # If a solution is found, the config is set and a True is returned,
936  # If all permission set is searched with no solution, False is returned and the object configuration will not change.
937  def closest_feasible_phi(self, phi, PS, increment = math.pi/360.0):
938  (phi_l, phi_h) = genmath.accommodating_interval(phi, PS)
939 
940  assert (phi < phi_h) and (phi > phi_l)
941 
942  phi_up = phi
943  phi_down = phi
944  while True:
945  stay_up = (phi_up < phi_h)
946  stay_down = (phi_down > phi_l)
947 
948  if stay_up:
949  phi_up = phi_up + increment
950  q = self.IK_config(phi_up)
951  if q != None:
952  if self.set_config(q):
953  return True
954 
955  if stay_down:
956  phi_down = phi_down - increment
957  q = self.IK_config(phi_down)
958  if q != None:
959  if self.set_config(q):
960  return True
961 
962  if not (stay_up or stay_down):
963  # Nothing found :-(
964  return False
965 
966  ## Solves the position based inverse kinematics and returns a direction in the jointspace towards the solution (joint correction)
967  # @param phi A scalar float specifying the desired value of the redundant parameter.
968  # If set as None (default), the current value of the shoulder-pan joint is replaced.
969  # @param optimize A boolean If True the IK solution minimize the defined cost function, otherwise the closest solution will be returned. The default is False.
970  # @return A numpy vector of size 7, containing the direction of joint correction.
971  def ik_direction(self, phi = None, optimize = False):
972  if self.use_magiks:
973  return self.ik.ik_direction()
974  else:
975  q0 = np.copy(self.config.q)
976  if self.goto_target(phi = phi, optimize = optimize):
977  q = self.restore_config(q0)
978  return trig.angles_standard_range(q - q0)
979  else:
980  return np.zeros(7)
981 
982  ## Given a direction for joint correction and a joint speed limit, this function returns the maximum feasible value by which the joints can move in this direction.
983  # @parameter direction A numpy vector of size 7 specifying the desired direction for joints to move
984  # @parameter speed_limit A scalar float specifying the maximum feasible joint speed
985  # @parameter step_time A scalar float specifying the step time
986  # @return A scalar float containing the maximum feasible norm of joint correction in the specified direction.
987  def feasible_joint_stepsize(self, direction, max_speed, time_step = 0.1):
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)
991  assert el < 1.0
992  if eh > 1.0:
993  eh = 1.0
994  return eh
996  def move_joints_towards(self, direction, max_speed, step_time = 0.1):
997  q = q0 + direction*self.feasible_joint_stepsize(direction, max_speed, step_time)
998  return self.set_config(q)
1000  def moveto_target(self, optimize = False):
1001  if self.use_magiks:
1002  if self.ik.moveto_target():
1003  self.sync_from_magiks()
1004  return True
1005  else:
1006  return False
1007  else:
1008  q0 = np.copy(self.config.q)
1009  err = self.pose_metric()
1010  jdir = self.ik_direction(phi = self.config.q[0], optimize = optimize)
1011  err_reduced = False
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)
1014  assert el < 0.0
1015  if eh > 1.0:
1016  eh = 1.0
1017  q = q0 + eh*jdir
1018  if self.set_config(q):
1019  if self.pose_metric() < err:
1020  err_reduced = True
1021  else:
1022  self.set_config(q0)
1023  else:
1024  return True
1025  return err_reduced
1027  def goto_target(self, phi = None, optimize = False, show = False):
1028  '''
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
1034 
1035  The new joint angles will be set if all the kinematic equations are satisfied.
1036  All kinematic parameters will be updated.
1037  '''
1038  if self.use_magiks:
1039  if self.ik.goto_target():
1040  self.sync_from_magiks()
1041  else:
1042  self.ik.set_config(self.config.q)
1043  print "\n Magiks could not find a solution ! \n"
1044  else:
1045  # Finding a feasible phi (theta0)
1046  if phi == None:
1047  phi = self.config.q[0]
1048 
1049  PS = self.permission_set_position()
1050  if show:
1051  print "Permission Set for phi = ", PS
1052  print "Initial phi = ", phi
1053 
1054  if len(PS) == 0:
1055  if show:
1056  print "len(PS) = 0"
1057  print "The target is out of workspace! No solution found."
1058  return False
1059  else:
1060  if not (phi in PS):
1061  phi = genmath.closest_border(phi, PS, k = 0.01)
1062  if show:
1063  print "Phi is not in PS"
1064  print "Closest phi in PS:", phi
1065 
1066  q = self.IK_config(phi)
1067  if q == None:
1068  if show:
1069  print phi, " is not a feasible phi. No solution found"
1070  if not self.closest_feasible_phi(phi, PS):
1071  if show:
1072  print "The target is out of workspace! No solution found."
1073  return False
1074  if show:
1075  print "Next phi: ", self.config.q[0]
1076  else:
1077  if not self.set_config(q):
1078  if show:
1079  print "Not expected to see. Solution exists but not feasible!"
1080  return False
1081 
1082  # when you reach here, the feasible q has been set
1083 
1084  if optimize:
1085  self.set_config(self.optimal_config())
1086 
1087  return self.in_target()
1089  def all_IK_solutions(self, phi):
1090  '''
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
1094  '''
1095  if not self.config.joint_in_range(0, phi):
1096  print "IK_config error: Given theta0 out of feasible range"
1097  return []
1098 
1099  solution_set = []
1100 
1101  c0 = math.cos(phi)
1102  s0 = math.sin(phi)
1103 
1104  [Q, Q2, d42, d44, a00, d22_plus_d44, foura00d44, alpha] = self.additional_dims
1105  [r2, ro2, R2, T2, alpha, betta, gamma, sai] = self.target_parameters
1106 
1107  u = c0*self.xd[0] + s0*self.xd[1]
1108  v = (2*self.a0*u - R2)/Q
1109 
1110  v2 = v**2
1111  A = self.d2 + v*self.d4
1112 
1113  if genmath.equal(v, 1.0):
1114  #"Singular Point"
1115  return []
1116  '''
1117  In this case, a singularity happens
1118  '''
1119  elif (v > 1.0) or (v < -1.0):
1120  #"Given pose out of workspace"
1121  return []
1122  else:
1123  i = 0
1124  tt3 = trig.arccos(v)
1125 
1126  while (i < 2):
1127  theta3 = (2*i - 1)*tt3 # theta3 is certainly in standard range
1128  if self.config.joint_in_range(3,theta3):
1129  s3 = math.sin(theta3)
1130  c3 = v
1131  c30 = c3*c0
1132  B = self.d4*s3
1133  T34 = genkin.transfer_DH_standard( 0.0 , math.pi/2, 0.0, 0.0, theta3)
1134  R34 = T34[0:3,0:3]
1135 
1136  w2 = (alpha*v2 + betta*v + gamma)/(1 - v2)
1137  if genmath.equal(w2, 1.0):
1138  w2 = 1.0
1139  elif genmath.equal(w2, 0.0):
1140  w2 = 0.0
1141  elif w2 < 0.0:
1142  print "IK_config error: w^2 is negative, This should never happen! Something is wrong!"
1143  assert False
1144 
1145  w = math.sqrt(w2)
1146  if (w < 1.0):
1147  m = 0
1148  while (m < 2) and (not ((w == 0.0) and (m == 1))): # beghole emam: intor nabashad ke ham w sefr bashad va ham m yek.
1149  s2 = (2*m - 1)*w
1150  s20 = s2*s0
1151  c0s2= c0*s2
1152 
1153  tt2 = trig.arcsin(s2)
1154  j = 0
1155  while (j < 2):
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)
1159  c20 = c2*c0
1160  c2s0 = c2*s0
1161  E = B*s2
1162  F = B*c2
1163  R1 = math.sqrt(A**2 + F**2)
1164  sai1 = math.atan2(F,A)
1165  R1_nul = genmath.equal(R1, 0)
1166  if not R1_nul:
1167  z_R1 = self.xd[2]/R1
1168  flg = (z_R1 < 1.0) and (z_R1 > - 1.0)
1169  else:
1170  flg = False
1171 
1172  if flg:
1173  tt1 = trig.arccos(self.xd[2]/R1)
1174  k = 0
1175  while (k < 2):
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)
1180 
1181  As1Fc1 = self.a0 + A*s1 + F*c1
1182  X = c0*As1Fc1 - E*s0
1183  Y = s0*As1Fc1 + E*c0
1184  Z = A*c1 - F*s1
1185 
1186  u2 = s2*s3*self.d4
1187  u3 = c2*s3*self.d4
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])
1195 
1196  if vecmat.equal(self.xd, [X,Y,Z]):
1197  if self.orientation_respected:
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 ]])
1201 
1202  R04 = np.dot(R03, R34)
1203  R47 = np.dot(R04.T, self.Rd)
1204  tt5 = trig.arccos(R47[2,2])
1205  l = 0
1206  while (l < 2):
1207  theta5 = (2*l - 1)*tt5 # theta5 is certainly in standard range
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)
1213  # "Singular Point"
1214  return []
1215  '''
1216  In this case, only sum of theta4 + theta6 is known
1217  '''
1218  else:
1219  c6 = - R47[2,0]/s5
1220  s6 = R47[2,1]/s5
1221  c4 = R47[0,2]/s5
1222  s4 = R47[1,2]/s5
1223 
1224  theta6 = trig.arcsincos(s6, c6)
1225  theta4 = trig.arcsincos(s4, c4)
1226 
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)
1231 
1232  assert self.config.joint_in_range(4, theta4)
1233  assert self.config.joint_in_range(6, theta6)
1234 
1235  solution_set.append(np.array([phi, theta1, theta2, theta3, theta4, theta5, theta6]))
1236  l = l + 1
1237  else:
1238  solution_set.append(np.array([phi, theta1, theta2, theta3, self.config.q[4], self.config.q[5], self.config.q[6]]))
1239  k = k + 1
1240  j = j + 1
1241  m = m + 1
1242  i = i + 1
1243  return solution_set
1245  def IK_config(self, phi):
1246  '''
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
1253  '''
1254  solution_set = self.all_IK_solutions(phi)
1255 
1256  if len(solution_set) == 0:
1257  # print "IK_config error: No solution found within the feasible joint ranges for given phi. Change the target or redundant parameter"
1258  print ".",
1259  return None
1260 
1261  delta_min = 1000
1262  for i in range(0, len(solution_set)):
1263  solution = solution_set[i]
1264  if self.ofuncode == 0:
1265  delta = np.linalg.norm(trig.angles_standard_range(solution - self.config.q))
1266  elif self.ofuncode == 1:
1267  P = trig.angles_standard_range(solution - self.config.qm)*self.config.w
1268  delta = np.dot(P.T,P)
1269  else:
1270  print "IK_config error: Value ",self.ofuncode," for argument ofuncode is not supported"
1271  assert False
1272 
1273  if delta < delta_min:
1274  delta_min = delta
1275  i_min = i
1276 
1277  return solution_set[i_min]
1279  def ts_project(self, js_traj, phi_start = 0.0, phi_end = None):
1280  '''
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.
1284  '''
1285 
1286  if phi_end == None:
1287  phi_end = js_traj.phi_end
1288 
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
1293 
1294  phi = phi_start
1295  stay = True
1296  while stay:
1297  if (phi > phi_end) or genmath.equal(phi, phi_end, epsilon = 0.1*self.dt):
1298  phi = phi_end
1299  stay = False
1300  js_traj.set_phi(phi)
1301  if self.set_config(js_traj.current_position):
1302  pos_traj.add_point(phi - phi_start, self.wrist_position())
1303  ori_traj.add_point(phi - phi_start, geo.Orientation_3D(self.wrist_orientation()))
1304  phi = phi + self.dt
1305 
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'):
1309  '''
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
1313  '''
1314  self.config.qm = 0.5*(self.config.ql + self.config.qh)
1315  keep_q = np.copy(self.config.q)
1316 
1317  if ori_traj == None:
1318  ori_traj = trajlib.Orientation_Path()
1319  ori_traj.add_point(0.0, geo.Orientation_3D(self.wrist_orientation()))
1320  ori_traj.add_point(pos_traj.phi_end, geo.Orientation_3D(self.wrist_orientation()))
1321 
1322  if phi_end == None:
1323  phi_end = min(pos_traj.phi_end, ori_traj.phi_end)
1324 
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)
1327 
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)
1332  else:
1333  assert False, "\n Unknown Trajectory Type \n"
1334 
1335  jt.vel_max = self.max_js
1336  jt.acc_max = self.max_ja
1337  jt.pos_max = self.config.qh
1338  jt.pos_min = self.config.ql
1339 
1340  phi = phi_start
1341  pos_traj.set_phi(phi)
1342  ori_traj.set_phi(phi)
1343  if relative:
1344  p0 = self.wrist_position() - pos_traj.current_position
1345  else:
1346  p0 = np.zeros(3)
1347  self.set_target(pos_traj.current_position, ori_traj.current_orientation['matrix'])
1348  self.goto_target(optimize = True)
1349 
1350  jt.add_position(0.0, pos = self.config.q)
1351 
1352  stay = True
1353 
1354  while stay:
1355  phi = phi + self.dt
1356 
1357  if (phi > phi_end) or genmath.equal(phi, phi_end, epsilon = 0.1*self.dt):
1358  phi = phi_end
1359  stay = False
1360 
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())
1365 
1366  self.config.qm = np.copy(self.config.q)
1367 
1368  err_reduced = self.moveto_target(optimize = True)
1369  self.set_target(self.wrist_position(), self.wrist_orientation())
1370  optim_success = self.moveto_optimal()
1371  if err_reduced:
1372  jt.add_position(phi = phi - phi_start, pos = np.copy(self.config.q))
1373  else:
1374  print ":",
1375 
1376  if traj_type == 'polynomial':
1377  jt.interpolate()
1378  # jt.consistent_velocities()
1379 
1380  self.config.qm = 0.5*(self.config.qh + self.config.ql)
1381  self.set_config(keep_q)
1382 
1383  return jt
1385  def sync_from_magiks(self):
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)
1389  def permission_set_position(self):
1390  """
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
1395  feasible range.
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.
1402  """
1403  if self.Phi != None:
1404  return self.Phi
1405 
1406  [r2, ro2, R2, T2, alpha, betta, gamma, sai] = self.target_parameters
1407  [Q, Q2, d42, d44, a00, d22_plus_d44, foura00d44, alpha] = self.additional_dims
1408 
1409  # feasibility set for v imposed by theta1
1410 
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
1414 
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) ]])
1418 
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])
1422 
1423  (alpha_l, alpha_h) = int_alpha[0]
1424  (betap_l, betap_h) = int_betap[0]
1425  (gamma_l, gamma_h) = int_gamma[0]
1426 
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)
1431 
1432  V1 = (Vp_1l & Vp_1h & interval([0.0,1.0])) | (Vn_1l & Vn_1h & interval([-1.0,0.0]))
1433 
1434  # Finding wh,wl:
1435 
1436  int_theta2 = interval([self.config.ql[2],self.config.qh[2]])
1437  int_w = imath.sin(int_theta2)**2
1438  (wl, wh) = int_w[0]
1439 
1440  #Finding V2l, V2h
1441 
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])
1444 
1445  #Finding V2
1446 
1447  V2 = V2l & V2h
1448 
1449  #Finding V3
1450 
1451  int_theta3 = interval([self.config.ql[3],self.config.qh[3]])
1452  V3 = imath.cos(int_theta3)
1453 
1454  #Finding V
1455 
1456  V = V3 & V2 & V1
1457 
1458  #Finding Ui
1459 
1460  denum = 2*self.a0*math.sqrt(r2)
1461  a = R2/denum
1462  b = 2*self.d2*self.d4/denum
1463 
1464  Phi1_3 = interval()
1465  nv = len(V)
1466  for i in range(0, nv):
1467  Ui = interval(a) - interval(b)*interval(V[i])
1468  (uli, uhi) = Ui[0]
1469 
1470  zl = trig.arcsin(uli)
1471  zh = trig.arcsin(uhi)
1472 
1473  B1 = trig.standard_interval(zl - sai, zh - sai)
1474  B2 = trig.standard_interval(math.pi- zh - sai, math.pi- zl - sai)
1475 
1476  Phi1_3 = Phi1_3 | B1 | B2
1477 
1478  #Finding P_phi
1479 
1480  Phi0 = interval([self.config.ql[0], self.config.qh[0]])
1481 
1482  self.Phi = genmath.connect_interval(Phi0 & Phi1_3)
1483 
1484  return self.Phi
1486  def delta_phi_interval(self, respect_js = False):
1487  '''
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
1490  '''
1491  if self.Delta == None:
1492  J = self.joint_redundancy_jacobian()
1493  self.Delta = self.permission_set_position() - interval(self.config.q[0]) # set initial Delta based on the position permission set for phi
1494 
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)): # if Ji and wi are not zero
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])
1501 
1502  d = self.dt*self.max_js/J[i]
1503 
1504  if respect_js:
1505  dli2 = genmath.binary_choice(- d, d, J[i])
1506  dhi2 = genmath.binary_choice( d, - d, J[i])
1507  assert dli2 <= 0.0
1508  assert dhi2 >= 0.0
1509  else:
1510  dli2 = - np.inf
1511  dhi2 = np.inf
1512 
1513 
1514  if genmath.equal(dli1, 0.0):
1515  dli1 = 0.0
1516  if genmath.equal(dhi1, 0.0):
1517  dhi1 = 0.0
1518 
1519  assert dli1 <= 0.0
1520  assert dhi1 >= 0.0
1521 
1522  self.Delta = self.Delta & interval([dli1, dhi1]) & interval([dli2, dhi2])
1523  if len(self.Delta) == 0:
1524  print "Error: self.Delta is empty:"
1525  print "Initial Delta : ", self.permission_set_position() - interval(self.config.q[0])
1526  print "interval([dli1, dhi2]): ", interval([dli1, dhi1])
1527  print "interval([dli1, dhi2]): ", interval([dli2, dhi2])
1528 
1529  return self.Delta
1530 
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...
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...
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).
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.
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 feasible_joint_stepsize
Given a direction for joint correction and a joint speed limit, this function returns the maximum fea...