jaxsim 0.2.1.dev69__tar.gz → 0.2.1.dev70__tar.gz
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-0.2.1.dev69 → jaxsim-0.2.1.dev70}/.gitignore +1 -1
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/PKG-INFO +1 -1
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/modules/api.rst +5 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/_version.py +2 -2
- jaxsim-0.2.1.dev70/src/jaxsim/api/__init__.py +13 -0
- jaxsim-0.2.1.dev70/src/jaxsim/api/frame.py +221 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/api/model.py +10 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/parsers/descriptions/link.py +37 -29
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim.egg-info/PKG-INFO +1 -1
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim.egg-info/SOURCES.txt +2 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/tests/conftest.py +19 -7
- jaxsim-0.2.1.dev70/tests/test_api_frame.py +144 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/tests/test_api_joint.py +1 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/tests/test_api_link.py +1 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/tests/test_pytree.py +4 -2
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/tests/utils_idyntree.py +7 -0
- jaxsim-0.2.1.dev69/src/jaxsim/api/__init__.py +0 -3
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/.devcontainer/Dockerfile +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/.devcontainer/devcontainer.json +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/.gitattributes +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/.github/CODEOWNERS +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/.github/workflows/ci_cd.yml +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/.github/workflows/read_the_docs.yml +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/.github/workflows/style.yml +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/.pre-commit-config.yaml +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/.readthedocs.yaml +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/CONTRIBUTING.md +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/LICENSE +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/README.md +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/Makefile +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/conf.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/guide/install.rst +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/index.rst +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/make.bat +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/modules/index.rst +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/modules/integrators.rst +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/modules/math.rst +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/modules/mujoco.rst +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/modules/parsers.rst +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/modules/rbda.rst +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/modules/typing.rst +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/docs/modules/utils.rst +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/environment.yml +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/examples/.gitattributes +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/examples/.gitignore +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/examples/PD_controller.ipynb +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/examples/Parallel_computing.ipynb +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/examples/README.md +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/examples/assets/cartpole.urdf +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/pixi.lock +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/pyproject.toml +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/setup.cfg +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/setup.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/__init__.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/api/com.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/api/common.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/api/contact.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/api/data.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/api/joint.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/api/kin_dyn_parameters.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/api/link.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/api/ode.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/api/ode_data.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/api/references.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/integrators/__init__.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/integrators/common.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/integrators/fixed_step.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/integrators/variable_step.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/logging.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/math/__init__.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/math/adjoint.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/math/cross.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/math/inertia.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/math/joint_model.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/math/quaternion.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/math/rotation.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/math/skew.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/math/transform.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/mujoco/__init__.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/mujoco/__main__.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/mujoco/loaders.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/mujoco/model.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/mujoco/visualizer.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/parsers/__init__.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/parsers/descriptions/__init__.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/parsers/descriptions/collision.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/parsers/descriptions/joint.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/parsers/descriptions/model.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/parsers/kinematic_graph.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/parsers/rod/__init__.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/parsers/rod/parser.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/parsers/rod/utils.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/rbda/__init__.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/rbda/aba.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/rbda/collidable_points.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/rbda/crba.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/rbda/forward_kinematics.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/rbda/jacobian.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/rbda/rnea.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/rbda/soft_contacts.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/rbda/utils.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/terrain/__init__.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/terrain/terrain.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/typing.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/utils/__init__.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/utils/hashless.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/utils/jaxsim_dataclass.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim/utils/tracing.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim.egg-info/dependency_links.txt +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim.egg-info/not-zip-safe +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim.egg-info/requires.txt +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/src/jaxsim.egg-info/top_level.txt +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/tests/__init__.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/tests/test_api_com.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/tests/test_api_data.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/tests/test_api_model.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/tests/test_automatic_differentiation.py +0 -0
- {jaxsim-0.2.1.dev69 → jaxsim-0.2.1.dev70}/tests/test_simulations.py +0 -0
@@ -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.dev70'
|
16
|
+
__version_tuple__ = version_tuple = (0, 2, 1, 'dev70')
|
@@ -0,0 +1,221 @@
|
|
1
|
+
import functools
|
2
|
+
from typing import Sequence
|
3
|
+
|
4
|
+
import jax
|
5
|
+
import jax.numpy as jnp
|
6
|
+
import jaxlie
|
7
|
+
import numpy as np
|
8
|
+
|
9
|
+
import jaxsim.api as js
|
10
|
+
import jaxsim.math
|
11
|
+
import jaxsim.typing as jtp
|
12
|
+
|
13
|
+
from .common import VelRepr
|
14
|
+
|
15
|
+
# =======================
|
16
|
+
# Index-related functions
|
17
|
+
# =======================
|
18
|
+
|
19
|
+
|
20
|
+
def idx_of_parent_link(model: js.model.JaxSimModel, *, frame_idx: jtp.IntLike) -> int:
|
21
|
+
"""
|
22
|
+
Get the index of the link to which the frame is rigidly attached.
|
23
|
+
|
24
|
+
Args:
|
25
|
+
model: The model to consider.
|
26
|
+
frame_idx: The index of the frame.
|
27
|
+
|
28
|
+
Returns:
|
29
|
+
The index of the frame's parent link.
|
30
|
+
"""
|
31
|
+
|
32
|
+
# Get the intermediate representation parsed from the model description.
|
33
|
+
ir = model.description.get()
|
34
|
+
|
35
|
+
# Extract the indices of the frame and the link it is attached to.
|
36
|
+
F = ir.frames[frame_idx - model.number_of_links()]
|
37
|
+
L = ir.links_dict[F.parent.name].index
|
38
|
+
|
39
|
+
return int(L)
|
40
|
+
|
41
|
+
|
42
|
+
def name_to_idx(model: js.model.JaxSimModel, *, frame_name: str) -> int:
|
43
|
+
"""
|
44
|
+
Convert the name of a frame to its index.
|
45
|
+
|
46
|
+
Args:
|
47
|
+
model: The model to consider.
|
48
|
+
frame_name: The name of the frame.
|
49
|
+
|
50
|
+
Returns:
|
51
|
+
The index of the frame.
|
52
|
+
"""
|
53
|
+
|
54
|
+
frame_names = np.array([frame.name for frame in model.description.get().frames])
|
55
|
+
|
56
|
+
if frame_name in frame_names:
|
57
|
+
idx_in_list = np.argwhere(frame_names == frame_name)
|
58
|
+
return int(idx_in_list.squeeze().tolist()) + model.number_of_links()
|
59
|
+
|
60
|
+
return -1
|
61
|
+
|
62
|
+
|
63
|
+
def idx_to_name(model: js.model.JaxSimModel, *, frame_index: jtp.IntLike) -> str:
|
64
|
+
"""
|
65
|
+
Convert the index of a frame to its name.
|
66
|
+
|
67
|
+
Args:
|
68
|
+
model: The model to consider.
|
69
|
+
frame_index: The index of the frame.
|
70
|
+
|
71
|
+
Returns:
|
72
|
+
The name of the frame.
|
73
|
+
"""
|
74
|
+
|
75
|
+
return model.description.get().frames[frame_index - model.number_of_links()].name
|
76
|
+
|
77
|
+
|
78
|
+
@functools.partial(jax.jit, static_argnames=["frame_names"])
|
79
|
+
def names_to_idxs(
|
80
|
+
model: js.model.JaxSimModel, *, frame_names: Sequence[str]
|
81
|
+
) -> jax.Array:
|
82
|
+
"""
|
83
|
+
Convert a sequence of frame names to their corresponding indices.
|
84
|
+
|
85
|
+
Args:
|
86
|
+
model: The model to consider.
|
87
|
+
frame_names: The names of the frames.
|
88
|
+
|
89
|
+
Returns:
|
90
|
+
The indices of the frames.
|
91
|
+
"""
|
92
|
+
|
93
|
+
return jnp.array(
|
94
|
+
[name_to_idx(model=model, frame_name=frame_name) for frame_name in frame_names]
|
95
|
+
).astype(int)
|
96
|
+
|
97
|
+
|
98
|
+
def idxs_to_names(
|
99
|
+
model: js.model.JaxSimModel, *, frame_indices: Sequence[jtp.IntLike]
|
100
|
+
) -> tuple[str, ...]:
|
101
|
+
"""
|
102
|
+
Convert a sequence of frame indices to their corresponding names.
|
103
|
+
|
104
|
+
Args:
|
105
|
+
model: The model to consider.
|
106
|
+
frame_indices: The indices of the frames.
|
107
|
+
|
108
|
+
Returns:
|
109
|
+
The names of the frames.
|
110
|
+
"""
|
111
|
+
|
112
|
+
return tuple(
|
113
|
+
idx_to_name(model=model, frame_index=frame_index)
|
114
|
+
for frame_index in frame_indices
|
115
|
+
)
|
116
|
+
|
117
|
+
|
118
|
+
# ==========
|
119
|
+
# Frame APIs
|
120
|
+
# ==========
|
121
|
+
|
122
|
+
|
123
|
+
@functools.partial(jax.jit, static_argnames=["frame_index"])
|
124
|
+
def transform(
|
125
|
+
model: js.model.JaxSimModel,
|
126
|
+
data: js.data.JaxSimModelData,
|
127
|
+
*,
|
128
|
+
frame_index: jtp.IntLike,
|
129
|
+
) -> jtp.Matrix:
|
130
|
+
"""
|
131
|
+
Compute the SE(3) transform from the world frame to the specified frame.
|
132
|
+
|
133
|
+
Args:
|
134
|
+
model: The model to consider.
|
135
|
+
data: The data of the considered model.
|
136
|
+
frame_index: The index of the frame for which the transform is requested.
|
137
|
+
|
138
|
+
Returns:
|
139
|
+
The 4x4 matrix representing the transform.
|
140
|
+
"""
|
141
|
+
|
142
|
+
# Compute the necessary transforms.
|
143
|
+
L = idx_of_parent_link(model=model, frame_idx=frame_index)
|
144
|
+
W_H_L = js.link.transform(model=model, data=data, link_index=L)
|
145
|
+
|
146
|
+
# Get the static frame pose wrt the parent link.
|
147
|
+
frame = model.description.get().frames[frame_index - model.number_of_links()]
|
148
|
+
L_H_F = frame.pose
|
149
|
+
|
150
|
+
# Combine the transforms computing the frame pose.
|
151
|
+
return W_H_L @ L_H_F
|
152
|
+
|
153
|
+
|
154
|
+
@functools.partial(jax.jit, static_argnames=["frame_index", "output_vel_repr"])
|
155
|
+
def jacobian(
|
156
|
+
model: js.model.JaxSimModel,
|
157
|
+
data: js.data.JaxSimModelData,
|
158
|
+
*,
|
159
|
+
frame_index: jtp.IntLike,
|
160
|
+
output_vel_repr: VelRepr | None = None,
|
161
|
+
) -> jtp.Matrix:
|
162
|
+
"""
|
163
|
+
Compute the free-floating jacobian of the frame.
|
164
|
+
|
165
|
+
Args:
|
166
|
+
model: The model to consider.
|
167
|
+
data: The data of the considered model.
|
168
|
+
frame_index: The index of the frame.
|
169
|
+
output_vel_repr:
|
170
|
+
The output velocity representation of the free-floating jacobian.
|
171
|
+
|
172
|
+
Returns:
|
173
|
+
The 6×(6+n) free-floating jacobian of the frame.
|
174
|
+
|
175
|
+
Note:
|
176
|
+
The input representation of the free-floating jacobian is the active
|
177
|
+
velocity representation.
|
178
|
+
"""
|
179
|
+
|
180
|
+
output_vel_repr = (
|
181
|
+
output_vel_repr if output_vel_repr is not None else data.velocity_representation
|
182
|
+
)
|
183
|
+
|
184
|
+
# Get the index of the parent link.
|
185
|
+
L = idx_of_parent_link(model=model, frame_idx=frame_index)
|
186
|
+
|
187
|
+
# Compute the Jacobian of the parent link using body-fixed output representation.
|
188
|
+
L_J_WL = js.link.jacobian(
|
189
|
+
model=model, data=data, link_index=L, output_vel_repr=VelRepr.Body
|
190
|
+
)
|
191
|
+
|
192
|
+
# Adjust the output representation
|
193
|
+
match output_vel_repr:
|
194
|
+
case VelRepr.Inertial:
|
195
|
+
W_H_L = js.link.transform(model=model, data=data, link_index=L)
|
196
|
+
W_X_L = jaxlie.SE3.from_matrix(W_H_L).adjoint()
|
197
|
+
W_J_WL = W_X_L @ L_J_WL
|
198
|
+
O_J_WL_I = W_J_WL
|
199
|
+
|
200
|
+
case VelRepr.Body:
|
201
|
+
W_H_L = js.link.transform(model=model, data=data, link_index=L)
|
202
|
+
W_H_F = transform(model=model, data=data, frame_index=frame_index)
|
203
|
+
F_H_L = jaxsim.math.Transform.inverse(W_H_F) @ W_H_L
|
204
|
+
F_X_L = jaxlie.SE3.from_matrix(F_H_L).adjoint()
|
205
|
+
F_J_WL = F_X_L @ L_J_WL
|
206
|
+
O_J_WL_I = F_J_WL
|
207
|
+
|
208
|
+
case VelRepr.Mixed:
|
209
|
+
W_H_L = js.link.transform(model=model, data=data, link_index=L)
|
210
|
+
W_H_F = transform(model=model, data=data, frame_index=frame_index)
|
211
|
+
F_H_L = jaxsim.math.Transform.inverse(W_H_F) @ W_H_L
|
212
|
+
FW_H_F = W_H_F.at[0:3, 3].set(jnp.zeros(3))
|
213
|
+
FW_H_L = FW_H_F @ F_H_L
|
214
|
+
FW_X_L = jaxlie.SE3.from_matrix(FW_H_L).adjoint()
|
215
|
+
FW_J_WL = FW_X_L @ L_J_WL
|
216
|
+
O_J_WL_I = FW_J_WL
|
217
|
+
|
218
|
+
case _:
|
219
|
+
raise ValueError(output_vel_repr)
|
220
|
+
|
221
|
+
return O_J_WL_I
|
@@ -252,6 +252,16 @@ class JaxSimModel(JaxsimDataclass):
|
|
252
252
|
|
253
253
|
return self.kin_dyn_parameters.link_names
|
254
254
|
|
255
|
+
def frame_names(self) -> tuple[str, ...]:
|
256
|
+
"""
|
257
|
+
Return the names of the links in the model.
|
258
|
+
|
259
|
+
Returns:
|
260
|
+
The names of the links in the model.
|
261
|
+
"""
|
262
|
+
|
263
|
+
return tuple([frame.name for frame in self.description.get().frames])
|
264
|
+
|
255
265
|
|
256
266
|
# =====================
|
257
267
|
# Model post-processing
|
@@ -1,5 +1,6 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import dataclasses
|
2
|
-
from typing import List
|
3
4
|
|
4
5
|
import jax.numpy as jnp
|
5
6
|
import jax_dataclasses
|
@@ -16,39 +17,46 @@ class LinkDescription(JaxsimDataclass):
|
|
16
17
|
In-memory description of a robot link.
|
17
18
|
|
18
19
|
Attributes:
|
19
|
-
name
|
20
|
-
mass
|
21
|
-
inertia
|
22
|
-
index
|
23
|
-
parent
|
24
|
-
pose
|
25
|
-
children
|
20
|
+
name: The name of the link.
|
21
|
+
mass: The mass of the link.
|
22
|
+
inertia: The inertia tensor of the link.
|
23
|
+
index: An optional index for the link (it gets automatically assigned).
|
24
|
+
parent: The parent link of this link.
|
25
|
+
pose: The pose transformation matrix of the link.
|
26
|
+
children: List of child links.
|
26
27
|
"""
|
27
28
|
|
28
29
|
name: Static[str]
|
29
|
-
mass: float
|
30
|
-
inertia: jtp.Matrix
|
30
|
+
mass: float = dataclasses.field(repr=False)
|
31
|
+
inertia: jtp.Matrix = dataclasses.field(repr=False)
|
31
32
|
index: int | None = None
|
32
|
-
parent:
|
33
|
+
parent: LinkDescription = dataclasses.field(default=None, repr=False)
|
33
34
|
pose: jtp.Matrix = dataclasses.field(default_factory=lambda: jnp.eye(4), repr=False)
|
34
|
-
|
35
|
+
|
36
|
+
children: Static[list[LinkDescription]] = dataclasses.field(
|
35
37
|
default_factory=list, repr=False
|
36
38
|
)
|
37
39
|
|
38
40
|
def __hash__(self) -> int:
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
and self.children == other.children
|
41
|
+
|
42
|
+
return hash(
|
43
|
+
(
|
44
|
+
hash(self.name),
|
45
|
+
hash(float(self.mass)),
|
46
|
+
hash(tuple(self.inertia.flatten().tolist())),
|
47
|
+
hash(int(self.index)),
|
48
|
+
hash(self.parent),
|
49
|
+
hash(tuple(hash(c) for c in self.children)),
|
50
|
+
)
|
50
51
|
)
|
51
52
|
|
53
|
+
def __eq__(self, other: LinkDescription) -> bool:
|
54
|
+
|
55
|
+
if not isinstance(other, LinkDescription):
|
56
|
+
return False
|
57
|
+
|
58
|
+
return hash(self) == hash(other)
|
59
|
+
|
52
60
|
@property
|
53
61
|
def name_and_index(self) -> str:
|
54
62
|
"""
|
@@ -61,19 +69,19 @@ class LinkDescription(JaxsimDataclass):
|
|
61
69
|
return f"#{self.index}_<{self.name}>"
|
62
70
|
|
63
71
|
def lump_with(
|
64
|
-
self, link:
|
65
|
-
) ->
|
72
|
+
self, link: LinkDescription, lumped_H_removed: jtp.Matrix
|
73
|
+
) -> LinkDescription:
|
66
74
|
"""
|
67
75
|
Combine the current link with another link, preserving mass and inertia.
|
68
76
|
|
69
77
|
Args:
|
70
|
-
link
|
71
|
-
lumped_H_removed
|
78
|
+
link: The link to combine with.
|
79
|
+
lumped_H_removed: The transformation matrix between the two links.
|
72
80
|
|
73
81
|
Returns:
|
74
|
-
|
75
|
-
|
82
|
+
The combined link.
|
76
83
|
"""
|
84
|
+
|
77
85
|
# Get the 6D inertia of the link to remove
|
78
86
|
I_removed = link.inertia
|
79
87
|
|
@@ -51,6 +51,7 @@ src/jaxsim/api/com.py
|
|
51
51
|
src/jaxsim/api/common.py
|
52
52
|
src/jaxsim/api/contact.py
|
53
53
|
src/jaxsim/api/data.py
|
54
|
+
src/jaxsim/api/frame.py
|
54
55
|
src/jaxsim/api/joint.py
|
55
56
|
src/jaxsim/api/kin_dyn_parameters.py
|
56
57
|
src/jaxsim/api/link.py
|
@@ -105,6 +106,7 @@ tests/__init__.py
|
|
105
106
|
tests/conftest.py
|
106
107
|
tests/test_api_com.py
|
107
108
|
tests/test_api_data.py
|
109
|
+
tests/test_api_frame.py
|
108
110
|
tests/test_api_joint.py
|
109
111
|
tests/test_api_link.py
|
110
112
|
tests/test_api_model.py
|
@@ -4,6 +4,8 @@ import pathlib
|
|
4
4
|
import jax
|
5
5
|
import pytest
|
6
6
|
import rod
|
7
|
+
import rod.urdf
|
8
|
+
import rod.urdf.exporter
|
7
9
|
|
8
10
|
import jaxsim
|
9
11
|
import jaxsim.api as js
|
@@ -120,18 +122,26 @@ def jaxsim_model_box() -> js.model.JaxSimModel:
|
|
120
122
|
rod_model = (
|
121
123
|
rod.builder.primitives.BoxBuilder(x=0.3, y=0.2, z=0.1, mass=1.0, name="box")
|
122
124
|
.build_model()
|
123
|
-
.add_link()
|
125
|
+
.add_link(name="box_link")
|
124
126
|
.add_inertial()
|
125
127
|
.add_visual()
|
126
128
|
.add_collision()
|
127
129
|
.build()
|
128
130
|
)
|
129
131
|
|
130
|
-
|
131
|
-
|
132
|
-
|
132
|
+
rod_model.add_frame(
|
133
|
+
rod.Frame(
|
134
|
+
name="box_frame",
|
135
|
+
attached_to="box_link",
|
136
|
+
pose=rod.Pose(relative_to="box_link", pose=[1, 1, 1, 0.5, 0.4, 0.3]),
|
137
|
+
)
|
133
138
|
)
|
134
139
|
|
140
|
+
# Export the URDF string.
|
141
|
+
urdf_string = rod.urdf.exporter.UrdfExporter(
|
142
|
+
pretty=True, gazebo_preserve_fixed_joints=True
|
143
|
+
).to_urdf_string(sdf=rod_model)
|
144
|
+
|
135
145
|
return build_jaxsim_model(model_description=urdf_string)
|
136
146
|
|
137
147
|
|
@@ -159,8 +169,8 @@ def jaxsim_model_sphere() -> js.model.JaxSimModel:
|
|
159
169
|
)
|
160
170
|
|
161
171
|
# Export the URDF string.
|
162
|
-
urdf_string = rod.urdf.exporter.UrdfExporter.
|
163
|
-
sdf=rod_model
|
172
|
+
urdf_string = rod.urdf.exporter.UrdfExporter(pretty=True).to_urdf_string(
|
173
|
+
sdf=rod_model
|
164
174
|
)
|
165
175
|
|
166
176
|
return build_jaxsim_model(model_description=urdf_string)
|
@@ -219,7 +229,9 @@ def jaxsim_model_ergocub_reduced(jaxsim_model_ergocub) -> js.model.JaxSimModel:
|
|
219
229
|
and "torso" not in j and "elbow" not in j and "shoulder" not in j
|
220
230
|
)
|
221
231
|
|
222
|
-
|
232
|
+
model = js.model.reduce(model=model_full, considered_joints=reduced_joints)
|
233
|
+
|
234
|
+
return model
|
223
235
|
|
224
236
|
|
225
237
|
@pytest.fixture(scope="session")
|
@@ -0,0 +1,144 @@
|
|
1
|
+
import jax
|
2
|
+
import numpy as np
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
import jaxsim.api as js
|
6
|
+
from jaxsim import VelRepr
|
7
|
+
|
8
|
+
from . import utils_idyntree
|
9
|
+
|
10
|
+
|
11
|
+
def test_frame_index(jaxsim_models_types: js.model.JaxSimModel):
|
12
|
+
|
13
|
+
model = jaxsim_models_types
|
14
|
+
|
15
|
+
# =====
|
16
|
+
# Tests
|
17
|
+
# =====
|
18
|
+
|
19
|
+
frame_indices = tuple(
|
20
|
+
frame.index
|
21
|
+
for frame in model.description.get().frames
|
22
|
+
if frame.index is not None
|
23
|
+
)
|
24
|
+
|
25
|
+
frame_names = np.array([frame.name for frame in model.description.get().frames])
|
26
|
+
|
27
|
+
for frame_idx, frame_name in zip(frame_indices, frame_names):
|
28
|
+
assert js.frame.name_to_idx(model=model, frame_name=frame_name) == frame_idx
|
29
|
+
assert js.frame.idx_to_name(model=model, frame_index=frame_idx) == frame_name
|
30
|
+
assert (
|
31
|
+
js.frame.idx_of_parent_link(model=model, frame_idx=frame_idx)
|
32
|
+
< model.number_of_links()
|
33
|
+
)
|
34
|
+
|
35
|
+
assert js.frame.names_to_idxs(
|
36
|
+
model=model, frame_names=tuple(frame_names)
|
37
|
+
) == pytest.approx(frame_indices)
|
38
|
+
|
39
|
+
assert js.frame.idxs_to_names(
|
40
|
+
model=model, frame_indices=frame_indices
|
41
|
+
) == pytest.approx(frame_names)
|
42
|
+
|
43
|
+
|
44
|
+
def test_frame_transforms(
|
45
|
+
jaxsim_models_types: js.model.JaxSimModel,
|
46
|
+
prng_key: jax.Array,
|
47
|
+
):
|
48
|
+
|
49
|
+
model = jaxsim_models_types
|
50
|
+
|
51
|
+
key, subkey = jax.random.split(prng_key, num=2)
|
52
|
+
data = js.data.random_model_data(
|
53
|
+
model=model, key=subkey, velocity_representation=VelRepr.Inertial
|
54
|
+
)
|
55
|
+
|
56
|
+
kin_dyn = utils_idyntree.build_kindyncomputations_from_jaxsim_model(
|
57
|
+
model=model, data=data
|
58
|
+
)
|
59
|
+
|
60
|
+
# Get all names of frames in the iDynTree model.
|
61
|
+
frame_names = [
|
62
|
+
frame.name
|
63
|
+
for frame in model.description.get().frames
|
64
|
+
if frame.name in kin_dyn.frame_names()
|
65
|
+
]
|
66
|
+
|
67
|
+
# Skip some entry of models with many frames.
|
68
|
+
frame_names = [
|
69
|
+
name
|
70
|
+
for name in frame_names
|
71
|
+
if "skin" not in name or "laser" not in name or "depth" not in name
|
72
|
+
]
|
73
|
+
|
74
|
+
# Get indices of frames.
|
75
|
+
frame_indices = tuple(
|
76
|
+
frame.index
|
77
|
+
for frame in model.description.get().frames
|
78
|
+
if frame.index is not None and frame.name in frame_names
|
79
|
+
)
|
80
|
+
|
81
|
+
# =====
|
82
|
+
# Tests
|
83
|
+
# =====
|
84
|
+
|
85
|
+
assert len(frame_indices) == len(frame_names)
|
86
|
+
|
87
|
+
for frame_name, frame_idx in zip(frame_names, frame_indices):
|
88
|
+
|
89
|
+
W_H_F_js = js.frame.transform(
|
90
|
+
model=model,
|
91
|
+
data=data,
|
92
|
+
frame_index=js.frame.name_to_idx(model=model, frame_name=frame_name),
|
93
|
+
)
|
94
|
+
W_H_F_idt = kin_dyn.frame_transform(frame_name=frame_name)
|
95
|
+
assert W_H_F_js == pytest.approx(W_H_F_idt, abs=1e-6), frame_name
|
96
|
+
|
97
|
+
|
98
|
+
def test_frame_jacobians(
|
99
|
+
jaxsim_models_types: js.model.JaxSimModel,
|
100
|
+
velocity_representation: VelRepr,
|
101
|
+
prng_key: jax.Array,
|
102
|
+
):
|
103
|
+
|
104
|
+
model = jaxsim_models_types
|
105
|
+
|
106
|
+
key, subkey = jax.random.split(prng_key, num=2)
|
107
|
+
data = js.data.random_model_data(
|
108
|
+
model=model, key=subkey, velocity_representation=velocity_representation
|
109
|
+
)
|
110
|
+
|
111
|
+
kin_dyn = utils_idyntree.build_kindyncomputations_from_jaxsim_model(
|
112
|
+
model=model, data=data
|
113
|
+
)
|
114
|
+
|
115
|
+
# Get all names of frames in the iDynTree model.
|
116
|
+
frame_names = [
|
117
|
+
frame.name
|
118
|
+
for frame in model.description.get().frames
|
119
|
+
if frame.name in kin_dyn.frame_names()
|
120
|
+
]
|
121
|
+
|
122
|
+
# Lower the number of frames for models with many frames.
|
123
|
+
if model.name().lower() == "ergocub":
|
124
|
+
assert any(["sole" in name for name in frame_names])
|
125
|
+
frame_names = [name for name in frame_names if "sole" in name]
|
126
|
+
|
127
|
+
# Get indices of frames.
|
128
|
+
frame_indices = tuple(
|
129
|
+
frame.index
|
130
|
+
for frame in model.description.get().frames
|
131
|
+
if frame.index is not None and frame.name in frame_names
|
132
|
+
)
|
133
|
+
|
134
|
+
# =====
|
135
|
+
# Tests
|
136
|
+
# =====
|
137
|
+
|
138
|
+
assert len(frame_indices) == len(frame_names)
|
139
|
+
|
140
|
+
for frame_name, frame_idx in zip(frame_names, frame_indices):
|
141
|
+
|
142
|
+
J_WL_js = js.frame.jacobian(model=model, data=data, frame_index=frame_idx)
|
143
|
+
J_WL_idt = kin_dyn.jacobian_frame(frame_name=frame_name)
|
144
|
+
assert J_WL_js == pytest.approx(J_WL_idt, abs=1e-9)
|
@@ -16,6 +16,7 @@ def test_joint_index(
|
|
16
16
|
|
17
17
|
for idx, joint_name in enumerate(model.joint_names()):
|
18
18
|
assert js.joint.name_to_idx(model=model, joint_name=joint_name) == idx
|
19
|
+
assert js.joint.idx_to_name(model=model, joint_index=idx) == joint_name
|
19
20
|
|
20
21
|
assert js.joint.names_to_idxs(
|
21
22
|
model=model, joint_names=model.joint_names()
|
@@ -20,6 +20,7 @@ def test_link_index(
|
|
20
20
|
|
21
21
|
for idx, link_name in enumerate(model.link_names()):
|
22
22
|
assert js.link.name_to_idx(model=model, link_name=link_name) == idx
|
23
|
+
assert js.link.idx_to_name(model=model, link_index=idx) == link_name
|
23
24
|
|
24
25
|
assert js.link.names_to_idxs(
|
25
26
|
model=model, link_names=model.link_names()
|
@@ -2,6 +2,7 @@ import io
|
|
2
2
|
from contextlib import redirect_stdout
|
3
3
|
|
4
4
|
import jax
|
5
|
+
import pytest
|
5
6
|
import rod.builder.primitives
|
6
7
|
import rod.urdf.exporter
|
7
8
|
|
@@ -9,6 +10,7 @@ import jaxsim.api as js
|
|
9
10
|
|
10
11
|
|
11
12
|
# https://github.com/ami-iit/jaxsim/issues/103
|
13
|
+
@pytest.mark.xfail(strict=True)
|
12
14
|
def test_call_jit_compiled_function_passing_different_objects():
|
13
15
|
|
14
16
|
# Create on-the-fly a ROD model of a box.
|
@@ -23,8 +25,8 @@ def test_call_jit_compiled_function_passing_different_objects():
|
|
23
25
|
)
|
24
26
|
|
25
27
|
# Export the URDF string.
|
26
|
-
urdf_string = rod.urdf.exporter.UrdfExporter.
|
27
|
-
sdf=rod_model
|
28
|
+
urdf_string = rod.urdf.exporter.UrdfExporter(pretty=True).to_urdf_string(
|
29
|
+
sdf=rod_model
|
28
30
|
)
|
29
31
|
|
30
32
|
model1 = js.model.JaxSimModel.build_from_model_description(
|
@@ -348,6 +348,13 @@ class KinDynComputations:
|
|
348
348
|
|
349
349
|
return H
|
350
350
|
|
351
|
+
def frame_parent_link_name(self, frame_name: str) -> str:
|
352
|
+
return self.kin_dyn.model().getLinkName(
|
353
|
+
self.kin_dyn.model().getFrameLink(
|
354
|
+
self.kin_dyn.model().getFrameIndex(frame_name)
|
355
|
+
)
|
356
|
+
)
|
357
|
+
|
351
358
|
def base_velocity(self) -> npt.NDArray:
|
352
359
|
|
353
360
|
nu = idt.VectorDynSize()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|