Add tendon actuator force limits to MJX.

PiperOrigin-RevId: 745529685
Change-Id: I43c372116daefc3dd2ed6ad1bb9c6e3978bc8527
This commit is contained in:
Taylor Howell
2025-04-09 04:27:48 -07:00
committed by Copybara-Service
parent 5031f88158
commit 8fc616bf8f
4 changed files with 98 additions and 0 deletions
+4
View File
@@ -23,6 +23,10 @@ General
- Added :ref:`tendon actuator force limits<tendon-spatial-actuatorfrclimited>` and
:ref:`tendon actuator force sensor<sensor-tendonactuatorfrc>`.
MJX
^^^
- Added tendon actuator force limits.
Bug fixes
^^^^^^^^^
- :ref:`mj_jacDot` was missing a term that accounts for the motion of the point with respect to
+29
View File
@@ -38,6 +38,7 @@ from mujoco.mjx._src.types import GainType
from mujoco.mjx._src.types import IntegratorType
from mujoco.mjx._src.types import JointType
from mujoco.mjx._src.types import Model
from mujoco.mjx._src.types import TrnType
# pylint: enable=g-importing-member
import numpy as np
@@ -178,6 +179,34 @@ def fwd_actuation(m: Model, d: Data) -> Data:
jp.array(m.actuator_acc0),
group_by='u',
)
# tendon total force clamping
if np.any(m.tendon_actfrclimited):
(tendon_actfrclimited_id,) = np.nonzero(m.tendon_actfrclimited)
actuator_tendon = m.actuator_trntype == TrnType.TENDON
force_mask = [
actuator_tendon & (m.actuator_trnid[:, 0] == tendon_id)
for tendon_id in tendon_actfrclimited_id
]
force_ids = np.concatenate([np.nonzero(mask)[0] for mask in force_mask])
force_mat = np.array(force_mask)[:, force_ids]
tendon_total_force = force_mat @ force[force_ids]
force_scaling = jp.where(
tendon_total_force < m.tendon_actfrcrange[tendon_actfrclimited_id, 0],
m.tendon_actfrcrange[tendon_actfrclimited_id, 0] / tendon_total_force,
1,
)
force_scaling = jp.where(
tendon_total_force > m.tendon_actfrcrange[tendon_actfrclimited_id, 1],
m.tendon_actfrcrange[tendon_actfrclimited_id, 1] / tendon_total_force,
force_scaling,
)
tendon_forces = force[force_ids] * (force_mat.T @ force_scaling)
force = force.at[force_ids].set(tendon_forces)
forcerange = jp.where(
m.actuator_forcelimited[:, None],
m.actuator_forcerange,
+16
View File
@@ -17,6 +17,7 @@
from absl.testing import absltest
from absl.testing import parameterized
import jax
from jax import numpy as jp
import mujoco
from mujoco import mjx
from mujoco.mjx._src import test_util
@@ -196,6 +197,21 @@ class ActuatorTest(parameterized.TestCase):
dx = jax.jit(mjx.euler)(mx, dx)
_assert_attr_eq(d, dx, 'act')
def test_tendon_force_clamp(self):
m = test_util.load_test_file('actuator/tendon_force_clamp.xml')
d = mujoco.MjData(m)
mx = mjx.put_model(m)
dx = mjx.put_data(m, d)
dx = dx.replace(ctrl=jp.array([1.0, 1.0, 1.0, -1.0, 1.0, -20.0, 5.0, -5.0]))
dx = mjx.forward(mx, dx)
_assert_eq(
dx.actuator_force,
jp.array([1.0, 1.0, 1.0, -1.0, 1.0, -10.0, 5.0, -5.0]),
'actuator_force',
)
if __name__ == '__main__':
absltest.main()
@@ -0,0 +1,49 @@
<mujoco model="fixed_site">
<worldbody>
<body>
<joint name="joint0" type="hinge" axis="0 1 0"/>
<geom type="capsule" size="0.05 0.5" fromto="0 0 0 0.5 0 0"/>
<site name="site0" pos="0.25 0 0.1" size="0.025"/>
<body pos="0.5 0 0">
<joint name="joint1" type="hinge" axis="0 1 0"/>
<geom type="capsule" size="0.05 0.5" fromto="0 0 0 0.5 0 0"/>
<site name="site1" pos="0.25 0 0.1" size="0.025"/>
<body pos="0.5 0 0">
<joint name="joint2" type="hinge" axis="0 1 0"/>
<geom type="capsule" size="0.05 0.5" fromto="0 0 0 0.5 0 0"/>
<site name="site2" pos="0.25 0 0.1" size="0.025"/>
</body>
</body>
</body>
</worldbody>
<tendon>
<spatial name="spatial0" width="0.0125">
<site site="site0"/>
<site site="site1"/>
<site site="site2"/>
</spatial>
<spatial name="spatial1" width="0.0125" actuatorfrclimited="true" actuatorfrcrange="-1 1">
<site site="site1"/>
<site site="site2"/>
</spatial>
<fixed name="fixed0" actuatorfrclimited="true" actuatorfrcrange="-10 10">
<joint joint="joint0" coef=".1"/>
<joint joint="joint1" coef=".2"/>
<joint joint="joint2" coef=".3"/>
</fixed>
<fixed name="fixed1" actuatorfrclimited="true" actuatorfrcrange="0 1">
<joint joint="joint0" coef=".1"/>
<joint joint="joint2" coef=".3"/>
</fixed>
</tendon>
<actuator>
<motor tendon="spatial0"/>
<motor tendon="spatial0"/>
<motor tendon="spatial0"/>
<motor tendon="spatial1"/>
<motor tendon="spatial1"/>
<motor tendon="fixed0"/>
<motor tendon="fixed1"/>
<motor tendon="fixed1"/>
</actuator>
</mujoco>