From b3aa5df68a7cdce3bd076e6672eec6a9f4f857fe Mon Sep 17 00:00:00 2001 From: Alessio Quaglino Date: Mon, 24 Feb 2025 04:25:38 -0800 Subject: [PATCH] Improve composite docs and changelog. PiperOrigin-RevId: 730394496 Change-Id: Ie993214deb82b526a96510e02f6ecff103c58607 --- doc/XMLreference.rst | 65 ++++++---------------- doc/XMLschema.rst | 4 +- doc/changelog.rst | 14 ++--- doc/modeling.rst | 105 ++++++++++++++++------------------- src/user/user_composite.cc | 1 - src/user/user_composite.h | 6 -- src/xml/xml_native_reader.cc | 14 ++--- 7 files changed, 78 insertions(+), 131 deletions(-) diff --git a/doc/XMLreference.rst b/doc/XMLreference.rst index 01c79d92..3a1b6819 100644 --- a/doc/XMLreference.rst +++ b/doc/XMLreference.rst @@ -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` (for repeated +objects) and :ref:`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: diff --git a/doc/XMLschema.rst b/doc/XMLschema.rst index 32da3890..15c962e5 100644 --- a/doc/XMLschema.rst +++ b/doc/XMLschema.rst @@ -342,9 +342,7 @@ | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | | | | | :ref:`prefix` | :ref:`type` | :ref:`count` | :ref:`offset` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`flatinertia` | :ref:`vertex` | :ref:`initial` | :ref:`curve` | | -| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`size` | | | | | +| | | | :ref:`vertex` | :ref:`initial` | :ref:`curve` | :ref:`size` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_2| composite |br| |_2| |L| | | .. table:: | diff --git a/doc/changelog.rst b/doc/changelog.rst index e5984f2c..79886dc3 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -29,20 +29,17 @@ General and a ``clear_figures`` method. - Separate collision and deformation meshes for :ref:`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` and :ref:`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` - instead, for example `this model - `__. .. 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` @@ -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`. + - Removed the ``particle`` composite type. It is recommended to use the more generic :ref:`replicate` + instead, see for example `this + model`__. MJX ^^^ diff --git a/doc/modeling.rst b/doc/modeling.rst index 1bf52b60..4ef331a4 100644 --- a/doc/modeling.rst +++ b/doc/modeling.rst @@ -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 ` 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` (for repeated objects) and :ref:`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 ` 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 ` 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 `. 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 ` 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` instead, for -example `this model `__. - -**Grid**. - -The grid composite type has been removed. It is recommended to use 2D flex :ref:`deformable objects ` 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 `. 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 +`__, 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`, 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` instead, for +example `this model `__. + +**Grid**. + +The grid composite type has been removed. It is recommended to use 2D flex :ref:`deformable objects ` 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 diff --git a/src/user/user_composite.cc b/src/user/user_composite.cc index 8f733bef..a0d713ca 100644 --- a/src/user/user_composite.cc +++ b/src/user/user_composite.cc @@ -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); diff --git a/src/user/user_composite.h b/src/user/user_composite.h index e48d98dc..383dd3a2 100644 --- a/src/user/user_composite.h +++ b/src/user/user_composite.h @@ -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 diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index 298df939..da2c68d3 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -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]) {