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 +2 -2
- jaxsim/api/model.py +12 -1
- jaxsim/mujoco/loaders.py +33 -7
- jaxsim/mujoco/model.py +43 -2
- jaxsim/terrain/__init__.py +1 -1
- {jaxsim-0.2.dev366.dist-info → jaxsim-0.2.dev376.dist-info}/METADATA +1 -1
- {jaxsim-0.2.dev366.dist-info → jaxsim-0.2.dev376.dist-info}/RECORD +10 -10
- {jaxsim-0.2.dev366.dist-info → jaxsim-0.2.dev376.dist-info}/LICENSE +0 -0
- {jaxsim-0.2.dev366.dist-info → jaxsim-0.2.dev376.dist-info}/WHEEL +0 -0
- {jaxsim-0.2.dev366.dist-info → jaxsim-0.2.dev376.dist-info}/top_level.txt +0 -0
jaxsim/_version.py
CHANGED
@@ -12,5 +12,5 @@ __version__: str
|
|
12
12
|
__version_tuple__: VERSION_TUPLE
|
13
13
|
version_tuple: VERSION_TUPLE
|
14
14
|
|
15
|
-
__version__ = version = '0.2.
|
16
|
-
__version_tuple__ = version_tuple = (0, 2, '
|
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,
|
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
|
416
|
-
|
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,
|
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,
|
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,
|
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()
|
jaxsim/terrain/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
from . import terrain
|
2
|
-
from .terrain import FlatTerrain, Terrain
|
2
|
+
from .terrain import FlatTerrain, PlaneTerrain, Terrain
|
@@ -1,5 +1,5 @@
|
|
1
1
|
jaxsim/__init__.py,sha256=OcrfoYS1DGcmAGqu2AqlCTiUVxcpi-IsVwcr_16x74Q,1789
|
2
|
-
jaxsim/_version.py,sha256=
|
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=
|
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=
|
33
|
-
jaxsim/mujoco/model.py,sha256=
|
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=
|
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.
|
61
|
-
jaxsim-0.2.
|
62
|
-
jaxsim-0.2.
|
63
|
-
jaxsim-0.2.
|
64
|
-
jaxsim-0.2.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|