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.
Files changed (121) hide show
  1. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/PKG-INFO +1 -1
  2. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/_version.py +2 -2
  3. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/mujoco/loaders.py +8 -4
  4. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/mujoco/model.py +82 -16
  5. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim.egg-info/PKG-INFO +1 -1
  6. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_simulations.py +50 -30
  7. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.devcontainer/Dockerfile +0 -0
  8. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.devcontainer/devcontainer.json +0 -0
  9. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.gitattributes +0 -0
  10. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.github/CODEOWNERS +0 -0
  11. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.github/workflows/ci_cd.yml +0 -0
  12. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.github/workflows/read_the_docs.yml +0 -0
  13. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.gitignore +0 -0
  14. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.pre-commit-config.yaml +0 -0
  15. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/.readthedocs.yaml +0 -0
  16. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/CONTRIBUTING.md +0 -0
  17. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/LICENSE +0 -0
  18. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/README.md +0 -0
  19. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/Makefile +0 -0
  20. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/conf.py +0 -0
  21. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/examples.rst +0 -0
  22. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/guide/install.rst +0 -0
  23. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/index.rst +0 -0
  24. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/make.bat +0 -0
  25. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/api.rst +0 -0
  26. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/integrators.rst +0 -0
  27. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/math.rst +0 -0
  28. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/mujoco.rst +0 -0
  29. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/parsers.rst +0 -0
  30. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/rbda.rst +0 -0
  31. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/typing.rst +0 -0
  32. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/docs/modules/utils.rst +0 -0
  33. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/environment.yml +0 -0
  34. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/examples/.gitattributes +0 -0
  35. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/examples/.gitignore +0 -0
  36. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/examples/PD_controller.ipynb +0 -0
  37. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/examples/Parallel_computing.ipynb +0 -0
  38. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/examples/README.md +0 -0
  39. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/examples/assets/cartpole.urdf +0 -0
  40. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/pixi.lock +0 -0
  41. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/pyproject.toml +0 -0
  42. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/setup.cfg +0 -0
  43. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/setup.py +0 -0
  44. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/__init__.py +0 -0
  45. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/__init__.py +0 -0
  46. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/com.py +0 -0
  47. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/common.py +0 -0
  48. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/contact.py +0 -0
  49. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/data.py +0 -0
  50. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/frame.py +0 -0
  51. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/joint.py +0 -0
  52. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/kin_dyn_parameters.py +0 -0
  53. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/link.py +0 -0
  54. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/model.py +0 -0
  55. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/ode.py +0 -0
  56. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/ode_data.py +0 -0
  57. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/api/references.py +0 -0
  58. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/exceptions.py +0 -0
  59. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/integrators/__init__.py +0 -0
  60. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/integrators/common.py +0 -0
  61. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/integrators/fixed_step.py +0 -0
  62. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/integrators/variable_step.py +0 -0
  63. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/logging.py +0 -0
  64. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/__init__.py +0 -0
  65. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/adjoint.py +0 -0
  66. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/cross.py +0 -0
  67. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/inertia.py +0 -0
  68. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/joint_model.py +0 -0
  69. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/quaternion.py +0 -0
  70. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/rotation.py +0 -0
  71. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/skew.py +0 -0
  72. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/math/transform.py +0 -0
  73. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/mujoco/__init__.py +0 -0
  74. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/mujoco/__main__.py +0 -0
  75. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/mujoco/visualizer.py +0 -0
  76. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/__init__.py +0 -0
  77. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/descriptions/__init__.py +0 -0
  78. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/descriptions/collision.py +0 -0
  79. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/descriptions/joint.py +0 -0
  80. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/descriptions/link.py +0 -0
  81. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/descriptions/model.py +0 -0
  82. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/kinematic_graph.py +0 -0
  83. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/rod/__init__.py +0 -0
  84. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/rod/parser.py +0 -0
  85. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/parsers/rod/utils.py +0 -0
  86. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/__init__.py +0 -0
  87. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/aba.py +0 -0
  88. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/collidable_points.py +0 -0
  89. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/contacts/__init__.py +0 -0
  90. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/contacts/common.py +0 -0
  91. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/contacts/soft.py +0 -0
  92. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/crba.py +0 -0
  93. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/forward_kinematics.py +0 -0
  94. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/jacobian.py +0 -0
  95. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/rnea.py +0 -0
  96. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/rbda/utils.py +0 -0
  97. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/terrain/__init__.py +0 -0
  98. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/terrain/terrain.py +0 -0
  99. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/typing.py +0 -0
  100. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/utils/__init__.py +0 -0
  101. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/utils/jaxsim_dataclass.py +0 -0
  102. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/utils/tracing.py +0 -0
  103. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim/utils/wrappers.py +0 -0
  104. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim.egg-info/SOURCES.txt +0 -0
  105. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim.egg-info/dependency_links.txt +0 -0
  106. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim.egg-info/requires.txt +0 -0
  107. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/src/jaxsim.egg-info/top_level.txt +0 -0
  108. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/__init__.py +0 -0
  109. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/conftest.py +0 -0
  110. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_com.py +0 -0
  111. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_contact.py +0 -0
  112. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_data.py +0 -0
  113. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_frame.py +0 -0
  114. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_joint.py +0 -0
  115. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_link.py +0 -0
  116. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_api_model.py +0 -0
  117. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_automatic_differentiation.py +0 -0
  118. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_contact.py +0 -0
  119. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_exceptions.py +0 -0
  120. {jaxsim-0.4.1.dev6 → jaxsim-0.4.1.dev11}/tests/test_pytree.py +0 -0
  121. {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.dev6
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.dev6'
16
- __version_tuple__ = version_tuple = (0, 4, 1, 'dev6')
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 dictionary.
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="100",
408
- ncol="100",
409
- size="5 5 1 1",
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 XML description and an optional assets dictionary.
50
+ Build a Mujoco model from an MJCF description.
48
51
 
49
52
  Args:
50
- mjcf_description: A string containing the XML description of the Mujoco model
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: A function in two variables that returns the height of a terrain
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
- # Create the Mujoco model from the XML and, optionally, the assets dictionary.
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
- if heightmap:
71
- nrow = model.hfield_nrow.item()
72
- ncol = model.hfield_ncol.item()
73
- new_hfield = generate_hfield(heightmap, (nrow, ncol))
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, size: tuple[int, int] = (10, 10)
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
- Generates a numpy array representing the heightmap of
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: A function that takes two arguments (x, y) and returns the height
462
+ heightmap:
463
+ A function that takes two arguments (x, y) and returns the height
402
464
  at that point.
403
- size: A tuple of two integers representing the size of the grid.
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
- np.ndarray: The terrain heightmap
472
+ A flat array of the sampled terrain heightmap.
407
473
  """
408
474
 
409
475
  # Generate the grid.
410
- x = np.linspace(0, 1, size[0])
411
- y = np.linspace(0, 1, size[1])
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.dev6
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.rbda.contacts.soft import SoftContactsParams
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, subkey2 = jax.random.split(prng_key, num=3)
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(subkey2, shape=(3,)),
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
- references = references.apply_link_forces(
133
- forces=jnp.atleast_2d(L_f),
134
- link_names=model.link_names(),
135
- model=model,
136
- data=data0,
137
- additive=False,
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, integrator_state = js.model.step(
160
- model=model,
161
- data=data,
162
- dt=dt,
163
- integrator=integrator,
164
- integrator_state=integrator_state,
165
- link_forces=references.link_forces(model=model, data=data),
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 * L_f[:, :3].squeeze() / js.model.total_mass(model=model) * tf**2,
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