Improve composite docs and changelog.

PiperOrigin-RevId: 730394496
Change-Id: Ie993214deb82b526a96510e02f6ecff103c58607
This commit is contained in:
Alessio Quaglino
2025-02-24 04:25:38 -08:00
committed by Copybara-Service
parent 81b1948b46
commit b3aa5df68a
7 changed files with 78 additions and 131 deletions
+17 -48
View File
@@ -2964,14 +2964,14 @@ the direction specified by the dir attribute. It does not have a full spatial fr
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is not a model element, but rather a macro which expands into multiple model elements representing a composite
object. These elements are bodies (with their own joints, geoms and sites) that become children of the parent body
containing the macro, as well as tendons and equality constraints added to the corresponding model sections. The
automatically-generated bodies are laid out in a regular grid in 1D, 2D or 3D depending on the object type and count
attributes. The macro expansion is done by the model compiler. If the resulting model is then saved, the macro will be
object. These elements are bodies (with their own joints and geoms) that become children of the parent body containing
the macro. The macro expansion is done by the model compiler. If the resulting model is then saved, the macro will be
replaced with the actual model elements. The defaults mechanism used in the rest of MJCF does not apply here, even if
the parent body has a childclass attribute defined. Instead there are internal defaults adjusted automatically for each
composite object type. Composite objects can only be defined if the model is in local coordinates. Using them in global
coordinates results in compiler error. See :ref:`CComposite` in the modeling guide for more detailed explanation.
composite object type. See :ref:`CComposite` in the modeling guide for more detailed explanation. Note that there used
to be several composite types, but they have incrementally replaced by :ref:`replicate<replicate>` (for repeated
objects) and :ref:`flexcomp<body-flexcomp>` (for soft objects). Therefore, the only supported composite type is now
cable, which produces an inextensible chain of bodies connected with ball joints.
.. _body-composite-prefix:
@@ -2982,16 +2982,8 @@ coordinates results in compiler error. See :ref:`CComposite` in the modeling gui
.. _body-composite-type:
:at:`type`: :at-val:`[particle, cable], required`
This attribute determines the type of composite object. The remaining attributes and sub-elements are then
interpreted according to the type. Default settings are also adjusted depending on the type.
The **particle** type creates a 1D, 2D or 3D grid of equally-spaced bodies. By default, each body has a single sphere
geom and 3 orthogonal sliding joints, allowing translation but not rotation. The geom condim and priority attributes
are set to 1 by default. This makes the spheres have frictionless contacts with all other geoms (unless the priority
of some frictional geom is higher). The user can replace the default sliders with multiple joints of kind="particle"
and replace the default sphere with a custom geom. Note that the particle composite type is deprecated and might be
removed in a future version. Instead of particle, it is recommended to use :ref:`replicate`.
:at:`type`: :at-val:`[cable], required`
This attribute determines the type of composite object. The only supported type is cable.
The **cable** type creates a 1D chain of bodies connected with ball joints, each having a geom with user-defined type
(cylinder, capsule or box). The geometry can either be defined with an array of 3D vertex coordinates :at:`vertex`
@@ -3013,41 +3005,30 @@ coordinates results in compiler error. See :ref:`CComposite` in the modeling gui
.. _body-composite-offset:
:at:`offset`: :at-val:`real(3), "0 0 0"`
This attribute affects particle and grid types, and is ignored for all other types. It specifies a 3D offset from the
center of the parent body to the center of the grid of elements. The offset is expressed in the local coordinate
frame of the parent body.
.. _body-composite-flatinertia:
:at:`flatinertia`: :at-val:`real, "0"`
This attribute affects the cloth type and is ignored for all other types. The default value 0 disables this
mechanism. When the value is positive, it specifies the ratio of the small-to-large axes of the modified diagonal
inertia. The idea is to set it to a small value, say 0.01, in which case the inertias of the body elements will
corresponds to flat boxes aligned with the cloth (which can then be used for lift forces). This will not change the
geom shapes, but instead will set the body inertias directly and disable the automatic computation of inertia from
geom shape for the composite body only.
It specifies a 3D offset from the center of the parent body to the center of the grid of elements. The offset is
expressed in the local coordinate frame of the parent body.
.. _body-composite-vertex:
:at:`vertex`: :at-val:`real(3*nvert), optional`
Vertex 3D positions in global coordinates (cable only).
Vertex 3D positions in global coordinates.
.. _body-composite-initial:
:at:`initial`: :at-val:`[free, ball, none], "0"`
Behavior of the first point (cable only). Free: free joint. Ball: ball joint. None: no dof.
Behavior of the first point. Free: free joint. Ball: ball joint. None: no dof.
.. _body-composite-curve:
:at:`curve`: :at-val:`string(3), optional`
Functions specifying the vertex positions (cable only). Available functions are `s`, `cos(s)`, and `sin(s)`, where
`s` is the arc length parameter.
Functions specifying the vertex positions. Available functions are `s`, `cos(s)`, and `sin(s)`, where `s` is the arc
length parameter.
.. _body-composite-size:
:at:`size`: :at-val:`int(3), optional`
Scaling of the curve functions (cable only). `size[0]` is the scaling of `s`, `size[1]` is the radius of `\cos(s)`
and `\sin(s)`, and `size[2]` is the speed of the argument (i.e. `\cos(2*\pi*size[2]*s)`).
Scaling of the curve functions. `size[0]` is the scaling of `s`, `size[1]` is the radius of `\cos(s)` and `\sin(s)`,
and `size[2]` is the speed of the argument (i.e. `\cos(2*\pi*size[2]*s)`).
.. _composite-joint:
@@ -3061,7 +3042,7 @@ joints should be created, as well as to adjust the attributes of both automatic
.. _composite-joint-kind:
:at:`kind`: :at-val:`[main, twist, stretch, particle], required`
:at:`kind`: :at-val:`[main], required`
The joint kind here is orthogonal to the joint type in the rest of MJCF. The joint kind refers to the function of the
joint within the mechanism comprising the composite body, while the joint type (hinge or slide) is implied by the
joint kind and composite body type.
@@ -3071,18 +3052,6 @@ joints should be created, as well as to adjust the attributes of both automatic
sliders for box, cylinder and rope; universal joints for cloth, rope and loop. Even though the main joints are
included automatically, this sub-element is still useful for adjusting their attributes.
The **twist** kind corresponds to hinge joints enabling rope, loop and cloth objects to twist. These are optional
joints and are only created if this sub-element is present. This sub-element is also used to adjust the attributes of
the optional twist joints. For other composite object types this sub-element has no effect.
The **stretch** kind corresponds to slide joints enabling rope, loop and cloth objects to stretch. These are optional
joints and are only created if this sub-element is present. This sub-element is also used to adjust the attributes of
the optional stretch joints. For other composite object types this sub-element has no effect.
The **particle** kind can only be used with the particle composite type. As opposed to all previous kinds, this kind
*replaces* the default 3 sliders with user-defined joints. User-defined joints can be repeated, for example
to create planar particles with two sliders and a hinge.
.. _composite-joint-solreffix:
.. _composite-joint-solimpfix:
+1 -3
View File
@@ -342,9 +342,7 @@
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`prefix<body-composite-prefix>` | :ref:`type<body-composite-type>` | :ref:`count<body-composite-count>` | :ref:`offset<body-composite-offset>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`flatinertia<body-composite-flatinertia>` | :ref:`vertex<body-composite-vertex>` | :ref:`initial<body-composite-initial>` | :ref:`curve<body-composite-curve>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`size<body-composite-size>` | | | | |
| | | | :ref:`vertex<body-composite-vertex>` | :ref:`initial<body-composite-initial>` | :ref:`curve<body-composite-curve>` | :ref:`size<body-composite-size>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_2| composite |br| |_2| |L| | | .. table:: |
+7 -7
View File
@@ -29,20 +29,17 @@ General
and a ``clear_figures`` method.
- Separate collision and deformation meshes for :ref:`flex<deformable-flex>`. This enables a fixed cost for the soft
body computations, while preserving the fidelity of high-resolution collisions.
- Added :ref:`mjs_setDeepCopy` API function. When the deep copy flag is 0, attaching a model will not copy it to the
parent, so the original references to the child can be used to modify the parent after attachment. The default
behavior is to perform such a shallow copy. The old behavior of creating a deep copy of the child model while
attaching can be restored by setting the deep copy flag to 1.
- Added :ref:`potential<sensor-e_potential>` and :ref:`kinetic<sensor-e_kinetic>` energy sensors.
- Improved shadow rendering in the native renderer.
- Moved ``introspect`` to ``python/introspect``.
- Removed the ``particle`` composite type. It is recommended to use the more generic :ref:`replicate<replicate>`
instead, for example `this model
<https://github.com/google-deepmind/mujoco/blob/main/model/replicate/particle.xml>`__.
.. admonition:: Breaking API changes
:class: attention
- Added :ref:`mjs_setDeepCopy` API function. When the deep copy flag is 0, attaching a model will not copy it to the
parent, so the original references to the child can be used to modify the parent after attachment. The default
behavior is to perform such a shallow copy. The old behavior of creating a deep copy of the child model while
attaching can be restored by setting the deep copy flag to 1.
- Changes to inertia inference from meshes:
Previously, in order to specify that the mass lies on the surface, :ref:`geom/shellinertia<body-geom-shellinertia>`
@@ -52,6 +49,9 @@ General
Previously, if the volumetric inertia computation failed (for example due to a very flat mesh), the compiler
would silently fall back to surface inertia computation. Now, the compiler will throw an informative error.
- Removed the composite type ``grid``. Users should instead use :ref:`flexcomp<body-flexcomp>`.
- Removed the ``particle`` composite type. It is recommended to use the more generic :ref:`replicate<replicate>`
instead, see for example `this
model<https://github.com/google-deepmind/mujoco/blob/main/model/replicate/particle.xml>`__.
MJX
^^^
+48 -57
View File
@@ -1121,59 +1121,40 @@ Intrinsics
Composite objects
~~~~~~~~~~~~~~~~~
Composite objects are not new model elements. Instead, they are (large) collections of existing elements designed to
simulate particle systems, ropes, cloth, and soft bodies. These collections are generated by the model compiler
automatically. The user configures the automatic generator on a high level, using the new XML element
:ref:`composite <body-composite>` and its attributes and sub-elements, as described in the XML reference
chapter. If the compiled model is then saved, :el:`composite` is no longer present and is replaced with the collection
of regular model elements that were automatically generated. So think of it as a macro that gets expanded by the model
compiler.
Composite objects are not new model elements. Instead, they are collections of existing element originally designed to
simulate particle systems, ropes, cloth, and soft bodies. Over time, most of these types have been replaced by
:ref:`replicate<replicate>` (for repeated objects) and :ref:`flexcomp<body-flexcomp>` (for soft objects). Therefore, the
only supported composite type is now ``cable``, which produces an inextensible chain of bodies connected with ball
joints.
Composite objects are made up of regular MuJoCo bodies, which we call "element bodies" in this context. The element
bodies are created as children of the body within which :el:`composite` appears; thus a composite object appears in the
same place in the XML where a regular child body may have been defined. Each automatically-generated element body has a
single geom attached to it, usually a sphere but could also be a capsule or an ellipsoid. Thus the composite object is
essentially a particle system, however the particles can be constrained to move together in ways that simulate various
flexible objects. The initial positions of the element bodies form a regular grid in 1D, 2D or 3D. They could all be
children of the parent body (which can be the world or another regular body; composite objects cannot be nested) and
have joints allowing motion relative to the parent, or they could form a kinematic tree with joints between the element
bodies. They can also be connected with tendons with soft equality constraints on the tendon length, creating the
necessary coupling. Joint equality constraints are also used in some cases. The :at:`solref` and :at:`solimp` attributes
of these equality constraints can be adjusted by the user, thereby adjusting the softness and flexibility of the
composite objects.
Composite objects are made up of regular MuJoCo bodies, which we call "element bodies" in this context. The collection
of element bodies is generated by the model compiler automatically. The user configures the automatic generator on a
high level, using the new XML element :ref:`composite <body-composite>` and its attributes and sub-elements, as
described in the XML reference chapter. If the compiled model is then saved, :el:`composite` is no longer present and is
replaced with the collection of regular model elements that were automatically generated. So think of it as a macro that
gets expanded by the model compiler. The element bodies are created as children of the body within which :el:`composite`
appears; thus a composite object appears in the same place in the XML where a regular child body may have been defined.
Each automatically-generated element body has a single geom attached to it. We have designed the composite object
generator to have intuitive high-level controls as much as possible, but at the same time it exposes a large number of
options that interact with each other and can profoundly affect the resulting physics. So at some point users should
read the :ref:`reference documentation <body-composite>` carefully.
In addition to setting up the physics, the composite object generator creates suitable rendering. 2D and 3D objects
can be rendered as :ref:`skins <asset-skin>`. The skin is generated
automatically, and can be textured as well as subdivided using bi-cubic interpolation. The actual physics and in
particular the collision detection are based on the element bodies and their geoms, while the skin is purely a
visualization object. Yet in most situations we prefer to look at the skin representation. To facilitate this, the
generator places all geoms, sites and tendons in group 3 whose visualization is disabled by default. So when you load
a 2D grid for example, you will see a continuous flexible surface and not a collection of spheres connected with
tendons. However when fine-tuning the model and trying to understand the physics behind it, it is useful to be able to
render the spheres and tendons. To switch the rendering style, disable the rendering of skins and enable group 3 for
geoms and tendons.
We have designed the composite object generator to have intuitive high-level controls as much as possible, but at the
same time it exposes a large number of options that interact with each other and can profoundly affect the resulting
physics. So at some point users should read the :ref:`reference documentation <body-composite>` carefully.
As a quick start though, MuJoCo comes with an example of each composite object type. Below we go over these
examples and explain the less obvious aspects. In all examples we have a static scene which is included in the model,
followed by a single composite object. The static scene has a mocap body (large capsule) that can be moved around with
the mouse to probe the behavior of the system. The XML snippets below are just the definition of the composite object;
see the XML model files in the distribution for the complete examples.
**Particle**.
The particle type is deprecated. It is recommended to use the more generic :ref:`replicate<replicate>` instead, for
example `this model <https://github.com/google-deepmind/mujoco/blob/main/model/replicate/particle.xml>`__.
**Grid**.
The grid composite type has been removed. It is recommended to use 2D flex :ref:`deformable objects <CDeformable>` for
simulating thin elastic structures.
In addition to setting up the physics, the composite object generator creates suitable rendering. Objects can be
rendered as :ref:`skins <asset-skin>`. The skin is generated automatically, and can be textured as well as subdivided
using bi-cubic interpolation. The actual physics and in particular the collision detection are based on the element
bodies and their geoms, while the skin is purely a visualization object. Yet in some situations we prefer to look at the
skin representation, as in `this model
<https://github.com/google-deepmind/mujoco/blob/main/model/plugin/elasticity/belt.xml>`__, whose skin is a continuous
flexible surface and not a collection of discontinuous thin boxes. However when fine-tuning the model and trying to
understand the physics behind it, it is useful to be able to render the geoms. To switch the rendering style, disable
the rendering of skins and enable group 3 for geoms and tendons.
**Cable**.
As a quick start, MuJoCo comes with an example of composite cables. In all examples we have a static scene which is
included in the model, followed by a single composite object. The XML snippets below are just the definition of the
composite object; see the XML model files in the distribution for the complete examples.
|coil|
.. code-block:: xml
@@ -1207,6 +1188,16 @@ stiffnesses can be set independently. Moreover, it is possible to specify if the
curve, such as in the case of coil springs. The cable requires using a first-party :ref:`engine plugin<exPlugin>`, which
may be integrated directly into the engine in the future.
**Particle**.
The particle type is deprecated. It is recommended to use the more generic :ref:`replicate<replicate>` instead, for
example `this model <https://github.com/google-deepmind/mujoco/blob/main/model/replicate/particle.xml>`__.
**Grid**.
The grid composite type has been removed. It is recommended to use 2D flex :ref:`deformable objects <CDeformable>` for
simulating thin elastic structures.
**Rope and loop**.
The rope and loop are deprecated. It is recommended to use the cable for simulating inextensible elastic rods that are
@@ -1431,15 +1422,15 @@ mocap bodies around:
|particle|
The key thing to understand about mocap bodies is that the simulator treats them as being fixed. We are causing them
to move from one simulation time step to the next by updating their position and orientation directly, but as far as
the physics model is concerned their position and orientation are constant. So what happens if we make contact with a
regular dynamic body, as in the composite object examples provided with the MuJoCo distribution (recall that in
those example we have a capsule probe which is a mocap body that we move with the mouse). A contact between two
regular bodies will experience penetration as well as relative velocity, while contact with a mocap body is missing
the relative velocity component because the simulator does not know that the mocap body itself is moving. So the
resulting contact force is smaller and it takes longer for the contact to push the dynamic object away. Also, in more
complex simulations the fact that we are doing something inconsistent with the physics can cause instabilities.
The key thing to understand about mocap bodies is that the simulator treats them as being fixed. We are causing them to
move from one simulation time step to the next by updating their position and orientation directly, but as far as the
physics model is concerned their position and orientation are constant. So what happens if we make contact with a
regular dynamic body, as in the particle examples provided with the MuJoCo distribution (recall that in those example we
have a capsule probe which is a mocap body that we move with the mouse). A contact between two regular bodies will
experience penetration as well as relative velocity, while contact with a mocap body is missing the relative velocity
component because the simulator does not know that the mocap body itself is moving. So the resulting contact force is
smaller and it takes longer for the contact to push the dynamic object away. Also, in more complex simulations the fact
that we are doing something inconsistent with the physics can cause instabilities.
There is however a better-behaved alternative. In addition to the mocap body, we include a second regular body and
connect it to the mocap body with a weld equality constraint. In the plots below, the pink box is the mocap body and
-1
View File
@@ -58,7 +58,6 @@ mjCComposite::mjCComposite(void) {
type = mjCOMPTYPE_PARTICLE;
count[0] = count[1] = count[2] = 1;
mjuu_setvec(offset, 0, 0, 0);
flatinertia = 0;
// plugin variables
mjs_defaultPlugin(&plugin);
-6
View File
@@ -38,11 +38,6 @@ typedef enum _mjtCompType {
typedef enum _mjtCompKind {
mjCOMPKIND_JOINT = 0,
mjCOMPKIND_TWIST,
mjCOMPKIND_STRETCH,
mjCOMPKIND_TENDON,
mjCOMPKIND_SHEAR,
mjCOMPKIND_PARTICLE,
mjNCOMPKINDS
} mjtCompKind;
@@ -79,7 +74,6 @@ class mjCComposite {
mjtCompType type; // composite type
int count[3]; // geom count in each dimension
double offset[3]; // position offset for particle and grid
double flatinertia; // flatten ineria of cloth elements; 0: disable
// currently used only for cable
std::string initial; // root boundary type
+5 -9
View File
@@ -287,8 +287,8 @@ const char* MJCF[nMJCF][mjXATTRNUM] = {
{"<"},
{"config", "*", "2", "key", "value"},
{">"},
{"composite", "*", "9", "prefix", "type", "count", "offset",
"flatinertia", "vertex", "initial", "curve", "size"},
{"composite", "*", "8", "prefix", "type", "count", "offset",
"vertex", "initial", "curve", "size"},
{"<"},
{"joint", "*", "17", "kind", "group", "stiffness", "damping", "armature",
"solreffix", "solimpfix", "type", "axis",
@@ -742,11 +742,8 @@ const mjMap comp_map[mjNCOMPTYPES] = {
// composite joint kind
const mjMap jkind_map[4] = {
{"main", mjCOMPKIND_JOINT},
{"twist", mjCOMPKIND_TWIST},
{"stretch", mjCOMPKIND_STRETCH},
{"particle", mjCOMPKIND_PARTICLE}
const mjMap jkind_map[1] = {
{"main", mjCOMPKIND_JOINT}
};
@@ -2399,7 +2396,6 @@ void mjXReader::OneComposite(XMLElement* elem, mjsBody* body, const mjsDefault*
}
ReadAttr(elem, "count", 3, comp.count, text, false, false);
ReadAttr(elem, "offset", 3, comp.offset, text);
ReadAttr(elem, "flatinertia", 1, &comp.flatinertia, text);
// plugin
XMLElement* eplugin = FirstChildElement(elem, "plugin");
@@ -2502,7 +2498,7 @@ void mjXReader::OneComposite(XMLElement* elem, mjsBody* body, const mjsDefault*
while (ejnt) {
// kind
int kind;
MapValue(ejnt, "kind", &kind, jkind_map, 4, true);
MapValue(ejnt, "kind", &kind, jkind_map, 1, true);
// create a new element if this kind already exists
if (comp.add[kind]) {