Merge branch 'google-deepmind:main' into tendons

This commit is contained in:
Abhishek Joshi
2024-06-16 23:40:10 -05:00
committed by GitHub
134 changed files with 12574 additions and 2764 deletions
+10
View File
@@ -154,6 +154,16 @@ jobs:
- name: Build MuJoCo
working-directory: build
run: cmake --build . --config=Release ${{ matrix.cmake_build_args }}
- name: Copy in the correct VC runtime DLLs (workaround for actions/runner-images#10004)
if: ${{ runner.os == 'Windows' }}
working-directory: build
shell: powershell
run: |
Copy-Item (Join-Path `
((Get-ChildItem -Directory `
-Path "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Redist\MSVC\14.*" |
Sort -Descending | Select-Object -First 1).FullName
) 'x64\Microsoft.VC143.CRT\*.dll') "bin\Release"
- name: Test MuJoCo
working-directory: build
run: ctest -C Release --output-on-failure .
+2 -1
View File
@@ -28,7 +28,7 @@ set(MSVC_INCREMENTAL_DEFAULT ON)
project(
mujoco
VERSION 3.1.6
VERSION 3.1.7
DESCRIPTION "MuJoCo Physics Simulator"
HOMEPAGE_URL "https://mujoco.org"
)
@@ -59,6 +59,7 @@ set(MUJOCO_HEADERS
include/mujoco/mjmodel.h
include/mujoco/mjplugin.h
include/mujoco/mjrender.h
include/mujoco/mjspec.h
include/mujoco/mjthread.h
include/mujoco/mjtnum.h
include/mujoco/mjui.h
+1 -1
View File
@@ -116,7 +116,7 @@ before the `else`:
else {
mjtNum mat[9];
mju_quat2Mat(mat, quat);
mju_rotVecMat(res, vec, mat);
mju_mulMatVec3(res, mat, vec);
}
}
```
+4 -4
View File
@@ -1,6 +1,6 @@
1 VERSIONINFO
FILEVERSION 3,1,6,0
PRODUCTVERSION 3,1,6,0
FILEVERSION 3,1,7,0
PRODUCTVERSION 3,1,7,0
FILEOS 0x4
FILETYPE 0x1
{
@@ -9,9 +9,9 @@ FILETYPE 0x1
BLOCK "040904b0"
{
VALUE "ProductName", "MuJoCo"
VALUE "ProductVersion", "3.1.6"
VALUE "ProductVersion", "3.1.7"
VALUE "FileDescription", "MuJoCo"
VALUE "FileVersion", "3.1.6"
VALUE "FileVersion", "3.1.7"
VALUE "InternalName", "mujoco.dll"
VALUE "OriginalFilename", "mujoco.dll"
VALUE "CompanyName", "Google DeepMind"
+4 -4
View File
@@ -1,8 +1,8 @@
MUJOCO ICON "mujoco.ico"
1 VERSIONINFO
FILEVERSION 3,1,6,0
PRODUCTVERSION 3,1,6,0
FILEVERSION 3,1,7,0
PRODUCTVERSION 3,1,7,0
FILEOS 0x4
FILETYPE 0x1
{
@@ -11,9 +11,9 @@ FILETYPE 0x1
BLOCK "040904b0"
{
VALUE "ProductName", "MuJoCo"
VALUE "ProductVersion", "3.1.6"
VALUE "ProductVersion", "3.1.7"
VALUE "FileDescription", "MuJoCo"
VALUE "FileVersion", "3.1.6"
VALUE "FileVersion", "3.1.7"
VALUE "InternalName", "simulate.exe"
VALUE "OriginalFilename", "simulate.exe"
VALUE "CompanyName", "Google DeepMind"
+42 -99
View File
@@ -9,105 +9,48 @@ large number of functions. However the functions that most users are likely to n
API function can be classified as:
- :ref:`Parse and compile<Parseandcompile>` an :ref:`mjModel` from XML files and assets.
- :ref:`Main simulation<Mainsimulation>` entry points, including :ref:`mj_step`.
- :ref:`Support<Support>` functions requiring :ref:`mjModel` and :ref:`mjData`.
- :ref:`Components<Components>` of the simulation pipeline, called from :ref:`mj_step`, :ref:`mj_forward` and :ref:`mj_inverse`.
- :ref:`Sub components<Subcomponents>` of the simulation pipeline.
- :ref:`Ray collisions<Raycollisions>`.
- :ref:`Printing<Printing>` of various quantities.
- :ref:`Virtual file system<Virtualfilesystem>`, used to load assets from memory.
- :ref:`Initialization<Initialization>` of data structures.
- :ref:`Abstract interaction<Interaction>`: mouse control of cameras and perturbations.
- :ref:`Abstract Visualization<Visualization-api>`.
- :ref:`OpenGL rendering<OpenGLrendering>`.
- :ref:`UI framework<UIframework>`.
- :ref:`Error and memory<Errorandmemory>`.
- :ref:`Aliases for C standard math<Standardmath>` functions.
- :ref:`Vector math<Vectormath>`.
- :ref:`Quaternions<Quaternions>`.
- :ref:`Poses transformations<Poses>`.
- :ref:`Matrix decompositions and solvers<Decompositions>`.
- :ref:`Miscellaneous<Miscellaneous>` functions.
- :ref:`Derivatives<Derivatives-api>`.
- :ref:`Plugin<Plugins-api>` related functions.
- :ref:`Macros<Macros>`.
- :ref:`Thread<Thread>` related functions.
- **Main entry points**
- :ref:`Parse and compile<Parseandcompile>` an :ref:`mjModel` from XML files and assets.
- :ref:`Main simulation<Mainsimulation>` entry points, including :ref:`mj_step`.
.. TODO(b/273075045): Better category-label namespacing.
- **Support functions**
- :ref:`Support<Support>` functions requiring :ref:`mjModel` and :ref:`mjData`.
- Pipeline :ref:`components<Components>`, called from :ref:`mj_step`, :ref:`mj_forward` and :ref:`mj_inverse`.
- :ref:`Sub components<Subcomponents>` of the simulation pipeline.
- :ref:`Ray casting<Raycollisions>`.
- :ref:`Printing<Printing>` of various quantities.
- :ref:`Virtual file system<Virtualfilesystem>`, used to load assets from memory.
- :ref:`Initialization<Initialization>` of data structures.
- :ref:`Error and memory<Errorandmemory>`.
- :ref:`Miscellaneous<Miscellaneous>` functions.
- **Visualization, Rendering, UI**
- :ref:`Abstract interaction<Interaction>`: mouse control of cameras and perturbations.
- :ref:`Abstract Visualization<Visualization-api>`.
- :ref:`OpenGL rendering<OpenGLrendering>`.
- :ref:`UI framework<UIframework>`.
- **Threads, Plugins, Derivatives**
- :ref:`Derivatives<Derivatives-api>`.
- :ref:`Thread<Thread>` |-| -related functions.
- :ref:`Plugin<Plugins-api>` |-| -related functions.
- **Math**
- Aliases for C :ref:`standard math<Standardmath>` functions.
- :ref:`Vector math<Vectormath>`.
- :ref:`Quaternions<Quaternions>`.
- :ref:`Pose transformations<Poses>`.
- :ref:`Matrix decompositions and solvers<Decompositions>`.
- **Model editing**
- :ref:`Attachment<Attachment>`.
- :ref:`Tree elements<AddTreeElements>`.
- :ref:`Non-tree elements<AddNonTreeElements>`.
- :ref:`Assets<AddAssets>`.
- :ref:`Find and get utilities<FindAndGetUtilities>`.
- :ref:`Attribute setters<AttributeSetters>`.
- :ref:`Attribute getters<AttributeGetters>`.
- :ref:`Spec utilities<SpecUtilities>`.
- :ref:`Element initialization<ElementInitialization>`.
.. include:: functions.rst
.. _Macros:
Macros
^^^^^^
.. _mjDISABLED:
mjDISABLED
~~~~~~~~~~
.. code-block:: C
#define mjDISABLED(x) (m->opt.disableflags & (x))
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
~~~~~~~~~
.. code-block:: C
#define mjENABLED(x) (m->opt.enableflags & (x))
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
~~~~~
.. code-block:: C
#define mjMAX(a,b) (((a) > (b)) ? (a) : (b))
Return maximum value. To avoid repeated evaluation with mjtNum types, use the function :ref:`mju_max`.
.. _mjMIN:
mjMIN
~~~~~
.. code-block:: C
#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<exRegistration>` for more details.
+77 -1
View File
@@ -13,6 +13,7 @@ Global variable and constant definitions can be classified as:
- The :ref:`collision table<glCollision>` containing narrow-phase collision functions.
- :ref:`String constants<glString>`.
- :ref:`Numeric constants<glNumeric>`.
- :ref:`Macros<Macros>`.
- :ref:`X Macros<tyXMacro>`.
.. _glError:
@@ -522,12 +523,87 @@ shown in the table below. Their names are in the format ``mjKEY_XXX``. They corr
- Maximum number of UI rectangles.
Defined in `mjui.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjui.h>`_.
* - ``mjVERSION_HEADER``
- 316
- 317
- The version of the MuJoCo headers; changes with every release. This is an integer equal to 100x the software
version, so 210 corresponds to version 2.1. Defined in mujoco.h. The API function :ref:`mj_version` returns a
number with the same meaning but for the compiled library.
.. _Macros:
Macros
^^^^^^
.. _mjDISABLED:
mjDISABLED
~~~~~~~~~~
.. code-block:: C
#define mjDISABLED(x) (m->opt.disableflags & (x))
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
~~~~~~~~~
.. code-block:: C
#define mjENABLED(x) (m->opt.enableflags & (x))
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
~~~~~
.. code-block:: C
#define mjMAX(a,b) (((a) > (b)) ? (a) : (b))
Return maximum value. To avoid repeated evaluation with mjtNum types, use the function :ref:`mju_max`.
.. _mjMIN:
mjMIN
~~~~~
.. code-block:: C
#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<exRegistration>` for more details.
.. _tyXMacro:
X Macros
+418 -11
View File
@@ -9,9 +9,11 @@ MuJoCo defines a large number of types:
- Enums used in :ref:`mjModel<tyModelEnums>`.
- Enums used in :ref:`mjData<tyDataEnums>`.
- Abstract :ref:`visualization enums<tyVisEnums>`.
- Enums for abstract :ref:`visualization<tyVisEnums>`.
- Enums used by the :ref:`openGL renderer<tyRenderEnums>`.
- Enums used by the :ref:`mjUI<tyUIEnums>` user interface package.
- Enums used by :ref:`engine plugins<tyPluginEnums>`.
- Enums used for :ref:`procedural model manipulation<tySpecEnums>`.
Note that the API does not use these enum types directly. Instead it uses ints, and the documentation/comments state
that certain ints correspond to certain enum types. This is because we want the API to be compiler-independent, and
@@ -31,9 +33,10 @@ MuJoCo defines a large number of types:
- Structs for :ref:`abstract visualization<tyVisStructure>`.
- Structs used by the :ref:`openGL renderer<tyRenderStructure>`.
- Structs used by the :ref:`UI framework<tyUIStructure>`.
- Structs used for :ref:`procedural model manipulation<tySpecStructure>`.
- Structs used by :ref:`engine plugins<tyPluginStructure>`.
- Several :ref:`tyFunction` for user-defined callbacks.
- Several :ref:`function types<tyFunction>` for user-defined callbacks.
- :ref:`tyNotes` regarding specific data structures that require detailed description.
@@ -43,7 +46,7 @@ MuJoCo defines a large number of types:
Primitive types
---------------
The two types below are defined in `mjtnum.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjtnum.h>`_.
The two types below are defined in `mjtnum.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjtnum.h>`__.
.. _mjtNum:
@@ -89,13 +92,14 @@ Byte type used to represent boolean variables.
Enum types
----------
All enum types use the ``mjt`` prefix.
.. _tyModelEnums:
Model
^^^^^
The enums below are defined in `mjmodel.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjmodel.h>`_.
The enums below are defined in `mjmodel.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjmodel.h>`__.
.. _mjtDisableBit:
@@ -333,7 +337,7 @@ These are the possible sensor data types, used in ``mjData.sensor_datatype``.
Data
^^^^
The enums below are defined in `mjdata.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjdata.h>`_.
The enums below are defined in `mjdata.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjdata.h>`__.
@@ -376,7 +380,7 @@ Timer types. The number of timer types is given by ``mjNTIMER`` which is also th
Visualization
^^^^^^^^^^^^^
The enums below are defined in `mjvisualize.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjvisualize.h>`_.
The enums below are defined in `mjvisualize.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjvisualize.h>`__.
.. _mjtCatBit:
@@ -480,7 +484,7 @@ These are the possible stereo rendering types. They are used in ``mjvScene.stere
Rendering
^^^^^^^^^
The enums below are defined in `mjrender.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjrender.h>`_.
The enums below are defined in `mjrender.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjrender.h>`__.
.. _mjtGridPos:
@@ -542,7 +546,7 @@ These are the possible font types.
User Interface
^^^^^^^^^^^^^^
The enums below are defined in `mjui.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjui.h>`_.
The enums below are defined in `mjui.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjui.h>`__.
.. _mjtButton:
@@ -574,13 +578,74 @@ Item types used in the UI framework.
.. mujoco-include:: mjtItem
.. _tySpecEnums:
Spec
^^^^
The enums below are defined in `mjspec.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjspec.h>`__.
.. _mjtGeomInertia:
mjtGeomInertia
~~~~~~~~~~~~~~
Type of inertia inference.
.. mujoco-include:: mjtGeomInertia
.. _mjtBuiltin:
mjtBuiltin
~~~~~~~~~~
Type of built-in procedural texture.
.. mujoco-include:: mjtBuiltin
.. _mjtMark:
mjtMark
~~~~~~~
Mark type for procedural textures.
.. mujoco-include:: mjtMark
.. _mjtLimited:
mjtLimited
~~~~~~~~~~
Type of limit specification.
.. mujoco-include:: mjtLimited
.. _mjtInertiaFromGeom:
mjtInertiaFromGeom
~~~~~~~~~~~~~~~~~~
Whether to infer body inertias from child geoms.
.. mujoco-include:: mjtInertiaFromGeom
.. _mjtOrientation:
mjtOrientation
~~~~~~~~~~~~~~
Type of orientation specifier.
.. mujoco-include:: mjtOrientation
.. _tyPluginEnums:
Plugins
^^^^^^^
The enums below are defined in `mjplugin.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjplugin.h>`_.
The enums below are defined in `mjplugin.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjplugin.h>`__.
See :ref:`exPlugin` for details.
@@ -994,6 +1059,348 @@ is initialized, others change at runtime.
.. mujoco-include:: mjUI
.. _tySpecStructure:
mjSpec
^^^^^^
The strucs below are defined in `mjspec.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjspec.h>`__
and, with the exception of the top level :ref:`mjSpec` struct, begin with the ``mjs`` prefix.
For more details, see the :doc:`Model Editing <../programming/modeledit>` chapter.
.. _mjSpec:
mjSpec
~~~~~~
Model specification.
.. mujoco-include:: mjSpec
.. _mjsElement:
mjsElement
~~~~~~~~~~
Special type corresponding to any element.
.. mujoco-include:: mjsElement
.. _mjsOrientation:
mjsOrientation
~~~~~~~~~~~~~~
Alternative orientation specifiers.
.. mujoco-include:: mjsOrientation
.. _mjsBody:
mjsBody
~~~~~~~
Body specification.
.. mujoco-include:: mjsBody
.. _mjsFrame:
mjsFrame
~~~~~~~~
Frame specification.
.. mujoco-include:: mjsFrame
.. _mjsJoint:
mjsJoint
~~~~~~~~
Joint specification.
.. mujoco-include:: mjsJoint
.. _mjsGeom:
mjsGeom
~~~~~~~
Geom specification.
.. mujoco-include:: mjsGeom
.. _mjsSite:
mjsSite
~~~~~~~
Site specification.
.. mujoco-include:: mjsSite
.. _mjsCamera:
mjsCamera
~~~~~~~~~
Camera specification.
.. mujoco-include:: mjsCamera
.. _mjsLight:
mjsLight
~~~~~~~~
Light specification.
.. mujoco-include:: mjsLight
.. _mjsFlex:
mjsFlex
~~~~~~~
Flex specification.
.. mujoco-include:: mjsFlex
.. _mjsMesh:
mjsMesh
~~~~~~~
Mesh specification.
.. mujoco-include:: mjsMesh
.. _mjsHField:
mjsHField
~~~~~~~~~
Height field specification.
.. mujoco-include:: mjsHField
.. _mjsSkin:
mjsSkin
~~~~~~~
Skin specification.
.. mujoco-include:: mjsSkin
.. _mjsTexture:
mjsTexture
~~~~~~~~~~
Texture specification.
.. mujoco-include:: mjsTexture
.. _mjsMaterial:
mjsMaterial
~~~~~~~~~~~
Material specification.
.. mujoco-include:: mjsMaterial
.. _mjsPair:
mjsPair
~~~~~~~
Pair specification.
.. mujoco-include:: mjsPair
.. _mjsExclude:
mjsExclude
~~~~~~~~~~
Exclude specification.
.. mujoco-include:: mjsExclude
.. _mjsEquality:
mjsEquality
~~~~~~~~~~~
Equality specification.
.. mujoco-include:: mjsEquality
.. _mjsTendon:
mjsTendon
~~~~~~~~~
Tendon specification.
.. mujoco-include:: mjsTendon
.. _mjsWrap:
mjsWrap
~~~~~~~
Wrapping object specification.
.. mujoco-include:: mjsWrap
.. _mjsActuator:
mjsActuator
~~~~~~~~~~~
Actuator specification.
.. mujoco-include:: mjsActuator
.. _mjsSensor:
mjsSensor
~~~~~~~~~
Sensor specification.
.. mujoco-include:: mjsSensor
.. _mjsNumeric:
mjsNumeric
~~~~~~~~~~
Custom numeric field specification.
.. mujoco-include:: mjsNumeric
.. _mjsText:
mjsText
~~~~~~~
Custom text specification.
.. mujoco-include:: mjsText
.. _mjsTuple:
mjsTuple
~~~~~~~~
Tuple specification.
.. mujoco-include:: mjsTuple
.. _mjsKey:
mjsKey
~~~~~~
Keyframe specification.
.. mujoco-include:: mjsKey
.. _mjsDefault:
mjsDefault
~~~~~~~~~~
Default specification.
.. mujoco-include:: mjsDefault
.. _mjsPlugin:
mjsPlugin
~~~~~~~~~
Plugin specification.
.. mujoco-include:: mjsPlugin
.. _mjString:
.. _mjStringVec:
.. _mjIntVec:
.. _mjIntVecVec:
.. _mjFloatVec:
.. _mjFloatVecVec:
.. _mjDoubleVec:
Array handles
~~~~~~~~~~~~~
Explain how handles work.
.. code-block:: C++
#ifdef __cplusplus
// C++: defined to be compatible with corresponding std types
using mjString = std::string;
using mjStringVec = std::vector<std::string>;
using mjIntVec = std::vector<int>;
using mjIntVecVec = std::vector<std::vector<int>>;
using mjFloatVec = std::vector<float>;
using mjFloatVecVec = std::vector<std::vector<float>>;
using mjDoubleVec = std::vector<double>;
#else
// C: opaque types
typedef void mjString;
typedef void mjStringVec;
typedef void mjIntVec;
typedef void mjIntVecVec;
typedef void mjFloatVec;
typedef void mjFloatVecVec;
typedef void mjDoubleVec;
#endif
.. _tyPluginStructure:
Plugins
@@ -1028,8 +1435,8 @@ Function types
--------------
MuJoCo callbacks have corresponding function types. They are defined in `mjdata.h
<https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjdata.h>`_ and in `mjui.h
<https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjui.h>`_. The actual callback functions are documented
<https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjdata.h>`__ and in `mjui.h
<https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjui.h>`__. The actual callback functions are documented
in the :doc:`globals<APIglobals>` page.
File diff suppressed because it is too large Load Diff
+19 -2
View File
@@ -312,7 +312,7 @@ depending on which UI item was modified and what the state of that item is after
This function is called in the screen refresh loop. It copies the offscreen OpenGL buffer to the window framebuffer. If
there are multiple UIs in the application, it should be called once for each UI. Thus ``mjui_render`` is called all the
time, while :ref:`mjui_update` is called only when changes in the UI take place.
time, while :ref:`mjui_update` is called only when changes in the UI take place. dsffsdg
@@ -533,6 +533,18 @@ Symmetrize square matrix :math:`R = \frac{1}{2}(M + M^T)`.
.. _Miscellaneous:
.. _mju_sigmoid:
Twice continuously differentiable sigmoid function using a quintic polynomial:
.. math::
s(x) =
\begin{cases}
0, & & x \le 0 \\
6x^5 - 15x^4 + 10x^3, & 0 \lt & x \lt 1 \\
1, & 1 \le & x \qquad
\end{cases}
.. _Derivatives-api:
The functions below provide useful derivatives of various functions, both analytic and
@@ -545,7 +557,7 @@ Finite-differenced discrete-time transition matrices.
Letting :math:`x, u` denote the current :ref:`state<gePhysicsState>` and :ref:`control<geInput>`
vector in an mjData instance, and letting :math:`y, s` denote the next state and sensor
values, the top-level :ref:`mj_step` function computes :math:`(x,u) \rightarrow (y,s)`.
values, the top-level :ref:`mj_step` function computes :math:`(x,u) \rightarrow (y,s)`
:ref:`mjd_transitionFD` computes the four associated Jacobians using finite-differencing.
These matrices and their dimensions are:
@@ -623,3 +635,8 @@ to the inputs. Below, :math:`\bar q` denotes the pre-modified quaternion:
Note that derivatives depend only on :math:`h` and :math:`v` (in fact, on :math:`s = h v`).
All outputs are optional.
.. _SpecManip:
These functions provide high level manipulation for :ref:`mjSpec` structs, which represent an uncompiled :ref:`mjModel`.
+41 -16
View File
@@ -1233,6 +1233,13 @@ The full list of processing steps applied by the compiler to each mesh is as fol
faces at large angles relative to the average normal are excluded from the average. In this way, sharp edges (as in
cube edges) are not smoothed.
.. _asset-mesh-maxhullvert:
:at:`maxhullvert`: :at-val:`int, "-1"`
Maximum number of vertices in a mesh's convex hull. Currently this is implemented by asking qhull
`to teminate <http://www.qhull.org/html/qh-optt.htm#TAn>`__ after :at:`maxhullvert` vertices. The default
value of -1 means "unlimited". Positive values must be larger than 3.
.. _asset-mesh-vertex:
:at:`vertex`: :at-val:`real(3*nvert), optional`
@@ -1450,7 +1457,7 @@ still be specified here but this functionality is now deprecated and will be rem
This attribute determines how the texture is represented and mapped to objects. It also determines which of the
remaining attributes are relevant. The keywords have the following meaning:
The **cube** type is the most common. It has the effect of shrink-wrapping a texture cube over an object. Apart from
The **cube** type has the effect of shrink-wrapping a texture cube over an object. Apart from
the adjustment provided by the texuniform attribute of :ref:`material <asset-material>`, the process is automatic.
Internally the GPU constructs a ray from the center of the object to each pixel (or rather fragment), finds the
intersection of this ray with the cube surface (the cube and the object have the same center), and uses the
@@ -1473,15 +1480,13 @@ still be specified here but this functionality is now deprecated and will be rem
a texture is referenced from a material applied to a regular object, the effect is equivalent to a cube map. Note
however that the images suitable for skyboxes are rarely suitable for texturing objects.
The **2d** type may be the most familiar to users, however it is only suitable for planes and height fields. This is
because the texture coordinate generator is trying to map a 2D image to 3D space, and as a result there are entire
curves on the object surface that correspond to the same texture pixel. For a box geom for example, the two faces
whose normals are aligned with the Z axis of the local frame appear normal, while the other four faces appear
stretched. For planes this is not an issue because the plane is always normal to the local Z axis. For height fields
the sides enclosing the terrain map appear stretched, but in that case the effect is actually desirable. 2d textures
can be rectangular, unlike the sides of cube textures which must be square. The scaling can be controlled with the
texrepeat attribute of :ref:`material <asset-material>`. The data can be loaded from a singlefile or created
procedurally.
The **2d** type maps a 2D image to a 3D object using :ref:`texture coordinates<asset-mesh-texcoord>` (a.k.a UV
coordinates). However, UV coordinates are only available for meshes. For primitive geoms, the texture is mapped to
the object surface using the local XY coordinates of the geom, effectively projecting the texture along the Z axis.
This sort of mapping is only suitable for planes and height fields, since their top surfaces always face the Z axis.
2d textures can be rectangular, unlike the sides of cube textures which must be square. The scaling can be controlled
with the texrepeat attribute of :ref:`material <asset-material>`. The data can be loaded from a single file or
created procedurally.
.. _asset-texture-content_type:
@@ -2608,11 +2613,20 @@ and the +Y axis points up. Thus the frame position and orientation are the key a
When the camera mode is "targetbody" or "targetbodycom", this attribute becomes required. It specifies which body
should be targeted by the camera. In all other modes this attribute is ignored.
.. _body-camera-orthographic:
:at:`orthographic`: :at-val:`[false, true], "false"`
Whether the camera uses a perspective projection (the default) or an orthographic projection. Setting this attribute
changes the semantic of the :ref:`fovy<body-camera-fovy>` attribute, see below.
.. _body-camera-fovy:
:at:`fovy`: :at-val:`real, "45"`
Vertical field of view of the camera, expressed in degrees regardless of the global angle setting. The horizontal
field of view is computed automatically given the window size and the vertical field of view.
Vertical field-of-view of the camera. If the camera uses a perspective projection, the field-of-view is expressed in
degrees, regardless of the global :ref:`compiler/angle <compiler-angle>` setting. If the camera uses an orthographic
projection, the field-of-view is expressed in units of length; note that in this case the default of 45 is too large
for most scenes and should likely be reduced. In either case, the horizontal field of view is computed automatically
given the window size and the vertical field of view.
.. _body-camera-resolution:
@@ -7150,14 +7164,22 @@ coordinated visual settings corresponding to a "theme", and then include this fi
While all settings in mjVisual are global, the settings here could not be fit into any of the other subsections. So this
is effectively a miscellaneous subsection.
.. _visual-global-orthographic:
:at:`orthographic`: :at-val:`[false, true], "false"`
Whether the free camera uses a perspective projection (the default) or an orthographic projection. Setting this
attribute changes the semantic of the :ref:`global/fovy<visual-global-fovy>` attribute, see below.
.. _visual-global-fovy:
:at:`fovy`: :at-val:`real, "45"`
This attribute specifies the vertical field of view of the free camera, i.e., the camera that is always available in
the visualizer even if no cameras are explicitly defined in the model. It is always expressed in degrees, regardless
of the setting of the angle attribute of :ref:`compiler <compiler>`, and is also represented in the low level model
in degrees. This is because we pass it to OpenGL which uses degrees. The same convention applies to the fovy
attribute of the :ref:`camera <body-camera>` element below.
the visualizer even if no cameras are explicitly defined in the model. If the camera uses a perspective projection,
the field-of-view is expressed in degrees, regardless of the global :ref:`compiler/angle <compiler-angle>` setting.
If the camera uses an orthographic projection, the field-of-view is expressed in units of length; note that in this
case the default of 45 is too large for most scenes and should likely be reduced. In either case, the horizontal
field of view is computed automatically given the window size and the vertical field of view. The same convention
applies to the :ref:`camera/fovy <body-camera-fovy>` attribute.
.. _visual-global-ipd:
@@ -7666,6 +7688,8 @@ if omitted.
.. _default-mesh-scale:
.. _default-mesh-maxhullvert:
:el-prefix:`default/` |-| **mesh** (?)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7860,6 +7884,7 @@ if omitted.
| This element sets the attributes of the dummy :ref:`site <body-site>` element of the defaults class.
| All site attributes are available here except: name, class.
.. _default-camera-orthographic:
.. _default-camera-fovy:
+17 -13
View File
@@ -103,6 +103,8 @@
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`refpos<asset-mesh-refpos>` | :ref:`refquat<asset-mesh-refquat>` | :ref:`scale<asset-mesh-scale>` | :ref:`smoothnormal<asset-mesh-smoothnormal>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`maxhullvert<asset-mesh-maxhullvert>` | | | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_2| mesh |br| |_2| |L| | | .. table:: |
| :ref:`plugin | \* | :class: mjcf-attributes |
@@ -275,15 +277,15 @@
| :ref:`camera | \* | :class: mjcf-attributes |
| <body-camera>` | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`name<body-camera-name>` | :ref:`class<body-camera-class>` | :ref:`fovy<body-camera-fovy>` | :ref:`ipd<body-camera-ipd>` | |
| | | | :ref:`name<body-camera-name>` | :ref:`class<body-camera-class>` | :ref:`orthographic<body-camera-orthographic>` | :ref:`fovy<body-camera-fovy>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`resolution<body-camera-resolution>` | :ref:`pos<body-camera-pos>` | :ref:`quat<body-camera-quat>` | :ref:`axisangle<body-camera-axisangle>` | |
| | | | :ref:`ipd<body-camera-ipd>` | :ref:`resolution<body-camera-resolution>` | :ref:`pos<body-camera-pos>` | :ref:`quat<body-camera-quat>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`xyaxes<body-camera-xyaxes>` | :ref:`zaxis<body-camera-zaxis>` | :ref:`euler<body-camera-euler>` | :ref:`mode<body-camera-mode>` | |
| | | | :ref:`axisangle<body-camera-axisangle>` | :ref:`xyaxes<body-camera-xyaxes>` | :ref:`zaxis<body-camera-zaxis>` | :ref:`euler<body-camera-euler>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`target<body-camera-target>` | :ref:`focal<body-camera-focal>` | :ref:`focalpixel<body-camera-focalpixel>` | :ref:`principal<body-camera-principal>` | |
| | | | :ref:`mode<body-camera-mode>` | :ref:`target<body-camera-target>` | :ref:`focal<body-camera-focal>` | :ref:`focalpixel<body-camera-focalpixel>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`principalpixel<body-camera-principalpixel>` | :ref:`sensorsize<body-camera-sensorsize>` | :ref:`user<body-camera-user>` | | |
| | | | :ref:`principal<body-camera-principal>` | :ref:`principalpixel<body-camera-principalpixel>` | :ref:`sensorsize<body-camera-sensorsize>` | :ref:`user<body-camera-user>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| body |br| |_| |L| | | .. table:: |
@@ -1244,11 +1246,11 @@
| :ref:`global | ? | :class: mjcf-attributes |
| <visual-global>` | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`fovy<visual-global-fovy>` | :ref:`ipd<visual-global-ipd>` | :ref:`azimuth<visual-global-azimuth>` | :ref:`elevation<visual-global-elevation>` | |
| | | | :ref:`orthographic<visual-global-orthographic>` | :ref:`fovy<visual-global-fovy>` | :ref:`ipd<visual-global-ipd>` | :ref:`azimuth<visual-global-azimuth>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`linewidth<visual-global-linewidth>` | :ref:`glow<visual-global-glow>` | :ref:`offwidth<visual-global-offwidth>` | :ref:`offheight<visual-global-offheight>` | |
| | | | :ref:`elevation<visual-global-elevation>` | :ref:`linewidth<visual-global-linewidth>` | :ref:`glow<visual-global-glow>` | :ref:`offwidth<visual-global-offwidth>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`realtime<visual-global-realtime>` | :ref:`ellipsoidinertia<visual-global-ellipsoidinertia>` | :ref:`bvactive<visual-global-bvactive>` | | |
| | | | :ref:`offheight<visual-global-offheight>` | :ref:`realtime<visual-global-realtime>` | :ref:`ellipsoidinertia<visual-global-ellipsoidinertia>` | :ref:`bvactive<visual-global-bvactive>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| visual |br| |_| |L| | | .. table:: |
@@ -1325,7 +1327,7 @@
| :ref:`mesh | ? | :class: mjcf-attributes |
| <default-mesh>` | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`scale<default-mesh-scale>` | | | | |
| | | | :ref:`scale<default-mesh-scale>` | :ref:`maxhullvert<default-mesh-maxhullvert>` | | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| default |br| |_| |L| | | .. table:: |
@@ -1394,13 +1396,15 @@
| :ref:`camera | ? | :class: mjcf-attributes |
| <default-camera>` | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`fovy<default-camera-fovy>` | :ref:`ipd<default-camera-ipd>` | :ref:`resolution<default-camera-resolution>` | :ref:`pos<default-camera-pos>` | |
| | | | :ref:`orthographic<default-camera-orthographic>` | :ref:`fovy<default-camera-fovy>` | :ref:`ipd<default-camera-ipd>` | :ref:`resolution<default-camera-resolution>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`quat<default-camera-quat>` | :ref:`axisangle<default-camera-axisangle>` | :ref:`xyaxes<default-camera-xyaxes>` | :ref:`zaxis<default-camera-zaxis>` | |
| | | | :ref:`pos<default-camera-pos>` | :ref:`quat<default-camera-quat>` | :ref:`axisangle<default-camera-axisangle>` | :ref:`xyaxes<default-camera-xyaxes>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`euler<default-camera-euler>` | :ref:`mode<default-camera-mode>` | :ref:`focal<default-camera-focal>` | :ref:`focalpixel<default-camera-focalpixel>` | |
| | | | :ref:`zaxis<default-camera-zaxis>` | :ref:`euler<default-camera-euler>` | :ref:`mode<default-camera-mode>` | :ref:`focal<default-camera-focal>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`principal<default-camera-principal>` | :ref:`principalpixel<default-camera-principalpixel>` | :ref:`sensorsize<default-camera-sensorsize>` | :ref:`user<default-camera-user>` | |
| | | | :ref:`focalpixel<default-camera-focalpixel>` | :ref:`principal<default-camera-principal>` | :ref:`principalpixel<default-camera-principalpixel>` | :ref:`sensorsize<default-camera-sensorsize>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`user<default-camera-user>` | | | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| default |br| |_| |L| | | .. table:: |
+37 -7
View File
@@ -5,6 +5,36 @@ Changelog
Upcoming version (not yet released)
-----------------------------------
General
^^^^^^^
1. Added a new API for :doc:`procedural model manipulation<programming/modeledit>`. Fixes :github:issue:`364`.
Still missing:
- Detailed documentation.
- Python bindings.
.. youtube:: ZXBTEIDWHhs
:align: right
:width: 240px
2. Added support for orthographic cameras. This is available for both fixed cameras and the free camera, using the
:ref:`camera/orthographic<body-camera-orthographic>` and :ref:`global/orthographic<visual-global-orthographic>`
attributes, respectively.
3. Added :ref:`maxhullvert<asset-mesh-maxhullvert>`, the maximum number of vertices in a mesh's convex hull.
4. Added :ref:`mj_setKeyframe` for saving the current state into a model keyframe.
5. Added support for ``ball`` joints in the URDF parser ("spherical" in URDF).
6. Deprecated :ref:`mju_rotVecMat` and :ref:`mju_rotVecMatT` in favor of :ref:`mju_mulMatVec3` and
:ref:`mju_mulMatTVec3`. These functions names and argument ordering are more consistent with the rest of the API.
MJX
~~~
7. Added support for :ref:`elliptic friction cones<option-cone>`.
8. Fixed a bug that resulted in less-optimal linesearch solutions for some difficult constraint settings.
9. Fixed a bug in the Newton solver that sometimes resulted in less-optimal gradients.
Version 3.1.6 (Jun 3, 2024)
---------------------------
General
^^^^^^^
@@ -715,13 +745,13 @@ General
Previously, the smooth part consisted of two stitched quadratics, once continuously differentiable.
It is now a single quintic, twice continuously differentiable:
.. math::
s(x) =
\begin{cases}
0, & & x \le 0 \\
6x^5 - 15x^4 + 10x^3, & 0 \lt & x \lt 1 \\
1, & 1 \le & x \qquad
\end{cases}
.. math::
s(x) =
\begin{cases}
0, & & x \le 0 \\
6x^5 - 15x^4 + 10x^3, & 0 \lt & x \lt 1 \\
1, & 1 \le & x \qquad
\end{cases}
17. Added optional :ref:`tausmooth<actuator-muscle-tausmooth>` attribute to muscle actuators. When positive, the
time-constant :math:`\tau` of muscle activation/deactivation uses :ref:`mju_sigmoid` to transition smoothly
+8
View File
@@ -266,6 +266,14 @@ dt .at {
margin-bottom: 0.3em;
}
/* Adjust margins around code blocks */
.highlight pre {
margin-top: -0.3em;
margin-bottom: -0.3em;
margin-left: -0.5em;
margin-right: -0.5em;
}
details summary {
font-weight: 600;
}
+756 -9
View File
@@ -751,7 +751,8 @@ struct mjOption_ { // physics options
typedef struct mjOption_ mjOption;
struct mjVisual_ { // visualization options
struct { // global parameters
float fovy; // y-field of view for free camera (degrees)
int orthographic; // is the free camera orthographic (0: no, 1: yes)
float fovy; // y field-of-view of free camera (orthographic ? length : degree)
float ipd; // inter-pupilary distance for free camera
float azimuth; // initial azimuth of free camera (degrees)
float elevation; // initial elevation of free camera (degrees)
@@ -1072,11 +1073,12 @@ struct mjModel_ {
mjtNum* cam_poscom0; // global position rel. to sub-com in qpos0 (ncam x 3)
mjtNum* cam_pos0; // global position rel. to body in qpos0 (ncam x 3)
mjtNum* cam_mat0; // global orientation in qpos0 (ncam x 9)
int* cam_resolution; // [width, height] in pixels (ncam x 2)
mjtNum* cam_fovy; // y-field of view (deg) (ncam x 1)
float* cam_intrinsic; // [focal length; principal point] (ncam x 4)
float* cam_sensorsize; // sensor size (ncam x 2)
int* cam_orthographic; // orthographic camera; 0: no, 1: yes (ncam x 1)
mjtNum* cam_fovy; // y field-of-view (ortho ? len : deg) (ncam x 1)
mjtNum* cam_ipd; // inter-pupilary distance (ncam x 1)
int* cam_resolution; // resolution: pixels [width, height] (ncam x 2)
float* cam_sensorsize; // sensor size: length [width, height] (ncam x 2)
float* cam_intrinsic; // [focal length; principal point] (ncam x 4)
mjtNum* cam_user; // user data (ncam x nuser_cam)
// lights
@@ -1434,7 +1436,7 @@ struct mjpPlugin_ {
void (*copy)(mjData* dest, const mjModel* m, const mjData* src, int instance);
// called when an mjData is being reset (required)
void (*reset)(const mjModel* m, double* plugin_state, void* plugin_data, int instance);
void (*reset)(const mjModel* m, mjtNum* plugin_state, void* plugin_data, int instance);
// called when the plugin needs to update its outputs (required)
void (*compute)(const mjModel* m, mjData* d, int instance, int capability_bit);
@@ -1598,6 +1600,638 @@ struct mjrContext_ { // custom OpenGL context
int readDepthMap; // depth mapping: mjDEPTH_ZERONEAR or mjDEPTH_ZEROFAR
};
typedef struct mjrContext_ mjrContext;
typedef enum mjtGeomInertia_ { // type of inertia inference
mjINERTIA_VOLUME, // mass distributed in the volume
mjINERTIA_SHELL, // mass distributed on the surface
} mjtGeomInertia;
typedef enum mjtBuiltin_ { // type of built-in procedural texture
mjBUILTIN_NONE = 0, // no built-in texture
mjBUILTIN_GRADIENT, // gradient: rgb1->rgb2
mjBUILTIN_CHECKER, // checker pattern: rgb1, rgb2
mjBUILTIN_FLAT // 2d: rgb1; cube: rgb1-up, rgb2-side, rgb3-down
} mjtBuiltin;
typedef enum mjtMark_ { // mark type for procedural textures
mjMARK_NONE = 0, // no mark
mjMARK_EDGE, // edges
mjMARK_CROSS, // cross
mjMARK_RANDOM // random dots
} mjtMark;
typedef enum mjtLimited_ { // type of limit specification
mjLIMITED_FALSE = 0, // not limited
mjLIMITED_TRUE, // limited
mjLIMITED_AUTO, // limited inferred from presence of range
} mjtLimited;
typedef enum mjtInertiaFromGeom_ { // whether to infer body inertias from child geoms
mjINERTIAFROMGEOM_FALSE = 0, // do not use; inertial element required
mjINERTIAFROMGEOM_TRUE, // always use; overwrite inertial element
mjINERTIAFROMGEOM_AUTO // use only if inertial element is missing
} mjtInertiaFromGeom;
typedef enum mjtOrientation_ { // type of orientation specifier
mjORIENTATION_QUAT = 0, // quaternion
mjORIENTATION_AXISANGLE, // axis and angle
mjORIENTATION_XYAXES, // x and y axes
mjORIENTATION_ZAXIS, // z axis (minimal rotation)
mjORIENTATION_EULER, // Euler angles
} mjtOrientation;
typedef struct mjsElement_ { // element type, do not modify
mjtObj elemtype; // element type
} mjsElement;
typedef struct mjSpec_ { // model specification
mjsElement* element; // element type
mjString* modelname; // model name
// compiler settings
mjtByte autolimits; // infer "limited" attribute based on range
double boundmass; // enforce minimum body mass
double boundinertia; // enforce minimum body diagonal inertia
double settotalmass; // rescale masses and inertias; <=0: ignore
mjtByte balanceinertia; // automatically impose A + B >= C rule
mjtByte strippath; // automatically strip paths from mesh files
mjtByte fitaabb; // meshfit to aabb instead of inertia box
mjtByte degree; // angles in radians or degrees
char euler[3]; // sequence for euler rotations
mjString* meshdir; // mesh and hfield directory
mjString* texturedir; // texture directory
mjtByte discardvisual; // discard visual geoms in parser
mjtByte convexhull; // compute mesh convex hulls
mjtByte usethread; // use multiple threads to speed up compiler
mjtByte fusestatic; // fuse static bodies with parent
int inertiafromgeom; // use geom inertias (mjtInertiaFromGeom)
int inertiagrouprange[2]; // range of geom groups used to compute inertia
mjtByte exactmeshinertia; // if false, use old formula
mjLROpt LRopt; // options for lengthrange computation
// engine data
mjOption option; // physics options
mjVisual visual; // visual options
mjStatistic stat; // statistics override (if defined)
// sizes
size_t memory; // number of bytes in arena+stack memory
int nemax; // max number of equality constraints
int nuserdata; // number of mjtNums in userdata
int nuser_body; // number of mjtNums in body_user
int nuser_jnt; // number of mjtNums in jnt_user
int nuser_geom; // number of mjtNums in geom_user
int nuser_site; // number of mjtNums in site_user
int nuser_cam; // number of mjtNums in cam_user
int nuser_tendon; // number of mjtNums in tendon_user
int nuser_actuator; // number of mjtNums in actuator_user
int nuser_sensor; // number of mjtNums in sensor_user
int nkey; // number of keyframes
int njmax; // (deprecated) max number of constraints
int nconmax; // (deprecated) max number of detected contacts
size_t nstack; // (deprecated) number of mjtNums in mjData stack
// global data
mjString* comment; // comment at top of XML
mjString* modelfiledir; // path to model file
// other
mjtByte hasImplicitPluginElem; // already encountered an implicit plugin sensor/actuator
} mjSpec;
typedef struct mjsOrientation_ { // alternative orientation specifiers
mjtOrientation type; // active orientation specifier
double axisangle[4]; // axis and angle
double xyaxes[6]; // x and y axes
double zaxis[3]; // z axis (minimal rotation)
double euler[3]; // Euler angles
} mjsOrientation;
typedef struct mjsPlugin_ { // plugin specification
mjsElement* instance; // element type
mjString* name; // name
mjString* instance_name; // instance name
int plugin_slot; // global registered slot number of the plugin
mjtByte active; // is the plugin active
mjString* info; // message appended to compiler errors
} mjsPlugin;
typedef struct mjsBody_ { // body specification
mjsElement* element; // element type
mjString* name; // name
mjString* childclass; // childclass name
// body frame
double pos[3]; // frame position
double quat[4]; // frame orientation
mjsOrientation alt; // frame alternative orientation
// inertial frame
double mass; // mass
double ipos[3]; // inertial frame position
double iquat[4]; // inertial frame orientation
double inertia[3]; // diagonal inertia (in i-frame)
mjsOrientation ialt; // inertial frame alternative orientation
double fullinertia[6]; // non-axis-aligned inertia matrix
// other
mjtByte mocap; // is this a mocap body
double gravcomp; // gravity compensation
mjDoubleVec* userdata; // user data
mjtByte explicitinertial; // whether to save the body with explicit inertial clause
mjsPlugin plugin; // passive force plugin
mjString* info; // message appended to compiler errors
} mjsBody;
typedef struct mjsFrame_ { // frame specification
mjsElement* element; // element type
mjString* name; // name
mjString* childclass; // childclass name
double pos[3]; // position
double quat[4]; // orientation
mjsOrientation alt; // alternative orientation
mjString* info; // message appended to compiler errors
} mjsFrame;
typedef struct mjsJoint_ { // joint specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjtJoint type; // joint type
// kinematics
double pos[3]; // anchor position
double axis[3]; // joint axis
double ref; // value at reference configuration: qpos0
// stiffness
double stiffness; // stiffness coefficient
double springref; // spring reference value: qpos_spring
double springdamper[2]; // timeconst, dampratio
// limits
int limited; // does joint have limits (mjtLimited)
double range[2]; // joint limits
double margin; // margin value for joint limit detection
mjtNum solref_limit[mjNREF]; // solver reference: joint limits
mjtNum solimp_limit[mjNIMP]; // solver impedance: joint limits
int actfrclimited; // are actuator forces on joint limited (mjtLimited)
double actfrcrange[2]; // actuator force limits
// dof properties
double armature; // armature inertia (mass for slider)
double damping; // damping coefficient
double frictionloss; // friction loss
mjtNum solref_friction[mjNREF]; // solver reference: dof friction
mjtNum solimp_friction[mjNIMP]; // solver impedance: dof friction
// other
int group; // group
mjtByte actgravcomp; // is gravcomp force applied via actuators
mjDoubleVec* userdata; // user data
mjString* info; // message appended to compiler errors
} mjsJoint;
typedef struct mjsGeom_ { // geom specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // classname
mjtGeom type; // geom type
// frame, size
double pos[3]; // position
double quat[4]; // orientation
mjsOrientation alt; // alternative orientation
double fromto[6]; // alternative for capsule, cylinder, box, ellipsoid
double size[3]; // type-specific size
// contact related
int contype; // contact type
int conaffinity; // contact affinity
int condim; // contact dimensionality
int priority; // contact priority
double friction[3]; // one-sided friction coefficients: slide, roll, spin
double solmix; // solver mixing for contact pairs
mjtNum solref[mjNREF]; // solver reference
mjtNum solimp[mjNIMP]; // solver impedance
double margin; // margin for contact detection
double gap; // include in solver if dist < margin-gap
// inertia inference
double mass; // used to compute density
double density; // used to compute mass and inertia from volume or surface
mjtGeomInertia typeinertia; // selects between surface and volume inertia
// fluid forces
mjtNum fluid_ellipsoid; // whether ellipsoid-fluid model is active
mjtNum fluid_coefs[5]; // ellipsoid-fluid interaction coefs
// visual
mjString* material; // name of material
float rgba[4]; // rgba when material is omitted
int group; // group
// other
mjString* hfieldname; // heightfield attached to geom
mjString* meshname; // mesh attached to geom
double fitscale; // scale mesh uniformly
mjDoubleVec* userdata; // user data
mjsPlugin plugin; // sdf plugin
mjString* info; // message appended to compiler errors
} mjsGeom;
typedef struct mjsSite_ { // site specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// frame, size
double pos[3]; // position
double quat[4]; // orientation
mjsOrientation alt; // alternative orientation
double fromto[6]; // alternative for capsule, cylinder, box, ellipsoid
double size[3]; // geom size
// visual
mjtGeom type; // geom type
mjString* material; // name of material
int group; // group
float rgba[4]; // rgba when material is omitted
// other
mjDoubleVec* userdata; // user data
mjString* info; // message appended to compiler errors
} mjsSite;
typedef struct mjsCamera_ { // camera specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// extrinsics
double pos[3]; // position
double quat[4]; // orientation
mjsOrientation alt; // alternative orientation
mjtCamLight mode; // tracking mode
mjString* targetbody; // target body for tracking/targeting
// intrinsics
int orthographic; // is camera orthographic
double fovy; // y-field of view
double ipd; // inter-pupilary distance
float intrinsic[4]; // camera intrinsics (length)
float sensor_size[2]; // sensor size (length)
float resolution[2]; // resolution (pixel)
float focal_length[2]; // focal length (length)
float focal_pixel[2]; // focal length (pixel)
float principal_length[2]; // principal point (length)
float principal_pixel[2]; // principal point (pixel)
// other
mjDoubleVec* userdata; // user data
mjString* info; // message appended to compiler errors
} mjsCamera;
typedef struct mjsLight_ { // light specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// frame
double pos[3]; // position
double dir[3]; // direction
mjtCamLight mode; // tracking mode
mjString* targetbody; // target body for targeting
// intrinsics
mjtByte active; // is light active
mjtByte directional; // is light directional or spot
mjtByte castshadow; // does light cast shadows
double bulbradius; // bulb radius, for soft shadows
float attenuation[3]; // OpenGL attenuation (quadratic model)
float cutoff; // OpenGL cutoff
float exponent; // OpenGL exponent
float ambient[3]; // ambient color
float diffuse[3]; // diffuse color
float specular[3]; // specular color
// other
mjString* info; // message appended to compiler errorsx
} mjsLight;
typedef struct mjsFlex_ { // flex specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// contact properties
int contype; // contact type
int conaffinity; // contact affinity
int condim; // contact dimensionality
int priority; // contact priority
double friction[3]; // one-sided friction coefficients: slide, roll, spin
double solmix; // solver mixing for contact pairs
mjtNum solref[mjNREF]; // solver reference
mjtNum solimp[mjNIMP]; // solver impedance
double margin; // margin for contact detection
double gap; // include in solver if dist<margin-gap
// other properties
int dim; // element dimensionality
double radius; // radius around primitive element
mjtByte internal; // enable internal collisions
mjtByte flatskin; // render flex skin with flat shading
int selfcollide; // mode for flex self colllision
int activelayers; // number of active element layers in 3D
int group; // group for visualizatioh
double edgestiffness; // edge stiffness
double edgedamping; // edge damping
float rgba[4]; // rgba when material is omitted
mjString* material; // name of material used for rendering
// mesh properties
mjStringVec* vertbody; // vertex body names
mjDoubleVec* vert; // vertex positions
mjIntVec* elem; // element vertex ids
mjFloatVec* texcoord; // vertex texture coordinates
// other
mjString* info; // message appended to compiler errors
} mjsFlex;
typedef struct mjsMesh_ { // mesh specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjString* content_type; // content type of file
mjString* file; // mesh file
double refpos[3]; // reference position
double refquat[4]; // reference orientation
double scale[3]; // rescale mesh
mjtByte smoothnormal; // do not exclude large-angle faces from normals
int maxhullvert; // maximum vertex count for the convex hull
mjFloatVec* uservert; // user vertex data
mjFloatVec* usernormal; // user normal data
mjFloatVec* usertexcoord; // user texcoord data
mjIntVec* userface; // user vertex indices
mjIntVec* userfacenormal; // user normal indices
mjIntVec* userfacetexcoord; // user texcoord indices
mjsPlugin plugin; // sdf plugin
mjString* info; // message appended to compiler errors
} mjsMesh;
typedef struct mjsHField_ { // height field specification
mjsElement* element; // element type
mjString* name; // name
mjString* content_type; // content type of file
mjString* file; // file: (nrow, ncol, [elevation data])
double size[4]; // hfield size (ignore referencing geom size)
int nrow; // number of rows
int ncol; // number of columns
mjFloatVec* userdata; // user-provided elevation data
mjString* info; // message appended to compiler errors
} mjsHField;
typedef struct mjsSkin_ { // skin specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjString* file; // skin file
mjString* material; // name of material used for rendering
float rgba[4]; // rgba when material is omitted
float inflate; // inflate in normal direction
int group; // group for visualization
// mesh
mjFloatVec* vert; // vertex positions
mjFloatVec* texcoord; // texture coordinates
mjIntVec* face; // faces
// skin
mjStringVec* bodyname; // body names
mjFloatVec* bindpos; // bind pos
mjFloatVec* bindquat; // bind quat
mjIntVecVec* vertid; // vertex ids
mjFloatVecVec* vertweight; // vertex weights
// other
mjString* info; // message appended to compiler errors
} mjsSkin;
typedef struct mjsTexture_ { // texture specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjtTexture type; // texture type
// method 1: builtin
int builtin; // builtin type (mjtBuiltin)
int mark; // mark type (mjtMark)
double rgb1[3]; // first color for builtin
double rgb2[3]; // second color for builtin
double markrgb[3]; // mark color
double random; // probability of random dots
int height; // height in pixels (square for cube and skybox)
int width; // width in pixels
// method 2: single file
mjString* content_type; // content type of file
mjString* file; // png file to load; use for all sides of cube
int gridsize[2]; // size of grid for composite file; (1,1)-repeat
char gridlayout[13]; // row-major: L,R,F,B,U,D for faces; . for unused
// method 3: separate files
mjStringVec* cubefiles; // different file for each side of the cube
// flip options
mjtByte hflip; // horizontal flip
mjtByte vflip; // vertical flip
// other
mjString* info; // message appended to compiler errors
} mjsTexture;
typedef struct mjsMaterial_ { // material specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjString* texture; // name of texture (empty: none)
mjtByte texuniform; // make texture cube uniform
float texrepeat[2]; // texture repetition for 2D mapping
float emission; // emission
float specular; // specular
float shininess; // shininess
float reflectance; // reflectance
float metallic; // metallic
float roughness; // roughness
float rgba[4]; // rgba
mjString* info; // message appended to compiler errors
} mjsMaterial;
typedef struct mjsPair_ { // pair specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjString* geomname1; // name of geom 1
mjString* geomname2; // name of geom 2
// optional parameters: computed from geoms if not set by user
int condim; // contact dimensionality
mjtNum solref[mjNREF]; // solver reference, normal direction
mjtNum solreffriction[mjNREF]; // solver reference, frictional directions
mjtNum solimp[mjNIMP]; // solver impedance
double margin; // margin for contact detection
double gap; // include in solver if dist<margin-gap
double friction[5]; // full contact friction
mjString* info; // message appended to errors
} mjsPair;
typedef struct mjsExclude_ { // exclude specification
mjsElement* element; // element type
mjString* name; // name
mjString* bodyname1; // name of geom 1
mjString* bodyname2; // name of geom 2
mjString* info; // message appended to errors
} mjsExclude;
typedef struct mjsEquality_ { // equality specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjtEq type; // constraint type
double data[mjNEQDATA]; // type-dependent data
mjtByte active; // is equality initially active
mjString* name1; // name of object 1
mjString* name2; // name of object 2
mjtNum solref[mjNREF]; // solver reference
mjtNum solimp[mjNIMP]; // solver impedance
mjString* info; // message appended to errors
} mjsEquality;
typedef struct mjsTendon_ { // tendon specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// stiffness, damping, friction
double stiffness; // stiffness coefficient
double springlength[2]; // spring resting length; {-1, -1}: use qpos_spring
double damping; // damping coefficient
double frictionloss; // friction loss
mjtNum solref_friction[mjNREF]; // solver reference: tendon friction
mjtNum solimp_friction[mjNIMP]; // solver impedance: tendon friction
// length range
int limited; // does tendon have limits (mjtLimited)
double range[2]; // length limits
double margin; // margin value for tendon limit detection
mjtNum solref_limit[mjNREF]; // solver reference: tendon limits
mjtNum solimp_limit[mjNIMP]; // solver impedance: tendon limits
// visual
mjString* material; // name of material for rendering
double width; // width for rendering
float rgba[4]; // rgba when material is omitted
int group; // group
// other
mjDoubleVec* userdata; // user data
mjString* info; // message appended to errors
} mjsTendon;
typedef struct mjsWrap_ { // wrapping object specification
mjsElement* element; // element type
mjString* info; // message appended to errors
} mjsWrap;
typedef struct mjsActuator_ { // actuator specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// gain, bias
mjtGain gaintype; // gain type
double gainprm[mjNGAIN]; // gain parameters
mjtBias biastype; // bias type
double biasprm[mjNGAIN]; // bias parameters
// activation state
mjtDyn dyntype; // dynamics type
double dynprm[mjNDYN]; // dynamics parameters
int actdim; // number of activation variables
int plugin_actdim; // actuator state size for plugins
mjtByte actearly; // apply next activations to qfrc
// transmission
mjtTrn trntype; // transmission type
double gear[6]; // length and transmitted force scaling
mjString* target; // name of transmission target
mjString* refsite; // reference site, for site transmission
mjString* slidersite; // site defining cylinder, for slider-crank
double cranklength; // crank length, for slider-crank
double lengthrange[2]; // transmission length range
double inheritrange; // automatic range setting for position and intvelocity
// input/output clamping
int ctrllimited; // are control limits defined (mjtLimited)
double ctrlrange[2]; // control range
int forcelimited; // are force limits defined (mjtLimited)
double forcerange[2]; // force range
int actlimited; // are activation limits defined (mjtLimited)
double actrange[2]; // activation range
// other
int group; // group
mjDoubleVec* userdata; // user data
mjsPlugin plugin; // actuator plugin
mjString* info; // message appended to compiler errors
} mjsActuator;
typedef struct mjsSensor_ { // sensor specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// sensor definition
mjtSensor type; // type of sensor
mjtObj objtype; // type of sensorized object
mjString* objname; // name of sensorized object
mjtObj reftype; // type of referenced object
mjString* refname; // name of referenced object
// user-defined sensors
mjtDataType datatype; // data type for sensor measurement
mjtStage needstage; // compute stage needed to simulate sensor
int dim; // number of scalar outputs
// output post-processing
double cutoff; // cutoff for real and positive datatypes
double noise; // noise stdev
// other
mjDoubleVec* userdata; // user data
mjsPlugin plugin; // sensor plugin
mjString* info; // message appended to compiler errors
} mjsSensor;
typedef struct mjsNumeric_ { // custom numeric field specification
mjsElement* element; // element type
mjString* name; // name
mjDoubleVec* data; // initialization data
int size; // array size, can be bigger than data size
mjString* info; // message appended to compiler errors
} mjsNumeric;
typedef struct mjsText_ { // custom text specification
mjsElement* element; // element type
mjString* name; // name
mjString* data; // text string
mjString* info; // message appended to compiler errors
} mjsText;
typedef struct mjsTuple_ { // tuple specification
mjsElement* element; // element type
mjString* name; // name
mjIntVec* objtype; // object types
mjStringVec* objname; // object names
mjDoubleVec* objprm; // object parameters
mjString* info; // message appended to compiler errors
} mjsTuple;
typedef struct mjsKey_ { // keyframe specification
mjsElement* element; // element type
mjString* name; // name
double time; // time
mjDoubleVec* qpos; // qpos
mjDoubleVec* qvel; // qvel
mjDoubleVec* act; // act
mjDoubleVec* mpos; // mocap pos
mjDoubleVec* mquat; // mocap quat
mjDoubleVec* ctrl; // ctrl
mjString* info; // message appended to compiler errors
} mjsKey;
typedef struct mjsDefault_ { // default specification
mjsElement* element; // element type
mjString* name; // class name
mjsJoint* joint; // joint defaults
mjsGeom* geom; // geom defaults
mjsSite* site; // site defaults
mjsCamera* camera; // camera defaults
mjsLight* light; // light defaults
mjsFlex* flex; // flex defaults
mjsMesh* mesh; // mesh defaults
mjsMaterial* material; // material defaults
mjsPair* pair; // pair defaults
mjsEquality* equality; // equality defaults
mjsTendon* tendon; // tendon defaults
mjsActuator* actuator; // actuator defaults
} mjsDefault;
typedef enum mjtTaskStatus_ { // status values for mjTask
mjTASK_NEW = 0, // newly created
mjTASK_QUEUED, // enqueued in a thread pool
@@ -1971,6 +2605,9 @@ struct mjvCamera_ { // abstract camera
mjtNum distance; // distance to lookat point or tracked body
mjtNum azimuth; // camera azimuth (deg)
mjtNum elevation; // camera elevation (deg)
// orthographic / perspective
int orthographic; // 0: perspective; 1: orthographic
};
typedef struct mjvCamera_ mjvCamera;
struct mjvGLCamera_ { // OpenGL camera
@@ -1986,6 +2623,9 @@ struct mjvGLCamera_ { // OpenGL camera
float frustum_top; // top
float frustum_near; // near
float frustum_far; // far
// orthographic / perspective
int orthographic; // 0: perspective; 1: orthographic
};
typedef struct mjvGLCamera_ mjvGLCamera;
struct mjvGeom_ { // abstract geom
@@ -2238,10 +2878,12 @@ struct mjvSceneState_ {
mjtNum* site_size;
float* site_rgba;
int* cam_orthographic;
mjtNum* cam_fovy;
mjtNum* cam_ipd;
float* cam_intrinsic;
int* cam_resolution;
float* cam_sensorsize;
float* cam_intrinsic;
mjtByte* light_directional;
mjtByte* light_castshadow;
@@ -2431,10 +3073,15 @@ int mj_deleteFileVFS(mjVFS* vfs, const char* filename);
void mj_deleteVFS(mjVFS* vfs);
int mj_makeEmptyFileVFS(mjVFS* vfs, const char* filename, int filesize);
mjModel* mj_loadXML(const char* filename, const mjVFS* vfs, char* error, int error_sz);
mjSpec* mj_parseXML(const char* filename, const mjVFS* vfs, char* error, int error_sz);
mjSpec* mj_parseXMLString(const char* xml, const mjVFS* vfs, char* error, int error_sz);
mjModel* mj_compile(mjSpec* s, const mjVFS* vfs);
void mj_recompile(mjSpec* s, const mjVFS* vfs, mjModel* m, mjData* d);
int mj_saveLastXML(const char* filename, const mjModel* m, char* error, int error_sz);
void mj_freeLastXML(void);
int mj_printSchema(const char* filename, char* buffer, int buffer_sz,
int flg_html, int flg_pad);
void mj_copyBack(mjSpec* s, const mjModel* m);
int mj_saveXMLString(const mjSpec* s, char* xml, int xml_sz, char* error, int error_sz);
int mj_saveXML(const mjSpec* s, const char* filename, char* error, int error_sz);
void mj_step(const mjModel* m, mjData* d);
void mj_step1(const mjModel* m, mjData* d);
void mj_step2(const mjModel* m, mjData* d);
@@ -2466,6 +3113,9 @@ void mj_resetCallbacks(void);
void mj_setConst(mjModel* m, mjData* d);
int mj_setLengthRange(mjModel* m, mjData* d, int index,
const mjLROpt* opt, char* error, int error_sz);
mjSpec* mj_makeSpec(void);
mjSpec* mj_copySpec(const mjSpec* s);
void mj_deleteSpec(mjSpec* s);
void mj_printFormattedModel(const mjModel* m, const char* filename, const char* float_format);
void mj_printModel(const mjModel* m, const char* filename);
void mj_printFormattedData(const mjModel* m, mjData* d, const char* filename,
@@ -2474,6 +3124,8 @@ void mj_printData(const mjModel* m, mjData* d, const char* filename);
void mju_printMat(const mjtNum* mat, int nr, int nc);
void mju_printMatSparse(const mjtNum* mat, int nr,
const int* rownnz, const int* rowadr, const int* colind);
int mj_printSchema(const char* filename, char* buffer, int buffer_sz,
int flg_html, int flg_pad);
void mj_fwdPosition(const mjModel* m, mjData* d);
void mj_fwdVelocity(const mjModel* m, mjData* d);
void mj_fwdActuation(const mjModel* m, mjData* d);
@@ -2519,6 +3171,7 @@ void mj_constraintUpdate(const mjModel* m, mjData* d, const mjtNum* jar,
int mj_stateSize(const mjModel* m, unsigned int spec);
void mj_getState(const mjModel* m, const mjData* d, mjtNum* state, unsigned int spec);
void mj_setState(const mjModel* m, mjData* d, const mjtNum* state, unsigned int spec);
void mj_setKeyframe(mjModel* m, const mjData* d, int k);
int mj_addContact(const mjModel* m, mjData* d, const mjContact* con);
int mj_isPyramidal(const mjModel* m);
int mj_isSparse(const mjModel* m);
@@ -2695,6 +3348,8 @@ void* mju_malloc(size_t size);
void mju_free(void* ptr);
void mj_warning(mjData* d, int warning, int info);
void mju_writeLog(const char* type, const char* msg);
const char* mjs_getError(mjSpec* s);
int mjs_isWarning(mjSpec* s);
void mju_zero3(mjtNum res[3]);
void mju_copy3(mjtNum res[3], const mjtNum data[3]);
void mju_scl3(mjtNum res[3], const mjtNum vec[3], mjtNum scl);
@@ -2708,6 +3363,8 @@ mjtNum mju_normalize3(mjtNum vec[3]);
mjtNum mju_norm3(const mjtNum vec[3]);
mjtNum mju_dot3(const mjtNum vec1[3], const mjtNum vec2[3]);
mjtNum mju_dist3(const mjtNum pos1[3], const mjtNum pos2[3]);
void mju_mulMatVec3(mjtNum res[3], const mjtNum mat[9], const mjtNum vec[3]);
void mju_mulMatTVec3(mjtNum res[3], const mjtNum mat[9], const mjtNum vec[3]);
void mju_rotVecMat(mjtNum res[3], const mjtNum vec[3], const mjtNum mat[9]);
void mju_rotVecMatT(mjtNum res[3], const mjtNum vec[3], const mjtNum mat[9]);
void mju_cross(mjtNum res[3], const mjtNum a[3], const mjtNum b[3]);
@@ -2838,4 +3495,94 @@ void mju_threadPoolEnqueue(mjThreadPool* thread_pool, mjTask* task);
void mju_threadPoolDestroy(mjThreadPool* thread_pool);
void mju_defaultTask(mjTask* task);
void mju_taskJoin(mjTask* task);
int mjs_attachBody(mjsFrame* parent, const mjsBody* child,
const char* prefix, const char* suffix);
int mjs_attachFrame(mjsBody* parent, const mjsFrame* child,
const char* prefix, const char* suffix);
int mjs_detachBody(mjSpec* s, mjsBody* b);
mjsBody* mjs_addBody(mjsBody* body, mjsDefault* def);
mjsSite* mjs_addSite(mjsBody* body, mjsDefault* def);
mjsJoint* mjs_addJoint(mjsBody* body, mjsDefault* def);
mjsJoint* mjs_addFreeJoint(mjsBody* body);
mjsGeom* mjs_addGeom(mjsBody* body, mjsDefault* def);
mjsCamera* mjs_addCamera(mjsBody* body, mjsDefault* def);
mjsLight* mjs_addLight(mjsBody* body, mjsDefault* def);
mjsFrame* mjs_addFrame(mjsBody* body, mjsFrame* parentframe);
void mjs_delete(mjsElement* element);
mjsActuator* mjs_addActuator(mjSpec* s, mjsDefault* def);
mjsSensor* mjs_addSensor(mjSpec* s);
mjsFlex* mjs_addFlex(mjSpec* s);
mjsPair* mjs_addPair(mjSpec* s, mjsDefault* def);
mjsExclude* mjs_addExclude(mjSpec* s);
mjsEquality* mjs_addEquality(mjSpec* s, mjsDefault* def);
mjsTendon* mjs_addTendon(mjSpec* s, mjsDefault* def);
mjsWrap* mjs_wrapSite(mjsTendon* tendon, const char* name);
mjsWrap* mjs_wrapGeom(mjsTendon* tendon, const char* name, const char* sidesite);
mjsWrap* mjs_wrapJoint(mjsTendon* tendon, const char* name, double coef);
mjsWrap* mjs_wrapPulley(mjsTendon* tendon, double divisor);
mjsNumeric* mjs_addNumeric(mjSpec* s);
mjsText* mjs_addText(mjSpec* s);
mjsTuple* mjs_addTuple(mjSpec* s);
mjsKey* mjs_addKey(mjSpec* s);
mjsPlugin* mjs_addPlugin(mjSpec* s);
mjsDefault* mjs_addDefault(mjSpec* s, const char* classname, int parentid, int* id);
mjsMesh* mjs_addMesh(mjSpec* s, mjsDefault* def);
mjsHField* mjs_addHField(mjSpec* s);
mjsSkin* mjs_addSkin(mjSpec* s);
mjsTexture* mjs_addTexture(mjSpec* s);
mjsMaterial* mjs_addMaterial(mjSpec* s, mjsDefault* def);
mjSpec* mjs_getSpec(mjsBody* body);
mjsBody* mjs_findBody(mjSpec* s, const char* name);
mjsBody* mjs_findChild(mjsBody* body, const char* name);
mjsMesh* mjs_findMesh(mjSpec* s, const char* name);
mjsFrame* mjs_findFrame(mjSpec* s, const char* name);
mjsDefault* mjs_getDefault(mjsElement* element);
mjsDefault* mjs_findDefault(mjSpec* s, const char* classname);
mjsDefault* mjs_getSpecDefault(mjSpec* s);
int mjs_getId(mjsElement* element);
mjsElement* mjs_firstChild(mjsBody* body, mjtObj type);
mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child);
void mjs_setString(mjString* dest, const char* text);
void mjs_setStringVec(mjStringVec* dest, const char* text);
mjtByte mjs_setInStringVec(mjStringVec* dest, int i, const char* text);
void mjs_appendString(mjStringVec* dest, const char* text);
void mjs_setInt(mjIntVec* dest, const int* array, int size);
void mjs_appendIntVec(mjIntVecVec* dest, const int* array, int size);
void mjs_setFloat(mjFloatVec* dest, const float* array, int size);
void mjs_appendFloatVec(mjFloatVecVec* dest, const float* array, int size);
void mjs_setDouble(mjDoubleVec* dest, const double* array, int size);
void mjs_setPluginAttributes(mjsPlugin* plugin, void* attributes);
const char* mjs_getString(const mjString* source);
const double* mjs_getDouble(const mjDoubleVec* source, int* size);
void mjs_setActivePlugins(mjSpec* s, void* activeplugins);
void mjs_setDefault(mjsElement* element, mjsDefault* def);
void mjs_setFrame(mjsElement* dest, mjsFrame* frame);
const char* mjs_resolveOrientation(double quat[4], mjtByte degree, const char* sequence,
const mjsOrientation* orientation);
const char* mjs_fullInertia(double quat[4], double inertia[3], const double fullinertia[6]);
void mjs_defaultSpec(mjSpec* spec);
void mjs_defaultOrientation(mjsOrientation* orient);
void mjs_defaultBody(mjsBody* body);
void mjs_defaultFrame(mjsFrame* frame);
void mjs_defaultJoint(mjsJoint* joint);
void mjs_defaultGeom(mjsGeom* geom);
void mjs_defaultSite(mjsSite* site);
void mjs_defaultCamera(mjsCamera* camera);
void mjs_defaultLight(mjsLight* light);
void mjs_defaultFlex(mjsFlex* flex);
void mjs_defaultMesh(mjsMesh* mesh);
void mjs_defaultHField(mjsHField* hfield);
void mjs_defaultSkin(mjsSkin* skin);
void mjs_defaultTexture(mjsTexture* texture);
void mjs_defaultMaterial(mjsMaterial* material);
void mjs_defaultPair(mjsPair* pair);
void mjs_defaultEquality(mjsEquality* equality);
void mjs_defaultTendon(mjsTendon* tendon);
void mjs_defaultActuator(mjsActuator* actuator);
void mjs_defaultSensor(mjsSensor* sensor);
void mjs_defaultNumeric(mjsNumeric* numeric);
void mjs_defaultText(mjsText* text);
void mjs_defaultTuple(mjsTuple* tuple);
void mjs_defaultKey(mjsKey* key);
void mjs_defaultPlugin(mjsPlugin* plugin);
// NOLINTEND
+3 -5
View File
@@ -198,13 +198,13 @@ The following features are **fully supported** in MJX:
* - :ref:`Geom <mjtGeom>`
- ``PLANE``, ``HFIELD``, ``SPHERE``, ``CAPSULE``, ``BOX``, ``MESH`` are fully implemented. ``ELLIPSOID`` and ``CYLINDER`` are implemented but only collide with other primitives.
* - :ref:`Constraint <mjtConstraint>`
- ``EQUALITY``, ``LIMIT_JOINT``, ``CONTACT_FRICTIONLESS``, ``CONTACT_PYRAMIDAL``
- ``EQUALITY``, ``LIMIT_JOINT``, ``CONTACT_FRICTIONLESS``, ``CONTACT_PYRAMIDAL``, ``CONTACT_ELLIPTIC``
* - :ref:`Equality <mjtEq>`
- ``CONNECT``, ``WELD``, ``JOINT``
* - :ref:`Integrator <mjtIntegrator>`
- ``EULER``, ``RK4``
* - :ref:`Cone <mjtCone>`
- ``PYRAMIDAL``
- ``PYRAMIDAL``, ``ELLIPTIC``
* - :ref:`Condim <coContact>`
- 1, 3, 4, 6
* - :ref:`Solver <mjtSolver>`
@@ -225,7 +225,7 @@ The following features are **in development** and coming soon:
* - :ref:`Geom <mjtGeom>`
- ``SDF``. Collisions between (``SPHERE``, ``BOX``, ``MESH``, ``HFIELD``) and ``CYLINDER``. Collisions between (``BOX``, ``MESH``, ``HFIELD``) and ``ELLIPSOID``.
* - :ref:`Constraint <mjtConstraint>`
- :ref:`Frictionloss <coFriction>`, ``CONTACT_ELLIPTIC``, ``FRICTION_DOF``
- :ref:`Frictionloss <coFriction>`, ``FRICTION_DOF``
* - :ref:`Integrator <mjtIntegrator>`
- ``IMPLICIT``, ``IMPLICITFAST``
* - Dynamics
@@ -240,8 +240,6 @@ The following features are **in development** and coming soon:
- ``MUSCLE``
* - :ref:`Tendon Wrapping <mjtWrap>`
- ``NONE``, ``JOINT``, ``PULLEY``, ``SITE``, ``SPHERE``, ``CYLINDER``
* - :ref:`Cone <mjtCone>`
- ``ELLIPTIC``
* - Fluid Model
- :ref:`flEllipsoid`
* - :ref:`Tendons <tendon>`
+18 -10
View File
@@ -36,19 +36,19 @@ mjModel memory buffer. MJCF and URDF files are loaded with :ref:`mj_loadXML` whi
:ref:`mj_loadModel`.
When an XML file is loaded, it is first parsed into a document object model (DOM) using the TinyXML parser internally.
This DOM is then processed and converted into a high-level mjCModel object. The conversion depends on the model format
- which is inferred from the top-level element in the XML file, and not from the file extension. Recall that a valid
XML file has a unique top-level element. This element must be :el:`mujoco` for MJCF, and :el:`robot` for URDF.
This DOM is then processed and converted into a high-level :ref:`mjSpec` object. The conversion depends on the model
format -- which is inferred from the top-level element in the XML file, and not from the file extension. Recall that a
valid XML file has a unique top-level element. This element must be :el:`mujoco` for MJCF, and :el:`robot` for URDF.
.. _Compile:
Compiling models
~~~~~~~~~~~~~~~~
Once a high-level mjCModel is created---by loading an MJCF file or a URDF file, or programmatically when such
functionality becomes available---it is compiled into mjModel. Even though loading and compilation are presently
combined in one step, compilation is independent of loading, meaning that the compiler works in the same way
regardless of how mjCModel was created. Both the parser and the compiler perform extensive error checking, and abort
Once a high-level :ref:`mjSpec` is created---by loading an MJCF file or a URDF file, or
:doc:`programmatically<programming/modeledit>`---it is compiled into :ref:`mjModel`.
Compilation is independent of loading, meaning that the compiler works in the same way regardless of how :ref:`mjSpec`
was created. Both the parser and the compiler perform extensive error checking, and abort
when the first error is encountered. The resulting error messages contain the row and column number in the XML file,
and are self-explanatory so we do not document them here. The parser uses a custom schema to make sure that the file
structure, elements and attributes are valid. The compiler then applies many additional semantic checks. Finally, one
@@ -72,9 +72,9 @@ binary MJB file with :ref:`mj_saveModel`. The MJB is a stand-alone file and does
refer to any other files. It also loads faster. So we recommend saving commonly used models as MJB and loading them
when needed for simulation.
It is also possible to save a compiled mjCModel as MJCF with :ref:`mj_saveLastXML`. If any real-valued fields in the
corresponding mjModel were modified after compilation (which is unusual but can happen in system identification
applications for example), the modifications are automatically copied back into mjCModel before saving. Note that
It is also possible to save a compiled :ref:`mjSpec` as MJCF with :ref:`mj_saveLastXML`. If any real-valued fields in
the corresponding mjModel were modified after compilation (which is unusual but can happen in system identification
applications for example), the modifications are automatically copied back into :ref:`mjSpec` before saving. Note that
structural changes cannot be made in the compiled model. The XML writer attempts to generate the smallest MJCF file
which is guaranteed to compile into the same model, modulo negligible numeric differences caused by the plain text
representation of real values. The resulting file may not have the same structure as the original because MJCF has many
@@ -83,6 +83,14 @@ subset of MJCF where all coordinates are local and all body positions, orientati
explicitly specified. In the Computation chapter we showed an `example <_static/example.xml>`__ MJCF file and the
corresponding `saved example <_static/example_saved.xml>`__.
.. _EditModel:
Editing models
~~~~~~~~~~~~~~
As of MuJoCo 3.2, it is possible to create and modify models using the :ref:`mjSpec` struct and related API.
For further documentation, please see the :doc:`Model Editing<programming/modeledit>` chapter.
.. _Mechanisms:
MJCF Mechanisms
+2
View File
@@ -120,6 +120,8 @@ Arms
- .. image:: https://raw.githubusercontent.com/google-deepmind/mujoco_menagerie/main/ufactory_lite6/lite6.png
* - `ViperX 300 6DOF <https://github.com/google-deepmind/mujoco_menagerie/tree/main/trossen_vx300s>`_
- .. image:: https://raw.githubusercontent.com/google-deepmind/mujoco_menagerie/main/trossen_vx300s/vx300s.png
* - `WidowX 250 6DOF <https://github.com/google-deepmind/mujoco_menagerie/tree/main/trossen_wx250s>`_
- .. image:: https://raw.githubusercontent.com/google-deepmind/mujoco_menagerie/main/trossen_wx250s/wx250s.png
* - `ALOHA 2 <https://github.com/google-deepmind/mujoco_menagerie/tree/main/aloha>`_
- .. image:: https://raw.githubusercontent.com/google-deepmind/mujoco_menagerie/main/aloha/aloha.png
* - `Unitree Z1 <https://github.com/google-deepmind/mujoco_menagerie/tree/main/unitree_z1>`_
+18 -20
View File
@@ -141,32 +141,30 @@ There are several entities called "model" in MuJoCo. The user defines the model
The software can then create multiple instances of the same model in different media (file or memory) and on different
levels of description (high or low). All combinations are possible as shown in the following table:
+------------+----------------------+----------------------+
| | High level | Low level |
+============+======================+======================+
| **File** | MJCF/URDF (XML) | MJB (binary) |
+------------+----------------------+----------------------+
| **Memory** | mjCModel (C++ class) | mjModel (C struct) |
+------------+----------------------+----------------------+
+------------+---------------------------+----------------------------+
| | High level | Low level |
+============+===========================+============================+
| **File** | MJCF/URDF (XML) | MJB (binary) |
+------------+---------------------------+----------------------------+
| **Memory** | :ref:`mjSpec` (C struct) | :ref:`mjModel` (C struct) |
+------------+---------------------------+----------------------------+
All runtime computations are performed with ``mjModel`` which is too complex to create manually. This is why we have two
levels of modeling. The high level exists for user convenience: its sole purpose is to be compiled into a low level
model on which computations can be performed. The resulting ``mjModel`` can be loaded and saved into a binary file
All runtime computations are performed with :ref:`mjModel` which is too complex to create manually. This is why we have
two levels of modeling. The high level exists for user convenience: its sole purpose is to be compiled into a low level
model on which computations can be performed. The resulting :ref:`mjModel` can be loaded and saved into a binary file
(MJB), however those are version-specific and cannot be decompiled, thus models should always be maintained as XML
files.
The (internal) C++ class ``mjCModel`` is roughly in one-to-one correspondence with the MJCF file format. The XML parser
interprets the MJCF or URDF file and creates the corresponding ``mjCModel``. In principle the user can create
``mjCModel`` programmatically and then save it to MJCF or compile it. However this functionality is not yet exposed
because a C++ API cannot be exported from a compiler-independent library. There is a plan to develop a C wrapper around
it, but for the time being the parser and compiler are always invoked together, and models can only be created in XML.
The :ref:`mjSpec` C struct is in one-to-one correspondence with the MJCF file format. The XML loader interprets the MJCF
or URDF file, creates the corresponding :ref:`mjSpec` and compiles it to :ref:`mjModel`. The user can create
:ref:`mjSpec` programmatically and then save it to MJCF or compile it. Procedural model creation and editing is
described in the :doc:`Model Editing <programming/modeledit>` chapter.
The following diagram shows the different paths to obtaining an ``mjModel`` (again, the second bullet point is not yet
available):
The following diagram shows the different paths to obtaining an :ref:`mjModel`:
- (text editor) → MJCF/URDF file → (MuJoCo parser → mjCModel → MuJoCo compiler) → mjModel
- (user code) → mjCModel → (MuJoCo compiler) → mjModel
- MJB file → (MuJoCo loader) → mjModel
- (text editor) → MJCF/URDF file → (MuJoCo parser → mjSpec → compiler) → mjModel
- (user code) → mjSpec → (MuJoCo compiler) → mjModel
- MJB file → (model loader) → mjModel
.. _Examples:
+14 -7
View File
@@ -18,7 +18,7 @@ Engine
The simulator (or physics engine) is written in C. It is responsible for all runtime computations.
Parser
The XML parser is written in C++. It can parse MJCF models and URDF models, converting them into an internal mjCModel
C++ object which is not directly exposed to the user.
C++ object which is exposed to the user via mjSpec.
Compiler
The compiler is written in C++. It takes an mjCModel C++ object constructed by the parser, and converts it into an
mjModel C structure used at runtime.
@@ -108,10 +108,10 @@ Building from source
To build MuJoCo from source, you will need CMake and a working C++17 compiler installed. The steps are:
#. Clone the ``mujoco`` repository from GitHub.
#. Create a new build directory somewhere, and ``cd`` into it.
#. Run ``cmake $PATH_TO_CLONED_REPO`` to configure the build.
#. Run ``cmake --build .`` to build.
#. Clone the ``mujoco`` repository from GitHub.
#. Create a new build directory somewhere, and ``cd`` into it.
#. Run ``cmake $PATH_TO_CLONED_REPO`` to configure the build.
#. Run ``cmake --build .`` to build.
MuJoCo's build system automatically fetches dependencies from upstream repositories over the Internet using CMake's
`FetchContent <https://cmake.org/cmake/help/latest/module/FetchContent.html>`_ module.
@@ -123,8 +123,8 @@ section of the documentation.
Additionally, the CMake setup also implements an installation phase which will copy and organize the output files to a
target directory.
5. Select the directory: ``cmake $PATH_TO_CLONED_REPO -DCMAKE_INSTALL_PREFIX=<my_install_dir>``
#. After building, install with ``cmake --install .``
5. Select the directory: ``cmake $PATH_TO_CLONED_REPO -DCMAKE_INSTALL_PREFIX=<my_install_dir>``
#. After building, install with ``cmake --install .``
When building on Windows, use Visual Studio 2019 or later and make sure Windows SDK version 10.0.22000 or later is
installed (see `here <https://github.com/google-deepmind/mujoco/issues/862>`__ for more details).
@@ -160,6 +160,8 @@ links below, to make this documentation self-contained.
Defines the primitive types and structures needed by the UI framework.
`mjtnum.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjtnum.h>`__
Defines MuJoCo's ``mjtNum`` floating-point type to be either ``double`` or ``float``. See :ref:`mjtNum`.
`mjspec.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjspec.h>`__
Defines enums and structs used for :doc:`procedural model editing <modeledit>`.
`mjmacro.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjmacro.h>`__
Defines C macros that are useful in user code.
`mjxmacro.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjxmacro.h>`__
@@ -226,6 +228,8 @@ to which the symbol belongs. First we list the prefixes corresponding to type de
Data structure related to OpenGL rendering, for example :ref:`mjrContext`.
``mjui``
Data structure related to UI framework, for example :ref:`mjuiSection`.
``mjs``
Data structure related :doc:`procedural model editing <modeledit>`, for example :ref:`mjsJoint`.
Next we list the prefixes corresponding to function definitions. Note that function prefixes always end with underscore.
@@ -247,6 +251,8 @@ Next we list the prefixes corresponding to function definitions. Note that funct
custom callbacks by setting these global pointers to user-defined functions.
``mjd_``
Functions for computing derivatives, for example :ref:`mjd_transitionFD`.
``mjs_``
Functions for :doc:`procedural model editing <modeledit>`, for example :ref:`mjs_addJoint`.
.. _inOpenGL:
@@ -276,5 +282,6 @@ now lazily resolved at runtime after the switch to GLAD, the "nogl" libraries ar
simulation
visualization
ui
modeledit
samples
extension
+44
View File
@@ -0,0 +1,44 @@
Model Editing
-------------
.. admonition:: Unstable API
:class: attention
The API described below is new and unstable. There may be latent bugs and function signatures may change. Early
adopters are welcome (indeed, encouraged) to try it out and report any issues on GitHub.
As of MuJoCo 3.2, it is possible to create and modify models using the :ref:`mjSpec` struct and related API.
This datastructure is in one-to-one correspondence with MJCF and indeed, MuJoCo's own XML parsers (both MJCF and URDF)
use this API when loading a model.
.. _meOverview:
Overview
~~~~~~~~
As summarized in the the :ref:`Overview chapter<Instance>`, the traditional workflow to create compiled :ref:`mjModel`
instances is:
1. Create an XML model description file (MJCF or URDF).
2. Call :ref:`mj_loadXML` passing in the XML (and associated assets), obtain an :ref:`mjModel` instance.
The new workflow looks like:
1. Create an :ref:`mjSpec`, either an empty one corresponding to the XML ``<mujoco/>``, or by loading an existing XML
file.
2. Modify the :ref:`mjSpec` as desired, adding, editing and removing elements.
3. Compile the :ref:`mjSpec` at any point, obtaining an updated :ref:`mjModel` instance. After compilation, the
:ref:`mjSpec` remains editable, so steps 2 and 3 are interchangable.
.. _meUsage:
Usage
~~~~~
Detailed documentation is still missing. In the meantime, advanced users can refer to
`user_api_test.cc <https://github.com/google-deepmind/mujoco/blob/main/test/user/user_api_test.cc>`__ and the MJCF
parser in `xml_native_reader.cc <https://github.com/google-deepmind/mujoco/blob/main/src/xml/xml_native_reader.cc>`__,
which is already using this API.
+2 -2
View File
@@ -585,8 +585,8 @@ corresponding to precomputed quantities when the model is in the reference confi
Finally, if changes are made to mjModel at runtime, it may be desirable to save them back to the XML. The function
:ref:`mj_saveLastXML` does that in a limited sense: it copies all real-valued parameters from mjModel back to the
internal mjCModel, and then saves it as XML. This does not cover all possible changes that the user could have made.
The only way to guarantee that all changes are saved is to save the model as a binary MJB file with the function
internal :ref:`mjSpec`, and then saves it as XML. This does not cover all possible changes that the user could have
made. The only way to guarantee that all changes are saved is to save the model as a binary MJB file with the function
:ref:`mj_saveModel`, or even better, make the changes directly in the XML. Unfortunately there are situations where
changes need to be made programmatically, as in system identification for example, and this can only be done with the
compiled model. So in summary, we have reasonable but not perfect mechanisms for saving model changes. The reason for
+2 -2
View File
@@ -30,14 +30,14 @@ _____
The MuJoCo app needs to be run at least once before the native library can be used, in order to register the library as
a trusted binary. Then, copy the dynamic library file from
``/Applications/MuJoCo.app/Contents/Frameworks/mujoco.framework/Versions/Current/libmujoco.3.1.6.dylib`` (it can be
``/Applications/MuJoCo.app/Contents/Frameworks/mujoco.framework/Versions/Current/libmujoco.3.1.7.dylib`` (it can be
found by browsing the contents of ``MuJoCo.app``) and rename it as ``mujoco.dylib``.
Linux
_____
Expand the ``tar.gz`` archive to ``~/.mujoco``. Then copy the dynamic library from
``~/.mujoco/mujoco-3.1.6/lib/libmujoco.so.3.1.6`` and rename it as ``libmujoco.so``.
``~/.mujoco/mujoco-3.1.7/lib/libmujoco.so.3.1.7`` and rename it as ``libmujoco.so``.
Windows
_______
+7 -5
View File
@@ -458,7 +458,8 @@ typedef struct mjOption_ mjOption;
struct mjVisual_ { // visualization options
struct { // global parameters
float fovy; // y-field of view for free camera (degrees)
int orthographic; // is the free camera orthographic (0: no, 1: yes)
float fovy; // y field-of-view of free camera (orthographic ? length : degree)
float ipd; // inter-pupilary distance for free camera
float azimuth; // initial azimuth of free camera (degrees)
float elevation; // initial elevation of free camera (degrees)
@@ -787,11 +788,12 @@ struct mjModel_ {
mjtNum* cam_poscom0; // global position rel. to sub-com in qpos0 (ncam x 3)
mjtNum* cam_pos0; // global position rel. to body in qpos0 (ncam x 3)
mjtNum* cam_mat0; // global orientation in qpos0 (ncam x 9)
int* cam_resolution; // [width, height] in pixels (ncam x 2)
mjtNum* cam_fovy; // y-field of view (deg) (ncam x 1)
float* cam_intrinsic; // [focal length; principal point] (ncam x 4)
float* cam_sensorsize; // sensor size (ncam x 2)
int* cam_orthographic; // orthographic camera; 0: no, 1: yes (ncam x 1)
mjtNum* cam_fovy; // y field-of-view (ortho ? len : deg) (ncam x 1)
mjtNum* cam_ipd; // inter-pupilary distance (ncam x 1)
int* cam_resolution; // resolution: pixels [width, height] (ncam x 2)
float* cam_sensorsize; // sensor size: length [width, height] (ncam x 2)
float* cam_intrinsic; // [focal length; principal point] (ncam x 4)
mjtNum* cam_user; // user data (ncam x nuser_cam)
// lights
+1 -1
View File
@@ -99,7 +99,7 @@ struct mjpPlugin_ {
void (*copy)(mjData* dest, const mjModel* m, const mjData* src, int instance);
// called when an mjData is being reset (required)
void (*reset)(const mjModel* m, double* plugin_state, void* plugin_data, int instance);
void (*reset)(const mjModel* m, mjtNum* plugin_state, void* plugin_data, int instance);
// called when the plugin needs to update its outputs (required)
void (*compute)(const mjModel* m, mjData* d, int instance, int capability_bit);
+764
View File
@@ -0,0 +1,764 @@
// Copyright 2024 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MUJOCO_INCLUDE_MJSPEC_H_
#define MUJOCO_INCLUDE_MJSPEC_H_
#include <stddef.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjtnum.h>
// this is a C-API
#ifdef __cplusplus
#include <string>
#include <vector>
extern "C" {
#endif
//-------------------------------- handles to strings and arrays -----------------------------------
#ifdef __cplusplus
// C++: defined to be compatible with corresponding std types
using mjString = std::string;
using mjStringVec = std::vector<std::string>;
using mjIntVec = std::vector<int>;
using mjIntVecVec = std::vector<std::vector<int>>;
using mjFloatVec = std::vector<float>;
using mjFloatVecVec = std::vector<std::vector<float>>;
using mjDoubleVec = std::vector<double>;
#else
// C: opaque types
typedef void mjString;
typedef void mjStringVec;
typedef void mjIntVec;
typedef void mjIntVecVec;
typedef void mjFloatVec;
typedef void mjFloatVecVec;
typedef void mjDoubleVec;
#endif
//-------------------------------- enum types (mjt) ------------------------------------------------
typedef enum mjtGeomInertia_ { // type of inertia inference
mjINERTIA_VOLUME, // mass distributed in the volume
mjINERTIA_SHELL, // mass distributed on the surface
} mjtGeomInertia;
typedef enum mjtBuiltin_ { // type of built-in procedural texture
mjBUILTIN_NONE = 0, // no built-in texture
mjBUILTIN_GRADIENT, // gradient: rgb1->rgb2
mjBUILTIN_CHECKER, // checker pattern: rgb1, rgb2
mjBUILTIN_FLAT // 2d: rgb1; cube: rgb1-up, rgb2-side, rgb3-down
} mjtBuiltin;
typedef enum mjtMark_ { // mark type for procedural textures
mjMARK_NONE = 0, // no mark
mjMARK_EDGE, // edges
mjMARK_CROSS, // cross
mjMARK_RANDOM // random dots
} mjtMark;
typedef enum mjtLimited_ { // type of limit specification
mjLIMITED_FALSE = 0, // not limited
mjLIMITED_TRUE, // limited
mjLIMITED_AUTO, // limited inferred from presence of range
} mjtLimited;
typedef enum mjtInertiaFromGeom_ { // whether to infer body inertias from child geoms
mjINERTIAFROMGEOM_FALSE = 0, // do not use; inertial element required
mjINERTIAFROMGEOM_TRUE, // always use; overwrite inertial element
mjINERTIAFROMGEOM_AUTO // use only if inertial element is missing
} mjtInertiaFromGeom;
typedef enum mjtOrientation_ { // type of orientation specifier
mjORIENTATION_QUAT = 0, // quaternion
mjORIENTATION_AXISANGLE, // axis and angle
mjORIENTATION_XYAXES, // x and y axes
mjORIENTATION_ZAXIS, // z axis (minimal rotation)
mjORIENTATION_EULER, // Euler angles
} mjtOrientation;
//-------------------------------- attribute structs (mjs) -----------------------------------------
typedef struct mjsElement_ { // element type, do not modify
mjtObj elemtype; // element type
} mjsElement;
typedef struct mjSpec_ { // model specification
mjsElement* element; // element type
mjString* modelname; // model name
// compiler settings
mjtByte autolimits; // infer "limited" attribute based on range
double boundmass; // enforce minimum body mass
double boundinertia; // enforce minimum body diagonal inertia
double settotalmass; // rescale masses and inertias; <=0: ignore
mjtByte balanceinertia; // automatically impose A + B >= C rule
mjtByte strippath; // automatically strip paths from mesh files
mjtByte fitaabb; // meshfit to aabb instead of inertia box
mjtByte degree; // angles in radians or degrees
char euler[3]; // sequence for euler rotations
mjString* meshdir; // mesh and hfield directory
mjString* texturedir; // texture directory
mjtByte discardvisual; // discard visual geoms in parser
mjtByte convexhull; // compute mesh convex hulls
mjtByte usethread; // use multiple threads to speed up compiler
mjtByte fusestatic; // fuse static bodies with parent
int inertiafromgeom; // use geom inertias (mjtInertiaFromGeom)
int inertiagrouprange[2]; // range of geom groups used to compute inertia
mjtByte exactmeshinertia; // if false, use old formula
mjLROpt LRopt; // options for lengthrange computation
// engine data
mjOption option; // physics options
mjVisual visual; // visual options
mjStatistic stat; // statistics override (if defined)
// sizes
size_t memory; // number of bytes in arena+stack memory
int nemax; // max number of equality constraints
int nuserdata; // number of mjtNums in userdata
int nuser_body; // number of mjtNums in body_user
int nuser_jnt; // number of mjtNums in jnt_user
int nuser_geom; // number of mjtNums in geom_user
int nuser_site; // number of mjtNums in site_user
int nuser_cam; // number of mjtNums in cam_user
int nuser_tendon; // number of mjtNums in tendon_user
int nuser_actuator; // number of mjtNums in actuator_user
int nuser_sensor; // number of mjtNums in sensor_user
int nkey; // number of keyframes
int njmax; // (deprecated) max number of constraints
int nconmax; // (deprecated) max number of detected contacts
size_t nstack; // (deprecated) number of mjtNums in mjData stack
// global data
mjString* comment; // comment at top of XML
mjString* modelfiledir; // path to model file
// other
mjtByte hasImplicitPluginElem; // already encountered an implicit plugin sensor/actuator
} mjSpec;
typedef struct mjsOrientation_ { // alternative orientation specifiers
mjtOrientation type; // active orientation specifier
double axisangle[4]; // axis and angle
double xyaxes[6]; // x and y axes
double zaxis[3]; // z axis (minimal rotation)
double euler[3]; // Euler angles
} mjsOrientation;
typedef struct mjsPlugin_ { // plugin specification
mjsElement* instance; // element type
mjString* name; // name
mjString* instance_name; // instance name
int plugin_slot; // global registered slot number of the plugin
mjtByte active; // is the plugin active
mjString* info; // message appended to compiler errors
} mjsPlugin;
typedef struct mjsBody_ { // body specification
mjsElement* element; // element type
mjString* name; // name
mjString* childclass; // childclass name
// body frame
double pos[3]; // frame position
double quat[4]; // frame orientation
mjsOrientation alt; // frame alternative orientation
// inertial frame
double mass; // mass
double ipos[3]; // inertial frame position
double iquat[4]; // inertial frame orientation
double inertia[3]; // diagonal inertia (in i-frame)
mjsOrientation ialt; // inertial frame alternative orientation
double fullinertia[6]; // non-axis-aligned inertia matrix
// other
mjtByte mocap; // is this a mocap body
double gravcomp; // gravity compensation
mjDoubleVec* userdata; // user data
mjtByte explicitinertial; // whether to save the body with explicit inertial clause
mjsPlugin plugin; // passive force plugin
mjString* info; // message appended to compiler errors
} mjsBody;
typedef struct mjsFrame_ { // frame specification
mjsElement* element; // element type
mjString* name; // name
mjString* childclass; // childclass name
double pos[3]; // position
double quat[4]; // orientation
mjsOrientation alt; // alternative orientation
mjString* info; // message appended to compiler errors
} mjsFrame;
typedef struct mjsJoint_ { // joint specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjtJoint type; // joint type
// kinematics
double pos[3]; // anchor position
double axis[3]; // joint axis
double ref; // value at reference configuration: qpos0
// stiffness
double stiffness; // stiffness coefficient
double springref; // spring reference value: qpos_spring
double springdamper[2]; // timeconst, dampratio
// limits
int limited; // does joint have limits (mjtLimited)
double range[2]; // joint limits
double margin; // margin value for joint limit detection
mjtNum solref_limit[mjNREF]; // solver reference: joint limits
mjtNum solimp_limit[mjNIMP]; // solver impedance: joint limits
int actfrclimited; // are actuator forces on joint limited (mjtLimited)
double actfrcrange[2]; // actuator force limits
// dof properties
double armature; // armature inertia (mass for slider)
double damping; // damping coefficient
double frictionloss; // friction loss
mjtNum solref_friction[mjNREF]; // solver reference: dof friction
mjtNum solimp_friction[mjNIMP]; // solver impedance: dof friction
// other
int group; // group
mjtByte actgravcomp; // is gravcomp force applied via actuators
mjDoubleVec* userdata; // user data
mjString* info; // message appended to compiler errors
} mjsJoint;
typedef struct mjsGeom_ { // geom specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // classname
mjtGeom type; // geom type
// frame, size
double pos[3]; // position
double quat[4]; // orientation
mjsOrientation alt; // alternative orientation
double fromto[6]; // alternative for capsule, cylinder, box, ellipsoid
double size[3]; // type-specific size
// contact related
int contype; // contact type
int conaffinity; // contact affinity
int condim; // contact dimensionality
int priority; // contact priority
double friction[3]; // one-sided friction coefficients: slide, roll, spin
double solmix; // solver mixing for contact pairs
mjtNum solref[mjNREF]; // solver reference
mjtNum solimp[mjNIMP]; // solver impedance
double margin; // margin for contact detection
double gap; // include in solver if dist < margin-gap
// inertia inference
double mass; // used to compute density
double density; // used to compute mass and inertia from volume or surface
mjtGeomInertia typeinertia; // selects between surface and volume inertia
// fluid forces
mjtNum fluid_ellipsoid; // whether ellipsoid-fluid model is active
mjtNum fluid_coefs[5]; // ellipsoid-fluid interaction coefs
// visual
mjString* material; // name of material
float rgba[4]; // rgba when material is omitted
int group; // group
// other
mjString* hfieldname; // heightfield attached to geom
mjString* meshname; // mesh attached to geom
double fitscale; // scale mesh uniformly
mjDoubleVec* userdata; // user data
mjsPlugin plugin; // sdf plugin
mjString* info; // message appended to compiler errors
} mjsGeom;
typedef struct mjsSite_ { // site specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// frame, size
double pos[3]; // position
double quat[4]; // orientation
mjsOrientation alt; // alternative orientation
double fromto[6]; // alternative for capsule, cylinder, box, ellipsoid
double size[3]; // geom size
// visual
mjtGeom type; // geom type
mjString* material; // name of material
int group; // group
float rgba[4]; // rgba when material is omitted
// other
mjDoubleVec* userdata; // user data
mjString* info; // message appended to compiler errors
} mjsSite;
typedef struct mjsCamera_ { // camera specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// extrinsics
double pos[3]; // position
double quat[4]; // orientation
mjsOrientation alt; // alternative orientation
mjtCamLight mode; // tracking mode
mjString* targetbody; // target body for tracking/targeting
// intrinsics
int orthographic; // is camera orthographic
double fovy; // y-field of view
double ipd; // inter-pupilary distance
float intrinsic[4]; // camera intrinsics (length)
float sensor_size[2]; // sensor size (length)
float resolution[2]; // resolution (pixel)
float focal_length[2]; // focal length (length)
float focal_pixel[2]; // focal length (pixel)
float principal_length[2]; // principal point (length)
float principal_pixel[2]; // principal point (pixel)
// other
mjDoubleVec* userdata; // user data
mjString* info; // message appended to compiler errors
} mjsCamera;
typedef struct mjsLight_ { // light specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// frame
double pos[3]; // position
double dir[3]; // direction
mjtCamLight mode; // tracking mode
mjString* targetbody; // target body for targeting
// intrinsics
mjtByte active; // is light active
mjtByte directional; // is light directional or spot
mjtByte castshadow; // does light cast shadows
double bulbradius; // bulb radius, for soft shadows
float attenuation[3]; // OpenGL attenuation (quadratic model)
float cutoff; // OpenGL cutoff
float exponent; // OpenGL exponent
float ambient[3]; // ambient color
float diffuse[3]; // diffuse color
float specular[3]; // specular color
// other
mjString* info; // message appended to compiler errorsx
} mjsLight;
typedef struct mjsFlex_ { // flex specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// contact properties
int contype; // contact type
int conaffinity; // contact affinity
int condim; // contact dimensionality
int priority; // contact priority
double friction[3]; // one-sided friction coefficients: slide, roll, spin
double solmix; // solver mixing for contact pairs
mjtNum solref[mjNREF]; // solver reference
mjtNum solimp[mjNIMP]; // solver impedance
double margin; // margin for contact detection
double gap; // include in solver if dist<margin-gap
// other properties
int dim; // element dimensionality
double radius; // radius around primitive element
mjtByte internal; // enable internal collisions
mjtByte flatskin; // render flex skin with flat shading
int selfcollide; // mode for flex self colllision
int activelayers; // number of active element layers in 3D
int group; // group for visualizatioh
double edgestiffness; // edge stiffness
double edgedamping; // edge damping
float rgba[4]; // rgba when material is omitted
mjString* material; // name of material used for rendering
// mesh properties
mjStringVec* vertbody; // vertex body names
mjDoubleVec* vert; // vertex positions
mjIntVec* elem; // element vertex ids
mjFloatVec* texcoord; // vertex texture coordinates
// other
mjString* info; // message appended to compiler errors
} mjsFlex;
typedef struct mjsMesh_ { // mesh specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjString* content_type; // content type of file
mjString* file; // mesh file
double refpos[3]; // reference position
double refquat[4]; // reference orientation
double scale[3]; // rescale mesh
mjtByte smoothnormal; // do not exclude large-angle faces from normals
int maxhullvert; // maximum vertex count for the convex hull
mjFloatVec* uservert; // user vertex data
mjFloatVec* usernormal; // user normal data
mjFloatVec* usertexcoord; // user texcoord data
mjIntVec* userface; // user vertex indices
mjIntVec* userfacenormal; // user normal indices
mjIntVec* userfacetexcoord; // user texcoord indices
mjsPlugin plugin; // sdf plugin
mjString* info; // message appended to compiler errors
} mjsMesh;
typedef struct mjsHField_ { // height field specification
mjsElement* element; // element type
mjString* name; // name
mjString* content_type; // content type of file
mjString* file; // file: (nrow, ncol, [elevation data])
double size[4]; // hfield size (ignore referencing geom size)
int nrow; // number of rows
int ncol; // number of columns
mjFloatVec* userdata; // user-provided elevation data
mjString* info; // message appended to compiler errors
} mjsHField;
typedef struct mjsSkin_ { // skin specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjString* file; // skin file
mjString* material; // name of material used for rendering
float rgba[4]; // rgba when material is omitted
float inflate; // inflate in normal direction
int group; // group for visualization
// mesh
mjFloatVec* vert; // vertex positions
mjFloatVec* texcoord; // texture coordinates
mjIntVec* face; // faces
// skin
mjStringVec* bodyname; // body names
mjFloatVec* bindpos; // bind pos
mjFloatVec* bindquat; // bind quat
mjIntVecVec* vertid; // vertex ids
mjFloatVecVec* vertweight; // vertex weights
// other
mjString* info; // message appended to compiler errors
} mjsSkin;
typedef struct mjsTexture_ { // texture specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjtTexture type; // texture type
// method 1: builtin
int builtin; // builtin type (mjtBuiltin)
int mark; // mark type (mjtMark)
double rgb1[3]; // first color for builtin
double rgb2[3]; // second color for builtin
double markrgb[3]; // mark color
double random; // probability of random dots
int height; // height in pixels (square for cube and skybox)
int width; // width in pixels
// method 2: single file
mjString* content_type; // content type of file
mjString* file; // png file to load; use for all sides of cube
int gridsize[2]; // size of grid for composite file; (1,1)-repeat
char gridlayout[13]; // row-major: L,R,F,B,U,D for faces; . for unused
// method 3: separate files
mjStringVec* cubefiles; // different file for each side of the cube
// flip options
mjtByte hflip; // horizontal flip
mjtByte vflip; // vertical flip
// other
mjString* info; // message appended to compiler errors
} mjsTexture;
typedef struct mjsMaterial_ { // material specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjString* texture; // name of texture (empty: none)
mjtByte texuniform; // make texture cube uniform
float texrepeat[2]; // texture repetition for 2D mapping
float emission; // emission
float specular; // specular
float shininess; // shininess
float reflectance; // reflectance
float metallic; // metallic
float roughness; // roughness
float rgba[4]; // rgba
mjString* info; // message appended to compiler errors
} mjsMaterial;
typedef struct mjsPair_ { // pair specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjString* geomname1; // name of geom 1
mjString* geomname2; // name of geom 2
// optional parameters: computed from geoms if not set by user
int condim; // contact dimensionality
mjtNum solref[mjNREF]; // solver reference, normal direction
mjtNum solreffriction[mjNREF]; // solver reference, frictional directions
mjtNum solimp[mjNIMP]; // solver impedance
double margin; // margin for contact detection
double gap; // include in solver if dist<margin-gap
double friction[5]; // full contact friction
mjString* info; // message appended to errors
} mjsPair;
typedef struct mjsExclude_ { // exclude specification
mjsElement* element; // element type
mjString* name; // name
mjString* bodyname1; // name of geom 1
mjString* bodyname2; // name of geom 2
mjString* info; // message appended to errors
} mjsExclude;
typedef struct mjsEquality_ { // equality specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
mjtEq type; // constraint type
double data[mjNEQDATA]; // type-dependent data
mjtByte active; // is equality initially active
mjString* name1; // name of object 1
mjString* name2; // name of object 2
mjtNum solref[mjNREF]; // solver reference
mjtNum solimp[mjNIMP]; // solver impedance
mjString* info; // message appended to errors
} mjsEquality;
typedef struct mjsTendon_ { // tendon specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// stiffness, damping, friction
double stiffness; // stiffness coefficient
double springlength[2]; // spring resting length; {-1, -1}: use qpos_spring
double damping; // damping coefficient
double frictionloss; // friction loss
mjtNum solref_friction[mjNREF]; // solver reference: tendon friction
mjtNum solimp_friction[mjNIMP]; // solver impedance: tendon friction
// length range
int limited; // does tendon have limits (mjtLimited)
double range[2]; // length limits
double margin; // margin value for tendon limit detection
mjtNum solref_limit[mjNREF]; // solver reference: tendon limits
mjtNum solimp_limit[mjNIMP]; // solver impedance: tendon limits
// visual
mjString* material; // name of material for rendering
double width; // width for rendering
float rgba[4]; // rgba when material is omitted
int group; // group
// other
mjDoubleVec* userdata; // user data
mjString* info; // message appended to errors
} mjsTendon;
typedef struct mjsWrap_ { // wrapping object specification
mjsElement* element; // element type
mjString* info; // message appended to errors
} mjsWrap;
typedef struct mjsActuator_ { // actuator specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// gain, bias
mjtGain gaintype; // gain type
double gainprm[mjNGAIN]; // gain parameters
mjtBias biastype; // bias type
double biasprm[mjNGAIN]; // bias parameters
// activation state
mjtDyn dyntype; // dynamics type
double dynprm[mjNDYN]; // dynamics parameters
int actdim; // number of activation variables
int plugin_actdim; // actuator state size for plugins
mjtByte actearly; // apply next activations to qfrc
// transmission
mjtTrn trntype; // transmission type
double gear[6]; // length and transmitted force scaling
mjString* target; // name of transmission target
mjString* refsite; // reference site, for site transmission
mjString* slidersite; // site defining cylinder, for slider-crank
double cranklength; // crank length, for slider-crank
double lengthrange[2]; // transmission length range
double inheritrange; // automatic range setting for position and intvelocity
// input/output clamping
int ctrllimited; // are control limits defined (mjtLimited)
double ctrlrange[2]; // control range
int forcelimited; // are force limits defined (mjtLimited)
double forcerange[2]; // force range
int actlimited; // are activation limits defined (mjtLimited)
double actrange[2]; // activation range
// other
int group; // group
mjDoubleVec* userdata; // user data
mjsPlugin plugin; // actuator plugin
mjString* info; // message appended to compiler errors
} mjsActuator;
typedef struct mjsSensor_ { // sensor specification
mjsElement* element; // element type
mjString* name; // name
mjString* classname; // class name
// sensor definition
mjtSensor type; // type of sensor
mjtObj objtype; // type of sensorized object
mjString* objname; // name of sensorized object
mjtObj reftype; // type of referenced object
mjString* refname; // name of referenced object
// user-defined sensors
mjtDataType datatype; // data type for sensor measurement
mjtStage needstage; // compute stage needed to simulate sensor
int dim; // number of scalar outputs
// output post-processing
double cutoff; // cutoff for real and positive datatypes
double noise; // noise stdev
// other
mjDoubleVec* userdata; // user data
mjsPlugin plugin; // sensor plugin
mjString* info; // message appended to compiler errors
} mjsSensor;
typedef struct mjsNumeric_ { // custom numeric field specification
mjsElement* element; // element type
mjString* name; // name
mjDoubleVec* data; // initialization data
int size; // array size, can be bigger than data size
mjString* info; // message appended to compiler errors
} mjsNumeric;
typedef struct mjsText_ { // custom text specification
mjsElement* element; // element type
mjString* name; // name
mjString* data; // text string
mjString* info; // message appended to compiler errors
} mjsText;
typedef struct mjsTuple_ { // tuple specification
mjsElement* element; // element type
mjString* name; // name
mjIntVec* objtype; // object types
mjStringVec* objname; // object names
mjDoubleVec* objprm; // object parameters
mjString* info; // message appended to compiler errors
} mjsTuple;
typedef struct mjsKey_ { // keyframe specification
mjsElement* element; // element type
mjString* name; // name
double time; // time
mjDoubleVec* qpos; // qpos
mjDoubleVec* qvel; // qvel
mjDoubleVec* act; // act
mjDoubleVec* mpos; // mocap pos
mjDoubleVec* mquat; // mocap quat
mjDoubleVec* ctrl; // ctrl
mjString* info; // message appended to compiler errors
} mjsKey;
typedef struct mjsDefault_ { // default specification
mjsElement* element; // element type
mjString* name; // class name
mjsJoint* joint; // joint defaults
mjsGeom* geom; // geom defaults
mjsSite* site; // site defaults
mjsCamera* camera; // camera defaults
mjsLight* light; // light defaults
mjsFlex* flex; // flex defaults
mjsMesh* mesh; // mesh defaults
mjsMaterial* material; // material defaults
mjsPair* pair; // pair defaults
mjsEquality* equality; // equality defaults
mjsTendon* tendon; // tendon defaults
mjsActuator* actuator; // actuator defaults
} mjsDefault;
#ifdef __cplusplus
}
#endif
#endif // MUJOCO_INCLUDE_MJSPEC_H_
+9 -1
View File
@@ -192,6 +192,9 @@ struct mjvCamera_ { // abstract camera
mjtNum distance; // distance to lookat point or tracked body
mjtNum azimuth; // camera azimuth (deg)
mjtNum elevation; // camera elevation (deg)
// orthographic / perspective
int orthographic; // 0: perspective; 1: orthographic
};
typedef struct mjvCamera_ mjvCamera;
@@ -211,6 +214,9 @@ struct mjvGLCamera_ { // OpenGL camera
float frustum_top; // top
float frustum_near; // near
float frustum_far; // far
// orthographic / perspective
int orthographic; // 0: perspective; 1: orthographic
};
typedef struct mjvGLCamera_ mjvGLCamera;
@@ -487,10 +493,12 @@ struct mjvSceneState_ {
mjtNum* site_size;
float* site_rgba;
int* cam_orthographic;
mjtNum* cam_fovy;
mjtNum* cam_ipd;
float* cam_intrinsic;
int* cam_resolution;
float* cam_sensorsize;
float* cam_intrinsic;
mjtByte* light_directional;
mjtByte* light_castshadow;
+4 -3
View File
@@ -277,16 +277,17 @@
X ( int, cam_mode, ncam, 1 ) \
X ( int, cam_bodyid, ncam, 1 ) \
X ( int, cam_targetbodyid, ncam, 1 ) \
X ( int, cam_resolution, ncam, 2 ) \
XMJV( float, cam_sensorsize, ncam, 2 ) \
XMJV( float, cam_intrinsic, ncam, 4 ) \
X ( mjtNum, cam_pos, ncam, 3 ) \
X ( mjtNum, cam_quat, ncam, 4 ) \
X ( mjtNum, cam_poscom0, ncam, 3 ) \
X ( mjtNum, cam_pos0, ncam, 3 ) \
X ( mjtNum, cam_mat0, ncam, 9 ) \
XMJV( int, cam_orthographic, ncam, 1 ) \
XMJV( mjtNum, cam_fovy, ncam, 1 ) \
XMJV( mjtNum, cam_ipd, ncam, 1 ) \
XMJV( int, cam_resolution, ncam, 2 ) \
XMJV( float, cam_sensorsize, ncam, 2 ) \
XMJV( float, cam_intrinsic, ncam, 4 ) \
X ( mjtNum, cam_user, ncam, MJ_M(nuser_cam) ) \
X ( int, light_mode, nlight, 1 ) \
X ( int, light_bodyid, nlight, 1 ) \
+363 -23
View File
@@ -15,16 +15,8 @@
#ifndef MUJOCO_MUJOCO_H_
#define MUJOCO_MUJOCO_H_
#include <mujoco/mjexport.h>
// this is a C-API
#ifdef __cplusplus
extern "C" {
#endif
// header version; should match the library version as returned by mj_version()
#define mjVERSION_HEADER 316
#define mjVERSION_HEADER 317
// needed to define size_t, fabs and log10
#include <stdlib.h>
@@ -32,15 +24,21 @@ extern "C" {
// type definitions
#include <mujoco/mjdata.h>
#include <mujoco/mjexport.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjmacro.h>
#include <mujoco/mjplugin.h>
#include <mujoco/mjrender.h>
#include <mujoco/mjspec.h>
#include <mujoco/mjthread.h>
#include <mujoco/mjtnum.h>
#include <mujoco/mjui.h>
#include <mujoco/mjvisualize.h>
// this is a C-API
#ifdef __cplusplus
extern "C" {
#endif
// user error and memory handlers
MJAPI extern void (*mju_user_error)(const char*);
@@ -97,6 +95,7 @@ MJAPI void mj_deleteVFS(mjVFS* vfs);
// deprecated: use mj_copyBufferVFS.
MJAPI int mj_makeEmptyFileVFS(mjVFS* vfs, const char* filename, int filesize);
//---------------------------------- Parse and compile ---------------------------------------------
// Parse XML file in MJCF or URDF format, compile it, return low-level model.
@@ -104,6 +103,18 @@ MJAPI int mj_makeEmptyFileVFS(mjVFS* vfs, const char* filename, int filesize);
// If error is not NULL, it must have size error_sz.
MJAPI mjModel* mj_loadXML(const char* filename, const mjVFS* vfs, char* error, int error_sz);
// Parse spec from XML file.
MJAPI mjSpec* mj_parseXML(const char* filename, const mjVFS* vfs, char* error, int error_sz);
// Parse spec from XML string.
MJAPI mjSpec* mj_parseXMLString(const char* xml, const mjVFS* vfs, char* error, int error_sz);
// Compile spec to model.
MJAPI mjModel* mj_compile(mjSpec* s, const mjVFS* vfs);
// Recompile spec to model, preserving the state.
MJAPI void mj_recompile(mjSpec* s, const mjVFS* vfs, mjModel* m, mjData* d);
// Update XML data structures with info from low-level model, save as MJCF.
// If error is not NULL, it must have size error_sz.
MJAPI int mj_saveLastXML(const char* filename, const mjModel* m, char* error, int error_sz);
@@ -111,9 +122,14 @@ MJAPI int mj_saveLastXML(const char* filename, const mjModel* m, char* error, in
// Free last XML model if loaded. Called internally at each load.
MJAPI void mj_freeLastXML(void);
// Print internal XML schema as plain text or HTML, with style-padding or &nbsp;.
MJAPI int mj_printSchema(const char* filename, char* buffer, int buffer_sz,
int flg_html, int flg_pad);
// Copy (possibly modified) model fields back into spec.
MJAPI void mj_copyBack(mjSpec* s, const mjModel* m);
// Save spec to XML string, return 1 on success, 0 otherwise.
MJAPI int mj_saveXMLString(const mjSpec* s, char* xml, int xml_sz, char* error, int error_sz);
// Save spec to XML file, return 1 on success, 0 otherwise.
MJAPI int mj_saveXML(const mjSpec* s, const char* filename, char* error, int error_sz);
//---------------------------------- Main simulation -----------------------------------------------
@@ -221,6 +237,15 @@ MJAPI void mj_setConst(mjModel* m, mjData* d);
MJAPI int mj_setLengthRange(mjModel* m, mjData* d, int index,
const mjLROpt* opt, char* error, int error_sz);
// Create empty spec.
MJAPI mjSpec* mj_makeSpec(void);
// Copy spec.
MJAPI mjSpec* mj_copySpec(const mjSpec* s);
// Free memory allocation in mjSpec.
MJAPI void mj_deleteSpec(mjSpec* s);
//---------------------------------- Printing ------------------------------------------------------
@@ -246,6 +271,10 @@ MJAPI void mju_printMat(const mjtNum* mat, int nr, int nc);
MJAPI void mju_printMatSparse(const mjtNum* mat, int nr,
const int* rownnz, const int* rowadr, const int* colind);
// Print internal XML schema as plain text or HTML, with style-padding or &nbsp;.
MJAPI int mj_printSchema(const char* filename, char* buffer, int buffer_sz,
int flg_html, int flg_pad);
//---------------------------------- Components ----------------------------------------------------
@@ -389,6 +418,9 @@ MJAPI void mj_getState(const mjModel* m, const mjData* d, mjtNum* state, unsigne
// Set state.
MJAPI void mj_setState(const mjModel* m, mjData* d, const mjtNum* state, unsigned int spec);
// Copy current state to the k-th model keyframe.
MJAPI void mj_setKeyframe(mjModel* m, const mjData* d, int k);
// Add contact to d->contact list; return 0 if success; 1 if buffer full.
MJAPI int mj_addContact(const mjModel* m, mjData* d, const mjContact* con);
@@ -510,7 +542,7 @@ MJAPI int mj_version(void);
MJAPI const char* mj_versionString(void);
//---------------------------------- Ray collisions ------------------------------------------------
//---------------------------------- Ray casting ---------------------------------------------------
// Intersect multiple rays emanating from a single point.
// Similar semantics to mj_ray, but vec is an array of (nray x 3) directions.
@@ -852,6 +884,12 @@ MJAPI void mj_warning(mjData* d, int warning, int info);
// Write [datetime, type: message] to MUJOCO_LOG.TXT.
MJAPI void mju_writeLog(const char* type, const char* msg);
// Get compiler error message from spec.
MJAPI const char* mjs_getError(mjSpec* s);
// Return 1 if compiler error is a warning.
MJAPI int mjs_isWarning(mjSpec* s);
//---------------------------------- Standard math -------------------------------------------------
@@ -932,10 +970,16 @@ MJAPI mjtNum mju_dot3(const mjtNum vec1[3], const mjtNum vec2[3]);
// Return Cartesian distance between 3D vectors pos1 and pos2.
MJAPI mjtNum mju_dist3(const mjtNum pos1[3], const mjtNum pos2[3]);
// Multiply vector by 3D rotation matrix: res = mat * vec.
// Multiply 3-by-3 matrix by vector: res = mat * vec.
MJAPI void mju_mulMatVec3(mjtNum res[3], const mjtNum mat[9], const mjtNum vec[3]);
// Multiply transposed 3-by-3 matrix by vector: res = mat' * vec.
MJAPI void mju_mulMatTVec3(mjtNum res[3], const mjtNum mat[9], const mjtNum vec[3]);
// Deprecated, use mju_mulMatVec3(res, mat, vec).
MJAPI void mju_rotVecMat(mjtNum res[3], const mjtNum vec[3], const mjtNum mat[9]);
// Multiply vector by transposed 3D rotation matrix: res = mat' * vec.
// Deprecated, use mju_mulMatTVec3(res, mat, vec).
MJAPI void mju_rotVecMatT(mjtNum res[3], const mjtNum vec[3], const mjtNum mat[9]);
// Compute cross-product: res = cross(a, b).
@@ -1037,6 +1081,7 @@ MJAPI void mju_transformSpatial(mjtNum res[6], const mjtNum vec[6], int flg_forc
const mjtNum newpos[3], const mjtNum oldpos[3],
const mjtNum rotnew2old[9]);
//---------------------------------- Quaternions ---------------------------------------------------
// Rotate vector by quaternion.
@@ -1079,6 +1124,7 @@ MJAPI void mju_quatZ2Vec(mjtNum quat[4], const mjtNum vec[3]);
// seq[0,1,2] must be in 'xyzXYZ', lower/upper-case mean intrinsic/extrinsic rotations.
MJAPI void mju_euler2Quat(mjtNum quat[4], const mjtNum euler[3], const char* seq);
//---------------------------------- Poses ---------------------------------------------------------
// Multiply two poses.
@@ -1166,7 +1212,8 @@ MJAPI int mju_boxQP(mjtNum* res, mjtNum* R, int* index, const mjtNum* H, const m
MJAPI void mju_boxQPmalloc(mjtNum** res, mjtNum** R, int** index, mjtNum** H, mjtNum** g, int n,
mjtNum** lower, mjtNum** upper);
//---------------------- Miscellaneous -------------------------------------------------------------
//---------------------------------- Miscellaneous -------------------------------------------------
// Muscle active force, prm = (range[2], force, scale, lmin, lmax, vmax, fpmax, fvmax).
MJAPI mjtNum mju_muscleGain(mjtNum len, mjtNum vel, const mjtNum lengthrange[2],
@@ -1252,7 +1299,7 @@ MJAPI char* mju_strncpy(char *dst, const char *src, int n);
MJAPI mjtNum mju_sigmoid(mjtNum x);
//---------------------- Derivatives ---------------------------------------------------------------
//---------------------------------- Derivatives ---------------------------------------------------
// Finite differenced transition matrices (control theory notation)
// d(x_next) = A*dx + B*du
@@ -1292,7 +1339,8 @@ MJAPI void mjd_subQuat(const mjtNum qa[4], const mjtNum qb[4], mjtNum Da[9], mjt
MJAPI void mjd_quatIntegrate(const mjtNum vel[3], mjtNum scale,
mjtNum Dquat[9], mjtNum Dvel[9], mjtNum Dscale[3]);
//---------------------- Plugins -------------------------------------------------------------------
//---------------------------------- Plugins -------------------------------------------------------
// Set default plugin definition.
MJAPI void mjp_defaultPlugin(mjpPlugin* plugin);
@@ -1333,7 +1381,8 @@ MJAPI const mjpResourceProvider* mjp_getResourceProvider(const char* resource_na
// If invalid slot number, return NULL.
MJAPI const mjpResourceProvider* mjp_getResourceProviderAtSlot(int slot);
//---------------------- Thread -------------------------------------------------------------------
//---------------------------------- Threads -------------------------------------------------------
// Create a thread pool with the specified number of threads running.
MJAPI mjThreadPool* mju_threadPoolCreate(size_t number_of_threads);
@@ -1353,10 +1402,301 @@ MJAPI void mju_defaultTask(mjTask* task);
// Wait for a task to complete.
MJAPI void mju_taskJoin(mjTask* task);
//---------------------- Sanitizer instrumentation helpers -----------------------------------------
//
// Most MuJoCo users can ignore these functions, the following comments are aimed primarily at
// MuJoCo developers.
//---------------------------------- Attachment ----------------------------------------------------
// Attach child body to a parent frame, return 0 on success.
MJAPI int mjs_attachBody(mjsFrame* parent, const mjsBody* child,
const char* prefix, const char* suffix);
// Attach child frame to a parent body, return 0 on success.
MJAPI int mjs_attachFrame(mjsBody* parent, const mjsFrame* child,
const char* prefix, const char* suffix);
// Detach body from mjSpec, remove all references and delete the body, return 0 on success.
MJAPI int mjs_detachBody(mjSpec* s, mjsBody* b);
//---------------------------------- Tree elements -------------------------------------------------
// Add child body to body, return child.
MJAPI mjsBody* mjs_addBody(mjsBody* body, mjsDefault* def);
// Add site to body, return site spec.
MJAPI mjsSite* mjs_addSite(mjsBody* body, mjsDefault* def);
// Add joint to body.
MJAPI mjsJoint* mjs_addJoint(mjsBody* body, mjsDefault* def);
// Add freejoint to body.
MJAPI mjsJoint* mjs_addFreeJoint(mjsBody* body);
// Add geom to body.
MJAPI mjsGeom* mjs_addGeom(mjsBody* body, mjsDefault* def);
// Add camera to body.
MJAPI mjsCamera* mjs_addCamera(mjsBody* body, mjsDefault* def);
// Add light to body.
MJAPI mjsLight* mjs_addLight(mjsBody* body, mjsDefault* def);
// Add frame to body.
MJAPI mjsFrame* mjs_addFrame(mjsBody* body, mjsFrame* parentframe);
// Delete object corresponding to the given element.
MJAPI void mjs_delete(mjsElement* element);
//---------------------------------- Non-tree elements ---------------------------------------------
// Add actuator.
MJAPI mjsActuator* mjs_addActuator(mjSpec* s, mjsDefault* def);
// Add sensor.
MJAPI mjsSensor* mjs_addSensor(mjSpec* s);
// Add flex.
MJAPI mjsFlex* mjs_addFlex(mjSpec* s);
// Add contact pair.
MJAPI mjsPair* mjs_addPair(mjSpec* s, mjsDefault* def);
// Add excluded body pair.
MJAPI mjsExclude* mjs_addExclude(mjSpec* s);
// Add equality.
MJAPI mjsEquality* mjs_addEquality(mjSpec* s, mjsDefault* def);
// Add tendon.
MJAPI mjsTendon* mjs_addTendon(mjSpec* s, mjsDefault* def);
// Wrap site using tendon.
MJAPI mjsWrap* mjs_wrapSite(mjsTendon* tendon, const char* name);
// Wrap geom using tendon.
MJAPI mjsWrap* mjs_wrapGeom(mjsTendon* tendon, const char* name, const char* sidesite);
// Wrap joint using tendon.
MJAPI mjsWrap* mjs_wrapJoint(mjsTendon* tendon, const char* name, double coef);
// Wrap pulley using tendon.
MJAPI mjsWrap* mjs_wrapPulley(mjsTendon* tendon, double divisor);
// Add numeric.
MJAPI mjsNumeric* mjs_addNumeric(mjSpec* s);
// Add text.
MJAPI mjsText* mjs_addText(mjSpec* s);
// Add tuple.
MJAPI mjsTuple* mjs_addTuple(mjSpec* s);
// Add keyframe.
MJAPI mjsKey* mjs_addKey(mjSpec* s);
// Add plugin.
MJAPI mjsPlugin* mjs_addPlugin(mjSpec* s);
// Add default.
MJAPI mjsDefault* mjs_addDefault(mjSpec* s, const char* classname, int parentid, int* id);
//---------------------------------- Assets --------------------------------------------------------
// Add mesh.
MJAPI mjsMesh* mjs_addMesh(mjSpec* s, mjsDefault* def);
// Add height field.
MJAPI mjsHField* mjs_addHField(mjSpec* s);
// Add skin.
MJAPI mjsSkin* mjs_addSkin(mjSpec* s);
// Add texture.
MJAPI mjsTexture* mjs_addTexture(mjSpec* s);
// Add material.
MJAPI mjsMaterial* mjs_addMaterial(mjSpec* s, mjsDefault* def);
//---------------------------------- Find and get utilities ----------------------------------------
// Get spec from body.
MJAPI mjSpec* mjs_getSpec(mjsBody* body);
// Find body in model by name.
MJAPI mjsBody* mjs_findBody(mjSpec* s, const char* name);
// Find child body by name.
MJAPI mjsBody* mjs_findChild(mjsBody* body, const char* name);
// Find mesh by name.
MJAPI mjsMesh* mjs_findMesh(mjSpec* s, const char* name);
// Find frame by name.
MJAPI mjsFrame* mjs_findFrame(mjSpec* s, const char* name);
// Get default corresponding to an element.
MJAPI mjsDefault* mjs_getDefault(mjsElement* element);
// Find default in model by class name.
MJAPI mjsDefault* mjs_findDefault(mjSpec* s, const char* classname);
// Get global default from model.
MJAPI mjsDefault* mjs_getSpecDefault(mjSpec* s);
// Get element id.
MJAPI int mjs_getId(mjsElement* element);
// Return body's first child of given type.
MJAPI mjsElement* mjs_firstChild(mjsBody* body, mjtObj type);
// Return body's next child of the same type; return NULL if child is last.
MJAPI mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child);
//---------------------------------- Attribute setters ---------------------------------------------
// Copy text to string.
MJAPI void mjs_setString(mjString* dest, const char* text);
// Split text to entries and copy to string vector.
MJAPI void mjs_setStringVec(mjStringVec* dest, const char* text);
// Set entry in string vector.
MJAPI mjtByte mjs_setInStringVec(mjStringVec* dest, int i, const char* text);
// Append text entry to string vector.
MJAPI void mjs_appendString(mjStringVec* dest, const char* text);
// Copy int array to vector.
MJAPI void mjs_setInt(mjIntVec* dest, const int* array, int size);
// Append int array to vector of arrays.
MJAPI void mjs_appendIntVec(mjIntVecVec* dest, const int* array, int size);
// Copy float array to vector.
MJAPI void mjs_setFloat(mjFloatVec* dest, const float* array, int size);
// Append float array to vector of arrays.
MJAPI void mjs_appendFloatVec(mjFloatVecVec* dest, const float* array, int size);
// Copy double array to vector.
MJAPI void mjs_setDouble(mjDoubleVec* dest, const double* array, int size);
// Set plugin attributes.
MJAPI void mjs_setPluginAttributes(mjsPlugin* plugin, void* attributes);
//---------------------------------- Attribute getters ---------------------------------------------
// Get string contents.
MJAPI const char* mjs_getString(const mjString* source);
// Get double array contents and optionally its size.
MJAPI const double* mjs_getDouble(const mjDoubleVec* source, int* size);
//---------------------------------- Spec utilities ------------------------------------------------
// Set active plugins.
MJAPI void mjs_setActivePlugins(mjSpec* s, void* activeplugins);
// Set element's default.
MJAPI void mjs_setDefault(mjsElement* element, mjsDefault* def);
// Set element's enlcosing frame.
MJAPI void mjs_setFrame(mjsElement* dest, mjsFrame* frame);
// Resolve alternative orientations to quat, return error if any.
MJAPI const char* mjs_resolveOrientation(double quat[4], mjtByte degree, const char* sequence,
const mjsOrientation* orientation);
// Compute quat and diag inertia from full inertia matrix, return error if any.
MJAPI const char* mjs_fullInertia(double quat[4], double inertia[3], const double fullinertia[6]);
//---------------------------------- Element initialization ---------------------------------------
// Default spec attributes.
MJAPI void mjs_defaultSpec(mjSpec* spec);
// Default orientation attributes.
MJAPI void mjs_defaultOrientation(mjsOrientation* orient);
// Default body attributes.
MJAPI void mjs_defaultBody(mjsBody* body);
// Default frame attributes.
MJAPI void mjs_defaultFrame(mjsFrame* frame);
// Default joint attributes.
MJAPI void mjs_defaultJoint(mjsJoint* joint);
// Default geom attributes.
MJAPI void mjs_defaultGeom(mjsGeom* geom);
// Default site attributes.
MJAPI void mjs_defaultSite(mjsSite* site);
// Default camera attributes.
MJAPI void mjs_defaultCamera(mjsCamera* camera);
// Default light attributes.
MJAPI void mjs_defaultLight(mjsLight* light);
// Default flex attributes.
MJAPI void mjs_defaultFlex(mjsFlex* flex);
// Default mesh attributes.
MJAPI void mjs_defaultMesh(mjsMesh* mesh);
// Default height field attributes.
MJAPI void mjs_defaultHField(mjsHField* hfield);
// Default skin attributes.
MJAPI void mjs_defaultSkin(mjsSkin* skin);
// Default texture attributes.
MJAPI void mjs_defaultTexture(mjsTexture* texture);
// Default material attributes.
MJAPI void mjs_defaultMaterial(mjsMaterial* material);
// Default pair attributes.
MJAPI void mjs_defaultPair(mjsPair* pair);
// Default equality attributes.
MJAPI void mjs_defaultEquality(mjsEquality* equality);
// Default tendon attributes.
MJAPI void mjs_defaultTendon(mjsTendon* tendon);
// Default actuator attributes.
MJAPI void mjs_defaultActuator(mjsActuator* actuator);
// Default sensor attributes.
MJAPI void mjs_defaultSensor(mjsSensor* sensor);
// Default numeric attributes.
MJAPI void mjs_defaultNumeric(mjsNumeric* numeric);
// Default text attributes.
MJAPI void mjs_defaultText(mjsText* text);
// Default tuple attributes.
MJAPI void mjs_defaultTuple(mjsTuple* tuple);
// Default keyframe attributes.
MJAPI void mjs_defaultKey(mjsKey* key);
// Default plugin attributes.
MJAPI void mjs_defaultPlugin(mjsPlugin* plugin);
//---------------------------------- Sanitizer instrumentation -------------------------------------
// Most users can ignore these functions, the following comments are primarily for developers.
//
// When built and run under address sanitizer (asan), mj_markStack and mj_freeStack are instrumented
// to detect leakage of mjData stack frames. When the compiler inlines several callees that call
+1 -1
View File
@@ -123,7 +123,7 @@ class MjStructVisitor:
"""Makes a Decl object from a Clang AST RecordDecl node."""
name = f"{node['tagUsed']} {node['name']}" if 'name' in node else ''
fields = []
for child in node['inner']:
for child in node.get('inner', ()):
child_kind = child.get('kind')
if child_kind == 'FieldDecl':
fields.append(self._make_field(child))
+63
View File
@@ -686,6 +686,69 @@ ENUMS: Mapping[str, EnumDecl] = dict([
('mjFONT_BIG', 2),
]),
)),
('mjtGeomInertia',
EnumDecl(
name='mjtGeomInertia',
declname='enum mjtGeomInertia_',
values=dict([
('mjINERTIA_VOLUME', 0),
('mjINERTIA_SHELL', 1),
]),
)),
('mjtBuiltin',
EnumDecl(
name='mjtBuiltin',
declname='enum mjtBuiltin_',
values=dict([
('mjBUILTIN_NONE', 0),
('mjBUILTIN_GRADIENT', 1),
('mjBUILTIN_CHECKER', 2),
('mjBUILTIN_FLAT', 3),
]),
)),
('mjtMark',
EnumDecl(
name='mjtMark',
declname='enum mjtMark_',
values=dict([
('mjMARK_NONE', 0),
('mjMARK_EDGE', 1),
('mjMARK_CROSS', 2),
('mjMARK_RANDOM', 3),
]),
)),
('mjtLimited',
EnumDecl(
name='mjtLimited',
declname='enum mjtLimited_',
values=dict([
('mjLIMITED_FALSE', 0),
('mjLIMITED_TRUE', 1),
('mjLIMITED_AUTO', 2),
]),
)),
('mjtInertiaFromGeom',
EnumDecl(
name='mjtInertiaFromGeom',
declname='enum mjtInertiaFromGeom_',
values=dict([
('mjINERTIAFROMGEOM_FALSE', 0),
('mjINERTIAFROMGEOM_TRUE', 1),
('mjINERTIAFROMGEOM_AUTO', 2),
]),
)),
('mjtOrientation',
EnumDecl(
name='mjtOrientation',
declname='enum mjtOrientation_',
values=dict([
('mjORIENTATION_QUAT', 0),
('mjORIENTATION_AXISANGLE', 1),
('mjORIENTATION_XYAXES', 2),
('mjORIENTATION_ZAXIS', 3),
('mjORIENTATION_EULER', 4),
]),
)),
('mjtButton',
EnumDecl(
name='mjtButton',
+2022 -15
View File
File diff suppressed because it is too large Load Diff
+3052 -20
View File
File diff suppressed because it is too large Load Diff
+4 -1
View File
@@ -239,7 +239,8 @@ def plane_convex(plane: GeomInfo, convex: ConvexInfo) -> Collision:
plane_pos = convex.mat.T @ (plane.pos - convex.pos)
n = convex.mat.T @ plane.mat[:, 2]
support = (plane_pos - vert) @ n
idx = _manifold_points(vert, support > jp.maximum(0, support.max() - 1e-4), n)
# search for manifold points within a 1mm skin depth
idx = _manifold_points(vert, support > jp.maximum(0, support.max() - 1e-3), n)
pos = vert[idx]
# convert to world frame
@@ -970,6 +971,7 @@ def _box_box(b1: ConvexInfo, b2: ConvexInfo) -> Collision:
# Go back to world frame.
pos = b2.pos + pos @ b2.mat.T
n = normal @ b2.mat.T
dist = jp.where(jp.isinf(dist), jp.finfo(float).max, dist)
return dist, pos, n
@@ -1029,6 +1031,7 @@ def _convex_convex(c1: ConvexInfo, c2: ConvexInfo) -> Collision:
pos = c2.pos + pos @ c2.mat.T
n = normal @ c2.mat.T
n = -n if swapped else n
dist = jp.where(jp.isinf(dist), jp.finfo(float).max, dist)
return dist, pos, n
+240 -187
View File
@@ -24,6 +24,7 @@ from mujoco.mjx._src import math
from mujoco.mjx._src import support
# pylint: disable=g-importing-member
from mujoco.mjx._src.dataclasses import PyTreeNode
from mujoco.mjx._src.types import ConeType
from mujoco.mjx._src.types import ConstraintType
from mujoco.mjx._src.types import Contact
from mujoco.mjx._src.types import Data
@@ -35,18 +36,14 @@ from mujoco.mjx._src.types import Model
import numpy as np
_CONDIM_EFC_COUNT = {1: 1, 3: 4, 4: 6, 6: 10}
class _Efc(PyTreeNode):
"""Support data for creating constraint matrices."""
J: jax.Array
pos: jax.Array
pos_norm: jax.Array
pos_aref: jax.Array
pos_imp: jax.Array
invweight: jax.Array
solref: jax.Array
solimp: jax.Array
frictionloss: jax.Array
def _kbi(
@@ -59,13 +56,13 @@ def _kbi(
timeconst, dampratio = solref
if not m.opt.disableflags & DisableBit.REFSAFE:
timeconst = jp.maximum(timeconst, 2 * m.opt.timestep) * (timeconst > 0)
timeconst = jp.maximum(timeconst, 2 * m.opt.timestep)
dmin, dmax, width, mid, power = solimp
dmin = jp.clip(dmin, mujoco.mjMINIMP, mujoco.mjMAXIMP)
dmax = jp.clip(dmax, mujoco.mjMINIMP, mujoco.mjMAXIMP)
width = jp.maximum(0, width)
width = jp.maximum(mujoco.mjMINVAL, width)
mid = jp.clip(mid, mujoco.mjMINIMP, mujoco.mjMAXIMP)
power = jp.maximum(1, power)
@@ -73,8 +70,8 @@ def _kbi(
k = 1 / (dmax * dmax * timeconst * timeconst * dampratio * dampratio)
b = 2 / (dmax * timeconst)
# TODO(robotics-simulation): check various solparam settings in model gen test
k = jp.where(dampratio <= 0, -solref[0] / (dmax * dmax), k)
b = jp.where(timeconst <= 0, -solref[1] / dmax, b)
k = jp.where(solref[0] <= 0, -solref[0] / (dmax * dmax), k)
b = jp.where(solref[1] <= 0, -solref[1] / dmax, b)
imp_x = jp.abs(pos) / width
imp_a = (1.0 / jp.power(mid, power - 1)) * jp.power(imp_x, power)
@@ -87,254 +84,280 @@ def _kbi(
return k, b, imp # corresponds to K, B, I of efc_KBIP
def _instantiate_equality_connect(m: Model, d: Data) -> Optional[_Efc]:
def _row(j: jax.Array, *args) -> _Efc:
"""Creates an efc row, ensuring args all have same row count."""
if len(j.shape) < 2:
return _Efc(j, *args) # if j isn't batched, ignore
args = list(args)
for i, arg in enumerate(args):
if not arg.shape or arg.shape[0] != j.shape[0]:
args[i] = jp.tile(arg, (j.shape[0],) + (1,) * (len(arg.shape)))
return _Efc(j, *args)
def _efc_equality_connect(m: Model, d: Data) -> Optional[_Efc]:
"""Calculates constraint rows for connect equality constraints."""
ids = np.nonzero(m.eq_type == EqType.CONNECT)[0]
if (m.opt.disableflags & DisableBit.EQUALITY) or ids.size == 0:
eq_id = np.nonzero(m.eq_type == EqType.CONNECT)[0]
if (m.opt.disableflags & DisableBit.EQUALITY) or eq_id.size == 0:
return None
id1, id2, data = m.eq_obj1id[ids], m.eq_obj2id[ids], m.eq_data[ids]
@jax.vmap
def fn(data, id1, id2):
def rows(obj1id, obj2id, data, solref, solimp):
anchor1, anchor2 = data[0:3], data[3:6]
# find global points
pos1 = d.xmat[id1] @ anchor1 + d.xpos[id1]
pos2 = d.xmat[id2] @ anchor2 + d.xpos[id2]
# compute position error
cpos = pos1 - pos2
# error is difference in global positions
pos1 = d.xmat[obj1id] @ anchor1 + d.xpos[obj1id]
pos2 = d.xmat[obj2id] @ anchor2 + d.xpos[obj2id]
pos = pos1 - pos2
# compute Jacobian difference (opposite of contact: 0 - 1)
jacp1, _ = support.jac(m, d, pos1, id1)
jacp2, _ = support.jac(m, d, pos2, id2)
jacp1, _ = support.jac(m, d, pos1, obj1id)
jacp2, _ = support.jac(m, d, pos2, obj2id)
j = (jacp1 - jacp2).T
pos_imp = math.norm(pos)
invweight = m.body_invweight0[obj1id, 0] + m.body_invweight0[obj2id, 0]
return j, cpos, jp.repeat(math.norm(cpos), 3)
return _row(j, pos, pos_imp, invweight, solref, solimp)
# concatenate to drop connect grouping dimension
j, pos, pos_norm = jax.tree_util.tree_map(jp.concatenate, fn(data, id1, id2))
invweight = m.body_invweight0[id1, 0] + m.body_invweight0[id2, 0]
invweight = jp.repeat(invweight, 3)
solref = jp.tile(m.eq_solref[ids], (3, 1))
solimp = jp.tile(m.eq_solimp[ids], (3, 1))
frictionloss = jp.zeros_like(pos_norm)
return _Efc(j, pos, pos_norm, invweight, solref, solimp, frictionloss)
args = (m.eq_obj1id, m.eq_obj2id, m.eq_data, m.eq_solref, m.eq_solimp)
args = jax.tree_util.tree_map(lambda x: x[eq_id], args)
# concatenate to drop row grouping
return jax.tree_util.tree_map(jp.concatenate, rows(*args))
def _instantiate_equality_weld(m: Model, d: Data) -> Optional[_Efc]:
def _efc_equality_weld(m: Model, d: Data) -> Optional[_Efc]:
"""Calculates constraint rows for weld equality constraints."""
ids = np.nonzero(m.eq_type == EqType.WELD)[0]
if (m.opt.disableflags & DisableBit.EQUALITY) or ids.size == 0:
eq_id = np.nonzero(m.eq_type == EqType.WELD)[0]
if (m.opt.disableflags & DisableBit.EQUALITY) or eq_id.size == 0:
return None
id1, id2, data = m.eq_obj1id[ids], m.eq_obj2id[ids], m.eq_data[ids]
@jax.vmap
def fn(data, id1, id2):
def rows(obj1id, obj2id, data, solref, solimp):
anchor1, anchor2 = data[0:3], data[3:6]
relpose, torquescale = data[6:10], data[10]
# find global points
pos1 = d.xmat[id1] @ anchor2 + d.xpos[id1]
pos2 = d.xmat[id2] @ anchor1 + d.xpos[id2]
# compute position error
# error is difference in global position and orientation
pos1 = d.xmat[obj1id] @ anchor2 + d.xpos[obj1id]
pos2 = d.xmat[obj2id] @ anchor1 + d.xpos[obj2id]
cpos = pos1 - pos2
# compute Jacobian difference (opposite of contact: 0 - 1)
jacp1, jacr1 = support.jac(m, d, pos1, id1)
jacp2, jacr2 = support.jac(m, d, pos2, id2)
jacp1, jacr1 = support.jac(m, d, pos1, obj1id)
jacp2, jacr2 = support.jac(m, d, pos2, obj2id)
jacdifp = jacp1 - jacp2
jacdifr = (jacr1 - jacr2) * torquescale
# compute orientation error: neg(q1) * q0 * relpose (axis components only)
quat = math.quat_mul(d.xquat[id1], relpose)
quat1 = math.quat_inv(d.xquat[id2])
quat = math.quat_mul(d.xquat[obj1id], relpose)
quat1 = math.quat_inv(d.xquat[obj2id])
crot = math.quat_mul(quat1, quat)[1:] # copy axis components
pos = jp.concatenate((cpos, crot * torquescale))
# correct rotation Jacobian: 0.5 * neg(q1) * (jac0-jac1) * q0 * relpose
jac_fn = lambda j: math.quat_mul(math.quat_mul_axis(quat1, j), quat)[1:]
jacdifr = 0.5 * jax.vmap(jac_fn)(jacdifr)
j = jp.concatenate((jacdifp.T, jacdifr.T))
pos = jp.concatenate((cpos, crot * torquescale))
pos_imp = math.norm(pos)
invweight = m.body_invweight0[obj1id] + m.body_invweight0[obj2id]
invweight = jp.repeat(invweight, 3, axis=0)
return j, pos, jp.repeat(math.norm(pos), 6)
return _row(j, pos, pos_imp, invweight, solref, solimp)
# concatenate to drop weld grouping dimension
j, pos, pos_norm = jax.tree_util.tree_map(jp.concatenate, fn(data, id1, id2))
invweight = m.body_invweight0[id1] + m.body_invweight0[id2]
invweight = jp.repeat(invweight, 3)
solref = jp.tile(m.eq_solref[ids], (6, 1))
solimp = jp.tile(m.eq_solimp[ids], (6, 1))
frictionloss = jp.zeros_like(pos_norm)
return _Efc(j, pos, pos_norm, invweight, solref, solimp, frictionloss)
args = (m.eq_obj1id, m.eq_obj2id, m.eq_data, m.eq_solref, m.eq_solimp)
args = jax.tree_util.tree_map(lambda x: x[eq_id], args)
# concatenate to drop row grouping
return jax.tree_util.tree_map(jp.concatenate, rows(*args))
def _instantiate_equality_joint(m: Model, d: Data) -> Optional[_Efc]:
def _efc_equality_joint(m: Model, d: Data) -> Optional[_Efc]:
"""Calculates constraint rows for joint equality constraints."""
ids = np.nonzero(m.eq_type == EqType.JOINT)[0]
eq_id = np.nonzero(m.eq_type == EqType.JOINT)[0]
if (m.opt.disableflags & DisableBit.EQUALITY) or ids.size == 0:
if (m.opt.disableflags & DisableBit.EQUALITY) or eq_id.size == 0:
return None
id1, id2, data = m.eq_obj1id[ids], m.eq_obj2id[ids], m.eq_data[ids]
dofadr1, dofadr2 = m.jnt_dofadr[id1], m.jnt_dofadr[id2]
qposadr1, qposadr2 = m.jnt_qposadr[id1], m.jnt_qposadr[id2]
@jax.vmap
def fn(data, id2, dofadr1, dofadr2, qposadr1, qposadr2):
def rows(obj2id, data, solref, solimp, dofadr1, dofadr2, qposadr1, qposadr2):
pos1, pos2 = d.qpos[qposadr1], d.qpos[qposadr2]
ref1, ref2 = m.qpos0[qposadr1], m.qpos0[qposadr2]
pos2, ref2 = pos2 * (id2 > -1), ref2 * (id2 > -1)
dif = pos2 - ref2
dif = (pos2 - ref2) * (obj2id > -1)
dif_power = jp.power(dif, jp.arange(0, 5))
deriv = jp.dot(data[1:5], dif_power[:4] * jp.arange(1, 5))
j = jp.zeros((m.nv)).at[dofadr1].set(1.0).at[dofadr2].set(-deriv)
pos = pos1 - ref1 - jp.dot(data[:5], dif_power)
return j, pos
deriv = jp.dot(data[1:5], dif_power[:4] * jp.arange(1, 5)) * (obj2id > -1)
j, pos = fn(data, id2, dofadr1, dofadr2, qposadr1, qposadr2)
invweight = m.dof_invweight0[dofadr1] + m.dof_invweight0[dofadr2] * (id2 > -1)
solref, solimp = m.eq_solref[ids], m.eq_solimp[ids]
frictionloss = jp.zeros_like(pos)
j = jp.zeros((m.nv)).at[dofadr2].set(-deriv).at[dofadr1].set(1.0)
invweight = m.dof_invweight0[dofadr1]
invweight += m.dof_invweight0[dofadr2] * (obj2id > -1)
return _Efc(j, pos, pos, invweight, solref, solimp, frictionloss)
return _row(j, pos, pos, invweight, solref, solimp)
args = (m.eq_obj1id, m.eq_obj2id, m.eq_data, m.eq_solref, m.eq_solimp)
args = jax.tree_util.tree_map(lambda x: x[eq_id], args)
dofadr1, dofadr2 = m.jnt_dofadr[args[0]], m.jnt_dofadr[args[1]]
qposadr1, qposadr2 = m.jnt_qposadr[args[0]], m.jnt_qposadr[args[1]]
args = args[1:] + (dofadr1, dofadr2, qposadr1, qposadr2)
return rows(*args)
def _instantiate_friction(m: Model, d: Data) -> Optional[_Efc]:
def _efc_friction(m: Model, d: Data) -> Optional[_Efc]:
# TODO(robotics-team): implement _instantiate_friction
del m, d
return None
def _instantiate_limit_ball(m: Model, d: Data) -> Optional[_Efc]:
def _efc_limit_ball(m: Model, d: Data) -> Optional[_Efc]:
"""Calculates constraint rows for ball joint limits."""
ids = np.nonzero((m.jnt_type == JointType.BALL) & m.jnt_limited)[0]
jnt_id = np.nonzero((m.jnt_type == JointType.BALL) & m.jnt_limited)[0]
if (m.opt.disableflags & DisableBit.LIMIT) or ids.size == 0:
if (m.opt.disableflags & DisableBit.LIMIT) or jnt_id.size == 0:
return None
jnt_range = m.jnt_range[ids]
jnt_margin = m.jnt_margin[ids]
qposadr = np.array([np.arange(q, q + 4) for q in m.jnt_qposadr[ids]])
dofadr = np.array([np.arange(d, d + 3) for d in m.jnt_dofadr[ids]])
@jax.vmap
def fn(jnt_range, jnt_margin, qposadr, dofadr):
axis, angle = math.quat_to_axis_angle(d.qpos[qposadr])
j = jp.zeros(m.nv).at[dofadr].set(-axis)
def rows(qposadr, dofadr, jnt_range, jnt_margin, solref, solimp):
axis, angle = math.quat_to_axis_angle(d.qpos[jp.arange(4) + qposadr])
pos = jp.amax(jnt_range) - angle - jnt_margin
active = pos < 0
return j * active, pos * active
j = jp.zeros(m.nv).at[jp.arange(3) + dofadr].set(-axis)
invweight = m.dof_invweight0[dofadr]
j, pos = fn(jnt_range, jnt_margin, qposadr, dofadr)
invweight = m.dof_invweight0[m.jnt_dofadr[ids]]
solref, solimp = m.jnt_solref[ids], m.jnt_solimp[ids]
frictionloss = jp.zeros_like(pos)
return _row(j * active, pos * active, pos, invweight, solref, solimp)
return _Efc(j, pos, pos, invweight, solref, solimp, frictionloss)
args = (m.jnt_qposadr, m.jnt_dofadr, m.jnt_range, m.jnt_margin, m.jnt_solref)
args += (m.jnt_solimp,)
args = jax.tree_util.tree_map(lambda x: x[jnt_id], args)
return rows(*args)
def _instantiate_limit_slide_hinge(m: Model, d: Data) -> Optional[_Efc]:
def _efc_limit_slide_hinge(m: Model, d: Data) -> Optional[_Efc]:
"""Calculates constraint rows for slide and hinge joint limits."""
slide_hinge = np.isin(m.jnt_type, (JointType.SLIDE, JointType.HINGE))
ids = np.nonzero(slide_hinge & m.jnt_limited)[0]
jnt_id = np.nonzero(slide_hinge & m.jnt_limited)[0]
if (m.opt.disableflags & DisableBit.LIMIT) or ids.size == 0:
if (m.opt.disableflags & DisableBit.LIMIT) or jnt_id.size == 0:
return None
jnt_range = m.jnt_range[ids]
jnt_margin = m.jnt_margin[ids]
qposadr = m.jnt_qposadr[ids]
dofadr = m.jnt_dofadr[ids]
@jax.vmap
def fn(jnt_range, jnt_margin, qposadr, dofadr):
dist_min = d.qpos[qposadr] - jnt_range[0]
dist_max = jnt_range[1] - d.qpos[qposadr]
j = jp.zeros(m.nv).at[dofadr].set((dist_min < dist_max) * 2 - 1)
def rows(qposadr, dofadr, jnt_range, jnt_margin, solref, solimp):
qpos = d.qpos[qposadr]
dist_min, dist_max = qpos - jnt_range[0], jnt_range[1] - qpos
pos = jp.minimum(dist_min, dist_max) - jnt_margin
active = pos < 0
return j * active, pos * active
j = jp.zeros(m.nv).at[dofadr].set((dist_min < dist_max) * 2 - 1)
invweight = m.dof_invweight0[dofadr]
j, pos = fn(jnt_range, jnt_margin, qposadr, dofadr)
invweight = m.dof_invweight0[dofadr]
solref, solimp = m.jnt_solref[ids], m.jnt_solimp[ids]
frictionloss = jp.zeros_like(pos)
return _row(j * active, pos * active, pos, invweight, solref, solimp)
return _Efc(j, pos, pos, invweight, solref, solimp, frictionloss)
args = (m.jnt_qposadr, m.jnt_dofadr, m.jnt_range, m.jnt_margin, m.jnt_solref)
args += (m.jnt_solimp,)
args = jax.tree_util.tree_map(lambda x: x[jnt_id], args)
return rows(*args)
def _instantiate_contact(m: Model, d: Data) -> Optional[_Efc]:
"""Calculates constraint rows for contacts."""
def _efc_contact_frictionless(m: Model, d: Data) -> Optional[_Efc]:
"""Calculates constraint rows for frictionless contacts."""
if d.ncon == 0:
con_id = np.nonzero(d.contact.dim == 1)[0]
if con_id.size == 0:
return None
def contact_efc(c: Contact, condim: int):
@jax.vmap
def rows(c: Contact):
pos = c.dist - c.includemargin
active = pos < 0
body1, body2 = jp.array(m.geom_bodyid)[c.geom]
jac1p, _ = support.jac(m, d, c.pos, body1)
jac2p, _ = support.jac(m, d, c.pos, body2)
j = (c.frame @ (jac2p - jac1p).T)[0]
invweight = m.body_invweight0[body1, 0] + m.body_invweight0[body2, 0]
@jax.vmap
def fn(c: Contact):
dist = c.dist - c.includemargin
active = dist < 0
body1, body2 = jp.array(m.geom_bodyid)[c.geom]
jac1p, jac1r = support.jac(m, d, c.pos, body1)
jac2p, jac2r = support.jac(m, d, c.pos, body2)
diff = c.frame @ (jac2p - jac1p).T
if condim > 3: # only calculate rotational diff if needed
diff = jp.concatenate((diff, c.frame @ (jac2r - jac1r).T), axis=0)
tran = m.body_invweight0[body1, 0] + m.body_invweight0[body2, 0]
return _row(j * active, pos * active, pos, invweight, c.solref, c.solimp)
if condim == 1:
return diff[0] * active, tran, dist * active, c.solref, c.solimp
contact = jax.tree_util.tree_map(lambda x: x[con_id], d.contact)
# a pair of opposing pyramid edges per friction dimension
# repeat friction directions with positive and negative sign
fri = jp.repeat(c.friction[: condim - 1], 2, axis=0).at[1::2].mul(-1)
# repeat condims of jacdiff to match +/- friction directions
j = diff[0] + jp.repeat(diff[1:condim], 2, axis=0) * fri[:, None]
# pyramidal has common invweight across all edges
diag_approx = tran + fri[0] * fri[0] * tran
inv_w = diag_approx * 2 * fri[0] * fri[0] / m.opt.impratio
repeat_fn = lambda x: jp.repeat(x[None], (condim - 1) * 2, axis=0)
inv_w, pos, solref, solimp = jax.tree_util.tree_map(
repeat_fn, (inv_w, dist, c.solref, c.solimp)
)
return j * active, inv_w, pos * active, solref, solimp
return rows(contact)
return fn(c)
# group efc calculations by condim
dims, begs = np.unique(d.contact.dim, return_index=True)
efcs = []
for i in range(len(dims)):
dim, beg = dims[i], begs[i]
end = begs[i + 1] if i < len(dims) - 1 else None
c = jax.tree_util.tree_map(lambda x, b=beg, e=end: x[b:e], d.contact)
efc = contact_efc(c, dim)
if dim > 1:
# remove efc grouping dimension
efc = jax.tree_util.tree_map(jp.concatenate, efc)
efcs.append(efc)
def _efc_contact_pyramidal(m: Model, d: Data, condim: int) -> Optional[_Efc]:
"""Calculates constraint rows for frictional pyramidal contacts."""
efc = jax.tree_util.tree_map(lambda *x: jp.concatenate(x), *efcs)
j, invweight, pos, solref, solimp = efc
frictionloss = jp.zeros_like(pos)
con_id = np.nonzero(d.contact.dim == condim)[0]
return _Efc(j, pos, pos, invweight, solref, solimp, frictionloss)
if con_id.size == 0:
return None
@jax.vmap
def rows(c: Contact):
pos = c.dist - c.includemargin
active = pos < 0
body1, body2 = jp.array(m.geom_bodyid)[c.geom]
jac1p, jac1r = support.jac(m, d, c.pos, body1)
jac2p, jac2r = support.jac(m, d, c.pos, body2)
diff = c.frame @ (jac2p - jac1p).T
if condim > 3:
diff = jp.concatenate((diff, (c.frame @ (jac2r - jac1r).T)), axis=0)
# a pair of opposing pyramid edges per friction dimension
# repeat friction directions with positive and negative sign
fri = jp.repeat(c.friction[: condim - 1], 2, axis=0).at[1::2].mul(-1)
# repeat condims of jacdiff to match +/- friction directions
j = diff[0] + jp.repeat(diff[1:condim], 2, axis=0) * fri[:, None]
# pyramidal has common invweight across all edges
invweight = m.body_invweight0[body1, 0] + m.body_invweight0[body2, 0]
invweight = invweight + fri[0] * fri[0] * invweight
invweight = invweight * 2 * fri[0] * fri[0] / m.opt.impratio
return _row(j * active, pos * active, pos, invweight, c.solref, c.solimp)
contact = jax.tree_util.tree_map(lambda x: x[con_id], d.contact)
# concatenate to drop row grouping
return jax.tree_util.tree_map(jp.concatenate, rows(contact))
def _efc_contact_elliptic(m: Model, d: Data, condim: int) -> Optional[_Efc]:
"""Calculates constraint rows for frictional elliptic contacts."""
con_id = np.nonzero(d.contact.dim == condim)[0]
if con_id.size == 0:
return None
@jax.vmap
def rows(c: Contact):
pos = c.dist - c.includemargin
active = pos < 0
obj1id, obj2id = jp.array(m.geom_bodyid)[c.geom]
jac1p, jac1r = support.jac(m, d, c.pos, obj1id)
jac2p, jac2r = support.jac(m, d, c.pos, obj2id)
j = c.frame @ (jac2p - jac1p).T
if condim > 3:
j = jp.concatenate((j, (c.frame @ (jac2r - jac1r).T)[: condim - 3]))
invweight = m.body_invweight0[obj1id, 0] + m.body_invweight0[obj2id, 0]
# normal row comes from solref, remaining rows from solreffriction
solreffriction = c.solreffriction + c.solref * ~c.solreffriction.any()
solreffriction = jp.tile(solreffriction, (condim - 1, 1))
solref = jp.concatenate((c.solref[None], solreffriction))
fri = jp.square(c.friction[0]) / jp.square(c.friction[1 : condim - 1])
invweight = jp.array([invweight, invweight / m.opt.impratio])
invweight = jp.concatenate((invweight, invweight[1] * fri))
pos_aref = jp.zeros(condim).at[0].set(pos)
return _row(j * active, pos_aref * active, pos, invweight, solref, c.solimp)
contact = jax.tree_util.tree_map(lambda x: x[con_id], d.contact)
# concatenate to drop row grouping
return jax.tree_util.tree_map(jp.concatenate, rows(contact))
def counts(efc_type: np.ndarray) -> Tuple[int, int, int, int]:
@@ -344,7 +367,8 @@ def counts(efc_type: np.ndarray) -> Tuple[int, int, int, int]:
nl = (efc_type == ConstraintType.LIMIT_JOINT).sum()
nc_f = (efc_type == ConstraintType.CONTACT_FRICTIONLESS).sum()
nc_p = (efc_type == ConstraintType.CONTACT_PYRAMIDAL).sum()
nc = nc_f + nc_p
nc_e = (efc_type == ConstraintType.CONTACT_ELLIPTIC).sum()
nc = nc_f + nc_p + nc_e
return ne, nf, nl, nc
@@ -363,25 +387,48 @@ def make_efc_type(
num_rows = (m.eq_type == EqType.CONNECT).sum() * 3
num_rows += (m.eq_type == EqType.WELD).sum() * 6
num_rows += (m.eq_type == EqType.JOINT).sum()
efc_types.extend([ConstraintType.EQUALITY] * num_rows)
efc_types += [ConstraintType.EQUALITY] * num_rows
if not m.opt.disableflags & DisableBit.LIMIT:
efc_types.extend([ConstraintType.LIMIT_JOINT] * m.jnt_limited.sum())
efc_types += [ConstraintType.LIMIT_JOINT] * m.jnt_limited.sum()
if not m.opt.disableflags & DisableBit.CONTACT:
num_rows = sum(_CONDIM_EFC_COUNT[d] for d in dim)
efc_types.extend([ConstraintType.CONTACT_PYRAMIDAL] * num_rows)
for condim in (1, 3, 4, 6):
n = (dim == condim).sum()
if condim == 1:
efc_types += [ConstraintType.CONTACT_FRICTIONLESS] * n
elif m.opt.cone == ConeType.PYRAMIDAL:
efc_types += [ConstraintType.CONTACT_PYRAMIDAL] * (condim - 1) * 2 * n
elif m.opt.cone == ConeType.ELLIPTIC:
efc_types += [ConstraintType.CONTACT_ELLIPTIC] * condim * n
else:
raise ValueError(f'Unknown cone: {m.opt.cone}')
return np.array(efc_types)
def make_efc_address(efc_type: np.ndarray, dim: np.ndarray) -> np.ndarray:
def make_efc_address(
m: Union[Model, mujoco.MjModel], dim: np.ndarray, efc_type: np.ndarray
) -> np.ndarray:
"""Returns efc_address that maps contacts to constraint row address."""
nc = (efc_type == ConstraintType.CONTACT_PYRAMIDAL).sum()
nc_start = efc_type.size - nc
offsets = np.cumsum([0] + [_CONDIM_EFC_COUNT[d] for d in dim])[:-1]
offsets = np.array([0], dtype=int)
for condim in (1, 3, 4, 6):
n = (dim == condim).sum()
if n == 0:
continue
if condim == 1:
offsets = np.concatenate((offsets, [1] * n))
elif m.opt.cone == ConeType.PYRAMIDAL:
offsets = np.concatenate((offsets, [(condim - 1) * 2] * n))
elif m.opt.cone == ConeType.ELLIPTIC:
offsets = np.concatenate((offsets, [condim] * n))
else:
raise ValueError(f'Unknown cone: {m.opt.cone}')
return nc_start + offsets
_, _, _, nc = counts(efc_type)
address = efc_type.size - nc + np.cumsum(offsets)[:-1]
return address
def make_constraint(m: Model, d: Data) -> Data:
@@ -390,15 +437,21 @@ def make_constraint(m: Model, d: Data) -> Data:
if m.opt.disableflags & DisableBit.CONSTRAINT:
efcs = ()
else:
efcs = tuple(efc for efc in (
_instantiate_equality_connect(m, d),
_instantiate_equality_weld(m, d),
_instantiate_equality_joint(m, d),
_instantiate_friction(m, d),
_instantiate_limit_ball(m, d),
_instantiate_limit_slide_hinge(m, d),
_instantiate_contact(m, d),
) if efc is not None)
efcs = (
_efc_equality_connect(m, d),
_efc_equality_weld(m, d),
_efc_equality_joint(m, d),
_efc_friction(m, d),
_efc_limit_ball(m, d),
_efc_limit_slide_hinge(m, d),
_efc_contact_frictionless(m, d),
)
if m.opt.cone == ConeType.ELLIPTIC:
con_fn = _efc_contact_elliptic
else:
con_fn = _efc_contact_pyramidal
efcs += tuple(con_fn(m, d, dim) for dim in (3, 4, 6))
efcs = tuple(efc for efc in efcs if efc is not None)
if not efcs:
z = jp.empty(0)
@@ -410,13 +463,13 @@ def make_constraint(m: Model, d: Data) -> Data:
@jax.vmap
def fn(efc):
k, b, imp = _kbi(m, efc.solref, efc.solimp, efc.pos_norm)
k, b, imp = _kbi(m, efc.solref, efc.solimp, efc.pos_imp)
r = jp.maximum(efc.invweight * (1 - imp) / imp, mujoco.mjMINVAL)
aref = -b * (efc.J @ d.qvel) - k * imp * efc.pos
aref = -b * (efc.J @ d.qvel) - k * imp * efc.pos_aref
return aref, r
aref, r = fn(efc)
d = d.replace(efc_J=efc.J, efc_D=1 / r, efc_aref=aref)
d = d.replace(efc_frictionloss=efc.frictionloss)
d = d.replace(efc_frictionloss=jp.zeros_like(r))
return d
+21 -29
View File
@@ -15,6 +15,7 @@
"""Tests for constraint functions."""
from absl.testing import absltest
from absl.testing import parameterized
from jax import numpy as jp
import mujoco
from mujoco import mjx
@@ -38,41 +39,32 @@ def _assert_attr_eq(a, b, attr):
_assert_eq(getattr(a, attr), getattr(b, attr), attr)
class ConstraintTest(absltest.TestCase):
class ConstraintTest(parameterized.TestCase):
def test_constraints(self):
@parameterized.parameters(
mujoco.mjtCone.mjCONE_PYRAMIDAL, mujoco.mjtCone.mjCONE_ELLIPTIC
)
def test_constraints(self, cone):
"""Test constraints."""
m = test_util.load_test_file('constraints.xml')
m.opt.cone = cone
d = mujoco.MjData(m)
mujoco.mj_step(m, d, 100) # at 100 steps mix of active/inactive constraints
mujoco.mj_forward(m, d)
mx = mjx.put_model(m)
dx = mjx.put_data(m, d)
dx = mjx.make_constraint(mx, dx)
d_efc_j = d.efc_J.reshape((-1, m.nv))
# ne, nf, nl order matches
efl = d.ne + d.nf + d.nl
_assert_eq(d_efc_j[:efl], dx.efc_J[:efl], 'efc_J')
_assert_eq(d.efc_D[:efl], dx.efc_D[:efl], 'efc_D')
_assert_eq(d.efc_aref[:efl], dx.efc_aref[:efl], 'efc_aref')
_assert_eq(dx.efc_frictionloss, 0, 'efc_frictionloss')
# sample a mix of active/inactive constraints at different timesteps
for key in range(3):
mujoco.mj_resetDataKeyframe(m, d, key)
mujoco.mj_forward(m, d)
mx = mjx.put_model(m)
dx = mjx.put_data(m, d)
dx = mjx.make_constraint(mx, dx)
# contact order might not match, so check efcs contact by contact
for i in range(d.ncon):
geom_match = (dx.contact.geom == d.contact.geom[i]).all(axis=-1)
geom_match &= (dx.contact.pos == d.contact.pos[i]).all(axis=-1)
self.assertTrue(geom_match.any(), f'contact {i} not found in MJX contact')
j = np.nonzero(geom_match)[0][0]
self.assertEqual(d.contact.dim[i], dx.contact.dim[j])
nc = max(1, (d.contact.dim[i] - 1) * 2)
d_beg, dx_beg = d.contact.efc_address[i], dx.contact.efc_address[j]
d_end, dx_end = d_beg + nc, dx_beg + nc
_assert_eq(d_efc_j[d_beg:d_end], dx.efc_J[dx_beg:dx_end], 'efc_J')
_assert_eq(d.efc_D[d_beg:d_end], dx.efc_D[dx_beg:dx_end], 'efc_D')
d_efc_aref = d.efc_aref[d_beg:d_end]
dx_efc_aref = dx.efc_aref[dx_beg:dx_end]
_assert_eq(d_efc_aref, dx_efc_aref, 'efc_aref')
order = test_util.efc_order(m, d, dx)
d_efc_j = d.efc_J.reshape((-1, m.nv))
_assert_eq(d_efc_j, dx.efc_J[order][:d.nefc], 'efc_J')
_assert_eq(0, dx.efc_J[order][d.nefc:], 'efc_J')
_assert_eq(d.efc_aref, dx.efc_aref[order][:d.nefc], 'efc_aref')
_assert_eq(0, dx.efc_aref[order][d.nefc:], 'efc_aref')
_assert_eq(d.efc_D, dx.efc_D[order][:d.nefc], 'efc_D')
def test_disable_refsafe(self):
m = test_util.load_test_file('constraints.xml')
+26 -12
View File
@@ -15,7 +15,7 @@
"""Functions to initialize, load, or save data."""
import copy
from typing import List, Union
from typing import List, Tuple, Union
import jax
from jax import numpy as jp
@@ -133,7 +133,7 @@ def make_data(m: Union[types.Model, mujoco.MjModel]) -> types.Data:
"""Allocate and initialize Data."""
dim = collision_driver.make_condim(m)
efc_type = constraint.make_efc_type(m, dim)
efc_address = constraint.make_efc_address(efc_type, dim)
efc_address = constraint.make_efc_address(m, dim, efc_type)
ne, nf, nl, nc = constraint.counts(efc_type)
ncon, nefc = dim.size, ne + nf + nl + nc
@@ -174,7 +174,7 @@ def make_data(m: Union[types.Model, mujoco.MjModel]) -> types.Data:
nefc=nefc,
ncon=ncon,
solver_niter=jp.array(0, dtype=int),
time=jp.array(0.0),
time=jp.array(0.0, dtype=float),
qpos=jp.array(m.qpos0),
qvel=zero_nv,
act=zero_na,
@@ -330,7 +330,7 @@ def _make_contact(
c: mujoco._structs._MjContactList,
dim: np.ndarray,
efc_address: np.ndarray,
) -> types.Contact:
) -> Tuple[types.Contact, np.ndarray]:
"""Converts mujoco.structs._MjContactList into mjx.Contact."""
fields = {f.name: getattr(c, f.name) for f in types.Contact.fields()}
fields['frame'] = fields['frame'].reshape((-1, 3, 3))
@@ -351,21 +351,21 @@ def _make_contact(
zero = jax.tree_util.tree_map(
lambda x: np.zeros((1,) + x.shape[1:], dtype=x.dtype), fields
)
zero['dist'][:] = np.finfo(float).max
zero['dist'][:] = 1e10
fields = jax.tree_util.tree_map(lambda *x: np.concatenate(x), fields, zero)
fields = jax.tree_util.tree_map(lambda x: x[contact_map], fields)
fields['dim'] = dim
fields['efc_address'] = efc_address
return types.Contact(**fields)
return types.Contact(**fields), contact_map
def put_data(m: mujoco.MjModel, d: mujoco.MjData, device=None) -> types.Data:
"""Puts mujoco.MjData onto a device, resulting in mjx.Data."""
dim = collision_driver.make_condim(m)
efc_type = constraint.make_efc_type(m, dim)
efc_address = constraint.make_efc_address(efc_type, dim)
efc_address = constraint.make_efc_address(m, dim, efc_type)
ne, nf, nl, nc = constraint.counts(efc_type)
ncon, nefc = dim.size, ne + nf + nl + nc
@@ -388,6 +388,8 @@ def put_data(m: mujoco.MjModel, d: mujoco.MjData, device=None) -> types.Data:
# MJX does not support islanding, so only transfer the first solver_niter
fields['solver_niter'] = fields['solver_niter'][0]
contact, contact_map = _make_contact(d.contact, dim, efc_address)
# pad efc fields: MuJoCo efc arrays are sparse for inactive constraints.
# efc_J is also optionally column-sparse (typically for large nv). MJX is
# neither: it contains zeros for inactive constraints, and efc_J is always
@@ -403,13 +405,25 @@ def put_data(m: mujoco.MjModel, d: mujoco.MjData, device=None) -> types.Data:
else:
fields['efc_J'] = fields['efc_J'].reshape((-1 if m.nv else 0, m.nv))
# move efc rows to their correct offsets
for fname in ('efc_J', 'efc_frictionloss', 'efc_D', 'efc_aref', 'efc_force'):
value = np.zeros((nefc, m.nv)) if fname == 'efc_J' else np.zeros(nefc)
for i in range(4):
value_beg = sum([ne, nf, nl][:i])
d_beg = sum([d.ne, d.nf, d.nl][:i])
size = [d.ne, d.nf, d.nl, d.nefc - d.nl - d.nf - d.ne][i]
for i in range(3):
value_beg = sum([ne, nf][:i])
d_beg = sum([d.ne, d.nf][:i])
size = [d.ne, d.nf, d.nl][i]
value[value_beg : value_beg + size] = fields[fname][d_beg : d_beg + size]
# for nc, we may reorder contacts so they match MJX order: group by dim
for id_to, id_from in enumerate(contact_map):
if id_from == -1:
continue
num_rows = dim[id_to]
if num_rows > 1 and m.opt.cone == mujoco.mjtCone.mjCONE_PYRAMIDAL:
num_rows = (num_rows - 1) * 2
efc_i, efc_o = d.contact.efc_address[id_from], efc_address[id_to]
value[efc_o:efc_o + num_rows] = fields[fname][efc_i:efc_i + num_rows]
fields[fname] = value
# convert qM and qLD if jacobian is dense
@@ -424,7 +438,7 @@ def put_data(m: mujoco.MjModel, d: mujoco.MjData, device=None) -> types.Data:
fields['qLD'] = np.zeros((m.nv, m.nv))
fields['qLDiagInv'] = np.zeros(0)
fields['contact'] = _make_contact(d.contact, dim, efc_address)
fields['contact'] = contact
fields.update(ne=ne, nf=nf, nl=nl, nefc=nefc, ncon=ncon, efc_type=efc_type)
# copy because device_put is async:
+1 -9
View File
@@ -140,14 +140,6 @@ class ModelIOTest(parameterized.TestCase):
)
)
def test_cone_not_implemented(self):
with self.assertRaises(NotImplementedError):
mjx.put_model(
mujoco.MjModel.from_xml_string(
'<mujoco><option cone="elliptic"/><worldbody/></mujoco>'
)
)
def test_pgs_not_implemented(self):
with self.assertRaises(NotImplementedError):
mjx.put_model(
@@ -299,7 +291,7 @@ class DataIOTest(parameterized.TestCase):
self.assertEqual(dx.contact.dist.shape, (4,))
self.assertEqual(d.ncon, 1) # however only 1 contact in this step
np.testing.assert_allclose(dx.contact.dist[0], d.contact.dist[0])
self.assertTrue(np.isinf(dx.contact.dist[1:]).all())
self.assertTrue((dx.contact.dist[1:] > 0).all())
self.assertEqual(dx.contact.frame.shape, (4, 3, 3))
np.testing.assert_allclose(
dx.contact.frame[0].reshape(9), d.contact.frame[0]
+214 -40
View File
@@ -22,6 +22,7 @@ from mujoco.mjx._src import smooth
from mujoco.mjx._src import support
# pylint: disable=g-importing-member
from mujoco.mjx._src.dataclasses import PyTreeNode
from mujoco.mjx._src.types import ConeType
from mujoco.mjx._src.types import Data
from mujoco.mjx._src.types import DisableBit
from mujoco.mjx._src.types import Model
@@ -45,8 +46,12 @@ class _Context(PyTreeNode):
cost: constraint + Gauss cost
prev_cost: cost from previous iter
solver_niter: number of solver iterations
active: active (quadratic) constraints (nefc,)
fri: friction of regularized cone (num(con.dim > 1), 6)
dm: regularized constraint mass (num(con.dim > 1))
u: friction cone (normal and tangents) (num(con.dim > 1), 6)
h: cone hessian (num(con.dim > 1), 6, 6)
"""
qacc: jax.Array
qfrc_constraint: jax.Array
Jaref: jax.Array # pylint: disable=invalid-name
@@ -59,6 +64,11 @@ class _Context(PyTreeNode):
cost: jax.Array
prev_cost: jax.Array
solver_niter: jax.Array
active: jax.Array
fri: jax.Array
dm: jax.Array
u: jax.Array
h: jax.Array
@classmethod
def create(cls, m: Model, d: Data, grad: bool = True) -> '_Context':
@@ -66,6 +76,15 @@ class _Context(PyTreeNode):
# TODO(robotics-team): determine nv at which sparse mul is faster
ma = support.mul_m(m, d, d.qacc)
nv_0 = jp.zeros(m.nv)
fri = 0.0
if m.opt.cone == ConeType.ELLIPTIC:
friction = d.contact.friction[d.contact.dim > 1]
dim = d.contact.dim[d.contact.dim > 1]
mu = friction[:, 0] / jp.sqrt(m.opt.impratio)
fri = jp.concatenate((mu[:, None], friction), axis=1)
for condim in (3, 4, 6):
fri = fri.at[dim == condim, condim:].set(0)
ctx = _Context(
qacc=d.qacc,
qfrc_constraint=d.qfrc_constraint,
@@ -79,8 +98,13 @@ class _Context(PyTreeNode):
cost=jp.inf,
prev_cost=0.0,
solver_niter=0,
active=0.0,
fri=fri,
dm=0.0,
u=0.0,
h=0.0,
)
ctx = _update_constraint(d, ctx)
ctx = _update_constraint(m, d, ctx)
if grad:
ctx = _update_gradient(m, d, ctx)
ctx = ctx.replace(search=-ctx.Mgrad) # start with preconditioned gradient
@@ -106,24 +130,68 @@ class _LSPoint(PyTreeNode):
@classmethod
def create(
cls,
m: Model,
d: Data,
ctx: _Context,
alpha: jax.Array,
jv: jax.Array,
quad: jax.Array,
quad_gauss: jax.Array,
uu: jax.Array,
v0: jax.Array,
uv: jax.Array,
vv: jax.Array,
) -> '_LSPoint':
"""Creates a linesearch point with first and second derivatives."""
# roughly corresponds to CGEval in mujoco/src/engine/engine_solver.c
# TODO(robotics-team): change this to support friction constraints
active = ((ctx.Jaref + alpha * jv) < 0).at[:d.ne + d.nf].set(True)
quad = jax.vmap(jp.multiply)(quad, active) # only active
quad_total = quad_gauss + jp.sum(quad, axis=0)
cost, deriv_0, deriv_1 = 0.0, 0.0, 0.0
quad_total = quad_gauss
if m.opt.cone == ConeType.ELLIPTIC:
mu, u0 = ctx.fri[:, 0], ctx.u[:, 0]
n = u0 + alpha * v0
tsqr = uu + alpha * (2 * uv + alpha * vv)
t = jp.sqrt(tsqr) # tangential force
bottom_zone = ((tsqr <= 0) & (n < 0)) | ((tsqr > 0) & ((mu * n + t) <= 0))
middle_zone = (tsqr > 0) & (n < (mu * t)) & ((mu * n + t) > 0)
# quadratic cost for equality, friction, limits, frictionless contacts
dim1 = d.contact.efc_address[d.contact.dim == 1]
nefl = d.ne + d.nf + d.nl
active = ((ctx.Jaref + alpha * jv) < 0).at[:d.ne + d.nf].set(True)
active = active.at[nefl:].set(False).at[dim1].set(active[dim1])
quad_efld = jax.vmap(jp.multiply)(quad, active)
quad_total += jp.sum(quad_efld, axis=0)
# elliptic bottom zone: quadratic cost
efc_elliptic = d.contact.efc_address[d.contact.dim > 1]
quad_c = jax.vmap(jp.multiply)(quad[efc_elliptic], bottom_zone)
quad_total += jp.sum(quad_c, axis=0)
# elliptic middle zone
t += (t == 0) * mujoco.mjMINVAL
tsqr += (tsqr == 0) * mujoco.mjMINVAL
n1 = v0
t1 = (uv + alpha * vv) / t
t2 = vv / t - (uv + alpha * vv) * t1 / tsqr
dm = ctx.dm * middle_zone
nmt = n - mu * t
cost = 0.5 * jp.sum(dm * jp.square(nmt))
deriv_0 = jp.sum(dm * nmt * (n1 - mu * t1))
deriv_1 = jp.sum(dm * (jp.square(n1 - mu * t1) - nmt * mu * t2))
elif m.opt.cone == ConeType.PYRAMIDAL:
active = ((ctx.Jaref + alpha * jv) < 0).at[:d.ne + d.nf].set(True)
quad = jax.vmap(jp.multiply)(quad, active) # only active
quad_total += jp.sum(quad, axis=0)
else:
raise NotImplementedError(f'unsupported cone type: {m.opt.cone}')
alpha_sq = alpha * alpha
cost += alpha_sq * quad_total[2] + alpha * quad_total[1] + quad_total[0]
deriv_0 += 2 * alpha * quad_total[2] + quad_total[1]
deriv_1 += 2 * quad_total[2] + (quad_total[2] == 0) * mujoco.mjMINVAL
cost = alpha * alpha * quad_total[2] + alpha * quad_total[1] + quad_total[0]
deriv_0 = 2 * alpha * quad_total[2] + quad_total[1]
deriv_1 = 2 * quad_total[2] + (quad_total[2] == 0) * mujoco.mjMINVAL
return _LSPoint(alpha=alpha, cost=cost, deriv_0=deriv_0, deriv_1=deriv_1)
@@ -159,34 +227,95 @@ def _while_loop_scan(cond_fun, body_fun, init_val, max_iter):
return jax.lax.scan(_fun, init, None, length=max_iter)[0][0]
def _update_constraint(d: Data, ctx: _Context) -> _Context:
def _update_constraint(m: Model, d: Data, ctx: _Context) -> _Context:
"""Updates constraint force and resulting cost given latst solver iteration.
Corresponds to CGupdateConstraint in mujoco/src/engine/engine_solver.c
Args:
m: model defining constraints
d: data which contains latest qacc and smooth terms
ctx: current solver context
Returns:
context with new constraint force and costs
"""
# TODO(robotics-team): add friction constraints
if m.opt.cone == ConeType.PYRAMIDAL:
# ne/nf constraints are always active, rest are non-negative constraints
active = (ctx.Jaref < 0).at[:d.ne + d.nf].set(True)
efc_force = d.efc_D * -ctx.Jaref * active
cost = 0.5 * jp.sum(d.efc_D * ctx.Jaref * ctx.Jaref * active)
dm, u, h = 0.0, 0.0, 0.0
elif m.opt.cone == ConeType.ELLIPTIC:
friction = d.contact.friction[d.contact.dim > 1]
efc_address = d.contact.efc_address[d.contact.dim > 1]
dim = d.contact.dim[d.contact.dim > 1]
slice_fn = jax.vmap(lambda x: jax.lax.dynamic_slice(ctx.Jaref, (x,), (6,)))
u = slice_fn(efc_address) * ctx.fri
mu, n, t = ctx.fri[:, 0], u[:, 0], jax.vmap(math.norm)(u[:, 1:])
# only count active constraints
active = (ctx.Jaref < 0).at[:d.ne + d.nf].set(True)
# bottom zone: quadratic
bottom_zone = ((t <= 0) & (n < 0)) | ((t > 0) & ((mu * n + t) <= 0))
active = (ctx.Jaref < 0).at[:d.ne + d.nf].set(True)
adr_i, adr_j = [], []
for i, (condim, addr) in enumerate(zip(dim, efc_address)):
adr_i.extend(range(addr, addr + condim))
adr_j.extend([i] * condim)
active = active.at[jp.array(adr_i)].set(bottom_zone[jp.array(adr_j)])
efc_force = d.efc_D * -ctx.Jaref * active
cost = 0.5 * jp.sum(d.efc_D * ctx.Jaref * ctx.Jaref * active)
# middle zone: cone
middle_zone = (t > 0) & (n < (mu * t)) & ((mu * n + t) > 0)
dm = d.efc_D[efc_address] / jp.maximum(
mu * mu * (1 + mu * mu), mujoco.mjMINVAL
)
nmt = n - mu * t
cost += 0.5 * jp.sum(dm * nmt * nmt * middle_zone)
# tangent and friction for middle zone:
force = -dm * nmt * mu * middle_zone
force_fri = -force / (t + ~middle_zone * mujoco.mjMINVAL)
force_fri = force_fri[:, None] * u[:, 1:] * friction
efc_force = efc_force.at[efc_address].add(force)
efc_adr, adr_i, adr_j = [], [], []
for i, (condim, addr) in enumerate(zip(dim, efc_address)):
efc_adr.extend(range(addr + 1, addr + condim))
adr_i.extend([i] * (condim - 1))
adr_j.extend(range(condim - 1))
efc_adr, adr_i, adr_j = jp.array(efc_adr), jp.array(adr_i), jp.array(adr_j)
efc_force = efc_force.at[efc_adr].add(force_fri[(adr_i, adr_j)])
# cone hessian
h = 0.0
if m.opt.solver == SolverType.NEWTON:
t = jp.maximum(t, mujoco.mjMINVAL)
# h = mu*N/T^3 * U*U'
ttt = jp.maximum(t * t * t, mujoco.mjMINVAL)
h = jax.vmap(lambda x, y: x * jp.outer(y, y.T))(mu * n / ttt, u)
# add to diagonal: (mu^2 - mu*N/T) * I
h += jax.vmap(lambda x: x * jp.eye(6, 6))(mu * mu - mu * n / t)
# set first row: (1, -mu/T * U)
h_0 = jax.vmap(lambda mu, t, u: jp.append(1, -mu / t * u[1:]))(mu, t, u)
h = h.at[:, 0].set(h_0).at[:, :, 0].set(h_0)
# pre and post multiply by diag(mu, friction), scale by Dm
h *= jax.vmap(lambda d, f: d * jp.outer(f, f.T))(dm, ctx.fri)
# only cone constraints
h = jax.vmap(jp.multiply)(h, middle_zone)
else:
raise NotImplementedError(f'unsupported cone type: {m.opt.cone}')
efc_force = d.efc_D * -ctx.Jaref * active
qfrc_constraint = d.efc_J.T @ efc_force
gauss = 0.5 * jp.dot(ctx.Ma - d.qfrc_smooth, ctx.qacc - d.qacc_smooth)
cost = 0.5 * jp.sum(d.efc_D * ctx.Jaref * ctx.Jaref * active) + gauss
ctx = ctx.replace(
qfrc_constraint=qfrc_constraint,
gauss=gauss,
cost=cost,
cost=cost + gauss,
prev_cost=ctx.cost,
efc_force=efc_force,
active=active,
dm=dm,
u=u,
h=h,
)
return ctx
@@ -213,8 +342,17 @@ def _update_gradient(m: Model, d: Data, ctx: _Context) -> _Context:
if m.opt.solver == SolverType.CG:
mgrad = smooth.solve_m(m, d, grad)
elif m.opt.solver == SolverType.NEWTON:
active = (ctx.Jaref < 0).at[: d.ne + d.nf].set(True)
h = (d.efc_J.T * d.efc_D * active) @ d.efc_J
if m.opt.cone == ConeType.ELLIPTIC:
cm = jp.diag(d.efc_D * ctx.active)
efc_address = d.contact.efc_address[d.contact.dim > 1]
dim = d.contact.dim[d.contact.dim > 1]
# set efc of cone H along diagonal
for i, (condim, addr) in enumerate(zip(dim, efc_address)):
h_cone = ctx.h[i, :condim, :condim]
cm = cm.at[addr:addr+condim, addr:addr+condim].add(h_cone)
h = d.efc_J.T @ cm @ d.efc_J
else:
h = (d.efc_J.T * d.efc_D * ctx.active) @ d.efc_J
h = support.full_m(m, d) + h
h_ = jax.scipy.linalg.cho_factor(h)
mgrad = jax.scipy.linalg.cho_solve(h_, grad)
@@ -256,8 +394,28 @@ def _linesearch(m: Model, d: Data, ctx: _Context) -> _Context:
))
quad = jp.stack((0.5 * ctx.Jaref * ctx.Jaref, jv * ctx.Jaref, 0.5 * jv * jv))
quad = (quad * d.efc_D).T
uu, v0, uv, vv = 0.0, 0.0, 0.0, 0.0
if m.opt.cone == ConeType.ELLIPTIC:
mask = d.contact.dim > 1
# complete vector quadratic (for bottom zone)
efc_con, efc_fri = [], []
for condim, addr in zip(d.contact.dim[mask], d.contact.efc_address[mask]):
efc_con.extend([addr] * (condim - 1))
efc_fri.extend(range(addr + 1, addr + condim))
quad = quad.at[jp.array(efc_con)].add(quad[jp.array(efc_fri)])
point_fn = lambda a: _LSPoint.create(d, ctx, a, jv, quad, quad_gauss)
# rescale to make primal cone circular
jv_fn = jax.vmap(lambda x: jax.lax.dynamic_slice(jv, (x,), (6,)))
efc_elliptic = d.contact.efc_address[mask]
v = jv_fn(efc_elliptic) * ctx.fri
uu = jp.sum(ctx.u[:, 1:] * ctx.u[:, 1:], axis=1)
v0 = v[:, 0]
uv = jp.sum(ctx.u[:, 1:] * v[:, 1:], axis=1)
vv = jp.sum(v[:, 1:] * v[:, 1:], axis=1)
point_fn = lambda a: _LSPoint.create(
m, d, ctx, a, jv, quad, quad_gauss, uu, v0, uv, vv
)
def cond(ctx: _LSContext) -> jax.Array:
done = ctx.ls_iter >= m.opt.ls_iterations
@@ -274,21 +432,34 @@ def _linesearch(m: Model, d: Data, ctx: _Context) -> _Context:
hi_next = point_fn(hi.alpha - hi.deriv_0 / hi.deriv_1)
mid = point_fn(0.5 * (lo.alpha + hi.alpha))
# we swap lo/hi if:
# 1) they are not correctly at a bracket boundary (e.g. lo.deriv_0 > 0), OR
# 2) if moving to next or mid narrows the bracket
swap_lo_next = (lo.deriv_0 > 0) | (lo.deriv_0 < lo_next.deriv_0)
lo = jax.tree_util.tree_map(lambda x, y: jp.where(swap_lo_next, y, x), lo, lo_next)
swap_lo_mid = (mid.deriv_0 < 0) & (lo.deriv_0 < mid.deriv_0)
lo = jax.tree_util.tree_map(lambda x, y: jp.where(swap_lo_mid, y, x), lo, mid)
swap_hi_next = (hi.deriv_0 < 0) | (hi.deriv_0 > hi_next.deriv_0)
hi = jax.tree_util.tree_map(lambda x, y: jp.where(swap_hi_next, y, x), hi, hi_next)
swap_hi_mid = (mid.deriv_0 > 0) & (hi.deriv_0 > mid.deriv_0)
hi = jax.tree_util.tree_map(lambda x, y: jp.where(swap_hi_mid, y, x), hi, mid)
swap = swap_lo_next | swap_lo_mid | swap_hi_next | swap_hi_mid
# swap lo/hi if the derivative points to a narrower bracket width
in_bracket = lambda x, y: ((x < y) & (y < 0) | (x > y) & (y > 0))
swap_lo_next = in_bracket(lo.deriv_0, lo_next.deriv_0)
lo = jax.tree_util.tree_map(
lambda x, y: jp.where(swap_lo_next, y, x), lo, lo_next
)
swap_lo_mid = in_bracket(lo.deriv_0, mid.deriv_0)
lo = jax.tree_util.tree_map(
lambda x, y: jp.where(swap_lo_mid, y, x), lo, mid
)
swap_lo_hi_next = in_bracket(lo.deriv_0, hi_next.deriv_0)
lo = jax.tree_util.tree_map(
lambda x, y: jp.where(swap_lo_hi_next, y, x), lo, hi_next
)
swap_hi_next = in_bracket(hi.deriv_0, hi_next.deriv_0)
hi = jax.tree_util.tree_map(
lambda x, y: jp.where(swap_hi_next, y, x), hi, hi_next
)
swap_hi_mid = in_bracket(hi.deriv_0, mid.deriv_0)
hi = jax.tree_util.tree_map(
lambda x, y: jp.where(swap_hi_mid, y, x), hi, mid
)
swap_hi_lo_next = in_bracket(hi.deriv_0, lo_next.deriv_0)
hi = jax.tree_util.tree_map(
lambda x, y: jp.where(swap_hi_lo_next, y, x), hi, lo_next
)
swap = swap_lo_next | swap_lo_mid | swap_lo_hi_next
swap = swap | swap_hi_next | swap_hi_mid | swap_hi_lo_next
ctx = ctx.replace(lo=lo, hi=hi, swap=swap, ls_iter=ctx.ls_iter + 1)
return ctx
@@ -331,14 +502,17 @@ def solve(m: Model, d: Data) -> Data:
def body(ctx: _Context) -> _Context:
ctx = _linesearch(m, d, ctx)
prev_grad, prev_Mgrad = ctx.grad, ctx.Mgrad # pylint: disable=invalid-name
ctx = _update_constraint(d, ctx)
ctx = _update_constraint(m, d, ctx)
ctx = _update_gradient(m, d, ctx)
# polak-ribiere:
beta = jp.dot(ctx.grad, ctx.Mgrad - prev_Mgrad)
beta = beta / jp.maximum(mujoco.mjMINVAL, jp.dot(prev_grad, prev_Mgrad))
beta = jp.maximum(0, beta)
search = -ctx.Mgrad + beta * ctx.search
if m.opt.solver == SolverType.NEWTON:
search = -ctx.Mgrad
else:
# polak-ribiere:
beta = jp.dot(ctx.grad, ctx.Mgrad - prev_Mgrad)
beta = beta / jp.maximum(mujoco.mjMINVAL, jp.dot(prev_grad, prev_Mgrad))
beta = jp.maximum(0, beta)
search = -ctx.Mgrad + beta * ctx.search
ctx = ctx.replace(search=search, solver_niter=ctx.solver_niter + 1)
return ctx
+58 -43
View File
@@ -15,16 +15,18 @@
"""Tests for constraint functions."""
from absl.testing import absltest
from absl.testing import parameterized
import jax
import mujoco
from mujoco import mjx
from mujoco.mjx._src import solver
from mujoco.mjx._src import test_util
import numpy as np
# tolerance for difference between MuJoCo and MJX constraint calculations,
# tolerance for difference between MuJoCo and MJX solver calculations,
# mostly due to float precision
_TOLERANCE = 5e-5
_TOLERANCE = 5e-3
def _assert_eq(a, b, name, tol=_TOLERANCE):
@@ -37,72 +39,85 @@ def _assert_attr_eq(a, b, attr, tol=_TOLERANCE):
_assert_eq(getattr(a, attr), getattr(b, attr), attr, tol=tol)
class SolverTest(absltest.TestCase):
class SolverTest(parameterized.TestCase):
def test_newton(self):
"""Test newton solver."""
@parameterized.parameters(
# these scene challenges the solver, with CG you need to crank up
# the iterations, otherwise it diverges
(mujoco.mjtSolver.mjSOL_CG, mujoco.mjtCone.mjCONE_PYRAMIDAL, 100),
(mujoco.mjtSolver.mjSOL_CG, mujoco.mjtCone.mjCONE_ELLIPTIC, 100),
# Newton converges much more quickly, lower iterations to demonstrate
# mgrad is being calculated optimally
(mujoco.mjtSolver.mjSOL_NEWTON, mujoco.mjtCone.mjCONE_PYRAMIDAL, 2),
(mujoco.mjtSolver.mjSOL_NEWTON, mujoco.mjtCone.mjCONE_ELLIPTIC, 2),
)
def test_solver(self, solver_, cone, iterations):
"""Test newton, CG solver with pyramidal, elliptic cones."""
m = test_util.load_test_file('constraints.xml')
# it's critical that mgrad is optimally calculated, so lower iterations
# to be sure that MJX is converging as quickly as MuJoCo
m.opt.iterations = 1
m.opt.solver = solver_
m.opt.cone = cone
m.opt.iterations = iterations
d = mujoco.MjData(m)
mujoco.mj_step(m, d, 20) # significant constraint forces at 20 steps
# mj_forward overwrites qacc_warmstart, so let's restore it to what it was
# at the beginning of the step so that MJX does not have a trivial solution
warmstart = d.qacc_warmstart.copy()
mujoco.mj_forward(m, d)
d.qacc_warmstart = warmstart
def cost(qacc):
jaref = np.zeros(d.nefc, dtype=float)
cost = np.zeros(1)
mujoco.mj_mulJacVec(m, d, jaref, qacc)
mujoco.mj_constraintUpdate(m, d, jaref - d.efc_aref, cost, 0)
return cost
dx = jax.jit(mjx.solve)(mjx.put_model(m), mjx.put_data(m, d))
# sample a mix of active/inactive constraints at different timesteps
for key in range(0, 3):
mujoco.mj_resetDataKeyframe(m, d, key)
mujoco.mj_step(m, d) # step to generate warmstart
_assert_attr_eq(d, dx, 'qacc')
_assert_attr_eq(d, dx, 'qfrc_constraint')
nnz = dx.efc_J.any(axis=1)
_assert_eq(d.efc_force, dx.efc_force[nnz], 'efc_force')
# compare costs
mj_cost = cost(d.qacc)
ctx = solver._Context.create(mjx.put_model(m), mjx.put_data(m, d))
mjx_cost = ctx.cost - ctx.gauss
_assert_eq(mj_cost, mjx_cost, 'cost')
def test_cg(self):
"""Test CG solver."""
m = test_util.load_test_file('constraints.xml')
d = mujoco.MjData(m)
mujoco.mj_step(m, d, 20) # significant constraint forces at 20 steps
# mj_forward overwrites qacc_warmstart, so let's restore it to what it was
# before the step so that MJX does not have a trivial solution
warmstart = d.qacc_warmstart.copy()
mujoco.mj_forward(m, d)
d.qacc_warmstart = warmstart
dx = jax.jit(mjx.solve)(mjx.put_model(m), mjx.put_data(m, d))
# CG does not converge as quickly as Newton but is cheaper to calculate
m.opt.solver = mujoco.mjtSolver.mjSOL_CG
m.opt.iterations = 8
# MJX finds very similar solutions with the newton solver
if solver_ == mujoco.mjtSolver.mjSOL_NEWTON:
nnz = dx.efc_J.any(axis=1)
_assert_eq(d.efc_force, dx.efc_force[nnz], 'efc_force')
_assert_attr_eq(d, dx, 'qfrc_constraint')
_assert_attr_eq(d, dx, 'qacc')
# mj_forward overwrites qacc_warmstart, so let's restore it to what it was
# at the beginning of the step so that MJX does not have a trivial solution
warmstart = d.qacc_warmstart.copy()
mujoco.mj_forward(m, d)
d.qacc_warmstart = warmstart
dx = jax.jit(mjx.solve)(mjx.put_model(m), mjx.put_data(m, d))
_assert_attr_eq(d, dx, 'qacc')
_assert_attr_eq(d, dx, 'qfrc_constraint', tol=8e-4)
nnz = dx.efc_J.any(axis=1)
_assert_eq(d.efc_force, dx.efc_force[nnz], 'efc_force', tol=5e-4)
# both CG and Newton find costs that are nearly the same as MuJoCo, often
# lower (due to slight differences in the MJX linsearch algorithm)
mj_cost = cost(d.qacc)
mjx_cost = cost(dx.qacc)
self.assertLess(mjx_cost, mj_cost * 1.01)
def test_no_warmstart(self):
"""Test no warmstart."""
m = test_util.load_test_file('constraints.xml')
d = mujoco.MjData(m)
mujoco.mj_step(m, d, 20) # significant constraint forces at 20 steps
# significant constraint forces keyframe 2
mujoco.mj_resetDataKeyframe(m, d, 2)
m.opt.disableflags |= mujoco.mjtDisableBit.mjDSBL_WARMSTART
mujoco.mj_forward(m, d)
mx = mjx.put_model(m)
dx = jax.jit(mjx.solve)(mx, mjx.put_data(m, d))
nnz = dx.efc_J.any(axis=1)
# without warmstart, the solution is not as close
_assert_eq(d.efc_force, dx.efc_force[nnz], 'efc_force', tol=2e-2)
# even without warmstart, newton converges quickly
_assert_eq(d.efc_force, dx.efc_force[nnz], 'efc_force', tol=2e-4)
def test_sparse(self):
"""Test solver works with sparse mass matrices."""
m = test_util.load_test_file('constraints.xml')
m.opt.jacobian = mujoco.mjtJacobian.mjJAC_SPARSE
d = mujoco.MjData(m)
mujoco.mj_step(m, d, 20) # significant constraint forces at 20 steps
# significant constraint forces keyframe 2
mujoco.mj_resetDataKeyframe(m, d, 2)
# mj_forward overwrites qacc_warmstart, so let's restore it to what it was
# at the beginning of the step so that MJX does not have a trivial solution
+23
View File
@@ -26,6 +26,7 @@ import mujoco
# pylint: disable=g-importing-member
from mujoco.mjx._src import forward
from mujoco.mjx._src import io
from mujoco.mjx._src.types import Data
# pylint: enable=g-importing-member
import numpy as np
@@ -104,6 +105,28 @@ def benchmark(
return jit_time, run_time, steps
def efc_order(m: mujoco.MjModel, d: mujoco.MjData, dx: Data) -> np.ndarray:
"""Returns a sort order such that dx.efc_*[order][:d.nefc] == d.efc_*."""
# reorder efc rows to skip inactive constraints and match contact order
efl = dx.ne + dx.nf + dx.nl
order = np.arange(efl)
order[(dx.efc_J[:efl] == 0).all(axis=1)] = 2**16 # move empty rows to end
for i in range(dx.ncon):
num_rows = dx.contact.dim[i]
if dx.contact.dim[i] > 1 and m.opt.cone == mujoco.mjtCone.mjCONE_PYRAMIDAL:
num_rows = (dx.contact.dim[i] - 1) * 2
if dx.contact.dist[i] > 0: # move empty contacts to end
order = np.append(order, np.repeat(2 ** 16, num_rows))
continue
contact_match = (d.contact.geom == dx.contact.geom[i]).all(axis=-1)
contact_match &= (d.contact.pos == dx.contact.pos[i]).all(axis=-1)
assert contact_match.any(), f'contact {i} not found'
contact_id = np.nonzero(contact_match)[0][0]
order = np.append(order, np.repeat(efl + contact_id, num_rows))
return np.argsort(order, kind='stable')
_ACTUATOR_TYPES = ['motor', 'velocity', 'position', 'general', 'intvelocity']
_DYN_TYPES = ['none', 'integrator', 'filter', 'filterexact']
_DYN_PRMS = ['0.189', '2.1']
+5 -4
View File
@@ -135,9 +135,10 @@ class ConeType(enum.IntEnum):
Attributes:
PYRAMIDAL: pyramidal
ELLIPTIC: elliptic
"""
PYRAMIDAL = mujoco.mjtCone.mjCONE_PYRAMIDAL
# unsupported: ELLIPTIC
ELLIPTIC = mujoco.mjtCone.mjCONE_ELLIPTIC
class JacobianType(enum.IntEnum):
@@ -245,7 +246,7 @@ class ConstraintType(enum.IntEnum):
# unsupported: LIMIT_TENDON
CONTACT_FRICTIONLESS = mujoco.mjtConstraint.mjCNSTR_CONTACT_FRICTIONLESS
CONTACT_PYRAMIDAL = mujoco.mjtConstraint.mjCNSTR_CONTACT_PYRAMIDAL
# unsupported: CONTACT_ELLIPTIC
CONTACT_ELLIPTIC = mujoco.mjtConstraint.mjCNSTR_CONTACT_ELLIPTIC
class CamLightType(enum.IntEnum):
@@ -703,7 +704,7 @@ class Contact(PyTreeNode):
solref: jax.Array
solreffriction: jax.Array
solimp: jax.Array
# unsupported: mu, H
# unsupported: mu, H (calculated locally in solver.py)
dim: np.ndarray
geom1: jax.Array
geom2: jax.Array
@@ -840,7 +841,7 @@ class Data(PyTreeNode):
qfrc_passive: jax.Array
qfrc_gravcomp: jax.Array
efc_aref: jax.Array
# position, velcoity, control & acceleration dependent:
# position, velocity, control & acceleration dependent:
qfrc_actuator: jax.Array
qfrc_smooth: jax.Array
qacc_smooth: jax.Array
+10 -1
View File
@@ -58,7 +58,7 @@
<geom class="box" condim="4"/>
</body>
<body name="box_condim6" pos="6 0 0">
<body name="box_condim6" pos="7 0 0">
<freejoint/>
<geom class="box" condim="6"/>
</body>
@@ -75,4 +75,13 @@
<motor gear="50000" joint="joint3" name="act2"/>
<motor gear="75000" joint="joint4" name="act3"/>
</actuator>
<keyframe>
<!-- keyframe 0: default position with some motion, zero contacts -->
<key qpos='1 0 0 0 -1 0 0 1 0 0 0 0 0 1 0 0 0 4 0 0 1 0 0 0 5 0 0 1 0 0 0 6 0 0 1 0 0 0 7 0 0 1 0 0 0' qvel='1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1'/>
<!-- keyframe 1: some contacts but constraints are quadratic -->
<key qpos='1 0.0011 -8.2e-07 -0.0011 -0.82 1.9 -0.58 0.97 -0.14 0.17 -0.069 0.22 0.29 0.93 0.2 0.15 0.28 4.3 0.23 -0.26 0.97 0.12 0.11 0.18 5.4 0.25 -0.26 0.97 0.11 0.16 0.17 6.4 0.25 -0.26 0.97 0.11 0.16 0.17 7.4 0.25 -0.26 0.97 0.11 0.16 0.17' qvel='-0.14 3.3e-05 0.14 -0.14 -0.93 -3.6 -1.8 1 -0.57 -0.16 0.21 1.1 1 2.2 0.65 1.3 -4.2 -2.6 -5.6 0.54 1.6 2.8 -3.7 -2.3 0.7 -1.8 1.6 2.8 -3.7 -2.3 0.62 -1.8 1.6 2.8 -3.7 -2.3 0.61 -1.8'/>
<!-- keyframe 2: some contacts and some constraints are in cone state (for elliptic) -->
<key qpos='1 0.0087 2.4e-07 -0.0086 -0.89 1.8 -0.77 0.98 -0.2 -0.0022 -0.026 0.19 0.33 0.86 0.32 0.064 0.38 4.4 0.36 -0.81 0.97 -0.0013 -0.0011 0.25 5.6 0.52 -0.75 0.98 -0.018 0.17 0.094 6.6 0.52 -0.75 0.98 -0.017 0.16 0.094 7.6 0.52 -0.76 0.98 -0.017 0.16 0.094' qvel='0.2 -1.8e-05 -0.2 -0.72 0.072 0.025 0.015 -4.9 0.35 -0.22 0.26 0.99 -4.6 1.7 1.1 0.52 -0.73 0.16 7.9 1 0.043 -0.042 1.3 1.6 -1.6 0.98 0.027 -0.024 1.3 1.6 -1.8 0.96 0.025 -0.022 1.3 1.6 -1.8 0.96'/>
</keyframe>
</mujoco>
+4 -4
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name="mujoco-mjx"
version = "3.1.6"
version = "3.1.7"
authors = [
{name = "Google DeepMind", email = "mujoco@deepmind.com"},
]
@@ -31,7 +31,7 @@ dependencies = [
"etils[epath]",
"jax",
"jaxlib",
"mujoco>=3.1.6.dev0",
"mujoco>=3.1.7.dev0",
"scipy",
"trimesh",
]
@@ -42,6 +42,6 @@ mjx-viewer = "mujoco.mjx.viewer:main"
[project.urls]
Homepage = "https://github.com/google-deepmind/mujoco/tree/main/mjx"
Documentation = "https://mujoco.readthedocs.io/en/3.1.6"
Documentation = "https://mujoco.readthedocs.io/en/3.1.7"
Repository = "https://github.com/google-deepmind/mujoco/tree/main/mjx"
Changelog = "https://mujoco.readthedocs.io/en/3.1.6/changelog.html"
Changelog = "https://mujoco.readthedocs.io/en/3.1.7/changelog.html"
+4 -2
View File
@@ -33,7 +33,8 @@ jaxlib==0.4.18; python_version >= '3.9' \
--hash=sha256:6cb20bbbdafd90e71ad0deb9295519a0175c108c8c557b84fb9fe94f751daee4 \
--hash=sha256:116a0d6aedd3e856b52493d7e392fb1b40952b84fb72448fde1c1ab5687db667 \
--hash=sha256:9593ff69f424947567e206f3e356b2a2df55ca68e6d815d5adc6cae308e8f652 \
--hash=sha256:2b17b3f05b3bbf8e0ddb85fba339525ac03bac21c9f26d0f83dcea1b1654353e
--hash=sha256:2b17b3f05b3bbf8e0ddb85fba339525ac03bac21c9f26d0f83dcea1b1654353e \
--hash=sha256:b35ec08984e2aa5e96ba3f3f8b88e90dee0283649e037f213dec8e85638fa17d
pip==23.3.1 \
--hash=sha256:55eb67bb6171d37447e82213be585b75fe2b12b359e993773aca4de9247a052b
pytest==7.4.2 \
@@ -68,7 +69,8 @@ scipy==1.11.3; python_version >= '3.9' \
--hash=sha256:5305792c7110e32ff155aed0df46aa60a60fc6e52cd4ee02cdeb67eaccd5356e \
--hash=sha256:a63d1ec9cadecce838467ce0631c17c15c7197ae61e49429434ba01d618caa83 \
--hash=sha256:715c9966eb8906bc67e450e962bd07a5254420077178f98258904da4004a172f \
--hash=sha256:d4d88a6fc091614b842a739b3db6ae15f95c77b308113bd6daefd4b05539b103
--hash=sha256:d4d88a6fc091614b842a739b3db6ae15f95c77b308113bd6daefd4b05539b103 \
--hash=sha256:cf0dbc4d3fe3107358868a60f263c9d8c2e9ba5de8a934cac4164124f727e6ca
setuptools==68.2.2 \
--hash=sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a
trimesh==4.0.0 \
+176 -24
View File
@@ -62,7 +62,7 @@
"source": [
"!pip install mujoco\n",
"!pip install mujoco_mjx\n",
"!pip install brax"
"!pip install brax\n"
]
},
{
@@ -102,11 +102,6 @@
"}\n",
"\"\"\")\n",
"\n",
"# Tell XLA to use Triton GEMM, this improves steps/sec by ~30% on some GPUs\n",
"xla_flags = os.environ.get('XLA_FLAGS', '')\n",
"xla_flags += ' --xla_gpu_triton_gemm_any=True'\n",
"os.environ['XLA_FLAGS'] = xla_flags\n",
"\n",
"# Configure MuJoCo to use the EGL rendering backend (requires GPU)\n",
"print('Setting environment variable to use GPU rendering:')\n",
"%env MUJOCO_GL=egl\n",
@@ -122,7 +117,12 @@
" 'If using a hosted Colab runtime, make sure you enable GPU acceleration '\n",
" 'by going to the Runtime menu and selecting \"Choose runtime type\".')\n",
"\n",
"print('Installation successful.')"
"print('Installation successful.')\n",
"\n",
"# Tell XLA to use Triton GEMM, this improves steps/sec by ~30% on some GPUs\n",
"xla_flags = os.environ.get('XLA_FLAGS', '')\n",
"xla_flags += ' --xla_gpu_triton_gemm_any=True'\n",
"os.environ['XLA_FLAGS'] = xla_flags\n"
]
},
{
@@ -155,20 +155,32 @@
"cell_type": "code",
"execution_count": 0,
"metadata": {
"cellView": "form",
"id": "ObF1UXrkb0Nd"
},
"outputs": [],
"source": [
"#@title Import MuJoCo, MJX, and Brax\n",
"\n",
"\n",
"from datetime import datetime\n",
"from etils import epath\n",
"import functools\n",
"from IPython.display import HTML\n",
"from typing import Any, Dict, Sequence, Tuple, Union\n",
"import os\n",
"from ml_collections import config_dict\n",
"\n",
"\n",
"import jax\n",
"from jax import numpy as jp\n",
"import numpy as np\n",
"from typing import Any, Dict, Sequence, Tuple, Union\n",
"from flax.training import orbax_utils\n",
"from flax import struct\n",
"from matplotlib import pyplot as plt\n",
"import mediapy as media\n",
"from orbax import checkpoint as ocp\n",
"\n",
"import mujoco\n",
"from mujoco import mjx\n",
"\n",
"from brax import base\n",
"from brax import envs\n",
@@ -178,15 +190,7 @@
"from brax.mjx.base import State as MjxState\n",
"from brax.training.agents.ppo import train as ppo\n",
"from brax.training.agents.ppo import networks as ppo_networks\n",
"from brax.io import html, mjcf, model\n",
"\n",
"from etils import epath\n",
"from flax import struct\n",
"from matplotlib import pyplot as plt\n",
"import mediapy as media\n",
"from ml_collections import config_dict\n",
"import mujoco\n",
"from mujoco import mjx\n"
"from brax.io import html, mjcf, model\n"
]
},
{
@@ -892,7 +896,7 @@
},
"outputs": [],
"source": [
"!git clone https://github.com/google-deepmind/mujoco_menagerie"
"!git clone https://github.com/google-deepmind/mujoco_menagerie\n"
]
},
{
@@ -905,6 +909,9 @@
"source": [
"#@title Barkour vb Quadruped Env\n",
"\n",
"BARKOUR_ROOT_PATH = epath.Path('mujoco_menagerie/google_barkour_vb')\n",
"\n",
"\n",
"def get_config():\n",
" \"\"\"Returns reward config for barkour quadruped environment.\"\"\"\n",
"\n",
@@ -972,9 +979,10 @@
" obs_noise: float = 0.05,\n",
" action_scale: float = 0.3,\n",
" kick_vel: float = 0.05,\n",
" scene_file: str = 'scene_mjx.xml',\n",
" **kwargs,\n",
" ):\n",
" path = epath.Path('mujoco_menagerie/google_barkour_vb/scene_mjx.xml')\n",
" path = BARKOUR_ROOT_PATH / scene_file\n",
" sys = mjcf.load(path.as_posix())\n",
" self._dt = 0.02 # this environment is 50 fps\n",
" sys = sys.tree_replace({'opt.timestep': 0.004})\n",
@@ -1284,10 +1292,11 @@
" return done & (step < 500)\n",
"\n",
" def render(\n",
" self, trajectory: List[base.State], camera: str | None = None\n",
" self, trajectory: List[base.State], camera: str | None = None,\n",
" width: int = 240, height: int = 320,\n",
" ) -> Sequence[np.ndarray]:\n",
" camera = camera or 'track'\n",
" return super().render(trajectory, camera=camera)\n",
" return super().render(trajectory, camera=camera, width=width, height=height)\n",
"\n",
"envs.register_environment('barkour', BarkourEnv)"
]
@@ -1323,6 +1332,17 @@
},
"outputs": [],
"source": [
"ckpt_path = epath.Path('/tmp/quadrupred_joystick/ckpts')\n",
"ckpt_path.mkdir(parents=True, exist_ok=True)\n",
"\n",
"def policy_params_fn(current_step, make_policy, params):\n",
" # save checkpoints\n",
" orbax_checkpointer = ocp.PyTreeCheckpointer()\n",
" save_args = orbax_utils.save_args_from_target(params)\n",
" path = ckpt_path / f'{current_step}'\n",
" orbax_checkpointer.save(path, params, force=True, save_args=save_args)\n",
"\n",
"\n",
"make_networks_factory = functools.partial(\n",
" ppo_networks.make_ppo_networks,\n",
" policy_hidden_layer_sizes=(128, 128, 128, 128))\n",
@@ -1333,7 +1353,9 @@
" num_updates_per_batch=4, discounting=0.97, learning_rate=3.0e-4,\n",
" entropy_cost=1e-2, num_envs=8192, batch_size=256,\n",
" network_factory=make_networks_factory,\n",
" randomization_fn=domain_randomize, seed=0)\n",
" randomization_fn=domain_randomize,\n",
" policy_params_fn=policy_params_fn,\n",
" seed=0)\n",
"\n",
"x_data = []\n",
"y_data = []\n",
@@ -1450,6 +1472,136 @@
"source": [
"HTML(html.render(eval_env.sys.tree_replace({'opt.timestep': eval_env.dt}), rollout))"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "gNagGnBODotY"
},
"source": [
"## Train Policy with Height Field\n",
"\n",
"We may also want the quadruped to learn to walk on rought terrain. Let's take the latest checkpoint from the joystick policy above, and finetune it on a height field terrain."
]
},
{
"cell_type": "code",
"execution_count": 0,
"metadata": {
"id": "wlT3xLouKxqT"
},
"outputs": [],
"source": [
"# use the height field scene\n",
"scene_file = 'scene_hfield_mjx.xml'\n",
"\n",
"env = envs.get_environment(env_name, scene_file=scene_file)\n",
"jit_reset = jax.jit(env.reset)\n",
"state = jit_reset(jax.random.PRNGKey(0))\n",
"plt.imshow(env.render([state.pipeline_state], camera='track')[0])"
]
},
{
"cell_type": "code",
"execution_count": 0,
"metadata": {
"id": "jOTx-OyPDqPW"
},
"outputs": [],
"source": [
"# grab the latest checkpoint from the flat terrain joystick policy\n",
"latest_ckpts = list(ckpt_path.glob('*'))\n",
"latest_ckpts.sort()\n",
"latest_ckpt = latest_ckpts[0]\n",
"\n",
"train_fn = functools.partial(\n",
" ppo.train, num_timesteps=40_000_000, num_evals=5,\n",
" reward_scaling=1, episode_length=1000, normalize_observations=True,\n",
" action_repeat=1, unroll_length=20, num_minibatches=32,\n",
" num_updates_per_batch=4, discounting=0.97, learning_rate=3.0e-4,\n",
" entropy_cost=1e-2, num_envs=8192, batch_size=256,\n",
" network_factory=make_networks_factory,\n",
" randomization_fn=domain_randomize, seed=0,\n",
" restore_checkpoint_path=latest_ckpt)\n",
"\n",
"x_data = []\n",
"y_data = []\n",
"ydataerr = []\n",
"times = [datetime.now()]\n",
"max_y, min_y = 40, 0\n",
"\n",
"# Reset environments since internals may be overwritten by tracers from the\n",
"# domain randomization function.\n",
"env = envs.get_environment(env_name, scene_file=scene_file)\n",
"eval_env = envs.get_environment(env_name, scene_file=scene_file)\n",
"make_inference_fn, params, _= train_fn(environment=env,\n",
" progress_fn=progress,\n",
" eval_env=eval_env)\n",
"\n",
"print(f'time to jit: {times[1] - times[0]}')\n",
"print(f'time to train: {times[-1] - times[1]}')"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "0wHRJyjLFww6"
},
"source": [
"## Visualize Policy with Height Field"
]
},
{
"cell_type": "code",
"execution_count": 0,
"metadata": {
"id": "1X57XkaVFu-v"
},
"outputs": [],
"source": [
"eval_env = envs.get_environment(env_name, scene_file=scene_file)\n",
"\n",
"jit_reset = jax.jit(eval_env.reset)\n",
"jit_step = jax.jit(eval_env.step)\n",
"inference_fn = make_inference_fn(params)\n",
"jit_inference_fn = jax.jit(inference_fn)"
]
},
{
"cell_type": "code",
"execution_count": 0,
"metadata": {
"id": "nAxexZcVFu-v"
},
"outputs": [],
"source": [
"# @markdown Commands **only used for Barkour Env**:\n",
"x_vel = 1.0 #@param {type: \"number\"}\n",
"y_vel = 0.0 #@param {type: \"number\"}\n",
"ang_vel = -0.5 #@param {type: \"number\"}\n",
"\n",
"the_command = jp.array([x_vel, y_vel, ang_vel])\n",
"\n",
"# initialize the state\n",
"rng = jax.random.PRNGKey(0)\n",
"state = jit_reset(rng)\n",
"state.info['command'] = the_command\n",
"rollout = [state.pipeline_state]\n",
"\n",
"# grab a trajectory\n",
"n_steps = 500\n",
"render_every = 2\n",
"\n",
"for i in range(n_steps):\n",
" act_rng, rng = jax.random.split(rng)\n",
" ctrl, _ = jit_inference_fn(state.obs, act_rng)\n",
" state = jit_step(state, ctrl)\n",
" rollout.append(state.pipeline_state)\n",
"\n",
"media.show_video(\n",
" eval_env.render(rollout[::render_every], camera='track'),\n",
" fps=1.0 / eval_env.dt / render_every)"
]
}
],
"metadata": {
+1 -1
View File
@@ -256,7 +256,7 @@ void Pid::RegisterPlugin() {
delete reinterpret_cast<Pid*>(d->plugin_data[instance]);
d->plugin_data[instance] = 0;
};
plugin.reset = +[](const mjModel* m, double* plugin_state, void* plugin_data,
plugin.reset = +[](const mjModel* m, mjtNum* plugin_state, void* plugin_data,
int instance) {
auto* pid = reinterpret_cast<Pid*>(plugin_data);
pid->Reset(plugin_state);
+5 -5
View File
@@ -80,7 +80,7 @@ void SdfVisualizer::Visualize(const mjModel* m, const mjData* d,
mjtNum* geom_quat = m->geom_quat + 4*g;
mju_quat2Mat(geom_mat, geom_quat);
mju_mulMatMatT(rotation, geom_xmat, geom_mat, 3, 3, 3);
mju_rotVecMat(offset, geom_pos, rotation);
mju_mulMatVec3(offset, rotation, geom_pos);
mju_sub3(offset, geom_xpos, offset);
for (int i = 0; i < niter; i++) {
@@ -97,15 +97,15 @@ void SdfVisualizer::Visualize(const mjModel* m, const mjData* d,
mjvGeom* thisgeom = scn->geoms + scn->ngeom;
mjtNum* p1 = points + (tot + (k == 0 ? (n-1) * j : j))*3;
mjtNum* p2 = points + (tot + j + 1)*3;
mju_rotVecMat(from, p1, rotation);
mju_mulMatVec3(from, rotation, p1);
mju_addTo3(from, offset);
mju_rotVecMat(to, p2, rotation);
mju_mulMatVec3(to, rotation, p2);
mju_addTo3(to, offset);
if (k == 0) {
float rgba[4] = {static_cast<float>(j > 0), 0,
static_cast<float>(j == 0), 1};
mjtNum size[] = {.2*m->stat.meansize};
mjv_initGeom(thisgeom, mjGEOM_SPHERE, size, from, geom_xmat, rgba);
mjtNum size = 0.2 * m->stat.meansize;
mjv_initGeom(thisgeom, mjGEOM_SPHERE, &size, from, geom_xmat, rgba);
} else {
mjv_initGeom(thisgeom, mjGEOM_NONE, NULL, NULL, NULL, NULL);
thisgeom->objtype = mjOBJ_UNKNOWN;
+15 -13
View File
@@ -306,10 +306,10 @@ void TouchGrid::Compute(const mjModel* m, mjData* d, int instance) {
// Note that contact.frame is column major.
mjtNum tmp_force[6], tmp1[3];
mj_contactForce(m, d, i, tmp_force);
mju_rotVecMatT(tmp1, tmp_force, d->contact[i].frame);
mju_rotVecMatT(forces + 6*contact, tmp1, site_mat);
mju_rotVecMatT(tmp1, tmp_force + 3, d->contact[i].frame);
mju_rotVecMatT(forces + 6*contact + 3, tmp1, site_mat);
mju_mulMatTVec3(tmp1, d->contact[i].frame, tmp_force);
mju_mulMatTVec3(forces + 6*contact, site_mat, tmp1);
mju_mulMatTVec3(tmp1, d->contact[i].frame, tmp_force + 3);
mju_mulMatTVec3(forces + 6*contact + 3, site_mat, tmp1);
// Forces point from the smaller to larger body, so flip sign if
// the parent body has smaller id.
@@ -324,7 +324,7 @@ void TouchGrid::Compute(const mjModel* m, mjData* d, int instance) {
// Get position, rotate into contact frame.
mjtNum tmp2[3];
mju_sub3(tmp1, d->contact[i].pos, site_pos);
mju_rotVecMatT(tmp2, tmp1, site_mat);
mju_mulMatTVec3(tmp2, site_mat, tmp1);
// Transform to spherical coordinates, copy into positions array.
CartesianToSpherical(tmp2, tmp1);
@@ -432,17 +432,19 @@ void TouchGrid::Visualize(const mjModel* m, mjData* d, const mjvOption* opt,
return;
} else {
// size
mjtNum size[3] = {dist*0.5*(x_edges[i+1]-x_edges[i]),
dist*0.5*(y_edges[j+1]-y_edges[j]),
dist*kRelativeThickness};
mjtNum size[3];
size[0] = dist*0.5*(x_edges[i+1]-x_edges[i]);
size[1] = dist*0.5*(y_edges[j+1]-y_edges[j]);
size[2] = dist*kRelativeThickness;
// position
mjtNum pos[3];
mjtNum aer[3] = {0.5*(x_edges[i+1]+x_edges[i]),
0.5*(y_edges[j+1]+y_edges[j]),
dist*(1-kRelativeThickness)};
mjtNum aer[3];
aer[0] = 0.5*(x_edges[i+1]+x_edges[i]);
aer[1] = 0.5*(y_edges[j+1]+y_edges[j]);
aer[2] = dist*(1-kRelativeThickness);
SphericalToCartesian(aer, pos);
mju_rotVecMat(pos, pos, site_mat);
mju_mulMatVec3(pos, site_mat, pos);
mju_addTo3(pos, site_pos);
// orientation
@@ -525,7 +527,7 @@ void TouchGrid::RegisterPlugin() {
};
// Reset callback.
plugin.reset = +[](const mjModel* m, double* plugin_state, void* plugin_data,
plugin.reset = +[](const mjModel* m, mjtNum* plugin_state, void* plugin_data,
int instance) {
auto* TouchGrid = reinterpret_cast<class TouchGrid*>(plugin_data);
TouchGrid->Reset(m, instance);
+2 -2
View File
@@ -84,7 +84,7 @@ if(NOT TARGET mujoco)
if(MUJOCO_FRAMEWORK)
message("MuJoCo framework is at ${MUJOCO_FRAMEWORK}/mujoco.framework")
set(MUJOCO_LIBRARY
${MUJOCO_FRAMEWORK}/mujoco.framework/Versions/A/libmujoco.3.1.6.dylib
${MUJOCO_FRAMEWORK}/mujoco.framework/Versions/A/libmujoco.3.1.7.dylib
)
target_compile_options(mujoco INTERFACE -F${MUJOCO_FRAMEWORK})
endif()
@@ -92,7 +92,7 @@ if(NOT TARGET mujoco)
if(NOT MUJOCO_FRAMEWORK)
find_library(
MUJOCO_LIBRARY mujoco mujoco.3.1.6 HINTS ${MUJOCO_LIBRARY_DIR} REQUIRED
MUJOCO_LIBRARY mujoco mujoco.3.1.7 HINTS ${MUJOCO_LIBRARY_DIR} REQUIRED
)
find_path(MUJOCO_INCLUDE mujoco/mujoco.h HINTS ${MUJOCO_INCLUDE_DIR} REQUIRED)
message("MuJoCo is at ${MUJOCO_LIBRARY}")
+32
View File
@@ -27,6 +27,7 @@ import numpy as np
TEST_XML = r"""
<mujoco model="test">
<compiler coordinate="local" angle="radian" eulerseq="xyz"/>
<size nkey="2"/>
<option timestep="0.002" gravity="0 0 -9.81"/>
<visual>
<global fovy="50" />
@@ -745,6 +746,37 @@ class MuJoCoBindingsTest(parameterized.TestCase):
# Expect next states to be equal.
np.testing.assert_array_equal(state1a, state1b)
def test_mj_setKeyframe(self): # pylint: disable=invalid-name
mujoco.mj_step(self.model, self.data)
# Test for invalid state spec
invalid_key = 2
expected_message = (
f'mj_setKeyframe: index must be smaller than {invalid_key} (keyframes'
' allocated in model)'
)
with self.assertRaisesWithLiteralMatch(mujoco.FatalError, expected_message):
mujoco.mj_setKeyframe(self.model, self.data, invalid_key)
valid_key = 1
time = self.data.time
qpos = self.data.qpos.copy()
qvel = self.data.qvel.copy()
act = self.data.act.copy()
mujoco.mj_setKeyframe(self.model, self.data, valid_key)
# Step, assert that time has changed.
mujoco.mj_step(self.model, self.data)
self.assertNotEqual(time, self.data.time)
# Reset to keyframe, assert that time, qpos, qvel, act are the same.
mujoco.mj_resetDataKeyframe(self.model, self.data, valid_key)
self.assertEqual(time, self.data.time)
np.testing.assert_array_equal(qpos, self.data.qpos)
np.testing.assert_array_equal(qvel, self.data.qvel)
np.testing.assert_array_equal(act, self.data.act)
def test_mj_angmomMat(self): # pylint: disable=invalid-name
self.data.qvel = np.ones(self.model.nv, np.float64)
mujoco.mj_forward(self.model, self.data)
+3
View File
@@ -302,6 +302,7 @@ PYBIND11_MODULE(_functions, pymodule) {
}
return InterceptMjErrors(::mj_setState)(m, d, state.data(), spec);
});
Def<traits::mj_setKeyframe>(pymodule);
Def<traits::mj_addContact>(pymodule);
Def<traits::mj_isPyramidal>(pymodule);
Def<traits::mj_isSparse>(pymodule);
@@ -697,6 +698,8 @@ PYBIND11_MODULE(_functions, pymodule) {
Def<traits::mju_norm3>(pymodule);
Def<traits::mju_dot3>(pymodule);
Def<traits::mju_dist3>(pymodule);
Def<traits::mju_mulMatVec3>(pymodule);
Def<traits::mju_mulMatTVec3>(pymodule);
Def<traits::mju_rotVecMat>(pymodule);
Def<traits::mju_rotVecMatT>(pymodule);
Def<traits::mju_cross>(pymodule);
+4 -4
View File
@@ -7,13 +7,13 @@
<key>CFBundleIdentifier</key>
<string>org.mujoco.mjpython</string>
<key>CFBundleVersion</key>
<string>3.1.6</string>
<string>3.1.7</string>
<key>CFBundleGetInfoString</key>
<string>3.1.6</string>
<string>3.1.7</string>
<key>CFBundleLongVersionString</key>
<string>3.1.6</string>
<string>3.1.7</string>
<key>CFBundleShortVersionString</key>
<string>3.1.6</string>
<string>3.1.7</string>
<key>CFBundleExecutable</key>
<string>mjpython</string>
<key>CFBundleIconFile</key>
+3
View File
@@ -1390,6 +1390,7 @@ PYBIND11_MODULE(_structs, m) {
});
DefineStructFunctions(mjVisualGlobal);
#define X(var) mjVisualGlobal.def_readwrite(#var, &raw::MjVisualGlobal::var)
X(orthographic);
X(fovy);
X(ipd);
X(azimuth);
@@ -2123,6 +2124,7 @@ This is useful for example when the MJB is not available as a file on disk.)"));
X(distance);
X(azimuth);
X(elevation);
X(orthographic);
#undef X
#define X(var) DefinePyArray(mjvCamera, #var, &MjvCameraWrapper::var)
@@ -2153,6 +2155,7 @@ This is useful for example when the MJB is not available as a file on disk.)"));
X(frustum_top);
X(frustum_near);
X(frustum_far);
X(orthographic);
#undef X
#define X(var) DefinePyArray(mjvGLCamera, #var, &MjvGLCameraWrapper::var)
+3 -3
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "mujoco"
version = "3.1.6"
version = "3.1.7"
authors = [
{name = "Google DeepMind", email = "mujoco@deepmind.com"},
]
@@ -36,9 +36,9 @@ dynamic = ["readme", "scripts"]
[project.urls]
Homepage = "https://github.com/google-deepmind/mujoco"
Documentation = "https://mujoco.readthedocs.io/en/3.1.6"
Documentation = "https://mujoco.readthedocs.io/en/3.1.7"
Repository = "https://github.com/google-deepmind/mujoco"
Changelog = "https://mujoco.readthedocs.io/en/3.1.6/changelog.html"
Changelog = "https://mujoco.readthedocs.io/en/3.1.7/changelog.html"
[tool.setuptools]
include-package-data = false
+29 -15
View File
@@ -479,8 +479,8 @@
"\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(xml)\n",
"data = mujoco.MjData(model)\n",
"renderer = mujoco.Renderer(model)\n",
"\n",
"renderer = mujoco.Renderer(model)\n",
"mujoco.mj_forward(model, data)\n",
"renderer.update_scene(data)\n",
"\n",
@@ -509,6 +509,7 @@
"# Run this cell multiple times for different colors\n",
"model.geom('red_box').rgba[:3] = np.random.rand(3)\n",
"renderer.update_scene(data)\n",
"\n",
"media.show_image(renderer.render())"
]
},
@@ -545,6 +546,7 @@
" renderer.update_scene(data)\n",
" pixels = renderer.render()\n",
" frames.append(pixels)\n",
"\n",
"media.show_video(frames, fps=framerate)"
]
},
@@ -590,6 +592,7 @@
"duration = 3.8 # (seconds)\n",
"framerate = 60 # (Hz)\n",
"\n",
"# Simulate and display video.\n",
"frames = []\n",
"mujoco.mj_resetData(model, data)\n",
"while data.time < duration:\n",
@@ -599,7 +602,6 @@
" pixels = renderer.render()\n",
" frames.append(pixels)\n",
"\n",
"# Simulate and display video.\n",
"media.show_video(frames, fps=framerate)"
]
},
@@ -646,6 +648,7 @@
"model.opt.gravity = (0, 0, 10)\n",
"print('flipped gravity', model.opt.gravity)\n",
"\n",
"# Simulate and display video.\n",
"frames = []\n",
"mujoco.mj_resetData(model, data)\n",
"while data.time < duration:\n",
@@ -756,10 +759,12 @@
"</mujoco>\n",
"\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(tippe_top)\n",
"renderer = mujoco.Renderer(model)\n",
"data = mujoco.MjData(model)\n",
"renderer = mujoco.Renderer(model)\n",
"\n",
"mujoco.mj_forward(model, data)\n",
"renderer.update_scene(data, camera=\"closeup\")\n",
"\n",
"media.show_image(renderer.render())"
]
},
@@ -933,10 +938,12 @@
"</mujoco>\n",
"\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(chaotic_pendulum)\n",
"renderer = mujoco.Renderer(model, 480, 640)\n",
"data = mujoco.MjData(model)\n",
"renderer = mujoco.Renderer(model, 480, 640)\n",
"\n",
"mujoco.mj_forward(model, data)\n",
"renderer.update_scene(data, camera=\"fixed\")\n",
"\n",
"media.show_image(renderer.render())"
]
},
@@ -965,12 +972,10 @@
"frames = []\n",
"renderer = mujoco.Renderer(model, 240, 320)\n",
"\n",
"\n",
"# set initial state\n",
"mujoco.mj_resetData(model, data)\n",
"data.joint('root').qvel = 10\n",
"\n",
"\n",
"# simulate and record frames\n",
"frame = 0\n",
"sim_time = 0\n",
@@ -1176,14 +1181,13 @@
" ax.plot(sim_time, energy, label='timestep = {:2.2g}ms'.format(1000*dt))\n",
" ax.set_yscale('log')\n",
"\n",
"\n",
"# finalize plot\n",
"ax.set_ybound(1, 1e3)\n",
"ax.set_title('energy')\n",
"ax.set_ylabel('Joule')\n",
"ax.set_xlabel('second')\n",
"ax.legend(frameon=True, loc='lower right');\n",
"plt.tight_layout()\n"
"plt.tight_layout()"
]
},
{
@@ -1228,10 +1232,12 @@
"</mujoco>\n",
"\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(free_body_MJCF)\n",
"renderer = mujoco.Renderer(model, 400, 600)\n",
"data = mujoco.MjData(model)\n",
"renderer = mujoco.Renderer(model, 400, 600)\n",
"\n",
"mujoco.mj_forward(model, data)\n",
"renderer.update_scene(data, \"fixed\")\n",
"\n",
"media.show_image(renderer.render())"
]
},
@@ -1275,7 +1281,7 @@
"mujoco.mj_resetData(model, data)\n",
"data.qvel[3:6] = 5*np.random.randn(3)\n",
"\n",
"# simulate and render\n",
"# Simulate and display video.\n",
"for i in range(n_frames):\n",
" while data.time < i/120.0: #1/4x real time\n",
" mujoco.mj_step(model, data)\n",
@@ -1283,7 +1289,6 @@
" frame = renderer.render()\n",
" frames.append(frame)\n",
"\n",
"# show video\n",
"media.show_video(frames, fps=30)"
]
},
@@ -1437,7 +1442,7 @@
"data = mujoco.MjData(model)\n",
"renderer = mujoco.Renderer(model, height, width)\n",
"\n",
"# simulate and render\n",
"# Simulate and display video.\n",
"mujoco.mj_resetData(model, data)\n",
"for i in range(n_frames):\n",
" while data.time < i/30.0:\n",
@@ -1445,6 +1450,7 @@
" renderer.update_scene(data, \"y\")\n",
" frame = renderer.render()\n",
" frames.append(frame)\n",
"\n",
"media.show_video(frames, fps=30)"
]
},
@@ -1513,10 +1519,12 @@
"</mujoco>\n",
"\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(MJCF)\n",
"renderer = mujoco.Renderer(model, 480, 480)\n",
"data = mujoco.MjData(model)\n",
"renderer = mujoco.Renderer(model, 480, 480)\n",
"\n",
"mujoco.mj_forward(model, data)\n",
"renderer.update_scene(data, \"fixed\")\n",
"\n",
"media.show_image(renderer.render())\n"
]
},
@@ -1551,7 +1559,7 @@
"mujoco.mj_resetData(model, data)\n",
"data.ctrl = 20\n",
"\n",
"# simulate and render\n",
"# Simulate and display video.\n",
"for i in range(n_frames):\n",
" while data.time < i/fps:\n",
" mujoco.mj_step(model, data)\n",
@@ -1783,10 +1791,10 @@
"outputs": [],
"source": [
"#@title Project from world to camera coordinates {vertical-output: true}\n",
"\n",
"# reset the scene\n",
"renderer.update_scene(data)\n",
"\n",
"\n",
"# Get the world coordinates of the box corners\n",
"box_pos = data.geom_xpos[model.geom('red_box').id]\n",
"box_mat = data.geom_xmat[model.geom('red_box').id].reshape(3, 3)\n",
@@ -1897,6 +1905,7 @@
" modify_scene(renderer.scene)\n",
" pixels = renderer.render()\n",
" frames.append(pixels)\n",
"\n",
"media.show_video(frames, fps=framerate)"
]
},
@@ -1923,6 +1932,7 @@
"outputs": [],
"source": [
"#@title Load the \"dominos\" model\n",
"\n",
"dominos_xml = \"\"\"\n",
"<mujoco>\n",
" <asset>\n",
@@ -2022,6 +2032,7 @@
"outputs": [],
"source": [
"#@title Render from fixed camera\n",
"\n",
"duration = 2.5 # (seconds)\n",
"framerate = 60 # (Hz)\n",
"\n",
@@ -2034,6 +2045,7 @@
" renderer.update_scene(data, camera='top')\n",
" pixels = renderer.render()\n",
" frames.append(pixels)\n",
"\n",
"media.show_video(frames, fps=framerate)"
]
},
@@ -2047,6 +2059,7 @@
"outputs": [],
"source": [
"#@title Render from moving camera\n",
"\n",
"duration = 3 # (seconds)\n",
"\n",
"# find time when box is thrown (speed > 2cm/s)\n",
@@ -2109,6 +2122,7 @@
" renderer.update_scene(data, cam)\n",
" pixels = renderer.render()\n",
" frames.append(pixels)\n",
"\n",
"media.show_video(frames, fps=framerate)"
]
}
+1 -1
View File
@@ -24,7 +24,7 @@ set(MSVC_INCREMENTAL_DEFAULT ON)
project(
mujoco_samples
VERSION 3.1.6
VERSION 3.1.7
DESCRIPTION "MuJoCo samples binaries"
HOMEPAGE_URL "https://mujoco.org"
)
+1 -1
View File
@@ -29,7 +29,7 @@ set(MUJOCO_DEP_VERSION_lodepng
project(
mujoco_simulate
VERSION 3.1.6
VERSION 3.1.7
DESCRIPTION "MuJoCo simulate binaries"
HOMEPAGE_URL "https://mujoco.org"
)
+3 -31
View File
@@ -56,9 +56,6 @@ const int kErrorLength = 1024; // load error string length
mjModel* m = nullptr;
mjData* d = nullptr;
// control noise variables
mjtNum* ctrlnoise = nullptr;
using Seconds = std::chrono::duration<double>;
@@ -278,10 +275,6 @@ void PhysicsLoop(mj::Simulate& sim) {
d = dnew;
mj_forward(m, d);
// allocate ctrlnoise
free(ctrlnoise);
ctrlnoise = (mjtNum*) malloc(sizeof(mjtNum)*m->nu);
mju_zero(ctrlnoise, m->nu);
} else {
sim.LoadMessageClear();
}
@@ -306,10 +299,6 @@ void PhysicsLoop(mj::Simulate& sim) {
d = dnew;
mj_forward(m, d);
// allocate ctrlnoise
free(ctrlnoise);
ctrlnoise = static_cast<mjtNum*>(malloc(sizeof(mjtNum)*m->nu));
mju_zero(ctrlnoise, m->nu);
} else {
sim.LoadMessageClear();
}
@@ -340,21 +329,6 @@ void PhysicsLoop(mj::Simulate& sim) {
const auto elapsedCPU = startCPU - syncCPU;
double elapsedSim = d->time - syncSim;
// inject noise
if (sim.ctrl_noise_std) {
// convert rate and scale to discrete time (OrnsteinUhlenbeck)
mjtNum rate = mju_exp(-m->opt.timestep / mju_max(sim.ctrl_noise_rate, mjMINVAL));
mjtNum scale = sim.ctrl_noise_std * mju_sqrt(1-rate*rate);
for (int i=0; i<m->nu; i++) {
// update noise
ctrlnoise[i] = rate * ctrlnoise[i] + scale * mju_standardNormal(nullptr);
// apply noise
d->ctrl[i] = ctrlnoise[i];
}
}
// requested slow-down factor
double slowdown = 100 / sim.percentRealTime[sim.real_time_index];
@@ -392,6 +366,9 @@ void PhysicsLoop(mj::Simulate& sim) {
measured = true;
}
// inject noise
sim.InjectNoise();
// call mj_step
mj_step(m, d);
stepped = true;
@@ -442,10 +419,6 @@ void PhysicsThread(mj::Simulate* sim, const char* filename) {
mj_forward(m, d);
// allocate ctrlnoise
free(ctrlnoise);
ctrlnoise = static_cast<mjtNum*>(malloc(sizeof(mjtNum)*m->nu));
mju_zero(ctrlnoise, m->nu);
} else {
sim->LoadMessageClear();
}
@@ -454,7 +427,6 @@ void PhysicsThread(mj::Simulate* sim, const char* filename) {
PhysicsLoop(*sim);
// delete everything we allocated
free(ctrlnoise);
mj_deleteData(d);
mj_deleteModel(m);
}
+37 -10
View File
@@ -887,14 +887,15 @@ void MakeVisualizationSection(mj::Simulate* sim, const mjModel* m, int oldstate)
{mjITEM_EDITFLOAT, "Ambient", 2, &(vis->headlight.ambient), "3"},
{mjITEM_EDITFLOAT, "Diffuse", 2, &(vis->headlight.diffuse), "3"},
{mjITEM_EDITFLOAT, "Specular", 2, &(vis->headlight.specular), "3"},
{mjITEM_SEPARATOR, "Initial Free Camera", 1},
{mjITEM_SEPARATOR, "Free Camera", 1},
{mjITEM_RADIO, "Orthographic", 2, &(vis->global.orthographic), "No\nYes"},
{mjITEM_EDITFLOAT, "Field of view", 2, &(vis->global.fovy), "1"},
{mjITEM_EDITNUM, "Center", 2, &(stat->center), "3"},
{mjITEM_EDITFLOAT, "Azimuth", 2, &(vis->global.azimuth), "1"},
{mjITEM_EDITFLOAT, "Elevation", 2, &(vis->global.elevation), "1"},
{mjITEM_BUTTON, "Align", 2, nullptr, "CA"},
{mjITEM_SEPARATOR, "Global", 1},
{mjITEM_EDITNUM, "Extent", 2, &(stat->extent), "1"},
{mjITEM_EDITFLOAT, "Field of view", 2, &(vis->global.fovy), "1"},
{mjITEM_RADIO, "Inertia", 5, &(vis->global.ellipsoidinertia), "Box\nEllipsoid"},
{mjITEM_RADIO, "BVH active", 5, &(vis->global.bvactive), "False\nTrue"},
{mjITEM_SEPARATOR, "Map", 1},
@@ -1977,14 +1978,7 @@ void Simulate::Sync() {
}
if (pending_.save_key) {
int i = this->key;
m_->key_time[i] = d_->time;
mju_copy(m_->key_qpos + i*m_->nq, d_->qpos, m_->nq);
mju_copy(m_->key_qvel + i*m_->nv, d_->qvel, m_->nv);
mju_copy(m_->key_act + i*m_->na, d_->act, m_->na);
mju_copy(m_->key_mpos + i*3*m_->nmocap, d_->mocap_pos, 3*m_->nmocap);
mju_copy(m_->key_mquat + i*4*m_->nmocap, d_->mocap_quat, 4*m_->nmocap);
mju_copy(m_->key_ctrl + i*m_->nu, d_->ctrl, m_->nu);
mj_setKeyframe(m_, d_, this->key);
pending_.save_key = false;
}
@@ -2747,6 +2741,39 @@ void Simulate::AddToHistory() {
mj_getState(m_, d_, state, mjSTATE_INTEGRATION);
}
// inject Brownian noise
void Simulate::InjectNoise() {
// no noise, return
if (ctrl_noise_std <= 0) {
return;
}
// convert rate and scale to discrete time (OrnsteinUhlenbeck)
mjtNum rate = mju_exp(-m_->opt.timestep / ctrl_noise_rate);
mjtNum scale = ctrl_noise_std * mju_sqrt(1-rate*rate);
for (int i=0; i<m_->nu; i++) {
mjtNum bottom = 0, top = 0, midpoint = 0, halfrange = 1;
if (m_->actuator_ctrllimited[i]) {
bottom = m_->actuator_ctrlrange[2*i];
top = m_->actuator_ctrlrange[2*i+1];
midpoint = 0.5 * (top + bottom); // target of exponential decay
halfrange = 0.5 * (top - bottom); // scales noise
}
// exponential convergence to midpoint at ctrl_noise_rate
d_->ctrl[i] = rate * d_->ctrl[i] + (1-rate) * midpoint;
// add noise
d_->ctrl[i] += scale * halfrange * mju_standardNormal(nullptr);
// clip to range if limited
if (m_->actuator_ctrllimited[i]) {
d_->ctrl[i] = mju_clip(d_->ctrl[i], bottom, top);
}
}
}
void Simulate::UpdateHField(int hfieldid) {
MutexLock lock(this->mtx);
if (!m_ || hfieldid < 0 || hfieldid >= m_->nhfield) {
+5 -2
View File
@@ -86,6 +86,9 @@ class Simulate {
// add state to history buffer
void AddToHistory();
// inject control noise
void InjectNoise();
// constants
static constexpr int kMaxFilenameLength = 1000;
@@ -293,8 +296,8 @@ class Simulate {
{mjITEM_SLIDERINT, "Key", 3, &this->key, "0 0"},
{mjITEM_BUTTON, "Load key", 3},
{mjITEM_BUTTON, "Save key", 3},
{mjITEM_SLIDERNUM, "Noise scale", 5, &this->ctrl_noise_std, "0 2"},
{mjITEM_SLIDERNUM, "Noise rate", 5, &this->ctrl_noise_rate, "0 2"},
{mjITEM_SLIDERNUM, "Noise scale", 5, &this->ctrl_noise_std, "0 1"},
{mjITEM_SLIDERNUM, "Noise rate", 5, &this->ctrl_noise_rate, "0 4"},
{mjITEM_SEPARATOR, "History", 1},
{mjITEM_SLIDERINT, "", 5, &this->scrub_index, "0 0"},
{mjITEM_END}
+16 -16
View File
@@ -48,7 +48,7 @@ int mjraw_SphereBox(mjContact* con, mjtNum margin,
mjtNum dist, closest;
mju_sub3(tmp, pos1, pos2);
mju_rotVecMatT(center, tmp, mat2);
mju_mulMatTVec3(center, mat2, tmp);
mju_copy(clamped, center, 3);
mju_clampVec(clamped, size2, 3);
@@ -76,16 +76,16 @@ int mjraw_SphereBox(mjContact* con, mjtNum margin,
mju_copy3(pos, center);
mju_addToScl3(pos, nearest, (size1[0] - closest) / 2);
mju_rotVecMat(con[0].frame, nearest, mat2);
mju_mulMatVec3(con[0].frame, mat2, nearest);
} else {
mju_addToScl3(deepest, tmp, size1[0]);
mju_zero3(pos);
mju_addToScl3(pos, clamped, 0.5);
mju_addToScl3(pos, deepest, 0.5);
mju_rotVecMat(con[0].frame, tmp, mat2);
mju_mulMatVec3(con[0].frame, mat2, tmp);
}
mju_rotVecMat(tmp, pos, mat2);
mju_mulMatVec3(tmp, mat2, pos);
mju_add3(con[0].pos, tmp, pos2);
con[0].dist = dist - size1[0];
mju_zero3(con[0].frame + 3);
@@ -153,13 +153,13 @@ int mjraw_CapsuleBox(mjContact* con, mjtNum margin,
secondpos = -4; // initialize to no 2nd contact (valid values are between -1 and 1)
mju_sub3(tmp1, pos1, pos2); // bring capsule to box-local frame (center's box is at (0,0,0))
mju_rotVecMatT(pos, tmp1, mat2); // and axis parralel to world
mju_mulMatTVec3(pos, mat2, tmp1); // and axis parralel to world
tmp1[0] = mat1[2]; // capsule's axis
tmp1[1] = mat1[5];
tmp1[2] = mat1[8];
mju_rotVecMatT(axis, tmp1, mat2); // do the same for the capsule axis
mju_mulMatTVec3(axis, mat2, tmp1); // do the same for the capsule axis
mju_scl3(halfaxis, axis, halflength); // scale to get actual capsule half-axis
axisdir = 0;
@@ -576,7 +576,7 @@ skip:
// create sphere in original orientation at first contact point
mju_copy3(tmp1, pos);
mju_addToScl3(tmp1, halfaxis, bestsegmentpos);
mju_rotVecMat(tmp2, tmp1, mat2);
mju_mulMatVec3(tmp2, mat2, tmp1);
mju_addTo3(tmp2, pos2);
// collide with
@@ -586,7 +586,7 @@ skip:
if (secondpos > -3) { // secondpos was modified
mju_copy3(tmp1, pos);
mju_addToScl3(tmp1, halfaxis, secondpos + bestsegmentpos); // note the summation
mju_rotVecMat(tmp2, tmp1, mat2);
mju_mulMatVec3(tmp2, mat2, tmp1);
mju_addTo3(tmp2, pos2);
n += mjraw_SphereBox(con + n, margin, tmp2, mat1, size1, pos2, mat2, size2);
}
@@ -633,10 +633,10 @@ int mjc_BoxBox(const mjModel* M, const mjData* D, mjContact* con, int g1, int g2
margin2 = margin * margin;
mju_sub3(tmp1, pos2, pos1);
mju_rotVecMatT(pos21, tmp1, mat1);
mju_mulMatTVec3(pos21, mat1, tmp1);
mju_sub3(tmp1, pos1, pos2);
mju_rotVecMatT(pos12, tmp1, mat2);
mju_mulMatTVec3(pos12, mat2, tmp1);
mju_mulMatTMat3(rot, mat1, mat2);
mju_transpose(rott, rot, 3, 3);
@@ -646,8 +646,8 @@ int mjc_BoxBox(const mjModel* M, const mjData* D, mjContact* con, int g1, int g2
for (i = 0; i < 9; i++)
rottabs[i] = fabs(rott[i]);
mju_rotVecMat(plen2, size2, rotabs);
mju_rotVecMatT(plen1, size1, rotabs);
mju_mulMatVec3(plen2, rotabs, size2);
mju_mulMatTVec3(plen1, rotabs, size1);
for (i = 0, penetration = margin; i < 3; i++)
penetration += size1[i] * 3 + size2[i] * 3;
@@ -974,7 +974,7 @@ int mjc_BoxBox(const mjModel* M, const mjData* D, mjContact* con, int g1, int g2
con[i].dist = points[i][2];
points[i][2] += hz;
mju_rotVecMat(tmp2, points[i], r);
mju_mulMatVec3(tmp2, r, points[i]);
mju_add3(con[i].pos, tmp2, p);
if (i)
@@ -1084,7 +1084,7 @@ edgeedge:
// mju_mulMatMat(r,rotmore,rot,3,3,3);
rotmatx(r, rot);
mju_rotVecMatT(tmp1, size1, rotmore);
mju_mulMatTVec3(tmp1, rotmore, size1);
for (i = 0; i < 3; i++)
s[i] = mju_abs(tmp1[i]);
@@ -1321,7 +1321,7 @@ edgeedge:
mju_mulMatMatT3(r, mat1, rotmore);
mju_rotVecMat(tmp1, rnorm, r);
mju_mulMatVec3(tmp1, r, rnorm);
mju_scl3(con[0].frame, tmp1, in ? -1 : 1);
mju_zero3(con[0].frame + 3);
@@ -1331,7 +1331,7 @@ edgeedge:
con[i].dist = depth[i];
points[i][2] += hz;
mju_rotVecMat(tmp2, points[i], r);
mju_mulMatVec3(tmp2, r, points[i]);
mju_add3(con[i].pos, tmp2, pos1);
+12 -12
View File
@@ -115,7 +115,7 @@ void mjccd_support(const void *obj, const ccd_vec3_t *_dir, ccd_vec3_t *vec) {
mjtNum res[3]; // result in geom local frame
// rotate dir to geom local frame
mju_rotVecMatT(dir, _dir->v, d->geom_xmat+9*g);
mju_mulMatTVec3(dir, d->geom_xmat+9*g, _dir->v);
// compute result according to geom type
switch ((mjtGeom) m->geom_type[g]) {
@@ -261,7 +261,7 @@ void mjccd_support(const void *obj, const ccd_vec3_t *_dir, ccd_vec3_t *vec) {
}
// rotate result to global frame
mju_rotVecMat(vec->v, res, d->geom_xmat+9*g);
mju_mulMatVec3(vec->v, d->geom_xmat+9*g, res);
// add geom position
mju_addTo3(vec->v, d->geom_xpos+3*g);
@@ -338,7 +338,7 @@ static void mju_rotateFrame(const mjtNum origin[3], const mjtNum rot[9],
mju_sub3(rel, origin, xpos);
// displacement of origin due to rotation: vec = rot*rel - rel
mju_rotVecMat(vec, rel, rot);
mju_mulMatVec3(vec, rot, rel);
mju_subFrom3(vec, rel);
// correct xpos by subtracting displacement: xpos = xpos - vec
@@ -446,7 +446,7 @@ static int addplanemesh(mjContact* con, const float vertex[3],
const mjtNum first[3], mjtNum rbound) {
// compute point in global coordinates
mjtNum pnt[3], v[3] = {vertex[0], vertex[1], vertex[2]};
mju_rotVecMat(pnt, v, mat2);
mju_mulMatVec3(pnt, mat2, v);
mju_addTo3(pnt, pos2);
// skip if too close to first contact
@@ -517,7 +517,7 @@ int mjc_PlaneConvex(const mjModel* m, const mjData* d,
// express dir in geom local frame
mjtNum locdir[3];
mju_rotVecMatT(locdir, dir.v, d->geom_xmat+9*g);
mju_mulMatTVec3(locdir, d->geom_xmat+9*g, dir.v);
// inclusion threshold along locdir, relative to geom2 center
mju_sub3(dif, pos2, pos1);
@@ -797,8 +797,8 @@ int mjc_ConvexHField(const mjModel* m, const mjData* d,
!ccdVec3Eq(&dirccd, ccd_vec3_origin)) {
// fill in contact data, transform to global coordinates
con[cnt].dist = -depth;
mju_rotVecMat(con[cnt].frame, dirccd.v, mat1);
mju_rotVecMat(con[cnt].pos, vecccd.v, mat1);
mju_mulMatVec3(con[cnt].frame, mat1, dirccd.v);
mju_mulMatVec3(con[cnt].pos, mat1, vecccd.v);
mju_addTo3(con[cnt].pos, pos1);
mju_zero3(con[cnt].frame+3);
@@ -979,8 +979,8 @@ void mjc_fixNormal(const mjModel* m, const mjData* d, mjContact* con, int g1, in
// map contact point and normal to local frame
mjtNum dif[3], pos[3], nrm[3];
mju_sub3(dif, con->pos, d->geom_xpos+3*gid[i]);
mju_rotVecMatT(pos, dif, mat);
mju_rotVecMatT(nrm, normal[i], mat);
mju_mulMatTVec3(pos, mat, dif);
mju_mulMatTVec3(nrm, mat, normal[i]);
// process according to type
switch (type[i]) {
@@ -1059,7 +1059,7 @@ void mjc_fixNormal(const mjModel* m, const mjData* d, mjContact* con, int g1, in
// normalize and map normal to global frame
if (processed[i]) {
mju_normalize3(nrm);
mju_rotVecMat(normal[i], nrm, mat);
mju_mulMatVec3(normal[i], mat, nrm);
}
}
}
@@ -1242,8 +1242,8 @@ int mjc_HFieldElem(const mjModel* m, const mjData* d, mjContact* con,
if (!ccdVec3Eq(&dirccd, ccd_vec3_origin)) {
// fill in contact data, transform to global coordinates
con[cnt].dist = -depth;
mju_rotVecMat(con[cnt].frame, dirccd.v, hmat);
mju_rotVecMat(con[cnt].pos, vecccd.v, hmat);
mju_mulMatVec3(con[cnt].frame, hmat, dirccd.v);
mju_mulMatVec3(con[cnt].pos, hmat, vecccd.v);
mju_addTo3(con[cnt].pos, hpos);
mju_zero3(con[cnt].frame+3);
+1 -1
View File
@@ -553,7 +553,7 @@ int mj_collideOBB(const mjtNum aabb1[6], const mjtNum aabb2[6],
for (int i=0; i < 2; i++) { // bounding boxes
for (int j=0; j < 3; j++) { // axes
if (xmat[i]) {
mju_rotVecMat(xcenter[i], aabb[i], xmat[i]);
mju_mulMatVec3(xcenter[i], xmat[i], aabb[i]);
} else {
mju_copy3(xcenter[i], aabb[i]);
}
+1 -1
View File
@@ -219,7 +219,7 @@ int mjc_PlaneBox(const mjModel* m, const mjData* d,
// get corner in global coordinates relative to box center
mjtNum corner[3];
mju_rotVecMat(corner, vec, mat2);
mju_mulMatVec3(corner, mat2, vec);
// compute distance to plane, skip if too far or pointing up
mjtNum ldist = mju_dot3(norm, corner);
+14 -14
View File
@@ -191,17 +191,17 @@ mjtNum mjc_distance(const mjModel* m, const mjData* d, const mjSDF* s, const mjt
case mjSDFTYPE_SINGLE:
return geomDistance(m, d, s->plugin[0], s->id[0], x, s->geomtype[0]);
case mjSDFTYPE_INTERSECTION:
mju_rotVecMat(y, x, s->relmat);
mju_mulMatVec3(y, s->relmat, x);
mju_addTo3(y, s->relpos);
return mju_max(geomDistance(m, d, s->plugin[0], s->id[0], x, s->geomtype[0]),
geomDistance(m, d, s->plugin[1], s->id[1], y, s->geomtype[1]));
case mjSDFTYPE_MIDSURFACE:
mju_rotVecMat(y, x, s->relmat);
mju_mulMatVec3(y, s->relmat, x);
mju_addTo3(y, s->relpos);
return geomDistance(m, d, s->plugin[0], s->id[0], x, s->geomtype[0]) -
geomDistance(m, d, s->plugin[1], s->id[1], y, s->geomtype[1]);
case mjSDFTYPE_COLLISION:
mju_rotVecMat(y, x, s->relmat);
mju_mulMatVec3(y, s->relmat, x);
mju_addTo3(y, s->relpos);
mjtNum A = geomDistance(m, d, s->plugin[0], s->id[0], x, s->geomtype[0]);
mjtNum B = geomDistance(m, d, s->plugin[1], s->id[1], y, s->geomtype[1]);
@@ -221,34 +221,34 @@ void mjc_gradient(const mjModel* m, const mjData* d, const mjSDF* s,
switch (s->type) {
case mjSDFTYPE_INTERSECTION:
mju_rotVecMat(y, x, s->relmat);
mju_mulMatVec3(y, s->relmat, x);
mju_addTo3(y, s->relpos);
int i = geomDistance(m, d, s->plugin[0], s->id[0], x, s->geomtype[0]) >
geomDistance(m, d, s->plugin[1], s->id[1], y, s->geomtype[1]) ? 0 : 1;
geomGradient(gradient, m, d, s->plugin[i], s->id[i], point[i], s->geomtype[i]);
if (i == 1) {
mju_rotVecMatT(gradient, gradient, s->relmat);
mju_mulMatTVec3(gradient, s->relmat, gradient);
}
break;
case mjSDFTYPE_MIDSURFACE:
mju_rotVecMat(y, x, s->relmat);
mju_mulMatVec3(y, s->relmat, x);
mju_addTo3(y, s->relpos);
geomGradient(grad1, m, d, s->plugin[0], s->id[0], x, s->geomtype[0]);
mju_normalize3(grad1);
geomGradient(grad2, m, d, s->plugin[1], s->id[1], y, s->geomtype[1]);
mju_rotVecMatT(grad2, grad2, s->relmat);
mju_mulMatTVec3(grad2, s->relmat, grad2);
mju_normalize3(grad2);
mju_sub3(gradient, grad1, grad2);
mju_normalize3(gradient);
break;
case mjSDFTYPE_COLLISION:
mju_rotVecMat(y, x, s->relmat);
mju_mulMatVec3(y, s->relmat, x);
mju_addTo3(y, s->relpos);
mjtNum A = geomDistance(m, d, s->plugin[0], s->id[0], x, s->geomtype[0]);
mjtNum B = geomDistance(m, d, s->plugin[1], s->id[1], y, s->geomtype[1]);
geomGradient(grad1, m, d, s->plugin[0], s->id[0], x, s->geomtype[0]);
geomGradient(grad2, m, d, s->plugin[1], s->id[1], y, s->geomtype[1]);
mju_rotVecMatT(grad2, grad2, s->relmat);
mju_mulMatTVec3(grad2, s->relmat, grad2);
gradient[0] = grad1[0] + grad2[0];
gradient[1] = grad1[1] + grad2[1];
gradient[2] = grad1[2] + grad2[2];
@@ -487,7 +487,7 @@ static int boxIntersect(const mjtNum bvh[6], const mjtNum offset[3],
mjtNum candidate[3];
mjtNum r = mju_norm3(bvh+3);
mju_rotVecMat(candidate, bvh, rotation);
mju_mulMatVec3(candidate, rotation, bvh);
mju_addTo3(candidate, offset);
// check if inside the bounding box
@@ -613,7 +613,7 @@ int mjc_MeshSDF(const mjModel* m, const mjData* d, mjContact* con, int g1, int g
};
// transform local 1 (mesh) to local 2 (sdf)
mju_rotVecMat(corners+3*v, vec, rotation);
mju_mulMatVec3(corners+3*v, rotation, vec);
mju_addTo3(corners+3*v, offset);
}
@@ -694,7 +694,7 @@ int mjc_SDF(const mjModel* m, const mjData* d, mjContact* con, int g1, int g2, m
vec2[1] = (i&2 ? size2[1]+size2[4] : size2[1]-size2[4]);
vec2[2] = (i&4 ? size2[2]+size2[5] : size2[2]-size2[5]);
mju_rotVecMat(vec2, vec2, rotation1);
mju_mulMatVec3(vec2, rotation1, vec2);
mju_addTo3(vec2, offset1);
for (int k=0; k < 3; k++) {
@@ -753,10 +753,10 @@ int mjc_SDF(const mjModel* m, const mjData* d, mjContact* con, int g1, int g2, m
x[1] = aabb[1] + (aabb[4]-aabb[1]) * mju_Halton(j, 3);
x[2] = aabb[2] + (aabb[5]-aabb[2]) * mju_Halton(j, 5);
mju_rotVecMat(y, x, rotation2);
mju_mulMatVec3(y, rotation2, x);
mju_addTo3(y, offset2);
mju_rotVecMat(x, y, rotation12);
mju_mulMatVec3(x, rotation12, y);
mju_addTo3(x, offset12);
j++;
+2 -2
View File
@@ -511,7 +511,7 @@ void mj_instantiateEquality(const mjModel* m, mjData* d) {
case mjEQ_CONNECT: // connect bodies with ball joint
// find global points
for (int j=0; j < 2; j++) {
mju_rotVecMat(pos[j], data + 3*j, d->xmat + 9*id[j]);
mju_mulMatVec3(pos[j], d->xmat + 9*id[j], data + 3*j);
mju_addTo3(pos[j], d->xpos + 3*id[j]);
}
@@ -532,7 +532,7 @@ void mj_instantiateEquality(const mjModel* m, mjData* d) {
// find global points
for (int j=0; j < 2; j++) {
mjtNum* anchor = data + 3*(1-j);
mju_rotVecMat(pos[j], anchor, d->xmat + 9*id[j]);
mju_mulMatVec3(pos[j], d->xmat + 9*id[j], anchor);
mju_addTo3(pos[j], d->xpos + 3*id[j]);
}
+11 -11
View File
@@ -88,7 +88,7 @@ void mj_kinematics(const mjModel* m, mjData* d) {
// apply fixed translation and rotation relative to parent
if (pid) {
mju_rotVecMat(xpos, bodypos, d->xmat+9*pid);
mju_mulMatVec3(xpos, d->xmat+9*pid, bodypos);
mju_addTo3(xpos, d->xpos+3*pid);
mju_mulQuat(xquat, d->xquat+4*pid, bodyquat);
} else {
@@ -464,7 +464,7 @@ void mj_flex(const mjModel* m, mjData* d) {
// non-centered: map from local to global
else {
for (int i=vstart; i < vend; i++) {
mju_rotVecMat(d->flexvert_xpos+3*i, m->flex_vert+3*i, d->xmat+9*m->flex_vertbodyid[i]);
mju_mulMatVec3(d->flexvert_xpos+3*i, d->xmat+9*m->flex_vertbodyid[i], m->flex_vert+3*i);
mju_addTo3(d->flexvert_xpos+3*i, d->xpos+3*m->flex_vertbodyid[i]);
}
}
@@ -1022,8 +1022,8 @@ void mj_transmission(const mjModel* m, mjData* d) {
// reference site undefined
if (m->actuator_trnid[2*i+1] == -1) {
// wrench: gear expressed in global frame
mju_rotVecMat(wrench, gear, d->site_xmat+9*id); // translation
mju_rotVecMat(wrench+3, gear+3, d->site_xmat+9*id); // rotation
mju_mulMatVec3(wrench, d->site_xmat+9*id, gear); // translation
mju_mulMatVec3(wrench+3, d->site_xmat+9*id, gear+3); // rotation
// moment: global Jacobian projected on wrench
mju_mulMatTVec(moment+i*nv, jac, wrench, 3, nv); // translation
@@ -1071,7 +1071,7 @@ void mj_transmission(const mjModel* m, mjData* d) {
if (!mju_isZero(gear, 3)) {
// vec: site position in reference site frame
mju_sub3(vec, d->site_xpos+3*id, d->site_xpos+3*refid);
mju_rotVecMatT(vec, vec, d->site_xmat+9*refid);
mju_mulMatTVec3(vec, d->site_xmat+9*refid, vec);
// length: dot product with gear
length[i] += mju_dot3(vec, gear);
@@ -1092,7 +1092,7 @@ void mj_transmission(const mjModel* m, mjData* d) {
}
// wrench: translational gear expressed in global frame
mju_rotVecMat(wrench, gear, d->site_xmat+9*refid);
mju_mulMatVec3(wrench, d->site_xmat+9*refid, gear);
// moment: global Jacobian projected on wrench
mju_mulMatTVec(moment+i*nv, jac, wrench, 3, nv);
@@ -1128,7 +1128,7 @@ void mj_transmission(const mjModel* m, mjData* d) {
}
// wrench: rotational gear expressed in global frame
mju_rotVecMat(wrench, gear+3, d->site_xmat+9*refid);
mju_mulMatVec3(wrench, d->site_xmat+9*refid, gear+3);
// moment_tmp: global Jacobian projected on wrench, add to moment
if (!moment_tmp) moment_tmp = mj_stackAllocNum(d, nv);
@@ -1691,11 +1691,11 @@ void mj_subtreeVel(const mjModel* m, mjData* d) {
mju_scl3(d->subtree_linvel+3*i, body_vel+6*i+3, m->body_mass[i]);
// body angular momentum
mju_rotVecMatT(dv, body_vel+6*i, d->ximat+9*i);
mju_mulMatTVec3(dv, d->ximat+9*i, body_vel+6*i);
dv[0] *= m->body_inertia[3*i];
dv[1] *= m->body_inertia[3*i+1];
dv[2] *= m->body_inertia[3*i+2];
mju_rotVecMat(d->subtree_angmom+3*i, dv, d->ximat+9*i);
mju_mulMatVec3(d->subtree_angmom+3*i, d->ximat+9*i, dv);
}
// subtree linvel
@@ -1838,8 +1838,8 @@ void mj_rnePostConstraint(const mjModel* m, mjData* d) {
mj_contactForce(m, d, i, lfrc);
// cfrc = world-oriented torque:force vector (swap in the process)
mju_rotVecMatT(cfrc, lfrc+3, con->frame);
mju_rotVecMatT(cfrc+3, lfrc, con->frame);
mju_mulMatTVec3(cfrc, con->frame, lfrc+3);
mju_mulMatTVec3(cfrc+3, con->frame, lfrc);
// body 1
int k;
+1 -1
View File
@@ -320,7 +320,7 @@ void mjd_quatIntegrate(const mjtNum vel[3], mjtNum scale,
if (Dvel || Dscale) Dvel_[i] = b*eye[i] + c*cross[i] + d*outer[i];
}
if (Dvel) mju_copy(Dvel, Dvel_, 9);
if (Dscale) mju_rotVecMat(Dscale, vel, Dvel_);
if (Dscale) mju_mulMatVec3(Dscale, Dvel_, vel);
}
+5 -4
View File
@@ -182,6 +182,7 @@ static void setf4(float* rgba, float r, float g, float b, float a) {
// set visual options to default values
void mj_defaultVisual(mjVisual* vis) {
// global
vis->global.orthographic = 0;
vis->global.fovy = 45;
vis->global.ipd = 0.068;
vis->global.azimuth = 90;
@@ -257,7 +258,7 @@ void mj_defaultVisual(mjVisual* vis) {
setf4(vis->rgba.actuatornegative, .2, .6, .9, 1.);
setf4(vis->rgba.actuatorpositive, .9, .4, .2, 1.);
setf4(vis->rgba.com, .9, .9, .9, 1.);
setf4(vis->rgba.camera, .6, .9, .6, .3);
setf4(vis->rgba.camera, .6, .9, .6, 1);
setf4(vis->rgba.light, .6, .6, .9, 1.);
setf4(vis->rgba.selectpoint, .9, .9, .1, 1.);
setf4(vis->rgba.connect, .2, .2, .8, 1.);
@@ -1093,7 +1094,7 @@ static void mj_setPtrData(const mjModel* m, mjData* d) {
// initialize plugins, copy into d (required for deletion)
static void _initPlugin(const mjModel* m, mjData* d) {
void mj_initPlugin(const mjModel* m, mjData* d) {
d->nplugin = m->nplugin;
for (int i = 0; i < m->nplugin; ++i) {
d->plugin[i] = m->plugin[i];
@@ -1203,7 +1204,7 @@ mjData* mj_makeData(const mjModel* m) {
mjData* d = NULL;
mj_makeRawData(&d, m);
if (d) {
_initPlugin(m, d);
mj_initPlugin(m, d);
mj_resetData(m, d);
}
return d;
@@ -1219,7 +1220,7 @@ mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src) {
// allocate new data if needed
if (!dest) {
mj_makeRawData(&dest, m);
_initPlugin(m, dest);
mj_initPlugin(m, dest);
}
// check sizes
+3
View File
@@ -110,6 +110,9 @@ MJAPI void mj_resetDataKeyframe(const mjModel* m, mjData* d, int key);
// mjData arena allocate
MJAPI void* mj_arenaAllocByte(mjData* d, size_t bytes, size_t alignment);
// init plugins
MJAPI void mj_initPlugin(const mjModel* m, mjData* d);
#ifndef ADDRESS_SANITIZER
// mjData mark stack frame
+4 -4
View File
@@ -371,8 +371,8 @@ void mj_inertiaBoxFluidModel(const mjModel* m, mjData* d, int i) {
mju_abs(lvel[2])*lvel[2]/64.0;
}
// rotate to global orientation: lfrc -> bfrc
mju_rotVecMat(bfrc, lfrc, d->ximat+9*i);
mju_rotVecMat(bfrc+3, lfrc+3, d->ximat+9*i);
mju_mulMatVec3(bfrc, d->ximat+9*i, lfrc);
mju_mulMatVec3(bfrc+3, d->ximat+9*i, lfrc+3);
// apply force and torque to body com
mj_applyFT(m, d, bfrc+3, bfrc, d->xipos+3*i, i, d->qfrc_fluid);
@@ -431,8 +431,8 @@ void mj_ellipsoidFluidModel(const mjModel* m, mjData* d, int bodyid) {
mju_scl(lfrc, lfrc, geom_interaction_coef, 6);
// rotate to global orientation: lfrc -> bfrc
mju_rotVecMat(bfrc, lfrc, d->geom_xmat + 9*geomid);
mju_rotVecMat(bfrc+3, lfrc+3, d->geom_xmat + 9*geomid);
mju_mulMatVec3(bfrc, d->geom_xmat + 9*geomid, lfrc);
mju_mulMatVec3(bfrc+3, d->geom_xmat + 9*geomid, lfrc+3);
// apply force and torque to body com
mj_applyFT(m, d, bfrc+3, bfrc,
+2 -2
View File
@@ -1122,7 +1122,7 @@ static int point_in_box(const mjtNum aabb[6], const mjtNum xpos[3],
// compute point in local coordinates of the box
mju_sub3(point, pnt, xpos);
mju_rotVecMatT(point, point, xmat);
mju_mulMatTVec3(point, xmat, point);
mju_subFrom3(point, aabb);
// check intersections
@@ -1238,7 +1238,7 @@ void mju_multiRayPrepare(const mjModel* m, const mjData* d, const mjtNum pnt[3],
vert[2] = (v&4 ? aabb[2]+aabb[5] : aabb[2]-aabb[5]);
// rotate to the world frame
mju_rotVecMat(box, vert, xmat);
mju_mulMatVec3(box, xmat, vert);
mju_addTo3(box, xpos);
// spherical coordinates
+4 -4
View File
@@ -328,12 +328,12 @@ void mj_sensorPos(const mjModel* m, mjData* d) {
get_xpos_xmat(d, reftype, refid, i, &xpos_ref, &xmat_ref);
if (type == mjSENS_FRAMEPOS) {
mju_sub3(rvec, xpos, xpos_ref);
mju_rotVecMatT(d->sensordata+adr, rvec, xmat_ref);
mju_mulMatTVec3(d->sensordata+adr, xmat_ref, rvec);
} else {
// offset = (0 or 1 or 2) for (x or y or z)-axis sensors, respectively
int offset = type - mjSENS_FRAMEXAXIS;
mjtNum axis[3] = {xmat[offset], xmat[offset+3], xmat[offset+6]};
mju_rotVecMatT(d->sensordata+adr, axis, xmat_ref);
mju_mulMatTVec3(d->sensordata+adr, xmat_ref, axis);
}
}
break;
@@ -616,8 +616,8 @@ void mj_sensorVel(const mjModel* m, mjData* d) {
mju_addTo3(rel_vel+3, cross);
// project into reference frame
mju_rotVecMatT(xvel, rel_vel, xmat_ref);
mju_rotVecMatT(xvel+3, rel_vel+3, xmat_ref);
mju_mulMatTVec3(xvel, xmat_ref, rel_vel);
mju_mulMatTVec3(xvel+3, xmat_ref, rel_vel+3);
}
// copy linear or angular component
+2 -2
View File
@@ -291,7 +291,7 @@ static void set0(mjModel* m, mjData* d) {
// data[3-5] = anchor position in body2 local frame
mju_subFrom3(pos, d->xpos+3*id2);
mju_rotVecMatT(m->eq_data+mjNEQDATA*i+3, pos, d->xmat+9*id2);
mju_mulMatTVec3(m->eq_data+mjNEQDATA*i+3, d->xmat+9*id2, pos);
}
// weld constraint
@@ -311,7 +311,7 @@ static void set0(mjModel* m, mjData* d) {
// data[3-5] = anchor position in body1 local frame
mju_subFrom3(pos, d->xpos+3*id1);
mju_rotVecMatT(m->eq_data+mjNEQDATA*i+3, pos, d->xmat+9*id1);
mju_mulMatTVec3(m->eq_data+mjNEQDATA*i+3, d->xmat+9*id1, pos);
// data[6-9] = neg(xquat1)*xquat2 = "xquat2-xquat1" in body1 local frame
mju_negQuat(quat, d->xquat+4*id1);
+25 -3
View File
@@ -39,8 +39,8 @@
//-------------------------- Constants -------------------------------------------------------------
#define mjVERSION 316
#define mjVERSIONSTRING "3.1.6"
#define mjVERSION 317
#define mjVERSIONSTRING "3.1.7"
// names of disable flags
const char* mjDISABLESTRING[mjNDISABLE] = {
@@ -232,6 +232,28 @@ void mj_setState(const mjModel* m, mjData* d, const mjtNum* state, unsigned int
// copy current state to the k-th model keyframe
void mj_setKeyframe(mjModel* m, const mjData* d, int k) {
// check keyframe index
if (k >= m->nkey) {
mjERROR("index must be smaller than %d (keyframes allocated in model)", m->nkey);
}
if (k < 0) {
mjERROR("keyframe index cannot be negative");
}
// copy state to model keyframe
m->key_time[k] = d->time;
mju_copy(m->key_qpos + k*m->nq, d->qpos, m->nq);
mju_copy(m->key_qvel + k*m->nv, d->qvel, m->nv);
mju_copy(m->key_act + k*m->na, d->act, m->na);
mju_copy(m->key_mpos + k*3*m->nmocap, d->mocap_pos, 3*m->nmocap);
mju_copy(m->key_mquat + k*4*m->nmocap, d->mocap_quat, 4*m->nmocap);
mju_copy(m->key_ctrl + k*m->nu, d->ctrl, m->nu);
}
//-------------------------- sparse chains ---------------------------------------------------------
// merge dof chains for two bodies
@@ -1860,7 +1882,7 @@ void mj_local2Global(mjData* d, mjtNum xpos[3], mjtNum xmat[9],
if (xpos && pos) {
// compute
if (sameframe == 0) {
mju_rotVecMat(xpos, pos, d->xmat+9*body);
mju_mulMatVec3(xpos, d->xmat+9*body, pos);
mju_addTo3(xpos, d->xpos+3*body);
}
+2
View File
@@ -43,6 +43,8 @@ MJAPI void mj_getState(const mjModel* m, const mjData* d, mjtNum* state, unsigne
// set state
MJAPI void mj_setState(const mjModel* m, mjData* d, const mjtNum* state, unsigned int spec);
// copy current state to the k-th model keyframe
MJAPI void mj_setKeyframe(mjModel* m, const mjData* d, int k);
//-------------------------- sparse chains ---------------------------------------------------------
+18 -4
View File
@@ -152,8 +152,8 @@ mjtNum mju_dist3(const mjtNum pos1[3], const mjtNum pos2[3]) {
// multiply vector by 3D rotation matrix
void mju_rotVecMat(mjtNum res[3], const mjtNum vec[3], const mjtNum mat[9]) {
// multiply 3-by-3 matrix by vector
void mju_mulMatVec3(mjtNum res[3], const mjtNum mat[9], const mjtNum vec[3]) {
mjtNum tmp[3] = {
mat[0]*vec[0] + mat[1]*vec[1] + mat[2]*vec[2],
mat[3]*vec[0] + mat[4]*vec[1] + mat[5]*vec[2],
@@ -166,8 +166,8 @@ void mju_rotVecMat(mjtNum res[3], const mjtNum vec[3], const mjtNum mat[9]) {
// multiply vector by transposed 3D rotation matrix
void mju_rotVecMatT(mjtNum res[3], const mjtNum vec[3], const mjtNum mat[9]) {
// multiply transposed 3-by-3 matrix by vector
void mju_mulMatTVec3(mjtNum res[3], const mjtNum mat[9], const mjtNum vec[3]) {
mjtNum tmp[3] = {
mat[0]*vec[0] + mat[3]*vec[1] + mat[6]*vec[2],
mat[1]*vec[0] + mat[4]*vec[1] + mat[7]*vec[2],
@@ -180,6 +180,20 @@ void mju_rotVecMatT(mjtNum res[3], const mjtNum vec[3], const mjtNum mat[9]) {
// multiply vector by 3D rotation matrix (deprecated)
void mju_rotVecMat(mjtNum res[3], const mjtNum vec[3], const mjtNum mat[9]) {
mju_mulMatVec3(res, mat, vec);
}
// multiply vector by transposed 3D rotation matrix (deprecated)
void mju_rotVecMatT(mjtNum res[3], const mjtNum vec[3], const mjtNum mat[9]) {
mju_mulMatTVec3(res, mat, vec);
}
// multiply 3x3 matrices,
void mju_mulMatMat3(mjtNum res[9], const mjtNum a[9], const mjtNum b[9]) {
res[0] = a[0]*b[0] + a[1]*b[3] + a[2]*b[6];
+8 -2
View File
@@ -103,10 +103,16 @@ MJAPI mjtNum mju_dot3(const mjtNum vec1[3], const mjtNum vec2[3]);
// Cartesian distance between 3D vectors
MJAPI mjtNum mju_dist3(const mjtNum pos1[3], const mjtNum pos2[3]);
// multiply vector by 3D rotation matrix
// multiply 3-by-3 matrix by vector
MJAPI void mju_mulMatVec3(mjtNum res[3], const mjtNum mat[9], const mjtNum vec[3]);
// multiply transposed 3-by-3 matrix by vector
MJAPI void mju_mulMatTVec3(mjtNum res[3], const mjtNum mat[9], const mjtNum vec[3]);
// multiply vector by 3D rotation matrix (deprecated)
MJAPI void mju_rotVecMat(mjtNum res[3], const mjtNum vec[3], const mjtNum mat[9]);
// multiply vector by transposed 3D rotation matrix
// multiply vector by transposed 3D rotation matrix (deprecated)
MJAPI void mju_rotVecMatT(mjtNum res[3], const mjtNum vec[3], const mjtNum mat[9]);
// multiply 3x3 matrices
+1 -1
View File
@@ -858,7 +858,7 @@ int mju_outsideBox(const mjtNum point[3], const mjtNum pos[3], const mjtNum mat[
// vector from pos to point, projected to box frame
mjtNum vec[3] = {point[0]-pos[0], point[1]-pos[1], point[2]-pos[2]};
mju_rotVecMatT(vec, vec, mat);
mju_mulMatTVec3(vec, mat, vec);
// big: inflated box
mjtNum big[3] = {size[0], size[1], size[2]};
+5 -5
View File
@@ -707,7 +707,7 @@ void mju_solveLUSparse(mjtNum* res, const mjtNum* LU, const mjtNum* vec, int n,
//--------------------------- eigen decomposition --------------------------------------------------
// eigenvalue decomposition of symmetric 3x3 matrix
static const mjtNum eigEPS = 1E-12;
static const mjtNum eigEPS = mjMINVAL * 1000;
int mju_eig3(mjtNum eigval[3], mjtNum eigvec[9], mjtNum quat[4], const mjtNum mat[9]) {
mjtNum D[9], tmp[9];
mjtNum tau, t, c;
@@ -730,11 +730,11 @@ int mju_eig3(mjtNum eigval[3], mjtNum eigvec[9], mjtNum quat[4], const mjtNum ma
eigval[2] = D[8];
// find max off-diagonal element, set indices
if (fabs(D[1]) > fabs(D[2]) && fabs(D[1]) > fabs(D[5])) {
if (mju_abs(D[1]) > mju_abs(D[2]) && mju_abs(D[1]) > mju_abs(D[5])) {
rk = 0; // row
ck = 1; // column
rotk = 2; // rotation axis
} else if (fabs(D[2]) > fabs(D[5])) {
} else if (mju_abs(D[2]) > mju_abs(D[5])) {
rk = 0;
ck = 2;
rotk = 1;
@@ -745,7 +745,7 @@ int mju_eig3(mjtNum eigval[3], mjtNum eigvec[9], mjtNum quat[4], const mjtNum ma
}
// terminate if max off-diagonal element too small
if (fabs(D[3*rk+ck]) < eigEPS) {
if (mju_abs(D[3*rk+ck]) < eigEPS) {
break;
}
@@ -789,7 +789,7 @@ int mju_eig3(mjtNum eigval[3], mjtNum eigvec[9], mjtNum quat[4], const mjtNum ma
eigval[j1+1] = t;
// rotate quaternion
tmp[0] = 0.707106781186548; // mju_cos(pi/4) = mju_sin(pi/4)
tmp[0] = 0.707106781186548; // = cos(pi/4) = sin(pi/4)
tmp[1] = tmp[2] = tmp[3] = 0;
tmp[(j1+2)%3+1] = tmp[0];
mju_mulQuat(quat, quat, tmp);
+3 -3
View File
@@ -471,8 +471,8 @@ void mju_transformSpatial(mjtNum res[6], const mjtNum vec[6], int flg_force,
// apply rotation if provided
if (rotnew2old) {
mju_rotVecMatT(res, tran, rotnew2old);
mju_rotVecMatT(res+3, tran+3, rotnew2old);
mju_mulMatTVec3(res, rotnew2old, tran);
mju_mulMatTVec3(res+3, rotnew2old, tran+3);
}
// otherwise copy
@@ -522,7 +522,7 @@ void mju_euler2Quat(mjtNum quat[4], const mjtNum euler[3], const char* seq) {
}
// init
double tmp[4] = {1, 0, 0, 0};
mjtNum tmp[4] = {1, 0, 0, 0};
// loop over euler angles, accumulate rotations
for (int i=0; i<3; i++) {
+10 -9
View File
@@ -359,15 +359,16 @@ void mjv_defaultCamera(mjvCamera* cam) {
void mjv_defaultFreeCamera(const mjModel* m, mjvCamera* cam) {
memset(cam, 0, sizeof(mjvCamera));
cam->type = mjCAMERA_FREE;
cam->fixedcamid = -1;
cam->trackbodyid = -1;
cam->lookat[0] = m->stat.center[0];
cam->lookat[1] = m->stat.center[1];
cam->lookat[2] = m->stat.center[2];
cam->distance = 1.5 * m->stat.extent;
cam->azimuth = m->vis.global.azimuth;
cam->elevation = m->vis.global.elevation;
cam->type = mjCAMERA_FREE;
cam->fixedcamid = -1;
cam->trackbodyid = -1;
cam->lookat[0] = m->stat.center[0];
cam->lookat[1] = m->stat.center[1];
cam->lookat[2] = m->stat.center[2];
cam->distance = 1.5 * m->stat.extent;
cam->azimuth = m->vis.global.azimuth;
cam->elevation = m->vis.global.elevation;
cam->orthographic = m->vis.global.orthographic;
}
+55 -17
View File
@@ -223,16 +223,29 @@ void mjv_cameraInRoom(mjtNum* headpos, mjtNum* forward, mjtNum* up, const mjvSce
// get frustum height at unit distance from camera; average left and right OpenGL cameras
mjtNum mjv_frustumHeight(const mjvScene* scn) {
mjtNum height;
const mjvGLCamera* cam1 = scn->camera;
const mjvGLCamera* cam2 = scn->camera + 1;
// check znear
if (scn->camera[0].frustum_near < mjMINVAL || scn->camera[1].frustum_near < mjMINVAL) {
mjERROR("mjvScene frustum_near too small");
if (cam1->orthographic != cam2->orthographic) {
mjERROR("cannot average frustums of perspective and orthographic cameras");
}
// add normalized height for left and right cameras
height = (scn->camera[0].frustum_top-scn->camera[0].frustum_bottom)/scn->camera[0].frustum_near +
(scn->camera[1].frustum_top-scn->camera[1].frustum_bottom)/scn->camera[1].frustum_near;
// get height
mjtNum height;
if (!cam1->orthographic) {
// check znear
if (cam1->frustum_near < mjMINVAL || cam2->frustum_near < mjMINVAL) {
mjERROR("mjvScene frustum_near too small");
}
// add normalized height for left and right cameras
height = (cam1->frustum_top - cam1->frustum_bottom) / cam1->frustum_near +
(cam2->frustum_top - cam2->frustum_bottom) / cam2->frustum_near;
} else {
// add height for left and right cameras
height = (cam1->frustum_top - cam1->frustum_bottom) +
(cam2->frustum_top - cam2->frustum_bottom);
}
// average
return 0.5*height;
@@ -337,6 +350,9 @@ void mjv_moveCamera(const mjModel* m, int action, mjtNum reldx, mjtNum reldy,
mju_sub3(dif, cam->lookat, headpos);
scl = mjv_frustumHeight(scn) * mju_dot3(dif, forward);
// multiply by mystery coefficient TODO: b/346130949
if (cam->orthographic) scl *= 0.15;
// move lookat point in opposite direction
mju_addToScl3(cam->lookat, vec, -scl);
break;
@@ -534,7 +550,7 @@ void mjv_initPerturb(const mjModel* m, mjData* d, const mjvScene* scn, mjvPertur
// compute selection point in world coordinates
mjtNum selpos[3];
mju_rotVecMat(selpos, pert->localpos, d->xmat+9*sel);
mju_mulMatVec3(selpos, d->xmat+9*sel, pert->localpos);
mju_addTo3(selpos, d->xpos+3*sel);
// compute average spatial inertia at selection point
@@ -563,6 +579,9 @@ void mjv_initPerturb(const mjModel* m, mjData* d, const mjvScene* scn, mjvPertur
mju_sub3(dif, pert->refselpos, headpos);
pert->scale = mjv_frustumHeight(scn) * mju_dot3(dif, forward);
// multiply by mystery coefficient TODO: b/346130949
if (scn->camera[0].orthographic) pert->scale *= 0.15;
mj_freeStack(d);
}
@@ -648,7 +667,7 @@ void mjv_applyPerturbForce(const mjModel* m, mjData* d, const mjvPerturb* pert)
if (((pert->active | pert->active2) & mjPERT_TRANSLATE)) {
// compute selection point in world coordinates
mjtNum selpos[3];
mju_rotVecMat(selpos, pert->localpos, d->xmat+9*sel);
mju_mulMatVec3(selpos, d->xmat+9*sel, pert->localpos);
mju_addTo3(selpos, d->xpos+3*sel);
// displacement of selection point from reference point
@@ -733,6 +752,12 @@ mjvGLCamera mjv_averageCamera(const mjvGLCamera* cam1, const mjvGLCamera* cam2)
cam.frustum_near = 0.5f * (cam1->frustum_near + cam2->frustum_near);
cam.frustum_far = 0.5f * (cam1->frustum_far + cam2->frustum_far);
if (cam1->orthographic != cam2->orthographic) {
mjERROR("cannot average perspective and orthographic cameras");
} else {
cam.orthographic = cam1->orthographic;
}
return cam;
}
@@ -755,17 +780,31 @@ int mjv_select(const mjModel* m, const mjData* d, const mjvOption* vopt,
// compute frustum halfwidth so as to match viewport aspect ratio
mjtNum halfwidth = 0.5*aspectratio*(cam.frustum_top - cam.frustum_bottom);
// construct ray
// compute up and left offsets from normalized cursor
mjtNum d_up = cam.frustum_bottom + rely*(cam.frustum_top-cam.frustum_bottom);
mjtNum d_left = -(cam.frustum_center + (2*relx-1)*halfwidth);
// define ray
mjtNum ray[3];
mju_scl3(ray, forward, cam.frustum_near);
mju_addToScl3(ray, up, cam.frustum_bottom + rely*(cam.frustum_top-cam.frustum_bottom));
mju_addToScl3(ray, left, -(cam.frustum_center + (2*relx-1)*halfwidth));
mju_normalize3(ray);
// construct ray for orthographic camera: fixed direction, modify pos
if (cam.orthographic) {
mju_copy3(ray, forward);
mju_addToScl3(pos, up, d_up);
mju_addToScl3(pos, left, d_left);
}
// construct ray for perspective camera: fixed pos, modify direction
else {
mju_scl3(ray, forward, cam.frustum_near);
mju_addToScl3(ray, up, d_up);
mju_addToScl3(ray, left, d_left);
mju_normalize3(ray);
}
// find intersection with geoms
*geomid = -1;
mjtNum geomdist = mj_ray(m, d, pos, ray, vopt->geomgroup,
vopt->flags[mjVIS_STATIC], -1, geomid);
mjtNum geomdist = mj_ray(m, d, pos, ray, vopt->geomgroup, vopt->flags[mjVIS_STATIC], -1, geomid);
// find intersection with flexes
int flexbodyid = -1;
@@ -851,7 +890,6 @@ int mjv_select(const mjModel* m, const mjData* d, const mjvOption* vopt,
}
}
// geom
if (best == 0) {
*flexid = -1;
+149 -124
View File
@@ -511,11 +511,11 @@ static int bodycategory(const mjModel* m, int bodyid) {
// computes the camera frustum
static void getFrustum(float zver[2], float zhor[2], float znear,
const float K[4], const float sensorsize[2]) {
zhor[0] = znear / K[0] * (sensorsize[0]/2.f - K[2]);
zhor[1] = znear / K[0] * (sensorsize[0]/2.f + K[2]);
zver[0] = znear / K[1] * (sensorsize[1]/2.f - K[3]);
zver[1] = znear / K[1] * (sensorsize[1]/2.f + K[3]);
const float intrinsic[4], const float sensorsize[2]) {
zhor[0] = znear / intrinsic[0] * (sensorsize[0]/2.f - intrinsic[2]);
zhor[1] = znear / intrinsic[0] * (sensorsize[0]/2.f + intrinsic[2]);
zver[0] = znear / intrinsic[1] * (sensorsize[1]/2.f - intrinsic[3]);
zver[1] = znear / intrinsic[1] * (sensorsize[1]/2.f + intrinsic[3]);
}
@@ -668,7 +668,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
// offset xpos with aabb center (not always at frame origin)
const mjtNum *center = isleaf ? m->geom_aabb + 6*geomid : m->bvh_aabb + 6*i;
mjtNum pos[3];
mju_rotVecMat(pos, center, xmat);
mju_mulMatVec3(pos, xmat, center);
mju_addTo3(pos, xpos);
// set box color
@@ -755,7 +755,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
// offset xpos with aabb center (not always at geom origin)
const mjtNum *center = m->bvh_aabb + 6*i;
mjtNum pos[3];
mju_rotVecMat(pos, center, xmat);
mju_mulMatVec3(pos, xmat, center);
mju_addTo3(pos, xpos);
START
@@ -830,7 +830,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
START
// compute selection point in world coordinates
mju_rotVecMat(selpos, pert->localpos, d->xmat+9*pert->select);
mju_mulMatVec3(selpos, d->xmat+9*pert->select, pert->localpos);
mju_addTo3(selpos, d->xpos+3*pert->select);
// construct geom
@@ -873,7 +873,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
if (m->body_bvhnum[i]) {
mjtNum* aabb = m->bvh_aabb+6*m->body_bvhadr[i];
mju_copy3(sz, aabb+3);
mju_rotVecMat(pos, aabb, d->ximat+9*i);
mju_mulMatVec3(pos, d->ximat+9*i, aabb);
}
// otherwise box of size meansize
@@ -946,7 +946,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
int i=0;
// compute selection point in world coordinates
mju_rotVecMat(selpos, pert->localpos, d->xmat+9*pert->select);
mju_mulMatVec3(selpos, d->xmat+9*pert->select, pert->localpos);
mju_addTo3(selpos, d->xpos+3*pert->select);
START
@@ -1502,11 +1502,97 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
}
}
// cameras
// cameras and frustums
objtype = mjOBJ_CAMERA;
category = mjCAT_DECOR;
if (vopt->flags[mjVIS_CAMERA] && (category & catmask)) {
for (int i=0; i < m->ncam; i++) {
// copy camera rgba
float cam_rgba[4];
f2f(cam_rgba, m->vis.rgba.camera, 4);
// draw frustum if sensorsize is defined
if (m->cam_sensorsize[2*i+1] > 0) {
// when drawing frustum, make camera translucent
cam_rgba[3] = 0.3;
// locals
const float* rgba = m->vis.rgba.frustum;
mjtNum vnear[4][3], vfar[4][3];
mjtNum center[3];
mjtNum znear = m->vis.map.znear * m->stat.extent;
mjtNum zfar = m->vis.scale.frustum * scl;
float zver[2], zhor[2];
// get frustum
getFrustum(zver, zhor, znear, m->cam_intrinsic + 4*i, m->cam_sensorsize + 2*i);
// frustum frame to convert from planes to vertex representation
mjtNum *cam_xpos = d->cam_xpos+3*i;
mjtNum *cam_xmat = d->cam_xmat+9*i;
mjtNum x[] = {cam_xmat[0], cam_xmat[3], cam_xmat[6]};
mjtNum y[] = {cam_xmat[1], cam_xmat[4], cam_xmat[7]};
mjtNum z[] = {cam_xmat[2], cam_xmat[5], cam_xmat[8]};
// vertices of the near plane
mju_addScl3(center, cam_xpos, z, -znear);
mju_addScl3(vnear[0], center, x, -zhor[0]);
mju_addScl3(vnear[1], center, x, zhor[1]);
mju_addScl3(vnear[2], center, x, zhor[1]);
mju_addScl3(vnear[3], center, x, -zhor[0]);
mju_addToScl3(vnear[0], y, -zver[0]);
mju_addToScl3(vnear[1], y, -zver[0]);
mju_addToScl3(vnear[2], y, zver[1]);
mju_addToScl3(vnear[3], y, zver[1]);
// vertices of the far plane
zhor[0] *= zfar / znear;
zhor[1] *= zfar / znear;
zver[0] *= zfar / znear;
zver[1] *= zfar / znear;
mju_addScl3(center, cam_xpos, z, -zfar);
mju_addScl3(vfar[0], center, x, -zhor[0]);
mju_addScl3(vfar[1], center, x, zhor[1]);
mju_addScl3(vfar[2], center, x, zhor[1]);
mju_addScl3(vfar[3], center, x, -zhor[0]);
mju_addToScl3(vfar[0], y, -zver[0]);
mju_addToScl3(vfar[1], y, -zver[0]);
mju_addToScl3(vfar[2], y, zver[1]);
mju_addToScl3(vfar[3], y, zver[1]);
// triangulation and wireframe of the frustum
for (int e=0; e < 4; e++) {
START
mju_sub3(x, vfar[e], vnear[e]);
mju_sub3(y, vnear[(e+1)%4], vnear[e]);
mju_cross(z, x, y);
mjtNum tri1[3] = {mju_normalize3(x), mju_normalize3(y), mju_normalize3(z)};
mjtNum xmat1[9] = {x[0], y[0], z[0], x[1], y[1], z[1], x[2], y[2], z[2]};
mjv_initGeom(thisgeom, mjGEOM_TRIANGLE, tri1, vnear[e], xmat1, rgba);
FINISH
START
mju_sub3(y, vnear[(e+1)%4], vfar[e]);
mju_sub3(x, vfar[(e+1)%4], vfar[e]);
mju_cross(z, x, y);
mjtNum tri2[3] = {mju_normalize3(x), mju_normalize3(y), mju_normalize3(z)};
mjtNum xmat2[9] = {x[0], y[0], z[0], x[1], y[1], z[1], x[2], y[2], z[2]};
mjv_initGeom(thisgeom, mjGEOM_TRIANGLE, tri2, vfar[e], xmat2, rgba);
FINISH
START
mjv_connector(thisgeom, mjGEOM_LINE, 3, vnear[e], vnear[(e+1)%4]);
f2f(thisgeom->rgba, rgba, 4);
FINISH
START
mjv_connector(thisgeom, mjGEOM_LINE, 3, vfar[e], vfar[(e+1)%4]);
f2f(thisgeom->rgba, rgba, 4);
FINISH
START
mjv_connector(thisgeom, mjGEOM_LINE, 3, vnear[e], vfar[e]);
f2f(thisgeom->rgba, rgba, 4);
FINISH
}
}
START
// construct geom: camera body
@@ -1516,7 +1602,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
thisgeom->size[2] = scl * m->vis.scale.camera * 0.4;
mju_n2f(thisgeom->pos, d->cam_xpos+3*i, 3);
mju_n2f(thisgeom->mat, d->cam_xmat+9*i, 9);
f2f(thisgeom->rgba, m->vis.rgba.camera, 4);
f2f(thisgeom->rgba, cam_rgba, 4);
// vopt->label
if (vopt->label == mjLABEL_CAMERA) {
@@ -1539,7 +1625,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
thisgeom->size[1] = scl * m->vis.scale.camera * 0.4;
thisgeom->size[2] = scl * m->vis.scale.camera * 0.3;
mju_n2f(thisgeom->mat, d->cam_xmat+9*i, 9);
f2f(thisgeom->rgba, m->vis.rgba.camera, 4);
f2f(thisgeom->rgba, cam_rgba, 4);
for (int k=0; k < 3; k++) {
thisgeom->rgba[k] *= 0.5; // make lens body darker
}
@@ -1582,88 +1668,6 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
}
}
// camera frustum
if (vopt->flags[mjVIS_CAMERA]) {
objtype = mjOBJ_CAMERA;
category = mjCAT_DECOR;
const float* rgba = m->vis.rgba.frustum;
mjtNum vnear[4][3], vfar[4][3];
mjtNum center[3];
mjtNum znear = m->vis.map.znear * m->stat.extent;
mjtNum zfar = m->vis.scale.frustum * scl;
float zver[2], zhor[2];
for (int i=0; i < m->ncam; i++) {
if (m->cam_sensorsize[2*i+1] == 0) {
continue;
}
getFrustum(zver, zhor, znear, m->cam_intrinsic + 4*i, m->cam_sensorsize + 2*i);
// frustum frame to convert from planes to vertex representation
mjtNum *cam_xpos = d->cam_xpos+3*i;
mjtNum *cam_xmat = d->cam_xmat+9*i;
mjtNum x[] = {cam_xmat[0], cam_xmat[3], cam_xmat[6]};
mjtNum y[] = {cam_xmat[1], cam_xmat[4], cam_xmat[7]};
mjtNum z[] = {cam_xmat[2], cam_xmat[5], cam_xmat[8]};
// vertices of the near plane
mju_addScl3(center, cam_xpos, z, -znear);
mju_addScl3(vnear[0], center, x, -zhor[0]);
mju_addScl3(vnear[1], center, x, zhor[1]);
mju_addScl3(vnear[2], center, x, zhor[1]);
mju_addScl3(vnear[3], center, x, -zhor[0]);
mju_addToScl3(vnear[0], y, -zver[0]);
mju_addToScl3(vnear[1], y, -zver[0]);
mju_addToScl3(vnear[2], y, zver[1]);
mju_addToScl3(vnear[3], y, zver[1]);
// vertices of the far plane
zhor[0] *= zfar / znear;
zhor[1] *= zfar / znear;
zver[0] *= zfar / znear;
zver[1] *= zfar / znear;
mju_addScl3(center, cam_xpos, z, -zfar);
mju_addScl3(vfar[0], center, x, -zhor[0]);
mju_addScl3(vfar[1], center, x, zhor[1]);
mju_addScl3(vfar[2], center, x, zhor[1]);
mju_addScl3(vfar[3], center, x, -zhor[0]);
mju_addToScl3(vfar[0], y, -zver[0]);
mju_addToScl3(vfar[1], y, -zver[0]);
mju_addToScl3(vfar[2], y, zver[1]);
mju_addToScl3(vfar[3], y, zver[1]);
// triangulation and wireframe of the frustum
for (int e=0; e < 4; e++) {
START
mju_sub3(x, vfar[e], vnear[e]);
mju_sub3(y, vnear[(e+1)%4], vnear[e]);
mju_cross(z, x, y);
mjtNum tri1[3] = {mju_normalize3(x), mju_normalize3(y), mju_normalize3(z)};
mjtNum xmat1[9] = {x[0], y[0], z[0], x[1], y[1], z[1], x[2], y[2], z[2]};
mjv_initGeom(thisgeom, mjGEOM_TRIANGLE, tri1, vnear[e], xmat1, rgba);
FINISH
START
mju_sub3(y, vnear[(e+1)%4], vfar[e]);
mju_sub3(x, vfar[(e+1)%4], vfar[e]);
mju_cross(z, x, y);
mjtNum tri2[3] = {mju_normalize3(x), mju_normalize3(y), mju_normalize3(z)};
mjtNum xmat2[9] = {x[0], y[0], z[0], x[1], y[1], z[1], x[2], y[2], z[2]};
mjv_initGeom(thisgeom, mjGEOM_TRIANGLE, tri2, vfar[e], xmat2, rgba);
FINISH
START
mjv_connector(thisgeom, mjGEOM_LINE, 3, vnear[e], vnear[(e+1)%4]);
f2f(thisgeom->rgba, rgba, 4);
FINISH
START
mjv_connector(thisgeom, mjGEOM_LINE, 3, vfar[e], vfar[(e+1)%4]);
f2f(thisgeom->rgba, rgba, 4);
FINISH
START
mjv_connector(thisgeom, mjGEOM_LINE, 3, vnear[e], vfar[e]);
f2f(thisgeom->rgba, rgba, 4);
FINISH
}
}
}
// lights
objtype = mjOBJ_LIGHT;
@@ -2026,9 +2030,9 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
if (d->eq_active[i] && (m->eq_type[i] == mjEQ_CONNECT || m->eq_type[i] == mjEQ_WELD)) {
// compute endpoints in global coordinates
int j = m->eq_obj1id[i], k = m->eq_obj2id[i];
mju_rotVecMat(vec, m->eq_data+mjNEQDATA*i+3*(m->eq_type[i] == mjEQ_WELD), d->xmat+9*j);
mju_mulMatVec3(vec, d->xmat+9*j, m->eq_data+mjNEQDATA*i+3*(m->eq_type[i] == mjEQ_WELD));
mju_addTo3(vec, d->xpos+3*j);
mju_rotVecMat(end, m->eq_data+mjNEQDATA*i+3*(m->eq_type[i] == mjEQ_CONNECT), d->xmat+9*k);
mju_mulMatVec3(end, d->xmat+9*k, m->eq_data+mjNEQDATA*i+3*(m->eq_type[i] == mjEQ_CONNECT));
mju_addTo3(end, d->xpos+3*k);
// construct geom
@@ -2131,28 +2135,31 @@ void mjv_makeLights(const mjModel* m, const mjData* d, mjvScene* scn) {
// update camera only
void mjv_updateCamera(const mjModel* m, const mjData* d, mjvCamera* cam, mjvScene* scn) {
mjtNum ca, sa, ce, se, move[3], *mat;
mjtNum headpos[3], forward[3], up[3], right[3], ipd;
// return if nothing to do
if (!m || !cam || cam->type == mjCAMERA_USER) {
return;
}
// initialize frustum
float zver[2], zhor[2] = {0, 0};
float znear = m->vis.map.znear * m->stat.extent;
float zfar = m->vis.map.zfar * m->stat.extent;
// define extrinsics
mjtNum move[3];
mjtNum headpos[3], forward[3], up[3], right[3];
// get headpos, forward[3], up, right, ipd, fovy
// define intrinsics
int cid, orthographic = 0;
mjtNum fovy, ipd;
float* intrinsic = NULL;
float* sensorsize = NULL;
// get headpos, forward, up, right, ipd, fovy, orthographic, intrinsic
switch (cam->type) {
case mjCAMERA_FREE:
case mjCAMERA_TRACKING:
// get global ipd
ipd = m->vis.global.ipd;
// compute image size from global fovy
zver[0] = zver[1] = (float)znear * mju_tan(m->vis.global.fovy * (float)(mjPI/360.0));
// get orthographic, fovy
orthographic = m->vis.global.orthographic;
fovy = m->vis.global.fovy;
// move lookat for tracking
if (cam->type == mjCAMERA_TRACKING) {
@@ -2168,10 +2175,10 @@ void mjv_updateCamera(const mjModel* m, const mjData* d, mjvCamera* cam, mjvScen
}
// compute frame
ca = mju_cos(cam->azimuth/180.0*mjPI);
sa = mju_sin(cam->azimuth/180.0*mjPI);
ce = mju_cos(cam->elevation/180.0*mjPI);
se = mju_sin(cam->elevation/180.0*mjPI);
mjtNum ca = mju_cos(cam->azimuth/180.0*mjPI);
mjtNum sa = mju_sin(cam->azimuth/180.0*mjPI);
mjtNum ce = mju_cos(cam->elevation/180.0*mjPI);
mjtNum se = mju_sin(cam->elevation/180.0*mjPI);
forward[0] = ce*ca;
forward[1] = ce*sa;
forward[2] = se;
@@ -2184,25 +2191,27 @@ void mjv_updateCamera(const mjModel* m, const mjData* d, mjvCamera* cam, mjvScen
mju_addScl3(headpos, cam->lookat, forward, -cam->distance);
break;
case mjCAMERA_FIXED: {
// get id and check
int cid = cam->fixedcamid;
case mjCAMERA_FIXED:
// get id, check range
cid = cam->fixedcamid;
if (cid < 0 || cid >= m->ncam) {
mjERROR("fixed camera id is outside valid range");
}
// get camera-specific ipd and fovy
// get camera-specific ipd, orthographic, fovy
ipd = m->cam_ipd[cid];
// get frustum from intrinsics or from fovy
orthographic = m->cam_orthographic[cid];
fovy = m->cam_fovy[cid];
// if positive sensorsize, get sensorsize and intrinsic
if (m->cam_sensorsize[2*cid+1]) {
getFrustum(zver, zhor, znear, m->cam_intrinsic + 4*cid, m->cam_sensorsize + 2*cid);
} else {
zver[0] = zver[1] = (float)znear * mju_tan(m->cam_fovy[cid] * (float)(mjPI/360.0));
sensorsize = m->cam_sensorsize + 2*cid;
intrinsic = m->cam_intrinsic + 4*cid;
}
// get pointer to camera orientation matrix
mat = d->cam_xmat + 9*cid;
mjtNum* mat = d->cam_xmat + 9*cid;
// get frame
forward[0] = -mat[2];
@@ -2215,13 +2224,26 @@ void mjv_updateCamera(const mjModel* m, const mjData* d, mjvCamera* cam, mjvScen
right[1] = mat[3];
right[2] = mat[6];
mju_copy3(headpos, d->cam_xpos + 3*cid);
}
break;
break;
default:
mjERROR("unknown camera type");
}
// convert intrinsics to frustum parameters
float znear = m->vis.map.znear * m->stat.extent;
float zfar = m->vis.map.zfar * m->stat.extent;
float zver[2], zhor[2] = {0, 0};
if (orthographic){
zver[0] = zver[1] = fovy / 2;
} else {
if (!intrinsic) {
zver[0] = zver[1] = znear * mju_tan(fovy * mjPI/360.0);
} else {
getFrustum(zver, zhor, znear, intrinsic, sensorsize);
}
}
// compute GL cameras
for (int view=0; view < 2; view++) {
// set frame
@@ -2231,6 +2253,9 @@ void mjv_updateCamera(const mjModel* m, const mjData* d, mjvCamera* cam, mjvScen
scn->camera[view].up[i] = (float)up[i];
}
// set orthographic
scn->camera[view].orthographic = orthographic;
// set symmetric frustum using intrinsic camera matrix
scn->camera[view].frustum_top = zver[1];
scn->camera[view].frustum_bottom = -zver[0];
@@ -2611,7 +2636,7 @@ void mjv_updateActiveSkin(const mjModel* m, const mjData* d, mjvScene* scn, cons
// compute translation
mjtNum translate[3];
mju_rotVecMat(translate, bindpos, rotate);
mju_mulMatVec3(translate, rotate, bindpos);
mju_sub3(translate, d->xpos+3*bodyid, translate);
// process all bone vertices
@@ -2631,7 +2656,7 @@ void mjv_updateActiveSkin(const mjModel* m, const mjData* d, mjvScene* scn, cons
// transform
mjtNum pos1[3];
mju_rotVecMat(pos1, pos, rotate);
mju_mulMatVec3(pos1, rotate, pos);
mju_addTo3(pos1, translate);
// accumulate position
+15 -5
View File
@@ -694,7 +694,7 @@ static void initLights(mjvScene* scn) {
// set projection and modelview
static void setView(int view, mjrRect viewport, const mjvScene* scn, const mjrContext* con,
float* camProject, float* camView) {
float camProject[16], float camView[16]) {
mjvGLCamera cam;
// copy specified camera for stereo, average for mono (view = -1)
@@ -709,24 +709,34 @@ static void setView(int view, mjrRect viewport, const mjvScene* scn, const mjrCo
: 0.5f * (float)viewport.width / (float)viewport.height *
(cam.frustum_top - cam.frustum_bottom);
// set projection
// prepare projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (mjGLAD_GL_ARB_clip_control) {
// reverse Z rendering mapping [znear, zfar] -> [1, 0] (ndc)
glTranslatef(0.0f, 0.0f, 0.5f);
glScalef(1.0f, 1.0f, -0.5f);
}
else {
} else {
// reverse Z rendering mapping without shift [znear, zfar] -> [1, -1] (ndc)
glScalef(1.0f, 1.0f, -1.0f);
}
glFrustum(cam.frustum_center - halfwidth,
// set projection, orthographic or perspective
if (cam.orthographic) {
glOrtho(cam.frustum_center - halfwidth,
cam.frustum_center + halfwidth,
cam.frustum_bottom,
cam.frustum_top,
cam.frustum_near,
cam.frustum_far);
} else {
glFrustum(cam.frustum_center - halfwidth,
cam.frustum_center + halfwidth,
cam.frustum_bottom,
cam.frustum_top,
cam.frustum_near,
cam.frustum_far);
}
// save projection matrix if requested
if (camProject) {
+50 -52
View File
@@ -52,7 +52,7 @@ static T& operator+(T& base, std::string_view suffix) {
// create model
mjSpec* mjs_createSpec() {
mjSpec* mj_makeSpec() {
mjCModel* modelC = new mjCModel;
return &modelC->spec;
}
@@ -60,7 +60,7 @@ mjSpec* mjs_createSpec() {
// copy model
mjSpec* mjs_copySpec(const mjSpec* s) {
mjSpec* mj_copySpec(const mjSpec* s) {
mjCModel* modelC = new mjCModel(*static_cast<mjCModel*>(s->element));
return &modelC->spec;
}
@@ -68,7 +68,7 @@ mjSpec* mjs_copySpec(const mjSpec* s) {
// copy back model
void mjs_copyBack(mjSpec* s, const mjModel* m) {
void mj_copyBack(mjSpec* s, const mjModel* m) {
mjCModel* modelC = static_cast<mjCModel*>(s->element);
modelC->CopyBack(m);
}
@@ -76,13 +76,23 @@ void mjs_copyBack(mjSpec* s, const mjModel* m) {
// compile model
mjModel* mjs_compile(mjSpec* s, const mjVFS* vfs) {
mjModel* mj_compile(mjSpec* s, const mjVFS* vfs) {
mjCModel* modelC = static_cast<mjCModel*>(s->element);
return modelC->Compile(vfs);
}
// recompile spec into existing model and data while preserving the state
void mj_recompile(mjSpec* s, const mjVFS* vfs, mjModel* m, mjData* d) {
mjCModel* modelC = static_cast<mjCModel*>(s->element);
modelC->SaveState(d);
modelC->Compile(vfs, &m);
modelC->RestoreState(m, &d);
}
// attach body to a frame of the parent
int mjs_attachBody(mjsFrame* parent, const mjsBody* child,
const char* prefix, const char* suffix) {
@@ -133,7 +143,7 @@ int mjs_isWarning(mjSpec* s) {
// delete model
void mjs_deleteSpec(mjSpec* s) {
void mj_deleteSpec(mjSpec* s) {
mjCModel* model = static_cast<mjCModel*>(s->element);
delete model;
}
@@ -141,7 +151,7 @@ void mjs_deleteSpec(mjSpec* s) {
// delete object, it will call the appropriate destructor since ~mjCBase is virtual
void mjs_delete(mjElement* element) {
void mjs_delete(mjsElement* element) {
mjCBase* object = static_cast<mjCBase*>(element);
delete object;
}
@@ -420,7 +430,7 @@ mjsKey* mjs_addKey(mjSpec* s) {
mjsPlugin* mjs_addPlugin(mjSpec* s) {
mjCModel* modelC = static_cast<mjCModel*>(s->element);
mjCPlugin* plugin = modelC->AddPlugin();
plugin->spec.instance = static_cast<mjElement*>(plugin);
plugin->spec.instance = static_cast<mjsElement*>(plugin);
return &plugin->spec;
}
@@ -448,7 +458,7 @@ mjSpec* mjs_getSpec(mjsBody* body) {
// get default
mjsDefault* mjs_getDefault(mjElement* element) {
mjsDefault* mjs_getDefault(mjsElement* element) {
return &(static_cast<mjCBase*>(element)->def->spec);
}
@@ -520,7 +530,7 @@ mjsFrame* mjs_findFrame(mjSpec* s, const char* name) {
// set frame
void mjs_setFrame(mjElement* dest, mjsFrame* frame) {
void mjs_setFrame(mjsElement* dest, mjsFrame* frame) {
if (!frame) {
return;
}
@@ -540,14 +550,14 @@ const char* mjs_resolveOrientation(double quat[4], mjtByte degree, const char* s
// get id
int mjs_getId(mjElement* element) {
int mjs_getId(mjsElement* element) {
return static_cast<mjCBase*>(element)->id;
}
// set default
void mjs_setDefault(mjElement* element, mjsDefault* defspec) {
void mjs_setDefault(mjsElement* element, mjsDefault* defspec) {
mjCBase* baseC = static_cast<mjCBase*>(element);
baseC->def = static_cast<mjCDef*>(defspec->element);
}
@@ -555,7 +565,7 @@ void mjs_setDefault(mjElement* element, mjsDefault* defspec) {
// return first child of selected type
mjElement* mjs_firstChild(mjsBody* body, mjtObj type) {
mjsElement* mjs_firstChild(mjsBody* body, mjtObj type) {
mjCBody* bodyC = static_cast<mjCBody*>(body->element);
return bodyC->NextChild(NULL, type);
}
@@ -563,7 +573,7 @@ mjElement* mjs_firstChild(mjsBody* body, mjtObj type) {
// return body's next child; return NULL if child is last
mjElement* mjs_nextChild(mjsBody* body, mjElement* child) {
mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child) {
mjCBody* bodyC = static_cast<mjCBody*>(body->element);
return bodyC->NextChild(child);
}
@@ -571,66 +581,61 @@ mjElement* mjs_nextChild(mjsBody* body, mjElement* child) {
// set string
void mjs_setString(mjString dest, const char* text) {
std::string* str = reinterpret_cast<std::string*>(dest);
void mjs_setString(mjString* dest, const char* text) {
std::string* str = static_cast<std::string*>(dest);
*str = std::string(text);
}
// Set specific entry in destination string vector.
mjtByte mjs_setInStringVec(mjStringVec dest, int i, const char* text) {
std::vector<std::string>* v = reinterpret_cast<std::vector<std::string>*>(dest);
if (v->size() <= i) {
mjtByte mjs_setInStringVec(mjStringVec* dest, int i, const char* text) {
if (dest->size() <= i) {
mju_error("Requested index in mjs_setInStringVec is out of bounds");
return 0;
}
v->at(i) = std::string(text);
dest->at(i) = std::string(text);
return 1;
}
// split text and copy into string array
void mjs_setStringVec(mjStringVec dest, const char* text) {
std::vector<std::string>* v = reinterpret_cast<std::vector<std::string>*>(dest);
void mjs_setStringVec(mjStringVec* dest, const char* text) {
std::vector<std::string>* v = static_cast<std::vector<std::string>*>(dest);
*v = mjXUtil::String2Vector<std::string>(text);
}
// add text entry to destination string vector
void mjs_appendString(mjStringVec dest, const char* text) {
std::vector<std::string>* v = reinterpret_cast<std::vector<std::string>*>(dest);
v->push_back(std::string(text));
void mjs_appendString(mjStringVec* dest, const char* text) {
dest->push_back(std::string(text));
}
// copy int array to vector
void mjs_setInt(mjIntVec dest, const int* array, int size) {
std::vector<int>* v = reinterpret_cast<std::vector<int>*>(dest);
v->assign(size, 0.0);
void mjs_setInt(mjIntVec* dest, const int* array, int size) {
dest->assign(size, 0.0);
for (int i = 0; i < size; ++i) {
(*v)[i] = array[i];
(*dest)[i] = array[i];
}
}
// append int array to vector of arrays
void mjs_appendIntVec(mjIntVecVec dest, const int* array, int size) {
std::vector<std::vector<int>>* v = reinterpret_cast<std::vector<std::vector<int>>*>(dest);
v->push_back(std::vector<int>(array, array + size));
void mjs_appendIntVec(mjIntVecVec* dest, const int* array, int size) {
dest->push_back(std::vector<int>(array, array + size));
}
// copy float array to vector
void mjs_setFloat(mjFloatVec dest, const float* array, int size) {
std::vector<float>* v = reinterpret_cast<std::vector<float>*>(dest);
v->assign(size, 0.0);
void mjs_setFloat(mjFloatVec* dest, const float* array, int size) {
dest->assign(size, 0.0);
for (int i = 0; i < size; ++i) {
(*v)[i] = array[i];
(*dest)[i] = array[i];
}
}
@@ -638,42 +643,35 @@ void mjs_setFloat(mjFloatVec dest, const float* array, int size) {
// append float array to vector of arrays
void mjs_appendFloatVec(mjFloatVecVec dest, const float* array, int size) {
std::vector<std::vector<float>>* v = reinterpret_cast<std::vector<std::vector<float>>*>(dest);
v->push_back(std::vector<float>(array, array + size));
void mjs_appendFloatVec(mjFloatVecVec* dest, const float* array, int size) {
dest->push_back(std::vector<float>(array, array + size));
}
// copy double array to vector
void mjs_setDouble(mjDoubleVec dest, const double* array, int size) {
std::vector<double>* v = reinterpret_cast<std::vector<double>*>(dest);
v->assign(size, 0.0);
void mjs_setDouble(mjDoubleVec* dest, const double* array, int size) {
dest->assign(size, 0.0);
for (int i = 0; i < size; ++i) {
(*v)[i] = array[i];
(*dest)[i] = array[i];
}
}
// get string
const char* mjs_getString(const mjString source) {
std::string* str = reinterpret_cast<std::string*>(source);
if (!str) {
return nullptr;
}
return str->c_str();
const char* mjs_getString(const mjString* source) {
return source->c_str();
}
// get double array
const double* mjs_getDouble(const mjDoubleVec source, int* size) {
std::vector<double>* v = reinterpret_cast<std::vector<double>*>(source);
const double* mjs_getDouble(const mjDoubleVec* source, int* size) {
if (size) {
*size = v->size();
*size = source->size();
}
return v->data();
return source->data();
}
+33 -742
View File
@@ -17,745 +17,36 @@
#include <math.h>
#include <stddef.h>
#include <mujoco/mjdata.h>
#include <mujoco/mjexport.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjspec.h>
#include <mujoco/mjtnum.h>
// this is a C-API
#ifdef __cplusplus
#include <string>
#include <vector>
extern "C" {
#endif
#define mjNAN NAN // used to mark undefined fields
//---------------------------------- handles to internal objects -----------------------------------
typedef struct _mjString* mjString;
typedef struct _mjStringVec* mjStringVec;
typedef struct _mjIntVec* mjIntVec;
typedef struct _mjIntVecVec* mjIntVecVec;
typedef struct _mjFloatVec* mjFloatVec;
typedef struct _mjFloatVecVec* mjFloatVecVec;
typedef struct _mjDoubleVec* mjDoubleVec;
//---------------------------------- enum types (mjt) ----------------------------------------------
typedef enum _mjtGeomInertia { // type of inertia inference
mjINERTIA_VOLUME, // mass distributed in the volume
mjINERTIA_SHELL, // mass distributed on the surface
} mjtGeomInertia;
typedef enum _mjtBuiltin { // type of built-in procedural texture
mjBUILTIN_NONE = 0, // no built-in texture
mjBUILTIN_GRADIENT, // gradient: rgb1->rgb2
mjBUILTIN_CHECKER, // checker pattern: rgb1, rgb2
mjBUILTIN_FLAT // 2d: rgb1; cube: rgb1-up, rgb2-side, rgb3-down
} mjtBuiltin;
typedef enum _mjtMark { // mark type for procedural textures
mjMARK_NONE = 0, // no mark
mjMARK_EDGE, // edges
mjMARK_CROSS, // cross
mjMARK_RANDOM // random dots
} mjtMark;
typedef enum _mjtLimited { // type of limit specification
mjLIMITED_FALSE = 0, // not limited
mjLIMITED_TRUE, // limited
mjLIMITED_AUTO, // limited inferred from presence of range
} mjtLimited;
typedef enum _mjtInertiaFromGeom { // whether to infer body inertias from child geoms
mjINERTIAFROMGEOM_FALSE = 0, // do not use; inertial element required
mjINERTIAFROMGEOM_TRUE, // always use; overwrite inertial element
mjINERTIAFROMGEOM_AUTO // use only if inertial element is missing
} mjtInertiaFromGeom;
typedef enum _mjtOrientation { // type of orientation specifier
mjORIENTATION_QUAT = 0, // quaternion
mjORIENTATION_AXISANGLE, // axis and angle
mjORIENTATION_XYAXES, // x and y axes
mjORIENTATION_ZAXIS, // z axis (minimal rotation)
mjORIENTATION_EULER, // Euler angles
} mjtOrientation;
//---------------------------------- attribute structs (mjs) ---------------------------------------
typedef struct _mjElement { // element type, do not modify
mjtObj elemtype; // element type
} mjElement;
typedef struct _mjSpec { // model specification
mjElement* element; // element type
mjString modelname; // model name
// compiler settings
mjtByte autolimits; // infer "limited" attribute based on range
double boundmass; // enforce minimum body mass
double boundinertia; // enforce minimum body diagonal inertia
double settotalmass; // rescale masses and inertias; <=0: ignore
mjtByte balanceinertia; // automatically impose A + B >= C rule
mjtByte strippath; // automatically strip paths from mesh files
mjtByte fitaabb; // meshfit to aabb instead of inertia box
mjtByte degree; // angles in radians or degrees
char euler[3]; // sequence for euler rotations
mjString meshdir; // mesh and hfield directory
mjString texturedir; // texture directory
mjtByte discardvisual; // discard visual geoms in parser
mjtByte convexhull; // compute mesh convex hulls
mjtByte usethread; // use multiple threads to speed up compiler
mjtByte fusestatic; // fuse static bodies with parent
int inertiafromgeom; // use geom inertias (mjtInertiaFromGeom)
int inertiagrouprange[2]; // range of geom groups used to compute inertia
mjtByte exactmeshinertia; // if false, use old formula
mjLROpt LRopt; // options for lengthrange computation
// engine data
mjOption option; // physics options
mjVisual visual; // visual options
mjStatistic stat; // statistics override (if defined)
// sizes
size_t memory; // number of bytes in arena+stack memory
int nemax; // max number of equality constraints
int nuserdata; // number of mjtNums in userdata
int nuser_body; // number of mjtNums in body_user
int nuser_jnt; // number of mjtNums in jnt_user
int nuser_geom; // number of mjtNums in geom_user
int nuser_site; // number of mjtNums in site_user
int nuser_cam; // number of mjtNums in cam_user
int nuser_tendon; // number of mjtNums in tendon_user
int nuser_actuator; // number of mjtNums in actuator_user
int nuser_sensor; // number of mjtNums in sensor_user
int nkey; // number of keyframes
int njmax; // (deprecated) max number of constraints
int nconmax; // (deprecated) max number of detected contacts
size_t nstack; // (deprecated) number of mjtNums in mjData stack
// global data
mjString comment; // comment at top of XML
mjString modelfiledir; // path to model file
// other
mjtByte hasImplicitPluginElem; // already encountered an implicit plugin sensor/actuator
} mjSpec;
typedef struct _mjsOrientation { // alternative orientation specifiers
mjtOrientation type; // active orientation specifier
double axisangle[4]; // axis and angle
double xyaxes[6]; // x and y axes
double zaxis[3]; // z axis (minimal rotation)
double euler[3]; // Euler angles
} mjsOrientation;
typedef struct _mjsPlugin { // plugin specification
mjElement* instance; // element type
mjString name; // name
mjString instance_name; // instance name
int plugin_slot; // global registered slot number of the plugin
mjtByte active; // is the plugin active
mjString info; // message appended to compiler errors
} mjsPlugin;
typedef struct _mjsBody { // body specification
mjElement* element; // element type
mjString name; // name
mjString childclass; // childclass name
// body frame
double pos[3]; // frame position
double quat[4]; // frame orientation
mjsOrientation alt; // frame alternative orientation
// inertial frame
double mass; // mass
double ipos[3]; // inertial frame position
double iquat[4]; // inertial frame orientation
double inertia[3]; // diagonal inertia (in i-frame)
mjsOrientation ialt; // inertial frame alternative orientation
double fullinertia[6]; // non-axis-aligned inertia matrix
// other
mjtByte mocap; // is this a mocap body
double gravcomp; // gravity compensation
mjDoubleVec userdata; // user data
mjtByte explicitinertial; // whether to save the body with explicit inertial clause
mjsPlugin plugin; // passive force plugin
mjString info; // message appended to compiler errors
} mjsBody;
typedef struct _mjsFrame { // frame specification
mjElement* element; // element type
mjString name; // name
mjString childclass; // childclass name
double pos[3]; // position
double quat[4]; // orientation
mjsOrientation alt; // alternative orientation
mjString info; // message appended to compiler errors
} mjsFrame;
typedef struct _mjsJoint { // joint specification
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
mjtJoint type; // joint type
// kinematics
double pos[3]; // anchor position
double axis[3]; // joint axis
double ref; // value at reference configuration: qpos0
// stiffness
double stiffness; // stiffness coefficient
double springref; // spring reference value: qpos_spring
double springdamper[2]; // timeconst, dampratio
// limits
int limited; // does joint have limits (mjtLimited)
double range[2]; // joint limits
double margin; // margin value for joint limit detection
mjtNum solref_limit[mjNREF]; // solver reference: joint limits
mjtNum solimp_limit[mjNIMP]; // solver impedance: joint limits
int actfrclimited; // are actuator forces on joint limited (mjtLimited)
double actfrcrange[2]; // actuator force limits
// dof properties
double armature; // armature inertia (mass for slider)
double damping; // damping coefficient
double frictionloss; // friction loss
mjtNum solref_friction[mjNREF]; // solver reference: dof friction
mjtNum solimp_friction[mjNIMP]; // solver impedance: dof friction
// other
int group; // group
mjtByte actgravcomp; // is gravcomp force applied via actuators
mjDoubleVec userdata; // user data
mjString info; // message appended to compiler errors
} mjsJoint;
typedef struct _mjsGeom { // geom specification
mjElement* element; // element type
mjString name; // name
mjString classname; // classname
mjtGeom type; // geom type
// frame, size
double pos[3]; // position
double quat[4]; // orientation
mjsOrientation alt; // alternative orientation
double fromto[6]; // alternative for capsule, cylinder, box, ellipsoid
double size[3]; // type-specific size
// contact related
int contype; // contact type
int conaffinity; // contact affinity
int condim; // contact dimensionality
int priority; // contact priority
double friction[3]; // one-sided friction coefficients: slide, roll, spin
double solmix; // solver mixing for contact pairs
mjtNum solref[mjNREF]; // solver reference
mjtNum solimp[mjNIMP]; // solver impedance
double margin; // margin for contact detection
double gap; // include in solver if dist < margin-gap
// inertia inference
double mass; // used to compute density
double density; // used to compute mass and inertia from volume or surface
mjtGeomInertia typeinertia; // selects between surface and volume inertia
// fluid forces
mjtNum fluid_ellipsoid; // whether ellipsoid-fluid model is active
mjtNum fluid_coefs[5]; // ellipsoid-fluid interaction coefs
// visual
mjString material; // name of material
float rgba[4]; // rgba when material is omitted
int group; // group
// other
mjString hfieldname; // heightfield attached to geom
mjString meshname; // mesh attached to geom
double fitscale; // scale mesh uniformly
mjDoubleVec userdata; // user data
mjsPlugin plugin; // sdf plugin
mjString info; // message appended to compiler errors
} mjsGeom;
typedef struct _mjsSite { // site specification
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
// frame, size
double pos[3]; // position
double quat[4]; // orientation
mjsOrientation alt; // alternative orientation
double fromto[6]; // alternative for capsule, cylinder, box, ellipsoid
double size[3]; // geom size
// visual
mjtGeom type; // geom type
mjString material; // name of material
int group; // group
float rgba[4]; // rgba when material is omitted
// other
mjDoubleVec userdata; // user data
mjString info; // message appended to compiler errors
} mjsSite;
typedef struct _mjsCamera { // camera specification
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
// extrinsics
double pos[3]; // position
double quat[4]; // orientation
mjsOrientation alt; // alternative orientation
mjtCamLight mode; // tracking mode
mjString targetbody; // target body for tracking/targeting
// intrinsics
double fovy; // y-field of view
double ipd; // inter-pupilary distance
float intrinsic[4]; // camera intrinsics (length)
float sensor_size[2]; // sensor size (length)
float resolution[2]; // resolution (pixel)
float focal_length[2]; // focal length (length)
float focal_pixel[2]; // focal length (pixel)
float principal_length[2]; // principal point (length)
float principal_pixel[2]; // principal point (pixel)
// other
mjDoubleVec userdata; // user data
mjString info; // message appended to compiler errors
} mjsCamera;
typedef struct _mjsLight { // light specification
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
// frame
double pos[3]; // position
double dir[3]; // direction
mjtCamLight mode; // tracking mode
mjString targetbody; // target body for targeting
// intrinsics
mjtByte active; // is light active
mjtByte directional; // is light directional or spot
mjtByte castshadow; // does light cast shadows
double bulbradius; // bulb radius, for soft shadows
float attenuation[3]; // OpenGL attenuation (quadratic model)
float cutoff; // OpenGL cutoff
float exponent; // OpenGL exponent
float ambient[3]; // ambient color
float diffuse[3]; // diffuse color
float specular[3]; // specular color
// other
mjString info; // message appended to compiler errors
} mjsLight;
typedef struct _mjsFlex {
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
// contact properties
int contype; // contact type
int conaffinity; // contact affinity
int condim; // contact dimensionality
int priority; // contact priority
double friction[3]; // one-sided friction coefficients: slide, roll, spin
double solmix; // solver mixing for contact pairs
mjtNum solref[mjNREF]; // solver reference
mjtNum solimp[mjNIMP]; // solver impedance
double margin; // margin for contact detection
double gap; // include in solver if dist<margin-gap
// other properties
int dim; // element dimensionality
double radius; // radius around primitive element
mjtByte internal; // enable internal collisions
mjtByte flatskin; // render flex skin with flat shading
int selfcollide; // mode for flex self colllision
int activelayers; // number of active element layers in 3D
int group; // group for visualizatioh
double edgestiffness; // edge stiffness
double edgedamping; // edge damping
float rgba[4]; // rgba when material is omitted
mjString material; // name of material used for rendering
// mesh properties
mjStringVec vertbody; // vertex body names
mjDoubleVec vert; // vertex positions
mjIntVec elem; // element vertex ids
mjFloatVec texcoord; // vertex texture coordinates
// other
mjString info; // message appended to compiler errors
} mjsFlex;
typedef struct _mjsMesh { // mesh specification
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
mjString content_type; // content type of file
mjString file; // mesh file
double refpos[3]; // reference position
double refquat[4]; // reference orientation
double scale[3]; // rescale mesh
mjtByte smoothnormal; // do not exclude large-angle faces from normals
mjFloatVec uservert; // user vertex data
mjFloatVec usernormal; // user normal data
mjFloatVec usertexcoord; // user texcoord data
mjIntVec userface; // user vertex indices
mjIntVec userfacenormal; // user normal indices
mjIntVec userfacetexcoord; // user texcoord indices
mjsPlugin plugin; // sdf plugin
mjString info; // message appended to compiler errors
} mjsMesh;
typedef struct _mjsHField { // height field specification
mjElement* element; // element type
mjString name; // name
mjString content_type; // content type of file
mjString file; // file: (nrow, ncol, [elevation data])
double size[4]; // hfield size (ignore referencing geom size)
int nrow; // number of rows
int ncol; // number of columns
mjFloatVec userdata; // user-provided elevation data
mjString info; // message appended to compiler errors
} mjsHField;
typedef struct _mjsSkin { // skin specification
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
mjString file; // skin file
mjString material; // name of material used for rendering
float rgba[4]; // rgba when material is omitted
float inflate; // inflate in normal direction
int group; // group for visualization
// mesh
mjFloatVec vert; // vertex positions
mjFloatVec texcoord; // texture coordinates
mjIntVec face; // faces
// skin
mjStringVec bodyname; // body names
mjFloatVec bindpos; // bind pos
mjFloatVec bindquat; // bind quat
mjIntVecVec vertid; // vertex ids
mjFloatVecVec vertweight; // vertex weights
// other
mjString info; // message appended to compiler errors
} mjsSkin;
typedef struct _mjsTexture { // texture specification
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
mjtTexture type; // texture type
// method 1: builtin
int builtin; // builtin type (mjtBuiltin)
int mark; // mark type (mjtMark)
double rgb1[3]; // first color for builtin
double rgb2[3]; // second color for builtin
double markrgb[3]; // mark color
double random; // probability of random dots
int height; // height in pixels (square for cube and skybox)
int width; // width in pixels
// method 2: single file
mjString content_type; // content type of file
mjString file; // png file to load; use for all sides of cube
int gridsize[2]; // size of grid for composite file; (1,1)-repeat
char gridlayout[13]; // row-major: L,R,F,B,U,D for faces; . for unused
// method 3: separate files
mjStringVec cubefiles; // different file for each side of the cube
// flip options
mjtByte hflip; // horizontal flip
mjtByte vflip; // vertical flip
// other
mjString info; // message appended to compiler errors
} mjsTexture;
typedef struct _mjsMaterial { // material specification
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
mjString texture; // name of texture (empty: none)
mjtByte texuniform; // make texture cube uniform
float texrepeat[2]; // texture repetition for 2D mapping
float emission; // emission
float specular; // specular
float shininess; // shininess
float reflectance; // reflectance
float metallic; // metallic
float roughness; // roughness
float rgba[4]; // rgba
mjString info; // message appended to compiler errors
} mjsMaterial;
typedef struct _mjsPair {
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
mjString geomname1; // name of geom 1
mjString geomname2; // name of geom 2
// optional parameters: computed from geoms if not set by user
int condim; // contact dimensionality
mjtNum solref[mjNREF]; // solver reference, normal direction
mjtNum solreffriction[mjNREF]; // solver reference, frictional directions
mjtNum solimp[mjNIMP]; // solver impedance
double margin; // margin for contact detection
double gap; // include in solver if dist<margin-gap
double friction[5]; // full contact friction
mjString info; // message appended to errors
} mjsPair;
typedef struct _mjsExclude {
mjElement* element; // element type
mjString name; // name
mjString bodyname1; // name of geom 1
mjString bodyname2; // name of geom 2
mjString info; // message appended to errors
} mjsExclude;
typedef struct _mjsEquality { // equality specification
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
mjtEq type; // constraint type
double data[mjNEQDATA]; // type-dependent data
mjtByte active; // is equality initially active
mjString name1; // name of object 1
mjString name2; // name of object 2
mjtNum solref[mjNREF]; // solver reference
mjtNum solimp[mjNIMP]; // solver impedance
mjString info; // message appended to errors
} mjsEquality;
typedef struct _mjsTendon { // tendon specification
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
// stiffness, damping, friction
double stiffness; // stiffness coefficient
double springlength[2]; // spring resting length; {-1, -1}: use qpos_spring
double damping; // damping coefficient
double frictionloss; // friction loss
mjtNum solref_friction[mjNREF]; // solver reference: tendon friction
mjtNum solimp_friction[mjNIMP]; // solver impedance: tendon friction
// length range
int limited; // does tendon have limits (mjtLimited)
double range[2]; // length limits
double margin; // margin value for tendon limit detection
mjtNum solref_limit[mjNREF]; // solver reference: tendon limits
mjtNum solimp_limit[mjNIMP]; // solver impedance: tendon limits
// visual
mjString material; // name of material for rendering
double width; // width for rendering
float rgba[4]; // rgba when material is omitted
int group; // group
// other
mjDoubleVec userdata; // user data
mjString info; // message appended to errors
} mjsTendon;
typedef struct _mjsWrap { // wrapping object specification
mjElement* element; // element type
mjString info; // message appended to errors
} mjsWrap;
typedef struct _mjsActuator { // actuator specification
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
// gain, bias
mjtGain gaintype; // gain type
double gainprm[mjNGAIN]; // gain parameters
mjtBias biastype; // bias type
double biasprm[mjNGAIN]; // bias parameters
// activation state
mjtDyn dyntype; // dynamics type
double dynprm[mjNDYN]; // dynamics parameters
int actdim; // number of activation variables
int plugin_actdim; // actuator state size for plugins
mjtByte actearly; // apply next activations to qfrc
// transmission
mjtTrn trntype; // transmission type
double gear[6]; // length and transmitted force scaling
mjString target; // name of transmission target
mjString refsite; // reference site, for site transmission
mjString slidersite; // site defining cylinder, for slider-crank
double cranklength; // crank length, for slider-crank
double lengthrange[2]; // transmission length range
double inheritrange; // automatic range setting for position and intvelocity
// input/output clamping
int ctrllimited; // are control limits defined (mjtLimited)
double ctrlrange[2]; // control range
int forcelimited; // are force limits defined (mjtLimited)
double forcerange[2]; // force range
int actlimited; // are activation limits defined (mjtLimited)
double actrange[2]; // activation range
// other
int group; // group
mjDoubleVec userdata; // user data
mjsPlugin plugin; // actuator plugin
mjString info; // message appended to compiler errors
} mjsActuator;
typedef struct _mjsSensor { // sensor specification
mjElement* element; // element type
mjString name; // name
mjString classname; // class name
// sensor defintion
mjtSensor type; // type of sensor
mjtObj objtype; // type of sensorized object
mjString objname; // name of sensorized object
mjtObj reftype; // type of referenced object
mjString refname; // name of referenced object
// user-defined sensors
mjtDataType datatype; // data type for sensor measurement
mjtStage needstage; // compute stage needed to simulate sensor
int dim; // number of scalar outputs
// output post-processing
double cutoff; // cutoff for real and positive datatypes
double noise; // noise stdev
// other
mjDoubleVec userdata; // user data
mjsPlugin plugin; // sensor plugin
mjString info; // message appended to compiler errors
} mjsSensor;
typedef struct _mjsNumeric { // custom numeric field specification
mjElement* element; // element type
mjString name; // name
mjDoubleVec data; // initialization data
int size; // array size, can be bigger than data size
mjString info; // message appended to compiler errors
} mjsNumeric;
typedef struct _mjsText { // custom text specification
mjElement* element; // element type
mjString name; // name
mjString data; // text string
mjString info; // message appended to compiler errors
} mjsText;
typedef struct _mjsTuple { // tuple specification
mjElement* element; // element type
mjString name; // name
mjIntVec objtype; // object types
mjStringVec objname; // object names
mjDoubleVec objprm; // object parameters
mjString info; // message appended to compiler errors
} mjsTuple;
typedef struct _mjsKey { // keyframe specification
mjElement* element; // element type
mjString name; // name
double time; // time
mjDoubleVec qpos; // qpos
mjDoubleVec qvel; // qvel
mjDoubleVec act; // act
mjDoubleVec mpos; // mocap pos
mjDoubleVec mquat; // mocap quat
mjDoubleVec ctrl; // ctrl
mjString info; // message appended to compiler errors
} mjsKey;
typedef struct _mjsDefault { // default specification
mjElement* element; // element type
mjString name; // class name
mjsJoint* joint; // joint defaults
mjsGeom* geom; // geom defaults
mjsSite* site; // site defaults
mjsCamera* camera; // camera defaults
mjsLight* light; // light defaults
mjsFlex* flex; // flex defaults
mjsMesh* mesh; // mesh defaults
mjsMaterial* material; // material defaults
mjsPair* pair; // pair defaults
mjsEquality* equality; // equality defaults
mjsTendon* tendon; // tendon defaults
mjsActuator* actuator; // actuator defaults
} mjsDefault;
//---------------------------------- Top-level spec manipulation -----------------------------------
// Create spec.
MJAPI mjSpec* mjs_createSpec(void);
MJAPI mjSpec* mj_makeSpec(void);
// Compile spec to model.
MJAPI mjModel* mjs_compile(mjSpec* s, const mjVFS* vfs);
MJAPI mjModel* mj_compile(mjSpec* s, const mjVFS* vfs);
// Recompile spec to model preserving the current state.
MJAPI void mj_recompile(mjSpec* s, const mjVFS* vfs, mjModel* m, mjData* d);
// Copy spec.
MJAPI mjSpec* mjs_copySpec(const mjSpec* s);
MJAPI mjSpec* mj_copySpec(const mjSpec* s);
// Get compiler error message from spec.
MJAPI const char* mjs_getError(mjSpec* s);
@@ -764,10 +55,10 @@ MJAPI const char* mjs_getError(mjSpec* s);
MJAPI int mjs_isWarning(mjSpec* s);
// Copy model fields back into spec.
MJAPI void mjs_copyBack(mjSpec* s, const mjModel* m);
MJAPI void mj_copyBack(mjSpec* s, const mjModel* m);
// Delete spec.
MJAPI void mjs_deleteSpec(mjSpec* s);
MJAPI void mj_deleteSpec(mjSpec* s);
//---------------------------------- Attachment ----------------------------------------------------
@@ -811,7 +102,7 @@ MJAPI mjsLight* mjs_addLight(mjsBody* body, mjsDefault* def);
MJAPI mjsFrame* mjs_addFrame(mjsBody* body, mjsFrame* parentframe);
// Delete object corresponding to the given element.
MJAPI void mjs_delete(mjElement* element);
MJAPI void mjs_delete(mjsElement* element);
//---------------------------------- Add non-tree elements -----------------------------------------
@@ -904,7 +195,7 @@ MJAPI mjsMesh* mjs_findMesh(mjSpec* s, const char* name);
MJAPI mjsFrame* mjs_findFrame(mjSpec* s, const char* name);
// Get default corresponding to an element.
MJAPI mjsDefault* mjs_getDefault(mjElement* element);
MJAPI mjsDefault* mjs_getDefault(mjsElement* element);
// Find default in model by class name.
MJAPI mjsDefault* mjs_findDefault(mjSpec* s, const char* classname);
@@ -913,46 +204,46 @@ MJAPI mjsDefault* mjs_findDefault(mjSpec* s, const char* classname);
MJAPI mjsDefault* mjs_getSpecDefault(mjSpec* s);
// Get element id.
MJAPI int mjs_getId(mjElement* element);
MJAPI int mjs_getId(mjsElement* element);
//---------------------------------- Tree traversal ------------------------------------------------
// Return body's first child of given type.
MJAPI mjElement* mjs_firstChild(mjsBody* body, mjtObj type);
MJAPI mjsElement* mjs_firstChild(mjsBody* body, mjtObj type);
// Return body's next child of the same type; return NULL if child is last.
MJAPI mjElement* mjs_nextChild(mjsBody* body, mjElement* child);
MJAPI mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child);
//---------------------------------- Attribute setters ---------------------------------------------
// Copy text to string.
MJAPI void mjs_setString(mjString dest, const char* text);
MJAPI void mjs_setString(mjString* dest, const char* text);
// Split text to entries and copy to string vector.
MJAPI void mjs_setStringVec(mjStringVec dest, const char* text);
MJAPI void mjs_setStringVec(mjStringVec* dest, const char* text);
// Set entry in string vector.
MJAPI mjtByte mjs_setInStringVec(mjStringVec dest, int i, const char* text);
MJAPI mjtByte mjs_setInStringVec(mjStringVec* dest, int i, const char* text);
// Append text entry to string vector.
MJAPI void mjs_appendString(mjStringVec dest, const char* text);
MJAPI void mjs_appendString(mjStringVec* dest, const char* text);
// Copy int array to vector.
MJAPI void mjs_setInt(mjIntVec dest, const int* array, int size);
MJAPI void mjs_setInt(mjIntVec* dest, const int* array, int size);
// Append int array to vector of arrays.
MJAPI void mjs_appendIntVec(mjIntVecVec dest, const int* array, int size);
MJAPI void mjs_appendIntVec(mjIntVecVec* dest, const int* array, int size);
// Copy float array to vector.
MJAPI void mjs_setFloat(mjFloatVec dest, const float* array, int size);
MJAPI void mjs_setFloat(mjFloatVec* dest, const float* array, int size);
// Append float array to vector of arrays.
MJAPI void mjs_appendFloatVec(mjFloatVecVec dest, const float* array, int size);
MJAPI void mjs_appendFloatVec(mjFloatVecVec* dest, const float* array, int size);
// Copy double array to vector.
MJAPI void mjs_setDouble(mjDoubleVec dest, const double* array, int size);
MJAPI void mjs_setDouble(mjDoubleVec* dest, const double* array, int size);
// Set plugin attributes.
MJAPI void mjs_setPluginAttributes(mjsPlugin* plugin, void* attributes);
@@ -961,10 +252,10 @@ MJAPI void mjs_setPluginAttributes(mjsPlugin* plugin, void* attributes);
//---------------------------------- Attribute getters ---------------------------------------------
// Get string contents.
MJAPI const char* mjs_getString(mjString source);
MJAPI const char* mjs_getString(const mjString* source);
// Get double array contents and optionally its size.
MJAPI const double* mjs_getDouble(mjDoubleVec source, int* size);
MJAPI const double* mjs_getDouble(const mjDoubleVec* source, int* size);
//---------------------------------- Other utilities -----------------------------------------------
@@ -973,10 +264,10 @@ MJAPI const double* mjs_getDouble(mjDoubleVec source, int* size);
MJAPI void mjs_setActivePlugins(mjSpec* s, void* activeplugins);
// Set element's default.
MJAPI void mjs_setDefault(mjElement* element, mjsDefault* def);
MJAPI void mjs_setDefault(mjsElement* element, mjsDefault* def);
// Set element's enlcosing frame.
MJAPI void mjs_setFrame(mjElement* dest, mjsFrame* frame);
MJAPI void mjs_setFrame(mjsElement* dest, mjsFrame* frame);
// Resolve alternative orientations to quat, return error if any.
MJAPI const char* mjs_resolveOrientation(double quat[4], mjtByte degree, const char* sequence,
@@ -1066,7 +357,7 @@ MJAPI void mjs_defaultPlugin(mjsPlugin* plugin);
//---------------------------------- Compiler cache ------------------------------------------------
typedef struct _mjCache* mjCache;
typedef struct mjCache_* mjCache;
// Set the size of the cache in bytes.
MJAPI void mj_setCacheSize(mjCache cache, size_t size);
@@ -1075,7 +366,7 @@ MJAPI void mj_setCacheSize(mjCache cache, size_t size);
MJAPI mjCache mj_globalCache(void);
#ifdef __cplusplus
}
} // extern "C"
#endif
#endif // MUJOCO_SRC_USER_USER_API_H_
+3 -3
View File
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "user/user_api.h"
#include <mujoco/mjspec.h>
#include "user/user_composite.h"
#include <algorithm>
@@ -69,8 +69,8 @@ mjCComposite::mjCComposite(void) {
mjs_defaultPlugin(&plugin);
plugin_name = "";
plugin_instance_name = "";
plugin.name = (mjString)&plugin_name;
plugin.instance_name = (mjString)&plugin_instance_name;
plugin.name = (mjString*)&plugin_name;
plugin.instance_name = (mjString*)&plugin_instance_name;
// cable
curve[0] = curve[1] = curve[2] = mjCOMPSHAPE_ZERO;
+1 -1
View File
@@ -20,7 +20,7 @@
#include <vector>
#include <mujoco/mjmodel.h>
#include "user/user_api.h"
#include <mujoco/mjspec.h>
#include "user/user_model.h"
#include "user/user_objects.h"
+5 -5
View File
@@ -34,7 +34,7 @@
#include "engine/engine_util_misc.h"
#include "engine/engine_util_spatial.h"
#include "user/user_flexcomp.h"
#include "user/user_api.h"
#include <mujoco/mjspec.h>
#include "user/user_model.h"
#include "user/user_objects.h"
#include "user/user_util.h"
@@ -91,8 +91,8 @@ mjCFlexcomp::mjCFlexcomp(void) {
mjs_defaultOrientation(&alt);
plugin_name = "";
plugin_instance_name = "";
plugin.name = (mjString)&plugin_name;
plugin.instance_name = (mjString)&plugin_instance_name;
plugin.name = (mjString*)&plugin_name;
plugin.instance_name = (mjString*)&plugin_instance_name;
}
@@ -443,7 +443,7 @@ bool mjCFlexcomp::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz) {
if (plugin.active) {
mjsPlugin* pplugin = &body->plugin;
pplugin->active = true;
pplugin->instance = static_cast<mjElement*>(plugin.instance);
pplugin->instance = static_cast<mjsElement*>(plugin.instance);
mjs_setString(pplugin->name, mjs_getString(plugin.name));
mjs_setString(pplugin->instance_name, plugin_instance_name.c_str());
}
@@ -507,7 +507,7 @@ bool mjCFlexcomp::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz) {
if (plugin.active) {
mjsPlugin* pplugin = &pb->plugin;
pplugin->active = true;
pplugin->instance = static_cast<mjElement*>(plugin.instance);
pplugin->instance = static_cast<mjsElement*>(plugin.instance);
mjs_setString(pplugin->name, mjs_getString(plugin.name));
mjs_setString(pplugin->instance_name, plugin_instance_name.c_str());
}
+1 -1
View File
@@ -19,7 +19,7 @@
#include <vector>
#include <mujoco/mujoco.h>
#include "user/user_api.h"
#include <mujoco/mjspec.h>
#include "user/user_model.h"
#include "user/user_objects.h"
+2
View File
@@ -15,6 +15,7 @@
#include <string.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjvisualize.h>
#include <mujoco/mjspec.h>
#include "engine/engine_io.h"
#include "user/user_api.h"
@@ -243,6 +244,7 @@ void mjs_defaultMesh(mjsMesh* mesh) {
memset(mesh, 0, sizeof(mjsMesh));
mesh->refquat[0] = 1;
mesh->scale[0] = mesh->scale[1] = mesh->scale[2] = 1;
mesh->maxhullvert = -1;
}
+73 -67
View File
@@ -27,6 +27,7 @@
#include <utility>
#include <vector>
#include <mujoco/mjspec.h>
#include "user/user_api.h"
#ifdef MUJOCO_TINYOBJLOADER_IMPL
@@ -50,8 +51,8 @@
#include <mujoco/mjmacro.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjtnum.h>
#include <mujoco/mjplugin.h>
#include <mujoco/mjtnum.h>
#include "engine/engine_crossplatform.h"
#include "engine/engine_io.h"
#include "engine/engine_plugin.h"
@@ -135,6 +136,7 @@ mjCMesh::mjCMesh(mjCModel* _model, mjCDef* _def) {
center_ = NULL;
graph_ = NULL;
needhull_ = false;
maxhullvert_ = -1;
invalidorientation_.first = -1;
invalidorientation_.second = -1;
validarea_ = true;
@@ -195,19 +197,19 @@ mjCMesh& mjCMesh::operator=(const mjCMesh& other) {
void mjCMesh::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.file = (mjString)&spec_file_;
spec.content_type = (mjString)&spec_content_type_;
spec.uservert = (mjFloatVec)&spec_vert_;
spec.usernormal = (mjFloatVec)&spec_normal_;
spec.userface = (mjIntVec)&spec_face_;
spec.usertexcoord = (mjFloatVec)&spec_texcoord_;
spec.userfacetexcoord = (mjIntVec)&spec_facetexcoord_;
spec.plugin.name = (mjString)&plugin_name;
spec.plugin.instance_name = (mjString)&plugin_instance_name;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.classname = &classname;
spec.file = &spec_file_;
spec.content_type = &spec_content_type_;
spec.uservert = &spec_vert_;
spec.usernormal = &spec_normal_;
spec.userface = &spec_face_;
spec.usertexcoord = &spec_texcoord_;
spec.userfacetexcoord = &spec_facetexcoord_;
spec.plugin.name = &plugin_name;
spec.plugin.instance_name = &plugin_instance_name;
spec.info = &info;
}
@@ -221,13 +223,14 @@ void mjCMesh::CopyFromSpec() {
face_ = spec_face_;
texcoord_ = spec_texcoord_;
facetexcoord_ = spec_facetexcoord_;
file = (mjString)&file_;
content_type = (mjString)&content_type_;
uservert = (mjFloatVec)&vert_;
usernormal = (mjFloatVec)&normal_;
userface = (mjIntVec)&face_;
usertexcoord = (mjFloatVec)&texcoord_;
userfacetexcoord = (mjIntVec)&facetexcoord_;
file = &file_;
content_type = &content_type_;
maxhullvert_ = spec.maxhullvert;
uservert = &vert_;
usernormal = &normal_;
userface = &face_;
usertexcoord = &texcoord_;
userfacetexcoord = &facetexcoord_;
plugin.active = spec.plugin.active;
plugin.instance = spec.plugin.instance;
plugin.name = spec.plugin.name;
@@ -1268,7 +1271,7 @@ void mjCMesh::ApplyTransformations() {
// process vertices
for (int i=0; i < nvert(); i++) {
mjtNum p1[3], p0[3] = {vert_[3*i], vert_[3*i+1], vert_[3*i+2]};
mju_rotVecMatT(p1, p0, mat);
mju_mulMatTVec3(p1, mat, p0);
vert_[3*i] = (float) p1[0];
vert_[3*i+1] = (float) p1[1];
vert_[3*i+2] = (float) p1[2];
@@ -1277,7 +1280,7 @@ void mjCMesh::ApplyTransformations() {
// process normals
for (int i=0; i < nnormal(); i++) {
mjtNum n1[3], n0[3] = {normal_[3*i], normal_[3*i+1], normal_[3*i+2]};
mju_rotVecMatT(n1, n0, mat);
mju_mulMatTVec3(n1, mat, n0);
normal_[3*i] = (float) n1[0];
normal_[3*i+1] = (float) n1[1];
normal_[3*i+2] = (float) n1[2];
@@ -1548,12 +1551,17 @@ double& mjCMesh::GetVolumeRef(mjtGeomInertia type) {
// make graph describing convex hull
void mjCMesh::MakeGraph(void) {
void mjCMesh::MakeGraph() {
int adr, ok, curlong, totlong, exitcode;
double* data;
facetT* facet, **facetp;
vertexT* vertex, *vertex1, **vertex1p;
char qhopt[10] = "qhull Qt";
std::string qhopt = "qhull Qt";
if (maxhullvert_ > -1) {
// qhull "TA" actually means "number of vertices added after the initial simplex"
qhopt += " TA" + std::to_string(maxhullvert_ - 4);
}
// graph not needed for small meshes
if (nvert() < 4) {
@@ -1585,7 +1593,7 @@ void mjCMesh::MakeGraph(void) {
qh->NOerrexit = false;
if (!exitcode) {
// actual init
qh_initflags(qh, qhopt);
qh_initflags(qh, const_cast<char*>(qhopt.c_str()));
qh_init_B(qh, data, nvert(), 3, False);
// construct convex hull
@@ -1742,8 +1750,6 @@ void mjCMesh::MakeGraph(void) {
}
}
// copy graph into face data
void mjCMesh::CopyGraph(void) {
// only if face data is missing
@@ -1978,20 +1984,20 @@ mjCSkin& mjCSkin::operator=(const mjCSkin& other) {
void mjCSkin::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.file = (mjString)&spec_file_;
spec.material = (mjString)&spec_material_;
spec.vert = (mjFloatVec)&spec_vert_;
spec.texcoord = (mjFloatVec)&spec_texcoord_;
spec.face = (mjIntVec)&spec_face_;
spec.bodyname = (mjStringVec)&spec_bodyname_;
spec.bindpos = (mjFloatVec)&spec_bindpos_;
spec.bindquat = (mjFloatVec)&spec_bindquat_;
spec.vertid = (mjIntVecVec)&spec_vertid_;
spec.vertweight = (mjFloatVecVec)&spec_vertweight_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.classname = &classname;
spec.file = &spec_file_;
spec.material = &spec_material_;
spec.vert = &spec_vert_;
spec.texcoord = &spec_texcoord_;
spec.face = &spec_face_;
spec.bodyname = &spec_bodyname_;
spec.bindpos = &spec_bindpos_;
spec.bindquat = &spec_bindquat_;
spec.vertid = &spec_vertid_;
spec.vertweight = &spec_vertweight_;
spec.info = &info;
}
@@ -2016,16 +2022,16 @@ void mjCSkin::CopyFromSpec() {
bindquat_ = spec_bindquat_;
vertid_ = spec_vertid_;
vertweight_ = spec_vertweight_;
file = (mjString)&spec_file_;
material = (mjString)&spec_material_;
vert = (mjFloatVec)&spec_vert_;
texcoord = (mjFloatVec)&spec_texcoord_;
face = (mjIntVec)&spec_face_;
bodyname = (mjStringVec)&spec_bodyname_;
bindpos = (mjFloatVec)&spec_bindpos_;
bindquat = (mjFloatVec)&spec_bindquat_;
vertid = (mjIntVecVec)&spec_vertid_;
vertweight = (mjFloatVecVec)&spec_vertweight_;
file = &spec_file_;
material = &spec_material_;
vert = &spec_vert_;
texcoord = &spec_texcoord_;
face = &spec_face_;
bodyname = &spec_bodyname_;
bindpos = &spec_bindpos_;
bindquat = &spec_bindquat_;
vertid = &spec_vertid_;
vertweight = &spec_vertweight_;
}
@@ -2390,15 +2396,15 @@ mjCFlex& mjCFlex::operator=(const mjCFlex& other) {
void mjCFlex::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.material = (mjString)&spec_material_;
spec.vertbody = (mjStringVec)&spec_vertbody_;
spec.vert = (mjDoubleVec)&spec_vert_;
spec.texcoord = (mjFloatVec)&spec_texcoord_;
spec.elem = (mjIntVec)&spec_elem_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.classname = &classname;
spec.material = &spec_material_;
spec.vertbody = &spec_vertbody_;
spec.vert = &spec_vert_;
spec.texcoord = &spec_texcoord_;
spec.elem = &spec_elem_;
spec.info = &info;
}
@@ -2413,17 +2419,17 @@ void mjCFlex::NameSpace(const mjCModel* m) {
void mjCFlex::CopyFromSpec() {
*static_cast<mjsFlex*>(this) = spec;
spec.info = (mjString)&info;
spec.info = &info;
material_ = spec_material_;
vertbody_ = spec_vertbody_;
vert_ = spec_vert_;
texcoord_ = spec_texcoord_;
elem_ = spec_elem_;
material = (mjString)&material_;
vertbody = (mjStringVec)&vertbody_;
vert = (mjDoubleVec)&vert_;
texcoord = (mjFloatVec)&texcoord_;
elem = (mjIntVec)&elem_;
material = &material_;
vertbody = &vertbody_;
vert = &vert_;
texcoord = &texcoord_;
elem = &elem_;
// clear precompiled asset. TODO: use asset cache
nedge = 0;
+91 -16
View File
@@ -28,6 +28,7 @@
#include <mujoco/mjdata.h>
#include <mujoco/mjmacro.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjspec.h>
#include <mujoco/mjtnum.h>
#include <mujoco/mjplugin.h>
#include <mujoco/mjvisualize.h>
@@ -416,12 +417,12 @@ void mjCModel::CreateObjectLists() {
void mjCModel::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.comment = (mjString)&spec_comment_;
spec.modelfiledir = (mjString)&spec_modelfiledir_;
spec.modelname = (mjString)&spec_modelname_;
spec.meshdir = (mjString)&spec_meshdir_;
spec.texturedir = (mjString)&spec_texturedir_;
spec.element = static_cast<mjsElement*>(this);
spec.comment = &spec_comment_;
spec.modelfiledir = &spec_modelfiledir_;
spec.modelname = &spec_modelname_;
spec.meshdir = &spec_meshdir_;
spec.texturedir = &spec_texturedir_;
}
@@ -433,11 +434,11 @@ void mjCModel::CopyFromSpec() {
modelname_ = spec_modelname_;
meshdir_ = spec_meshdir_;
texturedir_ = spec_texturedir_;
comment = (mjString)&comment_;
modelfiledir = (mjString)&modelfiledir_;
modelname = (mjString)&modelname_;
meshdir = (mjString)&meshdir_;
texturedir = (mjString)&texturedir_;
comment = &comment_;
modelfiledir = &modelfiledir_;
modelname = &modelname_;
meshdir = &meshdir_;
texturedir = &texturedir_;
}
@@ -1843,6 +1844,8 @@ void mjCModel::CopyTree(mjModel* m) {
int jid = pj->id;
// set joint fields
pj->qposadr_ = qposadr;
pj->dofadr_ = dofadr;
m->jnt_type[jid] = pj->type;
m->jnt_group[jid] = pj->group;
m->jnt_limited[jid] = (mjtByte)pj->is_limited();
@@ -2037,6 +2040,7 @@ void mjCModel::CopyTree(mjModel* m) {
m->cam_targetbodyid[cid] = pc->targetbodyid;
copyvec(m->cam_pos+3*cid, pc->pos, 3);
copyvec(m->cam_quat+4*cid, pc->quat, 4);
m->cam_orthographic[cid] = pc->orthographic;
m->cam_fovy[cid] = (mjtNum)pc->fovy;
m->cam_ipd[cid] = (mjtNum)pc->ipd;
copyvec(m->cam_resolution+2*cid, pc->resolution, 2);
@@ -2584,6 +2588,8 @@ void mjCModel::CopyObjects(mjModel* m) {
m->actuator_trnid[2*i+1] = pac->trnid[1];
m->actuator_actnum[i] = pac->actdim + pac->plugin_actdim;
m->actuator_actadr[i] = m->actuator_actnum[i] ? adr : -1;
pac->actadr_ = m->actuator_actadr[i];
pac->actnum_ = m->actuator_actnum[i];
adr += m->actuator_actnum[i];
m->actuator_group[i] = pac->group;
m->actuator_ctrllimited[i] = (mjtByte)pac->is_ctrllimited();
@@ -2716,6 +2722,75 @@ void mjCModel::CopyObjects(mjModel* m) {
// save the current state
void mjCModel::SaveState(const mjData* d) {
for (auto joint : joints_) {
switch (joint->type) {
case mjJNT_FREE:
mju_copy(joint->qpos, d->qpos + joint->qposadr_, 7);
mju_copy(joint->qvel, d->qvel + joint->dofadr_, 6);
break;
case mjJNT_BALL:
mju_copy(joint->qpos, d->qpos + joint->qposadr_, 4);
mju_copy(joint->qvel, d->qvel + joint->dofadr_, 3);
break;
case mjJNT_HINGE:
case mjJNT_SLIDE:
mju_copy(joint->qpos, d->qpos + joint->qposadr_, 1);
mju_copy(joint->qvel, d->qvel + joint->dofadr_, 1);
break;
}
}
for (auto actuator : actuators_) {
if (actuator->actadr_ != -1) {
actuator->act.assign(actuator->actnum_, 0);
mju_copy(actuator->act.data(), d->act + actuator->actadr_, actuator->actnum_);
}
}
}
// restore the previous state
void mjCModel::RestoreState(const mjModel* m, mjData** dest) {
mj_makeRawData(dest, m);
mjData* d = *dest;
if (d) {
mj_initPlugin(m, d);
mj_resetData(m, d);
}
for (auto joint : joints_) {
if (!mjuu_defined(joint->qpos[0]) || !mjuu_defined(joint->qvel[0])) {
continue;
}
switch (joint->type) {
case mjJNT_FREE:
mju_copy(d->qpos + joint->qposadr_, joint->qpos, 7);
mju_copy(d->qvel + joint->dofadr_, joint->qvel, 6);
break;
case mjJNT_BALL:
mju_copy(d->qpos + joint->qposadr_, joint->qpos, 4);
mju_copy(d->qvel + joint->dofadr_, joint->qvel, 3);
break;
case mjJNT_HINGE:
case mjJNT_SLIDE:
mju_copy(d->qpos + joint->qposadr_, joint->qpos, 1);
mju_copy(d->qvel + joint->dofadr_, joint->qvel, 1);
break;
}
}
for (auto actuator : actuators_) {
if (mjuu_defined(actuator->act[0])) {
mju_copy(d->act + actuator->actadr_, actuator->act.data(), actuator->actnum_);
}
}
}
//------------------------------- FUSE STATIC ------------------------------------------------------
template <class T>
@@ -3075,7 +3150,7 @@ static void warninghandler(const char* msg) {
// compiler
mjModel* mjCModel::Compile(const mjVFS* vfs) {
mjModel* mjCModel::Compile(const mjVFS* vfs, mjModel** m) {
if (compiled) {
// clear kinematic tree
for (int i=0; i<bodies_.size(); i++) {
@@ -3096,7 +3171,7 @@ mjModel* mjCModel::Compile(const mjVFS* vfs) {
// setjmp returns, and therefore to pass nullptr directly to the
// mj_deleteModel and mj_deleteData calls in the subsequent catch block,
// without ever reading the actual pointer values.
mjModel* volatile m = nullptr;
mjModel* volatile model = (m && *m) ? *m : nullptr;
mjData* volatile data = nullptr;
// save error and warning handlers
@@ -3118,10 +3193,10 @@ mjModel* mjCModel::Compile(const mjVFS* vfs) {
// TryCompile resulted in an mju_error which was converted to a longjmp.
throw mjCError(0, "engine error: %s", errortext);
}
TryCompile(*const_cast<mjModel**>(&m), *const_cast<mjData**>(&data), vfs);
TryCompile(*const_cast<mjModel**>(&model), *const_cast<mjData**>(&data), vfs);
} catch (mjCError err) {
// deallocate everything allocated in Compile
mj_deleteModel(m);
mj_deleteModel(model);
mj_deleteData(data);
mjCBody* world = bodies_[0];
Clear();
@@ -3140,7 +3215,7 @@ mjModel* mjCModel::Compile(const mjVFS* vfs) {
_mjPRIVATE__set_tls_error_fn(save_error);
_mjPRIVATE__set_tls_warning_fn(save_warning);
compiled = true;
return m;
return model;
}
+8 -6
View File
@@ -27,13 +27,13 @@
#include <mujoco/mjmodel.h>
#include <mujoco/mjplugin.h>
#include <mujoco/mjtnum.h>
#include "user/user_api.h"
#include <mujoco/mjspec.h>
#include "user/user_objects.h"
typedef std::map<std::string, int, std::less<> > mjKeyMap;
typedef std::array<mjKeyMap, mjNOBJECT> mjListKeyMap;
class mjCModel_ : public mjElement {
class mjCModel_ : public mjsElement {
public:
// attach namespaces
std::string prefix;
@@ -168,7 +168,7 @@ class mjCModel : public mjCModel_, private mjSpec {
mjSpec spec;
mjModel* Compile(const mjVFS* vfs = nullptr); // construct mjModel
mjModel* Compile(const mjVFS* vfs = nullptr, mjModel** m = nullptr); // construct mjModel
bool CopyBack(const mjModel*); // DECOMPILER: copy numeric back
void FuseStatic(); // fuse static bodies with parent
void FuseReindex(mjCBody* body); // reindex elements during fuse
@@ -254,9 +254,6 @@ class mjCModel : public mjCModel_, private mjSpec {
const std::string& plugin_instance_name,
mjCPlugin** plugin_instance);
void TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs);
mjModel* _Compile(const mjVFS* vfs);
// clear objects allocated by Compile
void Clear();
@@ -267,6 +264,10 @@ class mjCModel : public mjCModel_, private mjSpec {
template <class T> void DeleteMaterial(std::vector<T*>& list,
std::string_view name = "");
// save/restore the current state
void SaveState(const mjData* d);
void RestoreState(const mjModel* m, mjData** dest);
private:
// settings for each defaults class
std::vector<mjCDef*> defaults_;
@@ -275,6 +276,7 @@ class mjCModel : public mjCModel_, private mjSpec {
std::vector<std::pair<const mjpPlugin*, int>> active_plugins_;
// compile phases
void TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs);
void MakeLists(mjCBody* body); // make lists of bodies, geoms, joints, sites
void SetNuser(); // set nuser fields
void IndexAssets(bool discard); // convert asset names into indices
+189 -183
View File
@@ -45,6 +45,7 @@
#include "engine/engine_util_misc.h"
#include "engine/engine_util_solve.h"
#include "engine/engine_util_spatial.h"
#include <mujoco/mjspec.h>
#include "user/user_api.h"
#include "user/user_cache.h"
#include "user/user_model.h"
@@ -640,8 +641,8 @@ void mjCDef::PointToLocal() {
equality_.PointToLocal();
tendon_.PointToLocal();
actuator_.PointToLocal();
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.joint = &joint_.spec;
spec.geom = &geom_.spec;
spec.site = &site_.spec;
@@ -949,20 +950,20 @@ mjCBody& mjCBody::operator-=(const mjCBody& subtree) {
void mjCBody::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.childclass = (mjString)&classname;
spec.userdata = (mjDoubleVec)&spec_userdata_;
spec.plugin.name = (mjString)&plugin_name;
spec.plugin.instance_name = (mjString)&plugin_instance_name;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.childclass = &classname;
spec.userdata = &spec_userdata_;
spec.plugin.name = &plugin_name;
spec.plugin.instance_name = (&plugin_instance_name);
spec.info = &info;
}
void mjCBody::CopyFromSpec() {
*static_cast<mjsBody*>(this) = spec;
userdata_ = spec_userdata_;
userdata = (mjDoubleVec)&userdata_;
userdata = &userdata_;
plugin.active = spec.plugin.active;
plugin.instance = spec.plugin.instance;
plugin.name = spec.plugin.name;
@@ -1256,7 +1257,7 @@ mjCBase* mjCBody::FindObject(mjtObj type, string _name, bool recursive) {
template <class T>
static mjElement* GetNext(std::vector<T*>& list, mjElement* child) {
static mjsElement* GetNext(std::vector<T*>& list, mjsElement* child) {
for (unsigned int i = 0; i < list.size()-1; i++) {
if (list[i]->spec.element == child) {
return list[i+1]->spec.element;
@@ -1268,7 +1269,7 @@ static mjElement* GetNext(std::vector<T*>& list, mjElement* child) {
// get next child of given type
mjElement* mjCBody::NextChild(mjElement* child, mjtObj type) {
mjsElement* mjCBody::NextChild(mjsElement* child, mjtObj type) {
if (type == mjOBJ_UNKNOWN) {
if (!child) {
throw mjCError(this, "child type must be specified if no child element is given");
@@ -1669,10 +1670,10 @@ void mjCFrame::SetParent(mjCBody* _body) {
void mjCFrame::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.childclass = (mjString)&classname;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.childclass = &classname;
spec.info = &info;
}
@@ -1733,6 +1734,10 @@ mjCJoint::mjCJoint(mjCModel* _model, mjCDef* _def) {
// in case this joint is not compiled
CopyFromSpec();
// no previous state when a joint is created
qpos[0] = mjNAN;
qvel[0] = mjNAN;
}
@@ -1761,11 +1766,11 @@ bool mjCJoint::is_actfrclimited() const { return islimited(actfrclimited, actfrc
void mjCJoint::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.userdata = (mjDoubleVec)&spec_userdata_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.classname = &classname;
spec.userdata = &spec_userdata_;
spec.info = &info;
}
@@ -1773,7 +1778,7 @@ void mjCJoint::PointToLocal() {
void mjCJoint::CopyFromSpec() {
*static_cast<mjsJoint*>(this) = spec;
userdata_ = spec_userdata_;
userdata = (mjDoubleVec)&spec_userdata_;
userdata = &spec_userdata_;
}
@@ -1961,16 +1966,16 @@ mjCGeom& mjCGeom::operator=(const mjCGeom& other) {
// to be called after any default copy constructor
void mjCGeom::PointToLocal(void) {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.info = (mjString)&info;
spec.classname = (mjString)&classname;
spec.userdata = (mjDoubleVec)&spec_userdata_;
spec.material = (mjString)&spec_material_;
spec.meshname = (mjString)&spec_meshname_;
spec.hfieldname = (mjString)&spec_hfieldname_;
spec.plugin.name = (mjString)&plugin_name;
spec.plugin.instance_name = (mjString)&plugin_instance_name;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.info = &info;
spec.classname = &classname;
spec.userdata = &spec_userdata_;
spec.material = &spec_material_;
spec.meshname = &spec_meshname_;
spec.hfieldname = &spec_hfieldname_;
spec.plugin.name = &plugin_name;
spec.plugin.instance_name = &plugin_instance_name;
}
@@ -1981,10 +1986,10 @@ void mjCGeom::CopyFromSpec() {
hfieldname_ = spec_hfieldname_;
meshname_ = spec_meshname_;
material_ = spec_material_;
userdata = (mjDoubleVec)&userdata_;
hfieldname = (mjString)&hfieldname_;
meshname = (mjString)&meshname_;
material = (mjString)&material_;
userdata = &userdata_;
hfieldname = &hfieldname_;
meshname = &meshname_;
material = &material_;
plugin.active = spec.plugin.active;
plugin.instance = spec.plugin.instance;
plugin.name = spec.plugin.name;
@@ -2594,12 +2599,12 @@ mjCSite& mjCSite::operator=(const mjCSite& other) {
void mjCSite::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.info = (mjString)&info;
spec.classname = (mjString)&classname;
spec.material = (mjString)&spec_material_;
spec.userdata = (mjDoubleVec)&spec_userdata_;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.info = &info;
spec.classname = &classname;
spec.material = &spec_material_;
spec.userdata = &spec_userdata_;
}
@@ -2608,8 +2613,8 @@ void mjCSite::CopyFromSpec() {
*static_cast<mjsSite*>(this) = spec;
userdata_ = spec_userdata_;
material_ = spec_material_;
userdata = (mjDoubleVec)&userdata_;
material = (mjString)&material_;
userdata = &userdata_;
material = &material_;
}
@@ -2746,12 +2751,12 @@ mjCCamera& mjCCamera::operator=(const mjCCamera& other) {
void mjCCamera::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.userdata = (mjDoubleVec)&spec_userdata_;
spec.targetbody = (mjString)&spec_targetbody_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.classname = &classname;
spec.userdata = &spec_userdata_;
spec.targetbody = &spec_targetbody_;
spec.info = &info;
}
@@ -2771,8 +2776,8 @@ void mjCCamera::CopyFromSpec() {
*static_cast<mjsCamera*>(this) = spec;
userdata_ = spec_userdata_;
targetbody_ = spec_targetbody_;
userdata = (mjDoubleVec)&userdata_;
targetbody = (mjString)&targetbody_;
userdata = &userdata_;
targetbody = &targetbody_;
}
@@ -2897,11 +2902,11 @@ mjCLight& mjCLight::operator=(const mjCLight& other) {
void mjCLight::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.targetbody = (mjString)&spec_targetbody_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.classname = &classname;
spec.targetbody = &spec_targetbody_;
spec.info = &info;
}
@@ -2920,7 +2925,7 @@ void mjCLight::NameSpace(const mjCModel* m) {
void mjCLight::CopyFromSpec() {
*static_cast<mjsLight*>(this) = spec;
targetbody_ = spec_targetbody_;
targetbody = (mjString)&targetbody_;
targetbody = &targetbody_;
}
@@ -2997,12 +3002,12 @@ mjCHField& mjCHField::operator=(const mjCHField& other) {
void mjCHField::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.file = (mjString)&spec_file_;
spec.content_type = (mjString)&spec_content_type_;
spec.userdata = (mjFloatVec)&spec_userdata_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.file = &spec_file_;
spec.content_type = &spec_content_type_;
spec.userdata = &spec_userdata_;
spec.info = &info;
}
@@ -3012,9 +3017,9 @@ void mjCHField::CopyFromSpec() {
file_ = spec_file_;
content_type_ = spec_content_type_;
userdata_ = spec_userdata_;
file = (mjString)&file_;
content_type = (mjString)&content_type_;
userdata = (mjFloatVec)&userdata_;
file = &file_;
content_type = &content_type_;
userdata = &userdata_;
// clear precompiled asset. TODO: use asset cache
data.clear();
@@ -3202,7 +3207,7 @@ mjCTexture::mjCTexture(mjCModel* _model) {
// point to local
PointToLocal();
// in case this camera is not compiled
// in case this texture is not compiled
CopyFromSpec();
}
@@ -3226,13 +3231,13 @@ mjCTexture& mjCTexture::operator=(const mjCTexture& other) {
void mjCTexture::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.file = (mjString)&spec_file_;
spec.content_type = (mjString)&spec_content_type_;
spec.cubefiles = (mjStringVec)&spec_cubefiles_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.classname = &classname;
spec.file = &spec_file_;
spec.content_type = &spec_content_type_;
spec.cubefiles = &spec_cubefiles_;
spec.info = &info;
}
@@ -3242,9 +3247,9 @@ void mjCTexture::CopyFromSpec() {
file_ = spec_file_;
content_type_ = spec_content_type_;
cubefiles_ = spec_cubefiles_;
file = (mjString)&file_;
content_type = (mjString)&content_type_;
cubefiles = (mjStringVec)&cubefiles_;
file = &file_;
content_type = &content_type_;
cubefiles = &cubefiles_;
// clear precompiled asset. TODO: use asset cache
rgb.clear();
@@ -3905,14 +3910,12 @@ mjCMaterial::mjCMaterial(mjCModel* _model, mjCDef* _def) {
*this = _def->Material();
}
// set model, def
model = _model;
def = (_def ? _def : (_model ? _model->Defaults(0) : 0));
// point to local
PointToLocal();
// in case this camera is not compiled
// in case this material is not compiled
CopyFromSpec();
}
@@ -3937,11 +3940,11 @@ mjCMaterial& mjCMaterial::operator=(const mjCMaterial& other) {
void mjCMaterial::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.texture = (mjString)&spec_texture_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.classname = &classname;
spec.texture = &spec_texture_;
spec.info = &info;
}
@@ -3949,7 +3952,7 @@ void mjCMaterial::PointToLocal() {
void mjCMaterial::CopyFromSpec() {
*static_cast<mjsMaterial*>(this) = spec;
texture_ = spec_texture_;
texture = (mjString)&texture_;
texture = &texture_;
}
@@ -4027,12 +4030,12 @@ mjCPair& mjCPair::operator=(const mjCPair& other) {
void mjCPair::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.geomname1 = (mjString)&spec_geomname1_;
spec.geomname2 = (mjString)&spec_geomname2_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.classname = &classname;
spec.geomname1 = &spec_geomname1_;
spec.geomname2 = &spec_geomname2_;
spec.info = &info;
}
@@ -4051,8 +4054,8 @@ void mjCPair::CopyFromSpec() {
*static_cast<mjsPair*>(this) = spec;
geomname1_ = spec_geomname1_;
geomname2_ = spec_geomname2_;
geomname1 = (mjString)&geomname1_;
geomname2 = (mjString)&geomname2_;
geomname1 = &geomname1_;
geomname2 = &geomname2_;
}
@@ -4252,11 +4255,11 @@ mjCBodyPair& mjCBodyPair::operator=(const mjCBodyPair& other) {
void mjCBodyPair::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.bodyname1 = (mjString)&spec_bodyname1_;
spec.bodyname2 = (mjString)&spec_bodyname2_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.bodyname1 = &spec_bodyname1_;
spec.bodyname2 = &spec_bodyname2_;
spec.info = &info;
}
@@ -4275,8 +4278,8 @@ void mjCBodyPair::CopyFromSpec() {
*static_cast<mjsExclude*>(this) = spec;
bodyname1_ = spec_bodyname1_;
bodyname2_ = spec_bodyname2_;
bodyname1 = (mjString)&bodyname1_;
bodyname2 = (mjString)&bodyname2_;
bodyname1 = &bodyname1_;
bodyname2 = &bodyname2_;
}
@@ -4386,12 +4389,12 @@ mjCEquality& mjCEquality::operator=(const mjCEquality& other) {
void mjCEquality::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.name1 = (mjString)&spec_name1_;
spec.name2 = (mjString)&spec_name2_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.classname = &classname;
spec.name1 = &spec_name1_;
spec.name2 = &spec_name2_;
spec.info = &info;
}
@@ -4410,8 +4413,8 @@ void mjCEquality::CopyFromSpec() {
*static_cast<mjsEquality*>(this) = spec;
name1_ = spec_name1_;
name2_ = spec_name2_;
name1 = (mjString)&name1_;
name2 = (mjString)&name2_;
name1 = &name1_;
name2 = &name2_;
}
@@ -4555,12 +4558,12 @@ bool mjCTendon::is_limited() const { return islimited(limited, range); }
void mjCTendon::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.material = (mjString)&spec_material_;
spec.userdata = (mjDoubleVec)&spec_userdata_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.classname = &classname;
spec.material = &spec_material_;
spec.userdata = &spec_userdata_;
spec.info = &info;
}
@@ -4579,8 +4582,8 @@ void mjCTendon::CopyFromSpec() {
*static_cast<mjsTendon*>(this) = spec;
material_ = spec_material_;
userdata_ = spec_userdata_;
material = (mjString)&material_;
userdata = (mjDoubleVec)&userdata_;
material = &material_;
userdata = &userdata_;
// clear precompiled
for (int i=0; i<path.size(); i++) {
@@ -4887,8 +4890,8 @@ mjCWrap& mjCWrap::operator=(const mjCWrap& other) {
void mjCWrap::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.info = &info;
}
@@ -5003,6 +5006,9 @@ mjCActuator::mjCActuator(mjCModel* _model, mjCDef* _def) {
// point to local
PointToLocal();
// no previous state when an actuator is created
act.push_back(mjNAN);
}
@@ -5033,16 +5039,16 @@ bool mjCActuator::is_actlimited() const { return islimited(actlimited, actrange)
void mjCActuator::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.userdata = (mjDoubleVec)&spec_userdata_;
spec.target = (mjString)&spec_target_;
spec.refsite = (mjString)&spec_refsite_;
spec.slidersite = (mjString)&spec_slidersite_;
spec.plugin.name = (mjString)&plugin_name;
spec.plugin.instance_name = (mjString)&plugin_instance_name;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.classname = &classname;
spec.userdata = &spec_userdata_;
spec.target = &spec_target_;
spec.refsite = &spec_refsite_;
spec.slidersite = &spec_slidersite_;
spec.plugin.name = &plugin_name;
spec.plugin.instance_name = &plugin_instance_name;
spec.info = &info;
}
@@ -5064,10 +5070,10 @@ void mjCActuator::CopyFromSpec() {
target_ = spec_target_;
refsite_ = spec_refsite_;
slidersite_ = spec_slidersite_;
userdata = (mjDoubleVec)&userdata_;
target = (mjString)&target_;
refsite = (mjString)&refsite_;
slidersite = (mjString)&slidersite_;
userdata = &userdata_;
target = &target_;
refsite = &refsite_;
slidersite = &slidersite_;
plugin.active = spec.plugin.active;
plugin.instance = spec.plugin.instance;
plugin.name = spec.plugin.name;
@@ -5356,15 +5362,15 @@ mjCSensor& mjCSensor::operator=(const mjCSensor& other) {
void mjCSensor::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.userdata = (mjDoubleVec)&spec_userdata_;
spec.objname = (mjString)&spec_objname_;
spec.refname = (mjString)&spec_refname_;
spec.plugin.name = (mjString)&plugin_name;
spec.plugin.instance_name = (mjString)&plugin_instance_name;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.classname = &classname;
spec.userdata = &spec_userdata_;
spec.objname = &spec_objname_;
spec.refname = &spec_refname_;
spec.plugin.name = &plugin_name;
spec.plugin.instance_name = &plugin_instance_name;
spec.info = &info;
}
@@ -5384,9 +5390,9 @@ void mjCSensor::CopyFromSpec() {
userdata_ = spec_userdata_;
objname_ = spec_objname_;
refname_ = spec_refname_;
userdata = (mjDoubleVec)&userdata_;
objname = (mjString)&objname_;
refname = (mjString)&refname_;
userdata = &userdata_;
objname = &objname_;
refname = &refname_;
plugin.active = spec.plugin.active;
plugin.instance = spec.plugin.instance;
plugin.name = spec.plugin.name;
@@ -5859,10 +5865,10 @@ mjCNumeric& mjCNumeric::operator=(const mjCNumeric& other) {
void mjCNumeric::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.data = (mjDoubleVec)&spec_data_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.data = &spec_data_;
spec.info = &info;
}
@@ -5870,7 +5876,7 @@ void mjCNumeric::PointToLocal() {
void mjCNumeric::CopyFromSpec() {
*static_cast<mjsNumeric*>(this) = spec;
data_ = spec_data_;
data = (mjDoubleVec)&data_;
data = &data_;
}
@@ -5948,10 +5954,10 @@ mjCText& mjCText::operator=(const mjCText& other) {
void mjCText::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.data = (mjString)&spec_data_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.data = &spec_data_;
spec.info = &info;
}
@@ -5959,7 +5965,7 @@ void mjCText::PointToLocal() {
void mjCText::CopyFromSpec() {
*static_cast<mjsText*>(this) = spec;
data_ = spec_data_;
data = (mjString)&data_;
data = &data_;
}
@@ -6028,12 +6034,12 @@ mjCTuple& mjCTuple::operator=(const mjCTuple& other) {
void mjCTuple::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.objtype = (mjIntVec)&spec_objtype_;
spec.objname = (mjStringVec)&spec_objname_;
spec.objprm = (mjDoubleVec)&spec_objprm_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.objtype = (mjIntVec*)&spec_objtype_;
spec.objname = &spec_objname_;
spec.objprm = &spec_objprm_;
spec.info = &info;
}
@@ -6054,9 +6060,9 @@ void mjCTuple::CopyFromSpec() {
objtype_ = spec_objtype_;
objname_ = spec_objname_;
objprm_ = spec_objprm_;
objtype = (mjIntVec)&objtype_;
objname = (mjStringVec)&objname_;
objprm = (mjDoubleVec)&objprm_;
objtype = (mjIntVec*)&objtype_;
objname = &objname_;
objprm = &objprm_;
}
@@ -6163,15 +6169,15 @@ mjCKey& mjCKey::operator=(const mjCKey& other) {
void mjCKey::PointToLocal() {
spec.element = static_cast<mjElement*>(this);
spec.name = (mjString)&name;
spec.qpos = (mjDoubleVec)&spec_qpos_;
spec.qvel = (mjDoubleVec)&spec_qvel_;
spec.act = (mjDoubleVec)&spec_act_;
spec.mpos = (mjDoubleVec)&spec_mpos_;
spec.mquat = (mjDoubleVec)&spec_mquat_;
spec.ctrl = (mjDoubleVec)&spec_ctrl_;
spec.info = (mjString)&info;
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
spec.qpos = &spec_qpos_;
spec.qvel = &spec_qvel_;
spec.act = &spec_act_;
spec.mpos = &spec_mpos_;
spec.mquat = &spec_mquat_;
spec.ctrl = &spec_ctrl_;
spec.info = &info;
}
@@ -6184,12 +6190,12 @@ void mjCKey::CopyFromSpec() {
mpos_ = spec_mpos_;
mquat_ = spec_mquat_;
ctrl_ = spec_ctrl_;
qpos = (mjDoubleVec)&qpos_;
qvel = (mjDoubleVec)&qvel_;
act = (mjDoubleVec)&act_;
mpos = (mjDoubleVec)&mpos_;
mquat = (mjDoubleVec)&mquat_;
ctrl = (mjDoubleVec)&ctrl_;
qpos = &qpos_;
qvel = &qvel_;
act = &act_;
mpos = &mpos_;
mquat = &mquat_;
ctrl = &ctrl_;
}
@@ -6307,9 +6313,9 @@ mjCPlugin::mjCPlugin(mjCModel* _model) {
// public interface
mjs_defaultPlugin(&spec);
elemtype = mjOBJ_PLUGIN;
spec.name = (mjString)&name;
spec.instance_name = (mjString)&instance_name;
spec.info = (mjString)&info;
spec.name = &name;
spec.instance_name = &instance_name;
spec.info = &info;
}
+15 -6
View File
@@ -26,7 +26,7 @@
#include <mujoco/mjtnum.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjplugin.h>
#include "user/user_api.h"
#include <mujoco/mjspec.h>
#include "user/user_cache.h"
#include "user/user_util.h"
@@ -168,7 +168,7 @@ class mjCBoundingVolumeHierarchy : public mjCBoundingVolumeHierarchy_ {
//------------------------- class mjCBase ----------------------------------------------------------
// Generic functionality for all derived classes
class mjCBase_ : public mjElement {
class mjCBase_ : public mjsElement {
public:
int id; // object id
std::string name; // object name
@@ -309,7 +309,7 @@ class mjCBody : public mjCBody_, private mjsBody {
const std::vector<double>& get_userdata() { return userdata_; }
// get next child of given type
mjElement* NextChild(mjElement* child, mjtObj type = mjOBJ_UNKNOWN);
mjsElement* NextChild(mjsElement* child, mjtObj type = mjOBJ_UNKNOWN);
private:
mjCBody(const mjCBody& other, mjCModel* _model); // copy constructor
@@ -423,10 +423,14 @@ class mjCJoint : public mjCJoint_, private mjsJoint {
bool is_limited() const;
bool is_actfrclimited() const;
private:
int Compile(void); // compiler; return dofnum
void PointToLocal(void);
int qposadr_; // address of dof in data->qpos
int dofadr_; // address of dof in data->qvel
mjtNum qpos[7]; // qpos at the previous step
mjtNum qvel[6]; // qvel at the previous step
};
@@ -774,6 +778,7 @@ class mjCMesh_ : public mjCBase {
// size of mesh data to be copied into mjModel
int szgraph_; // size of graph data in ints
bool needhull_; // needs convex hull for collisions
int maxhullvert_; // max vertex count of convex hull
mjCBoundingVolumeHierarchy tree_; // bounding volume hierarchy
std::vector<double> face_aabb_; // bounding boxes of all faces
@@ -1062,7 +1067,7 @@ class mjCTexture : public mjCTexture_, private mjsTexture {
class mjCMaterial_ : public mjCBase {
protected:
int texid; // id of material
int texid; // id of material's texture
std::string texture_;
std::string spec_texture_;
};
@@ -1412,6 +1417,10 @@ class mjCActuator : public mjCActuator_, private mjsActuator {
void NameSpace(const mjCModel* m);
mjCBase* ptarget; // transmission target
int actadr_; // address of dof in data->act
int actnum_; // number of dofs in data->act
std::vector<mjtNum> act; // act at the previous step
};
@@ -1615,7 +1624,7 @@ class mjCKey : public mjCKey_, private mjsKey {
//------------------------- class mjCDef -----------------------------------------------------------
// Describes one set of defaults
class mjCDef : public mjElement {
class mjCDef : public mjsElement {
friend class mjXWriter;
public:
+6 -6
View File
@@ -35,7 +35,7 @@
#include "cc/array_safety.h"
#include "engine/engine_crossplatform.h"
#include "engine/engine_resource.h"
#include "user/user_api.h"
#include <mujoco/mjspec.h>
#include "user/user_util.h"
#include "user/user_vfs.h"
#include "xml/xml_native_reader.h"
@@ -100,7 +100,7 @@ class LocaleOverride {
} // namespace
// Main writer function - calls mjXWrite
std::string mjWriteXML(mjSpec* spec, char* error, int error_sz) {
std::string mjWriteXML(const mjSpec* spec, char* error, int error_sz) {
LocaleOverride locale_override;
// check for empty model
@@ -345,7 +345,7 @@ mjSpec* mjParseXML(const char* filename, const mjVFS* vfs,
}
// create model, set filedir
spec = mjs_createSpec();
spec = mj_makeSpec();
const char* dir;
int ndir = 0;
mju_getResourceDir(resource, &dir, &ndir);
@@ -394,7 +394,7 @@ mjSpec* mjParseXML(const char* filename, const mjVFS* vfs,
// catch known errors
catch (mjXError err) {
mjCopyError(error, err.message, error_sz);
mjs_deleteSpec(spec);
mj_deleteSpec(spec);
return nullptr;
}
@@ -424,9 +424,9 @@ static void RegisterResourceProvider() {
mjSpec* ParseSpecFromString(std::string_view xml, char* error,
int error_size, mjVFS* vfs) {
int error_size) {
RegisterResourceProvider();
std::string xml2 = {xml.begin(), xml.end()};
std::string str = "LoadModelFromString:" + xml2;
return mjParseXML(str.c_str(), vfs, error, error_size);
return mjParseXML(str.c_str(), nullptr, error, error_size);
}
+4 -5
View File
@@ -19,20 +19,19 @@
#include <mujoco/mjexport.h>
#include <mujoco/mjmodel.h>
#include "user/user_api.h"
#include <mujoco/mjspec.h>
// Top level API
// Main writer function
std::string mjWriteXML(mjSpec* spec, char* error, int error_sz);
std::string mjWriteXML(const mjSpec* spec, char* error, int error_sz);
// Main parser function
MJAPI mjSpec* mjParseXML(const char* filename, const mjVFS* vfs, char* error, int error_sz);
mjSpec* mjParseXML(const char* filename, const mjVFS* vfs, char* error, int error_sz);
// Returns a newly-allocated mjSpec, loaded from the contents of xml.
// On failure returns nullptr and populates the error array if present.
MJAPI mjSpec* ParseSpecFromString(std::string_view xml, char* error = nullptr,
int error_size = 0, mjVFS* vfs = nullptr);
mjSpec* ParseSpecFromString(std::string_view xml, char* error = nullptr, int error_size = 0);
#endif // MUJOCO_SRC_XML_XML_H_

Some files were not shown because too many files have changed in this diff Show More