18 import copy,numpy, math, rotation, general_python
as genpy
23 'DiRoMa' :
'Difference of Rotation Matrices',
24 'DiQu' :
'Difference of Quaternions',
25 'DiNoQu' :
'Non-redundant Difference of Quaternions',
26 'DiOrVe' :
'Difference of Orientation Vectors',
27 'ReRoMa' :
'Trace of Relative Rotation Matrix',
28 'ReRoMaTr' :
'Trace of Relative Rotation Matrix',
29 'AxInPr ' :
'Axis Inner Product',
30 'ReQu' :
'Relative Orientation Vector',
31 'ReOrVe' :
'Relative Orientation Vector',
32 'ReRoAn' :
'Relative Rotation Angle'}
36 'DiQu' :
'quaternion',
37 'DiNoQu' :
'quaternion',
40 'ReRoMaTr' :
'matrix',
41 'ReQu' :
'quaternion',
45 representations_of_position = [
'Cartesian Coordinates',
'Cylinderical Coordinates',
'Spherical Coordinates']
46 representations_of_orientation = [
'matrix',
'vector',
'angle',
'trace' ,
'diag',
'quaternion',
'angle_axis']
47 special_metric_representations = [
'AxInPr',
'DiNoQu',
'AxInPr+DiNoQu',
'ReRoAn + ReOrVe']
53 def __init__(self, representation = "Cartesian Coordinates", metric_type = "differential"):
54 assert (representation
in representations_of_position)
or (representation
in representations_of_orientation)
or (representation
in special_metric_representations), genpy.err_str(__name__,self.__class__.__name__,
'__init__', representation+
' is an invalid value for representation')
62 Property "power" determines the power of elements of basis error in the final vector of errors:
63 Please refer to the comments of property: "W" in this file.
65 0: Not considered for the corresponding coordinate
74 "ra" is the actual position
75 "rd" is the desired position
77 and r can be replaced by: X, Y or Z
79 self.
power = numpy.array([1, 1, 1])
82 property "W" is a 3 X 3 Weighting matrix. This matrix will be multiplied by the basis error and basis jacobian.
84 Matrix W is by default the identity matrix defining 3 constraints as:
92 "power" array = [1, 1, 1] and "W" is a (3 X 3) matrix
96 1st Row of "W": 1 0 0 (Xd - Xa) = 0
97 2nd Row of "W": 0 1 0 (Yd - Ya) = 0
98 3rd Row of "W": 0 0 1 (Zd - Za) = 0
102 "power" array = [2, 2, 1] and "W" is a (2 X 3) matrix
106 1st Row of "W": 1 1 0 (Xd - Xa)^2 + (Yd - Ya)^2 = 0
107 2nd Row of "W": 0 0 1 (Zd - Za) = 0
109 Example 3: (When only two coordinations "X" and "Z" are important to be identical)
110 In this example, it is important to also set the property "required_identical_coordinate" to: [True, False, True]
111 Please refer to the of comments for property "required_identical_coordinate".
113 "power" array = [1, 0, 1] and "W" is a (2 X 3) matrix
117 1st Row of "W": 1 0 0 (Xd - Xa) = 0
118 2nd Row of "W": 0 0 1 (Zd - Za) = 0
120 the same for the orientation ...
128 self.
offset = numpy.array([-1.0, -1.0, -1.0])
130 self.
weight = numpy.array([[1]])
131 self.
power = numpy.array([1])
133 self.
offset = numpy.array([-3.0])
135 self.
offset = numpy.array([0.0])
137 self.
offset = numpy.zeros(3)
140 "self.required_identical_coordinate" is an array of booleans and indicates which coordinates (x, y ,z) should be considered
141 as a criteria in determining the confirmity of the actual and desired positions and orientations.
142 For example if "required_identical_coordinate" = [True, False, True] the actual and desired positions are considered as identical only when
143 their "x" and "z" coordinates are equal.
144 (the "y" coordinate will be neglected)
145 Please refer to "example 3" of the comments provided for property: "W" in this file.
150 set "precision" or termination criteria by default as: 2 cm. It means actual and desired positions are considered "identical"
151 if for each position coordinate (x, y, z), the absolute value of the difference of current and desired, does not exceed: 2 cm.
153 if representation
in representations_of_position:
162 Metric includes everything regarding the error between two positions or orientations.
180 self.update(current, target)
185 self.update(current, target)
190 includes everything regarding the error between two positions
195 Metric.__init__(self, settings = copy.copy(settings))
201 return the value of basis_position_error
203 ers =
"Target has not been set"
204 assert target !=
None, genpy.err_str(__name__, self.__class__.__name__, sys._getframe().f_code.co_name, ers)
206 if self.settings.representation ==
'Cartesian Coordinates':
207 err = current - target
208 f = err**self.settings.power
209 elif self.settings.representation ==
'Cylindrical_Coordinates':
211 assert len(self.power) == p
214 elif self.settings.representation ==
'Spherical_Coordinates':
216 assert len(self.power) == p
220 ers = self.settings.representation +
" is an invalid value for property self.settings.representation"
221 assert False, genpy.err_str(__name__, self.__class__.__name__, sys._getframe().f_code.co_name, ers)
226 def basis_error_rate(self, x, xd, x_dot, xd_dot) :
228 return the rate of basis_position_error
230 if self.basis_error_function == 'differential_cartesian_coordinates':
232 assert len(self.power) == p
233 f_dot = numpy.zeros((p))
234 for k in range (0,p):
235 if self.power[k] == 0:
238 if self.power[k] == 1:
239 f[k] = x_dot[k] - xd_dot[k]
242 f[k] = self.power[k]*(err**(self.power[k] - 1))*(x_dot[k] - xd_dot[k])
244 elif self.basis_error_function == 'differential_cylindrical_coordinates':
246 assert len(self.power) == p
247 f_dot = numpy.zeros((p))
249 elif self.basis_error_function == 'differential_spherical_coordinates':
251 assert len(self.power) == p
252 f_dot = numpy.zeros((p))
255 print 'Wrong basis error function: ' + self.basis_error_function
260 def update_rate(self, x, xd, x_dot, xd_dot):
262 Calculates the error rate vector between the actual and desired positions of the corresponding taskpoint
264 ber = self.basis_error(x, xd, x_dot, xd_dot)
265 assert self.W.shape[1] == len(ber)
266 self.rate = numpy.dot(self.W, ber)
272 Calculates the error vector between the actual and desired positions of the corresponding taskpoint
275 assert self.settings.weight.shape[1] == len(be)
279 if self.settings.required_identical_coordinate[k]:
280 deviation = abs(target[k] - current[k])
285 includes everything regarding the error between two orientations
288 def __init__(self, settings = Metric_Settings(representation =
'AxInPr', metric_type =
'special')):
289 Metric.__init__(self, settings = copy.copy(settings))
293 set "precision" or termination criteria by default as: 2.0 degrees. It means actual and desired orientations are considered "identical"
294 if for each frame axis (i, j, k), the absolute value of the angle between current and desired frames, does not exceed: 2.0 degrees.
296 self.settings.precision_base =
'Axis Angle'
297 self.settings.precision = 1.0
302 rpn = self.settings.representation
303 if rpn
in [
'vector',
'ReRoAn + ReOrVe']:
304 current.set_parametrization( self.settings.parametrization )
305 target.set_parametrization( self.settings.parametrization )
308 if self.settings.metric_type ==
'relative':
311 elif self.settings.metric_type ==
'differential':
312 e = current[rpn] - target[rpn]
314 elif self.settings.metric_type ==
'special':
315 if self.settings.representation ==
'AxInPr':
317 assert len(self.settings.power) == p
319 for k
in range (0,p):
320 if self.settings.power[k] == 0:
324 err = numpy.dot(target.frame_axis(k), current.frame_axis(k))
325 if self.settings.power[k] == 1 :
328 f[k] = err**self.settings.power[k]
330 elif self.settings.representation ==
'DiNoQu':
332 assert len(self.settings.power) == p
334 qn = current[
'quaternion']
335 qnd = target[
'quaternion']
336 for k
in range (0,3):
337 z = - qnd[0]*qn[k+1] + qn[0]*qnd[k+1]
338 f[k] = z**self.settings.power[k]
340 elif self.settings.representation ==
'AxInPr + DiNoQu':
342 assert len(self.settings.power) == p
344 for k
in range (0,3):
345 if self.settings.power[k] == 0:
349 err = numpy.dot(target.frame_axis(k), current.frame_axis(k))
350 if self.settings.power[k] == 1 :
353 f[k] = err**self.settings.power[k]
354 qn = current[
'quaternion']
355 qnd = target[
'quaternion']
356 for k
in range (3,6):
357 z = - qnd[0]*qn[k-2] + qn[0]*qnd[k-2]
358 f[k] = z**self.settings.power[k]
360 elif self.settings.representation ==
'ReRoAn + ReOrVe':
362 assert len(self.settings.power) == p
366 e[1:4] = Oe[
'vector']
367 f = e**self.settings.power
372 assert False, genpy.err_str(__name__, self.__class__.__name__,
"basis_error", self.settings.metric_type +
" is an invalid metric type")
373 if self.settings.representation ==
'matrix':
376 f = e**self.settings.power
379 def basis_error_rate(self, R, Rd, R_dot, Rd_dot ) :
382 if self.basis_error_function == 'Axis Inner Product':
384 assert len(self.power) == p
385 f_dot = numpy.zeros((p))
386 for k in range (0,p):
387 if self.power[k] == 0:
390 err_rate = numpy.dot(vecmat.uvect(Rd_dot, k), vecmat.uvect(R, k)) + numpy.dot(vecmat.uvect(Rd, k), vecmat.uvect(R_dot, k))
391 if self.power[k] == 1 :
394 err = numpy.dot(vecmat.uvect(Rd, k), vecmat.uvect(R, k))
395 f_dot[k] = self.power[k]*err_rate*(err**(self.power[k]-1))
405 Calculates the error vector between the actual and desired orientations of the corresponding taskframe
409 assert self.settings.weight.shape[1] == len(be)
411 self.
current_value = numpy.dot(self.settings.weight, be) + self.settings.offset
413 if self.settings.precision_base ==
'Axis Angle':
417 if self.settings.required_identical_coordinate[k]:
418 cos_teta = numpy.dot(target.frame_axis(k), current.frame_axis(k))
419 if (cos_teta < 1.00000)
and (cos_teta > -1.00000):
420 deviation = abs((180.0/math.pi)*math.acos(cos_teta))
426 elif self.settings.precision_base ==
'Error Function':
429 assert False, genpy.err_str(__name__, self.__class__.__name__,
'update', self.settings.precision_base +
' is not a valid value for precision_base')
432 def update_rate(self, R, Rd, R_dot, Rd_dot ) :
434 Calculates the error rate vector between the actual and desired orientations of the corresponding taskframe
436 ber = self.basis_error(R, Rd, R_dot, Rd_dot)
437 assert self.W.shape[1] == len(ber)
438 self.rate = numpy.dot(self.W, ber)
452 Metric.__init__(self)
458 self.orientation_metric.basis_error()
461 self.position_metric.basis_error()
468 self.orientation_metric.update()
469 self.position_metric.update()