jaxsim 0.7.1.dev49__tar.gz → 0.7.1.dev53__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 (137) hide show
  1. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/PKG-INFO +1 -1
  2. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/examples/assets/cartpole.urdf +12 -0
  3. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/_version.py +2 -2
  4. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/contact.py +39 -23
  5. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/kin_dyn_parameters.py +97 -1
  6. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/model.py +22 -1
  7. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/math/rotation.py +14 -0
  8. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/mujoco/loaders.py +28 -1
  9. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/__init__.py +6 -0
  10. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/contacts/common.py +17 -11
  11. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/contacts/relaxed_rigid.py +125 -16
  12. jaxsim-0.7.1.dev53/src/jaxsim/rbda/kinematic_constraints.py +148 -0
  13. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim.egg-info/PKG-INFO +1 -1
  14. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim.egg-info/SOURCES.txt +3 -1
  15. jaxsim-0.7.1.dev53/tests/assets/double_pendulum.sdf +172 -0
  16. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/conftest.py +47 -0
  17. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_simulations.py +143 -0
  18. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/.devcontainer/Dockerfile +0 -0
  19. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/.devcontainer/devcontainer.json +0 -0
  20. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/.gitattributes +0 -0
  21. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/.github/CODEOWNERS +0 -0
  22. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/.github/dependabot.yml +0 -0
  23. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/.github/release.yml +0 -0
  24. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/.github/workflows/ci_cd.yml +0 -0
  25. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/.github/workflows/gpu_benchmark.yml +0 -0
  26. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/.github/workflows/pixi.yml +0 -0
  27. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/.github/workflows/read_the_docs.yml +0 -0
  28. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/.gitignore +0 -0
  29. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/.pre-commit-config.yaml +0 -0
  30. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/.readthedocs.yaml +0 -0
  31. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/CONTRIBUTING.md +0 -0
  32. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/LICENSE +0 -0
  33. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/README.md +0 -0
  34. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/Makefile +0 -0
  35. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/conf.py +0 -0
  36. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/examples.rst +0 -0
  37. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/guide/configuration.rst +0 -0
  38. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/guide/install.rst +0 -0
  39. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/index.rst +0 -0
  40. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/make.bat +0 -0
  41. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/modules/api.rst +0 -0
  42. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/modules/math.rst +0 -0
  43. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/modules/mujoco.rst +0 -0
  44. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/modules/parsers.rst +0 -0
  45. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/modules/rbda.rst +0 -0
  46. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/modules/typing.rst +0 -0
  47. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/docs/modules/utils.rst +0 -0
  48. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/environment.yml +0 -0
  49. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/examples/.gitattributes +0 -0
  50. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/examples/.gitignore +0 -0
  51. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/examples/README.md +0 -0
  52. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/examples/assets/build_cartpole_urdf.py +0 -0
  53. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/examples/jaxsim_as_multibody_dynamics_library.ipynb +0 -0
  54. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/examples/jaxsim_as_physics_engine.ipynb +0 -0
  55. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/examples/jaxsim_as_physics_engine_advanced.ipynb +0 -0
  56. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/examples/jaxsim_for_robot_controllers.ipynb +0 -0
  57. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/pixi.lock +0 -0
  58. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/pyproject.toml +0 -0
  59. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/setup.cfg +0 -0
  60. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/__init__.py +0 -0
  61. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/__init__.py +0 -0
  62. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/actuation_model.py +0 -0
  63. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/com.py +0 -0
  64. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/common.py +0 -0
  65. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/data.py +0 -0
  66. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/frame.py +0 -0
  67. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/integrators.py +0 -0
  68. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/joint.py +0 -0
  69. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/link.py +0 -0
  70. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/ode.py +0 -0
  71. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/api/references.py +0 -0
  72. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/exceptions.py +0 -0
  73. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/logging.py +0 -0
  74. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/math/__init__.py +0 -0
  75. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/math/adjoint.py +0 -0
  76. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/math/cross.py +0 -0
  77. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/math/inertia.py +0 -0
  78. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/math/joint_model.py +0 -0
  79. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/math/quaternion.py +0 -0
  80. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/math/skew.py +0 -0
  81. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/math/transform.py +0 -0
  82. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/math/utils.py +0 -0
  83. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/mujoco/__init__.py +0 -0
  84. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/mujoco/__main__.py +0 -0
  85. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/mujoco/model.py +0 -0
  86. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/mujoco/utils.py +0 -0
  87. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/mujoco/visualizer.py +0 -0
  88. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/parsers/__init__.py +0 -0
  89. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/parsers/descriptions/__init__.py +0 -0
  90. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/parsers/descriptions/collision.py +0 -0
  91. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/parsers/descriptions/joint.py +0 -0
  92. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/parsers/descriptions/link.py +0 -0
  93. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/parsers/descriptions/model.py +0 -0
  94. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/parsers/kinematic_graph.py +0 -0
  95. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/parsers/rod/__init__.py +0 -0
  96. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/parsers/rod/meshes.py +0 -0
  97. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/parsers/rod/parser.py +0 -0
  98. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/parsers/rod/utils.py +0 -0
  99. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/aba.py +0 -0
  100. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/actuation/__init__.py +0 -0
  101. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/actuation/common.py +0 -0
  102. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/collidable_points.py +0 -0
  103. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/contacts/__init__.py +0 -0
  104. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/contacts/rigid.py +0 -0
  105. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/contacts/soft.py +0 -0
  106. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/crba.py +0 -0
  107. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/forward_kinematics.py +0 -0
  108. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/jacobian.py +0 -0
  109. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/rnea.py +0 -0
  110. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/rbda/utils.py +0 -0
  111. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/terrain/__init__.py +0 -0
  112. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/terrain/terrain.py +0 -0
  113. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/typing.py +0 -0
  114. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/utils/__init__.py +0 -0
  115. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/utils/jaxsim_dataclass.py +0 -0
  116. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/utils/tracing.py +0 -0
  117. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim/utils/wrappers.py +0 -0
  118. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim.egg-info/dependency_links.txt +0 -0
  119. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim.egg-info/requires.txt +0 -0
  120. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/src/jaxsim.egg-info/top_level.txt +0 -0
  121. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/__init__.py +0 -0
  122. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_actuation.py +0 -0
  123. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_api_com.py +0 -0
  124. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_api_contact.py +0 -0
  125. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_api_data.py +0 -0
  126. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_api_frame.py +0 -0
  127. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_api_joint.py +0 -0
  128. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_api_link.py +0 -0
  129. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_api_model.py +0 -0
  130. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_api_model_hw_parametrization.py +0 -0
  131. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_automatic_differentiation.py +0 -0
  132. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_benchmark.py +0 -0
  133. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_exceptions.py +0 -0
  134. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_meshes.py +0 -0
  135. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_pytree.py +0 -0
  136. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/test_visualizer.py +0 -0
  137. {jaxsim-0.7.1.dev49 → jaxsim-0.7.1.dev53}/tests/utils_idyntree.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jaxsim
3
- Version: 0.7.1.dev49
3
+ Version: 0.7.1.dev53
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>, Filippo Luca Ferretti <filippoluca.ferretti@outlook.com>
6
6
  Maintainer-email: Filippo Luca Ferretti <filippo.ferretti@iit.it>, Alessandro Croci <alessandro.croci@iit.it>
@@ -58,6 +58,18 @@
58
58
  </geometry>
59
59
  </collision>
60
60
  </link>
61
+ <link name="cart_frame"/>
62
+ <link name="rail_frame"/>
63
+ <joint name="cart_frame_joint" type="fixed">
64
+ <parent link="cart" />
65
+ <child link="cart_frame" />
66
+ <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
67
+ </joint>
68
+ <joint name="rail_frame_joint" type="fixed">
69
+ <parent link="rail" />
70
+ <child link="rail_frame" />
71
+ <origin xyz="0.0 0.0 1.2" rpy="0.0 0.0 0.0" />
72
+ </joint>
61
73
  <joint name="world_to_rail" type="fixed">
62
74
  <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
63
75
  <parent link="world"/>
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.7.1.dev49'
21
- __version_tuple__ = version_tuple = (0, 7, 1, 'dev49')
20
+ __version__ = version = '0.7.1.dev53'
21
+ __version_tuple__ = version_tuple = (0, 7, 1, 'dev53')
@@ -191,39 +191,22 @@ def estimate_good_contact_parameters(
191
191
  The user is encouraged to fine-tune the parameters based on the
192
192
  specific application.
193
193
  """
194
-
195
- def estimate_model_height(model: js.model.JaxSimModel) -> jtp.Float:
196
- """
197
- Displacement between the CoM and the lowest collidable point using zero
198
- joint positions.
199
- """
200
-
201
- zero_data = js.data.JaxSimModelData.build(
202
- model=model,
203
- )
204
-
194
+ if max_penetration is None:
195
+ zero_data = js.data.JaxSimModelData.build(model=model)
205
196
  W_pz_CoM = js.com.com_position(model=model, data=zero_data)[2]
206
-
207
197
  if model.floating_base():
208
198
  W_pz_C = collidable_point_positions(model=model, data=zero_data)[:, -1]
209
- return 2 * (W_pz_CoM - W_pz_C.min())
210
-
211
- return 2 * W_pz_CoM
199
+ W_pz_CoM = W_pz_CoM - W_pz_C.min()
212
200
 
213
- max_δ = (
214
- max_penetration
215
- if max_penetration is not None
216
- # Consider as default a 0.5% of the model height.
217
- else 0.005 * estimate_model_height(model=model)
218
- )
201
+ # Consider as default a 1% of the model center of mass height.
202
+ max_penetration = 0.01 * W_pz_CoM
219
203
 
220
204
  nc = number_of_active_collidable_points_steady_state
221
-
222
205
  return model.contact_model._parameters_class().build_default_from_jaxsim_model(
223
206
  model=model,
224
207
  standard_gravity=standard_gravity,
225
208
  static_friction_coefficient=static_friction_coefficient,
226
- max_penetration=max_δ,
209
+ max_penetration=max_penetration,
227
210
  number_of_active_collidable_points_steady_state=nc,
228
211
  damping_ratio=damping_ratio,
229
212
  )
@@ -569,6 +552,39 @@ def link_contact_forces(
569
552
  # to the frames associated to the collidable points.
570
553
  W_f_L = link_forces_from_contact_forces(model=model, contact_forces=W_f_C)
571
554
 
555
+ # Process constraint wrenches if present.
556
+ if "constr_wrenches_inertial" in aux_dict:
557
+ wrench_pair_constr_inertial = aux_dict["constr_wrenches_inertial"]
558
+
559
+ # Retrieve the constraint map from the model's kinematic parameters.
560
+ constraint_map = model.kin_dyn_parameters.constraints
561
+
562
+ # Extract the frame indices of the constraints.
563
+ frame_idxs_1 = constraint_map.frame_idxs_1
564
+ frame_idxs_2 = constraint_map.frame_idxs_2
565
+
566
+ n_kin_constraints = frame_idxs_1.shape[0]
567
+
568
+ if n_kin_constraints > 0:
569
+ parent_link_indices = jax.vmap(
570
+ lambda frame_idx_1, frame_idx_2: jnp.array(
571
+ (
572
+ js.frame.idx_of_parent_link(model, frame_index=frame_idx_1),
573
+ js.frame.idx_of_parent_link(model, frame_index=frame_idx_2),
574
+ )
575
+ )
576
+ )(frame_idxs_1, frame_idxs_2)
577
+
578
+ # Apply each constraint wrench to its corresponding parent link in W_f_L.
579
+ def apply_wrench(W_f_L, parent_indices, wrench_pair):
580
+ W_f_L = W_f_L.at[parent_indices[0]].add(wrench_pair[0])
581
+ W_f_L = W_f_L.at[parent_indices[1]].add(wrench_pair[1])
582
+ return W_f_L
583
+
584
+ W_f_L = jax.vmap(apply_wrench, in_axes=(None, 0, 0))(
585
+ W_f_L, parent_link_indices, wrench_pair_constr_inertial
586
+ ).sum(axis=0)
587
+
572
588
  return W_f_L, aux_dict
573
589
 
574
590
 
@@ -34,6 +34,7 @@ class KinDynParameters(JaxsimDataclass):
34
34
  joint_model: The joint model of the model.
35
35
  joint_parameters: The parameters of the joints.
36
36
  hw_link_metadata: The hardware parameters of the model links.
37
+ constraints: The kinematic constraints of the model. They can be used only with Relaxed-Rigid contact model.
37
38
  """
38
39
 
39
40
  # Static
@@ -58,6 +59,9 @@ class KinDynParameters(JaxsimDataclass):
58
59
  # Model hardware parameters
59
60
  hw_link_metadata: HwLinkMetadata | None = dataclasses.field(default=None)
60
61
 
62
+ # Kinematic constraints
63
+ constraints: ConstraintMap | None = dataclasses.field(default=None)
64
+
61
65
  @property
62
66
  def motion_subspaces(self) -> jtp.Matrix:
63
67
  r"""
@@ -80,12 +84,15 @@ class KinDynParameters(JaxsimDataclass):
80
84
  return self._support_body_array_bool.get()
81
85
 
82
86
  @staticmethod
83
- def build(model_description: ModelDescription) -> KinDynParameters:
87
+ def build(
88
+ model_description: ModelDescription, constraints: ConstraintMap | None
89
+ ) -> KinDynParameters:
84
90
  """
85
91
  Construct the kinematic and dynamic parameters of the model.
86
92
 
87
93
  Args:
88
94
  model_description: The parsed model description to consider.
95
+ constraints: An object of type ConstraintMap specifying the kinematic constraint of the model.
89
96
 
90
97
  Returns:
91
98
  The kinematic and dynamic parameters of the model.
@@ -253,6 +260,12 @@ class KinDynParameters(JaxsimDataclass):
253
260
 
254
261
  motion_subspaces = jnp.vstack([jnp.zeros((6, 1))[jnp.newaxis, ...], S_J])
255
262
 
263
+ # ===========
264
+ # Constraints
265
+ # ===========
266
+
267
+ constraints = ConstraintMap() if constraints is None else constraints
268
+
256
269
  # =================================
257
270
  # Build and return KinDynParameters
258
271
  # =================================
@@ -267,6 +280,7 @@ class KinDynParameters(JaxsimDataclass):
267
280
  joint_parameters=joint_parameters,
268
281
  contact_parameters=contact_parameters,
269
282
  frame_parameters=frame_parameters,
283
+ constraints=constraints,
270
284
  )
271
285
 
272
286
  def __eq__(self, other: KinDynParameters) -> bool:
@@ -1168,3 +1182,85 @@ class ScalingFactors(JaxsimDataclass):
1168
1182
 
1169
1183
  dims: jtp.Vector
1170
1184
  density: jtp.Float
1185
+
1186
+
1187
+ @dataclasses.dataclass(frozen=True)
1188
+ class ConstraintType:
1189
+ """
1190
+ Enumeration of all supported constraint types.
1191
+ """
1192
+
1193
+ Weld: ClassVar[int] = 0
1194
+ # TODO: handle Connect constraint
1195
+ # Connect: ClassVar[int] = 1
1196
+
1197
+
1198
+ @jax_dataclasses.pytree_dataclass
1199
+ class ConstraintMap(JaxsimDataclass):
1200
+ """
1201
+ Class storing the kinematic constraints of a model.
1202
+ """
1203
+
1204
+ frame_idxs_1: jtp.Int = dataclasses.field(
1205
+ default_factory=lambda: jnp.array([], dtype=int)
1206
+ )
1207
+ frame_idxs_2: jtp.Int = dataclasses.field(
1208
+ default_factory=lambda: jnp.array([], dtype=int)
1209
+ )
1210
+ constraint_types: jtp.Int = dataclasses.field(
1211
+ default_factory=lambda: jnp.array([], dtype=int)
1212
+ )
1213
+ K_P: jtp.Float = dataclasses.field(
1214
+ default_factory=lambda: jnp.array([], dtype=float)
1215
+ )
1216
+ K_D: jtp.Float = dataclasses.field(
1217
+ default_factory=lambda: jnp.array([], dtype=float)
1218
+ )
1219
+
1220
+ def add_constraint(
1221
+ self,
1222
+ frame_idx_1: int,
1223
+ frame_idx_2: int,
1224
+ constraint_type: int,
1225
+ K_P: float | None = None,
1226
+ K_D: float | None = None,
1227
+ ) -> ConstraintMap:
1228
+ """
1229
+ Add a constraint to the constraint map.
1230
+
1231
+ Args:
1232
+ frame_idx_1: The index of the first frame.
1233
+ frame_idx_2: The index of the second frame.
1234
+ constraint_type: The type of constraint.
1235
+ K_P: The proportional gain for Baumgarte stabilization (default: 1000).
1236
+ K_D: The derivative gain for Baumgarte stabilization (default: 2 * sqrt(K_P)).
1237
+
1238
+ Returns:
1239
+ A new ConstraintMap instance with the added constraint.
1240
+
1241
+ Note:
1242
+ Since this method returns a new instance of ConstraintMap with the new constraint,
1243
+ it will trigger recompilations in JIT-compiled functions.
1244
+ """
1245
+
1246
+ # Set default values for Baumgarte coefficients if not provided
1247
+ if K_P is None:
1248
+ K_P = 1000
1249
+ if K_D is None:
1250
+ K_D = 2 * np.sqrt(K_P)
1251
+
1252
+ # Create new arrays with the input elements appended
1253
+ new_frame_idxs_1 = jnp.append(self.frame_idxs_1, frame_idx_1)
1254
+ new_frame_idxs2 = jnp.append(self.frame_idxs_2, frame_idx_2)
1255
+ new_constraint_types = jnp.append(self.constraint_types, constraint_type)
1256
+ new_K_P = jnp.append(self.K_P, K_P)
1257
+ new_K_D = jnp.append(self.K_D, K_D)
1258
+
1259
+ # Return a new ConstraintMap object with updated attributes
1260
+ return ConstraintMap(
1261
+ frame_idxs_1=new_frame_idxs_1,
1262
+ frame_idxs_2=new_frame_idxs2,
1263
+ constraint_types=new_constraint_types,
1264
+ K_P=new_K_P,
1265
+ K_D=new_K_D,
1266
+ )
@@ -141,6 +141,7 @@ class JaxSimModel(JaxsimDataclass):
141
141
  is_urdf: bool | None = None,
142
142
  considered_joints: Sequence[str] | None = None,
143
143
  gravity: jtp.FloatLike = jaxsim.math.STANDARD_GRAVITY,
144
+ constraints: jaxsim.rbda.kinematic_constraints.ConstraintMap | None = None,
144
145
  ) -> JaxSimModel:
145
146
  """
146
147
  Build a Model object from a model description.
@@ -167,6 +168,9 @@ class JaxSimModel(JaxsimDataclass):
167
168
  considered_joints:
168
169
  The list of joints to consider. If None, all joints are considered.
169
170
  gravity: The gravity constant. Normally passed as a positive value.
171
+ constraints:
172
+ An object of type ConstraintMap containing the kinematic constraints to consider. If None, no constraints are considered.
173
+ Note that constraints can be used only with RelaxedRigidContacts.
170
174
 
171
175
  Returns:
172
176
  The built Model object.
@@ -198,6 +202,7 @@ class JaxSimModel(JaxsimDataclass):
198
202
  contact_params=contact_params,
199
203
  integrator=integrator,
200
204
  gravity=-gravity,
205
+ constraints=constraints,
201
206
  )
202
207
 
203
208
  # Store the origin of the model, in case downstream logic needs it.
@@ -225,6 +230,7 @@ class JaxSimModel(JaxsimDataclass):
225
230
  actuation_params: jaxsim.rbda.actuation.ActuationParams | None = None,
226
231
  integrator: IntegratorType | None = None,
227
232
  gravity: jtp.FloatLike = jaxsim.math.STANDARD_GRAVITY,
233
+ constraints: jaxsim.rbda.kinematic_constraints.ConstraintMap | None = None,
228
234
  ) -> JaxSimModel:
229
235
  """
230
236
  Build a Model object from an intermediate model description.
@@ -247,6 +253,8 @@ class JaxSimModel(JaxsimDataclass):
247
253
  actuation_params: The parameters of the actuation model.
248
254
  integrator: The integrator to use for the simulation.
249
255
  gravity: The gravity constant.
256
+ constraints:
257
+ An object of type ConstraintMap containing the kinematic constraints to consider. If None, no constraints are considered.
250
258
 
251
259
  Returns:
252
260
  The built Model object.
@@ -278,6 +286,14 @@ class JaxSimModel(JaxsimDataclass):
278
286
  else jaxsim.rbda.contacts.RelaxedRigidContacts.build()
279
287
  )
280
288
 
289
+ if constraints is not None and not isinstance(
290
+ contact_model, jaxsim.rbda.contacts.RelaxedRigidContacts
291
+ ):
292
+ constraints = None
293
+ logging.warning(
294
+ f"Contact model {contact_model.__class__.__name__} does not support kinematic constraints. Use RelaxedRigidContacts instead."
295
+ )
296
+
281
297
  if contact_params is None:
282
298
  contact_params = contact_model._parameters_class()
283
299
 
@@ -295,7 +311,7 @@ class JaxSimModel(JaxsimDataclass):
295
311
  model = cls(
296
312
  model_name=model_name,
297
313
  kin_dyn_parameters=js.kin_dyn_parameters.KinDynParameters.build(
298
- model_description=model_description
314
+ model_description=model_description, constraints=constraints
299
315
  ),
300
316
  time_step=time_step,
301
317
  terrain=terrain,
@@ -777,6 +793,7 @@ def reduce(
777
793
  actuation_params=model.actuation_params,
778
794
  gravity=model.gravity,
779
795
  integrator=model.integrator,
796
+ constraints=model.kin_dyn_parameters.constraints,
780
797
  )
781
798
 
782
799
  with reduced_model.mutable_context(mutability=Mutability.MUTABLE_NO_VALIDATION):
@@ -2330,7 +2347,11 @@ def update_hw_parameters(
2330
2347
 
2331
2348
  Returns:
2332
2349
  The updated JaxSimModel object with modified hardware parameters.
2350
+
2351
+ Note:
2352
+ This function can be used only with models using Relax-Rigid contact model.
2333
2353
  """
2354
+
2334
2355
  kin_dyn_params: KinDynParameters = model.kin_dyn_parameters
2335
2356
  link_parameters: LinkParameters = kin_dyn_params.link_parameters
2336
2357
  hw_link_metadata: HwLinkMetadata = kin_dyn_params.hw_link_metadata
@@ -82,3 +82,17 @@ class Rotation:
82
82
  R = c * jnp.eye(3) - s * Skew.wedge(u) + c1 * u @ u.T
83
83
 
84
84
  return R.transpose()
85
+
86
+ @staticmethod
87
+ def log_vee(R: jnp.ndarray) -> jtp.Vector:
88
+ """
89
+ Compute the logarithm map of an SO(3) rotation matrix.
90
+
91
+ Args:
92
+ R: The SO(3) rotation matrix.
93
+
94
+ Returns:
95
+ The corresponding so(3) tangent vector.
96
+ """
97
+
98
+ return jaxlie.SO3.from_matrix(R).log()
@@ -5,6 +5,7 @@ import warnings
5
5
  from collections.abc import Sequence
6
6
  from typing import Any
7
7
 
8
+ import jaxlie
8
9
  import mujoco as mj
9
10
  import numpy as np
10
11
  import rod.urdf.exporter
@@ -279,11 +280,13 @@ class RodModelToMjcf:
279
280
  # Add a floating joint if floating-base
280
281
  # -------------------------------------
281
282
 
283
+ base_link_name = rod_model.get_canonical_link()
284
+
282
285
  if not rod_model.is_fixed_base():
283
286
  considered_joints |= {"world_to_base"}
284
287
  urdf_string = RodModelToMjcf.add_floating_joint(
285
288
  urdf_string=urdf_string,
286
- base_link_name=rod_model.get_canonical_link(),
289
+ base_link_name=base_link_name,
287
290
  floating_joint_name="world_to_base",
288
291
  )
289
292
 
@@ -379,6 +382,30 @@ class RodModelToMjcf:
379
382
  # Find the <mujoco> element (might be the root itself).
380
383
  mujoco_element: ET._Element = next(iter(root.iter("mujoco")))
381
384
 
385
+ # --------------
386
+ # Add the frames
387
+ # --------------
388
+
389
+ for frame in rod_model.frames():
390
+ frame: rod.Frame
391
+ parent_name = frame.attached_to
392
+ parent_element = mujoco_element.find(f".//body[@name='{parent_name}']")
393
+
394
+ if parent_element is None and parent_name == base_link_name:
395
+ parent_element = mujoco_element.find(".//worldbody")
396
+
397
+ if parent_element is not None:
398
+ quat = jaxlie.SO3.from_rpy_radians(*frame.pose.rpy).wxyz
399
+ _ = ET.SubElement(
400
+ parent_element,
401
+ "site",
402
+ name=frame.name,
403
+ pos=" ".join(map(str, frame.pose.xyz)),
404
+ quat=" ".join(map(str, quat)),
405
+ )
406
+ else:
407
+ warnings.warn(f"Parent link '{parent_name}' not found", stacklevel=2)
408
+
382
409
  # --------------
383
410
  # Add the motors
384
411
  # --------------
@@ -8,4 +8,10 @@ from .jacobian import (
8
8
  jacobian_derivative_full_doubly_left,
9
9
  jacobian_full_doubly_left,
10
10
  )
11
+ from .kinematic_constraints import (
12
+ compute_constraint_baumgarte_term,
13
+ compute_constraint_jacobians,
14
+ compute_constraint_jacobians_derivative,
15
+ compute_constraint_transforms,
16
+ )
11
17
  from .rnea import rnea
@@ -18,6 +18,10 @@ except ImportError:
18
18
  from typing_extensions import Self
19
19
 
20
20
 
21
+ MAX_STIFFNESS = 1e6
22
+ MAX_DAMPING = 1e4
23
+
24
+
21
25
  @functools.partial(jax.jit, static_argnames=("terrain",))
22
26
  def compute_penetration_data(
23
27
  p: jtp.VectorLike,
@@ -133,28 +137,30 @@ class ContactsParams(JaxsimDataclass):
133
137
  ξ = damping_ratio
134
138
  δ_max = max_penetration
135
139
  μc = static_friction_coefficient
140
+ nc = number_of_active_collidable_points_steady_state
136
141
 
137
142
  # Compute the total mass of the model.
138
143
  m = jnp.array(model.kin_dyn_parameters.link_parameters.mass).sum()
139
144
 
140
- # Rename the standard gravity.
141
- g = standard_gravity
142
-
143
- # Compute the average support force on each collidable point.
144
- f_average = m * g / number_of_active_collidable_points_steady_state
145
-
146
145
  # Compute the stiffness to get the desired steady-state penetration.
147
146
  # Note that this is dependent on the non-linear exponent used in
148
147
  # the damping term of the Hunt/Crossley model.
149
- K = f_average / jnp.power(δ_max, 1 + p) if stiffness is None else stiffness
148
+ if stiffness is None:
149
+ # Compute the average support force on each collidable point.
150
+ f_average = m * standard_gravity / nc
151
+
152
+ stiffness = f_average / jnp.power(δ_max, 1 + p)
153
+ stiffness = jnp.clip(stiffness, 0, MAX_STIFFNESS)
150
154
 
151
155
  # Compute the damping using the damping ratio.
152
- critical_damping = 2 * jnp.sqrt(K * m)
153
- D = ξ * critical_damping if damping is None else damping
156
+ critical_damping = 2 * jnp.sqrt(stiffness * m)
157
+ if damping is None:
158
+ damping = ξ * critical_damping
159
+ damping = jnp.clip(damping, 0, MAX_DAMPING)
154
160
 
155
161
  return self.build(
156
- K=K,
157
- D=D,
162
+ K=stiffness,
163
+ D=damping,
158
164
  mu=μc,
159
165
  p=p,
160
166
  q=q,