MAGIKS  1.1
Manipulator General Inverse Kinematic Solver
 All Classes Namespaces Files Functions Variables Pages
kinematic_manager.py
Go to the documentation of this file.
1 # HEADER
2 
3 ## @file kinematic_manager.py
4 # @brief This module contains the main class for handling the kinematics of a manipulator
5 # @author Nima Ramezani Taghiabadi
6 #
7 # PhD Researcher
8 # Faculty of Engineering and Information Technology
9 # University of Technology Sydney (UTS)
10 # Broadway, Ultimo, NSW 2007, Australia
11 # Phone No. : 04 5027 4611
12 # Email(1) : nima.ramezani@gmail.com
13 # Email(2) : Nima.RamezaniTaghiabadi@uts.edu.au
14 # @version 3.0
15 #
16 # Last Revision: 03 January 2015
17 
18 # BODY
19 
20 import numpy, math, time, copy, pickle
21 import general_python as genpy
24 
25 from math_tools.geometry import rotation, pose_metric as metriclib
26 from magiks.magiks_core import inverse_kinematics as iklib, log_manager as loglib, manipulator_library as manlib
27 from magiks.taskspace import endeffector as endlib, workspace as wslib
28 
29 """
30 def generate_my_default_kin_manager() :
31  '''
32  the name of method says that it creates somthing , but that it sets values, "massively"
33  '''
34  default_grids = ...
35 """
36 '''
37 'PP': 'Pose Projection', # Inverse Kinematics for a single pose
38 'TG': 'Trajectory Generation', # Constant Target Kinematic Control
39 'TP': 'Trajectory Projection', # Variable Target Kinematic Control
40 '''
41 all_application_scenarios = ['PPS', 'TGS', 'TPS']
42 
43 # \cond
44 key_dic = {
45  # For Application Scenario:
46  'NA' : 'Not Applicable',
47  'AS' : 'Application Scenario',
48  'PPS' : 'Pose Projection Scenario', # Single Pose Inverse Kinematic (Project a single pose to the workspace)
49  'TGS' : 'Trajectory Generation Scenario', # Kinematic Control-Constant Target Scenario
50  'TPS' : 'Trajectory Projection Scenario', # Kinematic Control-Variable Target Scenario (Project a ts trajectory to the jointspace)(Tracking a taskspace trajectory)
51  # For Algorithm (Joint Update Rule):
52  'AL' : 'Algorithm',
53  'JI' : 'Jacobian Inverse',
54  'JT' : 'Jacobian Transpose',
55  'JPI' : 'Jacobian Pseudo Inverse',
56  'DLS(CDF)' : 'Damped Least Squares Method (Constant Damping Factor)',
57  'DLS(ADF)' : 'Damped Least Squares Method (Adaptive Damping Factor)',
58  'DLS(MADF)' : 'Damped Least Squares Method (Manipulability Adjusted Damping Factor)',
59 
60  # For Manipulators:
61  'MAN' : 'Manipulator',
62  'PUMA' : 'PUMA (6 DOF)',
63  'PA10' : 'Mitsubishi PA10 (7 DOF)',
64  'EXO' : 'DFKI Capio Exoskeleton (9 DOF)',
65  'PR2ARM' : 'Willowgarage PR2 Arm (7 DOF)',
66  # For Position Metrics:
67  'DiCaCo(xyz)' : 'Difference of Cartesian Coordinates x-y-z', # default
68  'DiCaCo(xy)' : 'Difference of Cartesian Coordinates x-y',
69  'DiCaCo(xz)' : 'Identical Cartesian Coordinates x-z',
70  'DiCaCo(yz)' : 'Identical Cartesian Coordinates y-z',
71  'DiCaCo(x)' : 'Identical Cartesian Coordinates x',
72  'DiCaCo(y)' : 'Identical Cartesian Coordinates y',
73  'DiCaCo(z)' : 'Identical Cartesian Coordinates z',
74  # For Orientation Metrics:
75  'AxInPr(ijk)' : 'Axis Inner Product (Aligned Axis i-j-k)',
76  'AxInPr(ij)' : 'Axis Inner Product (Aligned Axis i-j)',
77  'AxInPr(ik)' : 'Axis Inner Product (Aligned Axis i-k)',
78  'AxInPr(jk)' : 'Axis Inner Product (Aligned Axis j-k)',
79  'AxInPr(i)' : 'Axis Inner Product (Aligned Axis i)',
80  'AxInPr(j)' : 'Axis Inner Product (Aligned Axis j)',
81  'AxInPr(k)' : 'Axis Inner Product (Aligned Axis k)',
82  'ReRoMaTr' : 'Trace of Relative Rotation Matrix',
83  'ReRoMa' : 'Relative Rotation Matrix',
84  'DiAnAx' : 'Difference of Angle-Axis',
85  'DiUnQu' : 'Difference of Unit Quaternions',
86  'ReAnAx' : 'Relative Angle-Axis',
87  'ReUnQu' : 'Relative Unit Quaternion',
88  'DiNoQu' : 'Difference of Non-Redundant(Normalized) Quaternions',
89  'ReRoAn' : 'Relative Rotation Angle',
90  'ReOrVe(LIN)' : 'Relative Orientation Vector (Linear parametrization)',
91  'ReOrVe(IDTY)' : 'Relative Orientation Vector (Identity parametrization)',
92  'ReOrVe(CaGiRo)': 'Relative Orientation Vector (Cayley-Gibbs-Rodrigues parametrization)' ,
93  'ReOrVe(EXP)' : 'Relative Orientation Vector (Exponential parametrization)' ,
94  'ReOrVe(BaTr)' : 'Relative Orientation Vector (Bauchau-Trainelli parametrization)' ,
95  'DiRoMa' : 'Difference of Rotation Matrices',
96  'DiOrVe(IDTY)' : 'Difference of Orientation Vectors (Identity parametrization)',
97  'DiOrVe(LIN)' : 'Difference of Orientation Vectors (Linear parametrization)',
98  'DiOrVe(CaGiRo)': 'Difference of Orientation Vectors (Cayley-Gibbs-Rodrigues parametrization)' ,
99  'DiOrVe(EXP)' : 'Difference of Orientation Vectors (Exponential parametrization)' ,
100  'DiOrVe(BaTr)' : 'Difference of Orientation Vectors (Bauchau-Trainelli parametrization)' ,
101  # Special Orientation Metrics:
102  'AxInPr + DiNoQu': 'Combined AxInPr and DiNoQu',
103  'ReRoAn + ReOrVe(LIN)': 'Combined Relative Angle and Vector (Linear Parametrization)',
104 
105  # For Joinspace Mapping:
106  'NM' : 'No Mapping', # default
107  'LM' : 'Linear Mapping',
108  'TM' : 'Trogonometric Mapping',
109  'MM' : 'Mechanism Mapping',
110  # For Workspace Coverage:
111  'WCTP' : 'Workspace Coverage for Target Poses',
112  'WCIC' : 'Workspace Coverage for Initial Configurations',
113 
114  # Forward:
115  'KC' : 'Kinematic Constraints',
116  'PP' : 'Precision for Position (mm)',
117  'PO' : 'Precision for Orientation (deg)',
118  'PM' : 'Position Metric',
119  'OM' : 'Orientation Metric',
120  'JM' : 'Joint Mapping',
121  'DF' : 'Damping Factor',
122  'DFG' : 'Damping Factor Gain',
123  'MNI' : 'Maximum Number of Iterations',
124 
125  # Inverse:
126  'Application Scenario' : 'AS',
127  'Algorithm' : 'AL',
128  'Manipulator' : 'MAN',
129  'Kinematic Constraints' : 'KC',
130  'Precision for Position (mm)' : 'PP',
131  'Precision for Orientation (deg)' : 'PO',
132  'Position Metric' : 'PM',
133  'Orientation Metric' : 'OM',
134  'Join Mapping' : 'JM',
135  'Damping Factor' : 'DF',
136  'Damping Factor Gain' : 'DFG'
137 }
138 
139 
140 nkc_dic = {'DiCaCo(xyz)':3,'DiCaCo(xy)':2,'DiCaCo(xz)':2,'DiCaCo(yz)':2, 'DiCaCo(x)':1, 'DiCaCo(y)':1,'DiCaCo(z)':1,
141  'AxInPr(ijk)':3,'AxInPr(ij)':3,'AxInPr(ik)':3,'AxInPr(jk)':3, 'AxInPr(i)':2, 'AxInPr(j)':2,'AxInPr(k)':2}
142 
143 param_dic = {'ReOrVe(IDTY)':'identity', 'ReOrVe(LIN)':'linear', 'ReOrVe(CaGiRo)' : 'cayley-gibbs-rodrigues', 'ReOrVe(EXP)' : 'exponential', 'ReOrVe(BaTr)' : 'bauchau-trainelli',
144  'DiOrVe(IDTY)':'identity', 'DiOrVe(LIN)':'linear', 'DiOrVe(CaGiRo)' : 'cayley-gibbs-rodrigues', 'DiOrVe(EXP)' : 'exponential', 'DiOrVe(BaTr)' : 'bauchau-trainelli'}
145 
146 def generate_orientation_metric_settings(orientation_constraint):
147 
148  if orientation_constraint[0:6] == 'AxInPr':
149  # ms = metriclib.Metric_Settings(metric_type = 'relative', representation = 'diag')
150  ms = metriclib.Metric_Settings(metric_type = 'special', representation = 'AxInPr')
151 
152  # Set Weighting Matrix and Power Array for AxInPr Group:
153 
154  if orientation_constraint == 'AxInPr(ij)':
155  ms.weight = numpy.array([[1, 0, 0], [0, 1, 0]] )
156  ms.power = numpy.array([1, 1, 0])
157  ms.required_identical_coordinate = [True, True, False]
158  elif orientation_constraint == 'AxInPr(jk)':
159  ms.weight = numpy.array([[0, 1, 0], [0, 0, 1]])
160  ms.power = numpy.array([0, 1, 1])
161  ms.required_identical_coordinate = [False, True, True]
162  elif orientation_constraint == 'AxInPr(ik)':
163  ms.weight = numpy.array([[1, 0, 0], [0, 0, 1]] )
164  ms.power = numpy.array([1, 0, 1])
165  ms.offset = numpy.array([-1.0, -1.0])
166  ms.required_identical_coordinate = [True, False, True]
167  elif orientation_constraint == 'AxInPr(i)':
168  ms.weight = numpy.array([[1, 0, 0]] )
169  ms.power = numpy.array([1, 0, 0])
170  ms.required_identical_coordinate = [True, False, False]
171  elif orientation_constraint == 'AxInPr(j)':
172  ms.weight = numpy.array([[0, 1, 0]] )
173  ms.power = numpy.array([0, 1, 0])
174  ms.required_identical_coordinate = [False, True, False]
175  elif orientation_constraint == 'AxInPr(k)':
176  ms.weight = numpy.array([[0, 0, 1]] )
177  ms.power = numpy.array([0, 0, 1])
178  ms.required_identical_coordinate = [False, False, True]
179 
180  if orientation_constraint == 'AxInPr(ijk)':
181  ms.offset = - numpy.ones(3)
182  elif orientation_constraint in ['AxInPr(ij)', 'AxInPr(ik)', 'AxInPr(jk)']:
183  ms.offset = - numpy.ones(2)
184  elif orientation_constraint in ['AxInPr(i)', 'AxInPr(j)', 'AxInPr(k)']:
185  ms.offset = - numpy.ones(1)
186  else:
187  assert False
188 
189  elif orientation_constraint == 'ReRoMaTr':
190  '''
191  represents the orientation error by calculating the trace of relative rotation matrix minus three: Trace(R_a * R_d^T) - 3
192  '''
193  #Defibe basis error function. It ensures that trace of relative rotation matrix is three or : trace(R_a * R_d^T) = 3.0
194  ms = metriclib.Metric_Settings(metric_type = 'relative', representation = 'trace')
195  # define the appropriate weighting matrix.
196  ms.weight = numpy.array([[1]])
197  # define the corresponding power array. (Please refer to the documentation)
198  ms.power = numpy.array([1])
199  ms.offset = numpy.array([- 3.0])
200 
201  elif orientation_constraint == 'ReRoAn':
202  ms = metriclib.Metric_Settings(metric_type = 'relative', representation = 'angle')
203  ms.weight = numpy.array([[1]])
204  ms.power = numpy.array([1])
205  ms.offset = numpy.array([0])
206 
207  elif orientation_constraint in ['ReOrVe(IDTY)', 'ReOrVe(LIN)', 'ReOrVe(CaGiRo)', 'ReOrVe(EXP)', 'ReOrVe(BaTr)']:
208  ms = metriclib.Metric_Settings(metric_type = 'relative', representation = 'vector')
209  ms.parametrization = param_dic[orientation_constraint]
210 
211  elif orientation_constraint in ['DiOrVe(IDTY)', 'DiOrVe(LIN)', 'DiOrVe(CaGiRo)', 'DiOrVe(EXP)', 'DiOrVe(BaTr)']:
212  ms = metriclib.Metric_Settings(metric_type = 'differential', representation = 'vector')
213  ms.parametrization = param_dic[orientation_constraint]
214 
215  elif orientation_constraint == 'DiNoQu':
216  ms = metriclib.Metric_Settings(metric_type = 'special', representation = 'DiNoQu')
217  ms.weight = numpy.eye(3)
218  ms.power = numpy.ones(3)
219  ms.offset = numpy.zeros(3)
220 
221  elif orientation_constraint == 'DiUnQu':
222  ms = metriclib.Metric_Settings(metric_type = 'differential', representation = 'quaternion')
223  ms.weight = numpy.eye(4)
224  ms.power = numpy.array([1, 1, 1, 1])
225  ms.offset = numpy.array([0, 0, 0, 0])
226 
227  elif orientation_constraint == 'DiAnAx':
228  ms = metriclib.Metric_Settings(metric_type = 'differential', representation = 'angle_axis')
229  ms.weight = numpy.eye(4)
230  ms.power = numpy.array([1, 1, 1, 1])
231  ms.offset = numpy.array([0, 0, 0, 0])
232 
233  elif orientation_constraint == 'DiRoMa':
234  ms = metriclib.Metric_Settings(metric_type = 'differential', representation = 'matrix')
235  ms.weight = numpy.eye(9)
236  ms.power = numpy.ones(9)
237  ms.offset = numpy.zeros(9)
238 
239  elif orientation_constraint == 'ReRoMa':
240  ms = metriclib.Metric_Settings(metric_type = 'relative', representation = 'matrix')
241  ms.weight = numpy.eye(9)
242  ms.power = numpy.ones(9)
243  ms.offset = - numpy.eye(3).flatten()
244 
245  elif orientation_constraint == 'ReUnQu':
246  ms = metriclib.Metric_Settings(metric_type = 'relative', representation = 'quaternion')
247  ms.weight = numpy.eye(4)
248  ms.power = numpy.ones(4)
249  ms.offset = numpy.array([- 1.0, 0.0, 0.0, 0.0])
250 
251  elif orientation_constraint == 'ReAnAx':
252  ms = metriclib.Metric_Settings(metric_type = 'relative', representation = 'angle_axis')
253  ms.weight = numpy.eye(4)
254  ms.power = numpy.array([1, 1, 1, 1])
255  ms.offset = numpy.array([0, 0, 0, 0])
256 
257  # Special Metrics
258  elif orientation_constraint == 'AxInPr(ijk) + DiNoQu':
259  ms = metriclib.Metric_Settings(metric_type = 'special', representation = 'AxInPr + DiNoQu')
260  ms.weight = numpy.eye(6)
261  ms.power = numpy.ones(6)
262  ms.offset = numpy.array([-1.0, -1.0, -1.0, 0.0, 0.0, 0.0])
263 
264  elif orientation_constraint == 'ReRoAn + ReOrVe(LIN)':
265  ms = metriclib.Metric_Settings(metric_type = 'special', representation = 'ReRoAn + ReOrVe')
266  ms.weight = numpy.eye(4)
267  ms.power = numpy.ones(4)
268  ms.offset = numpy.zeros(4)
269  ms.parametrization = 'linear'
270  else:
271  assert False, func_name + ": " + orientation_constraint + " is an unknown value for orientation_constraint"
272 
273  return ms
274 
275 def generate_position_metric_settings(position_constraint):
276  func_name = ".generate_position_metric_settings()"
277  if position_constraint == 'DiCaCo(xyz)':
278  ms = metriclib.Metric_Settings()
279  elif position_constraint == 'DiCaCo(xy)':
280  ms = metriclib.Metric_Settings()
281  ms.weight = numpy.array([[1, 0, 0], [0, 1, 0]] )
282  ms.power = numpy.array([1, 1, 0])
283  ms.offset = numpy.zeros(2)
284  ms.required_identical_coordinate = [True, True, False]
285  elif position_constraint == 'DiCaCo(xz)':
286  ms = metriclib.Metric_Settings()
287  ms.weight = numpy.array([[1, 0, 0], [0, 0, 1]] )
288  ms.power = numpy.array([1, 0, 1])
289  ms.constant_offset = numpy.zeros(2)
290  ms.required_identical_coordinate = [True, False, True]
291  elif position_constraint == 'DiCaCo(yz)':
292  ms = metriclib.Metric_Settings()
293  ms.constant_offset = numpy.zeros(2)
294  ms.weighting_matrix = numpy.array([[0, 1, 0], [0, 0, 1]])
295  ms.power_array = numpy.array([0, 1, 1])
296  ms.required_identical_coordinate = [False, True, True]
297  elif position_constraint == 'DiCaCo(x)':
298  ms = metriclib.Metric_Settings()
299  ms.weight = numpy.array([[1, 0, 0]] )
300  ms.power = numpy.array([1, 0, 0])
301  ms.offset = numpy.zeros(1)
302  ms.required_identical_coordinate = [True, False, False]
303  elif position_constraint == 'DiCaCo(y)':
304  ms = metriclib.Metric_Settings()
305  ms.weight = numpy.array([[0, 1, 0]] )
306  ms.power = numpy.array([0, 1, 0])
307  ms.offset = numpy.zeros(1)
308  ms.required_identical_coordinate = [False, True, False]
309  elif position_constraint == 'DiCaCo(z)':
310  ms = metriclib.Metric_Settings()
311  ms.weight = numpy.array([[0, 0, 1]] )
312  ms.power = numpy.array([0, 0, 1])
313  ms.offset = numpy.numpy.zeros(1)
314  ms.required_identical_coordinate = [False, False, True]
315  else:
316  assert False, __name__ + func_name + ": " + position_constraint + " is an unknown value for position_constraint"
317  return ms
318 
319 class Kinematic_Manager_Settings(object):
320  '''
321  '''
322 
323 # def __init__(self, manip_name, ik_settings, grid_settings, loging_settings, .. ):
324 
325 
326  def __init__(self, manip_name):
327  '''
328  '''
329  err_head = "Error from kinematic_manager.Kinematic_Manager_Settings."
330 
331 
332  self.str_parameter_set = ['AS', 'AL','MAN', 'KC', 'MNI', 'PP', 'PO', 'PM', 'OM', 'JM', 'WCTP', 'WCIC', 'DF', 'DFG']
333  self.csv_parameter_set = ['AS', 'AL','MAN', 'KC', 'MNI', 'PP', 'PO', 'PM', 'OM', 'JM', 'WCTP', 'WCIC', 'DF', 'DFG']
334  self.key_parameter_set = ['AS', 'AL','MAN', 'KC', 'MNI', 'PM', 'OM', 'JM', 'WCTP', 'WCIC', 'PP','PO', 'DF', 'DFG']
335 
336  # Geometry Settings set from the Name of the manipulator
337  self.geo_settings = manlib.manip_geo_settings(manip_name)
338  #Number of Kinematic Constraints
339  '''
340  This value can reflect the number of endeffectors as well.
341  The value of this property has no influence in the model and is designed to be shown in the test key and the table of test specifications
342  '''
343  #Number of endeffectors (orientation references)
344  self.num_position_ref = 1
345  self.num_orientation_ref = 1
346 
347  self.application_scenario = 'PPS' # Pose Projection Scenario
348  self.solution_class = 'Numeric'
349 
350  self.orientation_constraint = 'AxInPr(jk)'
351  self.position_constraint = 'DiCaCo(xyz)' #Identical Cartesian Coordinates (x,y,z)
352 
353  # Representation of Orientation Error
354  #self.err_func_orient = 'Axis Inner Product'
355 
356  self.config_settings = manlib.manip_config_settings(manip_name, joint_mapping = 'NM')
357  self.end_settings = endlib.Endeffector_Settings()
358  self.ik_settings = iklib.Inverse_Kinematics_Settings(algorithm = "JPI", run_mode = 'normal_run', num_steps = 100)
359  # Setting Desired Precision in Inverse Kinematics
360  self.ik_settings.ngp_active = False
361 
362  self.end_settings.precision_base_for_position = "Coordinate Distance"
363  self.end_settings.precision_base_for_rotation = "Axis Angle"
364 
365  self.end_settings.precision_for_position = 0.01 # coordinate distance in meters or error_function value depending on the precision_base
366  self.end_settings.precision_for_rotation = 1.0 # axis angle in degrees or error_function value depending on the precision_base
367 
368 
369  # When searching for nearest starting config in a precomputed set of poses, "self.workspace_settings_ic.grid_resolution" determine the jointspace grid size by which precomputed poses are generated
370  # "number_of_search_items" Determine how many startiong configs are to be found in search (Number of trials) (For each starting config, an IK trial is implemented)
371  self.workspace_settings_ic = wslib.Workspace_Settings(number_of_search_items = 10)
372  self.workspace_settings_tp = wslib.Workspace_Settings(representation_of_orientation = 'Rotation Matrix')
373 
374  # In the test evaluation, "self.grid_res_tar_pose" determine the jointspace grid size by which target poses are generated.
375 
376  import os
377 
378  ## MANUAL : path = os.getcwd() + "/" + manip_name
379  ## via LIB
380  path = os.path.join( os.getcwd(), manip_name+ '_results' )
381 
382  if os.path.exists(path) == False:
383  print "path not found"
384  os.makedirs(path)
385 
386  # similar simplification ...
387  self.path_str = path + '/'
388 
389  def NKC(self):
390  if self.orientation_constraint[0:6] == 'AxInPr':
391  noc = nkc_dic[self.orientation_constraint]
392  else:
393  noc = 3
394  return self.num_position_ref*nkc_dic[self.position_constraint] + self.num_orientation_ref*noc
395 
396  def valid(self):
397  func_name = 'valid()'
398  vld = True
399  vld = vld and (self.application_scenario in all_application_scenarios)
400  assert vld, self.__class__.err_head + func_name + ": The given application_scenario is not known!"
401  return vld
402 
403  def __str__( self, parameter_set = None ) :
404  '''
405  returns the algorithmic setting for the inverse kinematic evaluator
406  '''
407  if parameter_set == None:
408  parameter_set = self.str_parameter_set
409  s = '\n'
410  s += 'Kinematic Manager Settings:' + '\n' + '\n'
411  for p in parameter_set:
412  value = self.parameter_value(p)
413  param = key_dic[p]
414  if p in ['KC','PP','PO', 'DF', 'DFG', 'MNI', 'WCTP', 'WCIC']:
415  s += param + " "*(45-len(param)) +': ' + value + '\n'
416  else:
417  s += param + " "*(45-len(param)) + ': ' + key_dic[value] + '\n'
418  '''
419  s += 'Application Scenario : ' + key_dic[self.application_scenario] + '\n'
420  s += 'Algorithm : ' + key_dic[self.ik_settings.algorithm] + '\n'
421  s += 'Manipulator : ' + self.manip_name + '\n'
422  s += 'Number of position references : ' + str(self.num_position_ref) + '\n'
423  s += 'Number of orientation references : ' + str(self.num_orientation_ref) + '\n'
424  s += 'Metric for position : ' + key_dic[self.position_constraint] + '\n'
425  s += 'Metric for orientation : ' + key_dic[self.orientation_constraint] + '\n'
426  s += 'Maximum number of iterations : ' + str(self.ik_settings.number_of_steps) + '\n' + '\n'
427 
428  s += 'Initial Configuration Workspace: ' + '\n'
429  s += str(self.workspace_settings_ic) + '\n'
430 
431  s += 'Target Pose Workspace: ' + '\n'
432  s += str(self.workspace_settings_tp) + '\n'
433  '''
434  return s
435 
436  def parameter_value(self, parameter):
437  if parameter == 'AS':
438  return self.application_scenario
439  elif parameter == 'AL':
440  return self.ik_settings.algorithm
441  elif parameter == 'MAN':
442  return self.geo_settings.name
443  elif parameter == 'KC':
444  return str(self.NKC())
445  elif parameter == 'MNI':
446  return str(self.ik_settings.number_of_steps)
447  elif parameter == 'PP':
448  return str(1000*self.end_settings.precision_for_position)
449  elif parameter == 'PO':
450  return str(self.end_settings.precision_for_rotation)
451  elif parameter == 'PM':
452  if self.num_position_ref == 0:
453  return 'NA'
454  else:
455  return self.position_constraint
456  elif parameter == 'OM':
457  if self.num_orientation_ref == 0:
458  return 'NA'
459  else:
460  return self.orientation_constraint
461  elif parameter == 'JM':
462  if 'TM' in self.config_settings.joint_handling:
463  return 'TM'
464  elif 'LM' in self.config_settings.joint_handling:
465  return 'LM'
466  else:
467  return 'NM'
468  # return genpy.most_common(self.config_settings.joint_handling)
469  elif parameter == 'DF':
470  if self.ik_settings.algorithm[0:3] == 'DLS':
471  return str(self.ik_settings.initial_damping_factor)
472  else:
473  return 'NA'
474  elif parameter == 'DFG':
475  if self.ik_settings.algorithm == 'DLS(ADF)':
476  return str(self.ik_settings.df_gain)
477  elif self.ik_settings.algorithm == 'DLS(MADF)':
478  return str(self.ik_settings.manipulability_threshold)
479  else:
480  return 'NA'
481 
482  elif parameter == 'WCTP':
483  return self.workspace_settings_tp.gen_key()
484  elif parameter == 'WCIC':
485  return self.workspace_settings_ic.gen_key()
486  else:
487  assert False, genpy.err_str(__name__, self.__class__.__name__, 'parameter_value', parameter + ' is an Unknown Setting Parameter')
488 
489  def csv(self, header = True, parameter_set = None):
490  '''
491  returns the algorithmic setting for the inverse kinematic evaluator
492  '''
493  if parameter_set == None:
494  parameter_set = self.csv_parameter_set
495 
496  if header:
497  s = 'Setting Parameter' + ',' + 'Parameter Key' + ',' + 'Value' + ',' + 'Interpretation' + '\n'
498  else:
499  s = ''
500 
501  for p in parameter_set:
502  value = self.parameter_value(p)
503  s += key_dic[p] + ',' + p + ',' + value + ','
504  if not p in ['KC','PP','PO', 'DF', 'DFG','MNI', 'WCTP', 'WCIC']:
505  s += key_dic[value]
506  s += '\n'
507  return s
508 
509  def latex(self, header = True, parameter_set = None):
510  '''
511  returns the algorithmic setting for the inverse kinematic evaluator in latex format
512  '''
513  lf = '& \multicolumn{1}{l}{} & \multicolumn{1}{l}{} & \\ \n'
514  if parameter_set == None:
515  parameter_set = self.csv_parameter_set
516 
517  s = '\begin{table}[h]' + '\n' + '\begin{tabular}{lccl}' + '\n' + '\hline' + '\n'
518 
519  if header:
520  s += '\multicolumn{1}{c}{\textbf{Setting Parameter}}' + '&' + '\textbf{Parameter Key}' + '&' + '\textbf{Value}' + '&' + '\multicolumn{1}{c}{\textbf{Interpretation}}' + '\\ \hline \n'
521  s += lf
522  for p in parameter_set:
523  value = self.parameter_value(p)
524  s += key_dic[p] + '&' + p + '&' + value + '&'
525  if not p in ['KC','PP','PO', 'DF', 'DFG','MNI', 'WCTP', 'WCIC']:
526  s += key_dic[value]
527  s += '\\ \n'
528  s += lf
529  s += '\hline \n \end{tabular} \n \end{table}'
530  return s
531 
532  def csv_horizontal_header(self, parameter_set = None, use_key = False):
533  if parameter_set == None:
534  parameter_set = self.csv_parameter_set
535  s = ''
536  for p in parameter_set:
537  if use_key:
538  s += p + ","
539  else:
540  s += key_dic[p] + ","
541  s = s[0:len(s) - 1]
542  return s
543 
544  def csv_horizontal(self, parameter_set = None):
545  if parameter_set == None:
546  parameter_set = self.csv_parameter_set
547  s = ''
548  for p in parameter_set:
549  s += self.parameter_value(p) + ','
550  s = s[0:len(s) - 1]
551 
552  return s
553 
554  def generate_key( self, parameter_set = None):
555  '''
556  returns the settings key string for the test evaluator
557  '''
558  s = ''
559  if parameter_set == None:
560  parameter_set = self.key_parameter_set
561  for p in parameter_set:
562  if p in ['KC','PP','PO', 'DF', 'DFG','MNI', 'WCTP', 'WCIC']:
563  s += p + ':' + self.parameter_value(p) + '_'
564  else:
565  s += self.parameter_value(p) + '_'
566  return s[0:len(s) - 1]
567 
568  '''
569  if self.valid():
570 
571  key_str = "AS:" + self.application_scenario
572  rg_str = self.manip_name
573  key_str += "_RG:" + rg_str
574 
575  key_str += "_AL:" + self.ik_settings.algorithm
576  key_str += "_EE:"
577  for i in range(0, self.num_position_ref):
578  key_str += 'P'
579  for i in range(0, self.num_orientation_ref):
580  key_str += 'O'
581 
582  key_str += "_PRF:" + self.position_constraint + '-' + self.orientation_constraint
583 
584  key_str += '_TP:' + self.workspace_settings_tp.gen_key()
585  key_str += '_IC:' + self.workspace_settings_ic.gen_key()+'-'+self.workspace_settings_ic.search_criteria_key()
586 
587  return key_str
588  else:
589  print("Error from Kinematic_Manager_Settings.generate_key():Invalid Settings")
590  return None
591  '''
592 
593 class Kinematic_Manager(object):
594  '''
595 
596  Kinematic_Manager is the kinematic manager of a manipulator.
597  contains a mathematical kinematic model of a chain of joints and links which can be referred to a robot or any mechanical manipulator,
598  the whole or parts of human or animal moving mechanism.
599  This class contains all kinematic properties of a manipulator like geometry, joint configuration, transfer matrices, endeffector(s) and the jacobians
600  plus other miscellaneous geometric and algorithmic parameters for forward and inverse kinematic computations.
601  It also has a method which evaluate the performance of inverse kinematic solver by evaluating it for a set of target poses in the
602  workspace generated from a jointspace grid.
603  '''
604 
605  def __init__(self, settings):
606  '''
607  Predefined Class Properties :
608  '''
609  self.settings = settings
610  self.km_log = loglib.Test_Log(settings)
611 
612  # "self.forward_kinematics" is an instance of class "Forward_Kinematics" in package "kinemagic" which contains all kinematic properties of a manipulator which depend on the joint configuration
613  # These properties are: transfer matrices, analytic, geometric and error jacobians, taskpoints and taskframes and the pose error vector.
614 
615  #self.forward_kinematics = fklib.Forward_Kinematics(geometry, config)
616  if self.settings.workspace_settings_ic.search_criteria == 'NCC':
617  self.settings.ik_settings.include_current_config = True
618  else:
619  self.settings.ik_settings.include_current_config = False
620 
621 
622  self.inverse_kinematics = iklib.Inverse_Kinematics(self.settings.config_settings, self.settings.geo_settings, self.settings.end_settings, self.settings.ik_settings )
623 
624  #set desired position and orientation constraints:
625 
626  for tp in self.inverse_kinematics.task_point:
627  tp.error.settings = generate_position_metric_settings(self.settings.position_constraint)
628  tp.error.settings.precision = self.inverse_kinematics.end_settings.precision_for_position
629 
630  for tf in self.inverse_kinematics.task_frame:
631  tf.error.settings = generate_orientation_metric_settings(self.settings.orientation_constraint)
632  tf.error.settings.precision = self.inverse_kinematics.end_settings.precision_for_rotation
633 
634  self.inverse_kinematics.num_task_constraints()
635  #self.inverse_kinematics.configuration.set_joint_limits_for(settings.manip_name)
636  ###### self.inverse_kinematics.initialize()
637  '''
638  if self.settings.num_position_ref == 0:
639  self.inverse_kinematics.endeffector.reference_positions = []
640  if self.settings.num_orientation_ref == 0:
641  self.inverse_kinematics.endeffector.reference_orientations = []
642  '''
643 
644  if settings.workspace_settings_ic.read_workspace:
645  print 'Reading Init Config Workspace ... '
646  self.workspace_ic = wslib.read_from_file(settings.path_str + settings.workspace_settings_ic.gen_file_name(geometry.name))
647  self.workspace_ic.settings = self.settings.workspace_settings_ic
648  print 'Reading Init Config Workspace Finished '
649  else:
650  self.workspace_ic = wslib.Workspace(settings.config_settings, settings.geo_settings, settings.end_settings, settings.workspace_settings_ic)
651  self.workspace_ic.create()
652 
653  if settings.workspace_settings_ic.write_workspace:
654  print 'Saving init config workspace to : ', settings.path_str + settings.workspace_settings_ic.gen_file_name(geometry.name) + ' ... '
655  self.workspace_ic.write_to_file(settings.path_str + settings.workspace_settings_ic.gen_file_name(geometry.name))
656  print 'Finished saving workspace.'
657 
658  if settings.workspace_settings_tp.read_workspace:
659  print 'Reading Target Pose Workspace ... '
660  st = copy.copy(self.settings.workspace_settings_tp)
661  self.workspace_tp = wslib.read_from_file(settings.path_str + settings.workspace_settings_tp.gen_file_name(geometry.name))
662  self.workspace_tp.settings = self.settings.workspace_settings_tp
663  print 'Reading Target Pose Workspace Finished '
664  else:
665  self.workspace_tp = wslib.Workspace(settings.config_settings, settings.geo_settings, settings.end_settings, settings.workspace_settings_tp)
666  self.workspace_tp.create()
667  if settings.workspace_settings_tp.write_workspace:
668  print 'Saving target pose workspace to : ', settings.path_str + settings.workspace_settings_tp.gen_file_name(geometry.name) + ' ... '
669  self.workspace_tp.write_to_file(settings.path_str + settings.workspace_settings_tp.gen_file_name(geometry.name))
670  print 'Finished saving workspace.'
671 
672  #self.inverse_kinematics.settings.number_of_steps = settings.max_num_iters
673 
674  #self.inverse_kinematics.configuration.joint_handling = settings.joint_map
675 
676  def evaluate_ik_solver(self, verbose = False):
677  '''
678  run for the whole grid
679 
680  Evaluate the ik solver by implementing it for a number of target poses which are evenly distributed in the workspace of the manipulator
681  A grid(lattice) is created in the jointspace and the target poses are generated by computing the forward kinematics for those configurations
682  Therefore, each configuration makes a corresponding target pose
683  The ik solver is implemented for each target pose, from a constant initial configuration and a list of results is returned.
684  '''
685  # "p" specifies the number of tested target poses = number of configurations in the gridded jointspace
686  #p = self.settings.grid_res_tar_pose ** self.inverse_kinematics.configuration.DOF
687  n_suc = 0 #specifies number of successful attempts
688  n_iters_total = 0 #specifies total number of iterations
689  time_total = 0.00 #specifies total implementation time
690  cnt = 0
691  self.km_log.body = []
692 
693  for pose_tuple in self.workspace_tp.pose_list:
694 
695  #for qq in self.workspace_tp.config_list:
696 
697  #Set target for IK solver
698 
699  #self.take_target_to_grid_configuration(config_number = i, number_of_intervals = self.settings.grid_res_tar_pose)
700  '''
701  self.inverse_kinematics.configuration.q = numpy.copy(qq)
702  self.inverse_kinematics.forward_update()
703 
704  for tp in self.inverse_kinematics.endeffector.reference_positions:
705  tp.rd = numpy.copy(tp.ra)
706  for tf in self.inverse_kinematics.endeffector.reference_orientations:
707  tf.rd = numpy.copy(tf.ra)
708  '''
709  self.inverse_kinematics.tuple_to_pose('desired', pose_tuple, self.settings.workspace_settings_tp.representation_of_orientation)
710 
711  #take the manipulator to stored initial state
712  #self.inverse_kinematics.take_to_grid_configuration(0, self.settings.workspace_settings_ic.grid_resolution)
713 
714  start_kinematic_inversion = time.time()
715 
716  #find a list of the best initial configurations:
717 
718  self.inverse_kinematics.initial_config_list = self.workspace_ic.nearest_configs(self.inverse_kinematics)
719 
720  #implement the inverse kinematic solver
721  self.inverse_kinematics.goto_target()
722 
723  elapsed_kinematic_inversion = time.time() - start_kinematic_inversion
724 
725  self.workspace_tp.config_list[cnt] = numpy.copy(self.inverse_kinematics.q)
726 
727  (running_time, number_of_steps) = (self.inverse_kinematics.run_log.time_elapsed, len(self.inverse_kinematics.run_log.step))
728 
729  if number_of_steps == 0:
730  number_of_steps = 1
731  average_step_time = running_time / number_of_steps
732  n_iters_total = n_iters_total + number_of_steps
733 
734  if self.inverse_kinematics.in_target():
735  n_suc = n_suc + 1
736 
737  time_total = time_total + elapsed_kinematic_inversion
738 
739  # Retrieve initial status from which the solution is achieved:
740  ik_initial = copy.deepcopy(self.inverse_kinematics)
741  assert ik_initial.set_config(self.inverse_kinematics.initial_config)
742  if ik_initial.in_target():
743  print "Already in Target!"
744 
745  start_config_str = ik_initial.config_str()
746  start_pose_str = str(ik_initial)
747  # Final status:
748  final_config_str = self.inverse_kinematics.config_str()
749  final_pose_str = str(self.inverse_kinematics)
750 
751  run_log = loglib.Single_Run_Log(cnt, success = self.inverse_kinematics.in_target(), config_in_range = self.inverse_kinematics.joints_in_range(self.inverse_kinematics.free_config(self.inverse_kinematics.q)))
752  run_log.num_trial = 1 + int(number_of_steps/self.inverse_kinematics.ik_settings.number_of_steps)
753  run_log.num_suc_til_now = n_suc
754  run_log.num_iter = number_of_steps
755  run_log.num_iter_til_now = n_iters_total
756  run_log.run_time = elapsed_kinematic_inversion
757  run_log.run_time_til_now = time_total
758  run_log.mean_stp_time = average_step_time
759  run_log.start_config_str = start_config_str
760  run_log.final_config_str = final_config_str
761  run_log.start_pose_str = start_pose_str
762  run_log.final_pose_str = final_pose_str
763 
764  self.km_log.body.append(run_log)
765 
766  cnt += 1
767 
768  #test_result_list.append(result_info_detail)
769  if verbose:
770  print str(self.km_log.body[cnt - 1])
771  print 'Log: (Running Time, Number of Iterations)', (running_time, number_of_steps)
772  print "______________________________________________________________________________________________________________________________"
773 
774  #evaluation_log = (self.inverse_kinematics.endeffector.in_target, elapsed_kinematic_inversion, self.inverse_kinematics.log_info)
775  #self.log_list.append(evaluation_log)
776  self.km_log.header = self.settings
777  self.km_log.footer.calculate_statistics(self.km_log.body)
778 
779 
780  def execute(self, save_evaluation_log = True, save_evaluation_results = False, save_evaluation_csv = True, verbose = False):
781  '''
782  execute the evaluation according to the settings
783  '''
784 
785  # set error function for orientation
786  #self.inverse_kinematics.number_of_steps = self.settings.max_num_iters
787  #self.inverse_kinematics.configuration.joint_handling = self.settings.joint_map
788 
789  result_info_detail = str()
790 
791  test_key_str = self.settings.generate_key()
792 
793  if self.settings.workspace_settings_ic.search_criteria == 'NCC': # Nearest to Current Configuration
794  assert self.inverse_kinematics.ik_settings.include_current_config, "Error todo"
795  else:
796  assert not self.inverse_kinematics.ik_settings.include_current_config, "Error todo"
797 
798  self.evaluate_ik_solver(verbose = verbose)
799 
800  if save_evaluation_csv:
801  self.km_log.write_csv(filename = self.settings.path_str + test_key_str + '.csv')
802 
803  if save_evaluation_log:
804  self.km_log.write_log(filename = self.settings.path_str + test_key_str + '.log')
805 
806  if save_evaluation_results:
807  self.km_log.write_self(filename = self.settings.path_str + test_key_str + '.res')
808 
809 # \endcond