jaxsim 0.2.1.dev20__py3-none-any.whl → 0.2.1.dev38__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.
- jaxsim/_version.py +2 -2
- jaxsim/api/model.py +38 -11
- jaxsim/math/joint_model.py +11 -62
- jaxsim/parsers/descriptions/joint.py +30 -47
- jaxsim/parsers/descriptions/model.py +14 -6
- jaxsim/parsers/kinematic_graph.py +245 -78
- jaxsim/parsers/rod/parser.py +2 -2
- jaxsim/parsers/rod/utils.py +17 -32
- jaxsim/utils/jaxsim_dataclass.py +4 -2
- {jaxsim-0.2.1.dev20.dist-info → jaxsim-0.2.1.dev38.dist-info}/METADATA +3 -3
- {jaxsim-0.2.1.dev20.dist-info → jaxsim-0.2.1.dev38.dist-info}/RECORD +14 -14
- {jaxsim-0.2.1.dev20.dist-info → jaxsim-0.2.1.dev38.dist-info}/LICENSE +0 -0
- {jaxsim-0.2.1.dev20.dist-info → jaxsim-0.2.1.dev38.dist-info}/WHEEL +0 -0
- {jaxsim-0.2.1.dev20.dist-info → jaxsim-0.2.1.dev38.dist-info}/top_level.txt +0 -0
jaxsim/_version.py
CHANGED
@@ -12,5 +12,5 @@ __version__: str
|
|
12
12
|
__version_tuple__: VERSION_TUPLE
|
13
13
|
version_tuple: VERSION_TUPLE
|
14
14
|
|
15
|
-
__version__ = version = '0.2.1.
|
16
|
-
__version_tuple__ = version_tuple = (0, 2, 1, '
|
15
|
+
__version__ = version = '0.2.1.dev38'
|
16
|
+
__version_tuple__ = version_tuple = (0, 2, 1, 'dev38')
|
jaxsim/api/model.py
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import copy
|
3
4
|
import dataclasses
|
4
5
|
import functools
|
5
6
|
import pathlib
|
6
|
-
from typing import Any
|
7
|
+
from typing import Any, Sequence
|
7
8
|
|
8
9
|
import jax
|
9
10
|
import jax.numpy as jnp
|
@@ -55,7 +56,7 @@ class JaxSimModel(JaxsimDataclass):
|
|
55
56
|
*,
|
56
57
|
terrain: jaxsim.terrain.Terrain | None = None,
|
57
58
|
is_urdf: bool | None = None,
|
58
|
-
considered_joints:
|
59
|
+
considered_joints: Sequence[str] | None = None,
|
59
60
|
) -> JaxSimModel:
|
60
61
|
"""
|
61
62
|
Build a Model object from a model description.
|
@@ -257,24 +258,50 @@ class JaxSimModel(JaxsimDataclass):
|
|
257
258
|
# =====================
|
258
259
|
|
259
260
|
|
260
|
-
def reduce(
|
261
|
+
def reduce(
|
262
|
+
model: JaxSimModel,
|
263
|
+
considered_joints: tuple[str, ...],
|
264
|
+
locked_joint_positions: dict[str, jtp.Float] | None = None,
|
265
|
+
) -> JaxSimModel:
|
261
266
|
"""
|
262
267
|
Reduce the model by lumping together the links connected by removed joints.
|
263
268
|
|
264
269
|
Args:
|
265
270
|
model: The model to reduce.
|
266
271
|
considered_joints: The sequence of joints to consider.
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
+
locked_joint_positions:
|
273
|
+
A dictionary containing the positions of the joints to be considered
|
274
|
+
in the reduction process. The removed joints in the reduced model
|
275
|
+
will have their position locked to their value in this dictionary.
|
276
|
+
If a joint is not part of the dictionary, its position is set to zero.
|
272
277
|
"""
|
273
278
|
|
279
|
+
locked_joint_positions = (
|
280
|
+
locked_joint_positions if locked_joint_positions is not None else {}
|
281
|
+
)
|
282
|
+
|
283
|
+
# If locked joints are passed, make sure that they are valid.
|
284
|
+
if not set(locked_joint_positions).issubset(model.joint_names()):
|
285
|
+
new_joints = set(model.joint_names()) - set(locked_joint_positions)
|
286
|
+
raise ValueError(f"Passed joints not existing in the model: {new_joints}")
|
287
|
+
|
288
|
+
# Copy the model description with a deep copy of the joints.
|
289
|
+
intermediate_description = dataclasses.replace(
|
290
|
+
model.description.get(), joints=copy.deepcopy(model.description.get().joints)
|
291
|
+
)
|
292
|
+
|
293
|
+
# Update the initial position of the joints.
|
294
|
+
# This is necessary to compute the correct pose of the link pairs connected
|
295
|
+
# to removed joints.
|
296
|
+
for joint_name in set(model.joint_names()) - set(considered_joints):
|
297
|
+
j = intermediate_description.joints_dict[joint_name]
|
298
|
+
with j.mutable_context():
|
299
|
+
j.initial_position = float(locked_joint_positions.get(joint_name, 0.0))
|
300
|
+
|
274
301
|
# Reduce the model description.
|
275
|
-
# If considered_joints contains joints not existing in the model,
|
276
|
-
# will raise an exception.
|
277
|
-
reduced_intermediate_description =
|
302
|
+
# If `considered_joints` contains joints not existing in the model,
|
303
|
+
# the method will raise an exception.
|
304
|
+
reduced_intermediate_description = intermediate_description.reduce(
|
278
305
|
considered_joints=list(considered_joints)
|
279
306
|
)
|
280
307
|
|
jaxsim/math/joint_model.py
CHANGED
@@ -15,6 +15,7 @@ from jaxsim.parsers.descriptions import (
|
|
15
15
|
JointType,
|
16
16
|
ModelDescription,
|
17
17
|
)
|
18
|
+
from jaxsim.parsers.kinematic_graph import KinematicGraphTransforms
|
18
19
|
|
19
20
|
from .rotation import Rotation
|
20
21
|
|
@@ -87,21 +88,19 @@ class JointModel:
|
|
87
88
|
# w.r.t. the implicit __model__ SDF frame is not the identity).
|
88
89
|
suc_H_i = suc_H_i.at[0].set(ordered_links[0].pose)
|
89
90
|
|
91
|
+
# Create the object to compute forward kinematics.
|
92
|
+
fk = KinematicGraphTransforms(graph=description)
|
93
|
+
|
90
94
|
# Compute the parent-to-predecessor and successor-to-child transforms for
|
91
95
|
# each joint belonging to the model.
|
92
96
|
# Note that the joint indices starts from i=1 given our joint model,
|
93
97
|
# therefore the entries at index 0 are not updated.
|
94
98
|
for joint in ordered_joints:
|
95
99
|
λ_H_pre = λ_H_pre.at[joint.index].set(
|
96
|
-
|
97
|
-
relative_to=joint.parent.name,
|
98
|
-
name=joint.name,
|
99
|
-
)
|
100
|
+
fk.relative_transform(relative_to=joint.parent.name, name=joint.name)
|
100
101
|
)
|
101
102
|
suc_H_i = suc_H_i.at[joint.index].set(
|
102
|
-
|
103
|
-
relative_to=joint.name, name=joint.child.name
|
104
|
-
)
|
103
|
+
fk.relative_transform(relative_to=joint.name, name=joint.child.name)
|
105
104
|
)
|
106
105
|
|
107
106
|
# Define the DoFs of the base link.
|
@@ -243,16 +242,16 @@ def supported_joint_motion(
|
|
243
242
|
"""
|
244
243
|
|
245
244
|
if isinstance(joint_type, JointType):
|
246
|
-
|
245
|
+
type_enum = joint_type
|
247
246
|
elif isinstance(joint_type, JointDescriptor):
|
248
|
-
|
247
|
+
type_enum = joint_type.joint_type
|
249
248
|
else:
|
250
249
|
raise ValueError(joint_type)
|
251
250
|
|
252
251
|
# Prepare the joint position
|
253
252
|
s = jnp.array(joint_position).astype(float)
|
254
253
|
|
255
|
-
match
|
254
|
+
match type_enum:
|
256
255
|
|
257
256
|
case JointType.R:
|
258
257
|
joint_type: JointGenericAxis
|
@@ -276,58 +275,8 @@ def supported_joint_motion(
|
|
276
275
|
S = jnp.vstack(jnp.hstack([joint_type.axis.squeeze(), jnp.zeros(3)]))
|
277
276
|
|
278
277
|
case JointType.F:
|
279
|
-
|
280
|
-
|
281
|
-
case JointType.Rx:
|
282
|
-
|
283
|
-
pre_H_suc = jaxlie.SE3.from_rotation(
|
284
|
-
rotation=jaxlie.SO3.from_x_radians(theta=s)
|
285
|
-
)
|
286
|
-
|
287
|
-
S = jnp.vstack([0, 0, 0, 1.0, 0, 0])
|
288
|
-
|
289
|
-
case JointType.Ry:
|
290
|
-
|
291
|
-
pre_H_suc = jaxlie.SE3.from_rotation(
|
292
|
-
rotation=jaxlie.SO3.from_y_radians(theta=s)
|
293
|
-
)
|
294
|
-
|
295
|
-
S = jnp.vstack([0, 0, 0, 0, 1.0, 0])
|
296
|
-
|
297
|
-
case JointType.Rz:
|
298
|
-
|
299
|
-
pre_H_suc = jaxlie.SE3.from_rotation(
|
300
|
-
rotation=jaxlie.SO3.from_z_radians(theta=s)
|
301
|
-
)
|
302
|
-
|
303
|
-
S = jnp.vstack([0, 0, 0, 0, 0, 1.0])
|
304
|
-
|
305
|
-
case JointType.Px:
|
306
|
-
|
307
|
-
pre_H_suc = jaxlie.SE3.from_rotation_and_translation(
|
308
|
-
rotation=jaxlie.SO3.identity(),
|
309
|
-
translation=jnp.array([s, 0.0, 0.0]),
|
310
|
-
)
|
311
|
-
|
312
|
-
S = jnp.vstack([1.0, 0, 0, 0, 0, 0])
|
313
|
-
|
314
|
-
case JointType.Py:
|
315
|
-
|
316
|
-
pre_H_suc = jaxlie.SE3.from_rotation_and_translation(
|
317
|
-
rotation=jaxlie.SO3.identity(),
|
318
|
-
translation=jnp.array([0.0, s, 0.0]),
|
319
|
-
)
|
320
|
-
|
321
|
-
S = jnp.vstack([0, 1.0, 0, 0, 0, 0])
|
322
|
-
|
323
|
-
case JointType.Pz:
|
324
|
-
|
325
|
-
pre_H_suc = jaxlie.SE3.from_rotation_and_translation(
|
326
|
-
rotation=jaxlie.SO3.identity(),
|
327
|
-
translation=jnp.array([0.0, 0.0, s]),
|
328
|
-
)
|
329
|
-
|
330
|
-
S = jnp.vstack([0, 0, 1.0, 0, 0, 0])
|
278
|
+
pre_H_suc = jaxlie.SE3.identity()
|
279
|
+
S = jnp.zeros(shape=(6, 1))
|
331
280
|
|
332
281
|
case _:
|
333
282
|
raise ValueError(joint_type)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import dataclasses
|
2
4
|
import enum
|
3
5
|
from typing import Tuple, Union
|
@@ -6,79 +8,60 @@ import jax_dataclasses
|
|
6
8
|
import numpy as np
|
7
9
|
import numpy.typing as npt
|
8
10
|
|
11
|
+
import jaxsim.typing as jtp
|
9
12
|
from jaxsim.utils import JaxsimDataclass, Mutability
|
10
13
|
|
11
14
|
from .link import LinkDescription
|
12
15
|
|
13
16
|
|
17
|
+
@enum.unique
|
14
18
|
class JointType(enum.IntEnum):
|
15
19
|
"""
|
16
|
-
|
17
|
-
|
18
|
-
Args:
|
19
|
-
F: Fixed joint (no movement).
|
20
|
-
R: Revolute joint (rotation).
|
21
|
-
P: Prismatic joint (translation).
|
22
|
-
Rx: Revolute joint with rotation about the X-axis.
|
23
|
-
Ry: Revolute joint with rotation about the Y-axis.
|
24
|
-
Rz: Revolute joint with rotation about the Z-axis.
|
25
|
-
Px: Prismatic joint with translation along the X-axis.
|
26
|
-
Py: Prismatic joint with translation along the Y-axis.
|
27
|
-
Pz: Prismatic joint with translation along the Z-axis.
|
20
|
+
Type of supported joints.
|
28
21
|
"""
|
29
22
|
|
30
|
-
|
31
|
-
|
32
|
-
|
23
|
+
@staticmethod
|
24
|
+
def _generate_next_value_(name, start, count, last_values):
|
25
|
+
# Start auto Enum value from 0 instead of 1
|
26
|
+
return count
|
27
|
+
|
28
|
+
#: Fixed joint.
|
29
|
+
F = enum.auto()
|
33
30
|
|
34
|
-
|
35
|
-
|
36
|
-
Ry = enum.auto()
|
37
|
-
Rz = enum.auto()
|
31
|
+
#: Revolute joint (1 DoF around axis).
|
32
|
+
R = enum.auto()
|
38
33
|
|
39
|
-
|
40
|
-
|
41
|
-
Py = enum.auto()
|
42
|
-
Pz = enum.auto()
|
34
|
+
#: Prismatic joint (1 DoF along axis).
|
35
|
+
P = enum.auto()
|
43
36
|
|
44
37
|
|
45
|
-
@
|
38
|
+
@jax_dataclasses.pytree_dataclass
|
46
39
|
class JointDescriptor:
|
47
40
|
"""
|
48
|
-
|
49
|
-
|
50
|
-
Args:
|
51
|
-
code (JointType): The code representing the joint type.
|
52
|
-
|
41
|
+
Base class for joint types requiring to store additional metadata.
|
53
42
|
"""
|
54
43
|
|
55
|
-
|
44
|
+
#: The joint type.
|
45
|
+
joint_type: JointType
|
56
46
|
|
57
|
-
def __hash__(self) -> int:
|
58
|
-
return hash(self.__repr__())
|
59
47
|
|
60
|
-
|
61
|
-
@dataclasses.dataclass
|
48
|
+
@jax_dataclasses.pytree_dataclass
|
62
49
|
class JointGenericAxis(JointDescriptor):
|
63
50
|
"""
|
64
|
-
|
65
|
-
|
66
|
-
Attributes:
|
67
|
-
axis (npt.NDArray): The axis of rotation or translation for the joint.
|
68
|
-
|
51
|
+
A joint requiring the specification of a 3D axis.
|
69
52
|
"""
|
70
53
|
|
71
|
-
axis
|
54
|
+
#: The axis of rotation or translation of the joint (must have norm 1).
|
55
|
+
axis: jtp.Vector
|
72
56
|
|
73
|
-
def
|
74
|
-
|
75
|
-
raise ValueError(self.axis)
|
57
|
+
def __hash__(self) -> int:
|
58
|
+
return hash((self.joint_type, tuple(np.array(self.axis).tolist())))
|
76
59
|
|
77
|
-
def __eq__(self, other):
|
78
|
-
|
60
|
+
def __eq__(self, other: JointGenericAxis) -> bool:
|
61
|
+
if not isinstance(other, JointGenericAxis):
|
62
|
+
return False
|
79
63
|
|
80
|
-
|
81
|
-
return hash(self.__repr__())
|
64
|
+
return hash(self) == hash(other)
|
82
65
|
|
83
66
|
|
84
67
|
@jax_dataclasses.pytree_dataclass
|
@@ -4,7 +4,7 @@ from typing import List
|
|
4
4
|
|
5
5
|
from jaxsim import logging
|
6
6
|
|
7
|
-
from ..kinematic_graph import KinematicGraph, RootPose
|
7
|
+
from ..kinematic_graph import KinematicGraph, KinematicGraphTransforms, RootPose
|
8
8
|
from .collision import CollidablePoint, CollisionShape
|
9
9
|
from .joint import JointDescription
|
10
10
|
from .link import LinkDescription
|
@@ -75,6 +75,9 @@ class ModelDescription(KinematicGraph):
|
|
75
75
|
considered_joints=considered_joints
|
76
76
|
)
|
77
77
|
|
78
|
+
# Create the object to compute forward kinematics.
|
79
|
+
fk = KinematicGraphTransforms(graph=kinematic_graph)
|
80
|
+
|
78
81
|
# Store here the final model collisions
|
79
82
|
final_collisions: List[CollisionShape] = []
|
80
83
|
|
@@ -121,7 +124,7 @@ class ModelDescription(KinematicGraph):
|
|
121
124
|
# relative pose
|
122
125
|
moved_cp = cp.change_link(
|
123
126
|
new_link=real_parent_link_of_shape,
|
124
|
-
new_H_old=
|
127
|
+
new_H_old=fk.relative_transform(
|
125
128
|
relative_to=real_parent_link_of_shape.name,
|
126
129
|
name=cp.parent_link.name,
|
127
130
|
),
|
@@ -139,7 +142,9 @@ class ModelDescription(KinematicGraph):
|
|
139
142
|
root=kinematic_graph.root,
|
140
143
|
joints=kinematic_graph.joints,
|
141
144
|
frames=kinematic_graph.frames,
|
145
|
+
_joints_removed=kinematic_graph._joints_removed,
|
142
146
|
)
|
147
|
+
|
143
148
|
assert kinematic_graph.root.name == base_link_name, kinematic_graph.root.name
|
144
149
|
|
145
150
|
return model
|
@@ -158,15 +163,12 @@ class ModelDescription(KinematicGraph):
|
|
158
163
|
ValueError: If the specified joints are not part of the model.
|
159
164
|
"""
|
160
165
|
|
161
|
-
msg = "The model reduction logic assumes that removed joints have zero angles"
|
162
|
-
logging.info(msg=msg)
|
163
|
-
|
164
166
|
if len(set(considered_joints) - set(self.joint_names())) != 0:
|
165
167
|
extra_joints = set(considered_joints) - set(self.joint_names())
|
166
168
|
msg = f"Found joints not part of the model: {extra_joints}"
|
167
169
|
raise ValueError(msg)
|
168
170
|
|
169
|
-
|
171
|
+
reduced_model_description = ModelDescription.build_model_from(
|
170
172
|
name=self.name,
|
171
173
|
links=list(self.links_dict.values()),
|
172
174
|
joints=self.joints,
|
@@ -177,6 +179,12 @@ class ModelDescription(KinematicGraph):
|
|
177
179
|
considered_joints=considered_joints,
|
178
180
|
)
|
179
181
|
|
182
|
+
# Include the unconnected/removed joints from the original model.
|
183
|
+
for joint in self._joints_removed:
|
184
|
+
reduced_model_description._joints_removed.append(joint)
|
185
|
+
|
186
|
+
return reduced_model_description
|
187
|
+
|
180
188
|
def update_collision_shape_of_link(self, link_name: str, enabled: bool) -> None:
|
181
189
|
"""
|
182
190
|
Enable or disable collision shapes associated with a link.
|
@@ -1,3 +1,5 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import copy
|
2
4
|
import dataclasses
|
3
5
|
import functools
|
@@ -9,6 +11,7 @@ from typing import (
|
|
9
11
|
List,
|
10
12
|
NamedTuple,
|
11
13
|
Optional,
|
14
|
+
Sequence,
|
12
15
|
Tuple,
|
13
16
|
Union,
|
14
17
|
)
|
@@ -41,7 +44,7 @@ class RootPose(NamedTuple):
|
|
41
44
|
|
42
45
|
|
43
46
|
@dataclasses.dataclass(frozen=True)
|
44
|
-
class KinematicGraph:
|
47
|
+
class KinematicGraph(Sequence[descriptions.LinkDescription]):
|
45
48
|
"""
|
46
49
|
Represents a kinematic graph of links and joints.
|
47
50
|
|
@@ -76,6 +79,12 @@ class KinematicGraph:
|
|
76
79
|
repr=False, compare=False, default_factory=dict
|
77
80
|
)
|
78
81
|
|
82
|
+
# Private attribute storing the unconnected joints from the parsed model and
|
83
|
+
# the joints removed after model reduction.
|
84
|
+
_joints_removed: list[descriptions.JointDescription] = dataclasses.field(
|
85
|
+
default_factory=list, repr=False, compare=False
|
86
|
+
)
|
87
|
+
|
79
88
|
@functools.cached_property
|
80
89
|
def links_dict(self) -> Dict[str, descriptions.LinkDescription]:
|
81
90
|
return {l.name: l for l in iter(self)}
|
@@ -153,15 +162,24 @@ class KinematicGraph:
|
|
153
162
|
# Couple links and joints and create the graph of links.
|
154
163
|
# Note that the pose of the frames is not updated; it's the caller's
|
155
164
|
# responsibility to update their pose if they want to use them.
|
156
|
-
graph_root_node, graph_joints, graph_frames =
|
157
|
-
|
165
|
+
graph_root_node, graph_joints, graph_frames, unconnected_joints = (
|
166
|
+
KinematicGraph.create_graph(
|
167
|
+
links=links, joints=joints, root_link_name=root_link_name
|
168
|
+
)
|
158
169
|
)
|
159
170
|
|
160
171
|
for frame in graph_frames:
|
161
172
|
logging.warning(msg=f"Ignoring unconnected link / frame: '{frame.name}'")
|
162
173
|
|
174
|
+
for joint in unconnected_joints:
|
175
|
+
logging.warning(msg=f"Ignoring unconnected joint: '{joint.name}'")
|
176
|
+
|
163
177
|
return KinematicGraph(
|
164
|
-
root=graph_root_node,
|
178
|
+
root=graph_root_node,
|
179
|
+
joints=graph_joints,
|
180
|
+
frames=[],
|
181
|
+
root_pose=root_pose,
|
182
|
+
_joints_removed=unconnected_joints,
|
165
183
|
)
|
166
184
|
|
167
185
|
@staticmethod
|
@@ -173,9 +191,10 @@ class KinematicGraph:
|
|
173
191
|
descriptions.LinkDescription,
|
174
192
|
List[descriptions.JointDescription],
|
175
193
|
List[descriptions.LinkDescription],
|
194
|
+
list[descriptions.JointDescription],
|
176
195
|
]:
|
177
196
|
"""
|
178
|
-
Create a kinematic graph from lists of links and joints.
|
197
|
+
Create a kinematic graph from the lists of parsed links and joints.
|
179
198
|
|
180
199
|
Args:
|
181
200
|
links (List[descriptions.LinkDescription]): A list of link descriptions.
|
@@ -183,8 +202,9 @@ class KinematicGraph:
|
|
183
202
|
root_link_name (str): The name of the root link.
|
184
203
|
|
185
204
|
Returns:
|
186
|
-
|
187
|
-
|
205
|
+
A tuple containing the root node with the full kinematic graph as child nodes,
|
206
|
+
the list of joints associated to graph nodes, the list of frames rigidly
|
207
|
+
attached to graph nodes, and the list of joints not part of the graph.
|
188
208
|
"""
|
189
209
|
|
190
210
|
# Create a dict that maps link name to the link, for easy retrieval
|
@@ -246,18 +266,25 @@ class KinematicGraph:
|
|
246
266
|
links_dict[root_link_name].mutable(mutable=False),
|
247
267
|
list(set(joints) - set(removed_joints)),
|
248
268
|
frames,
|
269
|
+
list(set(removed_joints)),
|
249
270
|
)
|
250
271
|
|
251
|
-
def reduce(self, considered_joints: List[str]) ->
|
272
|
+
def reduce(self, considered_joints: List[str]) -> KinematicGraph:
|
252
273
|
"""
|
253
|
-
Reduce the kinematic graph by removing
|
274
|
+
Reduce the kinematic graph by removing unspecified joints.
|
275
|
+
|
276
|
+
When a joint is removed, the mass and inertia of its child link are lumped
|
277
|
+
with those of its parent link, obtaining a new link that combines the two.
|
278
|
+
The description of the removed joint specifies the default angle (usually 0)
|
279
|
+
that is considered when the joint is removed.
|
254
280
|
|
255
281
|
Args:
|
256
|
-
considered_joints
|
282
|
+
considered_joints: A list of joint names to consider.
|
257
283
|
|
258
284
|
Returns:
|
259
|
-
|
285
|
+
The reduced kinematic graph.
|
260
286
|
"""
|
287
|
+
|
261
288
|
# The current object represents the complete kinematic graph
|
262
289
|
full_graph = self
|
263
290
|
|
@@ -281,6 +308,9 @@ class KinematicGraph:
|
|
281
308
|
links_dict = copy.deepcopy(full_graph.links_dict)
|
282
309
|
joints_dict = copy.deepcopy(full_graph.joints_dict)
|
283
310
|
|
311
|
+
# Create the object to compute forward kinematics.
|
312
|
+
fk = KinematicGraphTransforms(graph=full_graph)
|
313
|
+
|
284
314
|
# The following steps are implemented below in order to create the reduced graph:
|
285
315
|
#
|
286
316
|
# 1. Lump the mass of the removed links into their parent
|
@@ -329,7 +359,7 @@ class KinematicGraph:
|
|
329
359
|
# Lump the link
|
330
360
|
lumped_link = parent_of_link_to_remove.lump_with(
|
331
361
|
link=link_to_remove,
|
332
|
-
lumped_H_removed=
|
362
|
+
lumped_H_removed=fk.relative_transform(
|
333
363
|
relative_to=parent_of_link_to_remove.name, name=link_to_remove.name
|
334
364
|
),
|
335
365
|
)
|
@@ -370,7 +400,7 @@ class KinematicGraph:
|
|
370
400
|
# Update the pose. Note that after the lumping process, the dict entry
|
371
401
|
# links_dict[joint.parent.name] contains the final lumped link
|
372
402
|
with joint.mutable_context(mutability=Mutability.MUTABLE):
|
373
|
-
joint.pose =
|
403
|
+
joint.pose = fk.relative_transform(
|
374
404
|
relative_to=links_dict[joint.parent.name].name, name=joint.name
|
375
405
|
)
|
376
406
|
with joint.mutable_context(mutability=Mutability.MUTABLE_NO_VALIDATION):
|
@@ -396,18 +426,25 @@ class KinematicGraph:
|
|
396
426
|
|
397
427
|
# Create the reduced graph data. We pass the full list of links so that those
|
398
428
|
# that are not part of the graph will be returned as frames.
|
399
|
-
reduced_root_node, reduced_joints, reduced_frames =
|
400
|
-
|
401
|
-
|
402
|
-
|
429
|
+
reduced_root_node, reduced_joints, reduced_frames, unconnected_joints = (
|
430
|
+
KinematicGraph.create_graph(
|
431
|
+
links=list(full_graph_links_dict.values()),
|
432
|
+
joints=[joints_dict[joint_name] for joint_name in considered_joints],
|
433
|
+
root_link_name=full_graph.root.name,
|
434
|
+
)
|
403
435
|
)
|
404
436
|
|
405
437
|
# Create the reduced graph
|
406
438
|
reduced_graph = KinematicGraph(
|
407
439
|
root=reduced_root_node,
|
408
440
|
joints=reduced_joints,
|
409
|
-
frames=reduced_frames,
|
441
|
+
frames=self.frames + reduced_frames,
|
410
442
|
root_pose=full_graph.root_pose,
|
443
|
+
_joints_removed=(
|
444
|
+
self._joints_removed
|
445
|
+
+ unconnected_joints
|
446
|
+
+ [joints_dict[name] for name in joint_names_to_remove]
|
447
|
+
),
|
411
448
|
)
|
412
449
|
|
413
450
|
# ================================================================
|
@@ -424,7 +461,7 @@ class KinematicGraph:
|
|
424
461
|
|
425
462
|
# Update the connection of the frame
|
426
463
|
frame.parent = new_parent_link
|
427
|
-
frame.pose =
|
464
|
+
frame.pose = fk.relative_transform(
|
428
465
|
relative_to=new_parent_link.name, name=frame.name
|
429
466
|
)
|
430
467
|
|
@@ -462,65 +499,6 @@ class KinematicGraph:
|
|
462
499
|
"""
|
463
500
|
return list(self.frames_dict.keys())
|
464
501
|
|
465
|
-
def transform(self, name: str) -> npt.NDArray:
|
466
|
-
"""
|
467
|
-
Compute the transformation matrix for a given link, joint, or frame.
|
468
|
-
|
469
|
-
Args:
|
470
|
-
name (str): The name of the link, joint, or frame.
|
471
|
-
|
472
|
-
Returns:
|
473
|
-
npt.NDArray: The transformation matrix.
|
474
|
-
"""
|
475
|
-
if name in self.transform_cache:
|
476
|
-
return self.transform_cache[name]
|
477
|
-
|
478
|
-
if name in self.joint_names():
|
479
|
-
joint = self.joints_dict[name]
|
480
|
-
|
481
|
-
if joint.initial_position != 0.0:
|
482
|
-
msg = f"Ignoring unsupported initial position of joint '{name}'"
|
483
|
-
logging.warning(msg=msg)
|
484
|
-
|
485
|
-
transform = self.transform(name=joint.parent.name) @ joint.pose
|
486
|
-
self.transform_cache[name] = transform
|
487
|
-
return self.transform_cache[name]
|
488
|
-
|
489
|
-
if name in self.link_names():
|
490
|
-
link = self.links_dict[name]
|
491
|
-
|
492
|
-
if link.name == self.root.name:
|
493
|
-
return link.pose
|
494
|
-
|
495
|
-
parent_joint = self.joints_connection_dict[(link.parent.name, link.name)]
|
496
|
-
transform = self.transform(name=parent_joint.name) @ link.pose
|
497
|
-
self.transform_cache[name] = transform
|
498
|
-
return self.transform_cache[name]
|
499
|
-
|
500
|
-
# It can only be a plain frame
|
501
|
-
if name not in self.frame_names():
|
502
|
-
raise ValueError(name)
|
503
|
-
|
504
|
-
frame = self.frames_dict[name]
|
505
|
-
transform = self.transform(name=frame.parent.name) @ frame.pose
|
506
|
-
self.transform_cache[name] = transform
|
507
|
-
return self.transform_cache[name]
|
508
|
-
|
509
|
-
def relative_transform(self, relative_to: str, name: str) -> npt.NDArray:
|
510
|
-
"""
|
511
|
-
Compute the relative transformation matrix between two elements in the kinematic graph.
|
512
|
-
|
513
|
-
Args:
|
514
|
-
relative_to (str): The name of the reference element.
|
515
|
-
name (str): The name of the element to compute the relative transformation for.
|
516
|
-
|
517
|
-
Returns:
|
518
|
-
npt.NDArray: The relative transformation matrix.
|
519
|
-
"""
|
520
|
-
return np.linalg.inv(self.transform(name=relative_to)) @ self.transform(
|
521
|
-
name=name
|
522
|
-
)
|
523
|
-
|
524
502
|
def print_tree(self) -> None:
|
525
503
|
"""
|
526
504
|
Print the tree structure of the kinematic graph.
|
@@ -574,6 +552,10 @@ class KinematicGraph:
|
|
574
552
|
|
575
553
|
yield child
|
576
554
|
|
555
|
+
# =================
|
556
|
+
# Sequence protocol
|
557
|
+
# =================
|
558
|
+
|
577
559
|
def __iter__(self) -> Iterable[descriptions.LinkDescription]:
|
578
560
|
yield from KinematicGraph.breadth_first_search(root=self.root)
|
579
561
|
|
@@ -606,3 +588,188 @@ class KinematicGraph:
|
|
606
588
|
return list(iter(self))[key]
|
607
589
|
|
608
590
|
raise TypeError(type(key).__name__)
|
591
|
+
|
592
|
+
def count(self, value: descriptions.LinkDescription) -> int:
|
593
|
+
return list(iter(self)).count(value)
|
594
|
+
|
595
|
+
def index(
|
596
|
+
self, value: descriptions.LinkDescription, start: int = 0, stop: int = -1
|
597
|
+
) -> int:
|
598
|
+
return list(iter(self)).index(value, start, stop)
|
599
|
+
|
600
|
+
|
601
|
+
# ====================
|
602
|
+
# Other useful classes
|
603
|
+
# ====================
|
604
|
+
|
605
|
+
|
606
|
+
@dataclasses.dataclass(frozen=True)
|
607
|
+
class KinematicGraphTransforms:
|
608
|
+
|
609
|
+
graph: KinematicGraph
|
610
|
+
|
611
|
+
_transform_cache: dict[str, npt.NDArray] = dataclasses.field(
|
612
|
+
default_factory=dict, init=False, repr=False, compare=False
|
613
|
+
)
|
614
|
+
|
615
|
+
_initial_joint_positions: dict[str, float] = dataclasses.field(
|
616
|
+
init=False, repr=False, compare=False
|
617
|
+
)
|
618
|
+
|
619
|
+
def __post_init__(self) -> None:
|
620
|
+
|
621
|
+
super().__setattr__(
|
622
|
+
"_initial_joint_positions",
|
623
|
+
{joint.name: joint.initial_position for joint in self.graph.joints},
|
624
|
+
)
|
625
|
+
|
626
|
+
@property
|
627
|
+
def initial_joint_positions(self) -> npt.NDArray:
|
628
|
+
|
629
|
+
return np.atleast_1d(
|
630
|
+
np.array(list(self._initial_joint_positions.values()))
|
631
|
+
).astype(float)
|
632
|
+
|
633
|
+
@initial_joint_positions.setter
|
634
|
+
def initial_joint_positions(
|
635
|
+
self,
|
636
|
+
positions: npt.NDArray | Sequence,
|
637
|
+
joint_names: Sequence[str] | None = None,
|
638
|
+
) -> None:
|
639
|
+
|
640
|
+
joint_names = (
|
641
|
+
joint_names
|
642
|
+
if joint_names is not None
|
643
|
+
else list(self._initial_joint_positions.keys())
|
644
|
+
)
|
645
|
+
|
646
|
+
s = np.atleast_1d(np.array(positions).squeeze())
|
647
|
+
|
648
|
+
if s.size != len(joint_names):
|
649
|
+
raise ValueError(s.size, len(joint_names))
|
650
|
+
|
651
|
+
for joint_name in joint_names:
|
652
|
+
if joint_name not in self._initial_joint_positions:
|
653
|
+
raise ValueError(joint_name)
|
654
|
+
|
655
|
+
# Clear transform cache.
|
656
|
+
self._transform_cache.clear()
|
657
|
+
|
658
|
+
# Update initial joint positions.
|
659
|
+
for joint_name, position in zip(joint_names, s):
|
660
|
+
self._initial_joint_positions[joint_name] = position
|
661
|
+
|
662
|
+
def transform(self, name: str) -> npt.NDArray:
|
663
|
+
"""
|
664
|
+
Compute the SE(3) transform of elements belonging to the kinematic graph.
|
665
|
+
|
666
|
+
Args:
|
667
|
+
name: The name of a link, a joint, or a frame.
|
668
|
+
|
669
|
+
Returns:
|
670
|
+
The 4x4 transform matrix of the element w.r.t. the model frame.
|
671
|
+
"""
|
672
|
+
|
673
|
+
# If the transform was already computed, return it.
|
674
|
+
if name in self._transform_cache:
|
675
|
+
return self._transform_cache[name]
|
676
|
+
|
677
|
+
# If the name is a joint, compute M_H_J transform.
|
678
|
+
if name in self.graph.joint_names():
|
679
|
+
|
680
|
+
# Get the joint.
|
681
|
+
joint = self.graph.joints_dict[name]
|
682
|
+
|
683
|
+
# Get the transform of the parent link.
|
684
|
+
M_H_L = self.transform(name=joint.parent.name)
|
685
|
+
|
686
|
+
# Rename the pose of the predecessor joint frame w.r.t. its parent link.
|
687
|
+
L_H_pre = joint.pose
|
688
|
+
|
689
|
+
# Compute the joint transform from the predecessor to the successor frame.
|
690
|
+
pre_H_J = self.pre_H_suc(
|
691
|
+
joint_type=joint.jtype,
|
692
|
+
joint_position=self._initial_joint_positions[joint.name],
|
693
|
+
)
|
694
|
+
|
695
|
+
# Compute the M_H_J transform.
|
696
|
+
self._transform_cache[name] = M_H_L @ L_H_pre @ pre_H_J
|
697
|
+
return self._transform_cache[name]
|
698
|
+
|
699
|
+
# If the name is a link, compute M_H_L transform.
|
700
|
+
if name in self.graph.link_names():
|
701
|
+
|
702
|
+
# Get the link.
|
703
|
+
link = self.graph.links_dict[name]
|
704
|
+
|
705
|
+
# Handle the pose between the __model__ frame and the root link.
|
706
|
+
if link.name == self.graph.root.name:
|
707
|
+
M_H_B = link.pose
|
708
|
+
return M_H_B
|
709
|
+
|
710
|
+
# Get the joint between the link and its parent.
|
711
|
+
parent_joint = self.graph.joints_connection_dict[
|
712
|
+
(link.parent.name, link.name)
|
713
|
+
]
|
714
|
+
|
715
|
+
# Get the transform of the parent joint.
|
716
|
+
M_H_J = self.transform(name=parent_joint.name)
|
717
|
+
|
718
|
+
# Rename the pose of the link w.r.t. its parent joint.
|
719
|
+
J_H_L = link.pose
|
720
|
+
|
721
|
+
# Compute the M_H_L transform.
|
722
|
+
self._transform_cache[name] = M_H_J @ J_H_L
|
723
|
+
return self._transform_cache[name]
|
724
|
+
|
725
|
+
# It can only be a plain frame.
|
726
|
+
if name not in self.graph.frame_names():
|
727
|
+
raise ValueError(name)
|
728
|
+
|
729
|
+
# Get the frame.
|
730
|
+
frame = self.graph.frames_dict[name]
|
731
|
+
|
732
|
+
# Get the transform of the parent link.
|
733
|
+
M_H_L = self.transform(name=frame.parent.name)
|
734
|
+
|
735
|
+
# Rename the pose of the frame w.r.t. its parent link.
|
736
|
+
L_H_F = frame.pose
|
737
|
+
|
738
|
+
# Compute the M_H_F transform.
|
739
|
+
self._transform_cache[name] = M_H_L @ L_H_F
|
740
|
+
return self._transform_cache[name]
|
741
|
+
|
742
|
+
def relative_transform(self, relative_to: str, name: str) -> npt.NDArray:
|
743
|
+
"""
|
744
|
+
Compute the SE(3) relative transform of elements belonging to the kinematic graph.
|
745
|
+
|
746
|
+
Args:
|
747
|
+
relative_to: The name of the reference element.
|
748
|
+
name: The name of a link, a joint, or a frame.
|
749
|
+
|
750
|
+
Returns:
|
751
|
+
The 4x4 transform matrix of the element w.r.t. the desired frame.
|
752
|
+
"""
|
753
|
+
|
754
|
+
import jaxsim.math
|
755
|
+
|
756
|
+
M_H_target = self.transform(name=name)
|
757
|
+
M_H_R = self.transform(name=relative_to)
|
758
|
+
|
759
|
+
# Compute the relative transform R_H_target, where R is the reference frame,
|
760
|
+
# and i the frame of the desired link|joint|frame.
|
761
|
+
return np.array(jaxsim.math.Transform.inverse(M_H_R)) @ M_H_target
|
762
|
+
|
763
|
+
@staticmethod
|
764
|
+
def pre_H_suc(
|
765
|
+
joint_type: descriptions.JointType | descriptions.JointDescriptor,
|
766
|
+
joint_position: float | None = None,
|
767
|
+
) -> npt.NDArray:
|
768
|
+
|
769
|
+
import jaxsim.math
|
770
|
+
|
771
|
+
return np.array(
|
772
|
+
jaxsim.math.supported_joint_motion(
|
773
|
+
joint_type=joint_type, joint_position=joint_position
|
774
|
+
)[0]
|
775
|
+
)
|
jaxsim/parsers/rod/parser.py
CHANGED
@@ -134,7 +134,7 @@ def extract_model_data(
|
|
134
134
|
name=j.name,
|
135
135
|
parent=world_link,
|
136
136
|
child=links_dict[j.child],
|
137
|
-
jtype=utils.
|
137
|
+
jtype=utils.joint_to_joint_type(joint=j),
|
138
138
|
axis=(
|
139
139
|
np.array(j.axis.xyz.xyz)
|
140
140
|
if j.axis is not None
|
@@ -201,7 +201,7 @@ def extract_model_data(
|
|
201
201
|
name=j.name,
|
202
202
|
parent=links_dict[j.parent],
|
203
203
|
child=links_dict[j.child],
|
204
|
-
jtype=utils.
|
204
|
+
jtype=utils.joint_to_joint_type(joint=j),
|
205
205
|
axis=(
|
206
206
|
np.array(j.axis.xyz.xyz)
|
207
207
|
if j.axis is not None
|
jaxsim/parsers/rod/utils.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import os
|
2
|
-
from typing import Union
|
3
2
|
|
4
3
|
import jaxlie
|
5
4
|
import numpy as np
|
@@ -60,57 +59,43 @@ def from_sdf_inertial(inertial: rod.Inertial) -> jtp.Matrix:
|
|
60
59
|
return M_L.astype(dtype=float)
|
61
60
|
|
62
61
|
|
63
|
-
def
|
64
|
-
|
65
|
-
) ->
|
62
|
+
def joint_to_joint_type(
|
63
|
+
joint: rod.Joint,
|
64
|
+
) -> descriptions.JointType | descriptions.JointDescriptor:
|
66
65
|
"""
|
67
|
-
|
66
|
+
Extract the joint type from an SDF joint.
|
68
67
|
|
69
68
|
Args:
|
70
|
-
|
71
|
-
type: The SDF joint type.
|
69
|
+
joint: The parsed SDF joint.
|
72
70
|
|
73
71
|
Returns:
|
74
72
|
The corresponding joint type description.
|
75
73
|
"""
|
76
74
|
|
77
|
-
|
75
|
+
axis = joint.axis
|
76
|
+
joint_type = joint.type
|
77
|
+
|
78
|
+
if joint_type == "fixed":
|
78
79
|
return descriptions.JointType.F
|
79
80
|
|
80
81
|
if not (axis.xyz is not None and axis.xyz.xyz is not None):
|
81
82
|
raise ValueError("Failed to read axis xyz data")
|
82
83
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
return descriptions.JointType.Rx
|
87
|
-
|
88
|
-
if np.allclose(axis_xyz, [0, 1, 0]) and type in {"revolute", "continuous"}:
|
89
|
-
return descriptions.JointType.Ry
|
90
|
-
|
91
|
-
if np.allclose(axis_xyz, [0, 0, 1]) and type in {"revolute", "continuous"}:
|
92
|
-
return descriptions.JointType.Rz
|
93
|
-
|
94
|
-
if np.allclose(axis_xyz, [1, 0, 0]) and type == "prismatic":
|
95
|
-
return descriptions.JointType.Px
|
96
|
-
|
97
|
-
if np.allclose(axis_xyz, [0, 1, 0]) and type == "prismatic":
|
98
|
-
return descriptions.JointType.Py
|
99
|
-
|
100
|
-
if np.allclose(axis_xyz, [0, 0, 1]) and type == "prismatic":
|
101
|
-
return descriptions.JointType.Pz
|
84
|
+
# Make sure that the axis is a unary vector.
|
85
|
+
axis_xyz = np.array(axis.xyz.xyz).astype(float)
|
86
|
+
axis_xyz = axis_xyz / np.linalg.norm(axis_xyz)
|
102
87
|
|
103
|
-
if
|
88
|
+
if joint_type in {"revolute", "continuous"}:
|
104
89
|
return descriptions.JointGenericAxis(
|
105
|
-
|
90
|
+
joint_type=descriptions.JointType.R, axis=axis_xyz
|
106
91
|
)
|
107
92
|
|
108
|
-
if
|
93
|
+
if joint_type == "prismatic":
|
109
94
|
return descriptions.JointGenericAxis(
|
110
|
-
|
95
|
+
joint_type=descriptions.JointType.P, axis=axis_xyz
|
111
96
|
)
|
112
97
|
|
113
|
-
raise ValueError("Joint not supported", axis_xyz,
|
98
|
+
raise ValueError("Joint not supported", axis_xyz, joint_type)
|
114
99
|
|
115
100
|
|
116
101
|
def create_box_collision(
|
jaxsim/utils/jaxsim_dataclass.py
CHANGED
@@ -50,7 +50,9 @@ class JaxsimDataclass(abc.ABC):
|
|
50
50
|
|
51
51
|
@contextlib.contextmanager
|
52
52
|
def mutable_context(
|
53
|
-
self: Self,
|
53
|
+
self: Self,
|
54
|
+
mutability: Mutability = Mutability.MUTABLE,
|
55
|
+
restore_after_exception: bool = True,
|
54
56
|
) -> Iterator[Self]:
|
55
57
|
"""
|
56
58
|
Context manager to temporarily change the mutability of the object.
|
@@ -86,7 +88,7 @@ class JaxsimDataclass(abc.ABC):
|
|
86
88
|
setattr(self, f.name, getattr(self_copy, f.name))
|
87
89
|
|
88
90
|
try:
|
89
|
-
self.set_mutability(mutability)
|
91
|
+
self.set_mutability(mutability=mutability)
|
90
92
|
yield self
|
91
93
|
|
92
94
|
if mutability is not Mutability.MUTABLE_NO_VALIDATION:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: jaxsim
|
3
|
-
Version: 0.2.1.
|
3
|
+
Version: 0.2.1.dev38
|
4
4
|
Home-page: https://github.com/ami-iit/jaxsim
|
5
5
|
Author: Diego Ferigo
|
6
6
|
Author-email: diego.ferigo@iit.it
|
@@ -43,7 +43,7 @@ Provides-Extra: all
|
|
43
43
|
Requires-Dist: black[jupyter] ~=24.0 ; extra == 'all'
|
44
44
|
Requires-Dist: isort ; extra == 'all'
|
45
45
|
Requires-Dist: pre-commit ; extra == 'all'
|
46
|
-
Requires-Dist: idyntree ; extra == 'all'
|
46
|
+
Requires-Dist: idyntree >=12.2.1 ; extra == 'all'
|
47
47
|
Requires-Dist: pytest >=6.0 ; extra == 'all'
|
48
48
|
Requires-Dist: pytest-icdiff ; extra == 'all'
|
49
49
|
Requires-Dist: robot-descriptions ; extra == 'all'
|
@@ -55,7 +55,7 @@ Requires-Dist: black[jupyter] ~=24.0 ; extra == 'style'
|
|
55
55
|
Requires-Dist: isort ; extra == 'style'
|
56
56
|
Requires-Dist: pre-commit ; extra == 'style'
|
57
57
|
Provides-Extra: testing
|
58
|
-
Requires-Dist: idyntree ; extra == 'testing'
|
58
|
+
Requires-Dist: idyntree >=12.2.1 ; extra == 'testing'
|
59
59
|
Requires-Dist: pytest >=6.0 ; extra == 'testing'
|
60
60
|
Requires-Dist: pytest-icdiff ; extra == 'testing'
|
61
61
|
Requires-Dist: robot-descriptions ; extra == 'testing'
|
@@ -1,5 +1,5 @@
|
|
1
1
|
jaxsim/__init__.py,sha256=OcrfoYS1DGcmAGqu2AqlCTiUVxcpi-IsVwcr_16x74Q,1789
|
2
|
-
jaxsim/_version.py,sha256=
|
2
|
+
jaxsim/_version.py,sha256=Cl_kuTOEO0aVEiwkm9tH1bjrDIciBhU4mo1dsIZmCdM,426
|
3
3
|
jaxsim/logging.py,sha256=c4zhwBKf9eAYAHVp62kTEllqdsZgh0K-kPKVy8L3elU,1584
|
4
4
|
jaxsim/typing.py,sha256=MeuOCQtLAr-sPkvB_sU8FtwGNRirz1auCwIgRC-QZl8,646
|
5
5
|
jaxsim/api/__init__.py,sha256=fNTCPUeDfOAizRd4RsW3Epv0sLTu0KJGoFRSEsi75VM,162
|
@@ -10,7 +10,7 @@ jaxsim/api/data.py,sha256=GXSCfq4_PsRZuUwsmcl18e2Ppdtu4ykYs0oWih8J2ZI,26775
|
|
10
10
|
jaxsim/api/joint.py,sha256=q31Kp3Cqv-yTcxijjzbj_QADFnGQyjb2al9fYZtzedo,4763
|
11
11
|
jaxsim/api/kin_dyn_parameters.py,sha256=G4mtSi8fElYe0yttLgsxSOPf7vcK-yqTu06Aa5SSrYg,26012
|
12
12
|
jaxsim/api/link.py,sha256=rypTwkMf9HJ5UuAtHRJh0LqqdJWcLKTtTjWcjduEsF0,9842
|
13
|
-
jaxsim/api/model.py,sha256=
|
13
|
+
jaxsim/api/model.py,sha256=Ci7hl4M1gbnHNQAO5GLjxOdvJe8w3dhvGB_7x2gdpaU,53540
|
14
14
|
jaxsim/api/ode.py,sha256=6l-6i2YHagsQvR8Ac-_fmO6P0hBVT6NkHhwXnrdITEg,9785
|
15
15
|
jaxsim/api/ode_data.py,sha256=dwRFVPJ30XMmdUbPXEu7YxsQ97jZP4L4fd5ZzhrO5Ys,22184
|
16
16
|
jaxsim/api/references.py,sha256=Lvskf17r619KKxwCJP7hAAty2kaXgDXJX1uKqoDIDgo,15483
|
@@ -22,7 +22,7 @@ jaxsim/math/__init__.py,sha256=inJ9nRFkqstuGa8OyFkfWVudo5U9Ug4WgDBuKva8AIA,337
|
|
22
22
|
jaxsim/math/adjoint.py,sha256=DT21izjVW497GRrgNfx8tv0ZeWW5QncWMGMhI0acUNw,4425
|
23
23
|
jaxsim/math/cross.py,sha256=U7yEx_l75mSy5g6O-jsjBztApvxC3WaV4MpkS5tThu4,1330
|
24
24
|
jaxsim/math/inertia.py,sha256=UAB7ym4gXFanejcs_ovZMpteHCc6poWYmt-mLmd5hhk,1640
|
25
|
-
jaxsim/math/joint_model.py,sha256=
|
25
|
+
jaxsim/math/joint_model.py,sha256=LSZM94oLpdc0z8DJr9lrN10PHYyScjvMZ1BVORUMkhk,9618
|
26
26
|
jaxsim/math/quaternion.py,sha256=X9b8jHf0QemKUjIZSnXRJc3DdMr42CBhBy_mi9_X_AM,5068
|
27
27
|
jaxsim/math/rotation.py,sha256=Z90daUjGpuNEVLfWB3SVtM9EtwAIaneVj9A9UpWXqhA,2182
|
28
28
|
jaxsim/math/skew.py,sha256=oOGSSR8PUGROl6IJFlrmu6K3gPH-u16hUPfKIkcVv9o,1177
|
@@ -33,15 +33,15 @@ jaxsim/mujoco/loaders.py,sha256=-z6TIsems7DDogueDBwYLS2JuoWalNfv6sV1F45H63k,2102
|
|
33
33
|
jaxsim/mujoco/model.py,sha256=5-4KTbEbU19zjrSuvUVdLo3noWxTvlCNsFIs3rQTNDY,13506
|
34
34
|
jaxsim/mujoco/visualizer.py,sha256=YlteqcCbeB1B6saAHKBz1IJad3N5Rp163reZrzKLAys,5065
|
35
35
|
jaxsim/parsers/__init__.py,sha256=sonYi-bBWAoB04kp1mxT4uIORxjb7SdZ0ukGPmVx98Y,44
|
36
|
-
jaxsim/parsers/kinematic_graph.py,sha256=
|
36
|
+
jaxsim/parsers/kinematic_graph.py,sha256=pzjY-2O9QDY5wUXHAhuTyWHs1Te238gkzlHnyKeA5T0,28935
|
37
37
|
jaxsim/parsers/descriptions/__init__.py,sha256=EbTfnrK3oCxA3pNv--YUwllJ6uICENvFgAdRbYtS9ts,238
|
38
38
|
jaxsim/parsers/descriptions/collision.py,sha256=HUWwuRgI9KznY29FFw1_zU3bGigDEezrcPOJSxSJGNU,3382
|
39
|
-
jaxsim/parsers/descriptions/joint.py,sha256=
|
39
|
+
jaxsim/parsers/descriptions/joint.py,sha256=vozAx4sr3q-9IroN90iLP0BPpY_5BJ6VME3DKPrBIoY,3600
|
40
40
|
jaxsim/parsers/descriptions/link.py,sha256=hqLLitrAXnouia6ULk1BPOIEfRxrXwHmoPsi306IZW8,2859
|
41
|
-
jaxsim/parsers/descriptions/model.py,sha256=
|
41
|
+
jaxsim/parsers/descriptions/model.py,sha256=hapbpO1VpC7f5ELkGH1ZtM2I3dpmYLz8Em5cb3DdiaA,9264
|
42
42
|
jaxsim/parsers/rod/__init__.py,sha256=G2vqlLajBLUc4gyzXwsEI2Wsi4TMOIF9bLDFeT6KrGU,92
|
43
|
-
jaxsim/parsers/rod/parser.py,sha256=
|
44
|
-
jaxsim/parsers/rod/utils.py,sha256=
|
43
|
+
jaxsim/parsers/rod/parser.py,sha256=83s8Z33LSS1ddYjjm0lOqf_fQPBgeFnaayuMgc2KRXk,12533
|
44
|
+
jaxsim/parsers/rod/utils.py,sha256=SJg9t-nnItmo_gfxkfQ6uILNYN_BddcAHckyQkTDAjY,5902
|
45
45
|
jaxsim/rbda/__init__.py,sha256=HLwxeU-IxaRpFGUCSQv-LDv20JHTt3Xj7ELiRbRieS8,319
|
46
46
|
jaxsim/rbda/aba.py,sha256=0OoCzHhf1v-qqr1y5PIrD7_mPwAlid0fjXxUrIa5E_s,9118
|
47
47
|
jaxsim/rbda/collidable_points.py,sha256=4ZNJbEj2nEi15jBLR-GNbdaqKgkN58FBgqd_TXupEgg,4948
|
@@ -55,10 +55,10 @@ jaxsim/terrain/__init__.py,sha256=f7lVX-iNpH_wkkjef9Qpjh19TTAUOQw76EiLYJDVizc,78
|
|
55
55
|
jaxsim/terrain/terrain.py,sha256=q0xkWqEShVq-p1j2abTLZq8sEhjyJwquxQKm80PaHhM,2161
|
56
56
|
jaxsim/utils/__init__.py,sha256=tnQq1_CavdfeKaLYt3pmO7Jk4MU2RwwQU_qICkjyoTY,197
|
57
57
|
jaxsim/utils/hashless.py,sha256=bFIwKeo9KiWwsY8QM55duEGGQOyyJ4jQyPcuqTLEp5k,297
|
58
|
-
jaxsim/utils/jaxsim_dataclass.py,sha256=
|
58
|
+
jaxsim/utils/jaxsim_dataclass.py,sha256=h26timZ_XrBL_Q_oymv-DkQd-EcUiHn8QexAaZXBY9c,11396
|
59
59
|
jaxsim/utils/tracing.py,sha256=KDMoyVPlu2NJvFkhtZwq5AkqMMgajt3munvJom-vEjQ,650
|
60
|
-
jaxsim-0.2.1.
|
61
|
-
jaxsim-0.2.1.
|
62
|
-
jaxsim-0.2.1.
|
63
|
-
jaxsim-0.2.1.
|
64
|
-
jaxsim-0.2.1.
|
60
|
+
jaxsim-0.2.1.dev38.dist-info/LICENSE,sha256=eaYdFmdeMbiIoIiPzEK0MjP1S9wtFXjXNR5er49uLR0,1546
|
61
|
+
jaxsim-0.2.1.dev38.dist-info/METADATA,sha256=63Xh0podujOMHsBQHfMyNCFYIXQPovXz6I6oWQ-IGd4,9744
|
62
|
+
jaxsim-0.2.1.dev38.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
63
|
+
jaxsim-0.2.1.dev38.dist-info/top_level.txt,sha256=LxGMA8FLtXjQ6oI7N5gd_R_oSUHxpXxUEOfT1xS_ni0,7
|
64
|
+
jaxsim-0.2.1.dev38.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|