Add sleeping documentation

https://youtu.be/vct493lGQ8Q

PiperOrigin-RevId: 829390353
Change-Id: I92f85a03be0bb585d2d8e29de1ed1a2e848f247f
This commit is contained in:
Yuval Tassa
2025-11-07 05:11:31 -08:00
committed by Copybara-Service
parent 769f37b653
commit 8734cab366
8 changed files with 754 additions and 29 deletions
+65 -14
View File
@@ -1380,25 +1380,28 @@ Constraint islands
:width: 58%
:align: right
Consider the abstract graph defined by degrees of freedom (dofs) and constraints. A vertex is all the dofs in a single
kinematic subtree; an edge is a constraint (a contact or equality) between two bodies belonging to different subtrees. A
*constraint island* is a disjoint sub-graph which can be solved for independently, because constraint forces cannot
propagate between islands. Constraint island discovery and construction ("islanding") invloves finding the disjoint
subgraphs and reordering both the dofs and constraints to make them memory-contiguous. This amounts to a
block-diagonalization of the constraint Jacobian :math:`J`, as illustrated in the figure. On the left is the monolithic
Jacobian of size :math:`\nc \times \nv`, where we use the :ref:`corresponding <Framework>` size names from MuJoCo's data
structures ``mjData.nefc`` and ``mjModel.nv``. On the right is the block-diagonalized Jacobian with 3 islands that can
be solved indepenently. Note that islanding also identifies unconstrained dofs, so ``mjData.nidof``, the total number of
dofs in all islands, might be smaller than ``mjModel.nv``. While islanding is not free (see implementation in
`engine_island.c <https://github.com/google-deepmind/mujoco/blob/main/src/engine/engine_island.c>`__), it is worth the
effort:
Consider the abstract graph defined by degrees of freedom (:ref:`DOFs<ElemDof>`) and constraints. A vertex is all the
DOFs in a single kinematic :ref:`tree<ElemTree>`; an edge is a constraint (a contact, equality or tendon limit) between
two bodies belonging to different trees. A *constraint island* is a disjoint sub-graph which can be solved for
independently, because constraint forces cannot propagate between islands. Constraint island discovery and construction
("islanding") involves finding these disjoint subgraphs and reordering both the DOFs and constraints to make them
memory-contiguous. This amounts to a block-diagonalization of the constraint Jacobian :math:`J`, as illustrated in the
figure. On the left is the monolithic Jacobian of size :math:`\nc \times \nv`, where we use the :ref:`corresponding
<Framework>` size names from MuJoCo's data structures ``mjData.nefc`` and ``mjModel.nv``. On the right is the
block-diagonalized Jacobian with 3 islands that can be solved independently. Note that islanding also identifies
unconstrained DOFs, so ``mjData.nidof``, the total number of DOFs in all islands, might be smaller than ``mjModel.nv``.
While islanding is not free (see implementation in `engine_island.c
<https://github.com/google-deepmind/mujoco/blob/main/src/engine/engine_island.c>`__), it is worth the effort:
- Different islands require different numbers of iterations to converge, and a monolithic solve would run for the
number required by the slowest island.
- Unconstrained dofs are completely untouched by the solver, which otherwise needs to discover that they are unaffected.
- Unconstrained DOFs are completely untouched by the solver, which otherwise needs to discover that they are unaffected.
- Solving separate islands can be multi-threaded.
Islanding is not yet supported by the PGS solver.
.. admonition:: Known issues
:class: note
Islanding is not yet supported by the PGS solver.
.. _soParameters:
@@ -1668,6 +1671,54 @@ callbacks. This can be used to incorporate a general-purpose "triangle soup" col
do not recommend such an approach. Pre-processing the geometry and representing it as a union of convex geoms takes some
work, but it pays off at runtime and yields both faster and more stable simulation.
.. _Sleeping:
Sleeping islands
----------------
Sleeping is a performance optimization whereby movable elements of the simulation that are detected to be stationary are
temporarily removed from the pipeline ("put to sleep"). This optimization is most useful when the model contains a large
number of passive objects. The smallest unit which can be asleep or awake is a :ref:`kinematic tree<ElemTree>`, however
trees are always put to sleep together with other trees to which they are connected by constraints, hence the term
"sleeping :ref:`islands<soIsland>`".
.. youtube:: vct493lGQ8Q
:align: right
:width: 50%
The video on the right demonstrates several aspects of sleeping. First we show the `dominos
<https://github.com/google-deepmind/mujoco/blob/main/model/sleep/dominos.xml>`__ model, which simulates a traditional
"chain reaction" of falling domino bricks. All bricks except one are in a stable equilibrium and quickly go to sleep,
but the first brick, which is unstable, remains awake and starts falling. Every time a contact is made between awake and
sleeping bricks, the latter are woken automatically. After stabilizing on the ground, piles of bricks are put to sleep
again and their associated contacts disappear. This sequence is repeated with island visualization enabled, which
recolors geoms according to the first DOF of their island, using darker colors if asleep. At the end of the subclip,
sleeping is toggled off and on, demonstrating the speed gain afforded by sleeping (lower right). The second subclip
shows a variant of the `100 humanoids
<https://github.com/google-deepmind/mujoco/blob/main/model/sleep/100_humanoids.xml>`__ model, where all humanoids are
*initialized asleep*. Trees initialized as sleeping can be in any configuration, including floating in mid-air, deep
penetration, etc. One humanoid is manually woken by direct user perturbation and then dragged around to wake any other
humanoid that it touches.
While the smooth dynamics benefit from sleeping, the largest speedup is due to the reduced number of contacts. Sleeping
islands behave like static bodies for the purpose of collision detection: all contacts within an island and between the
island and static bodies are skipped. In the case of static piles of objects, the number of skipped contacts can be
high, leading to substantial speed gains. Contacts between sleeping islands and awake trees are allowed, and indeed are
the main automatic trigger for waking, though manual waking is also supported. Because waking happens in the
:ref:`position stage <piStages>` of the pipeline it is effectively instantaneous, and the woken island will behave
exactly as if it was awake all along.
Sleeping is off by default and enabled using the :ref:`sleep<option-flag-sleep>` flag. A detailed description of the
sleeping mechanism is provided in the :ref:`Simulation chapter<siSleep>` but here we provide a brief overview.
Sleeping can occur in one of two ways:
- **Automatic:** A tree whose maximum velocity in absolute value is less than the
:ref:`tolerance <option-sleep_tolerance>` for :ref:`mjMINAWAKE <glNumeric>` time steps is marked as "ready to sleep".
If all trees in an island are ready to sleep, they are put to sleep during state advancement.
- **Initialized asleep:** By setting the :ref:`body/sleep<body-sleep>` attribute of a tree root to "init", it is
marked as "initialized-asleep" and put to sleep during :ref:`mjData` initialization.
.. _Pipeline:
Simulation pipeline