mujodico 3.15.0__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.
- mujodico-3.15.0/MANIFEST.in +1 -0
- mujodico-3.15.0/PKG-INFO +116 -0
- mujodico-3.15.0/README.md +81 -0
- mujodico-3.15.0/mujodico/examples/__main__.py +107 -0
- mujodico-3.15.0/mujodico/examples/methods/__init__.py +49 -0
- mujodico-3.15.0/mujodico/examples/methods/ipopt_contact_implicit_shooting.py +386 -0
- mujodico-3.15.0/mujodico/examples/methods/ipopt_lifted_multiple_shooting.py +68 -0
- mujodico-3.15.0/mujodico/examples/methods/ipopt_multiple_shooting.py +48 -0
- mujodico-3.15.0/mujodico/examples/methods/ipopt_single_shooting.py +134 -0
- mujodico-3.15.0/mujodico/examples/methods/ippas_lifted_multiple_shooting.py +110 -0
- mujodico-3.15.0/mujodico/examples/methods/support.py +159 -0
- mujodico-3.15.0/mujodico/examples/methods/transcription_lifted_multiple_shooting.py +108 -0
- mujodico-3.15.0/mujodico/examples/methods/transcription_multiple_shooting.py +76 -0
- mujodico-3.15.0/mujodico/examples/methods/transcription_single_shooting.py +86 -0
- mujodico-3.15.0/mujodico/examples/tasks/__init__.py +61 -0
- mujodico-3.15.0/mujodico/examples/tasks/allegro_ball.py +170 -0
- mujodico-3.15.0/mujodico/examples/tasks/allegro_cube.py +181 -0
- mujodico-3.15.0/mujodico/examples/tasks/allegro_pen.py +167 -0
- mujodico-3.15.0/mujodico/examples/tasks/finger_circular_knob.py +132 -0
- mujodico-3.15.0/mujodico/examples/tasks/fingers_sphere_2d.py +171 -0
- mujodico-3.15.0/mujodico/examples/tasks/plotly_util.py +100 -0
- mujodico-3.15.0/mujodico/examples/tasks/push_box_2d.py +150 -0
- mujodico-3.15.0/mujodico/examples/tasks/push_circular_knob.py +181 -0
- mujodico-3.15.0/mujodico/examples/tasks/push_multisphere_2d.py +166 -0
- mujodico-3.15.0/mujodico/examples/tasks/push_sphere_1d.py +122 -0
- mujodico-3.15.0/mujodico/examples/tasks/push_sphere_2d.py +150 -0
- mujodico-3.15.0/mujodico/examples/tasks/push_square_knob.py +181 -0
- mujodico-3.15.0/mujodico/examples/tasks/task.py +176 -0
- mujodico-3.15.0/mujodico/examples/visualizer.py +60 -0
- mujodico-3.15.0/mujodico/mjx/__init__.py +79 -0
- mujodico-3.15.0/mujodico/mjx/_src/__init__.py +14 -0
- mujodico-3.15.0/mujodico/mjx/_src/bvh.py +39 -0
- mujodico-3.15.0/mujodico/mjx/_src/collision_convex.py +1117 -0
- mujodico-3.15.0/mujodico/mjx/_src/collision_driver.py +461 -0
- mujodico-3.15.0/mujodico/mjx/_src/collision_driver_test.py +1113 -0
- mujodico-3.15.0/mujodico/mjx/_src/collision_primitive.py +405 -0
- mujodico-3.15.0/mujodico/mjx/_src/collision_primitive_test.py +182 -0
- mujodico-3.15.0/mujodico/mjx/_src/collision_sdf.py +275 -0
- mujodico-3.15.0/mujodico/mjx/_src/collision_types.py +79 -0
- mujodico-3.15.0/mujodico/mjx/_src/conic_solver.py +766 -0
- mujodico-3.15.0/mujodico/mjx/_src/conic_solver_test.py +142 -0
- mujodico-3.15.0/mujodico/mjx/_src/constraint.py +757 -0
- mujodico-3.15.0/mujodico/mjx/_src/constraint_test.py +178 -0
- mujodico-3.15.0/mujodico/mjx/_src/dataclasses.py +210 -0
- mujodico-3.15.0/mujodico/mjx/_src/dataclasses_test.py +117 -0
- mujodico-3.15.0/mujodico/mjx/_src/derivative.py +100 -0
- mujodico-3.15.0/mujodico/mjx/_src/forward.py +552 -0
- mujodico-3.15.0/mujodico/mjx/_src/forward_test.py +313 -0
- mujodico-3.15.0/mujodico/mjx/_src/inverse.py +112 -0
- mujodico-3.15.0/mujodico/mjx/_src/inverse_test.py +150 -0
- mujodico-3.15.0/mujodico/mjx/_src/io.py +1859 -0
- mujodico-3.15.0/mujodico/mjx/_src/io_test.py +1440 -0
- mujodico-3.15.0/mujodico/mjx/_src/math.py +394 -0
- mujodico-3.15.0/mujodico/mjx/_src/math_test.py +202 -0
- mujodico-3.15.0/mujodico/mjx/_src/mesh.py +337 -0
- mujodico-3.15.0/mujodico/mjx/_src/mesh_test.py +138 -0
- mujodico-3.15.0/mujodico/mjx/_src/passive.py +206 -0
- mujodico-3.15.0/mujodico/mjx/_src/passive_test.py +87 -0
- mujodico-3.15.0/mujodico/mjx/_src/ray.py +317 -0
- mujodico-3.15.0/mujodico/mjx/_src/ray_test.py +290 -0
- mujodico-3.15.0/mujodico/mjx/_src/render.py +82 -0
- mujodico-3.15.0/mujodico/mjx/_src/render_test.py +132 -0
- mujodico-3.15.0/mujodico/mjx/_src/render_util.py +150 -0
- mujodico-3.15.0/mujodico/mjx/_src/render_util_test.py +233 -0
- mujodico-3.15.0/mujodico/mjx/_src/scan.py +497 -0
- mujodico-3.15.0/mujodico/mjx/_src/scan_test.py +228 -0
- mujodico-3.15.0/mujodico/mjx/_src/sensor.py +789 -0
- mujodico-3.15.0/mujodico/mjx/_src/sensor_test.py +223 -0
- mujodico-3.15.0/mujodico/mjx/_src/smooth.py +1490 -0
- mujodico-3.15.0/mujodico/mjx/_src/smooth_test.py +449 -0
- mujodico-3.15.0/mujodico/mjx/_src/solver.py +610 -0
- mujodico-3.15.0/mujodico/mjx/_src/solver_conic.py +216 -0
- mujodico-3.15.0/mujodico/mjx/_src/solver_sap.py +953 -0
- mujodico-3.15.0/mujodico/mjx/_src/solver_sap_test.py +328 -0
- mujodico-3.15.0/mujodico/mjx/_src/solver_sap_util.py +143 -0
- mujodico-3.15.0/mujodico/mjx/_src/solver_test.py +169 -0
- mujodico-3.15.0/mujodico/mjx/_src/support.py +1153 -0
- mujodico-3.15.0/mujodico/mjx/_src/support_test.py +810 -0
- mujodico-3.15.0/mujodico/mjx/_src/test_util.py +488 -0
- mujodico-3.15.0/mujodico/mjx/_src/types.py +1249 -0
- mujodico-3.15.0/mujodico/mjx/integration_test/collision_driver_test.py +96 -0
- mujodico-3.15.0/mujodico/mjx/integration_test/forward_test.py +70 -0
- mujodico-3.15.0/mujodico/mjx/integration_test/smooth_test.py +95 -0
- mujodico-3.15.0/mujodico/mjx/test_data/actuator/arm21.xml +37 -0
- mujodico-3.15.0/mujodico/mjx/test_data/actuator/arm26.xml +118 -0
- mujodico-3.15.0/mujodico/mjx/test_data/actuator/general_dyntype.xml +18 -0
- mujodico-3.15.0/mujodico/mjx/test_data/actuator/tendon_force_clamp.xml +55 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/README.md +25 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/abduction.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/barkour_v0_mjx.xml +245 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/body.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/foot.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/handle.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/head.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/head_mount.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/hfield_240_280.png +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/lower_leg_1to1.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/powercable.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/upper_left_1.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/upper_left_2.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/upper_left_3.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/upper_right_1.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/upper_right_2.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/upper_right_3.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/constraints.xml +115 -0
- mujodico-3.15.0/mujodico/mjx/test_data/convex.xml +42 -0
- mujodico-3.15.0/mujodico/mjx/test_data/humanoid/01_humanoids.xml +150 -0
- mujodico-3.15.0/mujodico/mjx/test_data/humanoid/02_humanoids.xml +255 -0
- mujodico-3.15.0/mujodico/mjx/test_data/humanoid/03_humanoids.xml +359 -0
- mujodico-3.15.0/mujodico/mjx/test_data/humanoid/04_humanoids.xml +463 -0
- mujodico-3.15.0/mujodico/mjx/test_data/humanoid/05_humanoids.xml +567 -0
- mujodico-3.15.0/mujodico/mjx/test_data/humanoid/06_humanoids.xml +671 -0
- mujodico-3.15.0/mujodico/mjx/test_data/humanoid/07_humanoids.xml +775 -0
- mujodico-3.15.0/mujodico/mjx/test_data/humanoid/08_humanoids.xml +879 -0
- mujodico-3.15.0/mujodico/mjx/test_data/humanoid/09_humanoids.xml +983 -0
- mujodico-3.15.0/mujodico/mjx/test_data/humanoid/10_humanoids.xml +1087 -0
- mujodico-3.15.0/mujodico/mjx/test_data/humanoid/README.md +26 -0
- mujodico-3.15.0/mujodico/mjx/test_data/humanoid/humanoid.png +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/humanoid/humanoid.xml +262 -0
- mujodico-3.15.0/mujodico/mjx/test_data/meshes/dodecahedron.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/meshes/pyramid.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/meshes/tetrahedron.stl +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/pendula.xml +160 -0
- mujodico-3.15.0/mujodico/mjx/test_data/quadratic_frictionloss.xml +21 -0
- mujodico-3.15.0/mujodico/mjx/test_data/ray.xml +18 -0
- mujodico-3.15.0/mujodico/mjx/test_data/sensor/model.xml +74 -0
- mujodico-3.15.0/mujodico/mjx/test_data/sensor/sensor.xml +224 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/README.md +28 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/f_distal_pst.obj +10772 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/f_distal_pst_214.obj +326 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/f_knuckle.obj +1200 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/f_middle.obj +908 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/f_proximal.obj +2206 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/forearm_0.obj +2220 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/forearm_1.obj +37554 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/forearm_collision.obj +924 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/lf_metacarpal.obj +2996 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/mounting_plate.obj +3936 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/palm.obj +23598 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/th_distal_pst.obj +9528 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/th_distal_pst_190.obj +288 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/th_middle.obj +2544 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/th_proximal.obj +840 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/wrist.obj +3708 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/right_hand.xml +330 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/scene_right.xml +31 -0
- mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/shadow_hand.png +0 -0
- mujodico-3.15.0/mujodico/mjx/test_data/tendon/armature.xml +24 -0
- mujodico-3.15.0/mujodico/mjx/test_data/tendon/fixed.xml +23 -0
- mujodico-3.15.0/mujodico/mjx/test_data/tendon/fixed_site.xml +39 -0
- mujodico-3.15.0/mujodico/mjx/test_data/tendon/fixed_site_wrap.xml +58 -0
- mujodico-3.15.0/mujodico/mjx/test_data/tendon/no_tendon.xml +16 -0
- mujodico-3.15.0/mujodico/mjx/test_data/tendon/pulley_fixed_site_wrap.xml +103 -0
- mujodico-3.15.0/mujodico/mjx/test_data/tendon/pulley_site.xml +84 -0
- mujodico-3.15.0/mujodico/mjx/test_data/tendon/pulley_site_wrap.xml +98 -0
- mujodico-3.15.0/mujodico/mjx/test_data/tendon/pulley_wrap.xml +78 -0
- mujodico-3.15.0/mujodico/mjx/test_data/tendon/site.xml +26 -0
- mujodico-3.15.0/mujodico/mjx/test_data/tendon/site_wrap.xml +54 -0
- mujodico-3.15.0/mujodico/mjx/test_data/tendon/tendon.xml +66 -0
- mujodico-3.15.0/mujodico/mjx/test_data/tendon/wrap_sidesite.xml +61 -0
- mujodico-3.15.0/mujodico/mjx/testspeed.py +96 -0
- mujodico-3.15.0/mujodico/mjx/viewer.py +166 -0
- mujodico-3.15.0/mujodico/trajopt/__init__.py +7 -0
- mujodico-3.15.0/mujodico/trajopt/_src/fatrop_ref/__init__.py +12 -0
- mujodico-3.15.0/mujodico/trajopt/_src/fatrop_ref/fatrop_v43_runtime_patch.py +318 -0
- mujodico-3.15.0/mujodico/trajopt/_src/fatrop_ref/linear.py +273 -0
- mujodico-3.15.0/mujodico/trajopt/_src/fatrop_ref/linear_test.py +52 -0
- mujodico-3.15.0/mujodico/trajopt/_src/fatrop_ref/restoration_v32.py +959 -0
- mujodico-3.15.0/mujodico/trajopt/_src/fatrop_ref/solver.py +1474 -0
- mujodico-3.15.0/mujodico/trajopt/_src/ipopt_multiple_shooting_solver.py +513 -0
- mujodico-3.15.0/mujodico/trajopt/_src/prox_ddp.py +1049 -0
- mujodico-3.15.0/mujodico/trajopt/_src/prox_ddp_test.py +122 -0
- mujodico-3.15.0/mujodico.egg-info/PKG-INFO +116 -0
- mujodico-3.15.0/mujodico.egg-info/SOURCES.txt +178 -0
- mujodico-3.15.0/mujodico.egg-info/dependency_links.txt +1 -0
- mujodico-3.15.0/mujodico.egg-info/entry_points.txt +3 -0
- mujodico-3.15.0/mujodico.egg-info/requires.txt +14 -0
- mujodico-3.15.0/mujodico.egg-info/top_level.txt +1 -0
- mujodico-3.15.0/pyproject.toml +83 -0
- mujodico-3.15.0/setup.cfg +4 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
recursive-include mujodico/mjx/test_data *
|
mujodico-3.15.0/PKG-INFO
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mujodico
|
|
3
|
+
Version: 3.15.0
|
|
4
|
+
Summary: MuJoDiCo
|
|
5
|
+
Author-email: Wei-Chen Li <williamrob104@gmail.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/wei-chen-li/mujodico
|
|
8
|
+
Project-URL: Repository, https://github.com/wei-chen-li/mujodico
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Natural Language :: English
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
Requires-Dist: absl-py
|
|
24
|
+
Requires-Dist: etils[epath]
|
|
25
|
+
Requires-Dist: jax
|
|
26
|
+
Requires-Dist: jaxlib
|
|
27
|
+
Requires-Dist: mujoco>=3.15.0.dev0
|
|
28
|
+
Requires-Dist: scipy
|
|
29
|
+
Requires-Dist: trimesh
|
|
30
|
+
Provides-Extra: warp
|
|
31
|
+
Requires-Dist: warp-lang==1.17.0; extra == "warp"
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: isort; extra == "dev"
|
|
34
|
+
Requires-Dist: pyink; extra == "dev"
|
|
35
|
+
|
|
36
|
+
# MuJoDiCo (Multi-Joint dynamics with Differentiable Contact)
|
|
37
|
+
|
|
38
|
+
This package extends MuJoCo with differentiable contact dynamics and provides trajectory optimization algorithms for contact-rich dynamical systems. Gradients are computed using the implicit function theorem rather than differentiating through the solver rollout.
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
The recommended way to install this package is via [PyPI](https://pypi.org/project/mujodico/):
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
pip install mujodico
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
For local development, install from a checkout:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
git clone https://github.com/wei-chen-li/mujodico.git
|
|
52
|
+
cd mujodico
|
|
53
|
+
pip install -e .
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
[MuJoDiCo](https://github.com/wei-chen-li/mujodico) is a drop-in replacement for [MuJoCo MJX](https://mujoco.readthedocs.io/en/stable/mjx.html) that provides differentiable contact dynamics. You can simply replace `from mujoco import mjx` with `from mujodico import mjx`. For example:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import jax
|
|
62
|
+
import jax.numpy as jnp
|
|
63
|
+
import mujoco
|
|
64
|
+
from mujodico import mjx
|
|
65
|
+
|
|
66
|
+
model = mujoco.MjModel.from_xml_string(XML)
|
|
67
|
+
|
|
68
|
+
mjx_model = mjx.put_model(
|
|
69
|
+
model,
|
|
70
|
+
contact_approximation='Hunt-Crossley',
|
|
71
|
+
contact_smoothing=0.0,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def f(x, u):
|
|
75
|
+
nq, nv = mjx_model.nq, mjx_model.nv
|
|
76
|
+
d = mjx.make_data(mjx_model)
|
|
77
|
+
d = d.replace(qpos=x[:nq], qvel=x[nq:nq+nv], act=x[nq+nv:], ctrl=u)
|
|
78
|
+
d = mjx.step(mjx_model, d)
|
|
79
|
+
x_next = jnp.concatenate((d.qpos, d.qvel, d.act))
|
|
80
|
+
return x_next
|
|
81
|
+
|
|
82
|
+
x = jnp.zeros(mjx_model.nq + mjx_model.nv + mjx_model.na)
|
|
83
|
+
u = jnp.zeros(mjx_model.nu)
|
|
84
|
+
|
|
85
|
+
A, B = jax.jacfwd(f, argnums=(0,1))(x, u)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
MuJoDiCo computes dynamics Jacobian using the implicit function theorem. Both forward-mode (`jax.jacfwd`) and reverse-mode (`jax.jacrev`) differentiation are supported.
|
|
89
|
+
|
|
90
|
+
### Contact Modeling
|
|
91
|
+
|
|
92
|
+
MuJoDiCo provides configurable contact models through two parameters:
|
|
93
|
+
|
|
94
|
+
* **`contact_approximation`** — specifies the contact model used for the dynamics. `'Hunt-Crossley'` is recommended for most applications.
|
|
95
|
+
* **`contact_smoothing`** — adds artificial smoothing to the contact model to make the resulting dynamics **C¹-continuous**.
|
|
96
|
+
|
|
97
|
+
The `contact_smoothing=κ` parameter controls the amount of regularization. It can be interpreted as applying a force of κ newtons over a distance of 1 meter.
|
|
98
|
+
|
|
99
|
+
For forward simulation, where differentiability is not required, use `contact_smoothing=0.0`.
|
|
100
|
+
For trajectory optimization or other gradient-based methods that require C¹-continuous dynamics, `contact_smoothing=1e-5` is a good starting point, providing smooth dynamics while introducing relatively little unphysical behavior.
|
|
101
|
+
|
|
102
|
+
### Examples
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
python -m mujodico.examples --help
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Versioning
|
|
109
|
+
|
|
110
|
+
The `major.minor.micro` portion of the version number matches the version of MuJoCo. Optionally, if we release updates to MuJoDiCo that target the same version of MuJoCo, a `.postN` suffix is added, for example `3.0.1.post2` represents the second update to MuJoDiCo for MuJoCo 3.0.1.
|
|
111
|
+
|
|
112
|
+
## License and Disclaimer
|
|
113
|
+
|
|
114
|
+
MuJoDiCo is licensed under the Apache License, Version 2.0. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0.
|
|
115
|
+
|
|
116
|
+
This project includes code adapted from [MuJoCo](https://github.com/google-deepmind/mujoco), which is licensed under Apache License, Version 2.0. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# MuJoDiCo (Multi-Joint dynamics with Differentiable Contact)
|
|
2
|
+
|
|
3
|
+
This package extends MuJoCo with differentiable contact dynamics and provides trajectory optimization algorithms for contact-rich dynamical systems. Gradients are computed using the implicit function theorem rather than differentiating through the solver rollout.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
The recommended way to install this package is via [PyPI](https://pypi.org/project/mujodico/):
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pip install mujodico
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
For local development, install from a checkout:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
git clone https://github.com/wei-chen-li/mujodico.git
|
|
17
|
+
cd mujodico
|
|
18
|
+
pip install -e .
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
[MuJoDiCo](https://github.com/wei-chen-li/mujodico) is a drop-in replacement for [MuJoCo MJX](https://mujoco.readthedocs.io/en/stable/mjx.html) that provides differentiable contact dynamics. You can simply replace `from mujoco import mjx` with `from mujodico import mjx`. For example:
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
import jax
|
|
27
|
+
import jax.numpy as jnp
|
|
28
|
+
import mujoco
|
|
29
|
+
from mujodico import mjx
|
|
30
|
+
|
|
31
|
+
model = mujoco.MjModel.from_xml_string(XML)
|
|
32
|
+
|
|
33
|
+
mjx_model = mjx.put_model(
|
|
34
|
+
model,
|
|
35
|
+
contact_approximation='Hunt-Crossley',
|
|
36
|
+
contact_smoothing=0.0,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def f(x, u):
|
|
40
|
+
nq, nv = mjx_model.nq, mjx_model.nv
|
|
41
|
+
d = mjx.make_data(mjx_model)
|
|
42
|
+
d = d.replace(qpos=x[:nq], qvel=x[nq:nq+nv], act=x[nq+nv:], ctrl=u)
|
|
43
|
+
d = mjx.step(mjx_model, d)
|
|
44
|
+
x_next = jnp.concatenate((d.qpos, d.qvel, d.act))
|
|
45
|
+
return x_next
|
|
46
|
+
|
|
47
|
+
x = jnp.zeros(mjx_model.nq + mjx_model.nv + mjx_model.na)
|
|
48
|
+
u = jnp.zeros(mjx_model.nu)
|
|
49
|
+
|
|
50
|
+
A, B = jax.jacfwd(f, argnums=(0,1))(x, u)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
MuJoDiCo computes dynamics Jacobian using the implicit function theorem. Both forward-mode (`jax.jacfwd`) and reverse-mode (`jax.jacrev`) differentiation are supported.
|
|
54
|
+
|
|
55
|
+
### Contact Modeling
|
|
56
|
+
|
|
57
|
+
MuJoDiCo provides configurable contact models through two parameters:
|
|
58
|
+
|
|
59
|
+
* **`contact_approximation`** — specifies the contact model used for the dynamics. `'Hunt-Crossley'` is recommended for most applications.
|
|
60
|
+
* **`contact_smoothing`** — adds artificial smoothing to the contact model to make the resulting dynamics **C¹-continuous**.
|
|
61
|
+
|
|
62
|
+
The `contact_smoothing=κ` parameter controls the amount of regularization. It can be interpreted as applying a force of κ newtons over a distance of 1 meter.
|
|
63
|
+
|
|
64
|
+
For forward simulation, where differentiability is not required, use `contact_smoothing=0.0`.
|
|
65
|
+
For trajectory optimization or other gradient-based methods that require C¹-continuous dynamics, `contact_smoothing=1e-5` is a good starting point, providing smooth dynamics while introducing relatively little unphysical behavior.
|
|
66
|
+
|
|
67
|
+
### Examples
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
python -m mujodico.examples --help
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Versioning
|
|
74
|
+
|
|
75
|
+
The `major.minor.micro` portion of the version number matches the version of MuJoCo. Optionally, if we release updates to MuJoDiCo that target the same version of MuJoCo, a `.postN` suffix is added, for example `3.0.1.post2` represents the second update to MuJoDiCo for MuJoCo 3.0.1.
|
|
76
|
+
|
|
77
|
+
## License and Disclaimer
|
|
78
|
+
|
|
79
|
+
MuJoDiCo is licensed under the Apache License, Version 2.0. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0.
|
|
80
|
+
|
|
81
|
+
This project includes code adapted from [MuJoCo](https://github.com/google-deepmind/mujoco), which is licensed under Apache License, Version 2.0. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
import csv
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from absl import app
|
|
7
|
+
from absl import flags
|
|
8
|
+
import jax
|
|
9
|
+
from jax import numpy as jp
|
|
10
|
+
import mujoco
|
|
11
|
+
from mujodico import mjx
|
|
12
|
+
from mujodico.examples.methods import get_method_names, parse_method_name, support
|
|
13
|
+
from mujodico.examples.tasks import get_task_names, parse_task_name
|
|
14
|
+
from mujodico.examples.visualizer import Visualizer
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
_METHOD = flags.DEFINE_string(
|
|
19
|
+
'method',
|
|
20
|
+
None,
|
|
21
|
+
f'<{"|".join(get_method_names())}>\n(required)',
|
|
22
|
+
required=True,
|
|
23
|
+
)
|
|
24
|
+
_TASK = flags.DEFINE_string(
|
|
25
|
+
'task',
|
|
26
|
+
None,
|
|
27
|
+
f'<{"|".join(get_task_names())}>\n(required)',
|
|
28
|
+
required=True,
|
|
29
|
+
)
|
|
30
|
+
_ITERATIONS = flags.DEFINE_integer(
|
|
31
|
+
'iterations', 500, 'Number of solver iterations', lower_bound=0,
|
|
32
|
+
)
|
|
33
|
+
_TESTS = flags.DEFINE_integer(
|
|
34
|
+
'tests', 1, 'Number of test cases to run.', lower_bound=1,
|
|
35
|
+
)
|
|
36
|
+
_SEED = flags.DEFINE_integer(
|
|
37
|
+
'seed', 0, 'Random seed for tests.',
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _main(argv) -> None:
|
|
42
|
+
if len(argv) > 1:
|
|
43
|
+
raise app.UsageError('Too many command-line arguments.')
|
|
44
|
+
|
|
45
|
+
method_cls = parse_method_name(_METHOD.value)
|
|
46
|
+
task_cls = parse_task_name(_TASK.value)
|
|
47
|
+
|
|
48
|
+
result_dir = Path(__file__).resolve().parent / 'result'
|
|
49
|
+
result_dir.mkdir(exist_ok=True)
|
|
50
|
+
result_file = result_dir / f'{task_cls.__name__}_{method_cls.__name__}.csv'
|
|
51
|
+
print(f'Writing results to "{result_file}"')
|
|
52
|
+
|
|
53
|
+
with open(result_file, 'a', newline='') as f:
|
|
54
|
+
writer = csv.writer(f)
|
|
55
|
+
if f.tell() == 0:
|
|
56
|
+
writer.writerow(['seed', 'goal_error', 'solve_time_sec', 'solver_iters'])
|
|
57
|
+
|
|
58
|
+
visualizer = Visualizer()
|
|
59
|
+
visualizer.run()
|
|
60
|
+
|
|
61
|
+
method = None
|
|
62
|
+
for seed in range(_SEED.value, _SEED.value + _TESTS.value):
|
|
63
|
+
task = task_cls(seed)
|
|
64
|
+
if method is None:
|
|
65
|
+
method = method_cls(task)
|
|
66
|
+
elif hasattr(method, 'update'):
|
|
67
|
+
method.update(task)
|
|
68
|
+
else:
|
|
69
|
+
method = method_cls(task)
|
|
70
|
+
|
|
71
|
+
iters = _ITERATIONS.value
|
|
72
|
+
|
|
73
|
+
tic = time.perf_counter()
|
|
74
|
+
|
|
75
|
+
traj = method.solve(
|
|
76
|
+
traj_init={
|
|
77
|
+
'xs': task.xs_init,
|
|
78
|
+
'us': task.us_init,
|
|
79
|
+
},
|
|
80
|
+
iterations=iters,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
solve_time = time.perf_counter() - tic
|
|
84
|
+
|
|
85
|
+
goal_error = support.state_cost(
|
|
86
|
+
task.Q, task.x_goal, traj['xs'][-1], task.quaternion_w_idxs
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
writer.writerow([seed, goal_error, solve_time, iters])
|
|
90
|
+
f.flush()
|
|
91
|
+
|
|
92
|
+
traj['info'] = f'''
|
|
93
|
+
- Task: {task_cls.__name__}(seed={seed})
|
|
94
|
+
- goal error: {goal_error:.8f}
|
|
95
|
+
- Method: {method_cls.__name__}
|
|
96
|
+
- solve time: {solve_time:.4f} sec
|
|
97
|
+
- iterations: {iters}
|
|
98
|
+
'''
|
|
99
|
+
visualizer.update(task, traj)
|
|
100
|
+
|
|
101
|
+
if _TESTS.value == 1:
|
|
102
|
+
while True:
|
|
103
|
+
time.sleep(3600)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
if __name__ == '__main__':
|
|
107
|
+
app.run(_main)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from mujodico.examples.methods.ipopt_contact_implicit_shooting import IpoptContactImplicitShooting
|
|
2
|
+
from mujodico.examples.methods.ipopt_lifted_multiple_shooting import IpoptLiftedMultipleShooting
|
|
3
|
+
from mujodico.examples.methods.ipopt_multiple_shooting import IpoptMultipleShooting
|
|
4
|
+
from mujodico.trajopt._src.ipopt_multiple_shooting_solver import IpoptMultipleShootingSolver
|
|
5
|
+
from mujodico.examples.methods.ipopt_single_shooting import IpoptSingleShooting
|
|
6
|
+
from mujodico.examples.methods.ippas_lifted_multiple_shooting import IppasLiftedMultipleShooting
|
|
7
|
+
from mujodico.examples.methods.transcription_lifted_multiple_shooting import LiftedMultipleShootingTranscription
|
|
8
|
+
from mujodico.examples.methods.transcription_multiple_shooting import MultipleShootingTranscription
|
|
9
|
+
from mujodico.examples.methods.transcription_single_shooting import SingleShootingTranscription
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
'IpoptContactImplicitShooting',
|
|
14
|
+
'IpoptLiftedMultipleShooting',
|
|
15
|
+
'IpoptMultipleShooting',
|
|
16
|
+
'IpoptMultipleShootingSolver',
|
|
17
|
+
'IpoptSingleShooting',
|
|
18
|
+
'IppasLiftedMultipleShooting',
|
|
19
|
+
'LiftedMultipleShootingTranscription',
|
|
20
|
+
'MultipleShootingTranscription',
|
|
21
|
+
'SingleShootingTranscription',
|
|
22
|
+
'get_method_names',
|
|
23
|
+
'parse_method_name',
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
_METHODS = [
|
|
28
|
+
IpoptContactImplicitShooting,
|
|
29
|
+
IpoptLiftedMultipleShooting,
|
|
30
|
+
IpoptMultipleShooting,
|
|
31
|
+
IpoptSingleShooting,
|
|
32
|
+
IppasLiftedMultipleShooting,
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_method_names():
|
|
37
|
+
return [method.__name__ for method in _METHODS]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def parse_method_name(name: str):
|
|
41
|
+
name = name.lower().strip().translate(str.maketrans('', '', ' -_'))
|
|
42
|
+
|
|
43
|
+
for method in _METHODS:
|
|
44
|
+
if name == method.__name__.lower():
|
|
45
|
+
return method
|
|
46
|
+
|
|
47
|
+
raise ValueError(
|
|
48
|
+
f'unknown method: value should be one of <{"|".join(get_method_names())}>'
|
|
49
|
+
)
|