jaxsim 0.4.1.dev6__tar.gz → 0.4.1.dev11__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.4.1.dev6 → jaxsim-0.4.1.dev11}/PKG-INFO +1 -1
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/_version.py +2 -2
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/mujoco/loaders.py +8 -4
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/mujoco/model.py +82 -16
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim.egg-info/PKG-INFO +1 -1
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_simulations.py +50 -30
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.devcontainer/Dockerfile +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.devcontainer/devcontainer.json +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.gitattributes +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.github/CODEOWNERS +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.github/workflows/ci_cd.yml +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.github/workflows/read_the_docs.yml +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.gitignore +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.pre-commit-config.yaml +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.readthedocs.yaml +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/CONTRIBUTING.md +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/LICENSE +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/README.md +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/Makefile +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/conf.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/examples.rst +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/guide/install.rst +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/index.rst +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/make.bat +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/api.rst +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/integrators.rst +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/math.rst +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/mujoco.rst +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/parsers.rst +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/rbda.rst +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/typing.rst +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/utils.rst +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/environment.yml +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/examples/.gitattributes +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/examples/.gitignore +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/examples/PD_controller.ipynb +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/examples/Parallel_computing.ipynb +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/examples/README.md +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/examples/assets/cartpole.urdf +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/pixi.lock +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/pyproject.toml +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/setup.cfg +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/setup.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/__init__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/__init__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/com.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/common.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/contact.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/data.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/frame.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/joint.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/kin_dyn_parameters.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/link.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/model.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/ode.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/ode_data.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/references.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/exceptions.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/integrators/__init__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/integrators/common.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/integrators/fixed_step.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/integrators/variable_step.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/logging.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/__init__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/adjoint.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/cross.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/inertia.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/joint_model.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/quaternion.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/rotation.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/skew.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/transform.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/mujoco/__init__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/mujoco/__main__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/mujoco/visualizer.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/__init__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/descriptions/__init__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/descriptions/collision.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/descriptions/joint.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/descriptions/link.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/descriptions/model.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/kinematic_graph.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/rod/__init__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/rod/parser.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/rod/utils.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/__init__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/aba.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/collidable_points.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/contacts/__init__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/contacts/common.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/contacts/soft.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/crba.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/forward_kinematics.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/jacobian.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/rnea.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/utils.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/terrain/__init__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/terrain/terrain.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/typing.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/utils/__init__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/utils/jaxsim_dataclass.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/utils/tracing.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/utils/wrappers.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim.egg-info/SOURCES.txt +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim.egg-info/dependency_links.txt +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim.egg-info/requires.txt +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim.egg-info/top_level.txt +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/__init__.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/conftest.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_com.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_contact.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_data.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_frame.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_joint.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_link.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_model.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_automatic_differentiation.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_contact.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_exceptions.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_pytree.py +0 -0
- {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/utils_idyntree.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: jaxsim
|
3
|
-
Version: 0.4.1.
|
3
|
+
Version: 0.4.1.dev11
|
4
4
|
Summary: A differentiable physics engine and multibody dynamics library for control and robot learning.
|
5
5
|
Author-email: Diego Ferigo <dgferigo@gmail.com>
|
6
6
|
Maintainer-email: Diego Ferigo <dgferigo@gmail.com>, Filippo Luca Ferretti <filippo.ferretti@iit.it>
|
@@ -12,5 +12,5 @@ __version__: str
|
|
12
12
|
__version_tuple__: VERSION_TUPLE
|
13
13
|
version_tuple: VERSION_TUPLE
|
14
14
|
|
15
|
-
__version__ = version = '0.4.1.
|
16
|
-
__version_tuple__ = version_tuple = (0, 4, 1, '
|
15
|
+
__version__ = version = '0.4.1.dev11'
|
16
|
+
__version_tuple__ = version_tuple = (0, 4, 1, 'dev11')
|
@@ -160,6 +160,7 @@ class RodModelToMjcf:
|
|
160
160
|
considered_joints: list[str] | None = None,
|
161
161
|
plane_normal: tuple[float, float, float] = (0, 0, 1),
|
162
162
|
heightmap: bool | None = None,
|
163
|
+
heightmap_samples_xy: tuple[int, int] = (101, 101),
|
163
164
|
cameras: list[dict[str, str]] | dict[str, str] | None = None,
|
164
165
|
) -> tuple[str, dict[str, Any]]:
|
165
166
|
"""
|
@@ -170,10 +171,11 @@ class RodModelToMjcf:
|
|
170
171
|
considered_joints: The list of joint names to consider in the conversion.
|
171
172
|
plane_normal: The normal vector of the plane.
|
172
173
|
heightmap: Whether to generate a heightmap.
|
174
|
+
heightmap_samples_xy: The number of points in the heightmap grid.
|
173
175
|
cameras: The list of cameras to add to the scene.
|
174
176
|
|
175
177
|
Returns:
|
176
|
-
tuple: A tuple containing the MJCF string and the assets
|
178
|
+
tuple: A tuple containing the MJCF string and the dictionary of assets.
|
177
179
|
"""
|
178
180
|
|
179
181
|
# -------------------------------------
|
@@ -404,9 +406,11 @@ class RodModelToMjcf:
|
|
404
406
|
asset_element,
|
405
407
|
"hfield",
|
406
408
|
name="terrain",
|
407
|
-
nrow="
|
408
|
-
ncol="
|
409
|
-
size
|
409
|
+
nrow=f"{int(heightmap_samples_xy[0])}",
|
410
|
+
ncol=f"{int(heightmap_samples_xy[1])}",
|
411
|
+
# The following 'size' is a placeholder, it is updated dynamically
|
412
|
+
# when a hfield/heightmap is stored into MjData.
|
413
|
+
size="1 1 1 1",
|
410
414
|
)
|
411
415
|
if heightmap
|
412
416
|
else None
|
@@ -7,6 +7,7 @@ from typing import Any, Callable
|
|
7
7
|
import mujoco as mj
|
8
8
|
import numpy as np
|
9
9
|
import numpy.typing as npt
|
10
|
+
import xmltodict
|
10
11
|
from scipy.spatial.transform import Rotation
|
11
12
|
|
12
13
|
import jaxsim.typing as jtp
|
@@ -42,16 +43,27 @@ class MujocoModelHelper:
|
|
42
43
|
mjcf_description: str | pathlib.Path,
|
43
44
|
assets: dict[str, Any] | None = None,
|
44
45
|
heightmap: HeightmapCallable | None = None,
|
46
|
+
heightmap_name: str = "terrain",
|
47
|
+
heightmap_radius_xy: tuple[float, float] = (1.0, 1.0),
|
45
48
|
) -> MujocoModelHelper:
|
46
49
|
"""
|
47
|
-
Build a Mujoco model from an
|
50
|
+
Build a Mujoco model from an MJCF description.
|
48
51
|
|
49
52
|
Args:
|
50
|
-
mjcf_description:
|
53
|
+
mjcf_description:
|
54
|
+
A string containing the XML description of the Mujoco model
|
51
55
|
or a path to a file containing the XML description.
|
52
56
|
assets: An optional dictionary containing the assets of the model.
|
53
|
-
heightmap:
|
57
|
+
heightmap:
|
58
|
+
A function in two variables that returns the height of a terrain
|
54
59
|
in the specified coordinate point.
|
60
|
+
heightmap_name:
|
61
|
+
The default name of the heightmap in the MJCF description
|
62
|
+
to load the corresponding configuration.
|
63
|
+
heightmap_radius_xy:
|
64
|
+
The extension of the heightmap in the x-y surface corresponding to the
|
65
|
+
plane over which the grid of the sampled heightmap is generated.
|
66
|
+
|
55
67
|
Returns:
|
56
68
|
A MujocoModelHelper object.
|
57
69
|
"""
|
@@ -63,15 +75,61 @@ class MujocoModelHelper:
|
|
63
75
|
else mjcf_description
|
64
76
|
)
|
65
77
|
|
66
|
-
|
78
|
+
if heightmap is None:
|
79
|
+
hfield = None
|
80
|
+
|
81
|
+
else:
|
82
|
+
|
83
|
+
mjcf_description_dict = xmltodict.parse(xml_input=mjcf_description)
|
84
|
+
|
85
|
+
# Create a dictionary of all hfield configurations from the MJCF.
|
86
|
+
hfields = mjcf_description_dict["mujoco"]["asset"].get("hfield", [])
|
87
|
+
hfields = hfields if isinstance(hfields, list) else [hfields]
|
88
|
+
hfields_dict = {hfield["@name"]: hfield for hfield in hfields}
|
89
|
+
|
90
|
+
if heightmap_name not in hfields_dict:
|
91
|
+
raise ValueError(f"Heightmap '{heightmap_name}' not found in MJCF")
|
92
|
+
|
93
|
+
hfield_element = hfields_dict[heightmap_name]
|
94
|
+
|
95
|
+
# Generate the hfield by sampling the heightmap function.
|
96
|
+
hfield = generate_hfield(
|
97
|
+
heightmap=heightmap,
|
98
|
+
samples_xy=(int(hfield_element["@nrow"]), int(hfield_element["@ncol"])),
|
99
|
+
radius_xy=heightmap_radius_xy,
|
100
|
+
)
|
101
|
+
|
102
|
+
# Update dynamically the '/asset/hfield[@name=heightmap_name]@size' attribute
|
103
|
+
# with the information of the sampled points.
|
104
|
+
# This is necessary for correctly rendering the heightmap over the
|
105
|
+
# specified xy area with the correct z elevation.
|
106
|
+
size = [float(el) for el in hfield_element["@size"].split(" ")]
|
107
|
+
size[0], size[1] = heightmap_radius_xy
|
108
|
+
size[2] = 1.0
|
109
|
+
size[3] = max(0, -min(hfield))
|
110
|
+
|
111
|
+
# Replace the 'size' attribute.
|
112
|
+
hfields_dict[heightmap_name]["@size"] = " ".join(str(el) for el in size)
|
113
|
+
|
114
|
+
# Update the hfield elements of the original MJCF.
|
115
|
+
# Only the hfield corresponding to 'heightmap_name' was actually edited.
|
116
|
+
mjcf_description_dict["mujoco"]["asset"]["hfield"] = list(
|
117
|
+
hfields_dict.values()
|
118
|
+
)
|
119
|
+
|
120
|
+
# Serialize the updated MJCF to XML.
|
121
|
+
mjcf_description = xmltodict.unparse(
|
122
|
+
input_dict=mjcf_description_dict, pretty=True
|
123
|
+
)
|
124
|
+
|
125
|
+
# Create the Mujoco model from the XML and, optionally, the dictionary of assets.
|
67
126
|
model = mj.MjModel.from_xml_string(xml=mjcf_description, assets=assets)
|
68
127
|
data = mj.MjData(model)
|
69
128
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
model.hfield_data = new_hfield
|
129
|
+
# Store the sampled heightmap into the Mujoco model.
|
130
|
+
if heightmap is not None:
|
131
|
+
assert hfield is not None
|
132
|
+
model.hfield_data = hfield
|
75
133
|
|
76
134
|
return MujocoModelHelper(model=model, data=data)
|
77
135
|
|
@@ -385,10 +443,13 @@ class MujocoModelHelper:
|
|
385
443
|
|
386
444
|
|
387
445
|
def generate_hfield(
|
388
|
-
heightmap: HeightmapCallable,
|
446
|
+
heightmap: HeightmapCallable,
|
447
|
+
samples_xy: tuple[int, int] = (11, 11),
|
448
|
+
radius_xy: tuple[float, float] = (1.0, 1.0),
|
389
449
|
) -> npt.NDArray:
|
390
450
|
"""
|
391
|
-
|
451
|
+
Generate an array with elevation points sampled from a heightmap function.
|
452
|
+
|
392
453
|
The map will have the following format:
|
393
454
|
```
|
394
455
|
heightmap[0, 0] heightmap[0, 1] ... heightmap[0, size[1]-1]
|
@@ -398,17 +459,22 @@ def generate_hfield(
|
|
398
459
|
```
|
399
460
|
|
400
461
|
Args:
|
401
|
-
heightmap:
|
462
|
+
heightmap:
|
463
|
+
A function that takes two arguments (x, y) and returns the height
|
402
464
|
at that point.
|
403
|
-
|
465
|
+
samples_xy: A tuple of two integers representing the size of the grid.
|
466
|
+
radius_xy:
|
467
|
+
A tuple of two floats representing extension of the heightmap in the
|
468
|
+
x-y surface corresponding to the area over which the grid of the sampled
|
469
|
+
heightmap is generated.
|
404
470
|
|
405
471
|
Returns:
|
406
|
-
|
472
|
+
A flat array of the sampled terrain heightmap.
|
407
473
|
"""
|
408
474
|
|
409
475
|
# Generate the grid.
|
410
|
-
x = np.linspace(0,
|
411
|
-
y = np.linspace(
|
476
|
+
x = np.linspace(-radius_xy[0], radius_xy[0], samples_xy[0])
|
477
|
+
y = np.linspace(-radius_xy[1], radius_xy[1], samples_xy[1])
|
412
478
|
|
413
479
|
# Generate the heightmap.
|
414
480
|
return np.array([[heightmap(xi, yi) for xi in x] for yi in y]).flatten()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: jaxsim
|
3
|
-
Version: 0.4.1.
|
3
|
+
Version: 0.4.1.dev11
|
4
4
|
Summary: A differentiable physics engine and multibody dynamics library for control and robot learning.
|
5
5
|
Author-email: Diego Ferigo <dgferigo@gmail.com>
|
6
6
|
Maintainer-email: Diego Ferigo <dgferigo@gmail.com>, Filippo Luca Ferretti <filippo.ferretti@iit.it>
|
@@ -6,7 +6,7 @@ import jaxsim.api as js
|
|
6
6
|
import jaxsim.integrators
|
7
7
|
import jaxsim.rbda
|
8
8
|
from jaxsim import VelRepr
|
9
|
-
from jaxsim.
|
9
|
+
from jaxsim.utils import Mutability
|
10
10
|
|
11
11
|
|
12
12
|
def test_box_with_external_forces(
|
@@ -102,23 +102,19 @@ def test_box_with_zero_gravity(
|
|
102
102
|
|
103
103
|
model = jaxsim_model_box
|
104
104
|
|
105
|
+
# Move the terrain (almost) infinitely far away from the box.
|
106
|
+
with model.mutable_context(mutability=Mutability.MUTABLE_NO_VALIDATION):
|
107
|
+
model.terrain = jaxsim.terrain.FlatTerrain.build(height=-1e9)
|
108
|
+
|
105
109
|
# Split the PRNG key.
|
106
|
-
_, subkey
|
110
|
+
_, subkey = jax.random.split(prng_key, num=2)
|
107
111
|
|
108
112
|
# Build the data of the model.
|
109
113
|
data0 = js.data.JaxSimModelData.build(
|
110
114
|
model=model,
|
111
|
-
base_position=jax.random.uniform(
|
115
|
+
base_position=jax.random.uniform(subkey, shape=(3,)),
|
112
116
|
velocity_representation=velocity_representation,
|
113
117
|
standard_gravity=0.0,
|
114
|
-
contacts_params=SoftContactsParams.build(K=0.0, D=0.0, mu=0.0),
|
115
|
-
)
|
116
|
-
|
117
|
-
# Generate a random linear force.
|
118
|
-
L_f = (
|
119
|
-
jax.random.uniform(subkey, shape=(model.number_of_links(), 6))
|
120
|
-
.at[:, 3:]
|
121
|
-
.set(jnp.zeros(3))
|
122
118
|
)
|
123
119
|
|
124
120
|
# Initialize a references object that simplifies handling external forces.
|
@@ -129,13 +125,29 @@ def test_box_with_zero_gravity(
|
|
129
125
|
)
|
130
126
|
|
131
127
|
# Apply a link forces to the base link.
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
128
|
+
with references.switch_velocity_representation(jaxsim.VelRepr.Mixed):
|
129
|
+
|
130
|
+
# Generate a random linear force.
|
131
|
+
# We enforce them to be the same for all velocity representations so that
|
132
|
+
# we can compare their outcomes.
|
133
|
+
LW_f = 10.0 * (
|
134
|
+
jax.random.uniform(jax.random.key(0), shape=(model.number_of_links(), 6))
|
135
|
+
.at[:, 3:]
|
136
|
+
.set(jnp.zeros(3))
|
137
|
+
)
|
138
|
+
|
139
|
+
# Note that the context manager does not switch back the newly created
|
140
|
+
# `references` (that is not the yielded object) to the original representation.
|
141
|
+
# In the simulation loop below, we need to make sure that we switch both `data`
|
142
|
+
# and `references` to the same representation before extracting the information
|
143
|
+
# passed to the step function.
|
144
|
+
references = references.apply_link_forces(
|
145
|
+
forces=jnp.atleast_2d(LW_f),
|
146
|
+
link_names=model.link_names(),
|
147
|
+
model=model,
|
148
|
+
data=data0,
|
149
|
+
additive=False,
|
150
|
+
)
|
139
151
|
|
140
152
|
# Create the integrator.
|
141
153
|
integrator = jaxsim.integrators.fixed_step.RungeKutta4SO3.build(
|
@@ -145,8 +157,7 @@ def test_box_with_zero_gravity(
|
|
145
157
|
)
|
146
158
|
|
147
159
|
# Initialize the integrator.
|
148
|
-
tf = 1.0
|
149
|
-
dt = 0.010
|
160
|
+
tf, dt = 1.0, 0.010
|
150
161
|
T = jnp.arange(start=0, stop=tf * 1e9, step=dt * 1e9, dtype=int)
|
151
162
|
integrator_state = integrator.init(x0=data0.state, t0=0.0, dt=dt)
|
152
163
|
|
@@ -156,19 +167,28 @@ def test_box_with_zero_gravity(
|
|
156
167
|
# ... and step the simulation.
|
157
168
|
for t_ns in T:
|
158
169
|
|
159
|
-
data
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
170
|
+
assert data.time() == t_ns / 1e9
|
171
|
+
|
172
|
+
with (
|
173
|
+
data.switch_velocity_representation(velocity_representation),
|
174
|
+
references.switch_velocity_representation(velocity_representation),
|
175
|
+
):
|
176
|
+
|
177
|
+
data, integrator_state = js.model.step(
|
178
|
+
model=model,
|
179
|
+
data=data,
|
180
|
+
dt=dt,
|
181
|
+
integrator=integrator,
|
182
|
+
integrator_state=integrator_state,
|
183
|
+
link_forces=references.link_forces(model=model, data=data),
|
184
|
+
)
|
185
|
+
|
186
|
+
# Check the final simulation time.
|
187
|
+
assert data.time() == T[-1] / 1e9 + dt
|
167
188
|
|
168
189
|
# Check that the box moved as expected.
|
169
|
-
assert data.time() == t_ns / 1e9 + dt
|
170
190
|
assert data.base_position() == pytest.approx(
|
171
191
|
data0.base_position()
|
172
|
-
+ 0.5 *
|
192
|
+
+ 0.5 * LW_f[:, :3].squeeze() / js.model.total_mass(model=model) * tf**2,
|
173
193
|
abs=1e-3,
|
174
194
|
)
|
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
|
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
|