diff --git a/doc/APIreference/APIfunctions.rst b/doc/APIreference/APIfunctions.rst index dedb83c1..8809061a 100644 --- a/doc/APIreference/APIfunctions.rst +++ b/doc/APIreference/APIfunctions.rst @@ -43,6 +43,7 @@ API function can be classified as: Macros ^^^^^^ + .. _mjMARKSTACK: mjMARKSTACK @@ -62,6 +63,7 @@ This macro is helpful when using the MuJoCo stack in custom computations. It wor // ... use temp as needed mjFREESTACK + .. _mjFREESTACK: mjFREESTACK @@ -73,6 +75,7 @@ mjFREESTACK Reset the MuJoCo stack pointer to the variable \_mark, normally saved by mjMARKSTACK. + .. _mjDISABLED: mjDISABLED @@ -85,6 +88,7 @@ mjDISABLED Check if a given standard feature has been disabled via the physics options, assuming mjModel\* m is defined. x is of type :ref:`mjtDisableBit`. + .. _mjENABLED: mjENABLED @@ -97,6 +101,7 @@ mjENABLED Check if a given optional feature has been enabled via the physics options, assuming mjModel\* m is defined. x is of type :ref:`mjtEnableBit`. + .. _mjMAX: mjMAX @@ -108,6 +113,7 @@ mjMAX Return maximum value. To avoid repeated evaluation with mjtNum types, use the function :ref:`mju_max`. + .. _mjMIN: mjMIN @@ -118,3 +124,23 @@ mjMIN #define mjMIN(a,b) (((a) < (b)) ? (a) : (b)) Return minimum value. To avoid repeated evaluation with mjtNum types, use the function :ref:`mju_min`. + + +.. _mjPLUGIN_LIB_INIT: + +mjPLUGIN_LIB_INIT +~~~~~~~~~~~~~~~~~ + +.. code-block:: C + + #define mjPLUGIN_LIB_INIT \ + static void _mjplugin_dllmain(void); \ + mjEXTERNC int __stdcall mjDLLMAIN(void* hinst, unsigned long reason, void* reserved) { \ + if (reason == 1) { \ + _mjplugin_dllmain(); \ + } \ + return 1; \ + } \ + static void _mjplugin_dllmain(void) + +Register a plugin as a dynamic library. See :ref:`plugin registration` for more details. diff --git a/doc/APIreference/APItypes.rst b/doc/APIreference/APItypes.rst index 42404aa5..d275b011 100644 --- a/doc/APIreference/APItypes.rst +++ b/doc/APIreference/APItypes.rst @@ -26,6 +26,7 @@ MuJoCo defines a large number of types: - Structs for :ref:`abstract visualization`. - Structs used by the :ref:`openGL renderer`. - Structs used by the :ref:`UI framework`. + - Structs used by :ref:`engine plugins`. - Several :ref:`tyFunction` for user-defined callbacks. @@ -555,6 +556,25 @@ Item types used in the UI framework. .. mujoco-include:: mjtItem +.. _tyPluginEnums: + +Plugins +^^^^^^^ + +The enums below are defined in `mjplugin.h `_. +See :ref:`exPlugin` for details. + + +.. _mjtPluginCapabilityBit: + +mjtPluginCapabilityBit +~~~~~~~~~~~~~~~~~~~~~~ + +Capabilities declared by an engine plugin. + +.. mujoco-include:: mjtPluginCapabilityBit + + .. _tyStructure: @@ -838,7 +858,8 @@ This structure contains the custom OpenGL rendering context, with the ids of all User Interface ^^^^^^^^^^^^^^ -The names of these struct types are prefixed with ``mjui``. +The names of these struct types are prefixed with ``mjui``, except for the main :ref:`mjUI` struct itself. + .. _mjuiState: @@ -890,6 +911,16 @@ This structure defines one section of the UI. .. mujoco-include:: mjuiSection +.. _mjuiDef: + +mjuiDef +~~~~~~~ + +This structure defines one entry in the definition table used for simplified UI construction. + +.. mujoco-include:: mjuiDef + + .. _mjUI: mjUI @@ -900,14 +931,23 @@ This structure defines the entire UI. .. mujoco-include:: mjUI -.. _mjuiDef: +.. _tyPluginStructure: -mjuiDef -~~~~~~~ +Plugins +^^^^^^^ -This structure defines one entry in the definition table used for simplified UI construction. +The names of these struct types are prefixed with ``mjp``. See :ref:`exPlugin` for more details. -.. mujoco-include:: mjuiDef + +.. _mjpPlugin: + +mjpPlugin +~~~~~~~~~ + +This structure contains the definition of a single engine plugin. It mostly contains a set of callbacks, which are +triggered by the compiler and the engine during various phases of the computation pipeline. + +.. mujoco-include:: mjpPlugin diff --git a/doc/XMLreference.rst b/doc/XMLreference.rst index e9507035..39dd42c4 100644 --- a/doc/XMLreference.rst +++ b/doc/XMLreference.rst @@ -2889,6 +2889,24 @@ defined. Its body name is automatically defined as "world". See :ref:`CUser`. +.. _body-plugin: + +:el-prefix:`body/` |-| **plugin** (?) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Associate this body with an :ref:`engine plugin`. Either :at:`plugin` or :at:`instance` are required. + +.. _body-plugin-plugin: + +:at:`plugin`: :at-val:`string, optional` + Plugin identifier, used for implicit plugin instantiation. + +.. _body-plugin-instance: + +:at:`instance`: :at-val:`string, optional` + Instance name, used for explicit plugin instantiation. + + .. _body-inertial: :el-prefix:`body/` |-| **inertial** (?) @@ -4214,6 +4232,23 @@ handle where the composite object is attached. For other composite types this su attribute can have only one number, in which case the second number is automatically set to 0. +.. _composite-plugin: + +:el-prefix:`composite/` |-| **plugin** (?) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Associate this composite with an :ref:`engine plugin`. Either :at:`plugin` or :at:`instance` are required. + +.. _composite-plugin-plugin: + +:at:`plugin`: :at-val:`string, optional` + Plugin identifier, used for implicit plugin instantiation. + +.. _composite-plugin-instance: + +:at:`instance`: :at-val:`string, optional` + Instance name, used for explicit plugin instantiation. + .. _contact: **contact** (*) @@ -5682,6 +5717,65 @@ This element has a subset of the common attributes and two custom attributes. to the target body. +.. _actuator-plugin: + +:el-prefix:`actuator/` |-| **plugin** (?) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Associate this actuator with an :ref:`engine plugin`. Either :at:`plugin` or :at:`instance` are required. + +.. _actuator-plugin-plugin: + +:at:`plugin`: :at-val:`string, optional` + Plugin identifier, used for implicit plugin instantiation. + +.. _actuator-plugin-instance: + +:at:`instance`: :at-val:`string, optional` + Instance name, used for explicit plugin instantiation. + +.. _actuator-plugin-name: + +.. _actuator-plugin-class: + +.. _actuator-plugin-group: + +.. _actuator-plugin-ctrllimited: + +.. _actuator-plugin-forcelimited: + +.. _actuator-plugin-ctrlrange: + +.. _actuator-plugin-forcerange: + +.. _actuator-plugin-lengthrange: + +.. _actuator-plugin-gear: + +.. _actuator-plugin-cranklength: + +.. _actuator-plugin-joint: + +.. _actuator-plugin-jointinparent: + +.. _actuator-plugin-site: + +.. _actuator-plugin-tendon: + +.. _actuator-plugin-cranksite: + +.. _actuator-plugin-slidersite: + +.. _actuator-plugin-user: + +.. |actuator/plugin attrib list| replace:: :at:`name`, :at:`class`, :at:`group`, :at:`ctrllimited`, :at:`forcelimited` + :at:`ctrlrange`, :at:`forcerange`, :at:`lengthrange`, :at:`gear`, :at:`cranklength`, :at:`joint`, :at:`jointinparent` + :at:`site`, :at:`tendon`, :at:`cranksite`, :at:`slidersite`, :at:`user` + +|actuator/plugin attrib list| + Same as in actuator/ :ref:`general `. + + .. _sensor: **sensor** (*) @@ -6787,6 +6881,44 @@ bodies whose center of mass is of interest. Number of scalar outputs of this sensor. +.. _sensor-plugin: + +:el-prefix:`sensor/` |-| **plugin** (?) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Ascociate this sensor with an :ref:`engine plugin`. Either :at:`plugin` or :at:`instance` are required. + +.. _sensor-plugin-plugin: + +:at:`plugin`: :at-val:`string, optional` + Plugin identifier, used for implicit plugin instantiation. + +.. _sensor-plugin-instance: + +:at:`instance`: :at-val:`string, optional` + Instance name, used for explicit plugin instantiation. + +.. _sensor-plugin-name: + +.. _sensor-plugin-cutoff: + +.. _sensor-plugin-objtype: + +.. _sensor-plugin-objname: + +.. _sensor-plugin-reftype: + +.. _sensor-plugin-refname: + +.. _sensor-plugin-user: + +.. |sensor/plugin attrib list| replace:: :at:`name`, :at:`cutoff`, :at:`objtype`, :at:`objname`, :at:`reftype` + :at:`refname`, :at:`user` + +|sensor/plugin attrib list| + See :ref:`CSensor`. + + .. _keyframe: **keyframe** (*) @@ -6849,3 +6981,64 @@ This element sets the data for one of the keyframes. They are set in the order i :at:`mquat`: :at-val:`real(4*mjModel.nmocap), default = mjModel.body_quat` Vector of mocap body quaternions, copied into mjData.mocap_quat when the simulation state is set to this keyframe. + +.. _extension: + +**extension** (*) +~~~~~~~~~~~~~~~~~ + +This is a grouping element for MuJoCo extensions. Extensions allow the user to extend MuJoCo's capabilities with custom +code and are described in detail in the Programming chapter's :ref:`exExtension` page. Currently, the only available +extension type are :ref:`exPlugin`. + +.. _extension-plugin: + +:el-prefix:`extension/` |-| **plugin** (*) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This element specifies that an engine plugin is required in order to simulate this model. +See :ref:`exPlugin` for more details. + +.. _extension-plugin-plugin: + +:at:`plugin`: :at-val:`string, required` + Identifier of the plugin. + +.. _plugin-instance: + +:el-prefix:`plugin/` |-| **instance** (*) +''''''''''''''''''''''''''''''''''''''''' + +Declares a plugin instance. Explicit instances declaration is required when multiple elements are backed by the same +plugin, or when global plugin configuration is desired. See plugin :ref:`declaration` and +:ref:`configuration` for more details. + +.. _plugin-instance-name: + +:at:`name`: :at-val:`string, required` + Name of the plugin instance. + +.. _plugin-config: + +.. _instance-config: + +:el-prefix:`instance/` |-| **config** (*) +""""""""""""""""""""""""""""""""""""""""" + +Configuration of a plugin instance. When implicitly declaring a plugin under a model element, configuration is +performed with identical semantics using :el:`element/plugin/config`. The elements which currently support plugins are +:el:`body`, :el:`composite`, :el:`actuator` and :el:`sensor`. + +.. _plugin-config-key: + +.. _instance-config-key: + +:at:`key`: :at-val:`string, optional` + Key used for plugin configuration. + +.. _plugin-config-value: + +.. _instance-config-value: + +:at:`value`: :at-val:`string, optional` + Value associated with key. diff --git a/doc/XMLschema.rst b/doc/XMLschema.rst index a5edf0f0..7ede7c9f 100644 --- a/doc/XMLschema.rst +++ b/doc/XMLschema.rst @@ -446,27 +446,27 @@ | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | mujoco |br| |L| | | *no attributes* | -| extension | | | +| :ref:`extension` | | | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_| extension |br| |_| |L| | | .. table:: | -| :el:`plugin` | \* | :class: mjcf-attributes | -| | | | +| :ref:`plugin | \* | :class: mjcf-attributes | +| ` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`plugin` | | | | +| | | | :ref:`plugin` | | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_2| plugin |br| |_2| |L| | | .. table:: | -| :el:`instance` | \* | :class: mjcf-attributes | -| | | | +| :ref:`instance | \* | :class: mjcf-attributes | +| ` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`name` | | | | +| | | | :ref:`name` | | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_3| instance |br| |_3| |L| | | .. table:: | -| :el:`config` | \* | :class: mjcf-attributes | -| | | | +| :ref:`config | \* | :class: mjcf-attributes | +| ` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`key` | :at:`value` | | | +| | | | :ref:`key` | :ref:`value` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | mujoco |br| |L| | | *no attributes* | @@ -591,17 +591,17 @@ | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_| body |br| |_| |L| | | .. table:: | -| :el:`plugin` | \* | :class: mjcf-attributes | -| | | | +| :ref:`plugin | \* | :class: mjcf-attributes | +| ` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`plugin` | :at:`instance` | | | +| | | | :ref:`plugin` | :ref:`instance` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_2| plugin |br| |_2| |L| | | .. table:: | -| :el:`config` | \* | :class: mjcf-attributes | -| | | | +| :ref:`config | \* | :class: mjcf-attributes | +| ` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`key` | :at:`value` | | | +| | | | :ref:`key` | :ref:`value` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_| body |br| |_| |L| | | .. table:: | @@ -727,17 +727,17 @@ | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_2| composite |br| |_2| |L| | | .. table:: | -| :el:`plugin` | \* | :class: mjcf-attributes | -| | | | +| :ref:`plugin | \* | :class: mjcf-attributes | +| ` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`plugin` | :at:`instance` | | | +| | | | :ref:`plugin` | :ref:`instance` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_3| plugin |br| |_3| |L| | | .. table:: | -| :el:`config` | \* | :class: mjcf-attributes | -| | | | +| :ref:`config | \* | :class: mjcf-attributes | +| ` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`key` | :at:`value` | | | +| | | | :ref:`key` | :ref:`value` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_2| composite |br| |_2| |L| | | .. table:: | @@ -1126,29 +1126,29 @@ | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_| actuator |br| |_| |L| | | .. table:: | -| :el:`plugin` | \* | :class: mjcf-attributes | -| | | | +| :ref:`plugin | \* | :class: mjcf-attributes | +| ` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`name` | :at:`class` | :at:`plugin` | | +| | | | :ref:`name` | :ref:`class` | :ref:`plugin` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`instance` | :at:`group` | :at:`ctrllimited` | | +| | | | :ref:`instance` | :ref:`group` | :ref:`ctrllimited` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`forcelimited` | :at:`ctrlrange` | :at:`forcerange` | | +| | | | :ref:`forcelimited` | :ref:`ctrlrange` | :ref:`forcerange` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`lengthrange` | :at:`gear` | :at:`cranklength` | | +| | | | :ref:`lengthrange` | :ref:`gear` | :ref:`cranklength` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`joint` | :at:`jointinparent` | :at:`site` | | +| | | | :ref:`joint` | :ref:`jointinparent` | :ref:`site` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`tendon` | :at:`cranksite` | :at:`slidersite` | | +| | | | :ref:`tendon` | :ref:`cranksite` | :ref:`slidersite` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`user` | | | | +| | | | :ref:`user` | | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_2| plugin |br| |_2| |L| | | .. table:: | -| :el:`config` | \* | :class: mjcf-attributes | -| | | | +| :ref:`config | \* | :class: mjcf-attributes | +| ` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`key` | :at:`value` | | | +| | | | :ref:`key` | :ref:`value` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | mujoco |br| |L| | | *no attributes* | @@ -1504,21 +1504,21 @@ | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_| sensor |br| |_| |L| | | .. table:: | -| :el:`plugin` | \* | :class: mjcf-attributes | -| | | | +| :ref:`plugin | \* | :class: mjcf-attributes | +| ` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`name` | :at:`plugin` | :at:`instance` | | +| | | | :ref:`name` | :ref:`plugin` | :ref:`instance` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`cutoff` | :at:`objtype` | :at:`objname` | | +| | | | :ref:`cutoff` | :ref:`objtype` | :ref:`objname` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`reftype` | :at:`refname` | :at:`user` | | +| | | | :ref:`reftype` | :ref:`refname` | :ref:`user` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_2| plugin |br| |_2| |L| | | .. table:: | -| :el:`config` | \* | :class: mjcf-attributes | -| | | | +| :ref:`config | \* | :class: mjcf-attributes | +| ` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :at:`key` | :at:`value` | | | +| | | | :ref:`key` | :ref:`value` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | mujoco |br| |L| | | *no attributes* | diff --git a/doc/changelog.rst b/doc/changelog.rst index 87234d6e..04ce25e1 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -12,7 +12,9 @@ General :align: right :width: 240px -- Added :ref:`ellipsoidinertia` to visualize equivalent inertias with ellipsoids instead of the default boxes. +- Added :ref:`ellipsoidinertia` to visualize equivalent inertias with ellipsoids instead + of the default boxes. +- Added documentation for :ref:`engine plugins`. Bug fixes ^^^^^^^^^ diff --git a/doc/computation.rst b/doc/computation.rst index fb24d889..7e39b186 100644 --- a/doc/computation.rst +++ b/doc/computation.rst @@ -630,6 +630,15 @@ Warmstart accelerations `__ when time-stepping, quickly leading to divergent trajectories for different warmstarts. +.. _gePlugin: + +Plugin state +^^^^^^^^^^^^ + + ``plugin_state`` + ``mjData.plugin_state`` are states declared by :ref:`engine plugins`. Please see the :ref:`exPluginState` + section for more details. + .. _geIntegrationState: Integration state diff --git a/doc/programming/extension.rst b/doc/programming/extension.rst new file mode 100644 index 00000000..8a264508 --- /dev/null +++ b/doc/programming/extension.rst @@ -0,0 +1,248 @@ +.. _exExtension: + +Extensions +---------- + +This section describes MuJoCo's mechanisms for user-authored extensions. At present, extensibility is provided only +via **engine plugins**. + +.. _exPlugin: + +Engine plugins +~~~~~~~~~~~~~~ + +Engine plugins, introduced in MuJoCo 2.3.0, allow user-defined logic to be inserted into various parts of MuJoCo's +computational pipeline. For example, custom sensor and actuator types can be implemented as plugins. Plugin features are +referenced in the XML content of an MJCF model, allowing MJCF to remain an abstract physical description of +a system even if the simulation requirements extend beyond MuJoCo's built-in capabilities. + +The plugin mechanism was designed to overcome the disadvantages of MuJoCo's :ref:`physics callbacks`. These +global callbacks (:ref:`usage example`) are still available and useful for fast prototyping or when +the user wishes to implement functionality in Python, but are generally deprecated as a stable mechanism for extended +functionality. The central features of the plugin mechanism are: + +- **Thread safety:** Plugin instances (see below) are thread-local, avoiding collisions. +- **Statefulness:** Plugins can be stateful, and their state will be (de)serialized correctly. +- **Interoperability:** Different plugins can coexist without interference. + +Both users and developers of plugins should familiarize themselves with two key concepts: + +Plugin + A **plugin** is a collection of functions and static attributes that implement its capabilities, bundled into an + :ref:`mjpPlugin` struct. Plugin functions are **stateless**: they depend only on the + arguments passed to them. When a plugin requires an internal state, it declares this state + and allows MuJoCo to manage it and pass it in. This enables (de)serialization of the full simulation state. + A plugin can therefore be regarded as the "pure logic" part of the functionality and is often bundled as a C library. + A plugin is neither a model element nor is it associated with specific model elements. + +Plugin instance + A plugin **instance** represents the self-contained runtime state that is operated on by the + plugin: when the plugin logic is executed, the instance state is passed in by the engine. + A plugin instance is itself a model element of type :ref:`mjOBJ_PLUGIN`. + There are ``mjModel.nplugin`` instances with id's in ``[0 nplugin-1]``. Like other elements, instances + can have names, with :ref:`mj_name2id` and :ref:`mj_id2name` mapping between id's and names. Unlike the + plugin code which is loaded once into a global table, multiple instances of the same plugin can be defined and have a + one-to-many relationship with other model elements. + + **one-to-one:** + In this simplest case, each instance is referenced once in the model. For example, + two sensors may declare that their values are computed by two plugin instances of the same plugin. + In this case, every time the sensor output is computed, the plugin logic will be executed separately. + + **one-to-many:** + Alternatively, the behavior of multiple elements can be backed by a single plugin instance. There are + two main scenarios where this is useful: + + * The values of different element types are linked to the same physical entity and computation. For example + consider a motor with an internal thermometer. This would manifest as an actuator and sensor, both associated with + the same plugin instance which computes both torque outputs and temperature readings. + * It is advantageous to batch the computation of multiple related elements together, for example where the computed + value is the output of a neural network. The canonical example here is a robot that is equipped with ``N`` motors, + where motor dynamics are modeled as a neural network. In this case, it can be substantially faster to produce the + torque output of all N actuators in a single forward pass than for each motor separately. + +Below, we begin by describing plugins from a user perspective: + +* Types of plugin capabilities. +* How plugins are declared and configured in an MJCF model. +* How plugin states are incorporated into :ref:`mjData`, and what users need to do to safely duplicate and serialize + :ref:`mjData` structs when plugin instances are present. + +Next, we describe the logistics of plugin registration that are relevant to both users and developers of plugins. This +is followed by a section that targets plugin developers. + +.. _exCapabilities: + +Plugin capabilities +^^^^^^^^^^^^^^^^^^^ + +A plugin is described by the contents of its associated :ref:`mjpPlugin` struct. The ``capabilityflags`` member is an +integer bitfield describing the plugin's capabilities, where bit semantics are defined in the enum +:ref:`mjtPluginCapabilityBit`. Using a bitfield allows plugins to support multiple types of computation. The currently +supported plugin capabilities are: + +* Actuator plugin +* Sensor plugin +* Passive force plugin + +Additional capabilities will be added in the future as required. + + +.. _exDeclaration: + +Declaration in MJCF +^^^^^^^^^^^^^^^^^^^ + +First, a plugin dependency must be declared through ````. When the model is parsed, if any plugin +is declared but not registered (see below), a model compilation error is raised. If only a single MJCF element is +backed by a plugin, instances can be implicitly created in-place. If multiple elements are backed by the same plugin, +instance declaration must be explicit: + +.. code:: xml + + + + + + + + + ... + + + + + + ... + + + + + +In the example above, ``sensor0`` and ``sensor1`` are each backed by a simple plugin that does not share computation +among elements, so an instance is implicitly created for each sensor by directly referencing the plugin identifier. +In contrast, ``sensor2`` and ``actuator2`` are backed by a plugin that shares computation, so they must reference a +shared instance that was explicitly declared. + + +.. _exConfiguration: + +Configuration in MJCF +^^^^^^^^^^^^^^^^^^^^^ + +Plugins can declare custom attributes that represent specialized configurable parameters. For example, a DC motor model +may expose the resistance, inductance, and capacitance as configuration attributes. In MJCF, the values of these +attributes can be specified via ```` elements, where each ```` has a key and a value. Valid keys and +values are specified by the plugin developers, but are declared to MuJoCo during plugin registration time so that the +MuJoCo model compiler can raise errors for invalid values. + +.. code:: xml + + + + + + + + + + + ... + + + + + + + + + +In the example above, ``actuator0`` refers to a pre-existing plugin instance that was created and configured via the +```` element, while ``actuator1`` is implicitly creating and configuring a new plugin instance in-place. Note +that it would be an error to add ```` child elements directly to ``actuator0`` because a new plugin instance is +not being created there. + +.. _exPluginState: + +Plugin state +^^^^^^^^^^^^ + +While plugin code should be stateless, individual plugin instances are permitted to hold time-dependent state that is +intended to evolve alongside MuJoCo physics, for example temperature variables in thermodynamically coupled actuator +models. Separately, it may also be desirable for plugin instances to memoize potentially expensive parts of their +operation. For example, sensor or actuator plugins that are backed by pretrained neural networks will want to preload +their weights at model compilation time. It is important for us to distinguish between these two types of per-instance +plugin payload. The term **plugin state** refers to the time-dependent state of the plugin instance that consists of +*floating point* values, while the term **plugin data** refers to *arbitrary data structures* consisting of memoized +payload that should be considered implementation detail for the plugin's computation. + +Crucially, plugin data must be reconstructible only from plugin configuration attributes, the plugin state, +and :ref:`MuJoCo state variables`. This means that the plugin data is not expected to be serializable, and will +not be serialized by MuJoCo when it copies or stores data. On the other hand, plugin state is considered an integral +part of the physics and must be serialized alongside MuJoCo's other state variables in order for the physics to be +faithfully restored. + +Plugins must declare the number of floating point values required for each instance via the ``nstate`` callback of its +:ref:`mjpPlugin` struct. Note that this number can depend on the exact configuration of the instance. During +:ref:`mj_makeData`, MuJoCo allocate the requisite number of slots in the ``plugin_state`` field of :ref:`mjData` for +each plugin instance. The ``plugin_stateadr`` field in :ref:`mjModel` indicates the position within the overall +``plugin_state`` array at which each plugin instance can find its state values. + +Plugin data, however, is entirely opaque from MuJoCo's point of view. During :ref:`mj_makeData`, MuJoCo calls the +``init`` callback from the relevant :ref:`mjpPlugin`. In this callback, the plugin is permitted to allocate or otherwise +create an arbitrary data structure that it requires to function and stores its pointer in the ``plugin_data`` field of +:ref:`mjData` that is being created. During :ref:`mj_deleteData`, MuJoCo calls the ``destroy`` callback from the same +:ref:`mjpPlugin`, and the plugin is responsible for deallocating its internal resources associated with the instance. + +When :ref:`mjData` is being copied via :ref:`mj_copyData`, MuJoCo will copy over the plugin state. However, the plugin +code is responsible for setting up the plugin data for the newly copied :ref:`mjData`. To facilitate this, MuJoCo calls +the ``copy`` callback from :ref:`mjpPlugin` for each plugin instance present. + +.. _exRegistration: + +Registration +^^^^^^^^^^^^ + +Plugins must be registered with MuJoCo before they can be referenced in MJCF models. + +One-off plugins that are intended to support a specific application (or throwaway plugins that are implemented to help +troubleshoot issues with a model) can be statically linked into the application. This can be as simple as preparing an +:ref:`mjpPlugin` struct in the ``main`` function, then passing it to :ref:`mjp_registerPlugin` to be registered with +MuJoCo. + +Generally, reusable plugins are expected to be packaged as dynamic libraries. A dynamic library containing one or more +MuJoCo plugins should make sure that all plugins are registered when the library is loaded. In GCC-compatible compilers, +this can be achieved by calling :ref:`mjp_registerPlugin` in a function that is declared with +``__attribute__((constructor))``, while in MSVC this can be done in a DLL entry point (canonically known as +``DllMain``). MuJoCo provides a convenience macro :ref:`mjPLUGIN_LIB_INIT` that expands to either of these +constructs depending on the compiler used. + +Users of plugins that are delivered as dynamic libraries as described above can load the library using the function +:ref:`mj_loadPluginLibrary`. This is the preferred way to load dynamic libraries containing MuJoCo plugins (rather than, +say, calling ``dlopen`` or ``LoadLibraryA`` directly) since the exact way in which MuJoCo expects dynamic libraries to +auto-register plugins may change over time, but :ref:`mj_loadPluginLibrary` is expected to also evolve to reflect the +best practices. + +For applications that need to be able to load arbitrary user-provided MJCF models, it may be desirable to automatically +scan and load all dynamic libraries found without a specific directory. Users who bring along an MJCF that requires a +plugin can then be instructed to place the requisite plugin libraries in the relevant directory. For example, this is +what is done in the :ref:`saSimulate` interactive viewer application. The :ref:`mj_loadAllPluginLibraries` function is +provided for this scan-and-load use case. + +.. _exWriting: + +Writing plugins +^^^^^^^^^^^^^^^ + +This section, targeted at developers, is not yet written. We encourage people who wish to write their own plugins +to contact the MuJoCo development team for help. A good starting point for experienced developers is the +`associated tests `_ and the first-party +plugins in the `first-party plugin directory `_. + +A future version of this section will include: + +* The content of the :ref:`mjpPlugin` struct. +* Which functions and properties need to be provided in order to define a plugin. +* How to declare custom MJCF attributes for a plugin. +* Things that developers need to keep in mind in order to ensure that plugins function correctly when :ref:`mjData` is + copied, stepped, or reset. diff --git a/doc/programming/index.rst b/doc/programming/index.rst index 590f769d..36f5241f 100644 --- a/doc/programming/index.rst +++ b/doc/programming/index.rst @@ -135,18 +135,18 @@ mujoco.h   `(source) `__ - This file defines the C structure :ref:`mjModel` which is the runtime representation of the + Defines the C structure :ref:`mjModel` which is the runtime representation of the model being simulated. It also defines a number of primitive types and other structures needed to define mjModel. mjdata.h   `(source) `__ - This file defines the C structure :ref:`mjData` which is the workspace where all computations + Defines the C structure :ref:`mjData` which is the workspace where all computations read their inputs and write their outputs. It also defines primitive types and other structures needed to define mjData. mjvisualize.h   `(source) `__ - This file defines the primitive types and structures needed by the abstract visualizer. + Defines the primitive types and structures needed by the abstract visualizer. mjrender.h   `(source) `__ - This file defines the primitive types and structures needed by the OpenGL renderer. + Defines the primitive types and structures needed by the OpenGL renderer. mjui.h   `(source) `__ - This file defines the primitive types and structures needed by the UI framework. + Defines the primitive types and structures needed by the UI framework. mjtnum.h   `(source) `__ Defines MuJoCo's ``mjtNum`` floating-point type to be either ``double`` or ``float``. See :ref:`mjtNum`. mjxmacro.h   `(source) `__ @@ -156,9 +156,8 @@ mjxmacro.h   `(source) `__ Macros used for exporting public symbols from the MuJoCo library. This header should not be used directly by client code. -glfw3.h - This file is optional and is not included by mujoco.h. It is the only header file needed for the GLFW library. See - code sample :ref:`simulate.cc `. +mjplugin.h   `(source) `__ + Defines data structures required by :ref:`engine plugins`. .. _inVersion: @@ -262,3 +261,4 @@ now lazily resolved at runtime after the switch to GLAD, the "nogl" libraries ar samples simulation visualization + extension diff --git a/include/mujoco/mjplugin.h b/include/mujoco/mjplugin.h index 127da354..4081c697 100644 --- a/include/mujoco/mjplugin.h +++ b/include/mujoco/mjplugin.h @@ -67,8 +67,7 @@ typedef struct mjpPlugin_ mjpPlugin; #if defined(__has_attribute) #if __has_attribute(constructor) - #define mjPLUGIN_DYNAMIC_LIBRARY_INIT \ - __attribute__((constructor)) static void _mjplugin_init(void) + #define mjPLUGIN_LIB_INIT __attribute__((constructor)) static void _mjplugin_init(void) #endif // __has_attribute(constructor) #elif defined(_MSC_VER) @@ -86,7 +85,7 @@ typedef struct mjpPlugin_ mjpPlugin; #endif // !defined(mjEXTERNC) // NOLINTBEGIN(runtime/int) - #define mjPLUGIN_DYNAMIC_LIBRARY_INIT \ + #define mjPLUGIN_LIB_INIT \ static void _mjplugin_dllmain(void); \ mjEXTERNC int __stdcall mjDLLMAIN(void* hinst, unsigned long reason, void* reserved) { \ if (reason == 1) { \ diff --git a/plugin/elasticity/elasticity.cc b/plugin/elasticity/elasticity.cc index 38e63edb..e349379f 100644 --- a/plugin/elasticity/elasticity.cc +++ b/plugin/elasticity/elasticity.cc @@ -18,7 +18,7 @@ namespace mujoco::plugin::elasticity { -mjPLUGIN_DYNAMIC_LIBRARY_INIT { +mjPLUGIN_LIB_INIT { Cable::RegisterPlugin(); Solid::RegisterPlugin(); }