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
+36 -3
View File
@@ -463,7 +463,7 @@ adjust it properly through the XML.
.. _option-sleep_tolerance:
:at:`sleep_tolerance`: :at-val:`real, "1e-4"`
Velocity tolerance below which sleeping is possible. Feature under development, documentation pending.
Velocity tolerance below which :ref:`sleeping<Sleeping>` is allowed.
.. _option-sdf_iterations:
@@ -674,7 +674,16 @@ from its default.
.. _option-flag-sleep:
:at:`sleep`: :at-val:`[disable, enable], "disable"`
This flag enables sleeping. Feature under development, documentation pending.
This flag enables :ref:`sleeping<Sleeping>`. Disabling this flag when some trees are sleeping will wake them.
.. admonition:: flag value at initialization time
:class: attention
Unlike any other :ref:`flag<option-flag>`, the :at:`sleep` flag has an effect during :ref:`mjData`
**initialization** (:ref:`mj_makeData` or :ref:`mj_resetData`). First, it must be set at initialization time in
order for the :ref:`sleep-init<body-sleep>` policy to take effect. Second, it must be set in order for static
quantities to be computed. See :ref:`implementation notes<siSleep>` for more details.
.. _compiler:
@@ -2072,7 +2081,31 @@ defined. Its body name is automatically defined as "world".
.. _body-sleep:
:at:`sleep`: :at-val:`[auto, never, allowed, init], "auto"`
Sleep policy for the tree under this body. Feature under development, documentation pending.
:ref:`Sleep<Sleeping>` policy for the tree under this body. This attribute is only supported by moving bodies which
are the root of a kinematic :ref:`tree<ElemTree>`. For the default :at-val:`auto`, the compiler will set the sleep
policy as follows:
- A tree which is affected by actuators is not allowed to sleep (overridable).
- Trees which are connected by tendons which have non-zero stiffness and damping are not allowed to sleep
(overridable).
- Trees which are connected by tendons which connect more than two trees are not allowed to sleep (not overridable).
- :ref:`flexes<ElemFlex>` are not allowed to sleep (not overridable).
- All other trees are allowed to sleep (overridable).
The policies :at-val:`never` and :at-val:`allowed` constitute user overrides of the automatic compiler policy.
The :at-val:`init` sleep policy can only be specified by the user and means "initialize this tree as asleep". This
policy is implemented in :ref:`mj_resetData` and :ref:`mj_makeData` and only applies to the default configuration. If
a :ref:`keyframe<keyframe>` changes the configuration of (or assigns nonzero velocity to) a sleeping tree, it will be
woken up. This policy is useful for very large models where waiting for the automatic sleeping mechanism to kick in
can be expensive. Trees initialized as sleeping can be placed in unstable configurations like deep penetration or in
mid-air, but will only move when woken up. Also note that this policy can fail. For example if a tree marked as
sleep="init" is in contact with a tree not marked as such (i.e., they are in the same :ref:`island<soIsland>`) then
it is impossible to put the tree to sleep; such `models
<https://github.com/google-deepmind/mujoco/blob/main/test/engine/testdata/sleep/init_island_fail.xml>`__ will lead to
a compilation error.
See :ref:`implementation notes<siSleep>` for more details.
.. _body-user:
+7 -2
View File
@@ -6,9 +6,14 @@ Upcoming version (not yet released)
-----------------------------------
General
^^^^^^^^^
^^^^^^^
- Initial changes related to sleeping. Feature under development, documentation pending.
.. youtube:: vct493lGQ8Q
:align: right
:width: 35%
- Introduced a major new feature: :ref:`sleeping islands<Sleeping>`. Preliminary release for early testing, see
documentation for details.
- Added "quadratic" option to :ref:`flexcomp/dof<body-flexcomp-dof>`. This type of fast :ref:`deformable<CDeformable>`
flex object is similar to the "trilinear" option, but it includes curved deformations.
- Raise an error if there are name collisions also during parsing.
+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
+60 -9
View File
@@ -422,12 +422,19 @@ Kinematic tree
~~~~~~~~~~~~~~
MuJoCo simulates the dynamics of a collection of rigid bodies whose motion is usually constrained. The system state is
represented in joint coordinates and the bodies are explicitly organized into kinematic trees. Each body except for the
top-level "world" body has a unique parent. Kinematic loops are not allowed; if loop joints are needed they should be
modeled with equality constraints. Thus the backbone of a MuJoCo model is one or several kinematic trees formed by
nested body definitions; an isolated floating body counts as a tree. Several other elements listed below are defined
within a body and belong to that body. This is in contrast with the stand-alone elements listed later which cannot be
associated with a single body.
represented in joint coordinates and the bodies are explicitly organized into kinematic trees. The tree structure is
given by ``mjModel.body_parentid``, an integer array of length ``nbody >= 1``. The top-level "world" body always exists
(with id ``0``) and is its own parent, thus ``body_parentid[0] == 0`` and ``body_parentid[i] < i`` for all other ``i``.
Note that the world body and other static (joint-less) child bodies form a unique "static tree" with no associated
degrees of freedom. Below this top-level static tree, multiple kinematic trees can be attached, see :ref:`Tree
<ElemTree>` below.
Kinematic loops are not allowed; if loop joints are needed they should be modeled with equality constraints. Thus the
backbone of a MuJoCo model is one or several kinematic trees formed by nested body definitions; an isolated floating
body counts as a tree. Several other elements listed below are defined within a body and belong to that body. This is in
contrast with the stand-alone elements listed later which cannot be associated with a single body.
.. _ElemBody:
Body
^^^^
@@ -438,6 +445,9 @@ position other elements relative to it, and an inertial frame centered at the bo
its principal axes of inertia. The body inertia matrix is therefore diagonal in this frame. At each time step MuJoCo
computes the forward kinematics recursively, yielding all body positions and orientations in global Cartesian
coordinates. This provides the basis for all subsequent computations.
The number of bodies is given by ``mjModel.nbody``.
.. _ElemJoint:
Joint
^^^^^
@@ -448,7 +458,7 @@ over-complete Cartesian coordinates, where joints remove DOFs instead of adding
ball, slide, hinge, and a "free joint" which creates floating bodies. A single body can have multiple joints. In this
way composite joints are created automatically, without having to define dummy bodies. The orientation components of
ball and free joints are represented as unit quaternions, and all computations in MuJoCo respect the properties of
quaternions.
quaternions. The number of joints is given by ``mjModel.njnt``.
Joint reference
'''''''''''''''
@@ -475,6 +485,8 @@ spring reference pose is saved in ``mjModel.qpos_spring``. For slide and hinge j
specified with the attribute springref. For ball and free joints, the spring reference corresponds to the initial
model configuration.
.. _ElemDof:
DOF
^^^
@@ -485,7 +497,27 @@ system, while the joint velocities are coordinates over the tangent space to thi
DOFs have velocity-related properties such as friction loss, damping, armature inertia. All generalized forces acting
on the system are expressed in the space of DOFs. In contrast, joints have position-related properties such as limits
and spring stiffness. DOFs are not specified directly by the user. Instead they are created by the compiler given the
joints.
joints. The number of DOFs is given by ``mjModel.nv``.
.. _ElemTree:
Tree
^^^^
As explained :ref:`above <Kinematic>`, moving bodies are organized into kinematic trees. A kinematic tree or "tree" is
*a movable body and all of its descendants*. Thus the world and other static bodies are in the global tree structure but
not associated with any *tree*. Because the global tree structure uses a depth-first organization, all bodies, joints
and DOFs belonging to a single tree are always sequential. Note that unlike bodies which (if static) are not associated
with any tree, joints and DOFs are always associated with a tree. Both :ref:`island discovery <soIsland>` and
:ref:`island sleeping <Sleeping>` operate on the level of trees.
The number of trees is given by ``mjModel.ntree``. For example, a model containing three free bodies and the `standard
humanoid <https://github.com/google-deepmind/mujoco/blob/main/model/humanoid/humanoid.xml>`__ has ``ntree = 4``. Note
that while trees are indeed subtrees of the global tree (whose root is the world), this should not be confused with the
specific term ``subtree``, which is reserved for per-body partial trees, thus ``mjModel.body_subtreemass`` gives the
total mass of the partial tree under each body, for all bodies.
.. _ElemGeom:
Geom
^^^^
@@ -497,6 +529,9 @@ subsequent computation of contact forces, geoms are used for rendering, as well
and inertias when the latter are omitted. MuJoCo supports several primitive geometric shapes: plane, sphere, capsule,
ellipsoid, cylinder, box. A geom can also be a mesh or a height field; this is done by referencing the corresponding
asset. Geoms have a number of material properties that affect the simulation and visualization.
The number of geoms is given by ``mjModel.ngeom``.
.. _ElemSite:
Site
^^^^
@@ -504,6 +539,9 @@ Site
Sites are essentially light geoms. They represent locations of interest within the body frame. Sites do not
participate in collision detection or automated computation of inertial properties, however they can be used to
specify the spatial properties of other objects like sensors, tendon routing, and slider-crank endpoints.
The number of sites is given by ``mjModel.nsite``.
.. _ElemCamera:
Camera
^^^^^^
@@ -515,6 +553,9 @@ orientation, the user can adjust the vertical field of view and the inter-pupila
as well as create oblique projections needed for stereoscopic virtual environments. When modeling real cameras with
imperfect optics, it is possible to specify separate focal lengths for the horizontal and vertical directions and a
non-centered principal point.
The number of cameras is given by ``mjModel.ncam``.
.. _ElemLight:
Light
^^^^^
@@ -527,6 +568,7 @@ used with caution. Documenting the lighting model in detail is beyond the scope
documentation <http://www.glprogramming.com/red/chapter05.html>`__ instead. Note that in addition to lights defined
by the user in the kinematic tree, there is a default headlight that moves with the camera. Its properties are
adjusted through the mjVisual options.
The number of lights is given by ``mjModel.nlight``.
.. _Standalone:
@@ -536,6 +578,8 @@ Stand-alone
Here we describe the model elements which do not belong to an individual body, and therefore are described outside the
kinematic tree.
.. _ElemTendon:
Tendon
^^^^^^
@@ -549,6 +593,8 @@ other, the user can also specify the preferred side. If there are multiple wrapp
must be separated by sites, so as to avoid the need for an iterative solver. Spatial tendons can also be split into
multiple branches using pulleys.
.. _ElemActuator:
Actuator
^^^^^^^^
@@ -561,6 +607,8 @@ biological muscles; using such actuators makes the overall system dynamics 3rd-o
determines how the scalar control signal provided as input to the actuator is mapped into a scalar force, which is in
turn mapped into a generalized force by the moment arms inferred from the transmission.
.. _ElemSensor:
Sensor
^^^^^^
@@ -574,6 +622,8 @@ other quantity of interest in the sensor data array. MuJoCo also has off-screen
straightforward to simulate both color and depth camera sensors. This is not included in the standard sensor model
and instead has to be done programmatically, as illustrated in the code sample :ref:`simulate.cc <saSimulate>`.
.. _ElemEquality:
Equality
^^^^^^^^
@@ -584,11 +634,12 @@ available equality constraint types are: connect two bodies at a point (creating
tree); weld two bodies together; fix the position of a joint or tendon; couple the positions of two joints or two
tendons via a cubic polynomial; constrain the edges of a flex (i.e. deformable mesh) to their initial lengths.
.. _ElemFlex:
Flex
^^^^
Flexes were added in MuJoCo 3.0. They represent deformable meshes that can be 1, 2 or 3 dimensional (thus their elements
Flexes represent deformable meshes that can be 1, 2 or 3 dimensional (thus their elements
are capsules, triangles or tetrahedra). Unlike geoms which are static shapes attached rigidly to a single body, the
elements of a flex are deformable: they are constructed by connecting multiple bodies, thus the body positions and
orientations determine the shape of the flex elements at runtime. These deformable elements support collisions and
+171 -1
View File
@@ -106,7 +106,7 @@ The default (and recommended) way to control the system is to implement a contro
.. code-block:: C
// simple controller applying damping to each dof
// simple controller applying damping to each DOF
void mycontroller(const mjModel* m, mjData* d) {
if (m->nu == m->nv)
mju_scl(d->ctrl, d->qvel, -0.1, m->nv);
@@ -923,6 +923,176 @@ is in [3-5] and the Z axis is in [6-8]. The reason for this arrangement is becau
where only the normal axis is used, so it makes sense to have its coordinates in the first 3 positions of
``mjContact.frame``.
.. _siSleep:
Sleeping islands
~~~~~~~~~~~~~~~~
Sleeping islands are described in broad strokes in the :ref:`Computation chapter <Sleeping>`. Here we focus on
implementation details.
The high level sleep state of :ref:`trees<ElemTree>` is described by ``mjData.tree_asleep`` (though see caveat below). A
negative value means a tree is awake, non-negative means asleep. Maximally awake trees are given the value - |-| (1 |-|
+ |-| :ref:`mjMINAWAKE<glNumeric>`), and for every timestep where their velocity falls below the sleep :ref:`tolerance
<option-sleep_tolerance>`, this integer is incremented, up to -1, which means "ready to sleep". If all trees in an
island are ready to sleep, they are put to sleep during state advancement and their associated values in ``tree_asleep``
are set to a (non-negative) index cycle: the "sleeping island". If any tree in the island is woken, all are woken.
Sleep policy
^^^^^^^^^^^^
The ability of a kinematic tree to sleep is governed by a policy determined at model compile time. The compiler
automatically determines the :ref:`policy<mjtSleepPolicy>` to be either "allowed" or "never", though these can be
overridden using the :ref:`body/sleep <body-sleep>` attribute (see documentation therein). There is also a special
"init" sleep policy, see next section.
Sleeping
^^^^^^^^
Sleeping can happen in one of two ways:
**Automatic:**
The velocity threshold described above is w.r.t. the infinity norm (largest absolute value) of all velocities
associated with an island. Before taking this norm, velocities are scaled elementwise by ``mjModel.dof_length``
because rotational and translational velocities have different units. The length of a translational DOF is 1; the
length of a rotational DOF corresponds to the mean length of its associated geometry. Thus :ref:`sleep_tolerance
<option-sleep_tolerance>` has units of [length/time].
When an island is put to sleep, its associated velocities are set to 0. Therefore, on any timestep where
islands are put to sleep, all velocity-dependent quantities must be recomputed before the sleep state is propagated
using a call to :ref:`mj_forwardSkip`.
If any tree in the island has the "never" sleep policy, the entire island cannot sleep.
**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. This is useful for large models where waiting for many trees to
fall asleep can be expensive.
Since trees which share contacts or are otherwise in the same island must sleep together, if some trees in an island
are initialized as sleeping, all of them must be marked as such. `This model
<https://github.com/google-deepmind/mujoco/blob/main/test/engine/testdata/sleep/init_island_fail.xml>`__ contains an
example XML that will produce a compilation error because this condition is not met. Finally, note that the
initialized-asleep feature is only available for the default configuration (and not keyframes, see discussion below).
Waking
^^^^^^
Waking happens at the beginning of the timestep, either during :ref:`mj_kinematics` or soon thereafter during the
:ref:`position stage <piStages>` of the simulation pipeline. A sleeping island is woken up according to the following
criteria:
- Its associated configuration ``qpos`` is changed by the user, for example when repositioning the
configuration interactively when the simulation is paused.
- Its associated velocity ``qvel`` or applied forces ``qfrc_applied`` or ``xfrc_applied`` are set by the user to
a non-zero value, for example when perturbing the model interactively during simulation.
Note that the check is performed by bytewise comparison to 0, so setting an associated element to
the floating point value ``-0.0`` will wake the island but have no other side-effects.
- It comes into contact with an awake tree. Waking due to contact leads to collision detection being run *twice*, but
only on the timestep when it occurs. This is required in order to detect contacts inside the island and between the
island and the world, which were skipped in the first run when it was deemed asleep.
- It is connected to an awake tree by an active equality constraint or limited tendon.
- It is connected by an equality constraint to a sleeping tree in a different island. For this to occur, the equality
must have been disabled when both trees were put to sleep.
The automatic wake criteria listed above are designed so that sleeping islands behave as if they were awake, but this
is not always the case. For example, if free bodies on the floor are put to sleep and then gravity is reversed, they
will remain sleeping in place until woken for another reason. The most extreme example of non-physicality are islands
which are initialized asleep. These can be placed in mid-air or in deep collisions, but will not move until woken.
Notes
^^^^^
.. admonition:: New feature
:class: warning
Sleeping is a new feature (Nov 2025) that is subject to change and may have latent bugs.
**Sleeping actuators**
As explained in the :ref:`body/sleep <body-sleep>` documentation, trees with actuators are by default not allowed to
sleep, but this can be overridden by the user. The reason sleeping is not allowed by default is that once an actuator
is marked as asleep, the computation required to wake it is no longer performed. Even if it were performed (i.e. if
actuation forces were always computed for all actuators, regardless of their sleep state), this computation happens in
acceleration/force stage, by which time it is already too late to wake a tree, since waking must happen in the
position stage. Therefore, if a tree with actuators is allowed to sleep, waking must be done manually by touching the
associated velocities or forces, as described above.
**Sleeping sensors**
The computation of sensor values are skipped if the objects associated with it are asleep or static, so the last
valid computed values remain untouched. This is straightforward for most sensors, but :ref:`contact<sensor-contact>`
sensors are an exception. Because contact sensors report contacts that occurred in the current timestep, and
sleeping implies that some contacts are not computed, skipping the sensor computation is not always possible.
For example, consider a scene with free bodies on the floor, some of which may be asleep. A sensor which reports
information from contacts of body A (with anything else), will keep reporting the same thing when the body goes to
sleep. However a sensor that reports all world contacts will report something different when some bodies go to sleep.
**Provisional choices**
Some implementation choices are provisional and subject to change.
A concrete example is the decision to hard-code the value of :ref:`mjMINAWAKE<glNumeric>` instead of exposing it to
the user as a runtime option. This was done for two reasons. First, in our experiments, we've found that changing this
value is equivalent to changing the :ref:`sleep_tolerance<option-sleep_tolerance>`, which is the more useful knob.
Second, one could argue for a time-to-sleep semantic that is in units of time rather than an integer number of
timesteps. Until there is clear evidence that one or both of these reasons are invalid, we've opted for a simple
numeric constant.
**Static bodies**
Besides the main optimization of allowing kinematic trees to sleep, the sleep feature also includes another, related
optimization: the skipping of computation related to static bodies. This can be valuable if, for example,
the world body or its static children contain a large number of geoms, whose poses will be computed only once.
This leads to a subtle (if unlikely) "gotcha". Although it is allowed to enable sleeping during simulation, sleeping
must be enabled either at initialization time or after at least one :ref:`mj_step`. To wit:
.. code-block:: C
// this is OK:
mjData* d = mj_makeData(m); // sleeping is enabled at init time
mj_step(m, d);
...
// this is also OK:
mjData* d = mj_makeData(m); // sleeping is disabled at init time
mj_step(m, d);
...
m->opt.enableflags |= mjENABLE_SLEEP; // enable sleeping after at least one step
mj_step(m, d);
// this is an error:
mjData* d = mj_makeData(m); // sleeping is disabled at init time
m->opt.enableflags |= mjENABLE_SLEEP; // enable sleeping
mj_step(m, d); // undefined behavior, static elements not computed
**Violated assumptions**
Sleeping breaks several assumptions that are baked into the core of MuJoCo (and continue to hold if sleeping is
disabled).
*Pipeline stages*: It is usually guaranteed that no velocity-related quantities will be read before the end of the
position stage and that no force-related quantities will be read before the end of velocity stage. This assumption,
which lies at the heart of the :ref:`mj_step1`/:ref:`mj_step2` split, is violated by the reading of ``qvel``,
``qfrc_applied`` and ``xfrc_applied`` in :ref:`mj_kinematics`.
*Compact state*: While the sleep state is notionally given by ``mjData.tree_asleep``, this is a mirage. Once an island
is asleep, the entire subset of position and velocity-dependent quantities in mjData associated with it becomes
a pre-computed latent state that is "waiting for the island to wake up". For this reason, the only way to fully save
and restore the state of a simulation with sleeping elements is to :ref:`copy<mj_copyData>` the entire mjData
structure. This is also the reason why sleep initialization is only available for the default configuration and not
for keyframes. Note that saving and loading the state using the :ref:`standard tools<geState>` remains a valid
operation, merely that sleeping islands will be implicitly woken up.
**RK4 integrator**
The RK4 integrator is not currently supported, due to the subtleties of waking inside the sub-steps.
**Latent bugs**
Sleeping is a new feature (Nov 2025) and may have latent bugs. These bugs may generally come in two varieties:
- Quantities which could be skipped are instead recomputed. The only observable effect of such a bug would be that
the simulation is slower than it could be. This type of bug can only be diagnosed with detailed profiling.
- Actual bugs. Hopefully these will lead to informative runtime errors, please report any to the development team.
.. _siCoordinate:
Coordinate frames and transformations
+50
View File
@@ -0,0 +1,50 @@
<!-- Copyright 2025 DeepMind Technologies Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<mujoco model="100 Humanoids">
<option timestep="0.005">
<!-- modification of model/humanoid/100_humanoids.xml: enable sleep -->
<flag sleep="enable"/>
</option>
<size memory="100M"/>
<asset>
<texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="512" height="512"/>
<texture name="floor" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
<material name="floor" texture="floor" texrepeat="1 1" texuniform="true" reflectance=".2"/>
<model name="humanoid" file="humanoid.xml"/>
</asset>
<visual>
<map force="0.1" zfar="30"/>
<rgba haze="0.15 0.25 0.35 1"/>
<quality numslices="16" numstacks="8"/>
<global offwidth="800" offheight="800"/>
</visual>
<worldbody>
<geom name="floor" size="10 10 .05" type="plane" material="floor" condim="3"/>
<light directional="true" diffuse=".9 .9 .9" specular="0.1 0.1 0.1" pos="0 0 5" dir="0 0 -1" castshadow="true"/>
<light name="spotlight" mode="targetbodycom" target="world" diffuse="1 1 1" specular="0.3 0.3 0.3" pos="-6 -6 4" cutoff="60"/>
<replicate count="10" euler="0 0 36" sep="-">
<frame pos="1.2 0 0">
<replicate count="10" euler="0 0 17" sep="-" offset="0.6 0 0">
<attach model="humanoid" body="torso" prefix="_"/>
</replicate>
</frame>
</replicate>
</worldbody>
</mujoco>
+92
View File
@@ -0,0 +1,92 @@
<!-- Copyright 2025 DeepMind Technologies Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<mujoco model="sleeping dominos">
<option cone="elliptic" impratio="10" sleep_tolerance="3e-4">
<flag sleep="enable"/>
</option>
<default>
<default class="domino">
<geom type="box" size=".008 .044 .089" rgba=".9 .9 .9 1" mass="0.09"/>
</default>
</default>
<worldbody>
<light pos=".5 0 3" diffuse="1 1 1"/>
<geom type="plane" size="2 2 .01" pos=".5 0 1e-6"/>
<!-- one domino atilt kicks off the chain reaction -->
<body pos="-.1 0 .089" euler="0 7 0">
<freejoint/>
<geom type="box" class="domino"/>
</body>
<!-- 5 rows of 15 dominoes, arranged in toppling order for consistent ids and colors -->
<!-- 3 rows of 15 dominoes, left to right -->
<replicate count="3" offset="0 1 0">
<frame pos="0 -1 0">
<replicate count="15" offset=".1 0 0">
<body pos="0 0 .089">
<freejoint/>
<geom type="box" class="domino"/>
</body>
</replicate>
</frame>
</replicate>
<!-- 2 rows of 15 dominoes, right to left -->
<replicate count="2" offset="0 1 0">
<frame pos="0 -.5 0">
<replicate count="15" offset="-.1 0 0">
<body pos="1.4 0 .089">
<freejoint/>
<geom type="box" class="domino"/>
</body>
</replicate>
</frame>
</replicate>
<!-- two "U turns", place blocks not too close in order to break the island chain -->
<replicate offset="0 -.55 0" count="2">
<frame pos="1.5 .26 0">
<replicate count="5" euler="0 0 45">
<body pos="0 -.23 .089">
<freejoint/>
<geom type="box" class="domino"/>
</body>
</replicate>
</frame>
</replicate>
<!-- two more U turns for the outside rows -->
<replicate offset="0 1.5 0" count="2">
<frame pos="-.1 -.75 0" euler="0 0 180">
<replicate count="5" euler="0 0 45">
<body pos="0 -.23 .089">
<freejoint/>
<geom type="box" class="domino"/>
</body>
</replicate>
</frame>
</replicate>
</worldbody>
<visual>
<global elevation="-25" azimuth="60"/>
</visual>
<statistic center="1.2 0 0"/>
</mujoco>
+273
View File
@@ -0,0 +1,273 @@
<!-- Copyright 2025 DeepMind Technologies Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<mujoco model="Humanoid">
<option timestep="0.005">
<!-- modification of model/humanoid/humanoid.xml: enable sleep -->
<flag sleep="enable"/>
</option>
<visual>
<map force="0.1" zfar="30"/>
<rgba haze="0.15 0.25 0.35 1"/>
<global offwidth="2560" offheight="1440" elevation="-20" azimuth="120"/>
</visual>
<statistic center="0 0 0.7"/>
<asset>
<texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="32" height="512"/>
<texture name="body" type="cube" builtin="flat" mark="cross" width="128" height="128" rgb1="0.8 0.6 0.4" rgb2="0.8 0.6 0.4" markrgb="1 1 1"/>
<material name="body" texture="body" texuniform="true" rgba="0.8 0.6 .4 1"/>
<texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
<material name="grid" texture="grid" texrepeat="1 1" texuniform="true" reflectance=".2"/>
</asset>
<default>
<motor ctrlrange="-1 1" ctrllimited="true"/>
<default class="body">
<!-- geoms -->
<geom type="capsule" condim="1" friction=".7" solimp=".9 .99 .003" solref=".015 1" material="body" group="1"/>
<default class="thigh">
<geom size=".06"/>
</default>
<default class="shin">
<geom fromto="0 0 0 0 0 -.3" size=".049"/>
</default>
<default class="foot">
<geom size=".027"/>
<default class="foot1">
<geom fromto="-.07 -.01 0 .14 -.03 0"/>
</default>
<default class="foot2">
<geom fromto="-.07 .01 0 .14 .03 0"/>
</default>
</default>
<default class="arm_upper">
<geom size=".04"/>
</default>
<default class="arm_lower">
<geom size=".031"/>
</default>
<default class="hand">
<geom type="sphere" size=".04"/>
</default>
<!-- joints -->
<joint type="hinge" damping=".2" stiffness="1" armature=".01" limited="true" solimplimit="0 .99 .01"/>
<default class="joint_big">
<joint damping="5" stiffness="10"/>
<default class="hip_x">
<joint range="-30 10"/>
</default>
<default class="hip_z">
<joint range="-60 35"/>
</default>
<default class="hip_y">
<joint axis="0 1 0" range="-150 20"/>
</default>
<default class="joint_big_stiff">
<joint stiffness="20"/>
</default>
</default>
<default class="knee">
<joint pos="0 0 .02" axis="0 -1 0" range="-160 2"/>
</default>
<default class="ankle">
<joint range="-50 50"/>
<default class="ankle_y">
<joint pos="0 0 .08" axis="0 1 0" stiffness="6"/>
</default>
<default class="ankle_x">
<joint pos="0 0 .04" stiffness="3"/>
</default>
</default>
<default class="shoulder">
<joint range="-85 60"/>
</default>
<default class="elbow">
<joint range="-100 50" stiffness="0"/>
</default>
</default>
</default>
<worldbody>
<geom name="floor" size="0 0 .05" type="plane" material="grid" condim="3"/>
<light name="spotlight" mode="targetbodycom" target="torso" diffuse=".8 .8 .8" specular="0.3 0.3 0.3" pos="0 -6 4" cutoff="30"/>
<light name="top" pos="0 0 2" mode="trackcom"/>
<!-- modification of model/humanoid/humanoid.xml: initialized asleep -->
<body name="torso" pos="0 0 1.282" childclass="body" sleep="init">
<camera name="back" pos="-3 0 1" xyaxes="0 -1 0 1 0 2" mode="trackcom"/>
<camera name="side" pos="0 -3 1" xyaxes="1 0 0 0 1 2" mode="trackcom"/>
<freejoint name="root"/>
<geom name="torso" fromto="0 -.07 0 0 .07 0" size=".07"/>
<geom name="waist_upper" fromto="-.01 -.06 -.12 -.01 .06 -.12" size=".06"/>
<body name="head" pos="0 0 .19">
<geom name="head" type="sphere" size=".09"/>
<camera name="egocentric" pos=".09 0 0" xyaxes="0 -1 0 .1 0 1" fovy="80"/>
</body>
<body name="waist_lower" pos="-.01 0 -.26">
<geom name="waist_lower" fromto="0 -.06 0 0 .06 0" size=".06"/>
<joint name="abdomen_z" pos="0 0 .065" axis="0 0 1" range="-45 45" class="joint_big_stiff"/>
<joint name="abdomen_y" pos="0 0 .065" axis="0 1 0" range="-75 30" class="joint_big"/>
<body name="pelvis" pos="0 0 -.165">
<joint name="abdomen_x" pos="0 0 .1" axis="1 0 0" range="-35 35" class="joint_big"/>
<geom name="butt" fromto="-.02 -.07 0 -.02 .07 0" size=".09"/>
<body name="thigh_right" pos="0 -.1 -.04">
<joint name="hip_x_right" axis="1 0 0" class="hip_x"/>
<joint name="hip_z_right" axis="0 0 1" class="hip_z"/>
<joint name="hip_y_right" class="hip_y"/>
<geom name="thigh_right" fromto="0 0 0 0 .01 -.34" class="thigh"/>
<body name="shin_right" pos="0 .01 -.4">
<joint name="knee_right" class="knee"/>
<geom name="shin_right" class="shin"/>
<body name="foot_right" pos="0 0 -.39">
<joint name="ankle_y_right" class="ankle_y"/>
<joint name="ankle_x_right" class="ankle_x" axis="1 0 .5"/>
<geom name="foot1_right" class="foot1"/>
<geom name="foot2_right" class="foot2"/>
</body>
</body>
</body>
<body name="thigh_left" pos="0 .1 -.04">
<joint name="hip_x_left" axis="-1 0 0" class="hip_x"/>
<joint name="hip_z_left" axis="0 0 -1" class="hip_z"/>
<joint name="hip_y_left" class="hip_y"/>
<geom name="thigh_left" fromto="0 0 0 0 -.01 -.34" class="thigh"/>
<body name="shin_left" pos="0 -.01 -.4">
<joint name="knee_left" class="knee"/>
<geom name="shin_left" fromto="0 0 0 0 0 -.3" class="shin"/>
<body name="foot_left" pos="0 0 -.39">
<joint name="ankle_y_left" class="ankle_y"/>
<joint name="ankle_x_left" class="ankle_x" axis="-1 0 -.5"/>
<geom name="foot1_left" class="foot1"/>
<geom name="foot2_left" class="foot2"/>
</body>
</body>
</body>
</body>
</body>
<body name="upper_arm_right" pos="0 -.17 .06">
<joint name="shoulder1_right" axis="2 1 1" class="shoulder"/>
<joint name="shoulder2_right" axis="0 -1 1" class="shoulder"/>
<geom name="upper_arm_right" fromto="0 0 0 .16 -.16 -.16" class="arm_upper"/>
<body name="lower_arm_right" pos=".18 -.18 -.18">
<joint name="elbow_right" axis="0 -1 1" class="elbow"/>
<geom name="lower_arm_right" fromto=".01 .01 .01 .17 .17 .17" class="arm_lower"/>
<body name="hand_right" pos=".18 .18 .18">
<geom name="hand_right" zaxis="1 1 1" class="hand"/>
</body>
</body>
</body>
<body name="upper_arm_left" pos="0 .17 .06">
<joint name="shoulder1_left" axis="-2 1 -1" class="shoulder"/>
<joint name="shoulder2_left" axis="0 -1 -1" class="shoulder"/>
<geom name="upper_arm_left" fromto="0 0 0 .16 .16 -.16" class="arm_upper"/>
<body name="lower_arm_left" pos=".18 .18 -.18">
<joint name="elbow_left" axis="0 -1 -1" class="elbow"/>
<geom name="lower_arm_left" fromto=".01 -.01 .01 .17 -.17 .17" class="arm_lower"/>
<body name="hand_left" pos=".18 -.18 .18">
<geom name="hand_left" zaxis="1 -1 1" class="hand"/>
</body>
</body>
</body>
</body>
</worldbody>
<contact>
<exclude body1="waist_lower" body2="thigh_right"/>
<exclude body1="waist_lower" body2="thigh_left"/>
</contact>
<tendon>
<fixed name="hamstring_right" limited="true" range="-0.3 2">
<joint joint="hip_y_right" coef=".5"/>
<joint joint="knee_right" coef="-.5"/>
</fixed>
<fixed name="hamstring_left" limited="true" range="-0.3 2">
<joint joint="hip_y_left" coef=".5"/>
<joint joint="knee_left" coef="-.5"/>
</fixed>
</tendon>
<actuator>
<motor name="abdomen_z" gear="40" joint="abdomen_z"/>
<motor name="abdomen_y" gear="40" joint="abdomen_y"/>
<motor name="abdomen_x" gear="40" joint="abdomen_x"/>
<motor name="hip_x_right" gear="40" joint="hip_x_right"/>
<motor name="hip_z_right" gear="40" joint="hip_z_right"/>
<motor name="hip_y_right" gear="120" joint="hip_y_right"/>
<motor name="knee_right" gear="80" joint="knee_right"/>
<motor name="ankle_y_right" gear="20" joint="ankle_y_right"/>
<motor name="ankle_x_right" gear="20" joint="ankle_x_right"/>
<motor name="hip_x_left" gear="40" joint="hip_x_left"/>
<motor name="hip_z_left" gear="40" joint="hip_z_left"/>
<motor name="hip_y_left" gear="120" joint="hip_y_left"/>
<motor name="knee_left" gear="80" joint="knee_left"/>
<motor name="ankle_y_left" gear="20" joint="ankle_y_left"/>
<motor name="ankle_x_left" gear="20" joint="ankle_x_left"/>
<motor name="shoulder1_right" gear="20" joint="shoulder1_right"/>
<motor name="shoulder2_right" gear="20" joint="shoulder2_right"/>
<motor name="elbow_right" gear="40" joint="elbow_right"/>
<motor name="shoulder1_left" gear="20" joint="shoulder1_left"/>
<motor name="shoulder2_left" gear="20" joint="shoulder2_left"/>
<motor name="elbow_left" gear="40" joint="elbow_left"/>
</actuator>
<keyframe>
<!--
The values below are split into rows for readibility:
torso position
torso orientation
spinal
right leg
left leg
arms
-->
<key name="squat"
qpos="0 0 0.596
0.988015 0 0.154359 0
0 0.4 0
-0.25 -0.5 -2.5 -2.65 -0.8 0.56
-0.25 -0.5 -2.5 -2.65 -0.8 0.56
0 0 0 0 0 0"/>
<key name="stand_on_left_leg"
qpos="0 0 1.21948
0.971588 -0.179973 0.135318 -0.0729076
-0.0516 -0.202 0.23
-0.24 -0.007 -0.34 -1.76 -0.466 -0.0415
-0.08 -0.01 -0.37 -0.685 -0.35 -0.09
0.109 -0.067 -0.7 -0.05 0.12 0.16"/>
<key name="prone"
qpos="0.4 0 0.0757706
0.7325 0 0.680767 0
0 0.0729 0
0.0077 0.0019 -0.026 -0.351 -0.27 0
0.0077 0.0019 -0.026 -0.351 -0.27 0
0.56 -0.62 -1.752
0.56 -0.62 -1.752"/>
<key name="supine"
qpos="-0.4 0 0.08122
0.722788 0 -0.69107 0
0 -0.25 0
0.0182 0.0142 0.3 0.042 -0.44 -0.02
0.0182 0.0142 0.3 0.042 -0.44 -0.02
0.186 -0.73 -1.73
0.186 -0.73 -1.73"/>
</keyframe>
</mujoco>