Add sites to MJX.

PiperOrigin-RevId: 585691582
Change-Id: I6cc594daf436231f91534f137ff259e7b39811d9
This commit is contained in:
Baruch Tabanpour
2023-11-27 10:27:20 -08:00
committed by Copybara-Service
parent 37bb03f435
commit 35c90844ae
6 changed files with 68 additions and 5 deletions
+5
View File
@@ -23,6 +23,11 @@ Plugins
- Added the `pid <https://github.com/deepmind/mujoco/blob/main/plugin/actuator/README.md>`__ actuator plugin, a - Added the `pid <https://github.com/deepmind/mujoco/blob/main/plugin/actuator/README.md>`__ actuator plugin, a
configurable PID controller that implements the Integral term, which is not available with native MuJoCo actuators. configurable PID controller that implements the Integral term, which is not available with native MuJoCo actuators.
MJX
^^^
- Added ``site_xpos`` and ``site_xmat`` to MJX.
Bug fixes Bug fixes
^^^^^^^^^ ^^^^^^^^^
- Fix bug in Cartesian actuation with movable refsite, as when using body-centric Cartesian actuators on a quadruped. - Fix bug in Cartesian actuation with movable refsite, as when using body-centric Cartesian actuators on a quadruped.
+2
View File
@@ -67,6 +67,7 @@ _TRANSFORMS = {
(types.Data, 'ximat'): lambda x: x.reshape(x.shape[:-1] + (3, 3)), (types.Data, 'ximat'): lambda x: x.reshape(x.shape[:-1] + (3, 3)),
(types.Data, 'xmat'): lambda x: x.reshape(x.shape[:-1] + (3, 3)), (types.Data, 'xmat'): lambda x: x.reshape(x.shape[:-1] + (3, 3)),
(types.Data, 'geom_xmat'): lambda x: x.reshape(x.shape[:-1] + (3, 3)), (types.Data, 'geom_xmat'): lambda x: x.reshape(x.shape[:-1] + (3, 3)),
(types.Data, 'site_xmat'): lambda x: x.reshape(x.shape[:-1] + (3, 3)),
(types.Model, 'actuator_trnid'): lambda x: x[:, 0], (types.Model, 'actuator_trnid'): lambda x: x[:, 0],
(types.Contact, 'frame'): ( (types.Contact, 'frame'): (
lambda x: x.reshape(x.shape[:-1] + (3, 3)) # pylint: disable=g-long-lambda lambda x: x.reshape(x.shape[:-1] + (3, 3)) # pylint: disable=g-long-lambda
@@ -78,6 +79,7 @@ _INVERSE_TRANSFORMS = {
(types.Data, 'ximat'): lambda x: x.reshape(x.shape[:-2] + (9,)), (types.Data, 'ximat'): lambda x: x.reshape(x.shape[:-2] + (9,)),
(types.Data, 'xmat'): lambda x: x.reshape(x.shape[:-2] + (9,)), (types.Data, 'xmat'): lambda x: x.reshape(x.shape[:-2] + (9,)),
(types.Data, 'geom_xmat'): lambda x: x.reshape(x.shape[:-2] + (9,)), (types.Data, 'geom_xmat'): lambda x: x.reshape(x.shape[:-2] + (9,)),
(types.Data, 'site_xmat'): lambda x: x.reshape(x.shape[:-2] + (9,)),
(types.Contact, 'frame'): ( (types.Contact, 'frame'): (
lambda x: x.reshape(x.shape[:-2] + (9,)) # pylint: disable=g-long-lambda lambda x: x.reshape(x.shape[:-2] + (9,)) # pylint: disable=g-long-lambda
if x is not None and x.shape[0] else jp.zeros((0, 9)) if x is not None and x.shape[0] else jp.zeros((0, 9))
+2
View File
@@ -56,6 +56,8 @@ def make_data(m: Model) -> Data:
xaxis=jp.zeros((m.njnt, 3), dtype=jp.float32), xaxis=jp.zeros((m.njnt, 3), dtype=jp.float32),
geom_xpos=jp.zeros((m.ngeom, 3), dtype=jp.float32), geom_xpos=jp.zeros((m.ngeom, 3), dtype=jp.float32),
geom_xmat=jp.zeros((m.ngeom, 3, 3), dtype=jp.float32), geom_xmat=jp.zeros((m.ngeom, 3, 3), dtype=jp.float32),
site_xpos=jp.zeros((m.nsite, 3), dtype=jp.float32),
site_xmat=jp.zeros((m.nsite, 3, 3), dtype=jp.float32),
subtree_com=jp.zeros((m.nbody, 3), dtype=jp.float32), subtree_com=jp.zeros((m.nbody, 3), dtype=jp.float32),
cdof=jp.zeros((m.nv, 6), dtype=jp.float32), cdof=jp.zeros((m.nv, 6), dtype=jp.float32),
cinert=jp.zeros((m.nbody, 10), dtype=jp.float32), cinert=jp.zeros((m.nbody, 10), dtype=jp.float32),
+12 -5
View File
@@ -101,13 +101,20 @@ def kinematics(m: Model, d: Data) -> Data:
# TODO(erikfrey): confirm that quats are more performant for mjx than mats # TODO(erikfrey): confirm that quats are more performant for mjx than mats
xipos, ximat = local_to_global(xpos, xquat, m.body_ipos, m.body_iquat) xipos, ximat = local_to_global(xpos, xquat, m.body_ipos, m.body_iquat)
geom_xpos, geom_xmat = local_to_global(
xpos[m.geom_bodyid], xquat[m.geom_bodyid], m.geom_pos, m.geom_quat
)
d = d.replace(qpos=qpos, xanchor=xanchor, xaxis=xaxis, xpos=xpos) d = d.replace(qpos=qpos, xanchor=xanchor, xaxis=xaxis, xpos=xpos)
d = d.replace(xquat=xquat, xmat=xmat, xipos=xipos, ximat=ximat) d = d.replace(xquat=xquat, xmat=xmat, xipos=xipos, ximat=ximat)
d = d.replace(geom_xpos=geom_xpos, geom_xmat=geom_xmat)
if m.ngeom:
geom_xpos, geom_xmat = local_to_global(
xpos[m.geom_bodyid], xquat[m.geom_bodyid], m.geom_pos, m.geom_quat
)
d = d.replace(geom_xpos=geom_xpos, geom_xmat=geom_xmat)
if m.nsite:
site_xpos, site_xmat = local_to_global(
xpos[m.site_bodyid], xquat[m.site_bodyid], m.site_pos, m.site_quat
)
d = d.replace(site_xpos=site_xpos, site_xmat=site_xmat)
return d return d
+35
View File
@@ -162,5 +162,40 @@ class DisableGravityTest(absltest.TestCase):
) )
class SiteTest(absltest.TestCase):
def test_site(self):
"""Tests that site positions and orientations match MuJoCo."""
m = mujoco.MjModel.from_xml_string("""
<mujoco>
<worldbody>
<site name="origin"/>
<body>
<joint type="free"/>
<geom pos="1 0 1" type="box" size="0.1 0.01 0.01"/>
<site name="s1" pos="1.3 0 0"/> <!-- pos only -->
<site name="s2"/> <!-- no pos, no quat -->
<site name="s3" quat="1 0 1 0"/> <!- quat only -->
<site name="s4" pos="0 1.5 0" quat="1 0 1 0"/>
<site name="s5" pos="1 0 1"/> <!-- same as ipos -->
<site/>
</body>
</worldbody>
</mujoco>
""")
d = mujoco.MjData(m)
mx = mjx.device_put(m)
dx = mjx.device_put(d)
mujoco.mj_forward(m, d)
dx = mjx.forward(mx, dx)
np.testing.assert_array_almost_equal(dx.site_xpos, d.site_xpos)
np.testing.assert_array_almost_equal(
dx.site_xmat, d.site_xmat.reshape((-1, 3, 3))
)
if __name__ == '__main__': if __name__ == '__main__':
absltest.main() absltest.main()
+12
View File
@@ -260,6 +260,7 @@ class Model(PyTreeNode):
nbody: number of bodies nbody: number of bodies
njnt: number of joints njnt: number of joints
ngeom: number of geoms ngeom: number of geoms
nsite: number of sites
nmesh: number of meshes nmesh: number of meshes
npair: number of predefined geom pairs npair: number of predefined geom pairs
nexclude: number of excluded geom pairs nexclude: number of excluded geom pairs
@@ -327,6 +328,9 @@ class Model(PyTreeNode):
geom_friction: friction for (slide, spin, roll) (ngeom, 3) geom_friction: friction for (slide, spin, roll) (ngeom, 3)
geom_margin: include in solver if dist<margin-gap (ngeom,) geom_margin: include in solver if dist<margin-gap (ngeom,)
geom_gap: include in solver if dist<margin-gap (ngeom,) geom_gap: include in solver if dist<margin-gap (ngeom,)
site_bodyid: id of site's body (nsite,)
site_pos: local position offset rel. to body (nsite,3)
site_quat: local orientation offset rel. to body (nsite,4)
geom_convex_face: vertex face data, MJX only (ngeom,) geom_convex_face: vertex face data, MJX only (ngeom,)
geom_convex_vert: vertex data, MJX only (ngeom,) geom_convex_vert: vertex data, MJX only (ngeom,)
geom_convex_edge: unique edge data, MJX only (ngeom,) geom_convex_edge: unique edge data, MJX only (ngeom,)
@@ -377,6 +381,7 @@ class Model(PyTreeNode):
nbody: int nbody: int
njnt: int njnt: int
ngeom: int ngeom: int
nsite: int
nmesh: int nmesh: int
npair: int npair: int
nexclude: int nexclude: int
@@ -444,6 +449,9 @@ class Model(PyTreeNode):
geom_friction: jax.Array geom_friction: jax.Array
geom_margin: jax.Array geom_margin: jax.Array
geom_gap: jax.Array geom_gap: jax.Array
site_bodyid: np.ndarray
site_pos: jax.Array
site_quat: jax.Array
pair_dim: np.ndarray pair_dim: np.ndarray
pair_geom1: np.ndarray pair_geom1: np.ndarray
pair_geom2: np.ndarray pair_geom2: np.ndarray
@@ -569,6 +577,8 @@ class Data(PyTreeNode):
xaxis: Cartesian joint axis (njnt, 3) xaxis: Cartesian joint axis (njnt, 3)
geom_xpos: Cartesian geom position (ngeom, 3) geom_xpos: Cartesian geom position (ngeom, 3)
geom_xmat: Cartesian geom orientation (ngeom, 3, 3) geom_xmat: Cartesian geom orientation (ngeom, 3, 3)
site_xpos: Cartesian site position (nsite, 3)
site_xmat: Cartesian site orientation (nsite, 9)
subtree_com: center of mass of each subtree (nbody, 3) subtree_com: center of mass of each subtree (nbody, 3)
cdof: com-based motion axis of each dof (nv, 6) cdof: com-based motion axis of each dof (nv, 6)
cinert: com-based body inertia and mass (nbody, 10) cinert: com-based body inertia and mass (nbody, 10)
@@ -631,6 +641,8 @@ class Data(PyTreeNode):
xaxis: jax.Array xaxis: jax.Array
geom_xpos: jax.Array geom_xpos: jax.Array
geom_xmat: jax.Array geom_xmat: jax.Array
site_xpos: jax.Array
site_xmat: jax.Array
subtree_com: jax.Array subtree_com: jax.Array
cdof: jax.Array cdof: jax.Array
cinert: jax.Array cinert: jax.Array