Implicitfast integration for MJX.
PiperOrigin-RevId: 664889120 Change-Id: Id3bd3916fe821ab2af79c52e53e14837ae829b2a
This commit is contained in:
committed by
Copybara-Service
parent
5d91231d31
commit
a68141eeff
+5
-3
@@ -23,17 +23,19 @@ MJX
|
|||||||
7. Added velocity-dependent sensors: ``JOINTVEL``, ``ACTUATORVEL``, ``BALLANGVEL``.
|
7. Added velocity-dependent sensors: ``JOINTVEL``, ``ACTUATORVEL``, ``BALLANGVEL``.
|
||||||
8. Changed default policy to avoid placing unused (MuJoCo-only) arrays on device.
|
8. Changed default policy to avoid placing unused (MuJoCo-only) arrays on device.
|
||||||
9. Added ``device`` parameter to ``mjx.make_data`` to bring it to parity with ``mjx.put_model`` and ``mjx.put_data``.
|
9. Added ``device`` parameter to ``mjx.make_data`` to bring it to parity with ``mjx.put_model`` and ``mjx.put_data``.
|
||||||
|
10. Added support for :ref:`implicitfast integration<geIntegration>` for all cases except
|
||||||
|
:doc:`fluid drag <computation/fluid>`.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
10. Fixed a performance regression introduced in 3.1.7 in mesh Bounding Volume Hierarchies (:github:issue:`1875`,
|
11. Fixed a performance regression introduced in 3.1.7 in mesh Bounding Volume Hierarchies (:github:issue:`1875`,
|
||||||
contribution by :github:user:`michael-ahn`).
|
contribution by :github:user:`michael-ahn`).
|
||||||
11. Fixed a bug wherein, for models that have both muscles and stateless actuators and used one of the implicit
|
12. Fixed a bug wherein, for models that have both muscles and stateless actuators and used one of the implicit
|
||||||
integrators, wrong derivatives would be computed.
|
integrators, wrong derivatives would be computed.
|
||||||
|
|
||||||
Python bindings
|
Python bindings
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
12. Added support for engine plugins in :ref:`mjSpec` (:github:issue:`1903`).
|
13. Added support for engine plugins in :ref:`mjSpec` (:github:issue:`1903`).
|
||||||
|
|
||||||
|
|
||||||
Version 3.2.2 (Aug 8, 2024)
|
Version 3.2.2 (Aug 8, 2024)
|
||||||
|
|||||||
+2
-2
@@ -202,7 +202,7 @@ The following features are **fully supported** in MJX:
|
|||||||
* - :ref:`Equality <mjtEq>`
|
* - :ref:`Equality <mjtEq>`
|
||||||
- ``CONNECT``, ``WELD``, ``JOINT``, ``TENDON``
|
- ``CONNECT``, ``WELD``, ``JOINT``, ``TENDON``
|
||||||
* - :ref:`Integrator <mjtIntegrator>`
|
* - :ref:`Integrator <mjtIntegrator>`
|
||||||
- ``EULER``, ``RK4``
|
- ``EULER``, ``RK4``, ``IMPLICITFAST`` (``IMPLICITFAST`` not supported with :doc:`fluid drag <computation/fluid>`)
|
||||||
* - :ref:`Cone <mjtCone>`
|
* - :ref:`Cone <mjtCone>`
|
||||||
- ``PYRAMIDAL``, ``ELLIPTIC``
|
- ``PYRAMIDAL``, ``ELLIPTIC``
|
||||||
* - :ref:`Condim <coContact>`
|
* - :ref:`Condim <coContact>`
|
||||||
@@ -229,7 +229,7 @@ The following features are **in development** and coming soon:
|
|||||||
* - :ref:`Constraint <mjtConstraint>`
|
* - :ref:`Constraint <mjtConstraint>`
|
||||||
- :ref:`Frictionloss <coFriction>`, ``FRICTION_DOF``
|
- :ref:`Frictionloss <coFriction>`, ``FRICTION_DOF``
|
||||||
* - :ref:`Integrator <mjtIntegrator>`
|
* - :ref:`Integrator <mjtIntegrator>`
|
||||||
- ``IMPLICIT``, ``IMPLICITFAST``
|
- ``IMPLICIT``
|
||||||
* - Dynamics
|
* - Dynamics
|
||||||
- :ref:`Inverse <mj_inverse>`
|
- :ref:`Inverse <mj_inverse>`
|
||||||
* - :ref:`Actuator Dynamics <mjtDyn>`
|
* - :ref:`Actuator Dynamics <mjtDyn>`
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from mujoco.mjx._src.forward import fwd_acceleration
|
|||||||
from mujoco.mjx._src.forward import fwd_actuation
|
from mujoco.mjx._src.forward import fwd_actuation
|
||||||
from mujoco.mjx._src.forward import fwd_position
|
from mujoco.mjx._src.forward import fwd_position
|
||||||
from mujoco.mjx._src.forward import fwd_velocity
|
from mujoco.mjx._src.forward import fwd_velocity
|
||||||
|
from mujoco.mjx._src.forward import implicit
|
||||||
from mujoco.mjx._src.forward import rungekutta4
|
from mujoco.mjx._src.forward import rungekutta4
|
||||||
from mujoco.mjx._src.forward import step
|
from mujoco.mjx._src.forward import step
|
||||||
from mujoco.mjx._src.io import get_data
|
from mujoco.mjx._src.io import get_data
|
||||||
@@ -32,9 +33,9 @@ from mujoco.mjx._src.io import put_data
|
|||||||
from mujoco.mjx._src.io import put_model
|
from mujoco.mjx._src.io import put_model
|
||||||
from mujoco.mjx._src.passive import passive
|
from mujoco.mjx._src.passive import passive
|
||||||
from mujoco.mjx._src.ray import ray
|
from mujoco.mjx._src.ray import ray
|
||||||
|
from mujoco.mjx._src.sensor import sensor_acc
|
||||||
from mujoco.mjx._src.sensor import sensor_pos
|
from mujoco.mjx._src.sensor import sensor_pos
|
||||||
from mujoco.mjx._src.sensor import sensor_vel
|
from mujoco.mjx._src.sensor import sensor_vel
|
||||||
from mujoco.mjx._src.sensor import sensor_acc
|
|
||||||
from mujoco.mjx._src.smooth import camlight
|
from mujoco.mjx._src.smooth import camlight
|
||||||
from mujoco.mjx._src.smooth import com_pos
|
from mujoco.mjx._src.smooth import com_pos
|
||||||
from mujoco.mjx._src.smooth import com_vel
|
from mujoco.mjx._src.smooth import com_vel
|
||||||
|
|||||||
@@ -348,6 +348,46 @@ def rungekutta4(m: Model, d: Data) -> Data:
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
@named_scope
|
||||||
|
def implicit(m: Model, d: Data) -> Data:
|
||||||
|
"""Integrates fully implicit in velocity."""
|
||||||
|
|
||||||
|
qderiv = None
|
||||||
|
|
||||||
|
# qDeriv += d qfrc_actuator / d qvel
|
||||||
|
if not m.opt.disableflags & DisableBit.ACTUATION:
|
||||||
|
affine_bias = m.actuator_biastype == BiasType.AFFINE
|
||||||
|
bias_vel = m.actuator_biasprm[:, 2] * affine_bias
|
||||||
|
affine_gain = m.actuator_gaintype == GainType.AFFINE
|
||||||
|
gain_vel = m.actuator_gainprm[:, 2] * affine_gain
|
||||||
|
ctrl = d.ctrl.at[m.actuator_dyntype != DynType.NONE].set(d.act)
|
||||||
|
vel = bias_vel + gain_vel * ctrl
|
||||||
|
qderiv = d.actuator_moment.T @ jp.diag(vel) @ d.actuator_moment
|
||||||
|
|
||||||
|
# qDeriv += d qfrc_passive / d qvel
|
||||||
|
if not m.opt.disableflags & DisableBit.PASSIVE:
|
||||||
|
if qderiv is None:
|
||||||
|
qderiv = -jp.diag(m.dof_damping)
|
||||||
|
else:
|
||||||
|
qderiv -= jp.diag(m.dof_damping)
|
||||||
|
if m.ntendon:
|
||||||
|
qderiv -= d.ten_J.T @ jp.diag(m.tendon_damping) @ d.ten_J
|
||||||
|
# TODO(robotics-simulation): fluid drag model
|
||||||
|
if m.opt.has_fluid_params:
|
||||||
|
raise NotImplementedError('fluid drag not supported for implicitfast')
|
||||||
|
|
||||||
|
qacc = d.qacc
|
||||||
|
if qderiv is not None:
|
||||||
|
# TODO(robotics-simulation): use smooth.factor_m / solve_m here:
|
||||||
|
qm = support.full_m(m, d) if support.is_sparse(m) else d.qM
|
||||||
|
qm -= m.opt.timestep * qderiv
|
||||||
|
qh, _ = jax.scipy.linalg.cho_factor(qm)
|
||||||
|
qfrc = d.qfrc_smooth + d.qfrc_constraint
|
||||||
|
qacc = jax.scipy.linalg.cho_solve((qh, False), qfrc)
|
||||||
|
|
||||||
|
return _advance(m, d, d.act_dot, qacc)
|
||||||
|
|
||||||
|
|
||||||
@named_scope
|
@named_scope
|
||||||
def forward(m: Model, d: Data) -> Data:
|
def forward(m: Model, d: Data) -> Data:
|
||||||
"""Forward dynamics."""
|
"""Forward dynamics."""
|
||||||
@@ -377,6 +417,8 @@ def step(m: Model, d: Data) -> Data:
|
|||||||
d = euler(m, d)
|
d = euler(m, d)
|
||||||
elif m.opt.integrator == IntegratorType.RK4:
|
elif m.opt.integrator == IntegratorType.RK4:
|
||||||
d = rungekutta4(m, d)
|
d = rungekutta4(m, d)
|
||||||
|
elif m.opt.integrator == IntegratorType.IMPLICITFAST:
|
||||||
|
d = implicit(m, d)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(f'integrator {m.opt.integrator} not implemented.')
|
raise NotImplementedError(f'integrator {m.opt.integrator} not implemented.')
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,12 @@ class ForwardTest(absltest.TestCase):
|
|||||||
_assert_attr_eq(d, dx, 'qpos')
|
_assert_attr_eq(d, dx, 'qpos')
|
||||||
_assert_attr_eq(d, dx, 'time')
|
_assert_attr_eq(d, dx, 'time')
|
||||||
|
|
||||||
|
# implicitfast
|
||||||
|
m.opt.integrator = mujoco.mjtIntegrator.mjINT_IMPLICITFAST
|
||||||
|
dx = jax.jit(mjx.implicit)(mx, mjx.put_data(m, d))
|
||||||
|
mujoco.mj_implicit(m, d)
|
||||||
|
_assert_attr_eq(d, dx, 'qpos')
|
||||||
|
|
||||||
def test_step(self):
|
def test_step(self):
|
||||||
m = test_util.load_test_file('constraints.xml')
|
m = test_util.load_test_file('constraints.xml')
|
||||||
d = mujoco.MjData(m)
|
d = mujoco.MjData(m)
|
||||||
|
|||||||
@@ -47,13 +47,18 @@ def _make_option(o: mujoco.MjOption) -> types.Option:
|
|||||||
if o.enableflags & 2**i:
|
if o.enableflags & 2**i:
|
||||||
raise NotImplementedError(f'{mujoco.mjtEnableBit(2 ** i)}')
|
raise NotImplementedError(f'{mujoco.mjtEnableBit(2 ** i)}')
|
||||||
|
|
||||||
|
has_fluid_params = o.density > 0 or o.viscosity > 0 or o.wind.any()
|
||||||
|
implicitfast = o.integrator == mujoco.mjtIntegrator.mjINT_IMPLICITFAST
|
||||||
|
if implicitfast and has_fluid_params:
|
||||||
|
raise NotImplementedError('implicitfast not implemented for fluid drag.')
|
||||||
|
|
||||||
fields = {f.name: getattr(o, f.name, None) for f in types.Option.fields()}
|
fields = {f.name: getattr(o, f.name, None) for f in types.Option.fields()}
|
||||||
fields['integrator'] = types.IntegratorType(o.integrator)
|
fields['integrator'] = types.IntegratorType(o.integrator)
|
||||||
fields['cone'] = types.ConeType(o.cone)
|
fields['cone'] = types.ConeType(o.cone)
|
||||||
fields['jacobian'] = types.JacobianType(o.jacobian)
|
fields['jacobian'] = types.JacobianType(o.jacobian)
|
||||||
fields['solver'] = types.SolverType(o.solver)
|
fields['solver'] = types.SolverType(o.solver)
|
||||||
fields['disableflags'] = types.DisableBit(o.disableflags)
|
fields['disableflags'] = types.DisableBit(o.disableflags)
|
||||||
fields['has_fluid_params'] = o.density > 0 or o.viscosity > 0 or o.wind.any()
|
fields['has_fluid_params'] = has_fluid_params
|
||||||
|
|
||||||
return types.Option(**fields)
|
return types.Option(**fields)
|
||||||
|
|
||||||
|
|||||||
@@ -208,6 +208,14 @@ class ModelIOTest(parameterized.TestCase):
|
|||||||
</worldbody>
|
</worldbody>
|
||||||
</mujoco>"""))
|
</mujoco>"""))
|
||||||
|
|
||||||
|
def test_implicitfast_fluid_not_implemented(self):
|
||||||
|
with self.assertRaises(NotImplementedError):
|
||||||
|
mjx.put_model(mujoco.MjModel.from_xml_string("""
|
||||||
|
<mujoco>
|
||||||
|
<option viscosity="3.0" integrator="implicitfast"/>
|
||||||
|
<worldbody/>
|
||||||
|
</mujoco>"""))
|
||||||
|
|
||||||
|
|
||||||
class DataIOTest(parameterized.TestCase):
|
class DataIOTest(parameterized.TestCase):
|
||||||
"""IO tests for mjx.Data."""
|
"""IO tests for mjx.Data."""
|
||||||
|
|||||||
@@ -90,10 +90,12 @@ class IntegratorType(enum.IntEnum):
|
|||||||
Members:
|
Members:
|
||||||
EULER: semi-implicit Euler
|
EULER: semi-implicit Euler
|
||||||
RK4: 4th-order Runge Kutta
|
RK4: 4th-order Runge Kutta
|
||||||
|
IMPLICITFAST: implicit in velocity, no rne derivative
|
||||||
"""
|
"""
|
||||||
EULER = mujoco.mjtIntegrator.mjINT_EULER
|
EULER = mujoco.mjtIntegrator.mjINT_EULER
|
||||||
RK4 = mujoco.mjtIntegrator.mjINT_RK4
|
RK4 = mujoco.mjtIntegrator.mjINT_RK4
|
||||||
# unsupported: IMPLICIT, IMPLICITFAST
|
IMPLICITFAST = mujoco.mjtIntegrator.mjINT_IMPLICITFAST
|
||||||
|
# unsupported: IMPLICIT
|
||||||
|
|
||||||
|
|
||||||
class GeomType(enum.IntEnum):
|
class GeomType(enum.IntEnum):
|
||||||
|
|||||||
@@ -83,7 +83,7 @@
|
|||||||
</equality>
|
</equality>
|
||||||
|
|
||||||
<actuator>
|
<actuator>
|
||||||
<position ctrlrange="-20 20" gear="500" joint="joint1" name="act1"/>
|
<position ctrlrange="-20 20" gear="500" joint="joint1" kv="0.5" name="act1"/>
|
||||||
<motor gear="50000" joint="joint3" name="act2"/>
|
<motor gear="50000" joint="joint3" name="act2"/>
|
||||||
<motor gear="75000" joint="joint4" name="act3"/>
|
<motor gear="75000" joint="joint4" name="act3"/>
|
||||||
</actuator>
|
</actuator>
|
||||||
|
|||||||
Reference in New Issue
Block a user