Skip to content

Commit 815e5ec

Browse files
committed
Merge branch 'future' of github.com:petercorke/robotics-toolbox-python into future
2 parents db6e9b1 + 6b6136e commit 815e5ec

File tree

7 files changed

+74
-85
lines changed

7 files changed

+74
-85
lines changed

roboticstoolbox/backends/PyPlot/EllipsePlot.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ def make_ellipsoid2(self):
192192
# A = np.linalg.inv(A)
193193
# except:
194194
# A = np.zeros((2,2))
195+
if self.vell:
196+
# Do the extra step for the velocity ellipse
197+
A = np.linalg.inv(A)
195198

196199
if isinstance(self.centre, str) and self.centre == "ee":
197200
centre = self.robot.fkine(self.q).A[:3, -1]
@@ -204,7 +207,7 @@ def make_ellipsoid2(self):
204207
# RVC2 p 602
205208
# x = sp.linalg.sqrtm(A) @ y
206209

207-
x, y = base.ellipse(A, inverted=True, centre=centre[:2], scale=self.scale)
210+
x, y = base.ellipse(A, inverted=False, centre=centre[:2], scale=self.scale)
208211
self.x = x
209212
self.y = y
210213
# = x[0,:] * self.scale + centre[0]

roboticstoolbox/blocks/uav.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,18 @@ class MultiRotor(TransferBlock):
3838
vehicle state is a dict containing the following items:
3939
4040
- ``x`` pose in the world frame as :math:`[x, y, z, \theta_Y, \theta_P, \theta_R]`
41-
- ``vb`` translational velocity in the world frame (metres/sec)
42-
- ``w`` angular rates in the world frame as yaw-pitch-roll rates (radians/second)
41+
- ``trans`` position and velocity in the world frame as
42+
:math:`[x, y, z, \dot{x}, \dot{y}, \dot{z}]`
43+
- ``rot`` orientation and angular rate in the world frame as
44+
:math:`[\theta_Y, \theta_P, \theta_R, \dot{\theta_Y}, \dot{\theta_P}, \dot{\theta_R}]`
45+
- ``vb`` translational velocity in the body frame as
46+
:math:`[\dot{x}, \dot{y}, \dot{z}]`
47+
- ``w`` angular rates in the body frame as
48+
:math:`[\dot{\theta_Y}, \dot{\theta_P}, \dot{\theta_R}]`
4349
- ``a1s`` longitudinal flapping angles (radians)
4450
- ``b1s`` lateral flapping angles (radians)
45-
51+
- ``X`` full state vector as
52+
:math:`[x, y, z, \theta_Y, \theta_P, \theta_R, \dot{x}, \dot{y}, \dot{z}, \dot{\theta_Y}, \dot{\theta_P}, \dot{\theta_R}]`
4653
4754
The dynamic model is a dict with the following key/value pairs.
4855
@@ -263,6 +270,8 @@ def output(self, t, inports, x):
263270
out["x"] = x[0:6]
264271
out["trans"] = np.r_[x[:3], vd]
265272
out["rot"] = np.r_[x[3:6], rpyd]
273+
out["vb"] = np.linalg.inv(R) @ x[6:9] # translational velocity mapped to body frame
274+
out["w"] = iW @ x[9:12] # RPY rates mapped to body frame
266275

267276
out["a1s"] = self.a1s
268277
out["b1s"] = self.b1s

roboticstoolbox/models/ETS/Planar2.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ def __init__(self):
3535

3636
super().__init__([l0, l1, l2], name="Planar2", comment="Planar 2D manipulator")
3737

38-
self.qr = np.array([0, 0])
38+
self.qb = np.array([0, np.pi/2])
3939
self.qz = np.zeros(2)
4040

41-
self.addconfiguration("qr", self.qr)
4241
self.addconfiguration("qz", self.qz)
42+
self.addconfiguration("qb", self.qb)
4343

4444

4545
if __name__ == "__main__": # pragma nocover

roboticstoolbox/robot/DHLink.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -380,11 +380,11 @@ def __repr__(self):
380380
name = self.__class__.__name__
381381
args = []
382382
if self.isrevolute:
383-
self._format(args, "d")
383+
self._format_param(args, "d")
384384
else:
385-
self._format(args, "theta", "θ")
386-
self._format(args, "a")
387-
self._format(args, "alpha", "⍺")
385+
self._format_param(args, "theta", "θ")
386+
self._format_param(args, "a")
387+
self._format_param(args, "alpha", "⍺")
388388
args.extend(super()._params())
389389
return name + "(" + ", ".join(args) + ")"
390390

roboticstoolbox/robot/Link.py

Lines changed: 47 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,61 +1367,62 @@ def format(l, fmt, val): # noqa
13671367

13681368
return dyn
13691369

1370+
def _format_param(
1371+
self, l, name, symbol=None, ignorevalue=None, indices=None
1372+
): # noqa # pragma nocover
1373+
# if value == ignorevalue then don't display it
1374+
1375+
v = getattr(self, name)
1376+
s = None
1377+
if v is None:
1378+
return
1379+
if isinstance(v, str):
1380+
s = f'{name} = "{v}"'
1381+
elif isscalar(v) and v != ignorevalue:
1382+
if symbol is not None:
1383+
s = f"{symbol}={v:.3g}"
1384+
else: # pragma: nocover
1385+
try:
1386+
s = f"{name}={v:.3g}"
1387+
except TypeError:
1388+
s = f"{name}={v}"
1389+
elif isinstance(v, np.ndarray):
1390+
# if np.linalg.norm(v, ord=np.inf) > 0:
1391+
# if indices is not None:
1392+
# flat = v.flatten()
1393+
# v = np.r_[[flat[k] for k in indices]]
1394+
# s = f"{name}=[" + ", ".join([f"{x:.3g}" for x in v]) + "]"
1395+
if indices is not None:
1396+
v = v.ravel()[indices]
1397+
s = f"{name}=" + np.array2string(
1398+
v,
1399+
separator=", ",
1400+
suppress_small=True,
1401+
formatter={"float": lambda x: f"{x:.3g}"},
1402+
)
1403+
if s is not None:
1404+
l.append(s)
1405+
13701406
def _params(self, name: bool = True): # pragma nocover
1371-
def format_param(
1372-
self, l, name, symbol=None, ignorevalue=None, indices=None
1373-
): # noqa # pragma nocover
1374-
# if value == ignorevalue then don't display it
1375-
1376-
v = getattr(self, name)
1377-
s = None
1378-
if v is None:
1379-
return
1380-
if isinstance(v, str):
1381-
s = f'{name} = "{v}"'
1382-
elif isscalar(v) and v != ignorevalue:
1383-
if symbol is not None:
1384-
s = f"{symbol}={v:.3g}"
1385-
else: # pragma: nocover
1386-
try:
1387-
s = f"{name}={v:.3g}"
1388-
except TypeError:
1389-
s = f"{name}={v}"
1390-
elif isinstance(v, np.ndarray):
1391-
# if np.linalg.norm(v, ord=np.inf) > 0:
1392-
# if indices is not None:
1393-
# flat = v.flatten()
1394-
# v = np.r_[[flat[k] for k in indices]]
1395-
# s = f"{name}=[" + ", ".join([f"{x:.3g}" for x in v]) + "]"
1396-
if indices is not None:
1397-
v = v.ravel()[indices]
1398-
s = f"{name}=" + np.array2string(
1399-
v,
1400-
separator=", ",
1401-
suppress_small=True,
1402-
formatter={"float": lambda x: f"{x:.3g}"},
1403-
)
1404-
if s is not None:
1405-
l.append(s)
14061407

14071408
l = [] # noqa
14081409
if name:
1409-
format_param(self, l, "name")
1410+
self._format_param(l, "name")
14101411
if self.parent_name is not None:
14111412
l.append('parent="' + self.parent_name + '"')
14121413
elif isinstance(self.parent, BaseLink):
14131414
l.append('parent="' + self.parent.name + '"')
1414-
format_param(self, l, "parent")
1415-
format_param(self, l, "isflip", ignorevalue=False)
1416-
format_param(self, l, "qlim")
1415+
self._format_param(l, "parent")
1416+
self._format_param(l, "isflip", ignorevalue=False)
1417+
self._format_param(l, "qlim")
14171418
if self._hasdynamics:
1418-
format_param(self, l, "m")
1419-
format_param(self, l, "r")
1420-
format_param(self, l, "I", indices=[0, 4, 8, 1, 2, 5])
1421-
format_param(self, l, "Jm")
1422-
format_param(self, l, "B")
1423-
format_param(self, l, "Tc")
1424-
format_param(self, l, "G")
1419+
self._format_param(l, "m")
1420+
self._format_param(l, "r")
1421+
self._format_param(l, "I", indices=[0, 4, 8, 1, 2, 5])
1422+
self._format_param(l, "Jm")
1423+
self._format_param(l, "B")
1424+
self._format_param(l, "Tc")
1425+
self._format_param(l, "G")
14251426

14261427
return l
14271428

roboticstoolbox/robot/PoERobot.py

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,6 @@ def __str__(self):
3333
s += "]"
3434
return s
3535

36-
def _repr_pretty_(self, p, cycle):
37-
"""
38-
Pretty string for IPython (superclass method)
39-
40-
:param p: pretty printer handle (ignored)
41-
:param cycle: pretty printer flag (ignored)
42-
43-
"""
44-
# see https://ipython.org/ipython-doc/stable/api/generated/IPython.lib.pretty.html
45-
46-
p.text(f"{i}:\n{str(x)}")
47-
4836

4937
class PoERevolute(PoELink):
5038
def __init__(self, axis, point, **kwargs):
@@ -114,26 +102,14 @@ def __str__(self):
114102
return s
115103

116104
def __repr__(self):
117-
s = "PoERobot([\n "
118-
for j, link in enumerate(self):
119-
s += repr(link) + ","
120-
s += "],\n"
105+
s = "PoERobot([\n"
106+
s += "\n".join([" " + repr(link) + "," for link in self])
107+
s += "\n ],\n"
121108
s += f" T0=SE3({np.array_repr(self.T0.A)}),\n"
122-
s += f" name={self.name},\n"
109+
s += f" name=\"{self.name}\",\n"
123110
s += ")"
124111
return s
125112

126-
def _repr_pretty_(self, p, cycle):
127-
"""
128-
Pretty string for IPython (superclass method)
129-
130-
:param p: pretty printer handle (ignored)
131-
:param cycle: pretty printer flag (ignored)
132-
133-
"""
134-
# see https://ipython.org/ipython-doc/stable/api/generated/IPython.lib.pretty.html
135-
136-
p.text(f"{i}:\n{str(x)}")
137113

138114
def nbranches(self):
139115
return 0

tests/test_ERobot.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def test_teach(self):
170170
def test_plot_with_vellipse(self):
171171
robot = rtb.models.ETS.Planar2()
172172
e = robot.plot(
173-
robot.qz, block=False, name=True, vellipse=True, limits=[1, 2, 1, 2]
173+
robot.qb, block=False, name=True, vellipse=True, limits=[1, 2, 1, 2]
174174
)
175175
e.step()
176176
e.close()

0 commit comments

Comments
 (0)