55import math
66
77
8- def p_servo_old (wTe , wTep , gain = 2 , threshold = 0.1 ):
8+ def _angle_axis (T , Td ):
9+ e = np .empty (6 )
10+ e [:3 ] = Td [:3 , - 1 ] - T [:3 , - 1 ]
11+ R = Td [:3 , :3 ] @ T [:3 , :3 ].T
12+ li = np .array ([R [2 , 1 ] - R [1 , 2 ], R [0 , 2 ] - R [2 , 0 ], R [1 , 0 ] - R [0 , 1 ]])
13+
14+ if base .iszerovec (li ):
15+ # diagonal matrix case
16+ if np .trace (R ) > 0 :
17+ # (1,1,1) case
18+ a = np .zeros ((3 ,))
19+ else :
20+ a = np .pi / 2 * (np .diag (R ) + 1 )
21+ else :
22+ # non-diagonal matrix case
23+ ln = base .norm (li )
24+ a = math .atan2 (ln , np .trace (R ) - 1 ) * li / ln
25+
26+ e [3 :] = a
27+
28+ return e
29+
30+
31+ def p_servo (wTe , wTep , gain = 1.0 , threshold = 0.1 , method = "rpy" ):
932 """
1033 Position-based servoing.
1134
1235 Returns the end-effector velocity which will cause the robot to approach
1336 the desired pose.
1437
1538 :param wTe: The current pose of the end-effecor in the base frame.
16- :type wTe: SE3
39+ :type wTe: SE3 or ndarray
1740 :param wTep: The desired pose of the end-effecor in the base frame.
18- :type wTep: SE3
19- :param gain: The gain for the controller
20- :type gain: float
41+ :type wTep: SE3 or ndarray
42+ :param gain: The gain for the controller. Can be vector corresponding to each
43+ axis, or scalar corresponding to all axes.
44+ :type gain: float, or array-like
2145 :param threshold: The threshold or tolerance of the final error between
2246 the robot's pose and desired pose
2347 :type threshold: float
48+ :param method: The method used to calculate the error. Default is 'rpy' -
49+ error in the end-effector frame. 'angle-axis' - error in the base frame
50+ using angle-axis method.
51+ :type method: string: 'rpy' or 'angle-axis'
2452
2553 :returns v: The velocity of the end-effecotr which will casue the robot
2654 to approach wTep
@@ -31,71 +59,31 @@ def p_servo_old(wTe, wTep, gain=2, threshold=0.1):
3159
3260 """
3361
34- if not isinstance (wTe , SE3 ):
35- wTe = SE3 (wTe )
36-
37- if not isinstance (wTep , SE3 ):
38- wTep = SE3 (wTep )
39-
40- # Pose difference
41- eTep = wTe .inv () * wTep
62+ if isinstance (wTe , SE3 ):
63+ wTe = wTe .A
4264
43- # Translational error
44- ev = eTep . t
65+ if isinstance ( wTep , SE3 ):
66+ wTep = wTep . A
4567
46- # Angular error
47- ew = eTep .rpy ("rad" )
68+ if method == "rpy" :
69+ # Pose difference
70+ eTep = np .linalg .inv (wTe ) @ wTep
71+ e = np .empty (6 )
4872
49- # Form error vector
50- e = np . r_ [ ev , ew ]
73+ # Translational error
74+ e [: 3 ] = eTep [: 3 , - 1 ]
5175
52- # Desired end-effector velocity
53- v = gain * e
54-
55- if np .sum (np .abs (e )) < threshold :
56- arrived = True
76+ # Angular error
77+ e [3 :] = base .tr2rpy (eTep , unit = "rad" , order = "zyx" , check = False )
5778 else :
58- arrived = False
59-
60- return v , arrived
79+ e = _angle_axis (wTe , wTep )
6180
62-
63- def _angle_axis (T , Td ):
64- e = np .zeros (6 )
65- e [:3 ] = Td .t - T .t
66- R = Td .R @ T .R .T
67- li = np .array ([R [2 , 1 ] - R [1 , 2 ], R [0 , 2 ] - R [2 , 0 ], R [1 , 0 ] - R [0 , 1 ]])
68-
69- if base .iszerovec (li ):
70- # diagonal matrix case
71- if np .trace (R ) > 0 :
72- # (1,1,1) case
73- a = np .zeros ((3 ,))
74- else :
75- a = np .pi / 2 * (np .diag (R ) + 1 )
81+ if base .isscalar (gain ):
82+ k = gain * np .eye (6 )
7683 else :
77- # non-diagonal matrix case
78- ln = base .norm (li )
79- a = math .atan2 (ln , np .trace (R ) - 1 ) * li / ln
80-
81- e [3 :] = a
82-
83- return e
84-
85-
86- def p_servo (wTe , wTep , gain = [1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 ], threshold = 0.1 ):
87- if not isinstance (wTe , SE3 ):
88- wTe = SE3 (wTe )
89-
90- if not isinstance (wTep , SE3 ):
91- wTep = SE3 (wTep )
92-
93- k = np .diag (gain )
94-
95- e = _angle_axis (wTe , wTep )
84+ k = np .diag (gain )
9685
9786 v = k @ e
98-
9987 arrived = True if np .sum (np .abs (e )) < threshold else False
10088
10189 return v , arrived
0 commit comments