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.
Files changed (180) hide show
  1. mujodico-3.15.0/MANIFEST.in +1 -0
  2. mujodico-3.15.0/PKG-INFO +116 -0
  3. mujodico-3.15.0/README.md +81 -0
  4. mujodico-3.15.0/mujodico/examples/__main__.py +107 -0
  5. mujodico-3.15.0/mujodico/examples/methods/__init__.py +49 -0
  6. mujodico-3.15.0/mujodico/examples/methods/ipopt_contact_implicit_shooting.py +386 -0
  7. mujodico-3.15.0/mujodico/examples/methods/ipopt_lifted_multiple_shooting.py +68 -0
  8. mujodico-3.15.0/mujodico/examples/methods/ipopt_multiple_shooting.py +48 -0
  9. mujodico-3.15.0/mujodico/examples/methods/ipopt_single_shooting.py +134 -0
  10. mujodico-3.15.0/mujodico/examples/methods/ippas_lifted_multiple_shooting.py +110 -0
  11. mujodico-3.15.0/mujodico/examples/methods/support.py +159 -0
  12. mujodico-3.15.0/mujodico/examples/methods/transcription_lifted_multiple_shooting.py +108 -0
  13. mujodico-3.15.0/mujodico/examples/methods/transcription_multiple_shooting.py +76 -0
  14. mujodico-3.15.0/mujodico/examples/methods/transcription_single_shooting.py +86 -0
  15. mujodico-3.15.0/mujodico/examples/tasks/__init__.py +61 -0
  16. mujodico-3.15.0/mujodico/examples/tasks/allegro_ball.py +170 -0
  17. mujodico-3.15.0/mujodico/examples/tasks/allegro_cube.py +181 -0
  18. mujodico-3.15.0/mujodico/examples/tasks/allegro_pen.py +167 -0
  19. mujodico-3.15.0/mujodico/examples/tasks/finger_circular_knob.py +132 -0
  20. mujodico-3.15.0/mujodico/examples/tasks/fingers_sphere_2d.py +171 -0
  21. mujodico-3.15.0/mujodico/examples/tasks/plotly_util.py +100 -0
  22. mujodico-3.15.0/mujodico/examples/tasks/push_box_2d.py +150 -0
  23. mujodico-3.15.0/mujodico/examples/tasks/push_circular_knob.py +181 -0
  24. mujodico-3.15.0/mujodico/examples/tasks/push_multisphere_2d.py +166 -0
  25. mujodico-3.15.0/mujodico/examples/tasks/push_sphere_1d.py +122 -0
  26. mujodico-3.15.0/mujodico/examples/tasks/push_sphere_2d.py +150 -0
  27. mujodico-3.15.0/mujodico/examples/tasks/push_square_knob.py +181 -0
  28. mujodico-3.15.0/mujodico/examples/tasks/task.py +176 -0
  29. mujodico-3.15.0/mujodico/examples/visualizer.py +60 -0
  30. mujodico-3.15.0/mujodico/mjx/__init__.py +79 -0
  31. mujodico-3.15.0/mujodico/mjx/_src/__init__.py +14 -0
  32. mujodico-3.15.0/mujodico/mjx/_src/bvh.py +39 -0
  33. mujodico-3.15.0/mujodico/mjx/_src/collision_convex.py +1117 -0
  34. mujodico-3.15.0/mujodico/mjx/_src/collision_driver.py +461 -0
  35. mujodico-3.15.0/mujodico/mjx/_src/collision_driver_test.py +1113 -0
  36. mujodico-3.15.0/mujodico/mjx/_src/collision_primitive.py +405 -0
  37. mujodico-3.15.0/mujodico/mjx/_src/collision_primitive_test.py +182 -0
  38. mujodico-3.15.0/mujodico/mjx/_src/collision_sdf.py +275 -0
  39. mujodico-3.15.0/mujodico/mjx/_src/collision_types.py +79 -0
  40. mujodico-3.15.0/mujodico/mjx/_src/conic_solver.py +766 -0
  41. mujodico-3.15.0/mujodico/mjx/_src/conic_solver_test.py +142 -0
  42. mujodico-3.15.0/mujodico/mjx/_src/constraint.py +757 -0
  43. mujodico-3.15.0/mujodico/mjx/_src/constraint_test.py +178 -0
  44. mujodico-3.15.0/mujodico/mjx/_src/dataclasses.py +210 -0
  45. mujodico-3.15.0/mujodico/mjx/_src/dataclasses_test.py +117 -0
  46. mujodico-3.15.0/mujodico/mjx/_src/derivative.py +100 -0
  47. mujodico-3.15.0/mujodico/mjx/_src/forward.py +552 -0
  48. mujodico-3.15.0/mujodico/mjx/_src/forward_test.py +313 -0
  49. mujodico-3.15.0/mujodico/mjx/_src/inverse.py +112 -0
  50. mujodico-3.15.0/mujodico/mjx/_src/inverse_test.py +150 -0
  51. mujodico-3.15.0/mujodico/mjx/_src/io.py +1859 -0
  52. mujodico-3.15.0/mujodico/mjx/_src/io_test.py +1440 -0
  53. mujodico-3.15.0/mujodico/mjx/_src/math.py +394 -0
  54. mujodico-3.15.0/mujodico/mjx/_src/math_test.py +202 -0
  55. mujodico-3.15.0/mujodico/mjx/_src/mesh.py +337 -0
  56. mujodico-3.15.0/mujodico/mjx/_src/mesh_test.py +138 -0
  57. mujodico-3.15.0/mujodico/mjx/_src/passive.py +206 -0
  58. mujodico-3.15.0/mujodico/mjx/_src/passive_test.py +87 -0
  59. mujodico-3.15.0/mujodico/mjx/_src/ray.py +317 -0
  60. mujodico-3.15.0/mujodico/mjx/_src/ray_test.py +290 -0
  61. mujodico-3.15.0/mujodico/mjx/_src/render.py +82 -0
  62. mujodico-3.15.0/mujodico/mjx/_src/render_test.py +132 -0
  63. mujodico-3.15.0/mujodico/mjx/_src/render_util.py +150 -0
  64. mujodico-3.15.0/mujodico/mjx/_src/render_util_test.py +233 -0
  65. mujodico-3.15.0/mujodico/mjx/_src/scan.py +497 -0
  66. mujodico-3.15.0/mujodico/mjx/_src/scan_test.py +228 -0
  67. mujodico-3.15.0/mujodico/mjx/_src/sensor.py +789 -0
  68. mujodico-3.15.0/mujodico/mjx/_src/sensor_test.py +223 -0
  69. mujodico-3.15.0/mujodico/mjx/_src/smooth.py +1490 -0
  70. mujodico-3.15.0/mujodico/mjx/_src/smooth_test.py +449 -0
  71. mujodico-3.15.0/mujodico/mjx/_src/solver.py +610 -0
  72. mujodico-3.15.0/mujodico/mjx/_src/solver_conic.py +216 -0
  73. mujodico-3.15.0/mujodico/mjx/_src/solver_sap.py +953 -0
  74. mujodico-3.15.0/mujodico/mjx/_src/solver_sap_test.py +328 -0
  75. mujodico-3.15.0/mujodico/mjx/_src/solver_sap_util.py +143 -0
  76. mujodico-3.15.0/mujodico/mjx/_src/solver_test.py +169 -0
  77. mujodico-3.15.0/mujodico/mjx/_src/support.py +1153 -0
  78. mujodico-3.15.0/mujodico/mjx/_src/support_test.py +810 -0
  79. mujodico-3.15.0/mujodico/mjx/_src/test_util.py +488 -0
  80. mujodico-3.15.0/mujodico/mjx/_src/types.py +1249 -0
  81. mujodico-3.15.0/mujodico/mjx/integration_test/collision_driver_test.py +96 -0
  82. mujodico-3.15.0/mujodico/mjx/integration_test/forward_test.py +70 -0
  83. mujodico-3.15.0/mujodico/mjx/integration_test/smooth_test.py +95 -0
  84. mujodico-3.15.0/mujodico/mjx/test_data/actuator/arm21.xml +37 -0
  85. mujodico-3.15.0/mujodico/mjx/test_data/actuator/arm26.xml +118 -0
  86. mujodico-3.15.0/mujodico/mjx/test_data/actuator/general_dyntype.xml +18 -0
  87. mujodico-3.15.0/mujodico/mjx/test_data/actuator/tendon_force_clamp.xml +55 -0
  88. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/README.md +25 -0
  89. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/abduction.stl +0 -0
  90. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/barkour_v0_mjx.xml +245 -0
  91. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/body.stl +0 -0
  92. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/foot.stl +0 -0
  93. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/handle.stl +0 -0
  94. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/head.stl +0 -0
  95. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/head_mount.stl +0 -0
  96. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/hfield_240_280.png +0 -0
  97. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/lower_leg_1to1.stl +0 -0
  98. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/powercable.stl +0 -0
  99. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/upper_left_1.stl +0 -0
  100. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/upper_left_2.stl +0 -0
  101. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/upper_left_3.stl +0 -0
  102. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/upper_right_1.stl +0 -0
  103. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/upper_right_2.stl +0 -0
  104. mujodico-3.15.0/mujodico/mjx/test_data/barkour_v0/assets/upper_right_3.stl +0 -0
  105. mujodico-3.15.0/mujodico/mjx/test_data/constraints.xml +115 -0
  106. mujodico-3.15.0/mujodico/mjx/test_data/convex.xml +42 -0
  107. mujodico-3.15.0/mujodico/mjx/test_data/humanoid/01_humanoids.xml +150 -0
  108. mujodico-3.15.0/mujodico/mjx/test_data/humanoid/02_humanoids.xml +255 -0
  109. mujodico-3.15.0/mujodico/mjx/test_data/humanoid/03_humanoids.xml +359 -0
  110. mujodico-3.15.0/mujodico/mjx/test_data/humanoid/04_humanoids.xml +463 -0
  111. mujodico-3.15.0/mujodico/mjx/test_data/humanoid/05_humanoids.xml +567 -0
  112. mujodico-3.15.0/mujodico/mjx/test_data/humanoid/06_humanoids.xml +671 -0
  113. mujodico-3.15.0/mujodico/mjx/test_data/humanoid/07_humanoids.xml +775 -0
  114. mujodico-3.15.0/mujodico/mjx/test_data/humanoid/08_humanoids.xml +879 -0
  115. mujodico-3.15.0/mujodico/mjx/test_data/humanoid/09_humanoids.xml +983 -0
  116. mujodico-3.15.0/mujodico/mjx/test_data/humanoid/10_humanoids.xml +1087 -0
  117. mujodico-3.15.0/mujodico/mjx/test_data/humanoid/README.md +26 -0
  118. mujodico-3.15.0/mujodico/mjx/test_data/humanoid/humanoid.png +0 -0
  119. mujodico-3.15.0/mujodico/mjx/test_data/humanoid/humanoid.xml +262 -0
  120. mujodico-3.15.0/mujodico/mjx/test_data/meshes/dodecahedron.stl +0 -0
  121. mujodico-3.15.0/mujodico/mjx/test_data/meshes/pyramid.stl +0 -0
  122. mujodico-3.15.0/mujodico/mjx/test_data/meshes/tetrahedron.stl +0 -0
  123. mujodico-3.15.0/mujodico/mjx/test_data/pendula.xml +160 -0
  124. mujodico-3.15.0/mujodico/mjx/test_data/quadratic_frictionloss.xml +21 -0
  125. mujodico-3.15.0/mujodico/mjx/test_data/ray.xml +18 -0
  126. mujodico-3.15.0/mujodico/mjx/test_data/sensor/model.xml +74 -0
  127. mujodico-3.15.0/mujodico/mjx/test_data/sensor/sensor.xml +224 -0
  128. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/README.md +28 -0
  129. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/f_distal_pst.obj +10772 -0
  130. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/f_distal_pst_214.obj +326 -0
  131. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/f_knuckle.obj +1200 -0
  132. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/f_middle.obj +908 -0
  133. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/f_proximal.obj +2206 -0
  134. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/forearm_0.obj +2220 -0
  135. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/forearm_1.obj +37554 -0
  136. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/forearm_collision.obj +924 -0
  137. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/lf_metacarpal.obj +2996 -0
  138. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/mounting_plate.obj +3936 -0
  139. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/palm.obj +23598 -0
  140. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/th_distal_pst.obj +9528 -0
  141. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/th_distal_pst_190.obj +288 -0
  142. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/th_middle.obj +2544 -0
  143. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/th_proximal.obj +840 -0
  144. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/assets/wrist.obj +3708 -0
  145. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/right_hand.xml +330 -0
  146. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/scene_right.xml +31 -0
  147. mujodico-3.15.0/mujodico/mjx/test_data/shadow_hand/shadow_hand.png +0 -0
  148. mujodico-3.15.0/mujodico/mjx/test_data/tendon/armature.xml +24 -0
  149. mujodico-3.15.0/mujodico/mjx/test_data/tendon/fixed.xml +23 -0
  150. mujodico-3.15.0/mujodico/mjx/test_data/tendon/fixed_site.xml +39 -0
  151. mujodico-3.15.0/mujodico/mjx/test_data/tendon/fixed_site_wrap.xml +58 -0
  152. mujodico-3.15.0/mujodico/mjx/test_data/tendon/no_tendon.xml +16 -0
  153. mujodico-3.15.0/mujodico/mjx/test_data/tendon/pulley_fixed_site_wrap.xml +103 -0
  154. mujodico-3.15.0/mujodico/mjx/test_data/tendon/pulley_site.xml +84 -0
  155. mujodico-3.15.0/mujodico/mjx/test_data/tendon/pulley_site_wrap.xml +98 -0
  156. mujodico-3.15.0/mujodico/mjx/test_data/tendon/pulley_wrap.xml +78 -0
  157. mujodico-3.15.0/mujodico/mjx/test_data/tendon/site.xml +26 -0
  158. mujodico-3.15.0/mujodico/mjx/test_data/tendon/site_wrap.xml +54 -0
  159. mujodico-3.15.0/mujodico/mjx/test_data/tendon/tendon.xml +66 -0
  160. mujodico-3.15.0/mujodico/mjx/test_data/tendon/wrap_sidesite.xml +61 -0
  161. mujodico-3.15.0/mujodico/mjx/testspeed.py +96 -0
  162. mujodico-3.15.0/mujodico/mjx/viewer.py +166 -0
  163. mujodico-3.15.0/mujodico/trajopt/__init__.py +7 -0
  164. mujodico-3.15.0/mujodico/trajopt/_src/fatrop_ref/__init__.py +12 -0
  165. mujodico-3.15.0/mujodico/trajopt/_src/fatrop_ref/fatrop_v43_runtime_patch.py +318 -0
  166. mujodico-3.15.0/mujodico/trajopt/_src/fatrop_ref/linear.py +273 -0
  167. mujodico-3.15.0/mujodico/trajopt/_src/fatrop_ref/linear_test.py +52 -0
  168. mujodico-3.15.0/mujodico/trajopt/_src/fatrop_ref/restoration_v32.py +959 -0
  169. mujodico-3.15.0/mujodico/trajopt/_src/fatrop_ref/solver.py +1474 -0
  170. mujodico-3.15.0/mujodico/trajopt/_src/ipopt_multiple_shooting_solver.py +513 -0
  171. mujodico-3.15.0/mujodico/trajopt/_src/prox_ddp.py +1049 -0
  172. mujodico-3.15.0/mujodico/trajopt/_src/prox_ddp_test.py +122 -0
  173. mujodico-3.15.0/mujodico.egg-info/PKG-INFO +116 -0
  174. mujodico-3.15.0/mujodico.egg-info/SOURCES.txt +178 -0
  175. mujodico-3.15.0/mujodico.egg-info/dependency_links.txt +1 -0
  176. mujodico-3.15.0/mujodico.egg-info/entry_points.txt +3 -0
  177. mujodico-3.15.0/mujodico.egg-info/requires.txt +14 -0
  178. mujodico-3.15.0/mujodico.egg-info/top_level.txt +1 -0
  179. mujodico-3.15.0/pyproject.toml +83 -0
  180. mujodico-3.15.0/setup.cfg +4 -0
@@ -0,0 +1 @@
1
+ recursive-include mujodico/mjx/test_data *
@@ -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
+ )