Merge branch 'google-deepmind:main' into tendons
This commit is contained in:
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Vendored
+4
-4
@@ -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"
|
||||
|
||||
Vendored
+4
-4
@@ -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"
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
|
||||
|
||||
+1491
-526
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
|
||||
_______
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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 .
|
||||
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 .
|
||||
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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+3052
-20
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -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
@@ -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": {
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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
@@ -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 (Ornstein–Uhlenbeck)
|
||||
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
@@ -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 (Ornstein–Uhlenbeck)
|
||||
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
@@ -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}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ---------------------------------------------------------
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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_
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user