MAGIKS  1.1
Manipulator General Inverse Kinematic Solver
 All Classes Namespaces Files Functions Variables Pages
manipulator_configuration.py
Go to the documentation of this file.
1 # HEADER
2 '''
3 @file: manipulator_configuration.py
4 @brief: This module provides a class representing the configuration of a manipulator in the jointspace including some methods.
5 @author: Nima Ramezani Taghiabadi
6  PhD Researcher
7  Faculty of Engineering and Information Technology
8  University of Technology Sydney (UTS)
9  Broadway, Ultimo, NSW 2007, Australia
10  Room No.: CB10.03.512
11  Phone: 02 9514 4621
12  Mobile: 04 5027 4611
13  Email(1): Nima.RamezaniTaghiabadi@student.uts.edu.au
14  Email(2): nima.ramezani@gmail.com
15  Email(3): nima_ramezani@yahoo.com
16  Email(4): ramezanitn@alum.sharif.edu
17 @version: 3.0
18 Last Revision: 11 August 2015
19 '''
20 '''
21 Major change from previous version:
22  1- methods set_joint_bounds() added to class Manipulator_Configuration()
23  2- functions q_to_qstar() and qstar_to_q() renamed to mapto_virtual() and mapfrom_virtual() respectively
24  3- property qstar renamed to qvr
25 
26 '''
27 
28 # BODY
29 import numpy as np, math, random, general_python as genpy, copy
30 
31 from math_tools import general_math as gen
32 from math_tools.algebra import vectors_and_matrices as vecmat
33 from math_tools.geometry import trigonometry as trig
34 from math_tools.discrete import discrete
35 
36 ## @brief This class contains joint properties of a chained-link manipulator.
37 # These properties include degree of freedom, joint types, joint limits and mapping functions.
39  ## The Class Constructor:
40  # @param njoint A positive integer specifying the number of joints of the manipulator
41  # @param DOF A positive integer specifying the number of degrees of freedom
42  # @param joint_mapping A string specifying the default mapping function.
43  # This parameter must be chosen among these options:
44  # * \c NM: No Mapping (Identity mapping function)
45  # * \c LM: Linear Mapping
46  # * \c TM: Trigonometric Mapping
47  def __init__(self, njoint = 0, DOF= 0, joint_mapping = 'NM'):
48  self.njoint = njoint
49  ## An integer: Is a short form of Degrees of Freedom and represents the number of free joints
50  self.DOF = DOF
51 
52  ## An array of string containing the specific mapping function for each joint
53  # The array is of length \c DOF and is defined only for free joints.
54  self.joint_handling = [joint_mapping for i in range(DOF)]
55 
56  ## An array of booleans specifying which joints are limited. The array is of length \c DOF and is defined only for free joints.
57  # The array is of length \c DOF and is defined only for free joints.
58  self.limited = [True for i in range(0, DOF)]
59 
60  ## An array of string containing indivifual labels or names the for each joint.
61  # The array is of length \c DOF and is defined only for free joints.
62  self.joint_label = ['Joint ' + str(i) for i in range(DOF)]
63 
64  ## A boolean specify if the joint limits must be respected when new joint values are being set.
65  # If this property is True, the system checks for the given joint values to be in the defined feasible range
66  # and fails with an error if given joint values are beyond the limits.
67  # If False, any value for the joints are accepted.
69 
70  ## A vector of real numbers representing lower bounds for the joint configuration.
71  # The array is of length /c njoint and is defined for both fixed and free joints.
72  self.ql = [-math.pi for i in range(0, njoint)]
73  ## A vector of real numbers representing higher bounds for the joint configuration
74  # The array is of length /c njoint and is defined for both fixed and free joints.
75  self.qh = [math.pi for i in range(0, njoint)]
76 
77  ## A list of booleans representing the type of the corresponding joint number.
78  # If True, the joint is prismatic, if False it is revolute.
79  # The array is of length /c njoint and is defined for both fixed and free joints.
80  self.prismatic = [False for i in range(0, njoint)]
81 
82  # A list of booleans representing whether the corresponding joint is free or fixed at a certain value. The default is True for all joints
83  self.free = [True for i in range(0, njoint)]
84 
85 ## @brief This class represents a model of the joint configuration of a chained-link manipulator.
86 # It contains current actual and virtual(mapped) joint values and the required joint settings.
87 # The class also, has methods to check the feasibility of given joint values, set a given configuration,
88 # forward and inverse conversion of joint values into the mapped virtual space and a number of
89 # auxiliary methods. This class contains everything you need to handle joint vlaues of the manipulator.
91  ## The Class Constructor:
92  # @param settings An instance of class Manipulator_Configuration_Settings containing the joint settings of the manipulator
93  # including joint types, joint limits and mapping functions
94  def __init__(self, settings):
95  # An instance of class Manipulator_Configuration_Settings containing the joint settings of the manipulator
96  # including joint types, joint limits and mapping functions
97  self.config_settings = settings
98 
99  # A list of real numbers representing the current joint configuration of the manipulator in the jointspace
100  self.q = 0.5*(settings.qh + settings.ql)
101 
102  # A list of real numbers representing the current joint configuration of the manipulator in the mapped jointspace
103  self.qvr = None
104 
105  self.initialize()
106  '''
107  If you have a method in class A and you intended to have a method with the same name in a class B inherited from A,
108  you should not call this method in class A, so I created a function set_configuration() which is called by set_config()
109  '''
110 
111  self.mapto_virtual()
112  self.update_virtual_jacobian_multipliers()
113 
114  ## Only use this function to set the joint limits. Do not change the properties directly.
115  # @param ql A numpy array of length \c njoint containing the lower bounds of the joints
116  # @param qh A numpy array of length \c njoint containing the upper bounds of the joints
117  def set_joint_bounds(self, ql, qh):
118  self.config_settings.ql = copy.copy(ql)
119  self.config_settings.qh = copy.copy(qh)
120  self.initialize()
121 
122  ## Use this function to see the current configuration of the manipulator
123  # @return A string containing the current values of joints in degrees
124  def config_str(self):
125  s = "q = "
126  s += vecmat.vector_to_str((180.0/math.pi)*self.q, format="%.2f")
127  s += " (Joints are"
128  if not self.joints_in_range(self.free_config(self.q)):
129  s += " NOT"
130  s += " all in range)"
131 
132  return s
133 
134  # \cond
135  ## protected
136  def bring_revolute_joints_to_standard_range(self):
137  '''
138  Change revolute joint values (joint angles) if they are out of standard range (-pi +pi) to their equivalent value in the standard range
139  '''
140  for i in range(0, self.config_settings.njoint):
141  if not self.config_settings.prismatic[i]:
142  self.q[i] = trig.angle_standard_range( self.q[i] )
143  # \endcond
144  ## This function is used to check if a given value for specific joint is in its feasibility range
145  # @param i An integer between 0 to 6 specifying the joint number to be checked
146  # @param qi A float parameter specifying the value for the i-th joint
147  # @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)
148  def joint_in_range(self, i, qi):
149  if abs(qi - self.ql[i]) < gen.epsilon:
150  qi = self.ql[i]
151  if abs(qi - self.qh[i]) < gen.epsilon:
152  qi = self.qh[i]
153 
154  return ((qi <= self.qh[i]) and (qi >= self.ql[i]))
155 
156  ## This function is used to check if all values of the given joint array are in their feasibility range
157  # @param qd A numpy array of size DOF containing the values to be checked
158  # @return A boolean: If The given joints "qd" are out of the range specified by properties: ql and qh, returns False, otherwise returns True
159  def joints_in_range(self, qd):
160  flag = True
161  for i in range(0, self.config_settings.DOF):
162  if self.config_settings.limited[i]:
163  flag = flag and self.joint_in_range(i, qd[i])
164  return flag
165 
166  ## This function converts the free joint values from unlimited virtual joint-space into their actual values.
167  # @param qs A numpy array of length \c DOF containing the values of free joints in the virtual joint-space.
168  # @return A numpy array of length \c DOF containing the actual values of free joints equivalent to the given argument \c qs.
169  def mapfrom_virtual(self, qs):
170  qq = np.zeros((self.config_settings.DOF))
171  for i in range(self.config_settings.DOF):
172  if self.config_settings.limited[i]:
173  if self.config_settings.joint_handling[i] == 'NM':
174  qq[i] = trig.angle_standard_range( qs[i] )
175  elif self.config_settings.joint_handling[i] == 'LM':
176  qs[i] = trig.angle_standard_range( qs[i] )
177  qq[i] = (qs[i] - self.jmc_b[i]) / self.jmc_a[i]
178  elif self.config_settings.joint_handling[i] == 'TM':
179  qq[i] = self.jmc_f[i] * math.cos(qs[i]) + self.jmc_g[i]
180  elif self.config_settings.joint_handling[i] == 'TGM':
181  qq[i] = 2*math.atan(self.jmc_f[i] * math.cos(qs[i]) + self.jmc_g[i])
182  else:
183  assert False, genpy.err_str(__name__, self.__class__.__name__, 'mapfrom_virtual', self.config_settings.joint_handling[i] + " is not a valid value for joint_handling")
184  else:
185  qq[i] = qs[i]
186 
187  # return self.free_config_inv(qq)
188  return qq
189 
190  ## This function converts the current actual free joint values (picked from property \c q)
191  # into their equivalent values in the unlimited virtual joint-space.
192  # @return A numpy array of length \c DOF containing the current values of free joints in the unlimited virtual joint-space.
193  def mapto_virtual(self):
194  qf = self.free_config(self.q)
195 
196  self.qvr = np.zeros((self.config_settings.DOF))
197 
198  for i in range(self.config_settings.DOF):
199  if (not self.config_settings.limited) or (self.config_settings.joint_handling[i] == 'NM'):
200  self.qvr[i] = qf[i]
201  elif self.config_settings.joint_handling[i] == 'LM':
202  assert self.joint_in_range(i, qf[i]), "Joint " + str(i) + " = " + str(qf[i]) + " is not in feasible range: (" + str(self.config_settings.ql[i]) + ',' + str(self.config_settings.qh[i]) + ')'
203  self.qvr[i] = self.jmc_a[i] * qf[i] + self.jmc_b[i]
204  elif self.config_settings.joint_handling[i] == 'TM':
205  '''
206  ql = self.config_settings.ql[i]
207  qh = self.config_settings.qh[i]
208  print "i: ", i, "ql: ", ql," q: ", qf[i],"qh: ", qh, " g: ", self.jmc_g[i], " f: ", self.jmc_f[i], " c: ", (qf[i] - self.jmc_g[i]) / self.jmc_f[i]
209  '''
210  assert self.joint_in_range(i, qf[i]), "Joint " + str(i) + " = " + str(qf[i]) + " is not in feasible range: (" + str(self.config_settings.ql[i]) + ',' + str(self.config_settings.qh[i]) + ')'
211  self.qvr[i] = trig.arccos((qf[i] - self.jmc_g[i]) / self.jmc_f[i])
212  elif self.config_settings.joint_handling[i] == 'TGM':
213  assert self.joint_in_range(i, qf[i]), "Joint " + str(i) + " = " + str(qf[i]) + " is not in feasible range: (" + str(self.config_settings.ql[i]) + ',' + str(self.config_settings.qh[i]) + ')'
214  self.qvr[i] = trig.arccos((math.tan(0.5*qf[i]) - self.jmc_g[i]) / self.jmc_f[i])
215  else:
216  print 'Wrong Joint Handling (Free Joint ' + str(i) + '): ' + self.config_settings.joint_handling[i]
217  assert False, genpy.err_str(__name__, self.__class__.__name__, 'q_to_q', self.config_settings.joint_handling[i] + " is not a valid value for joint_handling")
218 
219  # \cond
220  ## protected
221  def update_virtual_jacobian_multipliers(self):
222  '''
223  joint_limit_multipliers are coefficients of forward and inverse mapping to/from limited to/from unlimited jointspace.
224  i.e: jmc_a is the derivative of q to q_star
225  (Refer also to the comments of method: initialize in this class)
226  This method calculates and updates the values of one of the joint limit multipliers: "jmc_c" which is called "joint_limit_jacobian_multipliers"
227  Each column of the error jacobian is multiplied by the corresponding element of vector "jmc_c": Jstar = Je * diag(jmc_c)
228  Since the coefficient "jmc_c" for a joint, depends on the current value of that joint, it should be updated everytime "q" changes
229  The other multipliers: "jmc_a", "jmc_b", "jmc_f" and "jmc_g" do not depend on the joints, therefore do not need to be updated
230  '''
231  func_name = "update_virtual_jacobian_multipliers"
232  for i in range(0,self.config_settings.DOF):
233  if self.config_settings.joint_handling[i] == 'NM':
234  self.jmc_c[i] = 1.0
235 
236  elif self.config_settings.joint_handling[i] == 'LM':
237  self.jmc_c[i] = 1.0 / self.jmc_a[i]
238 
239  elif self.config_settings.joint_handling[i] == 'TM':
240  self.jmc_c[i] = - math.sin(self.qvr[i])/self.jmc_a[i]
241 
242  elif self.config_settings.joint_handling[i] == 'TGM':
243  t = self.jmc_f[i] * math.cos(self.qvr[i]) + self.jmc_g[i]
244  self.jmc_c[i] = - 2.0 * math.sin(self.qvr[i])/(self.jmc_a[i]*(1 + t**2))
245  else:
246  assert False, genpy.err_str(__name__, self.__class__.__name__, 'update_virtual_jacobian_multipliers', self.config_settings.joint_handling[i] + " is not a valid value for joint_handling")
247 
248  # \endcond
249 
250  # This function is implemented once when a new instance of the object is constructed.
251  # If you chang any joints from fixed to free or vice-versa, after the construction of the object, you will need to call this function.
252  def initialize(self):
253  '''
254  Everything regarding joint parameters needed to be done before running kinematic calculations
255  This function must be called whenever you change joint limits or change type of a joint.
256  '''
257  func_name = "initialize()"
258  # Counting free joints in order to detremine the degree of freedom: "DOF"
259  self.config_settings.DOF = 0
260  # Important: Here you do not consider prismatic joints. Do it in the future
261  for i in range(0,self.config_settings.njoint):
262  # First bring revolute joint limits in the range (- pi , pi)
263  if (not self.config_settings.prismatic[i]):
264  self.config_settings.ql[i] = trig.angle_standard_range( self.config_settings.ql[i] )
265  self.config_settings.qh[i] = trig.angle_standard_range( self.config_settings.qh[i] )
266 
267  if self.config_settings.free[i]:
268  self.config_settings.DOF += 1
270  self.ql = self.free_config(self.config_settings.ql)
271  self.qh = self.free_config(self.config_settings.qh)
272 
273  # check all the joints are already in their desired range
274  '''
275  for i in range(self.DOF):
276  if not self.config_settings.joint_handling[i] == 'No Mapping':
277  assert self.joints_in_range() #check only for joint i
278  '''
279 
280  '''
281  The following code defines the joint limit multipliers
282  jmc_a and jmc_b are auxiliary coefficients which are used for conversion from "q" to "qvr" space
283  (Please refer to the joint limits section of the documentation associated with this code)
284 
285  To make sure that all joints are in their desired range identified as: (self.ql, self.qh), the real jointspace is mapped into an unlimited jointspace.
286 
287  "q " represent the real joint values which are in a limited jointpace
288  "qvr" represent the mapped joint values in unlimited jointspace
289 
290  The following code creates and defines "Joint Limit Multipliers". These are coefficients for this jointspace mapping - (jmc: Jointspace Mapping Coefficients)
291  in linear mapping:
292 
293  q = a * qvr + b
294  qs = (q - b) / a
295 
296  in trigonometric mapping:
297 
298  q = f * cos(qvr) + g
299  qvr = arccos [ (q - g) / f ]
300 
301  a, b, f and g are calculated in such a way that the real joint values which are in their feasible range are mapped into an equivalent qvr in an unlimited space (-pi, +pi)
302 
303  "jmc_c" is multiplied by the columns of the error jacobian matrix
304  '''
305  self.jmc_a = np.zeros((self.config_settings.DOF))
306  self.jmc_b = np.zeros((self.config_settings.DOF))
307  self.jmc_c = np.zeros((self.config_settings.DOF))
308  self.jmc_f = np.zeros((self.config_settings.DOF))
309  self.jmc_g = np.zeros((self.config_settings.DOF))
310 
311  self.jmc_f = 0.5*(self.qh - self.ql)
312  self.jmc_g = 0.5*(self.qh + self.ql)
313 
314  for i in range(0, self.config_settings.DOF):
315  if self.config_settings.joint_handling[i] == 'NM':
316  self.jmc_a[i] = 1.00000
317  self.jmc_b[i] = 0.00000
318  elif self.config_settings.joint_handling[i] == 'LM':
319  self.jmc_a[i] = 2*math.pi/(self.qh[i] - self.ql[i])
320  self.jmc_b[i] = math.pi * (self.qh[i] + self.ql[i])/(self.ql[i] - self.qh[i])
321  elif self.config_settings.joint_handling[i] == 'TM':
322  self.jmc_a[i] = 2.0/(self.qh[i] - self.ql[i])
323  self.jmc_b[i] = (self.qh[i] + self.ql[i])/(self.ql[i] - self.qh[i])
324  elif self.config_settings.joint_handling[i] == 'TGM':
325  th = math.tan(0.5*self.qh[i])
326  tl = math.tan(0.5*self.ql[i])
327  self.jmc_a[i] = 2/(th - tl)
328  self.jmc_b[i] = (tl + th)/(tl - th)
329  self.jmc_f[i] = 0.5*(th - tl)
330  self.jmc_g[i] = 0.5*(th + tl)
331  else:
332  assert False, genpy.err_str(__name__, self.__class__.__name__, 'initialize', self.config_settings.joint_handling[i] + " is not a valid value for joint_handling")
333 
334  # map q to qvr for the first time:
335  self.mapto_virtual()
336 
337  # assign the value of jmc_c the jacobian multiplier:
338  self.update_virtual_jacobian_multipliers()
339 
340  # \cond
341  def joint_correction_in_range(self, dq):
342  '''
343  Return True if the joint configuration will be in the desired range after being added by the given "dq"
344  '''
345  in_range = True
346  for i in range(0,self.DOF):
347  in_range = in_range and (self.q[i] + dq[i] <= self.qh[i]) and (self.q[i] + dq[i] >= self.ql[i])
348  i = i + 1
349  return in_range
350  # \endcond
351 
352  ## Sets the configuration given values of the free joints in the virtual joint-space.
353  # This function changes and updates the values of the joint configuration in the unlimited virtual space (property \c qvr).
354  # The actual joint values (property \c q) is then calculated and updated as well.
355  # This method changes the joint configuration. Therefore a forward kinematics update will be implemented.
356  # @param qvrd A numpy array of length \c DOF containing the desired values of the free joints in the unlimited space.
357  def set_config_virtual(self, qvrd):
358  self.qvr = qvrd
359  qd = self.mapfrom_virtual(qvrd)
360  permission = not self.config_settings.joint_limits_respected
361  if not permission:
362  permission = self.joints_in_range(qd)
363  if permission:
364  self.q = self.free_config_inv(qd)
365  self.update_virtual_jacobian_multipliers()
366  return True
367  else:
368  assert False, genpy.err_str(__name__, self.__class__.__name__, 'set_config_virtual', 'The joint values computed from qvr are out of range while joint limits are respected.')
369  return False
370 
371  ## The correction of joints is always restricted by joint limits and maximum feasible joint speed
372  # If you want to move the joints in a desired direction, how much are you allowed to move in order to respect joint position and speed limits?
373  # This function returns a feasible interval for the stepsize in the given direction.
374  # In other words, it gives an interval for the magnitude of the joint angles correction vector
375  # so that both joint position and speed limits are fulfilled.
376  # The joint direction of change must be multiplied by a scalar value in this range so that the applied changes are feasible.
377  # @param direction A numpy array of size \c DOF specifying the direction of change
378  # @param max_speed A float parameter specifying the maximum feasible speed for a joint change. (Set as infinity by default)
379  # @param delta_t The step time in which the change(correction) is to be applied.
380  # @return An instance of type <a href="http://pyinterval.googlecode.com/svn/trunk/html/index.html">Interval()</a>
381  def joint_stepsize_interval(self, direction, max_speed = gen.infinity, delta_t = 0.001):
382  etta_l = []
383  etta_h = []
384 
385  # for ii in range(self.config_settings.njoint):
386  for i in range(self.config_settings.DOF):
387  if not gen.equal(direction[i], 0.0):
388  if self.config_settings.limited[i] and self.config_settings.joint_handling[i] == 'NM':
389  a = (self.ql[i] - self.q[i])/direction[i]
390  b = (self.qh[i] - self.q[i])/direction[i]
391  etta_l.append(gen.sign_choice(a, b, direction[i]))
392  etta_h.append(gen.sign_choice(b, a, direction[i]))
393 
394  a = delta_t*max_speed/direction[i]
395  etta_l.append(gen.sign_choice(-a, a, direction[i]))
396  etta_h.append(gen.sign_choice( a,-a, direction[i]))
397 
398  if (etta_l == []) or (etta_h == []):
399  return (0.0, 0.0)
400  else:
401  return (max(etta_l), min(etta_h))
402 
403 
404  ## This function picks and returns the values of free joints among all the joints in the given argument \c q.
405  # @param A numpy vector of size \c njoint containing the actual values of all the joints
406  # @return A numpy vector of size \c DOF containing the values of free joints
407  def free_config(self, q):
408  fc = np.zeros((self.config_settings.DOF))
409  j = 0
410  for jj in range(0,self.config_settings.njoint):
411  if self.config_settings.free[jj]:
412  fc[j] = q[jj]
413  j = j + 1
414  return fc
415 
416  # \cond
417  def free_config_inv(self, qs):
418  '''
419  puts the values of free joints in their proper place in the main config vector. Return the main config vector
420  '''
421  c = np.copy(self.q)
422  j = 0
423  for jj in range(0,self.config_settings.njoint):
424  if self.config_settings.free[jj]:
425  c[jj] = qs[j]
426  j = j + 1
427  return c
428  # \endcond
429 
430  ## Use this function to set the joint configuration to the given desired values.
431  # If property joint_limits_respected is True, the system checks for given qd to be in the defined feasible range
432  # and fails with an error if given joint values are beyond the limits
433  # If property joint_limits_respected is False, any value for the joints are accepted.
434  # @param qd A numpy array of size 7 containing the desired joint values to be set
435  # @return A boolean: True if the given joints are in range and the configuration is set, False if not
436  def set_config(self, qd, set_virtual = True):
437  len_qd = len(qd)
438  assert len_qd == self.config_settings.DOF, genpy.err_str(__name__, self.__class__.__name__,'set_config','Length of given config vector is '+str(len_qd)+' which does not match the settings DOF('+str(self.config_settings.DOF)+')')
439  permission = not self.config_settings.joint_limits_respected
440  if not permission:
441  permission = self.joints_in_range(qd)
442 
443  if permission:
444  j = 0
445  for jj in range(0,self.config_settings.njoint):
446  if self.config_settings.free[jj]:
447  if self.config_settings.limited[j] and (not self.config_settings.prismatic[jj]):
448  self.q[jj] = trig.angle_standard_range(qd[j])
449  else:
450  self.q[jj] = qd[j]
451  j = j + 1
452 
453  self.mapto_virtual()
454  self.update_virtual_jacobian_multipliers()
455 
456  return True
457  else:
458  print "Warning from configuration.set_config(): Given joints are not in their feasible range"
459  for i in range(self.config_settings.DOF):
460  if not self.joint_in_range(i, qd[i]):
461  print
462  print "Joint Number: ", i
463  print "Lower Limit :", self.ql[i]
464  print "Desired Value:", qd[i]
465  print "Upper Limit :", self.qh[i]
466  return False
467 
468  ## Generates a random joint configuration in the defined feasible range in the settings.
469  # This function does not change manipulator configuration.
470  # @return An array of real numbers containing the joint values of the generated random configuration.
471  def random_config(self):
472  q_rnd = np.zeros(self.config_settings.DOF)
473 
474  for j in range(0, self.config_settings.DOF):
475  q_rnd[j] = self.ql[j] + random.random()*(self.qh[j] - self.ql[j])
476  return q_rnd
477 
478  ## If The feasible range of each joint is divided into a number of equal intervals,
479  # a joint-space lattice or grid is established.
480  # If a manipulator has \f$ n \f$ degrees of freedom, and each joint is divided to \f$ N + 1 \f$ intervals,
481  # a typical lattice \f$ \boldsymbol{\Lambda}_N \f$ in the joint space
482  # can be generated in the following form:
483  # \f[
484  # \boldsymbol{\Lambda}_N = \bigg \lbrace \boldsymbol{q}_o + \sum _{i = 1} ^{n} k_i \cdot a_i \cdot \boldsymbol{b}_i \quad \bigg \arrowvert \quad k_i \in \mathbb{Z}_N \bigg \rbrace
485  # \f]
486  # This function creates a lattice in which \a N is specified by argument <tt> number_of_intervals </tt>
487  # and returns the joint configuration corresponding to a specific node of the grid.
488  # This node is specified by argument <tt> config_number </tt> which is the order of the configuration in the gridded joint-space.
489  # The function does not change manipulator configuration.
490  # @return A numpy array of length \c DOF containing the joint values of the specified node of the generated grid.
491  def grid_config(self, config_number, number_of_intervals):
492  q_grd = np.zeros(self.config_settings.DOF)
493  A = discrete.number_in_base(N = config_number, base = number_of_intervals, n_digits = self.config_settings.DOF)
494 
495  for j in range(0, self.config_settings.DOF):
496  q_grd[j] = self.ql[j] + (2*A[j] + 1)*(self.qh[j] - self.ql[j])/(2*number_of_intervals)
497 
498  return q_grd
499 
500 # \cond
501  def objective_function_gradient(self, k = 1.0):
502  dof = self.config_settings.DOF
503  qh = self.qh
504  ql = self.ql
505  u = np.zeros(dof)
506  qs = trig.angles_standard_range(self.qvr)
507  for i in range(0, self.config_settings.DOF):
508  if self.config_settings.joint_handling[i] == 'TM':
509  u[i] = - k*qs[i]/(dof*((2*math.pi)**2))
510  elif self.config_settings.joint_handling[i] == 'NM':
511  if self.config_settings.limited[i]:
512  mean = 0.5*(self.qh[i] + self.ql[i])
513  u[i] = - k*(qs[i] - mean)/(dof*((self.qh[i] - self.ql[i])**2))
514  # print "qs[i] = ", qs[i], " mean = ", mean, " qh-ql= ", self.qh[i] - self.ql[i], " u = ", u[i]
515  else:
516  assert False, genpy.err_str(__name__, self.__class__.__name__, 'objective_function_gradient', self.config_settings.joint_handling[i] + " is not a valid value for joint_handling")
517  return u
518 
519  def objective_function_value(self, k = 1.0):
520  dof = self.config_settings.DOF
521  qs = trig.angles_standard_range(self.qvr)
522  qh = self.qh
523  ql = self.ql
524  f = 0.0
525  for i in range(0, self.config_settings.DOF):
526  df = 0.0
527  if self.config_settings.joint_handling[i] == 'TM':
528  f += - k*qs[i]/(dof*((2*math.pi)**2))
529  elif self.config_settings.joint_handling[i] == 'NM':
530  if self.config_settings.limited[i]:
531  mean = 0.5*(self.qh[i] + self.ql[i])
532  df = k*((qs[i] - mean)**2)/(dof*((self.qh[i] - self.ql[i])**2))
533  # print "qs[i] = ", qs[i], " mean = ", mean, " qh-ql= ", self.qh[i] - self.ql[i], " df = ", df
534 
535  else:
536  assert False, genpy.err_str(__name__, self.__class__.__name__, 'objective_function_value', self.config_settings.joint_handling[i] + " is not a valid value for joint_handling")
537  f += df
538  return f
539 
540 # \endcond
def free_config
This function picks and returns the values of free joints among all the joints in the given argument ...
def set_config
Use this function to set the joint configuration to the given desired values.
qh
A vector of real numbers representing higher bounds for the joint configuration The array is of lengt...
joint_handling
An array of string containing the specific mapping function for each joint The array is of length DOF...
DOF
An integer: Is a short form of Degrees of Freedom and represents the number of free joints...
def config_str
Use this function to see the current configuration of the manipulator.
This class represents a model of the joint configuration of a chained-link manipulator.
ql
A vector of real numbers representing lower bounds for the joint configuration.
joint_label
An array of string containing indivifual labels or names the for each joint.
def set_joint_bounds
Only use this function to set the joint limits.
def joint_in_range
This function is used to check if a given value for specific joint is in its feasibility range...
joint_limits_respected
A boolean specify if the joint limits must be respected when new joint values are being set...
def joint_stepsize_interval
The correction of joints is always restricted by joint limits and maximum feasible joint speed If you...
def mapfrom_virtual
This function converts the free joint values from unlimited virtual joint-space into their actual val...
def random_config
Generates a random joint configuration in the defined feasible range in the settings.
def grid_config
If The feasible range of each joint is divided into a number of equal intervals, a joint-space lattic...
def mapto_virtual
This function converts the current actual free joint values (picked from property q) into their equiv...
def joints_in_range
This function is used to check if all values of the given joint array are in their feasibility range...
prismatic
A list of booleans representing the type of the corresponding joint number.
def set_config_virtual
Sets the configuration given values of the free joints in the virtual joint-space.
This class contains joint properties of a chained-link manipulator.