Skip to content

Commit d0faa36

Browse files
thowellcopybara-github
authored andcommitted
Update MJX inverse dynamics for tendon armature.
PiperOrigin-RevId: 775658246 Change-Id: Ie6a71b971d4b165e0235689b7b4ee3246486e10d
1 parent da831f5 commit d0faa36

File tree

4 files changed

+67
-28
lines changed

4 files changed

+67
-28
lines changed

mjx/mujoco/mjx/_src/inverse.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,15 @@ def inverse(m: Model, d: Data) -> Data:
9393
d = discrete_acc(m, d)
9494

9595
d = inv_constraint(m, d)
96-
d = smooth.rne(m, d, flg_acc=True)
96+
d = smooth.rne(m, d)
97+
d = smooth.tendon_bias(m, d)
9798
d = sensor.sensor_acc(m, d)
9899

99100
qfrc_inverse = (
100-
d.qfrc_bias + m.dof_armature * d.qacc - d.qfrc_passive - d.qfrc_constraint
101+
d.qfrc_bias
102+
+ support.mul_m(m, d, d.qacc)
103+
- d.qfrc_passive
104+
- d.qfrc_constraint
101105
)
102106

103107
if m.opt.enableflags & EnableBit.INVDISCRETE:

mjx/mujoco/mjx/_src/inverse_test.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import mujoco
2020
from mujoco import mjx
2121
from mujoco.mjx._src import support
22+
from mujoco.mjx._src import test_util
2223
import numpy as np
2324

2425
# tolerance for difference between MuJoCo and MJX calculations - mostly
@@ -109,6 +110,41 @@ def test_forward_inverse_match(self, integrator, invdiscrete, eulerdamp):
109110
self.assertLess(fwdinv1, 1.0e-3)
110111
_assert_eq(dxinv.qacc, dx.qacc, 'qacc')
111112

113+
def test_inverse_tendon_armature(self):
114+
m = test_util.load_test_file('tendon/armature.xml')
115+
116+
d = mujoco.MjData(m)
117+
d.qvel = np.random.uniform(low=-0.01, high=0.01, size=d.qvel.shape)
118+
d.ctrl = np.random.uniform(low=-0.01, high=0.01, size=d.ctrl.shape)
119+
d.qfrc_applied = np.random.uniform(
120+
low=-0.01, high=0.01, size=d.qfrc_applied.shape
121+
)
122+
d.xfrc_applied = np.random.uniform(
123+
low=-0.01, high=0.01, size=d.xfrc_applied.shape
124+
)
125+
mujoco.mj_step(m, d, 10)
126+
127+
mx = mjx.put_model(m)
128+
dx = mjx.put_data(m, d)
129+
130+
dx = mjx.forward(mx, dx)
131+
dxinv = mjx.inverse(mx, dx)
132+
133+
fwdinv0 = jp.linalg.norm(
134+
dxinv.qfrc_constraint - dx.qfrc_constraint, ord=np.inf
135+
)
136+
fwdinv1 = jp.linalg.norm(
137+
dxinv.qfrc_inverse
138+
- (
139+
dx.qfrc_applied + dx.qfrc_actuator + support.xfrc_accumulate(mx, dx)
140+
),
141+
ord=np.inf,
142+
)
143+
144+
self.assertLess(fwdinv0, 1.0e-3)
145+
self.assertLess(fwdinv1, 1.0e-3)
146+
_assert_eq(dxinv.qacc, dx.qacc, 'qacc')
147+
112148

113149
if __name__ == '__main__':
114150
absltest.main()

mjx/mujoco/mjx/_src/smooth_test.py

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -321,32 +321,7 @@ def test_tendon(self, filename):
321321
@parameterized.parameters(JacobianType.DENSE, JacobianType.SPARSE)
322322
def test_tendon_armature(self, jacobian):
323323
"""Tests MJX tendon armature matches MuJoCo."""
324-
m = mujoco.MjModel.from_xml_string("""
325-
<mujoco>
326-
<worldbody>
327-
<site name="site0" pos="1 0 1"/>
328-
<body>
329-
<joint type="slide" axis="0 0 1"/>
330-
<joint type="hinge" axis="0 1 0"/>
331-
<geom type="box" size="0.1 0.1 0.1" mass="1" pos="1 0 0"/>
332-
<site name="site1"/>
333-
</body>
334-
</worldbody>
335-
<tendon>
336-
<spatial armature="123">
337-
<site site="site0"/>
338-
<site site="site1"/>
339-
</spatial>
340-
<spatial armature="456">
341-
<site site="site0"/>
342-
<site site="site1"/>
343-
</spatial>
344-
</tendon>
345-
<keyframe>
346-
<key qpos="1.2345 1.2345" qvel="1.2345 1.2345"/>
347-
</keyframe>
348-
</mujoco>
349-
""")
324+
m = test_util.load_test_file('tendon/armature.xml')
350325
m.opt.jacobian = jacobian
351326
d = mujoco.MjData(m)
352327
mujoco.mj_resetDataKeyframe(m, d, 0)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<mujoco>
2+
<worldbody>
3+
<site name="site0" pos="1 0 1"/>
4+
<body>
5+
<joint type="slide" axis="0 0 1"/>
6+
<joint type="hinge" axis="0 1 0"/>
7+
<geom type="box" size="0.1 0.1 0.1" mass="1" pos="1 0 0"/>
8+
<site name="site1"/>
9+
</body>
10+
</worldbody>
11+
<tendon>
12+
<spatial armature="123">
13+
<site site="site0"/>
14+
<site site="site1"/>
15+
</spatial>
16+
<spatial armature="456">
17+
<site site="site0"/>
18+
<site site="site1"/>
19+
</spatial>
20+
</tendon>
21+
<keyframe>
22+
<key qpos="1.2345 1.2345" qvel="1.2345 1.2345"/>
23+
</keyframe>
24+
</mujoco>

0 commit comments

Comments
 (0)