jaxsim 0.2.dev366__py3-none-any.whl → 0.2.dev376__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 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.dev366'
16
- __version_tuple__ = version_tuple = (0, 2, 'dev366')
15
+ __version__ = version = '0.2.dev376'
16
+ __version_tuple__ = version_tuple = (0, 2, 'dev376')
jaxsim/api/model.py CHANGED
@@ -52,6 +52,8 @@ class JaxSimModel(JaxsimDataclass):
52
52
  def build_from_model_description(
53
53
  model_description: str | pathlib.Path | rod.Model,
54
54
  model_name: str | None = None,
55
+ *,
56
+ terrain: jaxsim.terrain.Terrain | None = None,
55
57
  is_urdf: bool | None = None,
56
58
  considered_joints: list[str] | None = None,
57
59
  ) -> JaxSimModel:
@@ -65,6 +67,8 @@ class JaxSimModel(JaxsimDataclass):
65
67
  model_name:
66
68
  The optional name of the model that overrides the one in
67
69
  the description.
70
+ terrain:
71
+ The optional terrain to consider.
68
72
  is_urdf:
69
73
  Whether the model description is a URDF or an SDF. This is
70
74
  automatically inferred if the model description is a path to a file.
@@ -92,7 +96,9 @@ class JaxSimModel(JaxsimDataclass):
92
96
 
93
97
  # Build the model
94
98
  model = JaxSimModel.build(
95
- model_description=intermediate_description, model_name=model_name
99
+ model_description=intermediate_description,
100
+ model_name=model_name,
101
+ terrain=terrain,
96
102
  )
97
103
 
98
104
  # Store the origin of the model, in case downstream logic needs it
@@ -105,6 +111,8 @@ class JaxSimModel(JaxsimDataclass):
105
111
  def build(
106
112
  model_description: jaxsim.parsers.descriptions.ModelDescription,
107
113
  model_name: str | None = None,
114
+ *,
115
+ terrain: jaxsim.terrain.Terrain | None = None,
108
116
  ) -> JaxSimModel:
109
117
  """
110
118
  Build a Model object from an intermediate model description.
@@ -115,6 +123,8 @@ class JaxSimModel(JaxsimDataclass):
115
123
  of the model.
116
124
  model_name:
117
125
  The optional name of the model overriding the physics model name.
126
+ terrain:
127
+ The optional terrain to consider.
118
128
 
119
129
  Returns:
120
130
  The built Model object.
@@ -130,6 +140,7 @@ class JaxSimModel(JaxsimDataclass):
130
140
  kin_dyn_parameters=js.kin_dyn_parameters.KynDynParameters.build(
131
141
  model_description=model_description
132
142
  ),
143
+ terrain=terrain or JaxSimModel.__dataclass_fields__["terrain"].default,
133
144
  )
134
145
 
135
146
  return model
jaxsim/mujoco/loaders.py CHANGED
@@ -129,6 +129,8 @@ class RodModelToMjcf:
129
129
  def convert(
130
130
  rod_model: rod.Model,
131
131
  considered_joints: list[str] | None = None,
132
+ plane_normal: tuple[float, float, float] = (0, 0, 1),
133
+ heightmap: bool | None = None,
132
134
  ) -> tuple[str, dict[str, Any]]:
133
135
  """"""
134
136
 
@@ -198,8 +200,6 @@ class RodModelToMjcf:
198
200
  )
199
201
 
200
202
  urdf_string = ET.tostring(root, pretty_print=True).decode()
201
- # print(urdf_string)
202
- # raise
203
203
 
204
204
  # ------------------------------
205
205
  # Post-process all dummy visuals
@@ -358,6 +358,19 @@ class RodModelToMjcf:
358
358
  texuniform="true",
359
359
  )
360
360
 
361
+ _ = (
362
+ ET.SubElement(
363
+ asset_element,
364
+ "hfield",
365
+ name="terrain",
366
+ nrow="100",
367
+ ncol="100",
368
+ size="5 5 1 1",
369
+ )
370
+ if heightmap
371
+ else None
372
+ )
373
+
361
374
  # ----------------------------------
362
375
  # Populate the scene with the assets
363
376
  # ----------------------------------
@@ -368,12 +381,14 @@ class RodModelToMjcf:
368
381
  worldbody_scene_element,
369
382
  "geom",
370
383
  name="floor",
371
- type="plane",
384
+ type="plane" if not heightmap else "hfield",
372
385
  size="0 0 0.05",
373
386
  material="plane_material",
374
387
  condim="3",
375
388
  contype="1",
376
389
  conaffinity="1",
390
+ zaxis=" ".join(map(str, plane_normal)),
391
+ **({"hfield": "terrain"} if heightmap else {}),
377
392
  )
378
393
 
379
394
  _ = ET.SubElement(
@@ -407,13 +422,14 @@ class RodModelToMjcf:
407
422
  raise RuntimeError("Failed to find the <worldbody> element of the model")
408
423
 
409
424
  # Camera attached to the model
425
+ # It can be manually copied from `python -m mujoco.viewer --mjcf=<URDF_PATH>`
410
426
  _ = ET.SubElement(
411
427
  worldbody_element,
412
428
  "camera",
413
429
  name="track",
414
430
  mode="trackcom",
415
- pos="1 0 5",
416
- zaxis="0 0 1",
431
+ pos="1.930 -2.279 0.556",
432
+ xyaxes="0.771 0.637 0.000 -0.116 0.140 0.983",
417
433
  fovy="60",
418
434
  )
419
435
 
@@ -449,6 +465,8 @@ class UrdfToMjcf:
449
465
  urdf: str | pathlib.Path,
450
466
  considered_joints: list[str] | None = None,
451
467
  model_name: str | None = None,
468
+ plane_normal: tuple[float, float, float] = (0, 0, 1),
469
+ heightmap: bool | None = None,
452
470
  ) -> tuple[str, dict[str, Any]]:
453
471
  """"""
454
472
 
@@ -461,7 +479,10 @@ class UrdfToMjcf:
461
479
 
462
480
  # Convert the ROD model to MJCF.
463
481
  return RodModelToMjcf.convert(
464
- rod_model=rod_model, considered_joints=considered_joints
482
+ rod_model=rod_model,
483
+ considered_joints=considered_joints,
484
+ plane_normal=plane_normal,
485
+ heightmap=heightmap,
465
486
  )
466
487
 
467
488
 
@@ -471,6 +492,8 @@ class SdfToMjcf:
471
492
  sdf: str | pathlib.Path,
472
493
  considered_joints: list[str] | None = None,
473
494
  model_name: str | None = None,
495
+ plane_normal: tuple[float, float, float] = (0, 0, 1),
496
+ heightmap: bool | None = None,
474
497
  ) -> tuple[str, dict[str, Any]]:
475
498
  """"""
476
499
 
@@ -483,5 +506,8 @@ class SdfToMjcf:
483
506
 
484
507
  # Convert the ROD model to MJCF.
485
508
  return RodModelToMjcf.convert(
486
- rod_model=rod_model, considered_joints=considered_joints
509
+ rod_model=rod_model,
510
+ considered_joints=considered_joints,
511
+ plane_normal=plane_normal,
512
+ heightmap=heightmap,
487
513
  )
jaxsim/mujoco/model.py CHANGED
@@ -1,12 +1,14 @@
1
1
  import functools
2
2
  import pathlib
3
- from typing import Any
3
+ from typing import Any, Callable
4
4
 
5
5
  import mujoco as mj
6
6
  import numpy as np
7
7
  import numpy.typing as npt
8
8
  from scipy.spatial.transform import Rotation
9
9
 
10
+ HeightmapCallable = Callable[[jtp.FloatLike, jtp.FloatLike], jtp.FloatLike]
11
+
10
12
 
11
13
  class MujocoModelHelper:
12
14
  """
@@ -27,7 +29,9 @@ class MujocoModelHelper:
27
29
 
28
30
  @staticmethod
29
31
  def build_from_xml(
30
- mjcf_description: str | pathlib.Path, assets: dict[str, Any] = None
32
+ mjcf_description: str | pathlib.Path,
33
+ assets: dict[str, Any] = None,
34
+ heightmap: HeightmapCallable | None = None,
31
35
  ) -> "MujocoModelHelper":
32
36
  """"""
33
37
 
@@ -40,6 +44,13 @@ class MujocoModelHelper:
40
44
 
41
45
  # Create the Mujoco model from the XML and, optionally, the assets dictionary
42
46
  model = mj.MjModel.from_xml_string(xml=mjcf_description, assets=assets) # noqa
47
+ data = mj.MjData(model)
48
+
49
+ if heightmap:
50
+ nrow = model.hfield_nrow.item()
51
+ ncol = model.hfield_ncol.item()
52
+ new_hfield = generate_hfield(heightmap, (nrow, ncol))
53
+ model.hfield_data = new_hfield
43
54
 
44
55
  return MujocoModelHelper(model=model, data=mj.MjData(model))
45
56
 
@@ -350,3 +361,33 @@ class MujocoModelHelper:
350
361
  ]
351
362
  ).squeeze()
352
363
  )
364
+
365
+
366
+ def generate_hfield(
367
+ heightmap: HeightmapCallable, size: tuple[int, int] = (10, 10)
368
+ ) -> npt.NDArray:
369
+ """
370
+ Generates a numpy array representing the heightmap of
371
+ The map will have the following format:
372
+ ```
373
+ heightmap[0, 0] heightmap[0, 1] ... heightmap[0, size[1]-1]
374
+ heightmap[1, 0] heightmap[1, 1] ... heightmap[1, size[1]-1]
375
+ ...
376
+ heightmap[size[0]-1, 0] heightmap[size[0]-1, 1] ... heightmap[size[0]-1, size[1]-1]
377
+ ```
378
+
379
+ Args:
380
+ heightmap: A function that takes two arguments (x, y) and returns the height
381
+ at that point.
382
+ size: A tuple of two integers representing the size of the grid.
383
+
384
+ Returns:
385
+ np.ndarray: The terrain heightmap
386
+ """
387
+
388
+ # Generate the grid.
389
+ x = np.linspace(0, 1, size[0])
390
+ y = np.linspace(0, 1, size[1])
391
+
392
+ # Generate the heightmap.
393
+ return np.array([[heightmap(xi, yi) for xi in x] for yi in y]).flatten()
@@ -1,2 +1,2 @@
1
1
  from . import terrain
2
- from .terrain import FlatTerrain, Terrain
2
+ from .terrain import FlatTerrain, PlaneTerrain, Terrain
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jaxsim
3
- Version: 0.2.dev366
3
+ Version: 0.2.dev376
4
4
  Summary: A physics engine in reduced coordinates implemented with JAX.
5
5
  Home-page: https://github.com/ami-iit/jaxsim
6
6
  Author: Diego Ferigo
@@ -1,5 +1,5 @@
1
1
  jaxsim/__init__.py,sha256=OcrfoYS1DGcmAGqu2AqlCTiUVxcpi-IsVwcr_16x74Q,1789
2
- jaxsim/_version.py,sha256=ncT8dupmzd5NQtuHjYN5ljex6-14cJKuIIfJTJVSFHw,423
2
+ jaxsim/_version.py,sha256=nAy-z_b2P4v0CvZeZkkzcsMlBO4LKnDdLnFE2Kq0a4U,423
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=1AJyKjmXdsWEf_CkvOXRmvRsDZamG706mAAg1Gttll0,26773
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=LZVcQhQsTKsfR13KewFtEMYu4siVJl7mqoDwYsoFFes,9240
13
- jaxsim/api/model.py,sha256=mFdEwVuzIR7Lvj4oiIsA1n1oxpRZXWyB0IDzIxcG33Q,43689
13
+ jaxsim/api/model.py,sha256=_waDChFZsHRbKOX6dkajRQxGkhqXFRMiMp3JXMqZ-MU,44089
14
14
  jaxsim/api/ode.py,sha256=rbSruK0Dkp09oBgHbB_-NrZS4o2tY9geK0yLLJfXzpM,9821
15
15
  jaxsim/api/ode_data.py,sha256=dwRFVPJ30XMmdUbPXEu7YxsQ97jZP4L4fd5ZzhrO5Ys,22184
16
16
  jaxsim/api/references.py,sha256=Lvskf17r619KKxwCJP7hAAty2kaXgDXJX1uKqoDIDgo,15483
@@ -29,8 +29,8 @@ jaxsim/math/skew.py,sha256=oOGSSR8PUGROl6IJFlrmu6K3gPH-u16hUPfKIkcVv9o,1177
29
29
  jaxsim/math/transform.py,sha256=nqH6ofde6VWjfHihmYdXvDxKFChpOPH6AsoqkUI1Og0,2928
30
30
  jaxsim/mujoco/__init__.py,sha256=Zo5GAlN1DYKvX8s1hu1j6HntKIbBMLB9Puv9ouaNAZ8,158
31
31
  jaxsim/mujoco/__main__.py,sha256=GBmB7J-zj75ZnFyuAAmpSOpbxi_HhHhWJeot3ljGDJY,5291
32
- jaxsim/mujoco/loaders.py,sha256=8sXc_tsDFWBYl8nesgFarYd3hA-PESLMrXsnR3Siz1Y,16400
33
- jaxsim/mujoco/model.py,sha256=0kG2GERxjVFqWZ1K3352rgUNfchB4kRtIrsvv4pS4oc,10766
32
+ jaxsim/mujoco/loaders.py,sha256=IGhchLIzINXDm8nDIsy1qIrffoiOpr8Hs36JTOOYVhg,17392
33
+ jaxsim/mujoco/model.py,sha256=GgDlr7fSSEnkyqziPLLQaippMr4wRhfTo39DstD9Qik,12088
34
34
  jaxsim/mujoco/visualizer.py,sha256=-qg26t5tleTva6zzQmc5SdnlC8XZ1ZAwZ_lDjdwHJ0A,4400
35
35
  jaxsim/parsers/__init__.py,sha256=sonYi-bBWAoB04kp1mxT4uIORxjb7SdZ0ukGPmVx98Y,44
36
36
  jaxsim/parsers/kinematic_graph.py,sha256=2B5gtUboiSVJIm6PegbwHb5g_iXltG0R9_7h8RJ-92M,23785
@@ -51,14 +51,14 @@ jaxsim/rbda/jacobian.py,sha256=9LGGy9ya5m5U0mBmV1NFH5XYZpEMYbx74qnYBvZs7Ok,6360
51
51
  jaxsim/rbda/rnea.py,sha256=DjwkvXQVUSUclM3Uy3UPZ2tao91R5dGd4o7TsS2qObI,7650
52
52
  jaxsim/rbda/soft_contacts.py,sha256=2EZ9Lw4nFWqXTMEeYsirl17H61s82SmTZllKVsP1Yek,10759
53
53
  jaxsim/rbda/utils.py,sha256=zpbFM2Iq8cntku0BFVu9nfEqZhInCWi9D2INT6MFEI8,5003
54
- jaxsim/terrain/__init__.py,sha256=dzekq9yyj3DKTsCARteqc81lAw3OSnl6EhXn8_Q_ozI,64
54
+ 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
58
  jaxsim/utils/jaxsim_dataclass.py,sha256=9FtzgXQPSa6AN26FleDgXGsJMse4dtVACDESrn0g3bw,11359
59
59
  jaxsim/utils/tracing.py,sha256=KDMoyVPlu2NJvFkhtZwq5AkqMMgajt3munvJom-vEjQ,650
60
- jaxsim-0.2.dev366.dist-info/LICENSE,sha256=EsU2z6_sWW4Zduzq3goVWjZoCZVKQsM4H_y0o7oRA7Q,1547
61
- jaxsim-0.2.dev366.dist-info/METADATA,sha256=D-Ca1OQtpKyTen4FF58yJK_FdC9iAA2yYZj85blGCHg,7630
62
- jaxsim-0.2.dev366.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
63
- jaxsim-0.2.dev366.dist-info/top_level.txt,sha256=LxGMA8FLtXjQ6oI7N5gd_R_oSUHxpXxUEOfT1xS_ni0,7
64
- jaxsim-0.2.dev366.dist-info/RECORD,,
60
+ jaxsim-0.2.dev376.dist-info/LICENSE,sha256=EsU2z6_sWW4Zduzq3goVWjZoCZVKQsM4H_y0o7oRA7Q,1547
61
+ jaxsim-0.2.dev376.dist-info/METADATA,sha256=eWcinEhSdothvx37-yafMhBddfT5s0fIo4veqCLNnI8,7630
62
+ jaxsim-0.2.dev376.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
63
+ jaxsim-0.2.dev376.dist-info/top_level.txt,sha256=LxGMA8FLtXjQ6oI7N5gd_R_oSUHxpXxUEOfT1xS_ni0,7
64
+ jaxsim-0.2.dev376.dist-info/RECORD,,