1
1
#!/usr/bin/env python3
2
2
"""
3
3
@author: Jesse Haviland
4
+ @author: Peter Corke
4
5
"""
5
-
6
+ from collections import UserList , namedtuple
6
7
import numpy as np
7
8
from spatialmath import SE3
8
9
9
10
10
- class ET (object ):
11
+ class ET (UserList ): # TODO should be ETS
11
12
"""
12
13
This class implements a single elementary transform (ET)
13
14
@@ -25,53 +26,73 @@ class ET(object):
25
26
J. Haviland and P. Corke
26
27
27
28
"""
28
- def __init__ (self , axis_func , axis , eta = None , joint = None ):
29
29
30
- super (ET , self ).__init__ ()
31
- self .STATIC = 0
32
- self .VARIABLE = 1
30
+ # TODO should probably prefix with __
31
+ STATIC = 0
32
+ VARIABLE = 1
33
+ et = namedtuple ('ET' , 'eta axis_func axis jtype T j eta_deg' )
34
+
35
+ def __init__ (self , axis_func = None , axis = None , eta = None , joint = None ):
36
+
37
+ super ().__init__ () # init UserList superclass
33
38
34
- self ._eta = eta
35
- self ._axis_func = axis_func
36
- self ._axis = axis
39
+ if axis_func is None and axis is None and eta is None :
40
+ # ET()
41
+ # create instance with no values
42
+ self .data = []
43
+ return
37
44
38
- if self .eta is not None :
39
- self ._jtype = self .STATIC
40
- self ._T = axis_func (eta )
45
+ if eta is not None :
46
+ # constant value specified
47
+ jtype = self .STATIC
48
+ T = axis_func (eta )
49
+ j = None
41
50
else :
42
- self ._jtype = self .VARIABLE
43
- self .j = joint
51
+ # it's a joint variable
52
+ jtype = self .VARIABLE
53
+ j = joint
54
+ T = None
55
+
56
+ if jtype is self .STATIC and axis [0 ] == 'R' :
57
+ # it's a rotation joint
58
+ eta_deg = eta * (180 / np .pi )
59
+ else :
60
+ eta_deg = None
61
+
62
+ # save all the params in a named tuple
63
+ e = self .et (eta , axis_func , axis , jtype , T , j , eta_deg )
44
64
45
- if self . _jtype is self . STATIC and self . axis [ 0 ] == 'R' :
46
- self ._eta_deg = self . eta * ( 180 / np . pi )
65
+ # and make it the only value of this instance
66
+ self .data = [ e ]
47
67
48
68
@property
49
69
def eta (self ):
50
- return self ._eta
70
+ return self .data [ 0 ]. eta
51
71
72
+ # TODO why do we need degrees version?
52
73
@property
53
74
def eta_deg (self ):
54
- return self ._eta_deg
75
+ return self .data [ 0 ]. eta_deg
55
76
56
77
@property
57
78
def axis_func (self ):
58
- return self ._axis_func
79
+ return self .data [ 0 ]. axis_func
59
80
60
81
@property
61
82
def axis (self ):
62
- return self ._axis
83
+ return self .data [ 0 ]. axis
63
84
64
85
@property
65
86
def j (self ):
66
- return self ._j
87
+ return self .data [ 0 ]. j
67
88
68
89
@property
69
90
def jtype (self ):
70
- return self ._jtype
91
+ return self .data [ 0 ]. jtype
71
92
72
- @j .setter
73
- def j (self , j_new ):
74
- self ._j = j_new
93
+ # @j.setter
94
+ # def j(self, j_new):
95
+ # self._j = j_new
75
96
76
97
def T (self , q = None ):
77
98
"""
@@ -84,7 +105,7 @@ def T(self, q=None):
84
105
85
106
"""
86
107
if self .jtype is self .STATIC :
87
- return self ._T
108
+ return self .data [ 0 ]. T
88
109
else :
89
110
return self .axis_func (q )
90
111
@@ -96,13 +117,39 @@ def __str__(self):
96
117
:rtype: str
97
118
98
119
"""
99
- if self .jtype is self .STATIC :
100
- if self .axis [0 ] == 'R' :
101
- return '%s(%g)' % (self .axis , self .eta_deg )
120
+ es = []
121
+ joint = 0
122
+ for et in self : # for et in the object, display it, data comes from properties which come from the named tuple
123
+
124
+ if et .jtype is self .STATIC :
125
+ if et .axis [0 ] == 'R' :
126
+ s = '%s(%g)' % (et .axis , et .eta_deg )
127
+ else :
128
+ s = '%s(%g)' % (et .axis , et .eta )
102
129
else :
103
- return '%s(%g)' % (self .axis , self .eta )
130
+ # s = '%s(q%d)' % (et.axis, et.j)
131
+ s = '%s(q%d)' % (et .axis , joint )
132
+ joint += 1
133
+ es .append (s )
134
+
135
+ return " * " .join (es )
136
+
137
+ # redefine * operator to concatenate the internal lists
138
+ def __mul__ (self , rest ):
139
+ prod = ET ()
140
+ prod .data = self .data + rest .data
141
+ return prod
142
+
143
+ # redefine so that indexing returns an ET type
144
+ def __getitem__ (self , i ):
145
+ item = ET ()
146
+ data = self .data [i ] # can be [2] or slice, eg. [3:5]
147
+ # ensure that data is always a list
148
+ if isinstance (data , list ):
149
+ item .data = data
104
150
else :
105
- return '%s(q%d)' % (self .axis , self .j )
151
+ item .data = [data ]
152
+ return item
106
153
107
154
def __repr__ (self ):
108
155
return str (self )
@@ -115,7 +162,7 @@ def __repr__(self):
115
162
# 'or joint (the joint number) must be supplied')
116
163
117
164
@classmethod
118
- def TRx (cls , eta = None ):
165
+ def rx (cls , eta = None ):
119
166
"""
120
167
An elementary transform (ET). A pure rotation of eta about the x-axis.
121
168
@@ -133,19 +180,10 @@ def TRx(cls, eta=None):
133
180
:rtype: ET
134
181
135
182
"""
136
-
137
- def axis_func (eta ):
138
- return SE3 (np .array ([
139
- [1 , 0 , 0 , 0 ],
140
- [0 , np .cos (eta ), - np .sin (eta ), 0 ],
141
- [0 , np .sin (eta ), np .cos (eta ), 0 ],
142
- [0 , 0 , 0 , 1 ]
143
- ]))
144
-
145
- return cls (axis_func , axis = 'Rx' , eta = eta )
183
+ return cls (SE3 .Rx , axis = 'Rx' , eta = eta )
146
184
147
185
@classmethod
148
- def TRy (cls , eta = None ):
186
+ def ry (cls , eta = None ):
149
187
"""
150
188
An elementary transform (ET). A pure rotation of eta about the y-axis.
151
189
@@ -163,19 +201,10 @@ def TRy(cls, eta=None):
163
201
:rtype: ET
164
202
165
203
"""
166
-
167
- def axis_func (eta ):
168
- return SE3 (np .array ([
169
- [np .cos (eta ), 0 , np .sin (eta ), 0 ],
170
- [0 , 1 , 0 , 0 ],
171
- [- np .sin (eta ), 0 , np .cos (eta ), 0 ],
172
- [0 , 0 , 0 , 1 ]
173
- ]))
174
-
175
- return cls (axis_func , axis = 'Ry' , eta = eta )
204
+ return cls (SE3 .Ry , axis = 'Ry' , eta = eta )
176
205
177
206
@classmethod
178
- def TRz (cls , eta = None ):
207
+ def rz (cls , eta = None ):
179
208
"""
180
209
An elementary transform (ET). A pure rotation of eta about the z-axis.
181
210
@@ -191,19 +220,10 @@ def TRz(cls, eta=None):
191
220
:rtype: ET
192
221
193
222
"""
194
-
195
- def axis_func (eta ):
196
- return SE3 (np .array ([
197
- [np .cos (eta ), - np .sin (eta ), 0 , 0 ],
198
- [np .sin (eta ), np .cos (eta ), 0 , 0 ],
199
- [0 , 0 , 1 , 0 ],
200
- [0 , 0 , 0 , 1 ]
201
- ]))
202
-
203
- return cls (axis_func , axis = 'Rz' , eta = eta )
223
+ return cls (SE3 .Rz , axis = 'Rz' , eta = eta )
204
224
205
225
@classmethod
206
- def Ttx (cls , eta = None ):
226
+ def tx (cls , eta = None ):
207
227
"""
208
228
An elementary transform (ET). A pure translation of eta along the
209
229
x-axis
@@ -220,19 +240,10 @@ def Ttx(cls, eta=None):
220
240
:rtype: ET
221
241
222
242
"""
223
-
224
- def axis_func (eta ):
225
- return SE3 (np .array ([
226
- [1 , 0 , 0 , eta ],
227
- [0 , 1 , 0 , 0 ],
228
- [0 , 0 , 1 , 0 ],
229
- [0 , 0 , 0 , 1 ]
230
- ]))
231
-
232
- return cls (axis_func , axis = 'tx' , eta = eta )
243
+ return cls (SE3 .Tx , axis = 'tx' , eta = eta )
233
244
234
245
@classmethod
235
- def Tty (cls , eta = None ):
246
+ def ty (cls , eta = None ):
236
247
"""
237
248
An elementary transform (ET). A pure translation of eta along the
238
249
x-axis
@@ -249,19 +260,10 @@ def Tty(cls, eta=None):
249
260
:rtype: ET
250
261
251
262
"""
252
-
253
- def axis_func (eta ):
254
- return SE3 (np .array ([
255
- [1 , 0 , 0 , 0 ],
256
- [0 , 1 , 0 , eta ],
257
- [0 , 0 , 1 , 0 ],
258
- [0 , 0 , 0 , 1 ]
259
- ]))
260
-
261
- return cls (axis_func , axis = 'ty' , eta = eta )
263
+ return cls (SE3 .Ty , axis = 'ty' , eta = eta )
262
264
263
265
@classmethod
264
- def Ttz (cls , eta = None ):
266
+ def tz (cls , eta = None ):
265
267
"""
266
268
An elementary transform (ET). A pure translation of eta along the
267
269
z-axis
@@ -278,13 +280,18 @@ def Ttz(cls, eta=None):
278
280
:rtype: ET
279
281
280
282
"""
283
+ return cls (SE3 .Tz , axis = 'tz' , eta = eta )
284
+
285
+ if __name__ == "__main__" :
286
+
287
+ from math import pi
288
+
289
+ e = ET .rx (pi / 2 )
290
+ print (e )
281
291
282
- def axis_func (eta ):
283
- return SE3 (np .array ([
284
- [1 , 0 , 0 , 0 ],
285
- [0 , 1 , 0 , 0 ],
286
- [0 , 0 , 1 , eta ],
287
- [0 , 0 , 0 , 1 ]
288
- ]))
292
+ e = ET .rx (pi / 2 ) * ET .tx (0.3 ) * ET .ty (0.4 ) * ET .rx (- pi / 2 )
293
+ print (e )
289
294
290
- return cls (axis_func , axis = 'tz' , eta = eta )
295
+
296
+ e = ET .rx (pi / 2 ) * ET .tx () * ET .ty () * ET .rx (- pi / 2 )
297
+ print (e )
0 commit comments