Skip to content

Commit 62add1e

Browse files
committed
Add UserList so that ET list is implicit
1 parent 777d733 commit 62add1e

File tree

1 file changed

+102
-95
lines changed
  • roboticstoolbox/robot

1 file changed

+102
-95
lines changed

roboticstoolbox/robot/ET.py

Lines changed: 102 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#!/usr/bin/env python3
22
"""
33
@author: Jesse Haviland
4+
@author: Peter Corke
45
"""
5-
6+
from collections import UserList, namedtuple
67
import numpy as np
78
from spatialmath import SE3
89

910

10-
class ET(object):
11+
class ET(UserList): # TODO should be ETS
1112
"""
1213
This class implements a single elementary transform (ET)
1314
@@ -25,53 +26,73 @@ class ET(object):
2526
J. Haviland and P. Corke
2627
2728
"""
28-
def __init__(self, axis_func, axis, eta=None, joint=None):
2929

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
3338

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
3744

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
4150
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)
4464

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]
4767

4868
@property
4969
def eta(self):
50-
return self._eta
70+
return self.data[0].eta
5171

72+
# TODO why do we need degrees version?
5273
@property
5374
def eta_deg(self):
54-
return self._eta_deg
75+
return self.data[0].eta_deg
5576

5677
@property
5778
def axis_func(self):
58-
return self._axis_func
79+
return self.data[0].axis_func
5980

6081
@property
6182
def axis(self):
62-
return self._axis
83+
return self.data[0].axis
6384

6485
@property
6586
def j(self):
66-
return self._j
87+
return self.data[0].j
6788

6889
@property
6990
def jtype(self):
70-
return self._jtype
91+
return self.data[0].jtype
7192

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
7596

7697
def T(self, q=None):
7798
"""
@@ -84,7 +105,7 @@ def T(self, q=None):
84105
85106
"""
86107
if self.jtype is self.STATIC:
87-
return self._T
108+
return self.data[0].T
88109
else:
89110
return self.axis_func(q)
90111

@@ -96,13 +117,39 @@ def __str__(self):
96117
:rtype: str
97118
98119
"""
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)
102129
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
104150
else:
105-
return '%s(q%d)' % (self.axis, self.j)
151+
item.data = [data]
152+
return item
106153

107154
def __repr__(self):
108155
return str(self)
@@ -115,7 +162,7 @@ def __repr__(self):
115162
# 'or joint (the joint number) must be supplied')
116163

117164
@classmethod
118-
def TRx(cls, eta=None):
165+
def rx(cls, eta=None):
119166
"""
120167
An elementary transform (ET). A pure rotation of eta about the x-axis.
121168
@@ -133,19 +180,10 @@ def TRx(cls, eta=None):
133180
:rtype: ET
134181
135182
"""
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)
146184

147185
@classmethod
148-
def TRy(cls, eta=None):
186+
def ry(cls, eta=None):
149187
"""
150188
An elementary transform (ET). A pure rotation of eta about the y-axis.
151189
@@ -163,19 +201,10 @@ def TRy(cls, eta=None):
163201
:rtype: ET
164202
165203
"""
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)
176205

177206
@classmethod
178-
def TRz(cls, eta=None):
207+
def rz(cls, eta=None):
179208
"""
180209
An elementary transform (ET). A pure rotation of eta about the z-axis.
181210
@@ -191,19 +220,10 @@ def TRz(cls, eta=None):
191220
:rtype: ET
192221
193222
"""
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)
204224

205225
@classmethod
206-
def Ttx(cls, eta=None):
226+
def tx(cls, eta=None):
207227
"""
208228
An elementary transform (ET). A pure translation of eta along the
209229
x-axis
@@ -220,19 +240,10 @@ def Ttx(cls, eta=None):
220240
:rtype: ET
221241
222242
"""
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)
233244

234245
@classmethod
235-
def Tty(cls, eta=None):
246+
def ty(cls, eta=None):
236247
"""
237248
An elementary transform (ET). A pure translation of eta along the
238249
x-axis
@@ -249,19 +260,10 @@ def Tty(cls, eta=None):
249260
:rtype: ET
250261
251262
"""
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)
262264

263265
@classmethod
264-
def Ttz(cls, eta=None):
266+
def tz(cls, eta=None):
265267
"""
266268
An elementary transform (ET). A pure translation of eta along the
267269
z-axis
@@ -278,13 +280,18 @@ def Ttz(cls, eta=None):
278280
:rtype: ET
279281
280282
"""
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)
281291

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)
289294

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

Comments
 (0)