MAGIKS  1.1
Manipulator General Inverse Kinematic Solver
 All Classes Namespaces Files Functions Variables Pages
inverse_kinematics.py
Go to the documentation of this file.
1 # HEADER
2 
3 ## @file inverse_kinematics.py
4 # @brief This module provides a functor class regaring the inverse kinematic calculations 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 5.1
15 #
16 # Last Revision: 21 August 2015
17 
18 '''
19 Changes from previous version:
20  1- added function js_create()
21  2- added settings in ik_settings:
22  respect_error_reduction, respect_limits_in_trajectories
23  3- property ik_settings.joint_limits_respected renamed to ik_settings.continue_until_inrange
24  4- method DLS(MADF) added, property manipulability_threshold added to the ik_settings
25  5- property run_log added to the object. Functions run(), run_dls_vdf(), js_project() and js_create() generate log
26  The log is plottable and can be saved as a .csv file
27 '''
28 
29 # BODY
30 
31 import math, time, sys, copy, numpy as np
32 
33 import general_python as genpy
34 
35 from math_tools import general_math as genmath
36 from math_tools.geometry import geometry as geo, trajectory as trajlib
37 from math_tools.algebra import polynomials, vectors_and_matrices as vecmat
38 from math_tools.discrete import discrete
39 
40 from magiks.jointspace import manipulator_configuration as conflib
41 from magiks.taskspace import endeffector as eflib
42 
43 all_algorithms = ['JI', 'JT', 'JPI', 'DLS(CDF)', 'DLS(ADF)', 'DLS(MADF)']
44 
45 # \cond
46 # Module Dictionaries:
47 key_dic = {
48  'JI' : 'Jacobian Inverse',
49  'JT' : 'Jacobian Transpose',
50  'JPI' : 'Jacobian Pseudo Inverse',
51  'DLS(CDF)' : 'Damped Least Squares Method(Constant Damping Factor)',
52  'DLS(ADF)' : 'Damped Least Squares Method(Adaptive Damping Factor)',
53  'DLS(MADF)' : 'Damped Least Squares Method(Manipulability Adjusted Damping Factor)'
54 }
55 
56 all_figures = ['Time', 'Duration', 'Phase', 'Manipulability', 'Damping Factor', 'In Range', 'Target Reached', 'Error Norm']
57 
58 class Step_Log():
59  def __init__(self):
60  self.current_time = 0.0
61  self.time_elapsed = 0.0
62  self.phase = 0.0
63  self.configuration = None
64  self.end_pose = None
65  self.pose_error = None
66  self.error_norm = None
67  self.manipulability = None
68  self.damping_factor = None
69  self.is_in_target = None
70  self.joints_in_range = None
71 
72  def value(self, figure):
73  if figure == 'Time':
74  return self.current_time
75  elif figure == 'Duration':
76  return self.time_elapsed
77  elif figure == 'Phase':
78  return self.phase
79  elif figure == 'Manipulability':
80  return self.manipulability
81  elif figure == 'Damping Factor':
82  return self.damping_factor
83  elif figure == 'In Range':
84  return self.joints_in_range
85  elif figure == 'Target Reached':
86  return self.is_in_target
87  elif figure == 'Error Norm':
88  return self.error_norm
89  else:
90  ers = figure + ' is not a valid value for argument figure'
91  assert False, genpy.err_str(__name__, self.__class__.__name__, sys._getframe().f_code.co_name, ers)
92 
93  def csv_str(self, figures = all_figures):
94  i = 0
95  s = str(i)
96  for fig in figures:
97  s += ',' + str(self.value(fig))
98  return s + '\n'
99 
100 class Run_Log():
101  def __init__(self):
102  self.clear()
103 
104  def initial_config(self):
105  return step[0].configuration
106 
107  def final_config(self):
108  lsi = len(self.step) - 1 # last step index
109  return step[lsi].configuration
110 
111  def success(self):
112  lsi = len(self.step) - 1 # last step index
113  return step[lsi].is_in_target
114 
115  def clear(self):
116  self.step = []
117  self.time_elapsed = 0.0
118  self.time_start = time.time()
119 
120  def csv_str(self, figures = all_figures, header = True):
121  if header:
122  s = 'Row'
123  for fig in figures:
124  s += ',' + fig
125  s += '\n'
126  else:
127  s = ''
128  for stp in self.step:
129  s += stp.csv_str(figures = figures)
130  return s
131 
132  def write_csv(self, filename = 'iklog.csv', figures = all_figures, header = True):
133  FILE_HANDLE = open(filename, "w")
134  FILE_HANDLE.write(self.csv_str(figures = figures, header = header))
135 
136  def plot(self, axis_x = 'Time', axis_y = 'Error Norm', ltype = '-', plt = None):
137  if plt == None:
138  show = True
139  import matplotlib.pyplot as plt
140  else:
141  show = False
142  x = []
143  y = []
144  for stp in self.step:
145  x.append(stp.value(axis_x))
146  y.append(stp.value(axis_y))
147 
148  plt.xlabel(axis_x)
149  plt.ylabel(axis_y)
150  plt.plot(x,y, ltype)
151 
152  if show:
153  plt.show()
154 
155 
156 class Inverse_Kinematics_Settings():
157  '''
158  '''
159  # Class Sets:
160  all_run_modes = [ 'normal_run', 'binary_run' ]
161  all_algorithms = [ 'JI', 'JT', 'JPI', 'DLS(CDF)', 'DLS(ADF)' , 'DLS(MADF)']
162 
163 
164  def __init__(self, algorithm = 'JPI', run_mode = 'normal_run', num_steps = 100):
165 
166  assert run_mode in self.__class__.all_run_modes, self.__class__.err_head + func_name + ": The given run_mode is not known!"
167  assert algorithm in self.__class__.all_algorithms, self.__class__.err_head + func_name + ": The given algorithm is not known!"
168 
169  self.ngp_active = True # Nullspace Gradient Projection Active?
170  self.continue_until_inrange = True # Continue iterations until all joints are in range?
171  self.return_min_config = True # If True returns the configuration corresponding to minimum error achieved if False returnts the config of the last iteration
172  self.respect_error_reduction = True # If True the configuration is added to the trajectory only if the norm of pose error is reduced
173  self.respect_limits = True # If True, position, velocity and acceleration limits will be respected in function moveto_target()
174  self.respect_limits_in_trajectories = True # If True, position, velocity and acceleration limits will be respected in output trajectories
175  self.generate_log = True # If True, the system will generate log after each run or trajectory creation/projection. The log is stored in property self.run_log
176  self.df_gain = 2.0 # Determines the damping factor gain in DLS-ADF algorithm
177 
178  self.algorithm = algorithm
179  self.run_mode = run_mode
180  self.number_of_steps = num_steps
181  self.initial_damping_factor = 1.0
182  self.manipulability_threshold= 0.0001
183  self.real_time = False
184  self.time_step = 0.010 # (sec)
185  self.max_js = 2.0 # (Rad/sec)
186  self.max_ja = 100.0 # (Rad/sec^2)
187 
188  self.representation_of_orientation_for_binary_run = 'vectorial_identity'
189  self.include_current_config = True
190 
191  def __str__( self ) :
192  '''
193  returns the algorithmic setting for the inverse kinematic solver
194  '''
195  s = 'Running Mode : ' + self.run_mode
196  if self.run_mode == 'binary_run':
197  s += '(Representation of Orientation for Interpolation : ' + self.representation_of_orientation_for_binary_run + '\n'
198  else:
199  s += '\n'
200 
201  s += 'Algorithm : ' + key_dic[self.algorithm] + '\n'
202  s += 'Number of Steps : ' + str(self.number_of_steps) + '\n'
203  return s
204 
205  def algorithm_key(self):
206  assert self.algorithm in self.__class__.all_algorithms
207  return self.__class__.alg_dic[self.algorithm]
208 # \endcond
209 class Inverse_Kinematics( eflib.Endeffector ):
210  '''
211  Inherits all properties and methods of a "Forward_Kinematics" class
212  and has some additional properties and methods for inverse kinematic calculations
213  Method "update" changes the "configuration" property inherited from "Forward_Kinematics"
214 
215 
216  # goto_target (call from outside) -- runs the suff on the grid already, calls stepwise_run or run
217  # stepwise_run() --
218  # run() -- run() # single run()
219  # step_forward (SINGLE STEP) -- one update_step()
220 
221  '''
222 
223  def __init__(self, config_settings, geo_settings, end_settings, ik_settings):
224  ### def __init__( self, geometry ) : # njoint):
225  '''
226  '''
227  super(Inverse_Kinematics, self).__init__(copy.copy(config_settings), copy.copy(geo_settings), copy.copy(end_settings))
229  self.ik_settings = copy.copy(ik_settings)
230 
231  ## fklib.Forward_Kinematics.__init__(self, DEEPCOPY(??geometry??) ) # njoint)
232 
233  self.end_settings.last_link_number = geo_settings.nlink - 1
234 
235  self.run_log = Run_Log()
236 
237  # self.initial_config = self.free_config(self.q)
238  self.initial_config = None
239  self.damping_factor = ik_settings.initial_damping_factor
240 
241  self.initial_config_list = []
242 
243  # \cond
244 
245  def settings_key():
246  '''
247  generate and return the text key for the settings
248  '''
249 
250  def ik_direction(self, u = None):
251  '''
252  Returns the joint direction (joint update correction) expected to lead the endeffector closer to the target.
253  This direction should be multiplied by a proper stepsize to ensure that the pose error norm is reduced.
254  '''
255  genpy.check_valid(self.ik_settings.algorithm, all_algorithms, __name__, self.__class__.__name__, sys._getframe().f_code.co_name, 'ik_settings.algorithm')
256 
257  err = self.pose_error()
258  Je = self.error_jacobian()
259  W = self.joint_damping_weights()
260 
261  # right pseudo inverse of error jacobian is calculated and placed in Je_dagger
262  #(Je_dagger,not_singular) = mathpy.right_pseudo_inverse(Je)
263  if self.ik_settings.algorithm == "JI":
264  Je_dag = np.linalg.inv(Je)
265  elif self.ik_settings.algorithm == "JPI":
266  Je_dag = vecmat.weighted_pseudo_inverse(Je, W)
267  elif self.ik_settings.algorithm == "JT":
268  Je_dag = - Je.T
269  elif self.ik_settings.algorithm in ["DLS(CDF)", "DLS(ADF)"]:
270  # Je_dag = vecmat.right_dls_inverse(Je, self.damping_factor)
271  Je_dag = vecmat.weighted_dls_inverse(Je, W, k = self.damping_factor)
272  elif self.ik_settings.algorithm in ['DLS(MADF)']:
273  mu = self.manipulability()
274  if mu < self.ik_settings.manipulability_threshold:
275  self.damping_factor = self.ik_settings.initial_damping_factor*(1.0 - mu/self.ik_settings.manipulability_threshold)
276  Je_dag = vecmat.weighted_dls_inverse(Je, W, k = self.damping_factor)
277  else:
278  assert False
279 
280  # Joint Correction is calculated here:
281  delta_qs = - np.dot(Je_dag, err)
282  # print delta_qs
283 
284  if u != None:
285  assert len(u) == self.config_settings.DOF
286  J_dag_J = np.dot(Je_dag, Je)
287  In_minus_J_dag_J = np.eye(self.config_settings.DOF) - J_dag_J
288  dq = np.dot(In_minus_J_dag_J, u)
289  # print "Self motion: ", dq, self.qvr
290  delta_qs += dq
291 
292  return delta_qs
293 
294  def optimum_stepsize(self, direction):
295  if self.ik_settings.algorithm in ['JPI','JI']:
296  k = 1.0
297  elif self.ik_settings.algorithm in ['JT', 'DLS(CDF)', 'DLS(ADF)', 'DLS(MADF)']:
298  J_delta_q = np.dot(self.error_jacobian(), direction)
299  k = - np.sum(J_delta_q*J_delta_q)/np.sum(J_delta_q*self.pose_error())
300  else:
301  assert False, genpy.err_str(__name__, self.__class__.__name__, sys._getframe().f_code.co_name, self.ik_settings.algorithm + " is an unknown value for algorithm")
302 
303  # assert k >= 0.0
304  return k
305 
306  def update_step(self):
307  '''
308  Implements an update rule for the joint configuration. This function performs one iteration of the algorithm.
309  '''
310  '''
311  print 'US Start: **************************'
312  print 'US: qqs', np.sum(self.q), np.sum(self.qvr)
313  print 'US: per', np.sum(self.pose_error())
314  print 'US: ejt', np.sum(self.task_point[0].error_jacobian()), np.sum(self.task_frame[0].error_jacobian())
315  print 'US: EJ ', np.sum(self.error_jacobian()[0,:])
316  '''
317 
318  ts = time.time()
319  if self.ik_settings.ngp_active:
320  u = self.objective_function_gradient(k = 1.0)
321  # print "u = ", u
322  else:
323  u = None
324 
325  jdir = self.ik_direction(u)
326  k = self.optimum_stepsize(jdir)
327  delta_qs = k*jdir
328 
329  assert self.set_config_virtual(self.qvr + delta_qs)
330 
331  if self.ik_settings.generate_log:
332  telap = time.time() - ts
333  step_log = self.report_status()
334  step_log.time_elapsed = telap
335  self.run_log.step.append(step_log)
336 
337  def report_status(self):
338  sl = Step_Log()
339  sl.current_time = time.time() - self.run_log.time_start
340  sl.configuration = np.copy(self.free_config(self.q))
341  sl.end_pose = copy.copy(self.pose())
342  sl.pose_error = copy.copy(self.pose_error())
343  sl.error_norm = copy.copy(self.pose_error_norm())
344  sl.manipulability = self.manipulability()
345  sl.damping_factor = self.damping_factor
346  sl.is_in_target = self.in_target()
347  sl.joints_in_range = self.joints_in_range(sl.configuration)
348  return sl
349 
350  def copy_from(self, ik):
351  '''
352  Transfers all properties from ik to self
353  '''
354  self.config_settings = copy.copy(ik.config_settings)
355  self.geo_settings = copy.copy(ik.geo_settings)
356  self.end_settings = copy.copy(ik.end_settings)
357  self.ik_settings = copy.copy(ik.ik_settings)
358 
359  self.damping_factor = ik.damping_factor
360 
361  self.q = copy.copy(ik.q)
362  self.qvr = copy.copy(ik.qvr)
363  self.jmc_a = copy.copy(ik.jmc_a)
364  self.jmc_b = copy.copy(ik.jmc_b)
365  self.jmc_c = copy.copy(ik.jmc_c)
366  self.jmc_f = copy.copy(ik.jmc_f)
367  self.jmc_g = copy.copy(ik.jmc_g)
368 
369  self.T = copy.copy(ik.T)
370  self.H = copy.copy(ik.H)
371 
372  self.ajac = copy.deepcopy(ik.ajac)
373 
374  self.mp = ik.mp
375  self.mo = ik.mo
376 
377  for i in range(len(ik.task_point)):
378  self.task_point[i] = copy.deepcopy(ik.task_point[i])
379 
380  for i in range(len(ik.task_frame)):
381  self.task_frame[i] = copy.deepcopy(ik.task_frame[i])
382 
383  self.current_pose = copy.copy(ik.current_pose)
384  self.current_pose_error = copy.copy(ik.current_pose_error)
385  self.current_error_norm = copy.copy(ik.current_error_norm)
386 
387  self.all_task_points_in_target = ik.all_task_points_in_target
388  self.all_task_frames_in_target = ik.all_task_frames_in_target
389  self.is_in_target = ik.is_in_target
390 
391  self.geo_jac = copy.copy(ik.geo_jac)
392  self.err_jac = copy.copy(ik.err_jac)
393  self.run_log = copy.deepcopy(ik.run_log)
394  # \endcond
395  def js_create(self, phi_end = None, traj_capacity = 2, traj_type = 'regular'):
396  '''
397  '''
398  self.damping_factor = self.ik_settings.initial_damping_factor
399  if self.ik_settings.generate_log:
400  self.run_log.clear()
401  keep_q = np.copy(self.q)
402  H = self.transfer_matrices()
403 
404  if phi_end == None:
405  phi_end = self.ik_settings.number_of_steps*self.ik_settings.time_step
406 
407  if traj_type == 'regular':
408  jt = trajlib.Trajectory(dimension = self.config_settings.DOF, capacity = traj_capacity)
409  elif traj_type == 'polynomial':
410  jt = trajlib.Trajectory_Polynomial(dimension = self.config_settings.DOF, capacity = traj_capacity)
411  else:
412  assert False, "\n Unknown Trajectory Type \n"
413 
414  jt.plot_settings.axis_label = self.config_settings.joint_label
415  if self.ik_settings.respect_limits_in_trajectories:
416  jt.vel_max = self.ik_settings.max_js
417  jt.acc_max = self.ik_settings.max_ja
418  jt.pos_max = self.config_settings.qh
419  jt.pos_min = self.config_settings.ql
420 
421  phi = 0.0
422 
423  jt.add_position(0.0, pos = np.copy(self.q))
424 
425  stay = not self.in_target()
426 
427  while stay:
428  stay = not self.in_target()
429  phi = phi + self.ik_settings.time_step
430 
431  if (phi > phi_end) or genmath.equal(phi, phi_end, epsilon = 0.1*self.ik_settings.time_step):
432  phi = phi_end
433  stay = False
434 
435  err_reduced = self.moveto_target()
436 
437  if err_reduced or (not self.ik_settings.respect_error_reduction):
438  jt.add_position(phi = phi, pos = np.copy(self.q))
439 
440 
441  if traj_type == 'polynomial':
442  jt.interpolate()
443 
444  self.set_config(keep_q)
445  if self.ik_settings.generate_log:
446  self.run_log.time_elapsed = time.time() - self.run_log.time_start
448  return jt
449 
450  def run_dls_vdf(self):
451  '''
452  runs the IK iterations following Damped Least Squares method with Variable Damping Factor
453  The damping factor starts from the initial value.
454  At each time step, if the error norm is reduced, the joint correction is applied and the damping factor is reduced to half and
455  if it is increased, the algorithm returns to previous configuration and the DF is multiplied by 2.
456  This will continue until the error norm is reduced or maximum number of iterations achieved.
457  '''
458 
459  counter = 0
460  self.damping_factor = self.ik_settings.initial_damping_factor
461  not_arrived = not self.in_target()
462  have_time = (counter < self.ik_settings.number_of_steps)
463  err_reduced = False
464 
465  while not_arrived and have_time:
466  previous_pose_error_norm = self.pose_error_norm()
467  previous_configuration = self.free_config(self.q)
468 
469  try:
470  self.update_step()
471  counter += 1
472 
473  except np.linalg.linalg.LinAlgError:
474 
475  print "******** Singular Matrix ********";
476  break
477 
478  err_reduced = (self.pose_error_norm() < previous_pose_error_norm)
479 
480  if err_reduced or self.in_target():
481  self.damping_factor /= self.ik_settings.df_gain
482  # self.damping_factor /= self.ik_settings.df_gain
483  else:
484  self.damping_factor *= self.ik_settings.df_gain
485 
486  if self.damping_factor < 0.001:
487  self.set_config(previous_configuration)
488  else:
489  self.damping_factor /= self.ik_settings.df_gain
490 
491  rs = self.ik_settings.continue_until_inrange
492  ir = self.joints_in_range(self.free_config(self.q))
493 
494  not_arrived = (not self.in_target() ) or (rs and (not ir))
495  have_time = (counter < self.ik_settings.number_of_steps)
496 
497  if self.ik_settings.generate_log:
498  self.run_log.time_elapsed = time.time() - self.run_log.time_start
499  # \cond
500 
501 
502  def run(self):
503  '''
504  Runs the inverse kinematic algorithm from the given starting point.
505 
506  The stop criteria is the occurance of one of the following:
507  1- The counter exceeds property "number_of_steps" of the class and the norm of error is more than its value in the previous iteration
508  2- The solution is found according to the defined precision
509  when the stop criteria is met, the configuration corresponding to the minimum pose error norm is returned as the solution
510 
511  The running time and number of iteration is returned in the "pps_log" property.
512  This method should only be used for "Pose Projection" or "PP" application scenario.
513 
514  '''
515  self.damping_factor = self.ik_settings.initial_damping_factor
516 
517  if self.ik_settings.return_min_config:
518  min_config = self.free_config(self.q)
519  min_error = self.pose_error_norm()
520 
521  counter = 0
522 
523  not_yet = not self.in_target()
524  have_time = (counter < self.ik_settings.number_of_steps)
525  err_reduced = False
526 
527  # while not_yet and (have_time or err_reduced):
528  while not_yet and have_time:
529 
530  try:
531  self.update_step()
532  counter += 1
533 
534  except np.linalg.linalg.LinAlgError:
535 
536  print "******** Singular Matrix ********";
537  break
538 
539  rs = self.ik_settings.continue_until_inrange
540  ir = self.joints_in_range(self.free_config(self.q))
541  it = self.in_target()
542 
543  not_yet = (not it) or ((not ir) and rs)
544  have_time = (counter < self.ik_settings.number_of_steps)
545  '''
546  print
547  print "Current config : ", self.q
548  print "Current config v : ", self.qvr
549 
550  print "Current Error : ", self.pose_error_norm()
551  print "Current Ofun : ", self.objective_function_value()
552 
553  ra = self.task_point[0].position(self.H)
554  rd = self.task_point[0].rd
555 
556  print "Position Error : ", self.task_point[0].error.value(ra, rd)
557  print "Position in target: ", self.task_point[0].error.in_target(ra, rd)
558 
559  ra = self.task_frame[0].orientation(self.H)
560  rd = self.task_frame[0].rd
561 
562  print "Rotation Error : ", self.task_frame[0].error.value(ra, rd)
563  print "Rotation in target: ", self.task_frame[0].error.in_target(ra, rd)
564  '''
565 
566  if self.ik_settings.return_min_config:
567  '''
568  print "Min Error Achieved: ", min_config.pose_error_norm()
569  print "Min Error Ofun : ", min_config.objective_function_value()
570  '''
571  er = self.pose_error_norm() < min_error
572  err_reduced = er and (ir or (not rs))
573  if err_reduced:
574  min_config = self.free_config(self.q)
575  min_error = self.pose_error_norm()
576 
577  if not_yet and self.ik_settings.return_min_config:
578  self.set_config(min_config)
579 
580  if self.ik_settings.generate_log:
581  self.run_log.time_elapsed = time.time() - self.run_log.time_start
582 
583  def goto_target(self):
584  '''
585  '''
586  if self.ik_settings.generate_log:
587  self.run_log.clear()
588 
589  if self.ik_settings.include_current_config:
590  self.initial_config = self.free_config(self.q)
591  if self.in_target():
592  return True
593 
594  if self.ik_settings.run_mode == 'binary_run':
595  self.run_binary(True)
596  elif self.ik_settings.run_mode == 'normal_run':
597  if self.ik_settings.algorithm in ["JT","JPI","DLS(CDF)", "JI", "DLS(MADF)"]:
598  self.run()
599  elif self.ik_settings.algorithm == "DLS(ADF)":
600  self.run_dls_vdf()
601  else:
602  assert False, genpy.err_str(__name__, self.__class__.__name__, sys._getframe().f_code.co_name, self.ik_settings.algorithm + " is not a valid value for algorithm")
603 
604  self.start_node = 0
605  p = len(self.initial_config_list)
606 
607  while (not self.in_target()) and (self.start_node < p):
608 
609  assert self.set_config(self.initial_config_list[self.start_node])
610 
611  self.initial_config = self.free_config(self.q) # Just for keeping the information of the initial status (Initial status will be shown later in the results log file)
612 
613  # self.forward_update()
614 
615  if self.ik_settings.run_mode == 'binary_run':
616  self.run_binary(True)
617  elif self.ik_settings.run_mode == 'normal_run':
618  if self.ik_settings.algorithm in ["JT","JPI","DLS(CDF)", "JI", "DLS(MADF)"]:
619  self.run()
620  elif self.ik_settings.algorithm == "DLS(ADF)":
621  self.run_dls_vdf()
622  else:
623  assert False, genpy.err_str(__name__, self.__class__.__name__, sys._getframe().f_code.co_name, self.ik_settings.algorithm + ' is not a valid value for algorithm')
624 
625  self.start_node += 1
626 
627  return self.in_target()
628  # \endcond
629 
630  def moveto_target(self, show = False):
631  ts = time.time()
632  q0 = self.free_config(self.q)
633  err = self.pose_error_norm()
634 
635  if self.ik_settings.ngp_active:
636  u = self.objective_function_gradient(k = 1.0)
637  # print "u = ", u
638  else:
639  u = None
640 
641  jdir = self.ik_direction(u)
642 
643  elt = time.time() - ts # elt: elapsed time
644  if np.linalg.norm(jdir) > 0.00001:
645  max_eta = self.optimum_stepsize(jdir)
646  if self.ik_settings.respect_limits:
647  (el, eh) = self.joint_stepsize_interval(direction = jdir, max_speed = self.ik_settings.max_js, delta_t = self.ik_settings.time_step)
648  # assert el < 0.0
649  if eh > max_eta:
650  eh = max_eta # max_eta = 1.0 when algorithm is JPI
651  else:
652  eh = max_eta # max_eta = 1.0 when algorithm is JPI
653 
654  self.set_config_virtual(self.qvr + eh*jdir)
655 
656  if self.pose_error_norm() < err:
657  self.damping_factor = self.damping_factor/self.ik_settings.df_gain
658  if self.ik_settings.generate_log:
659  step_log = self.report_status()
660  step_log.time_elapsed = elt
661  self.run_log.step.append(step_log)
662  return True
663  else:
664  self.damping_factor = self.damping_factor*self.ik_settings.df_gain
665  if self.ik_settings.generate_log:
666  step_log = self.report_status()
667  step_log.time_elapsed = elt
668  self.run_log.step.append(step_log)
669  if self.ik_settings.respect_error_reduction:
670  assert self.set_config(q0)
671  return False
672  else:
673  if self.ik_settings.generate_log:
674  step_log = self.report_status()
675  step_log.time_elapsed = elt
676  self.run_log.step.append(step_log)
677  return True
678  # \cond
679  def js_project(self, pos_traj, ori_traj = None, phi_start = 0.0, phi_end = None, relative = True, traj_capacity = 2, traj_type = 'regular'):
680  '''
681  projects the given taskspace pose trajectory into the jointspace using the numeric inverse kinematics.
682  The phase starts from phi_start and added by self.ik_settings.time_step in each step.
683  at any time, if a solution is not found, the target is ignored and no configuration is added to the trajectory
684  '''
685  self.damping_factor = self.ik_settings.initial_damping_factor
686  keep_q = np.copy(self.q)
687  H = self.transfer_matrices()
688 
689  if ori_traj == None:
690  ori_traj = trajlib.Orientation_Path()
691  ori_traj.add_point(0.0, self.task_frame[0].orientation(H))
692  ori_traj.add_point(pos_traj.phi_end, self.task_frame[0].orientation(H))
693 
694  if phi_end == None:
695  phi_end = min(pos_traj.phi_end, ori_traj.phi_end)
696 
697  if (phi_end > pos_traj.phi_end) or (phi_end > ori_traj.phi_end):
698  phi_end = min(pos_traj.phi_end, ori_traj.phi_end)
699 
700  if traj_type == 'regular':
701  jt = trajlib.Trajectory(dimension = self.config_settings.DOF, capacity = traj_capacity)
702  elif traj_type == 'polynomial':
703  jt = trajlib.Trajectory_Polynomial(dimension = self.config_settings.DOF, capacity = traj_capacity)
704  else:
705  assert False, "\n Unknown Trajectory Type \n"
706 
707  if self.ik_settings.respect_limits_in_trajectories:
708  jt.vel_max = self.ik_settings.max_js
709  jt.acc_max = self.ik_settings.max_ja
710  jt.pos_max = self.config_settings.qh
711  jt.pos_min = self.config_settings.ql
712 
713  phi = phi_start
714  pos_traj.set_phi(phi)
715  ori_traj.set_phi(phi)
716  if relative:
717  p0 = self.task_point[0].position(H) - pos_traj.current_position
718  self.set_target([self.task_point[0].position(H)], [self.task_frame[0].orientation(H)])
719  else:
720  p0 = np.zeros(3)
721  self.set_target([pos_traj.current_position], [ori_traj.current_orientation])
722  self.goto_target()
723 
724  jt.add_position(0.0, pos = np.copy(self.q))
725 
726  if self.ik_settings.generate_log:
727  self.run_log.clear()
728  self.run_log.step.append(self.report_status())
729 
730  stay = True
731 
732  while stay:
733  phi = phi + self.ik_settings.time_step
734 
735  if (phi > phi_end) or genmath.equal(phi, phi_end, epsilon = 0.1*self.ik_settings.time_step):
736  phi = phi_end
737  stay = False
738 
739  pos_traj.set_phi(phi)
740  ori_traj.set_phi(phi)
741  p = p0 + pos_traj.current_position
742  self.set_target([p], [ori_traj.current_orientation])
743 
744  err_reduced = self.moveto_target()
745  if err_reduced or (not self.ik_settings.respect_error_reduction):
746  jt.add_position(phi = phi - phi_start, pos = np.copy(self.q))
747 
748  if traj_type == 'polynomial':
749  jt.interpolate()
750 
751  self.set_config(keep_q)
752 
753  if self.ik_settings.generate_log:
754  self.run_log.time_elapsed = time.time() - self.run_log.time_start
755 
756  return jt
757 
758  def ts_project(self, js_traj, phi_start = 0.0, phi_end = None):
759  '''
760  projects the given jointspace trajectory into the taskspace
761  The phase starts from phi_start and added by delta_phi in each step.
762  if at any time the joint values are not feasible, the process is stopped.
763  '''
764 
765  if phi_end == None:
766  phi_end = js_traj.phi_end
767 
768  pt = trajlib.Trajectory_Polynomial(dimension = 3*len(self.task_point) + 9*len(self.task_frame))
769  if phi_end > js_traj.phi_end:
770  phi_end = js_traj.phi_end
771 
772  phi = phi_start
773  stay = True
774  while stay:
775  if (phi > phi_end) or genmath.equal(phi, phi_end, epsilon = 0.1*self.ik_settings.time_step):
776  phi = phi_end
777  stay = False
778  js_traj.set_phi(phi)
779  if self.set_config(js_traj.current_position):
780  pt.add_point(phi - phi_start, self.pose())
781  phi = phi + self.ik_settings.time_step
782  return pt
783 
784  """
785  def ts_project(self, js_traj, phi_start = 0.0, phi_end = None):
786  '''
787  projects the given jointspace trajectory into the taskspace
788  The phase starts from phi_start and added by delta_phi in each step.
789  if at any time the joint values are not feasible, the process is stopped.
790  '''
791 
792  if phi_end == None:
793  phi_end = js_traj.phi_end
794 
795  ori_traj = trajlib.Orientation_Trajectory()
796  pos_traj = trajlib.Trajectory_Polynomial()
797  if phi_end > js_traj.phi_end:
798  phi_end = js_traj.phi_end
799 
800  phi = phi_start
801  js_traj.set_phi(phi)
802  stay = True
803  while stay and (self.set_config(js_traj.current_position)):
804  if phi > phi_end:
805  phi = phi_end
806  stay = False
807 
808  H = self.transfer_matrices()
809 
810  pos_traj.add_point(phi - phi_start, self.task_point[0].position(H))
811  ori_traj.add_point(phi - phi_start, self.task_frame[0].orientation(H))
812  phi = phi + self.ik_settings.time_step
813  js_traj.set_phi(phi)
814 
815  pos_traj.add_point(phi - phi_start, self.task_point[0].position(self.transfer_matrices()))
816  ori_traj.add_point(phi - phi_start, self.task_frame[0].orientation(self.transfer_matrices()))
817  return (pos_traj, ori_traj)
818  """
819  # \endcond
run_log
fklib.Forward_Kinematics.__init__(self, DEEPCOPY(??geometry??) ) # njoint)
ik_settings
def init( self, geometry ) : # njoint):