Implement midpoint integrator for free bodies.

PiperOrigin-RevId: 899043541
Change-Id: I0bb38f6ad94e189b45ab16777a04ad6fefc6adf7
This commit is contained in:
Yuval Tassa
2026-04-13 09:37:51 -07:00
committed by Copybara-Service
parent d9b5d8babb
commit 0c337799bd
12 changed files with 913 additions and 29 deletions
+16 -7
View File
@@ -657,13 +657,22 @@ from its default.
.. _option-flag-invdiscrete:
:at:`invdiscrete`: :at-val:`[disable, enable], "disable"`
This flag enables discrete-time inverse dynamics with :ref:`mj_inverse` for all
:ref:`integrators<option-integrator>` other than ``RK4``. Recall from the
:ref:`numerical integration<geIntegration>` section that the one-step integrators (``Euler``, ``implicit`` and
``implicitfast``), modify the mass matrix :math:`M \rightarrow M-hD`. This implies that finite-differenced
accelerations :math:`(v_{t+h} - v_t)/h` will not correspond to the continuous-time acceleration ``mjData.qacc``.
When this flag is enabled, :ref:`mj_inverse` will interpret ``qacc`` as having been computed from the difference of
two sequential velocities, and undo the above modification.
This dual-purpose flag enables discrete-time inverse dynamics and disables :ref:`midpoint integration<geMidpoint>`.
Enable discrete-time inverse dynamics
This flag **enables** discrete-time inverse dynamics with :ref:`mj_inverse` for all
:ref:`integrators<option-integrator>` other than ``RK4``. Recall from the :ref:`numerical
integration<geIntegration>` section that the one-step integrators (``Euler``, ``implicit`` and ``implicitfast``),
modify the mass matrix :math:`M \rightarrow M-hD`. This implies that finite-differenced accelerations
:math:`(v_{t+h} - v_t)/h` will not correspond to the continuous-time acceleration ``mjData.qacc``. When this flag
is enabled, :ref:`mj_inverse` will interpret ``qacc`` as having been computed from the difference of two sequential
velocities, and undo the above modification.
Disable midpoint integration
Additionally and relatedly, this flag **disables** :ref:`midpoint integration<geMidpoint>` for free bodies, which
would otherwise break the linear relationship between finite-differenced velocities and forces assumed by discrete
inverse dynamics. Note that disabling midpoint integration might be useful for debugging or for other reasons,
regardless or whether inverse dynamics are used.
.. _option-flag-multiccd:
+7 -2
View File
@@ -27,8 +27,13 @@ General
(``jnt_stiffness``, ``dof_damping``, etc.) continue to hold the linear coefficient and are unchanged.
The polynomial order is defined by the new constant :ref:`mjNPOLY<glNumericSizes>`. A future breaking C-API change
may unify the linear and higher-order coefficients into a single array.
- Introduced :ref:`mjpEncoder`, the counterpart to :ref:`mjpDecoder` for encoding of :ref:`mjSpec` and :ref:`mjModel` into :ref:`mjResource`.
- Added :ref:`midpoint integration<geMidpoint>` for standalone free bodies in ``implicit`` and ``implicitfast``
:ref:`integrators<geIntegrators>`. This applies the implicit midpoint rule to the rotational dynamics of free bodies
with no children, exactly conserving kinetic energy and angular momentum in the absence of external torques. The
:ref:`invdiscrete<option-flag-invdiscrete>` flag now also disables midpoint integration, providing an opt-out
mechanism.
- Introduced :ref:`mjpEncoder`, the counterpart to :ref:`mjpDecoder` for encoding of :ref:`mjSpec` and :ref:`mjModel`
into :ref:`mjResource`.
- Added :ref:`mj_encode`, :ref:`mjp_registerEncoder`, :ref:`mjp_defaultEncoder`, and :ref:`mjp_findEncoder`.
+51 -5
View File
@@ -573,6 +573,49 @@ Solving for :math:`v_{t+h}`, we obtain the implicit-in-velocity update
\widehat{M} &\equiv M-h D
\end{aligned}
.. _geMidpoint:
Midpoint integration for free bodies
The implicit-in-velocity update :eq:`eq_implicit_update` treats the acceleration as a function of velocity and
linearizes. While effective for damping-like forces, it is sub-optimal for rotational dynamics, where
Coriolis and gyroscopic forces are *quadratic* in angular velocity. For this case, a better approach is to directly
discretize the rotational equations of motion using the *midpoint method*.
Consider a rigid body rotating in its principal-axis frame with angular velocity
:math:`\omega \in \mathbb{R}^3` and diagonal inertia tensor :math:`I = \text{diag}(I_1, I_2, I_3)`. The rotational
dynamics are given by `Euler's rotation equation
<https://en.wikipedia.org/wiki/Euler%27s_equations_(rigid_body_dynamics)>`__:
.. math::
I \dot{\omega} + \omega \times I\omega = \tau
where :math:`\tau` is the external torque in the principal-axis frame.
Evaluating the velocities at the midpoint, :math:`\omega_\text{mid} = (\omega_t + \omega_{t+h})/2`, gives:
.. math::
\frac{2}{h} I (\omega_\text{mid} - \omega_t) + \omega_\text{mid} \times I \omega_\text{mid} = \tau
This is a system of 3 nonlinear equations in 3 unknowns :math:`\omega_\text{mid}`, solved at each timestep using
Newton's method with a backtracking line search. After solving, the new velocity is recovered as
:math:`\omega_{t+h} = 2\omega_\text{mid} - \omega_t`.
**Properties.** The midpoint method preserves all `quadratic first integrals
<https://doi.org/10.1007/3-540-30666-8>`__ of the ODE. For Euler's equations, these are the
kinetic energy :math:`H = \frac{1}{2}\omega^T I\omega` and the squared angular momentum
:math:`C = \frac{1}{2}|I\omega|^2`, both conserved exactly in the absence of external torque. Since :math:`C` is the
Casimir function of the `Lie-Poisson <https://en.wikipedia.org/wiki/Poisson_bracket>`__ structure, the midpoint
method is a symmetric (time-reversible) and second-order accurate *Poisson integrator*.
**Eligibility.** Midpoint integration is only applied to free bodies with no child bodies.
**Performance.** While the midpoint method carries computational overhead, we've found it to be
negligible compared to the rest of the pipeline, on the order of 1% in the worst case.
**Disabling.** Because midpoint integration solves a nonlinear equation for the next velocity, it breaks the linear
relationship between finite-differenced velocities and forces assumed by discrete inverse dynamics. Therefore,
setting the :ref:`invdiscrete<option-flag-invdiscrete>` flag disables midpoint integration, and also provides a
general opt-out mechanism for this integrator.
.. _geIntegrators:
Integrators
@@ -610,6 +653,9 @@ Fast implicit-in-velocity (``implicitfast``)
derivatives are also the main source of asymmetry of :math:`D`, by dropping them and symmetrizing, we can use the
faster :math:`L^TL` rather than :math:`LU` decomposition.
Both ``implicit`` and ``implicitfast`` apply :ref:`midpoint integration<geMidpoint>` to eligible free bodies,
providing exact energy conservation for spinning objects at negligible additional cost.
4th-order Runge-Kutta (``RK4``)
One advantage of our continuous-time formulation is that we can use higher order integrators such as Runge-Kutta or
multistep methods. MuJoCo implements the fixed-step `4th-order Runge-Kutta method
@@ -641,11 +687,11 @@ Fast implicit-in-velocity (``implicitfast``)
The ``implicitfast`` integrator has similar computational cost to ``Euler``, yet provides
increased stability, and is therefore a strict improvement. It is the recommended integrator for most models.
**implicit**:
The benefit over ``implicitfast`` is the implicit integration of Coriolis and centripetal forces, including
gyroscopic forces. The most common case where integrating such forces implicitly leads to noticeable improvement is
when free objects with asymmetric inertia are spinning quickly. `gyroscopic.xml <../_static/gyroscopic.xml>`__
shows an ellipsoid rolling on an inclined plane which quickly diverges with ``implicitfast`` but is stable with
``implicit``.
The benefit over ``implicitfast`` is the implicit integration of Coriolis and centripetal forces for *coupled*
rotational systems such as multi-link pendula. Both ``implicitfast`` and ``implicit`` apply :ref:`midpoint
integration<geMidpoint>` to eligible free bodies with no children, for example
`gyroscopic.xml <../_static/gyroscopic.xml>`__ shows an ellipsoid rolling on an
inclined plane; both ``implicitfast`` and ``implicit`` handle this case well, while ``Euler`` quickly diverges.
**RK4**:
This integrator is best for systems which are energy conserving, or almost energy-conserving. `pendulum.xml
<../_static/pendulum.xml>`__ shows a complicated pendulum mechanism which diverges quickly using ``Euler`` or