roboticstoolbox-python 1.4.0__py3-none-any.whl → 1.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- roboticstoolbox/__init__.py +3 -0
- roboticstoolbox/mobile/DistanceTransformPlanner.py +2 -4
- roboticstoolbox/models/URDF/URDFRobot.py +25 -20
- roboticstoolbox/robot/BaseRobot.py +3 -1
- roboticstoolbox/robot/DHLink.py +1 -1
- roboticstoolbox/robot/Dynamics.py +12 -16
- roboticstoolbox/robot/RobotPlottingMPL.py +4 -4
- roboticstoolbox/tools/__init__.py +4 -0
- roboticstoolbox/tools/trchain.py +233 -0
- {roboticstoolbox_python-1.4.0.dist-info → roboticstoolbox_python-1.4.1.dist-info}/METADATA +2 -1
- {roboticstoolbox_python-1.4.0.dist-info → roboticstoolbox_python-1.4.1.dist-info}/RECORD +14 -13
- {roboticstoolbox_python-1.4.0.dist-info → roboticstoolbox_python-1.4.1.dist-info}/WHEEL +0 -0
- {roboticstoolbox_python-1.4.0.dist-info → roboticstoolbox_python-1.4.1.dist-info}/entry_points.txt +0 -0
- {roboticstoolbox_python-1.4.0.dist-info → roboticstoolbox_python-1.4.1.dist-info}/licenses/LICENSE +0 -0
roboticstoolbox/__init__.py
CHANGED
|
@@ -9,7 +9,7 @@ from spatialmath.pose2d import SE2
|
|
|
9
9
|
from spatialmath import base
|
|
10
10
|
from scipy.ndimage import *
|
|
11
11
|
import matplotlib.pyplot as plt
|
|
12
|
-
from matplotlib import
|
|
12
|
+
from matplotlib import colormaps
|
|
13
13
|
from roboticstoolbox.mobile.PlannerBase import PlannerBase
|
|
14
14
|
|
|
15
15
|
|
|
@@ -324,9 +324,7 @@ def distancexform(occgrid, goal, metric="cityblock", animate=False, summary=Fals
|
|
|
324
324
|
plt.ylabel("y")
|
|
325
325
|
ax = plt.gca()
|
|
326
326
|
plt.pause(0.001)
|
|
327
|
-
cmap =
|
|
328
|
-
cmap.set_bad("red")
|
|
329
|
-
cmap.set_over("white")
|
|
327
|
+
cmap = colormaps.get_cmap("gray").with_extremes(bad="red", over="white")
|
|
330
328
|
h = plt.imshow(display, cmap=cmap)
|
|
331
329
|
plt.colorbar(label="distance")
|
|
332
330
|
else:
|
|
@@ -90,6 +90,31 @@ def _load_rd_module(robot_name: str):
|
|
|
90
90
|
"URDF model."
|
|
91
91
|
)
|
|
92
92
|
|
|
93
|
+
# robot_descriptions clones a git repository (via GitPython, which shells
|
|
94
|
+
# out to a real git binary) the first time a given model is imported.
|
|
95
|
+
# Pyodide/JupyterLite has no subprocess execution and no git binary, so
|
|
96
|
+
# this always fails there -- not a bug, an environment limitation.
|
|
97
|
+
# Checked up front, before the candidates loop below, rather than caught
|
|
98
|
+
# per-attempt: GitPython's failure in this sandbox surfaces as a plain
|
|
99
|
+
# ImportError (message: "emscripten does not support processes"), which
|
|
100
|
+
# the loop's `except ImportError` treats as "this candidate name doesn't
|
|
101
|
+
# exist, try the next one" -- so after exhausting every candidate it fell
|
|
102
|
+
# through to a misleading "model not found"/"renamed" error instead of
|
|
103
|
+
# this one. The outcome here is deterministic regardless of which
|
|
104
|
+
# candidate name is tried, so there is nothing to gain by attempting the
|
|
105
|
+
# loop at all on this platform.
|
|
106
|
+
if sys.platform == "emscripten":
|
|
107
|
+
raise ValueError(
|
|
108
|
+
f"Toolbox uses {_rd_link()} to provide URDF robot models, "
|
|
109
|
+
"which clones a git repository on first use. That isn't "
|
|
110
|
+
"possible in this browser (Pyodide/JupyterLite) sandbox -- "
|
|
111
|
+
f'this is an expected limitation loading "{robot_name}" '
|
|
112
|
+
"here, not a bug. Try a DH- or ETS-based model instead "
|
|
113
|
+
"(e.g. rtb.models.DH.Panda()), or run this notebook in a "
|
|
114
|
+
"regular Python environment to use robot_descriptions-"
|
|
115
|
+
"backed models."
|
|
116
|
+
)
|
|
117
|
+
|
|
93
118
|
candidates = [f"{robot_name}_description", f"{robot_name}_official_description"]
|
|
94
119
|
last_error: ImportError | None = None
|
|
95
120
|
for candidate in candidates:
|
|
@@ -103,26 +128,6 @@ def _load_rd_module(robot_name: str):
|
|
|
103
128
|
except ImportError as e:
|
|
104
129
|
last_error = e
|
|
105
130
|
continue
|
|
106
|
-
except Exception as e:
|
|
107
|
-
# robot_descriptions clones a git repository (via GitPython,
|
|
108
|
-
# which shells out to a real git binary) the first time a given
|
|
109
|
-
# model is imported. Pyodide/JupyterLite has no subprocess
|
|
110
|
-
# execution and no git binary, so this always fails there --
|
|
111
|
-
# not a bug, an environment limitation. The exact exception type
|
|
112
|
-
# depends on how GitPython fails in that sandbox, so this is
|
|
113
|
-
# deliberately broad, but only ever intercepts on Pyodide.
|
|
114
|
-
if sys.platform == "emscripten":
|
|
115
|
-
raise ValueError(
|
|
116
|
-
f"Toolbox uses {_rd_link()} to provide URDF robot models, "
|
|
117
|
-
"which clones a git repository on first use. That isn't "
|
|
118
|
-
"possible in this browser (Pyodide/JupyterLite) sandbox -- "
|
|
119
|
-
f'this is an expected limitation loading "{robot_name}" '
|
|
120
|
-
"here, not a bug. Try a DH- or ETS-based model instead "
|
|
121
|
-
"(e.g. rtb.models.DH.Panda()), or run this notebook in a "
|
|
122
|
-
"regular Python environment to use robot_descriptions-"
|
|
123
|
-
"backed models."
|
|
124
|
-
) from e
|
|
125
|
-
raise
|
|
126
131
|
|
|
127
132
|
renamed_to = _find_rd_rename(robot_name, candidates)
|
|
128
133
|
if renamed_to is not None:
|
|
@@ -2225,11 +2225,13 @@ class BaseRobot(SceneNode, DynamicsMixin, RobotPlottingMPLMixin, ABC, Generic[Li
|
|
|
2225
2225
|
already_blocked = env._add_teach_panel(self, q, handle, block)
|
|
2226
2226
|
|
|
2227
2227
|
if vellipse:
|
|
2228
|
-
vell = self.vellipse(q, centre="ee",
|
|
2228
|
+
vell = self.vellipse(q, centre="ee", add=False)
|
|
2229
|
+
env._teach_vellipse = vell
|
|
2229
2230
|
env.add(vell)
|
|
2230
2231
|
|
|
2231
2232
|
if fellipse:
|
|
2232
2233
|
fell = self.fellipse(q, centre="ee", add=False)
|
|
2234
|
+
env._teach_fellipse = fell
|
|
2233
2235
|
env.add(fell)
|
|
2234
2236
|
|
|
2235
2237
|
# Keep the plot open -- skipped if the backend already blocked
|
roboticstoolbox/robot/DHLink.py
CHANGED
|
@@ -1256,21 +1256,23 @@ class DynamicsMixin:
|
|
|
1256
1256
|
:returns: Operational space accelerations of the end-effector
|
|
1257
1257
|
:rtype: ndarray(6,)
|
|
1258
1258
|
|
|
1259
|
-
``xdd = accel_x(q,
|
|
1259
|
+
``xdd = accel_x(q, xd, wrench)`` is the operational space acceleration
|
|
1260
1260
|
due to ``wrench`` applied to the end-effector of a robot in joint
|
|
1261
|
-
configuration ``q`` and
|
|
1261
|
+
configuration ``q`` and operational space velocity ``xd``.
|
|
1262
1262
|
|
|
1263
1263
|
.. math::
|
|
1264
1264
|
|
|
1265
|
-
\ddot{x} = \mathbf{J}(q
|
|
1266
|
-
\mathbf{J}(q)
|
|
1265
|
+
\ddot{x} = \dot{\mathbf{J}}_a(q, \dot{q})\dot{q}
|
|
1266
|
+
+ \mathbf{J}_a(q) \mathbf{M}(q)^{-1} \left(
|
|
1267
|
+
\mathbf{J}_a(q)^T w - \mathbf{C}(q)\dot{q}
|
|
1268
|
+
- \mathbf{g}(q)
|
|
1267
1269
|
\right)
|
|
1268
1270
|
|
|
1269
1271
|
**Trajectory operation**
|
|
1270
1272
|
|
|
1271
|
-
If
|
|
1272
|
-
where each row is the acceleration
|
|
1273
|
-
of q
|
|
1273
|
+
If ``q`` is a matrix (m,n), and ``xd`` and ``wrench`` are matrices
|
|
1274
|
+
(m,6), then ``xdd`` is a matrix (m,6) where each row is the acceleration
|
|
1275
|
+
corresponding to the equivalent rows of ``q``, ``xd``, and ``wrench``.
|
|
1274
1276
|
|
|
1275
1277
|
.. rubric:: Notes
|
|
1276
1278
|
|
|
@@ -1294,7 +1296,7 @@ class DynamicsMixin:
|
|
|
1294
1296
|
if q.shape[1] != 6:
|
|
1295
1297
|
pinv = True
|
|
1296
1298
|
|
|
1297
|
-
xdd = np.zeros((q.shape[0],
|
|
1299
|
+
xdd = np.zeros((q.shape[0], 6))
|
|
1298
1300
|
|
|
1299
1301
|
for k, (qk, xdk, wk) in enumerate(zip(q, xd, w)):
|
|
1300
1302
|
Ja = self.jacob0_analytical(qk, representation=representation)
|
|
@@ -1322,16 +1324,10 @@ class DynamicsMixin:
|
|
|
1322
1324
|
|
|
1323
1325
|
# xd = Ja qd
|
|
1324
1326
|
# xdd = Jad qd + Ja qdd
|
|
1325
|
-
#
|
|
1326
|
-
# Ja = T J
|
|
1327
|
-
# Jad = Td J + T Jd
|
|
1328
|
-
# assume Td = 0, not sure how valid that is
|
|
1329
|
-
|
|
1330
|
-
# need Jacobian dot
|
|
1331
1327
|
qdk = Ji @ xdk
|
|
1332
|
-
|
|
1328
|
+
Jad = self.jacob0_dot(qk, qdk, representation=representation)
|
|
1333
1329
|
|
|
1334
|
-
xdd[k, :] =
|
|
1330
|
+
xdd[k, :] = Jad @ qdk + Ja @ qdd
|
|
1335
1331
|
|
|
1336
1332
|
if q.shape[0] == 1:
|
|
1337
1333
|
return xdd[0, :]
|
|
@@ -62,12 +62,12 @@ class RobotPlottingMPLMixin:
|
|
|
62
62
|
|
|
63
63
|
"""
|
|
64
64
|
|
|
65
|
-
from matplotlib import
|
|
65
|
+
from matplotlib import colormaps, colors
|
|
66
66
|
|
|
67
|
-
if isinstance(linkcolors, list) and len(linkcolors) == self.n: # type: ignore[attr-defined]
|
|
67
|
+
if isinstance(linkcolors, list) and len(linkcolors) == self.n: # type: ignore[attr-defined]
|
|
68
68
|
return colors.ListedColormap(linkcolors)
|
|
69
|
-
else:
|
|
70
|
-
return
|
|
69
|
+
else:
|
|
70
|
+
return colormaps.get_cmap(linkcolors).resampled(6)
|
|
71
71
|
|
|
72
72
|
# ------------------------------------------------------------------
|
|
73
73
|
# Ellipse creation
|
|
@@ -22,6 +22,7 @@ from roboticstoolbox.tools.data import (
|
|
|
22
22
|
)
|
|
23
23
|
from roboticstoolbox.tools.plot import xplot
|
|
24
24
|
from roboticstoolbox.tools.params import rtb_set_param, rtb_get_param
|
|
25
|
+
from roboticstoolbox.tools.trchain import TrChainToken, trchain, trchain2
|
|
25
26
|
from roboticstoolbox.tools.types import ArrayLike, NDArray, PyArrayLike
|
|
26
27
|
|
|
27
28
|
__all__ = [
|
|
@@ -48,6 +49,9 @@ __all__ = [
|
|
|
48
49
|
"rtb_path_to_datafile",
|
|
49
50
|
"rtb_set_param",
|
|
50
51
|
"rtb_get_param",
|
|
52
|
+
"TrChainToken",
|
|
53
|
+
"trchain",
|
|
54
|
+
"trchain2",
|
|
51
55
|
"PyArrayLike",
|
|
52
56
|
"ArrayLike",
|
|
53
57
|
"NDArray",
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""Evaluate chains of elementary homogeneous transforms."""
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
import operator
|
|
5
|
+
import re
|
|
6
|
+
from collections.abc import Callable, Mapping, Sequence
|
|
7
|
+
from typing import NamedTuple
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from spatialmath.base import symbolic as sym
|
|
11
|
+
from spatialmath.base import transl, transl2, trot2, trotx, troty, trotz
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TrChainToken(NamedTuple):
|
|
15
|
+
"""A parsed elementary-transform token.
|
|
16
|
+
|
|
17
|
+
:param op: elementary-transform operator
|
|
18
|
+
:param arg: expression inside the operator's parentheses
|
|
19
|
+
:param index: one-based joint index, or zero for a constant expression
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
op: str
|
|
23
|
+
arg: str
|
|
24
|
+
index: int
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
_TOKEN_RE = re.compile(r"(?P<op>R.?|T.)\(")
|
|
28
|
+
_BINARY_OPERATORS: dict[type[ast.operator], Callable[[object, object], object]] = {
|
|
29
|
+
ast.Add: operator.add,
|
|
30
|
+
ast.Sub: operator.sub,
|
|
31
|
+
ast.Mult: operator.mul,
|
|
32
|
+
ast.Div: operator.truediv,
|
|
33
|
+
ast.FloorDiv: operator.floordiv,
|
|
34
|
+
ast.Mod: operator.mod,
|
|
35
|
+
ast.Pow: operator.pow,
|
|
36
|
+
}
|
|
37
|
+
_UNARY_OPERATORS: dict[type[ast.unaryop], Callable[[object], object]] = {
|
|
38
|
+
ast.UAdd: operator.pos,
|
|
39
|
+
ast.USub: operator.neg,
|
|
40
|
+
}
|
|
41
|
+
_DEFAULT_VALUES = {
|
|
42
|
+
"pi": np.pi,
|
|
43
|
+
"sin": sym.sin,
|
|
44
|
+
"cos": sym.cos,
|
|
45
|
+
"tan": sym.tan,
|
|
46
|
+
"sqrt": sym.sqrt,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
_Transform = Callable[[object, str], np.ndarray]
|
|
50
|
+
_TRANSFORMS_3D: dict[str, _Transform] = {
|
|
51
|
+
"Rx": lambda value, unit: trotx(value, unit),
|
|
52
|
+
"Ry": lambda value, unit: troty(value, unit),
|
|
53
|
+
"Rz": lambda value, unit: trotz(value, unit),
|
|
54
|
+
"Tx": lambda value, _unit: transl(value, 0, 0),
|
|
55
|
+
"Ty": lambda value, _unit: transl(0, value, 0),
|
|
56
|
+
"Tz": lambda value, _unit: transl(0, 0, value),
|
|
57
|
+
}
|
|
58
|
+
_TRANSFORMS_2D: dict[str, _Transform] = {
|
|
59
|
+
"R": lambda value, unit: trot2(value, unit),
|
|
60
|
+
"Rz": lambda value, unit: trot2(value, unit),
|
|
61
|
+
"Tx": lambda value, _unit: transl2(value, 0),
|
|
62
|
+
"Ty": lambda value, _unit: transl2(0, value),
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _parse(chain: str, qvar: str) -> tuple[TrChainToken, ...]:
|
|
67
|
+
q_re = re.compile(rf"\b{re.escape(qvar)}([1-9][0-9]*)\b")
|
|
68
|
+
tokens = []
|
|
69
|
+
position = 0
|
|
70
|
+
|
|
71
|
+
while match := _TOKEN_RE.search(chain, position):
|
|
72
|
+
depth = 1
|
|
73
|
+
for position in range(match.end(), len(chain)):
|
|
74
|
+
if chain[position] == "(":
|
|
75
|
+
depth += 1
|
|
76
|
+
elif chain[position] == ")":
|
|
77
|
+
depth -= 1
|
|
78
|
+
if depth == 0:
|
|
79
|
+
break
|
|
80
|
+
else:
|
|
81
|
+
raise ValueError(f"unclosed transform {match['op']!r}")
|
|
82
|
+
|
|
83
|
+
arg = chain[match.end() : position]
|
|
84
|
+
indices = q_re.findall(arg)
|
|
85
|
+
if len(indices) > 1:
|
|
86
|
+
raise ValueError("only one joint variable is allowed in each transform")
|
|
87
|
+
tokens.append(TrChainToken(match["op"], arg, int(indices[0]) if indices else 0))
|
|
88
|
+
position += 1
|
|
89
|
+
|
|
90
|
+
return tuple(tokens)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _eval_expression(expression: str, values: Mapping[str, object]) -> object:
|
|
94
|
+
try:
|
|
95
|
+
tree = ast.parse(expression, mode="eval")
|
|
96
|
+
except SyntaxError as exc:
|
|
97
|
+
raise ValueError(f"cannot evaluate expression {expression!r}") from exc
|
|
98
|
+
|
|
99
|
+
def evaluate(node: ast.AST) -> object:
|
|
100
|
+
if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
|
|
101
|
+
return node.value
|
|
102
|
+
if isinstance(node, ast.Name):
|
|
103
|
+
try:
|
|
104
|
+
return values[node.id]
|
|
105
|
+
except KeyError as exc:
|
|
106
|
+
raise ValueError(
|
|
107
|
+
f"unknown name {node.id!r} in expression {expression!r}"
|
|
108
|
+
) from exc
|
|
109
|
+
if isinstance(node, ast.BinOp) and type(node.op) in _BINARY_OPERATORS:
|
|
110
|
+
return _BINARY_OPERATORS[type(node.op)](
|
|
111
|
+
evaluate(node.left), evaluate(node.right)
|
|
112
|
+
)
|
|
113
|
+
if isinstance(node, ast.UnaryOp) and type(node.op) in _UNARY_OPERATORS:
|
|
114
|
+
return _UNARY_OPERATORS[type(node.op)](evaluate(node.operand))
|
|
115
|
+
if (
|
|
116
|
+
isinstance(node, ast.Call)
|
|
117
|
+
and isinstance(node.func, ast.Name)
|
|
118
|
+
and not node.keywords
|
|
119
|
+
):
|
|
120
|
+
function = values.get(node.func.id)
|
|
121
|
+
if callable(function):
|
|
122
|
+
return function(*(evaluate(arg) for arg in node.args))
|
|
123
|
+
raise ValueError(f"unsupported expression {expression!r}")
|
|
124
|
+
|
|
125
|
+
return evaluate(tree.body)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _evaluate_chain(
|
|
129
|
+
chain: str | Sequence[TrChainToken],
|
|
130
|
+
q: Sequence[object] | np.ndarray | None,
|
|
131
|
+
unit: str,
|
|
132
|
+
qvar: str,
|
|
133
|
+
variables: Mapping[str, object] | None,
|
|
134
|
+
transforms: Mapping[str, _Transform],
|
|
135
|
+
size: int,
|
|
136
|
+
) -> tuple[np.ndarray, tuple[TrChainToken, ...]]:
|
|
137
|
+
if unit not in {"rad", "deg"}:
|
|
138
|
+
raise ValueError("unit must be 'rad' or 'deg'")
|
|
139
|
+
if not qvar.isidentifier():
|
|
140
|
+
raise ValueError("qvar must be a valid identifier")
|
|
141
|
+
|
|
142
|
+
if isinstance(chain, str):
|
|
143
|
+
tokens = _parse(chain, qvar)
|
|
144
|
+
else:
|
|
145
|
+
tokens = tuple(chain)
|
|
146
|
+
if not all(isinstance(token, TrChainToken) for token in tokens):
|
|
147
|
+
raise TypeError("chain must be a string or a sequence of TrChainToken")
|
|
148
|
+
|
|
149
|
+
q_values = np.asarray(()) if q is None else np.asarray(q).reshape(-1)
|
|
150
|
+
values = {**_DEFAULT_VALUES, **(variables or {})}
|
|
151
|
+
T = np.eye(size)
|
|
152
|
+
|
|
153
|
+
for token in tokens:
|
|
154
|
+
try:
|
|
155
|
+
transform = transforms[token.op]
|
|
156
|
+
except KeyError as exc:
|
|
157
|
+
raise ValueError(f"unknown transform {token.op!r}") from exc
|
|
158
|
+
|
|
159
|
+
token_values = values
|
|
160
|
+
if token.index:
|
|
161
|
+
if token.index > len(q_values):
|
|
162
|
+
raise ValueError("q has insufficient values")
|
|
163
|
+
token_values = {
|
|
164
|
+
**values,
|
|
165
|
+
f"{qvar}{token.index}": q_values[token.index - 1],
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
T = T @ transform(_eval_expression(token.arg, token_values), unit)
|
|
169
|
+
|
|
170
|
+
return T, tokens
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def trchain(
|
|
174
|
+
chain: str | Sequence[TrChainToken],
|
|
175
|
+
q: Sequence[object] | np.ndarray | None = None,
|
|
176
|
+
unit: str = "rad",
|
|
177
|
+
*,
|
|
178
|
+
qvar: str = "q",
|
|
179
|
+
variables: Mapping[str, object] | None = None,
|
|
180
|
+
return_tokens: bool = False,
|
|
181
|
+
) -> np.ndarray | tuple[np.ndarray, tuple[TrChainToken, ...]]:
|
|
182
|
+
"""Compound SE(3) elementary transforms from a string.
|
|
183
|
+
|
|
184
|
+
:param chain: transform chain or tokens returned by an earlier call
|
|
185
|
+
:param q: joint values referenced as ``q1``, ``q2``, and so on
|
|
186
|
+
:param unit: angular unit, ``"rad"`` or ``"deg"``
|
|
187
|
+
:param qvar: joint-variable prefix
|
|
188
|
+
:param variables: values and functions used by token expressions
|
|
189
|
+
:param return_tokens: also return the parsed tokens for reuse
|
|
190
|
+
:returns: the SE(3) matrix, optionally followed by its parsed tokens
|
|
191
|
+
:rtype: ndarray(4, 4) or tuple
|
|
192
|
+
|
|
193
|
+
The chain contains ``Rx``, ``Ry``, ``Rz``, ``Tx``, ``Ty``, and ``Tz``
|
|
194
|
+
tokens. Expressions support arithmetic, named values, ``pi``, and direct
|
|
195
|
+
calls to named functions. Names other than joint variables are supplied by
|
|
196
|
+
``variables``.
|
|
197
|
+
|
|
198
|
+
:seealso: :func:`trchain2`, :class:`roboticstoolbox.ETS`
|
|
199
|
+
"""
|
|
200
|
+
result = _evaluate_chain(chain, q, unit, qvar, variables, _TRANSFORMS_3D, 4)
|
|
201
|
+
return result if return_tokens else result[0]
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def trchain2(
|
|
205
|
+
chain: str | Sequence[TrChainToken],
|
|
206
|
+
q: Sequence[object] | np.ndarray | None = None,
|
|
207
|
+
unit: str = "rad",
|
|
208
|
+
*,
|
|
209
|
+
qvar: str = "q",
|
|
210
|
+
variables: Mapping[str, object] | None = None,
|
|
211
|
+
return_tokens: bool = False,
|
|
212
|
+
) -> np.ndarray | tuple[np.ndarray, tuple[TrChainToken, ...]]:
|
|
213
|
+
"""Compound SE(2) elementary transforms from a string.
|
|
214
|
+
|
|
215
|
+
:param chain: transform chain or tokens returned by an earlier call
|
|
216
|
+
:param q: joint values referenced as ``q1``, ``q2``, and so on
|
|
217
|
+
:param unit: angular unit, ``"rad"`` or ``"deg"``
|
|
218
|
+
:param qvar: joint-variable prefix
|
|
219
|
+
:param variables: values and functions used by token expressions
|
|
220
|
+
:param return_tokens: also return the parsed tokens for reuse
|
|
221
|
+
:returns: the SE(2) matrix, optionally followed by its parsed tokens
|
|
222
|
+
:rtype: ndarray(3, 3) or tuple
|
|
223
|
+
|
|
224
|
+
The chain contains ``R`` (or ``Rz``), ``Tx``, and ``Ty`` tokens.
|
|
225
|
+
Expressions are evaluated as described by :func:`trchain`.
|
|
226
|
+
|
|
227
|
+
:seealso: :func:`trchain`, :class:`roboticstoolbox.ETS2`
|
|
228
|
+
"""
|
|
229
|
+
result = _evaluate_chain(chain, q, unit, qvar, variables, _TRANSFORMS_2D, 3)
|
|
230
|
+
return result if return_tokens else result[0]
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
__all__ = ["TrChainToken", "trchain", "trchain2"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: roboticstoolbox-python
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.1
|
|
4
4
|
Summary: A Python library for robotics education and research
|
|
5
5
|
Keywords: python,robotics,robotics-toolbox,kinematics,dynamics,motion-planning,trajectory-generation,jacobian,hessian,control,simulation,robot-manipulator,mobile-robot
|
|
6
6
|
Author-Email: Jesse Haviland <j.haviland@qut.edu.au>, Peter Corke <rvc@petercorke.com>
|
|
@@ -33,6 +33,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
33
33
|
Classifier: Programming Language :: Python :: 3.11
|
|
34
34
|
Classifier: Programming Language :: Python :: 3.12
|
|
35
35
|
Classifier: Programming Language :: Python :: 3.13
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
36
37
|
Project-URL: homepage, https://petercorke.github.io/robotics-toolbox-python/
|
|
37
38
|
Project-URL: documentation, https://petercorke.github.io/robotics-toolbox-python/
|
|
38
39
|
Project-URL: repository, https://github.com/petercorke/robotics-toolbox-python
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
roboticstoolbox/__init__.py,sha256=
|
|
1
|
+
roboticstoolbox/__init__.py,sha256=D_IIMDfJ3IFnjkA1BS9ujcmIvBU5fCtJ4ETPNX-o1Uo,1972
|
|
2
2
|
roboticstoolbox/backends/Connector.py,sha256=oIIoFQdCgCyRvv6dlaCSopYmBRG7h-sUmlT_9Qf6Vkg,2655
|
|
3
3
|
roboticstoolbox/backends/Dynamixel/README.md,sha256=XSljkUIzB6DIyfih5RS-TlM_MFxHAE3VDr5yzQ8TgOM,289
|
|
4
4
|
roboticstoolbox/backends/Dynamixel/dynamixel.json,sha256=au-Yh-LPG1Tm9nMRxWrziatPs3ZSziGLdTam98JMVXQ,14181
|
|
@@ -480,7 +480,7 @@ roboticstoolbox/ets/fknm.py,sha256=vuZ_eEJiob3pvsjCBgH_Bq8rfc_NVXLCRECkSKTA0G4,1
|
|
|
480
480
|
roboticstoolbox/mobile/Animations.py,sha256=Z6VneDvf0fW0gFYQXVLoqBvq3qDKfK-y1cOa18S_cWs,15929
|
|
481
481
|
roboticstoolbox/mobile/Bug2.py,sha256=tp7NLJBHJcH_W43YQv_zeTBClLfwDbTOjtrHjvDCoOM,14510
|
|
482
482
|
roboticstoolbox/mobile/CurvaturePolyPlanner.py,sha256=vSqcsPxGwzeDzDbr6itKFUaKByth8jkynQs6UESdBjE,5464
|
|
483
|
-
roboticstoolbox/mobile/DistanceTransformPlanner.py,sha256=
|
|
483
|
+
roboticstoolbox/mobile/DistanceTransformPlanner.py,sha256=Nf4E-dBp5StzdLIk__8m_CNFedtbWXgJPVj1rGsPk5I,12224
|
|
484
484
|
roboticstoolbox/mobile/DstarPlanner.py,sha256=eZvgw3zYUPgc5SjgMzBd7No3m20xCRySgj89u4fnNB0,19219
|
|
485
485
|
roboticstoolbox/mobile/DubinsPlanner.py,sha256=HH62OZR4QTL1cUUVcrJsy7nCXNqHnikUH0ytp81tnSc,14087
|
|
486
486
|
roboticstoolbox/mobile/EKF.py,sha256=4ZJvnSNULUQNf67spJVJTmzse9NIC1aeAbsz-kfekJE,52390
|
|
@@ -548,7 +548,7 @@ roboticstoolbox/models/URDF/Puma560.py,sha256=1WHxYNXkYgJ6TJ9xJpJzfkZlfHZA2N9HFS
|
|
|
548
548
|
roboticstoolbox/models/URDF/UR10.py,sha256=OIw8-f3diIytx9M4FKofNOlduEDRiYTVQZdvZjY5Zo4,1073
|
|
549
549
|
roboticstoolbox/models/URDF/UR3.py,sha256=T0pd-KtNQYoqmONkfMaqWKZSA6WS3Wq0JzS3NIL1lvg,1066
|
|
550
550
|
roboticstoolbox/models/URDF/UR5.py,sha256=DDLzthyJ0fyylxijTZ14X_KZIYsCgLO1S6Pk5vecQZ0,1671
|
|
551
|
-
roboticstoolbox/models/URDF/URDFRobot.py,sha256=
|
|
551
|
+
roboticstoolbox/models/URDF/URDFRobot.py,sha256=cEyhWSozFhvQwJsYZ8hhGjkByzChGjHWXahTjiK6a7k,15441
|
|
552
552
|
roboticstoolbox/models/URDF/Valkyrie.py,sha256=7LLgVRXFZ_NM5lksNW7jx6jugSDEJ4uylqqqfwkbPP0,4133
|
|
553
553
|
roboticstoolbox/models/URDF/YuMi.py,sha256=IZQWtVrolGdhug08bm7rk5esirIdas4L_VBuWl0yupc,3245
|
|
554
554
|
roboticstoolbox/models/URDF/__init__.py,sha256=G4PNTfYRiYekdxssVHN8v3zPUWPhbcOrffJR9u6lWDo,1599
|
|
@@ -563,11 +563,11 @@ roboticstoolbox/models/URDF/wx250.py,sha256=1vu7dnbnG72P46d0ThP5Yx0I56aCl-sPXYll
|
|
|
563
563
|
roboticstoolbox/models/URDF/wx250s.py,sha256=A_BptSxGEBHXLauvB6TepFYHS5owvlHOPxpJbDK8QPA,1254
|
|
564
564
|
roboticstoolbox/models/__init__.py,sha256=HTx6EusezeH5Qq2wDwDqaI6JCcp9cDWeaYAgQL62VmI,245
|
|
565
565
|
roboticstoolbox/models/catalog.py,sha256=R-Lc_vHoOfae-afVS1olmoPu9cq7YTDfYqtCJeM3W9g,8694
|
|
566
|
-
roboticstoolbox/robot/BaseRobot.py,sha256=
|
|
566
|
+
roboticstoolbox/robot/BaseRobot.py,sha256=WK2pSU9Oqi_ARQtzv78wA-a4xK3NDyddnjZKqi3hfQo,82276
|
|
567
567
|
roboticstoolbox/robot/DHFactor.py,sha256=Bf-j7IvBKRA6_k3uev_ceQRMAC79D7W0Ir7kCJt4mec,15981
|
|
568
|
-
roboticstoolbox/robot/DHLink.py,sha256=
|
|
568
|
+
roboticstoolbox/robot/DHLink.py,sha256=_7FtGDuS_dVxFGUQx9-Vqj7EoLsMIhV9SwVDFpWBPWs,27815
|
|
569
569
|
roboticstoolbox/robot/DHRobot.py,sha256=AzGahOI9zs5A-3H5klUASKyaP_N1on9QGJ_TzTTpIJw,91705
|
|
570
|
-
roboticstoolbox/robot/Dynamics.py,sha256=
|
|
570
|
+
roboticstoolbox/robot/Dynamics.py,sha256=iCplz4L1wT2OeXuS0acO9x8h4uxsifT67PV4TViUwZw,52479
|
|
571
571
|
roboticstoolbox/robot/ELink.py,sha256=sgA-1c-U0Gz6TxABSJvfauq2L0Wu_1_pGJVKfLgrGP8,525
|
|
572
572
|
roboticstoolbox/robot/ERobot.py,sha256=aUnSg91PwHyIHO6ipWtnNBNLYCftKGIxgYz1qX8wghg,567
|
|
573
573
|
roboticstoolbox/robot/Gripper.py,sha256=CYyXFBYbEp52-RX-b6xGWS3EH-Y2BsYdtaR8Q0yAm3s,6954
|
|
@@ -576,7 +576,7 @@ roboticstoolbox/robot/Link.py,sha256=m98nfpv61C5Z1GDrOV_iN6gxyh9qj8URwiju9ssKXxw
|
|
|
576
576
|
roboticstoolbox/robot/PoERobot.py,sha256=mByMjb3P5FrW3Z8zyLS5waYcKBy8lpHG44g2uBUyB70,11053
|
|
577
577
|
roboticstoolbox/robot/Robot.py,sha256=cIixw_nx1ZzpzSVL_GzT6Hlf-HABK9aE856DPFWKGoM,77812
|
|
578
578
|
roboticstoolbox/robot/RobotKinematics.py,sha256=4aXOGhc2oGOCbr0tB4ruT1Od5nJMV5WL9Q3tmb2IU74,58631
|
|
579
|
-
roboticstoolbox/robot/RobotPlottingMPL.py,sha256=
|
|
579
|
+
roboticstoolbox/robot/RobotPlottingMPL.py,sha256=tmIGievDZwtLkd0To0Of2MeAB38yvbUd8T0bF0qwLd8,14207
|
|
580
580
|
roboticstoolbox/robot/RobotProto.py,sha256=os5bJSXp4ZO-ANJjaSF8_Xb-TJxbCg1Ry_obS3A6LqM,4339
|
|
581
581
|
roboticstoolbox/robot/__init__.py,sha256=RUeji1GTnAL3U3mn0ae6W1lnmvC-CFlUw5U7RTQnvO8,1237
|
|
582
582
|
roboticstoolbox/robot/cpp-extensions/README.md,sha256=hmXhlk7PVPmaLMXMmM1_IiI-AQpUKFqMyPvdx9kt0OU,1235
|
|
@@ -588,7 +588,7 @@ roboticstoolbox/robot/cpp-extensions/vmath.h,sha256=CEYvZMjVCNFrJQXts32iKskcliXh
|
|
|
588
588
|
roboticstoolbox/robot/frne.py,sha256=PjUxGEl3dRcPe-PZJwsH3LivGha6bgo7JJjhwOxTcZ8,1810
|
|
589
589
|
roboticstoolbox/tools/DHFactor.py,sha256=y_UOLTnFEAZJU7Vw2wPBREOxx5zph1VMXxVELGb8zFc,11815
|
|
590
590
|
roboticstoolbox/tools/Ticker.py,sha256=MxEWyDn1eAd6keZtyhfts2LmMe8rt-AUh3kN9zBtAKc,1204
|
|
591
|
-
roboticstoolbox/tools/__init__.py,sha256=
|
|
591
|
+
roboticstoolbox/tools/__init__.py,sha256=PRmXLt-qi26A25_c5XwvR6JSAUlkWFlJUI8wWb-cNM8,1460
|
|
592
592
|
roboticstoolbox/tools/data.py,sha256=ms51jPRCETDr_AGV1-OG-xocGIPOblHUYu-wekkq56o,5550
|
|
593
593
|
roboticstoolbox/tools/jsingu.py,sha256=4drWqPGNz4VBnMIcTxqkExmTiKu6v49r9yRzC7WDF4Q,1398
|
|
594
594
|
roboticstoolbox/tools/null.py,sha256=ZBBM4GN9f0d2xBaXpJL8n51_tEjeJuFhxfPjOpUJvNk,1507
|
|
@@ -597,14 +597,15 @@ roboticstoolbox/tools/p_servo.py,sha256=KpFoe2sgeYG_plr2kTwb0nRlVfKKCdaGR82NnD-1
|
|
|
597
597
|
roboticstoolbox/tools/params.py,sha256=2DRBgmjVFxulh-5u8rAiiqYQQycZEsAEoho4lVX0CoY,151
|
|
598
598
|
roboticstoolbox/tools/plot.py,sha256=THXEaz_R-J57FhL3gq_rdRVz9B6UykZQYxbIEvtkGv8,2896
|
|
599
599
|
roboticstoolbox/tools/trajectory.py,sha256=D0gJwuFvpkuYkVJkXwLRJYJaROwwad85-2JWBMkkISA,34214
|
|
600
|
+
roboticstoolbox/tools/trchain.py,sha256=p6MUo8m1Ydnjmu0SBtUWe-ODNO-s4WkLbqu7teI2V6A,8185
|
|
600
601
|
roboticstoolbox/tools/types.py,sha256=d9Oqs44fio7vI4myf4s4tqgoX83YDLqU_LOH7T4E6FM,231
|
|
601
602
|
roboticstoolbox/tools/urdf/__init__.py,sha256=tlo9oTXh3evQweOP3Hch-u3GiL_2NWavWHDBnk7BfKY,693
|
|
602
603
|
roboticstoolbox/tools/urdf/tests/data/ur5.urdf,sha256=9g0uYkRHRsWHWl6vn5lIK_JMHqhaUOi4HaBanuXco4A,11927
|
|
603
604
|
roboticstoolbox/tools/urdf/tests/test_urdf.py,sha256=MoRP8DolFu7RXxrKkwEWJOSfVygX7UJwEv-hLZkdlKw,3445
|
|
604
605
|
roboticstoolbox/tools/urdf/urdf.py,sha256=IE5EUSNjkOAZZUOkuhXKDhYRq2AuJGulIvfbsRHy7pI,58743
|
|
605
606
|
roboticstoolbox/tools/urdf/utils.py,sha256=6g1uuI2u7CUaWhKavI7wDHT3a2T3ijb92JByQ1lNq6w,1483
|
|
606
|
-
roboticstoolbox_python-1.4.
|
|
607
|
-
roboticstoolbox_python-1.4.
|
|
608
|
-
roboticstoolbox_python-1.4.
|
|
609
|
-
roboticstoolbox_python-1.4.
|
|
610
|
-
roboticstoolbox_python-1.4.
|
|
607
|
+
roboticstoolbox_python-1.4.1.dist-info/METADATA,sha256=77rLsFDnkDFxePDwO-G0X0KaUElESjFTeSYCTEObUy0,30215
|
|
608
|
+
roboticstoolbox_python-1.4.1.dist-info/WHEEL,sha256=DJBbB-IMWy7eyPvSdm5L2t-BbrULtweJWf0YC-blkl0,95
|
|
609
|
+
roboticstoolbox_python-1.4.1.dist-info/entry_points.txt,sha256=m9xEI6rJsYQL0HosyeS-4TUPzxOR3kqx4vbJVVxwo7k,214
|
|
610
|
+
roboticstoolbox_python-1.4.1.dist-info/licenses/LICENSE,sha256=oXNGHTPcMKl8PPZWk_4NIWGAtiaQcTgVJ1hpnTcnKFA,1062
|
|
611
|
+
roboticstoolbox_python-1.4.1.dist-info/RECORD,,
|
|
File without changes
|
{roboticstoolbox_python-1.4.0.dist-info → roboticstoolbox_python-1.4.1.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{roboticstoolbox_python-1.4.0.dist-info → roboticstoolbox_python-1.4.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|