Merge branch 'original/main' into vidur/remove-installing-glfw3-headers
This commit is contained in:
+22
-10
@@ -28,7 +28,7 @@ set(MSVC_INCREMENTAL_DEFAULT ON)
|
||||
|
||||
project(
|
||||
mujoco
|
||||
VERSION 3.3.3
|
||||
VERSION 3.3.4
|
||||
DESCRIPTION "MuJoCo Physics Simulator"
|
||||
HOMEPAGE_URL "https://mujoco.org"
|
||||
)
|
||||
@@ -42,14 +42,26 @@ option(MUJOCO_BUILD_EXAMPLES "Build samples for MuJoCo" ON)
|
||||
option(MUJOCO_BUILD_SIMULATE "Build simulate library for MuJoCo" ON)
|
||||
option(MUJOCO_BUILD_TESTS "Build tests for MuJoCo" ON)
|
||||
option(MUJOCO_TEST_PYTHON_UTIL "Build and test utility libraries for Python bindings" ON)
|
||||
option(MUJOCO_BUILD_USD_PLUGINS "Build OpenUSD plugins" OFF)
|
||||
option(MUJOCO_WITH_USD "Build with OpenUSD" OFF)
|
||||
|
||||
# USD libs to compile against.
|
||||
set(MUJOCO_USD_ALLOWED_TARGET_VALUES "USD" "Houdini")
|
||||
set(MUJOCO_USD_TARGET "USD" CACHE STRING "Select the USD target for the project.")
|
||||
set_property(CACHE MUJOCO_USD_TARGET
|
||||
PROPERTY STRINGS ${MUJOCO_USD_ALLOWED_TARGET_VALUES}
|
||||
)
|
||||
# Option to provide a path to an existing USD build directory or to Houdini HFS directory.
|
||||
set(USD_DIR "" CACHE PATH "Path to an existing USD build directory.")
|
||||
set(HOUDINI_HFS_DIR "" CACHE PATH "Path to Houdini HFS directory to build USD plugins against.")
|
||||
if(USD_DIR)
|
||||
if(EXISTS "${USD_DIR}")
|
||||
# If the path is provided, set MUJOCO_WITH_USD to ON and add the path to CMAKE_PREFIX_PATH.
|
||||
set(MUJOCO_WITH_USD ON CACHE BOOL "Build with OpenUSD" FORCE)
|
||||
list(PREPEND CMAKE_PREFIX_PATH "${USD_DIR}")
|
||||
message(STATUS "Using custom USD build directory: ${USD_DIR}")
|
||||
else()
|
||||
message(WARNING "Invalid path provided for USD_DIR: ${USD_DIR}")
|
||||
endif()
|
||||
elseif(HOUDINI_HFS_DIR)
|
||||
if(EXISTS "${HOUDINI_HFS_DIR}")
|
||||
set(MUJOCO_WITH_USD ON CACHE BOOL "Build with OpenUSD" FORCE)
|
||||
message(STATUS "Building Mujoco USD against Houdini HFS: ${HOUDINI_HFS_DIR}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(APPLE AND (MUJOCO_BUILD_EXAMPLES OR MUJOCO_BUILD_SIMULATE))
|
||||
enable_language(OBJC)
|
||||
@@ -189,8 +201,8 @@ if(MUJOCO_BUILD_EXAMPLES)
|
||||
add_subdirectory(sample)
|
||||
endif()
|
||||
|
||||
if(MUJOCO_BUILD_USD_PLUGINS)
|
||||
add_subdirectory(src/experimental/usd/plugins)
|
||||
if(MUJOCO_WITH_USD)
|
||||
add_subdirectory(src/experimental/usd)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING AND MUJOCO_BUILD_TESTS)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
# Build configuration for third party libraries used in MuJoCo.
|
||||
|
||||
set(MUJOCO_DEP_VERSION_lodepng
|
||||
b4ed2cd7ecf61d29076169b49199371456d4f90b
|
||||
17d08dd26cac4d63f43af217ebd70318bfb8189c
|
||||
CACHE STRING "Version of `lodepng` to be fetched."
|
||||
)
|
||||
set(MUJOCO_DEP_VERSION_tinyxml2
|
||||
@@ -35,21 +35,21 @@ set(MUJOCO_DEP_VERSION_ccd
|
||||
CACHE STRING "Version of `ccd` to be fetched."
|
||||
)
|
||||
set(MUJOCO_DEP_VERSION_qhull
|
||||
0c8fc90d2037588024d9964515c1e684f6007ecc
|
||||
c7bee59d068a69f427b1273e71cdc5bc455a5bdd
|
||||
CACHE STRING "Version of `qhull` to be fetched."
|
||||
)
|
||||
set(MUJOCO_DEP_VERSION_Eigen3
|
||||
464c1d097891a1462ab28bf8bb763c1683883892
|
||||
d0b490ee091629068e0c11953419eb089f9e6bb2
|
||||
CACHE STRING "Version of `Eigen3` to be fetched."
|
||||
)
|
||||
|
||||
set(MUJOCO_DEP_VERSION_abseil
|
||||
d9e4955c65cd4367dd6bf46f4ccb8cd3d100540b # LTS 20250127.1
|
||||
bc257a88f7c1939f24e0379f14a3589e926c950c # LTS 20250512.0
|
||||
CACHE STRING "Version of `abseil` to be fetched."
|
||||
)
|
||||
|
||||
set(MUJOCO_DEP_VERSION_gtest
|
||||
6910c9d9165801d8827d628cb72eb7ea9dd538c5 # v1.16.0
|
||||
52eb8108c5bdec04579160ae17225d66034bd723 # v1.17.0
|
||||
CACHE STRING "Version of `gtest` to be fetched."
|
||||
)
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ function(target_add_rpath)
|
||||
|
||||
set_target_properties(
|
||||
${_target}
|
||||
PROPERTIES INSTALL_RPATH ${_install_rpath}
|
||||
PROPERTIES INSTALL_RPATH "${_install_rpath}"
|
||||
INSTALL_RPATH_USE_LINK_PATH ${_ARGS_USE_LINK_PATH}
|
||||
BUILD_WITH_INSTALL_RPATH TRUE
|
||||
MACOSX_RPATH ON # This is ON by default.
|
||||
|
||||
Vendored
+4
-4
@@ -1,6 +1,6 @@
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 3,3,3,0
|
||||
PRODUCTVERSION 3,3,3,0
|
||||
FILEVERSION 3,3,4,0
|
||||
PRODUCTVERSION 3,3,4,0
|
||||
FILEOS 0x4
|
||||
FILETYPE 0x1
|
||||
{
|
||||
@@ -9,9 +9,9 @@ FILETYPE 0x1
|
||||
BLOCK "040904b0"
|
||||
{
|
||||
VALUE "ProductName", "MuJoCo"
|
||||
VALUE "ProductVersion", "3.3.3"
|
||||
VALUE "ProductVersion", "3.3.4"
|
||||
VALUE "FileDescription", "MuJoCo"
|
||||
VALUE "FileVersion", "3.3.3"
|
||||
VALUE "FileVersion", "3.3.4"
|
||||
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,3,3,0
|
||||
PRODUCTVERSION 3,3,3,0
|
||||
FILEVERSION 3,3,4,0
|
||||
PRODUCTVERSION 3,3,4,0
|
||||
FILEOS 0x4
|
||||
FILETYPE 0x1
|
||||
{
|
||||
@@ -11,9 +11,9 @@ FILETYPE 0x1
|
||||
BLOCK "040904b0"
|
||||
{
|
||||
VALUE "ProductName", "MuJoCo"
|
||||
VALUE "ProductVersion", "3.3.3"
|
||||
VALUE "ProductVersion", "3.3.4"
|
||||
VALUE "FileDescription", "MuJoCo"
|
||||
VALUE "FileVersion", "3.3.3"
|
||||
VALUE "FileVersion", "3.3.4"
|
||||
VALUE "InternalName", "simulate.exe"
|
||||
VALUE "OriginalFilename", "simulate.exe"
|
||||
VALUE "CompanyName", "Google DeepMind"
|
||||
|
||||
@@ -517,7 +517,7 @@ 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``
|
||||
- 333
|
||||
- 334
|
||||
- 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.
|
||||
|
||||
@@ -418,7 +418,7 @@ and :math:`\dot q` is the generalized velocity ``mjData.qvel``, then :math:`h =
|
||||
|
||||
.. mujoco-include:: mj_name2id
|
||||
|
||||
Get id of object with the specified mjtObj type and name, returns -1 if id not found.
|
||||
Get id of object with the specified :ref:`mjtObj` type and name, returns -1 if id not found.
|
||||
|
||||
.. _mj_id2name:
|
||||
|
||||
@@ -427,7 +427,7 @@ Get id of object with the specified mjtObj type and name, returns -1 if id not f
|
||||
|
||||
.. mujoco-include:: mj_id2name
|
||||
|
||||
Get name of object with the specified mjtObj type and id, returns NULL if name not found.
|
||||
Get name of object with the specified :ref:`mjtObj` type and id, returns ``NULL`` if name not found.
|
||||
|
||||
.. _mj_fullM:
|
||||
|
||||
@@ -3783,24 +3783,6 @@ Attachment
|
||||
|
||||
Attach child to a parent, return the attached element if success or NULL otherwise.
|
||||
|
||||
.. _mjs_detachBody:
|
||||
|
||||
`mjs_detachBody <#mjs_detachBody>`__
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. mujoco-include:: mjs_detachBody
|
||||
|
||||
Delete body and descendants from mjSpec, remove all references, return 0 on success.
|
||||
|
||||
.. _mjs_detachDefault:
|
||||
|
||||
`mjs_detachDefault <#mjs_detachDefault>`__
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. mujoco-include:: mjs_detachDefault
|
||||
|
||||
Delete default class and descendants from mjSpec, remove all references, return 0 on success.
|
||||
|
||||
.. _AddTreeElements:
|
||||
|
||||
Tree elements
|
||||
|
||||
@@ -231,6 +231,14 @@ generalized velocities to subtree angular momentum. More precisely if :math:`h`
|
||||
body index ``body`` in ``mjData.subtree_angmom`` (reported by the :ref:`subtreeangmom<sensor-subtreeangmom>` sensor)
|
||||
and :math:`\dot q` is the generalized velocity ``mjData.qvel``, then :math:`h = H \dot q`.
|
||||
|
||||
.. _mj_name2id:
|
||||
|
||||
Get id of object with the specified :ref:`mjtObj` type and name, returns -1 if id not found.
|
||||
|
||||
.. _mj_id2name:
|
||||
|
||||
Get name of object with the specified :ref:`mjtObj` type and id, returns ``NULL`` if name not found.
|
||||
|
||||
.. _mj_geomDistance:
|
||||
|
||||
Returns the smallest signed distance between two geoms and optionally the segment from ``geom1`` to ``geom2``.
|
||||
|
||||
+31
-12
@@ -724,13 +724,20 @@ has any effect. The settings here are global and apply to the entire model.
|
||||
compiler converts degrees into radians, and mjModel always uses radians. For URDF models the parser sets this
|
||||
attribute to "radian" internally, regardless of the XML setting.
|
||||
|
||||
.. image:: images/changelog/meshfit.png
|
||||
:align: right
|
||||
:width: 40%
|
||||
|
||||
.. _compiler-fitaabb:
|
||||
|
||||
:at:`fitaabb`: :at-val:`[false, true], "false"`
|
||||
The compiler is able to replace a mesh with a geometric primitive fitted to that mesh; see :ref:`geom <body-geom>`
|
||||
below. If this attribute is "true", the fitting procedure uses the axis-aligned bounding box (aabb) of the mesh.
|
||||
Otherwise it uses the equivalent-inertia box of the mesh. The type of geometric primitive used for fitting is
|
||||
specified separately for each geom.
|
||||
specified separately for each geom. The models used to generate the image on the right can be found
|
||||
`here <https://github.com/google-deepmind/mujoco/blob/main/test/user/testdata/fitmesh_inertiabox.xml>`__ (fit inertia
|
||||
box) and `here <https://github.com/google-deepmind/mujoco/blob/main/test/user/testdata/fitmesh_aabb.xml>`__ (fit
|
||||
aabb).
|
||||
|
||||
.. _compiler-eulerseq:
|
||||
|
||||
@@ -792,12 +799,14 @@ has any effect. The settings here are global and apply to the entire model.
|
||||
|
||||
:at:`fusestatic`: :at-val:`[false, true], "false" for MJCF, "true" for URDF`
|
||||
This attribute controls a compiler optimization feature where static bodies are fused with their parent, and any
|
||||
elements defined in those bodies are reassigned to the parent. This feature can only be used in models which do not
|
||||
have elements capable of named references inside the kinematic tree - namely skins, contact pairs, excludes, tendons,
|
||||
actuators, sensors, tuples, cameras, lights. If a model has any these elements, fusestatic does nothing even if
|
||||
enabled. This optimization is particularly useful when importing URDF models which often have many dummy bodies, but
|
||||
can also be used to optimize MJCF models. After optimization, the new model has identical kinematics and dynamics as
|
||||
the original but is faster to simulate.
|
||||
elements defined in those bodies are reassigned to the parent. Static bodies are fused with their parent unless
|
||||
|
||||
- They are referenced by another element in the model.
|
||||
- They contain a site which is referenced by a :ref:`force<sensor-force>` or :ref:`torque<sensor-torque>` sensor.
|
||||
|
||||
This optimization is particularly useful when importing URDF models which often have many dummy bodies, but can also
|
||||
be used to optimize MJCF models. After optimization, the new model has identical kinematics and dynamics as the
|
||||
original but is faster to simulate.
|
||||
|
||||
.. _compiler-inertiafromgeom:
|
||||
|
||||
@@ -1228,7 +1237,7 @@ The full list of processing steps applied by the compiler to each mesh is as fol
|
||||
|
||||
:at:`content_type`: :at-val:`string, optional`
|
||||
If the file attribute is specified, then this sets the
|
||||
`Media Type <https://www.iana.org/assignments/media-types/media-types.xhtml>`_ (formerly known as MIME type) of the
|
||||
`Media Type <https://www.iana.org/assignments/media-types/media-types.xhtml>`__ (formerly known as MIME type) of the
|
||||
file to be loaded. Any filename extensions will be overloaded. Currently ``model/vnd.mujoco.msh``, ``model/obj``,
|
||||
and ``model/stl`` are supported.
|
||||
|
||||
@@ -1776,15 +1785,19 @@ properties are grouped together.
|
||||
|
||||
.. _asset-material-metallic:
|
||||
|
||||
:at:`metallic`: :at-val:`real, "0"`
|
||||
:at:`metallic`: :at-val:`real, "-1"`
|
||||
This attribute corresponds to uniform metallicity coefficient applied to the entire material. This attribute has no
|
||||
effect in MuJoCo's native renderer, but it can be useful when rendering scenes with an external renderer.
|
||||
effect in MuJoCo's native renderer, but it can be useful when rendering scenes with a physically-based renderer. In
|
||||
this case, if a non-negative value is specified, this metallic value should be multiplied by the metallic texture
|
||||
sampled value to obtain the final metallicity of the material.
|
||||
|
||||
.. _asset-material-roughness:
|
||||
|
||||
:at:`roughness`: :at-val:`real, "1"`
|
||||
:at:`roughness`: :at-val:`real, "-1"`
|
||||
This attribute corresponds to uniform roughness coefficient applied to the entire material. This attribute has no
|
||||
effect in MuJoCo's native renderer, but it can be useful when rendering scenes with an external renderer.
|
||||
effect in MuJoCo's native renderer, but it can be useful when rendering scenes with a physically-based renderer. In
|
||||
this case, if a non-negative value is specified, this roughness value should be multiplied by the roughness texture
|
||||
sampled value to obtain the final roughness of the material.
|
||||
|
||||
.. _asset-material-rgba:
|
||||
|
||||
@@ -7528,6 +7541,12 @@ 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-cameraid:
|
||||
|
||||
:at:`cameraid`: :at-val:`int, "-1"`
|
||||
The id of the camera used when initially loading the model in the visualizer. The default value of -1 means the free
|
||||
camera. In order to specify a :ref:`modeled camera<body-camera>`, use the camera's id as given by :ref:`mj_name2id`.
|
||||
|
||||
.. _visual-global-orthographic:
|
||||
|
||||
:at:`orthographic`: :at-val:`[false, true], "false"`
|
||||
|
||||
+5
-3
@@ -1298,11 +1298,13 @@
|
||||
| :ref:`global | ? | :class: mjcf-attributes |
|
||||
| <visual-global>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`orthographic<visual-global-orthographic>` | :ref:`fovy<visual-global-fovy>` | :ref:`ipd<visual-global-ipd>` | :ref:`azimuth<visual-global-azimuth>` | |
|
||||
| | | | :ref:`cameraid<visual-global-cameraid>` | :ref:`orthographic<visual-global-orthographic>` | :ref:`fovy<visual-global-fovy>` | :ref:`ipd<visual-global-ipd>` | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`elevation<visual-global-elevation>` | :ref:`linewidth<visual-global-linewidth>` | :ref:`glow<visual-global-glow>` | :ref:`offwidth<visual-global-offwidth>` | |
|
||||
| | | | :ref:`azimuth<visual-global-azimuth>` | :ref:`elevation<visual-global-elevation>` | :ref:`linewidth<visual-global-linewidth>` | :ref:`glow<visual-global-glow>` | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`offheight<visual-global-offheight>` | :ref:`realtime<visual-global-realtime>` | :ref:`ellipsoidinertia<visual-global-ellipsoidinertia>` | :ref:`bvactive<visual-global-bvactive>` | |
|
||||
| | | | :ref:`offwidth<visual-global-offwidth>` | :ref:`offheight<visual-global-offheight>` | :ref:`realtime<visual-global-realtime>` | :ref:`ellipsoidinertia<visual-global-ellipsoidinertia>` | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`bvactive<visual-global-bvactive>` | | | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_| visual |br| |_| |L| | | .. table:: |
|
||||
|
||||
+45
-18
@@ -2,37 +2,64 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
Upcoming version (not yet release)
|
||||
----------------------------------
|
||||
Upcoming version (not yet released)
|
||||
-----------------------------------
|
||||
|
||||
.. admonition:: Breaking API changes
|
||||
:class: attention
|
||||
|
||||
- The functions ``mjs_detachBody`` and ``mjs_detachDefault`` have been replaced by :ref:`mjs_delete`.
|
||||
- The Python functions ``element.delete`` have been replaced by ``spec.delete(element)``.
|
||||
|
||||
General
|
||||
^^^^^^^
|
||||
- Refactored island implementation so that island data is memory-contiguous. This speeds up island processing in the
|
||||
solver and clears the way for the addition of the Newton and PGS solvers (currently only CG is supported).
|
||||
- Removed the :at:`shell` plugin. This is now supported by :ref:`flexcomp<body-flexcomp>` and is active depending on
|
||||
the :ref:`elastic2d<flexcomp-elasticity-elastic2d>` attribute (off by default).
|
||||
- Replaced the :ref:`directional<body-light-directional>` (boolean) field for lights with a
|
||||
:ref:`type<body-light-type>` field (of type :ref:`mjtLightType<mjtLightType>`) to allow for additional lighting
|
||||
types.
|
||||
- Added new sub-component :ref:`mj_makeM` which combines the :ref:`mj_crb` call with additional logic to support the
|
||||
introduction in 3.3.1 of :ref:`tendon armature<tendon-spatial-armature>`. In addition to the traditional
|
||||
``mjData.qM``, :ref:`mj_makeM` also computes ``mjData.M``, a CSR representation of the same matrix.
|
||||
- Added a new function :ref:`mj_copyBack` to copy real-valued arrays in an mjModel to a compatible mjSpec.
|
||||
- Added support for setting the initial camera in the viewer using
|
||||
:ref:`visual/global/cameraid<visual-global-cameraid>`.
|
||||
- Added support to only sync the state in the Python :ref:`passive viewer<PyViewerPassive>`'s ``Sync`` method, this is
|
||||
useful to improve performance. The default behavior is unchanged and copies the entire model and data.
|
||||
|
||||
Bug fixes
|
||||
^^^^^^^^^
|
||||
- Inverse dynamics were not being computed correctly when :ref:`tendon armature<tendon-spatial-armature>` was present,
|
||||
now fixed.
|
||||
|
||||
Version 3.3.3 (June 10, 2025)
|
||||
-----------------------------
|
||||
|
||||
General
|
||||
^^^^^^^
|
||||
1. Refactored island implementation so that island data is memory-contiguous. This speeds up island processing in the
|
||||
solver and clears the way for the addition of the Newton and PGS solvers (currently only CG is supported).
|
||||
2. Removed the :at:`shell` plugin. This is now supported by :ref:`flexcomp<body-flexcomp>` and is active depending on
|
||||
the :ref:`elastic2d<flexcomp-elasticity-elastic2d>` attribute (off by default).
|
||||
3. Replaced the :ref:`directional<body-light-directional>` (boolean) field for lights with a
|
||||
:ref:`type<body-light-type>` field (of type :ref:`mjtLightType<mjtLightType>`) to allow for additional lighting
|
||||
types.
|
||||
4. Added new sub-component :ref:`mj_makeM` which combines the :ref:`mj_crb` call with additional logic to support the
|
||||
introduction in 3.3.1 of :ref:`tendon armature<tendon-spatial-armature>`. In addition to the traditional
|
||||
``mjData.qM``, :ref:`mj_makeM` also computes ``mjData.M``, a CSR representation of the same matrix.
|
||||
5. Added a new function :ref:`mj_copyBack` to copy real-valued arrays in an mjModel to a compatible mjSpec.
|
||||
6. Removed the limitation of :ref:`fusestatic<compiler-fusestatic>` to models which contain no references. The fusestatic
|
||||
flag will now fuse all bodies which are not referenced and ignore bodies which are referenced.
|
||||
|
||||
Simulate
|
||||
^^^^^^^^
|
||||
- The struct ``mjv_sceneState`` has been removed. This struct was used for partial synchronization of ``mjModel`` and
|
||||
``mjData`` when the Python viewer is used in passive mode. This functionality is now provided by :ref:`mjv_copyModel`
|
||||
and :ref:`mjv_copyData`, which don't copy arrays which are not required for visualization.
|
||||
7. The struct ``mjv_sceneState`` has been removed. This struct was used for partial synchronization of ``mjModel`` and
|
||||
``mjData`` when the Python viewer is used in passive mode. This functionality is now provided by :ref:`mjv_copyModel`
|
||||
and :ref:`mjv_copyData`, which don't copy arrays which are not required for visualization.
|
||||
|
||||
.. image:: images/changelog/procedural_terrain_generation.png
|
||||
:width: 25%
|
||||
:width: 33%
|
||||
:align: right
|
||||
|
||||
Python bindings
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
- Added examples of procedural terrain generation to the Model Editing tutorial: |mjspec_colab|
|
||||
8. Added examples of procedural terrain generation to the Model Editing tutorial: |mjspec_colab|
|
||||
|
||||
MJX
|
||||
^^^
|
||||
9. Added tendon armature.
|
||||
|
||||
Version 3.3.2 (April 28, 2025)
|
||||
------------------------------
|
||||
|
||||
@@ -583,8 +583,7 @@ Fast implicit-in-velocity (``implicitfast``)
|
||||
performance.
|
||||
|
||||
**Euler**:
|
||||
Use ``Euler`` for compatibillity with older models and :ref:`MJX<Mjx>`. Specifically for MJX,
|
||||
setting the :ref:`eulerdamp<option-flag-eulerdamp>` disable flag can :ref:`improve performance<MjxPerformance>`.
|
||||
Use ``Euler`` for compatibillity with older models.
|
||||
**implicitfast**:
|
||||
The ``implicitfast`` integrator has similar computational cost to ``Euler``, yet provides
|
||||
increased stability, and is therefore a strict improvement. It is the recommended integrator for most models.
|
||||
|
||||
@@ -795,8 +795,8 @@ struct mjLROpt_ { // options for mj_setLengthRange()
|
||||
mjtNum tolrange; // convergence tolerance (relative to range)
|
||||
};
|
||||
typedef struct mjLROpt_ mjLROpt;
|
||||
struct mjVFS_ { // virtual file system for loading from memory
|
||||
void* impl_; // internal pointer to VFS memory
|
||||
struct mjVFS_ { // virtual file system for loading from memory
|
||||
void* impl_; // internal pointer to VFS memory
|
||||
};
|
||||
typedef struct mjVFS_ mjVFS;
|
||||
struct mjOption_ { // physics options
|
||||
@@ -844,7 +844,8 @@ struct mjOption_ { // physics options
|
||||
typedef struct mjOption_ mjOption;
|
||||
struct mjVisual_ { // visualization options
|
||||
struct { // global parameters
|
||||
int orthographic; // is the free camera orthographic (0: no, 1: yes)
|
||||
int cameraid; // initial camera id (-1: free)
|
||||
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)
|
||||
@@ -958,6 +959,7 @@ struct mjModel_ {
|
||||
int nbvh; // number of total bounding volumes in all bodies
|
||||
int nbvhstatic; // number of static bounding volumes (aabb stored in mjModel)
|
||||
int nbvhdynamic; // number of dynamic bounding volumes (aabb stored in mjData)
|
||||
int noct; // number of total octree cells in all meshes
|
||||
int njnt; // number of joints
|
||||
int ngeom; // number of geoms
|
||||
int nsite; // number of sites
|
||||
@@ -1091,6 +1093,11 @@ struct mjModel_ {
|
||||
int* bvh_nodeid; // geom or elem id of node; -1: non-leaf (nbvh x 1)
|
||||
mjtNum* bvh_aabb; // local bounding box (center, size) (nbvhstatic x 6)
|
||||
|
||||
// octree spatial partitioning
|
||||
int* oct_depth; // depth in the octree (noct x 1)
|
||||
int* oct_child; // children of octree node (noct x 8)
|
||||
mjtNum* oct_aabb; // octree node bounding box (center, size) (noct x 6)
|
||||
|
||||
// joints
|
||||
int* jnt_type; // type of joint (mjtJoint) (njnt x 1)
|
||||
int* jnt_qposadr; // start addr in 'qpos' for joint's data (njnt x 1)
|
||||
@@ -1278,6 +1285,8 @@ struct mjModel_ {
|
||||
int* mesh_facenum; // number of faces (nmesh x 1)
|
||||
int* mesh_bvhadr; // address of bvh root (nmesh x 1)
|
||||
int* mesh_bvhnum; // number of bvh (nmesh x 1)
|
||||
int* mesh_octadr; // address of octree root (nmesh x 1)
|
||||
int* mesh_octnum; // number of octree nodes (nmesh x 1)
|
||||
int* mesh_normaladr; // first normal address (nmesh x 1)
|
||||
int* mesh_normalnum; // number of normals (nmesh x 1)
|
||||
int* mesh_texcoordadr; // texcoord data address; -1: no texcoord (nmesh x 1)
|
||||
@@ -2875,6 +2884,7 @@ struct mjvOption_ { // abstract visualization options
|
||||
mjtByte skingroup[mjNGROUP]; // skin visualization by group
|
||||
mjtByte flags[mjNVISFLAG]; // visualization flags (indexed by mjtVisFlag)
|
||||
int bvh_depth; // depth of the bounding volume hierarchy to be visualized
|
||||
int oct_depth; // depth of the octree to be visualized
|
||||
int flex_layer; // element layer to be visualized for 3D flex
|
||||
};
|
||||
typedef struct mjvOption_ mjvOption;
|
||||
@@ -3410,8 +3420,6 @@ void mju_defaultTask(mjTask* task);
|
||||
void mju_taskJoin(mjTask* task);
|
||||
mjsElement* mjs_attach(mjsElement* parent, const mjsElement* child,
|
||||
const char* prefix, const char* suffix);
|
||||
int mjs_detachBody(mjSpec* s, mjsBody* b);
|
||||
int mjs_detachDefault(mjSpec* s, mjsDefault* d);
|
||||
mjsBody* mjs_addBody(mjsBody* body, const mjsDefault* def);
|
||||
mjsSite* mjs_addSite(mjsBody* body, const mjsDefault* def);
|
||||
mjsJoint* mjs_addJoint(mjsBody* body, const mjsDefault* def);
|
||||
@@ -3420,7 +3428,7 @@ mjsGeom* mjs_addGeom(mjsBody* body, const mjsDefault* def);
|
||||
mjsCamera* mjs_addCamera(mjsBody* body, const mjsDefault* def);
|
||||
mjsLight* mjs_addLight(mjsBody* body, const mjsDefault* def);
|
||||
mjsFrame* mjs_addFrame(mjsBody* body, mjsFrame* parentframe);
|
||||
int mjs_delete(mjsElement* element);
|
||||
int mjs_delete(mjSpec* spec, mjsElement* element);
|
||||
mjsActuator* mjs_addActuator(mjSpec* s, const mjsDefault* def);
|
||||
mjsSensor* mjs_addSensor(mjSpec* s);
|
||||
mjsFlex* mjs_addFlex(mjSpec* s);
|
||||
@@ -3438,6 +3446,19 @@ mjsTuple* mjs_addTuple(mjSpec* s);
|
||||
mjsKey* mjs_addKey(mjSpec* s);
|
||||
mjsPlugin* mjs_addPlugin(mjSpec* s);
|
||||
mjsDefault* mjs_addDefault(mjSpec* s, const char* classname, const mjsDefault* parent);
|
||||
const char* mjs_setToMotor(mjsActuator* actuator);
|
||||
const char* mjs_setToPosition(mjsActuator* actuator, double kp, double kv[1],
|
||||
double dampratio[1], double timeconst[1], double inheritrange);
|
||||
const char* mjs_setToIntVelocity(mjsActuator* actuator, double kp, double kv[1],
|
||||
double dampratio[1], double timeconst[1], double inheritrange);
|
||||
const char* mjs_setToVelocity(mjsActuator* actuator, double kv);
|
||||
const char* mjs_setToDamper(mjsActuator* actuator, double kv);
|
||||
const char* mjs_setToCylinder(mjsActuator* actuator, double timeconst,
|
||||
double bias, double area, double diameter);
|
||||
const char* mjs_setToMuscle(mjsActuator* actuator, double timeconst[2], double tausmooth,
|
||||
double range[2], double force, double scale, double lmin,
|
||||
double lmax, double vmax, double fpmax, double fvmax);
|
||||
const char* mjs_setToAdhesion(mjsActuator* actuator, double gain);
|
||||
mjsMesh* mjs_addMesh(mjSpec* s, const mjsDefault* def);
|
||||
mjsHField* mjs_addHField(mjSpec* s);
|
||||
mjsSkin* mjs_addSkin(mjSpec* s);
|
||||
|
||||
+3
-5
@@ -206,7 +206,7 @@ The following features are **fully supported** in MJX:
|
||||
* - Category
|
||||
- Feature
|
||||
* - Dynamics
|
||||
- :ref:`Forward <mj_forward>`
|
||||
- :ref:`Forward <mj_forward>`, :ref:`Inverse <mj_inverse>`
|
||||
* - :ref:`Joint <mjtJoint>`
|
||||
- ``FREE``, ``BALL``, ``SLIDE``, ``HINGE``
|
||||
* - :ref:`Transmission <mjtTrn>`
|
||||
@@ -235,8 +235,6 @@ The following features are **fully supported** in MJX:
|
||||
- 1, 3, 4, 6 (1 is not supported with ``ELLIPTIC``)
|
||||
* - :ref:`Solver <mjtSolver>`
|
||||
- ``CG``, ``NEWTON``
|
||||
* - Dynamics
|
||||
- :ref:`Inverse <mj_inverse>`
|
||||
* - Fluid Model
|
||||
- :ref:`flInertia`
|
||||
* - :ref:`Tendons <tendon>`
|
||||
@@ -248,6 +246,8 @@ The following features are **fully supported** in MJX:
|
||||
``FRAMEANGVEL``, ``SUBTREELINVEL``, ``SUBTREEANGMOM``, ``TOUCH``, ``ACCELEROMETER``, ``FORCE``, ``TORQUE``,
|
||||
``ACTUATORFRC``, ``JOINTACTFRC``, ``TENDONACTFRC``, ``FRAMELINACC``, ``FRAMEANGACC``
|
||||
(``ACCELEROMETER``, ``FORCE``, ``TORQUE`` not supported with connect or weld equality constraints)
|
||||
* - Lights
|
||||
- Positions and directions of lights
|
||||
|
||||
The following features are **in development** and coming soon:
|
||||
|
||||
@@ -268,8 +268,6 @@ The following features are **in development** and coming soon:
|
||||
- :ref:`flEllipsoid`
|
||||
* - :ref:`Sensors <mjtSensor>`
|
||||
- All except ``PLUGIN``, ``USER``
|
||||
* - Lights
|
||||
- Positions and directions of lights
|
||||
|
||||
The following features are **unsupported**:
|
||||
|
||||
|
||||
@@ -96,25 +96,37 @@ Elements cannot be created directly; they are returned to the user by the corres
|
||||
my_geom->type = mjGEOM_BOX; // set geom type
|
||||
my_geom->size[0] = my_geom->size[1] = my_geom->size[2] = 0.5; // set box size
|
||||
mjModel* model = mj_compile(spec, NULL); // compile to mjModel
|
||||
...
|
||||
mj_deleteModel(model); // free model
|
||||
mj_deleteSpec(spec); // free spec
|
||||
|
||||
The ``NULL`` second argument to :ref:`mjs_addGeom` is the optional default class pointer. When using defaults
|
||||
procedurally, default classes are passed in explicitly to element constructors. The global defaults of all elements
|
||||
(used when no default class is passed in) can be inspected in
|
||||
`user_init.c <https://github.com/google-deepmind/mujoco/blob/main/src/user/user_init.c>`__.
|
||||
|
||||
.. _meMemory:
|
||||
|
||||
Memory management
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
As seen in the examples above, model elements are never allocated by the user directly, but rather returned by a
|
||||
constructor. The library takes ownership of all elements and frees them when the parent :ref:`mjSpec` is deleted using
|
||||
:ref:`mj_deleteSpec`. The user is only responsible for freeing :ref:`mjSpec` structs.
|
||||
|
||||
.. _meAttachment:
|
||||
|
||||
Attachment
|
||||
^^^^^^^^^^
|
||||
|
||||
This framework introduces a powerful new feature: attaching and detaching model subtrees. This feature is already used
|
||||
to power the :ref:`attach<body-attach>` an :ref:`replicate<replicate>` meta-elements in MJCF. Attachment allows the user
|
||||
to move or copy a subtree from one model into another, while also copying or moving related referenced assets and
|
||||
referencing elements from outside the kinematic tree (e.g., actuators and sensors). Similarly, detaching a subtree will
|
||||
remove all associated elements from the model. The default behavior is to move the child into the parent while
|
||||
attaching, so subsequent changes to the child will also change the parent. Alternatively, the user can choose to make an
|
||||
entirely new copy during attach using :ref:`mjs_setDeepCopy`. This flag is temporarily set to true while parsing XMLs.
|
||||
It is possible to :ref:`attach a body to a frame<mjs_attach>`:
|
||||
This framework introduces a powerful new feature: attaching and deleting model subtrees. This feature is already used to
|
||||
power the :ref:`attach<body-attach>` an :ref:`replicate<replicate>` meta-elements in MJCF. Attachment allows the user to
|
||||
move or copy a subtree from one model into another, while also copying or moving related referenced assets and
|
||||
referencing elements from outside the kinematic tree (e.g., actuators and sensors). Similarly, deleting a subtree will
|
||||
remove all associated elements from the model. The default behavior ("shallow copy") is to move the child into the
|
||||
parent while attaching, so subsequent changes to the child will also change the parent. Alternatively, the user can
|
||||
choose to make an entirely new copy during attach using :ref:`mjs_setDeepCopy`. This flag is temporarily set to true
|
||||
while parsing XMLs. It is possible to :ref:`attach a body to a frame<mjs_attach>`:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
|
||||
+38
-31
@@ -50,25 +50,17 @@ Interactive viewer
|
||||
|
||||
An interactive GUI viewer is provided as part of the Python package in the ``mujoco.viewer`` module. It is based on the
|
||||
same codebase as the :ref:`simulate<saSimulate>` application that ships with the MuJoCo binary releases. Three distinct
|
||||
use cases are supported:
|
||||
|
||||
.. _PyViewerApp:
|
||||
|
||||
Standalone app
|
||||
--------------
|
||||
|
||||
- ``python -m mujoco.viewer`` launches an empty visualization session, where a model can be loaded by drag-and-drop.
|
||||
- ``python -m mujoco.viewer --mjcf=/path/to/some/mjcf.xml`` launches a visualization session for the specified
|
||||
model file.
|
||||
use cases are supported: :ref:`managed viewer<PyViewerManaged>`, :ref:`standalone app<PyViewerApp>`, and :ref:`passive
|
||||
viewer<PyViewerPassive>`.
|
||||
|
||||
.. _PyViewerManaged:
|
||||
|
||||
Managed viewer
|
||||
--------------
|
||||
|
||||
Called from a Python program/script, through the function ``viewer.launch``. This function *blocks user code* to
|
||||
support precise timing of the physics loop. This mode should be used if user code is implemented as
|
||||
:ref:`engine plugins<exPlugin>` or :ref:`physics callbacks<glPhysics>`, and is called by MuJoCo during :ref:`mj_step`.
|
||||
The ``viewer.launch`` function launches the interactive viewer and *blocks user code* which is useful to support precise
|
||||
timing of the physics loop. This mode should be used if user code is implemented as :ref:`engine
|
||||
plugins<exPlugin>` or :ref:`physics callbacks<glPhysics>`, and is called by MuJoCo during :ref:`mj_step`.
|
||||
|
||||
- ``viewer.launch()`` launches an empty visualization session, where a model can be loaded by drag-and-drop.
|
||||
- ``viewer.launch(model)`` launches a visualization session for the given ``mjModel`` where the visualizer
|
||||
@@ -76,21 +68,33 @@ support precise timing of the physics loop. This mode should be used if user cod
|
||||
- ``viewer.launch(model, data)`` is the same as above, except that the visualizer operates directly on the given
|
||||
``mjData`` instance -- upon exit the ``data`` object will have been modified.
|
||||
|
||||
.. _PyViewerApp:
|
||||
|
||||
Standalone app
|
||||
--------------
|
||||
|
||||
The ``mujoco.viewer`` Python package uses the ``if __name__ == '__main__'`` mechanism to allow the :ref:`managed
|
||||
viewer<PyViewerManaged>` to be called directly from the command line as a standalone app:
|
||||
|
||||
- ``python -m mujoco.viewer`` launches an empty visualization session, where a model can be loaded by drag-and-drop.
|
||||
- ``python -m mujoco.viewer --mjcf=/path/to/some/mjcf.xml`` launches a visualization session for the specified
|
||||
model file.
|
||||
|
||||
.. _PyViewerPassive:
|
||||
|
||||
Passive viewer
|
||||
--------------
|
||||
|
||||
By calling ``viewer.launch_passive(model, data)``. This function *does not block*, allowing user code to continue
|
||||
execution. In this mode, the user's script is responsible for timing and advancing the physics state, and mouse-drag
|
||||
perturbations will not work unless the user explicitly synchronizes incoming events.
|
||||
The ``viewer.launch_passive`` function launches the interactive viewer in a way which *does not block*, allowing user
|
||||
code to continue execution. In this mode, the user's script is responsible for timing and advancing the physics state,
|
||||
and mouse-drag perturbations will not work unless the user explicitly synchronizes incoming events.
|
||||
|
||||
.. warning::
|
||||
On MacOS, ``launch_passive`` requires that the user script is executed via a special ``mjpython`` launcher.
|
||||
The ``mjpython`` command is installed as part of the ``mujoco`` package, and can be used as a drop-in replacement
|
||||
for the usual ``python`` command and supports an identical set of command line flags and arguments. For example,
|
||||
a script can be executed via ``mjpython my_script.py``, and an IPython shell can be launched via
|
||||
``mjpython -m IPython``.
|
||||
On MacOS, ``launch_passive`` requires that the user script is executed via a special ``mjpython`` launcher, this is
|
||||
needed to circumvent a platform limitation which requires the main thread to be one that does the rendering. The
|
||||
``mjpython`` command is installed as part of the ``mujoco`` package, and can be used as a drop-in replacement for the
|
||||
usual ``python`` command and supports an identical set of command line flags and arguments. For example, a script can
|
||||
be executed via ``mjpython my_script.py``, and an IPython shell can be launched via ``mjpython -m IPython``.
|
||||
|
||||
The ``launch_passive`` function returns a handle which can be used to interact with the viewer. It has the following
|
||||
attributes:
|
||||
@@ -103,10 +107,14 @@ attributes:
|
||||
state. These include the ``mjModel`` and ``mjData`` instance passed to ``launch_passive``, and also the ``cam``,
|
||||
``opt``, and ``pert`` properties of the viewer handle.
|
||||
|
||||
- ``sync()``: synchronizes state between ``mjModel``, ``mjData``, and GUI user inputs since the previous call to
|
||||
``sync``. In order to allow user scripts to make arbitrary modifications to ``mjModel`` and ``mjData`` without
|
||||
needing to hold the viewer lock, the passive viewer does not access or modify these structs outside of ``sync``
|
||||
calls.
|
||||
- ``sync(state_only=False)``: synchronizes between the user's ``mjModel``, ``mjData`` and the GUI. In order to allow
|
||||
user scripts to make arbitrary modifications to ``mjModel`` and ``mjData`` without needing to hold the viewer lock,
|
||||
the passive viewer does not access or modify these structs outside of ``sync`` calls. If the ``state_only`` argument
|
||||
is ``True``, instead of syncing everything, only the ``mjData`` fields corresponding to
|
||||
:ref:`mjSTATE_INTEGRATION<mjtState>` are synced, followed by a call to :ref:`mj_forward`. The latter option is much
|
||||
faster, but would not pick up arbitrary changes as in the default case. Changes made via the GUI are picked up in
|
||||
either case but changing e.g., ``mjModel.geom_rgba`` via code will be picked up when ``state_only=False`` but not when
|
||||
``state_only=True``.
|
||||
|
||||
User scripts must call ``sync`` in order for the viewer to reflect physics state changes. The ``sync`` function
|
||||
also transfers user inputs from the GUI back into ``mjOption`` (inside ``mjModel``) and ``mjData``, including
|
||||
@@ -603,11 +611,10 @@ Lists of all elements in a spec can be accessed using named properties, using th
|
||||
|
||||
Element removal
|
||||
^^^^^^^^^^^^^^^
|
||||
For elements that can have children (bodies and defaults), the methods ``spec.detach_body(body)`` and
|
||||
``spec.detach_default(def)`` remove, respectively, ``body`` and ``def`` from the spec, together with all of their
|
||||
children. When detaching body subtrees, all elements which reference elements in the subtree, will also be removed. For
|
||||
all other elements, the method ``delete()`` removes the corresponding element from the spec, e.g.
|
||||
``spec.geom('my_geom').delete()`` will remove the geom named "my_geom" and all of the elements that reference it.
|
||||
The method ``delete()`` removes the corresponding element from the spec, e.g. ``spec.delete(spec.geom('my_geom'))`` will
|
||||
remove the geom named "my_geom" and all of the elements that reference it. For elements that can have children (bodies
|
||||
and defaults), ``delete`` also removes all of their children. When deleting body subtrees, all elements which reference
|
||||
elements in the subtree, will also be removed.
|
||||
|
||||
Tree traversal
|
||||
^^^^^^^^^^^^^^
|
||||
@@ -1061,5 +1068,5 @@ non-exhaustive list of specific mujoco-py features:
|
||||
This is the one context in which the MuJoCo library (and therefore also ``mujoco``) is stateful: it holds a copy in
|
||||
memory of the last XML that was compiled, which is used in :ref:`mujoco.mj_saveLastXML(fname) <mj_saveLastXML>`. Note
|
||||
that mujoco-py’s implementation has a convenient extra feature, whereby the pose (as determined by ``sim.data``’s
|
||||
state) is transformed to a keyframe that’s added to the model before saving. This extra feature is not currently
|
||||
state) is transformed to a keyframe that’s added to the model before saving. This extra feature is not currently
|
||||
available in ``mujoco``.
|
||||
|
||||
+2
-2
@@ -37,14 +37,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.3.3.dylib`` (it can be
|
||||
``/Applications/MuJoCo.app/Contents/Frameworks/mujoco.framework/Versions/Current/libmujoco.3.3.4.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.3.3/lib/libmujoco.so.3.3.3`` and rename it as ``libmujoco.so``.
|
||||
``~/.mujoco/mujoco-3.3.4/lib/libmujoco.so.3.3.4`` and rename it as ``libmujoco.so``.
|
||||
|
||||
Windows
|
||||
_______
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2025 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_SRC_EXPERIMENTAL_USD_LAYER_SINK_H_
|
||||
#define MUJOCO_SRC_EXPERIMENTAL_USD_LAYER_SINK_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <mujoco/mujoco.h>
|
||||
#include <pxr/usd/sdf/path.h>
|
||||
#include <pxr/usd/usd/common.h>
|
||||
|
||||
namespace mujoco {
|
||||
namespace usd {
|
||||
|
||||
// A sink for writing pose data to an SDF layer.
|
||||
// Opinions will be authored on the edit target layer for the
|
||||
// passed stage argument.
|
||||
class LayerSink {
|
||||
public:
|
||||
explicit LayerSink(pxr::UsdStageRefPtr stage);
|
||||
void Update(const mjData* const data, std::vector<pxr::SdfPath> body_paths_);
|
||||
|
||||
private:
|
||||
pxr::UsdStageRefPtr stage_;
|
||||
};
|
||||
} // namespace usd
|
||||
} // namespace mujoco
|
||||
|
||||
#endif // MUJOCO_SRC_EXPERIMENTAL_USD_LAYER_SINK_H_
|
||||
+12
-29
@@ -17,18 +17,18 @@
|
||||
|
||||
/// \file mjcPhysics/actuatorAPI.h
|
||||
|
||||
#include "./api.h"
|
||||
#include "./tokens.h"
|
||||
#include "pxr/base/gf/matrix4d.h"
|
||||
#include "pxr/base/gf/vec3d.h"
|
||||
#include "pxr/base/gf/vec3f.h"
|
||||
#include "pxr/base/tf/token.h"
|
||||
#include "pxr/base/tf/type.h"
|
||||
#include "pxr/base/vt/value.h"
|
||||
#include "pxr/pxr.h"
|
||||
#include "pxr/usd/usd/apiSchemaBase.h"
|
||||
#include "pxr/usd/usd/prim.h"
|
||||
#include "pxr/usd/usd/stage.h"
|
||||
#include <mujoco/experimental/usd/mjcPhysics/api.h>
|
||||
#include <mujoco/experimental/usd/mjcPhysics/tokens.h>
|
||||
#include <pxr/base/gf/matrix4d.h>
|
||||
#include <pxr/base/gf/vec3d.h>
|
||||
#include <pxr/base/gf/vec3f.h>
|
||||
#include <pxr/base/tf/token.h>
|
||||
#include <pxr/base/tf/type.h>
|
||||
#include <pxr/base/vt/value.h>
|
||||
#include <pxr/pxr.h>
|
||||
#include <pxr/usd/usd/apiSchemaBase.h>
|
||||
#include <pxr/usd/usd/prim.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
@@ -775,23 +775,6 @@ class MjcPhysicsActuatorAPI : public UsdAPISchemaBase {
|
||||
MJCPHYSICS_API
|
||||
UsdRelationship CreateMjcRefSiteRel() const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCCRANKSITE
|
||||
// --------------------------------------------------------------------- //
|
||||
/// If specified, the actuator acts on a slider-crank mechanism which is
|
||||
/// implicitly determined by the actuator (i.e., it is not a separate model
|
||||
/// element). The target site corresponds to the pin joining the crank and the
|
||||
/// connecting rod.
|
||||
///
|
||||
MJCPHYSICS_API
|
||||
UsdRelationship GetMjcCrankSiteRel() const;
|
||||
|
||||
/// See GetMjcCrankSiteRel(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create
|
||||
MJCPHYSICS_API
|
||||
UsdRelationship CreateMjcCrankSiteRel() const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCSLIDERSITE
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
#ifndef MJCPHYSICS_API_H
|
||||
#define MJCPHYSICS_API_H
|
||||
|
||||
#include "pxr/base/arch/export.h"
|
||||
#include <pxr/base/arch/export.h>
|
||||
|
||||
#if defined(PXR_STATIC)
|
||||
#define MJCPHYSICS_API
|
||||
+12
-12
@@ -17,18 +17,18 @@
|
||||
|
||||
/// \file mjcPhysics/collisionAPI.h
|
||||
|
||||
#include "./api.h"
|
||||
#include "./tokens.h"
|
||||
#include "pxr/base/gf/matrix4d.h"
|
||||
#include "pxr/base/gf/vec3d.h"
|
||||
#include "pxr/base/gf/vec3f.h"
|
||||
#include "pxr/base/tf/token.h"
|
||||
#include "pxr/base/tf/type.h"
|
||||
#include "pxr/base/vt/value.h"
|
||||
#include "pxr/pxr.h"
|
||||
#include "pxr/usd/usd/apiSchemaBase.h"
|
||||
#include "pxr/usd/usd/prim.h"
|
||||
#include "pxr/usd/usd/stage.h"
|
||||
#include <mujoco/experimental/usd/mjcPhysics/api.h>
|
||||
#include <mujoco/experimental/usd/mjcPhysics/tokens.h>
|
||||
#include <pxr/base/gf/matrix4d.h>
|
||||
#include <pxr/base/gf/vec3d.h>
|
||||
#include <pxr/base/gf/vec3f.h>
|
||||
#include <pxr/base/tf/token.h>
|
||||
#include <pxr/base/tf/type.h>
|
||||
#include <pxr/base/vt/value.h>
|
||||
#include <pxr/pxr.h>
|
||||
#include <pxr/usd/usd/apiSchemaBase.h>
|
||||
#include <pxr/usd/usd/prim.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
@@ -0,0 +1,622 @@
|
||||
// Copyright 2025 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 MJCPHYSICS_GENERATED_JOINTAPI_H
|
||||
#define MJCPHYSICS_GENERATED_JOINTAPI_H
|
||||
|
||||
/// \file mjcPhysics/jointAPI.h
|
||||
|
||||
#include <mujoco/experimental/usd/mjcPhysics/api.h>
|
||||
#include <mujoco/experimental/usd/mjcPhysics/tokens.h>
|
||||
#include <pxr/base/gf/matrix4d.h>
|
||||
#include <pxr/base/gf/vec3d.h>
|
||||
#include <pxr/base/gf/vec3f.h>
|
||||
#include <pxr/base/tf/token.h>
|
||||
#include <pxr/base/tf/type.h>
|
||||
#include <pxr/base/vt/value.h>
|
||||
#include <pxr/pxr.h>
|
||||
#include <pxr/usd/usd/apiSchemaBase.h>
|
||||
#include <pxr/usd/usd/prim.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
class SdfAssetPath;
|
||||
|
||||
// -------------------------------------------------------------------------- //
|
||||
// PHYSICSJOINTSAPI //
|
||||
// -------------------------------------------------------------------------- //
|
||||
|
||||
/// \class MjcPhysicsJointAPI
|
||||
///
|
||||
/// API describing a Mujoco joint.
|
||||
///
|
||||
/// For any described attribute \em Fallback \em Value or \em Allowed \em Values
|
||||
/// below that are text/tokens, the actual token is published and defined in
|
||||
/// \ref MjcPhysicsTokens. So to set an attribute to the value "rightHanded",
|
||||
/// use MjcPhysicsTokens->rightHanded as the value.
|
||||
///
|
||||
class MjcPhysicsJointAPI : public UsdAPISchemaBase {
|
||||
public:
|
||||
/// Compile time constant representing what kind of schema this class is.
|
||||
///
|
||||
/// \sa UsdSchemaKind
|
||||
static const UsdSchemaKind schemaKind = UsdSchemaKind::SingleApplyAPI;
|
||||
|
||||
/// Construct a MjcPhysicsJointAPI on UsdPrim \p prim .
|
||||
/// Equivalent to MjcPhysicsJointAPI::Get(prim.GetStage(), prim.GetPath())
|
||||
/// for a \em valid \p prim, but will not immediately throw an error for
|
||||
/// an invalid \p prim
|
||||
explicit MjcPhysicsJointAPI(const UsdPrim &prim = UsdPrim())
|
||||
: UsdAPISchemaBase(prim) {}
|
||||
|
||||
/// Construct a MjcPhysicsJointAPI on the prim held by \p schemaObj .
|
||||
/// Should be preferred over MjcPhysicsJointAPI(schemaObj.GetPrim()),
|
||||
/// as it preserves SchemaBase state.
|
||||
explicit MjcPhysicsJointAPI(const UsdSchemaBase &schemaObj)
|
||||
: UsdAPISchemaBase(schemaObj) {}
|
||||
|
||||
/// Destructor.
|
||||
MJCPHYSICS_API
|
||||
virtual ~MjcPhysicsJointAPI();
|
||||
|
||||
/// Return a vector of names of all pre-declared attributes for this schema
|
||||
/// class and all its ancestor classes. Does not include attributes that
|
||||
/// may be authored by custom/extended methods of the schemas involved.
|
||||
MJCPHYSICS_API
|
||||
static const TfTokenVector &GetSchemaAttributeNames(
|
||||
bool includeInherited = true);
|
||||
|
||||
/// Return a MjcPhysicsJointAPI holding the prim adhering to this
|
||||
/// schema at \p path on \p stage. If no prim exists at \p path on
|
||||
/// \p stage, or if the prim at that path does not adhere to this schema,
|
||||
/// return an invalid schema object. This is shorthand for the following:
|
||||
///
|
||||
/// \code
|
||||
/// MjcPhysicsJointAPI(stage->GetPrimAtPath(path));
|
||||
/// \endcode
|
||||
///
|
||||
MJCPHYSICS_API
|
||||
static MjcPhysicsJointAPI Get(const UsdStagePtr &stage, const SdfPath &path);
|
||||
|
||||
/// Returns true if this <b>single-apply</b> API schema can be applied to
|
||||
/// the given \p prim. If this schema can not be a applied to the prim,
|
||||
/// this returns false and, if provided, populates \p whyNot with the
|
||||
/// reason it can not be applied.
|
||||
///
|
||||
/// Note that if CanApply returns false, that does not necessarily imply
|
||||
/// that calling Apply will fail. Callers are expected to call CanApply
|
||||
/// before calling Apply if they want to ensure that it is valid to
|
||||
/// apply a schema.
|
||||
///
|
||||
/// \sa UsdPrim::GetAppliedSchemas()
|
||||
/// \sa UsdPrim::HasAPI()
|
||||
/// \sa UsdPrim::CanApplyAPI()
|
||||
/// \sa UsdPrim::ApplyAPI()
|
||||
/// \sa UsdPrim::RemoveAPI()
|
||||
///
|
||||
MJCPHYSICS_API
|
||||
static bool CanApply(const UsdPrim &prim, std::string *whyNot = nullptr);
|
||||
|
||||
/// Applies this <b>single-apply</b> API schema to the given \p prim.
|
||||
/// This information is stored by adding "PhysicsJointsAPI" to the
|
||||
/// token-valued, listOp metadata \em apiSchemas on the prim.
|
||||
///
|
||||
/// \return A valid MjcPhysicsJointAPI object is returned upon success.
|
||||
/// An invalid (or empty) MjcPhysicsJointAPI object is returned upon
|
||||
/// failure. See \ref UsdPrim::ApplyAPI() for conditions
|
||||
/// resulting in failure.
|
||||
///
|
||||
/// \sa UsdPrim::GetAppliedSchemas()
|
||||
/// \sa UsdPrim::HasAPI()
|
||||
/// \sa UsdPrim::CanApplyAPI()
|
||||
/// \sa UsdPrim::ApplyAPI()
|
||||
/// \sa UsdPrim::RemoveAPI()
|
||||
///
|
||||
MJCPHYSICS_API
|
||||
static MjcPhysicsJointAPI Apply(const UsdPrim &prim);
|
||||
|
||||
protected:
|
||||
/// Returns the kind of schema this class belongs to.
|
||||
///
|
||||
/// \sa UsdSchemaKind
|
||||
MJCPHYSICS_API
|
||||
UsdSchemaKind _GetSchemaKind() const override;
|
||||
|
||||
private:
|
||||
// needs to invoke _GetStaticTfType.
|
||||
friend class UsdSchemaRegistry;
|
||||
MJCPHYSICS_API
|
||||
static const TfType &_GetStaticTfType();
|
||||
|
||||
static bool _IsTypedSchema();
|
||||
|
||||
// override SchemaBase virtuals.
|
||||
MJCPHYSICS_API
|
||||
const TfType &_GetTfType() const override;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCSPRINGDAMPER
|
||||
// --------------------------------------------------------------------- //
|
||||
/// When both numbers are positive, the compiler will override any stiffness
|
||||
/// and damping values specified with the attributes below, and will instead
|
||||
/// set them automatically so that the resulting mass-spring-damper for this
|
||||
/// joint has the desired time constant (first value) and damping ratio
|
||||
/// (second value). This is done by taking into account the joint inertia in
|
||||
/// the model reference configuration. Note that the format is the same as the
|
||||
/// solref parameter of the constraint solver.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double[] mjc:springdamper = [0, 0]` |
|
||||
/// | C++ Type | VtArray<double> |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->DoubleArray |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcSpringdamperAttr() const;
|
||||
|
||||
/// See GetMjcSpringdamperAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcSpringdamperAttr(
|
||||
VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCSOLREFLIMIT
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Constraint solver parameters for simulating joint limits.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double[] mjc:solreflimit = [0.02, 1]` |
|
||||
/// | C++ Type | VtArray<double> |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->DoubleArray |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcSolreflimitAttr() const;
|
||||
|
||||
/// See GetMjcSolreflimitAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcSolreflimitAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCSOLIMPLIMIT
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Constraint solver parameters for simulating joint limits.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double[] mjc:solimplimit = [0.9, 0.95, 0.001,
|
||||
/// 0.5, 2]` | | C++ Type | VtArray<double> | | \ref Usd_Datatypes "Usd Type"
|
||||
/// | SdfValueTypeNames->DoubleArray | | \ref SdfVariability "Variability" |
|
||||
/// SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcSolimplimitAttr() const;
|
||||
|
||||
/// See GetMjcSolimplimitAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcSolimplimitAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCSOLREFFRICTION
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Constraint solver parameters for simulating dry friction.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double[] mjc:solreffriction = [0.02, 1]` |
|
||||
/// | C++ Type | VtArray<double> |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->DoubleArray |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcSolreffrictionAttr() const;
|
||||
|
||||
/// See GetMjcSolreffrictionAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcSolreffrictionAttr(
|
||||
VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCSOLIMPFRICTION
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Constraint solver parameters for simulating dry friction.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double[] mjc:solimpfriction = [0.9, 0.95, 0.001,
|
||||
/// 0.5, 2]` | | C++ Type | VtArray<double> | | \ref Usd_Datatypes "Usd Type"
|
||||
/// | SdfValueTypeNames->DoubleArray | | \ref SdfVariability "Variability" |
|
||||
/// SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcSolimpfrictionAttr() const;
|
||||
|
||||
/// See GetMjcSolimpfrictionAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcSolimpfrictionAttr(
|
||||
VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCSTIFFNESS
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Joint stiffness. If this value is positive, a spring will be created with
|
||||
/// equilibrium position given by springref below. The spring force is
|
||||
/// computed along with the other passive forces.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double mjc:stiffness = 0` |
|
||||
/// | C++ Type | double |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Double |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcStiffnessAttr() const;
|
||||
|
||||
/// See GetMjcStiffnessAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcStiffnessAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCACTUATORFRCRANGEMIN
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Minimum range for clamping total actuator forces acting on this joint. See
|
||||
/// Force limits for details. It is available only for scalar joints (hinge
|
||||
/// and slider) and ignored for ball and free joints. The compiler expects the
|
||||
/// first value to be smaller than the second value. Setting this attribute
|
||||
/// without specifying actuatorfrclimited is an error if compiler-autolimits
|
||||
/// is 'false'.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double mjc:actuatorfrcrange:min = 0` |
|
||||
/// | C++ Type | double |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Double |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcActuatorfrcrangeMinAttr() const;
|
||||
|
||||
/// See GetMjcActuatorfrcrangeMinAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcActuatorfrcrangeMinAttr(
|
||||
VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCACTUATORFRCRANGEMAX
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Maximum range for clamping total actuator forces acting on this joint. See
|
||||
/// Force limits for details. It is available only for scalar joints (hinge
|
||||
/// and slider) and ignored for ball and free joints. The compiler expects the
|
||||
/// first value to be smaller than the second value. Setting this attribute
|
||||
/// without specifying actuatorfrclimited is an error if compiler-autolimits
|
||||
/// is 'false'.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double mjc:actuatorfrcrange:max = 0` |
|
||||
/// | C++ Type | double |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Double |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcActuatorfrcrangeMaxAttr() const;
|
||||
|
||||
/// See GetMjcActuatorfrcrangeMaxAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcActuatorfrcrangeMaxAttr(
|
||||
VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCACTUATORFRCLIMITED
|
||||
// --------------------------------------------------------------------- //
|
||||
/// This attribute specifies whether actuator forces acting on the joint
|
||||
/// should be clamped. See Force limits for details. It is available only for
|
||||
/// scalar joints (hinge and slider) and ignored for ball and free joints.
|
||||
/// This attribute interacts with the actuatorfrcrange attribute. If this
|
||||
/// attribute is 'false', actuator force clamping is disabled. If it is
|
||||
/// 'true', actuator force clamping is enabled. If this attribute is 'auto',
|
||||
/// and autolimits is set in compiler, actuator force clamping will be enabled
|
||||
/// if actuatorfrcrange is defined.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform token mjc:actuatorfrclimited = "auto"` |
|
||||
/// | C++ Type | TfToken |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Token |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
/// | \ref MjcPhysicsTokens "Allowed Values" | false, true, auto |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcActuatorfrclimitedAttr() const;
|
||||
|
||||
/// See GetMjcActuatorfrclimitedAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcActuatorfrclimitedAttr(
|
||||
VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCACTUATORGRAVCOMP
|
||||
// --------------------------------------------------------------------- //
|
||||
/// If this flag is enabled, gravity compensation applied to this joint is
|
||||
/// added to actuator forces (mjData.qfrc_actuator) rather than passive forces
|
||||
/// (mjData.qfrc_passive). Notionally, this means that gravity compensation is
|
||||
/// the result of a control system rather than natural buoyancy. In practice,
|
||||
/// enabling this flag is useful when joint-level actuator force clamping is
|
||||
/// used. In this case, the total actuation force applied on a joint,
|
||||
/// including gravity compensation, is guaranteed to not exceed the specified
|
||||
/// limits. See Force limits and actuatorfrcrange for more details on this
|
||||
/// type of force limit.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform bool mjc:actuatorgravcomp = 0` |
|
||||
/// | C++ Type | bool |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Bool |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcActuatorgravcompAttr() const;
|
||||
|
||||
/// See GetMjcActuatorgravcompAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcActuatorgravcompAttr(
|
||||
VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCMARGIN
|
||||
// --------------------------------------------------------------------- //
|
||||
/// The distance threshold below which limits become active. Recall that the
|
||||
/// Constraint solver normally generates forces as soon as a constraint
|
||||
/// becomes active, even if the margin parameter makes that happen at a
|
||||
/// distance. This attribute together with solreflimit and solimplimit can be
|
||||
/// used to model a soft joint limit.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double mjc:margin = 0` |
|
||||
/// | C++ Type | double |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Double |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcMarginAttr() const;
|
||||
|
||||
/// See GetMjcMarginAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcMarginAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCREF
|
||||
// --------------------------------------------------------------------- //
|
||||
/// The reference position or angle of the joint. This attribute is only used
|
||||
/// for slide and hinge joints. It defines the joint value corresponding to
|
||||
/// the initial model configuration. The amount of spatial transformation that
|
||||
/// the joint applies at runtime equals the current joint value stored in
|
||||
/// mjData.qpos minus this reference value stored in mjModel.qpos0. The
|
||||
/// meaning of these vectors was discussed in the Stand-alone section in the
|
||||
/// Overview chapter.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double mjc:ref = 0` |
|
||||
/// | C++ Type | double |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Double |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcRefAttr() const;
|
||||
|
||||
/// See GetMjcRefAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcRefAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCSPRINGREF
|
||||
// --------------------------------------------------------------------- //
|
||||
/// The joint position or angle in which the joint spring (if any) achieves
|
||||
/// equilibrium. Similar to the vector mjModel.qpos0 which stores all joint
|
||||
/// reference values specified with the ref attribute above, all spring
|
||||
/// reference values specified with this attribute are stored in the vector
|
||||
/// mjModel.qpos_spring. The model configuration corresponding to
|
||||
/// mjModel.qpos_spring is also used to compute the spring reference lengths
|
||||
/// of all tendons, stored in mjModel.tendon_lengthspring. This is because
|
||||
/// tendons can also have springs.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double mjc:springref = 0` |
|
||||
/// | C++ Type | double |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Double |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcSpringrefAttr() const;
|
||||
|
||||
/// See GetMjcSpringrefAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcSpringrefAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCARMATURE
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Additional inertia associated with movement of the joint that is not due
|
||||
/// to body mass. This added inertia is usually due to a rotor (a.k.a
|
||||
/// armature) spinning faster than the joint itself due to a geared
|
||||
/// transmission. The value applies to all degrees of freedom created by this
|
||||
/// joint. Besides increasing the realism of joints with geared transmission,
|
||||
/// positive armature significantly improves simulation stability, even for
|
||||
/// small values, and is a recommended possible fix when encountering
|
||||
/// stability issues.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double mjc:armature = 0` |
|
||||
/// | C++ Type | double |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Double |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcArmatureAttr() const;
|
||||
|
||||
/// See GetMjcArmatureAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcArmatureAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCDAMPING
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Damping applied to all degrees of freedom created by this joint. Unlike
|
||||
/// friction loss which is computed by the constraint solver, damping is
|
||||
/// simply a force linear in velocity. It is included in the passive forces.
|
||||
/// Despite this simplicity, larger damping values can make numerical
|
||||
/// integrators unstable, which is why our Euler integrator handles damping
|
||||
/// implicitly. See Integration in the Computation chapter.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double mjc:damping = 0` |
|
||||
/// | C++ Type | double |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Double |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcDampingAttr() const;
|
||||
|
||||
/// See GetMjcDampingAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcDampingAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCFRICTIONLOSS
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Friction loss due to dry friction. This value is the same for all degrees
|
||||
/// of freedom created by this joint. Semantically friction loss does not make
|
||||
/// sense for free joints, but the compiler allows it. To enable friction
|
||||
/// loss, set this attribute to a positive value.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `uniform double mjc:frictionloss = 0` |
|
||||
/// | C++ Type | double |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Double |
|
||||
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcFrictionlossAttr() const;
|
||||
|
||||
/// See GetMjcFrictionlossAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcFrictionlossAttr(
|
||||
VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// ===================================================================== //
|
||||
// Feel free to add custom code below this line, it will be preserved by
|
||||
// the code generator.
|
||||
//
|
||||
// Just remember to:
|
||||
// - Close the class declaration with };
|
||||
// - Close the namespace with PXR_NAMESPACE_CLOSE_SCOPE
|
||||
// - Close the include guard with #endif
|
||||
// ===================================================================== //
|
||||
// --(BEGIN CUSTOM CODE)--
|
||||
};
|
||||
|
||||
PXR_NAMESPACE_CLOSE_SCOPE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,292 @@
|
||||
// Copyright 2025 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 MJCPHYSICS_GENERATED_KEYFRAME_H
|
||||
#define MJCPHYSICS_GENERATED_KEYFRAME_H
|
||||
|
||||
/// \file mjcPhysics/keyframe.h
|
||||
|
||||
#include <mujoco/experimental/usd/mjcPhysics/api.h>
|
||||
#include <mujoco/experimental/usd/mjcPhysics/tokens.h>
|
||||
#include <pxr/base/gf/matrix4d.h>
|
||||
#include <pxr/base/gf/vec3d.h>
|
||||
#include <pxr/base/gf/vec3f.h>
|
||||
#include <pxr/base/tf/token.h>
|
||||
#include <pxr/base/tf/type.h>
|
||||
#include <pxr/base/vt/value.h>
|
||||
#include <pxr/pxr.h>
|
||||
#include <pxr/usd/usd/prim.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
#include <pxr/usd/usd/typed.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
class SdfAssetPath;
|
||||
|
||||
// -------------------------------------------------------------------------- //
|
||||
// KEYFRAME //
|
||||
// -------------------------------------------------------------------------- //
|
||||
|
||||
/// \class MjcPhysicsKeyframe
|
||||
///
|
||||
/// Represents time independent keyframe values.
|
||||
///
|
||||
class MjcPhysicsKeyframe : public UsdTyped {
|
||||
public:
|
||||
/// Compile time constant representing what kind of schema this class is.
|
||||
///
|
||||
/// \sa UsdSchemaKind
|
||||
static const UsdSchemaKind schemaKind = UsdSchemaKind::ConcreteTyped;
|
||||
|
||||
/// Construct a MjcPhysicsKeyframe on UsdPrim \p prim .
|
||||
/// Equivalent to MjcPhysicsKeyframe::Get(prim.GetStage(), prim.GetPath())
|
||||
/// for a \em valid \p prim, but will not immediately throw an error for
|
||||
/// an invalid \p prim
|
||||
explicit MjcPhysicsKeyframe(const UsdPrim &prim = UsdPrim())
|
||||
: UsdTyped(prim) {}
|
||||
|
||||
/// Construct a MjcPhysicsKeyframe on the prim held by \p schemaObj .
|
||||
/// Should be preferred over MjcPhysicsKeyframe(schemaObj.GetPrim()),
|
||||
/// as it preserves SchemaBase state.
|
||||
explicit MjcPhysicsKeyframe(const UsdSchemaBase &schemaObj)
|
||||
: UsdTyped(schemaObj) {}
|
||||
|
||||
/// Destructor.
|
||||
MJCPHYSICS_API
|
||||
virtual ~MjcPhysicsKeyframe();
|
||||
|
||||
/// Return a vector of names of all pre-declared attributes for this schema
|
||||
/// class and all its ancestor classes. Does not include attributes that
|
||||
/// may be authored by custom/extended methods of the schemas involved.
|
||||
MJCPHYSICS_API
|
||||
static const TfTokenVector &GetSchemaAttributeNames(
|
||||
bool includeInherited = true);
|
||||
|
||||
/// Return a MjcPhysicsKeyframe holding the prim adhering to this
|
||||
/// schema at \p path on \p stage. If no prim exists at \p path on
|
||||
/// \p stage, or if the prim at that path does not adhere to this schema,
|
||||
/// return an invalid schema object. This is shorthand for the following:
|
||||
///
|
||||
/// \code
|
||||
/// MjcPhysicsKeyframe(stage->GetPrimAtPath(path));
|
||||
/// \endcode
|
||||
///
|
||||
MJCPHYSICS_API
|
||||
static MjcPhysicsKeyframe Get(const UsdStagePtr &stage, const SdfPath &path);
|
||||
|
||||
/// Attempt to ensure a \a UsdPrim adhering to this schema at \p path
|
||||
/// is defined (according to UsdPrim::IsDefined()) on this stage.
|
||||
///
|
||||
/// If a prim adhering to this schema at \p path is already defined on this
|
||||
/// stage, return that prim. Otherwise author an \a SdfPrimSpec with
|
||||
/// \a specifier == \a SdfSpecifierDef and this schema's prim type name for
|
||||
/// the prim at \p path at the current EditTarget. Author \a SdfPrimSpec s
|
||||
/// with \p specifier == \a SdfSpecifierDef and empty typeName at the
|
||||
/// current EditTarget for any nonexistent, or existing but not \a Defined
|
||||
/// ancestors.
|
||||
///
|
||||
/// The given \a path must be an absolute prim path that does not contain
|
||||
/// any variant selections.
|
||||
///
|
||||
/// If it is impossible to author any of the necessary PrimSpecs, (for
|
||||
/// example, in case \a path cannot map to the current UsdEditTarget's
|
||||
/// namespace) issue an error and return an invalid \a UsdPrim.
|
||||
///
|
||||
/// Note that this method may return a defined prim whose typeName does not
|
||||
/// specify this schema class, in case a stronger typeName opinion overrides
|
||||
/// the opinion at the current EditTarget.
|
||||
///
|
||||
MJCPHYSICS_API
|
||||
static MjcPhysicsKeyframe Define(const UsdStagePtr &stage,
|
||||
const SdfPath &path);
|
||||
|
||||
protected:
|
||||
/// Returns the kind of schema this class belongs to.
|
||||
///
|
||||
/// \sa UsdSchemaKind
|
||||
MJCPHYSICS_API
|
||||
UsdSchemaKind _GetSchemaKind() const override;
|
||||
|
||||
private:
|
||||
// needs to invoke _GetStaticTfType.
|
||||
friend class UsdSchemaRegistry;
|
||||
MJCPHYSICS_API
|
||||
static const TfType &_GetStaticTfType();
|
||||
|
||||
static bool _IsTypedSchema();
|
||||
|
||||
// override SchemaBase virtuals.
|
||||
MJCPHYSICS_API
|
||||
const TfType &_GetTfType() const override;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCQPOS
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Vector of joint positions, copied into mjData.qpos when the simulation
|
||||
/// state is set to this keyframe.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `double[] mjc:qpos` |
|
||||
/// | C++ Type | VtArray<double> |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->DoubleArray |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcQposAttr() const;
|
||||
|
||||
/// See GetMjcQposAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcQposAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCQVEL
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Vector of joint velocities, copied into mjData.qvel when the simulation
|
||||
/// state is set to this keyframe.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `double[] mjc:qvel` |
|
||||
/// | C++ Type | VtArray<double> |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->DoubleArray |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcQvelAttr() const;
|
||||
|
||||
/// See GetMjcQvelAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcQvelAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCACT
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Vector of actuator activations, copied into mjData.act when the simulation
|
||||
/// state is set to this keyframe.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `double[] mjc:act` |
|
||||
/// | C++ Type | VtArray<double> |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->DoubleArray |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcActAttr() const;
|
||||
|
||||
/// See GetMjcActAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcActAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCCTRL
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Vector of controls, copied into mjData.ctrl when the simulation state is
|
||||
/// set to this keyframe.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `double[] mjc:ctrl` |
|
||||
/// | C++ Type | VtArray<double> |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->DoubleArray |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcCtrlAttr() const;
|
||||
|
||||
/// See GetMjcCtrlAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcCtrlAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCMPOS
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Vector of mocap body positions, copied into mjData.mocap_pos when the
|
||||
/// simulation state is set to this keyframe.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `double[] mjc:mpos` |
|
||||
/// | C++ Type | VtArray<double> |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->DoubleArray |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcMposAttr() const;
|
||||
|
||||
/// See GetMjcMposAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcMposAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------- //
|
||||
// MJCMQUAT
|
||||
// --------------------------------------------------------------------- //
|
||||
/// Vector of mocap body quaternions, copied into mjData.mocap_quat when the
|
||||
/// simulation state is set to this keyframe.
|
||||
///
|
||||
/// | ||
|
||||
/// | -- | -- |
|
||||
/// | Declaration | `double[] mjc:mquat` |
|
||||
/// | C++ Type | VtArray<double> |
|
||||
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->DoubleArray |
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute GetMjcMquatAttr() const;
|
||||
|
||||
/// See GetMjcMquatAttr(), and also
|
||||
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
|
||||
/// If specified, author \p defaultValue as the attribute's default,
|
||||
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
|
||||
/// the default for \p writeSparsely is \c false.
|
||||
MJCPHYSICS_API
|
||||
UsdAttribute CreateMjcMquatAttr(VtValue const &defaultValue = VtValue(),
|
||||
bool writeSparsely = false) const;
|
||||
|
||||
public:
|
||||
// ===================================================================== //
|
||||
// Feel free to add custom code below this line, it will be preserved by
|
||||
// the code generator.
|
||||
//
|
||||
// Just remember to:
|
||||
// - Close the class declaration with };
|
||||
// - Close the namespace with PXR_NAMESPACE_CLOSE_SCOPE
|
||||
// - Close the include guard with #endif
|
||||
// ===================================================================== //
|
||||
// --(BEGIN CUSTOM CODE)--
|
||||
};
|
||||
|
||||
PXR_NAMESPACE_CLOSE_SCOPE
|
||||
|
||||
#endif
|
||||
+12
-12
@@ -17,18 +17,18 @@
|
||||
|
||||
/// \file mjcPhysics/meshCollisionAPI.h
|
||||
|
||||
#include "./api.h"
|
||||
#include "./tokens.h"
|
||||
#include "pxr/base/gf/matrix4d.h"
|
||||
#include "pxr/base/gf/vec3d.h"
|
||||
#include "pxr/base/gf/vec3f.h"
|
||||
#include "pxr/base/tf/token.h"
|
||||
#include "pxr/base/tf/type.h"
|
||||
#include "pxr/base/vt/value.h"
|
||||
#include "pxr/pxr.h"
|
||||
#include "pxr/usd/usd/apiSchemaBase.h"
|
||||
#include "pxr/usd/usd/prim.h"
|
||||
#include "pxr/usd/usd/stage.h"
|
||||
#include <mujoco/experimental/usd/mjcPhysics/api.h>
|
||||
#include <mujoco/experimental/usd/mjcPhysics/tokens.h>
|
||||
#include <pxr/base/gf/matrix4d.h>
|
||||
#include <pxr/base/gf/vec3d.h>
|
||||
#include <pxr/base/gf/vec3f.h>
|
||||
#include <pxr/base/tf/token.h>
|
||||
#include <pxr/base/tf/type.h>
|
||||
#include <pxr/base/vt/value.h>
|
||||
#include <pxr/pxr.h>
|
||||
#include <pxr/usd/usd/apiSchemaBase.h>
|
||||
#include <pxr/usd/usd/prim.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
+12
-12
@@ -17,18 +17,18 @@
|
||||
|
||||
/// \file mjcPhysics/sceneAPI.h
|
||||
|
||||
#include "./api.h"
|
||||
#include "./tokens.h"
|
||||
#include "pxr/base/gf/matrix4d.h"
|
||||
#include "pxr/base/gf/vec3d.h"
|
||||
#include "pxr/base/gf/vec3f.h"
|
||||
#include "pxr/base/tf/token.h"
|
||||
#include "pxr/base/tf/type.h"
|
||||
#include "pxr/base/vt/value.h"
|
||||
#include "pxr/pxr.h"
|
||||
#include "pxr/usd/usd/apiSchemaBase.h"
|
||||
#include "pxr/usd/usd/prim.h"
|
||||
#include "pxr/usd/usd/stage.h"
|
||||
#include <mujoco/experimental/usd/mjcPhysics/api.h>
|
||||
#include <mujoco/experimental/usd/mjcPhysics/tokens.h>
|
||||
#include <pxr/base/gf/matrix4d.h>
|
||||
#include <pxr/base/gf/vec3d.h>
|
||||
#include <pxr/base/gf/vec3f.h>
|
||||
#include <pxr/base/tf/token.h>
|
||||
#include <pxr/base/tf/type.h>
|
||||
#include <pxr/base/vt/value.h>
|
||||
#include <pxr/pxr.h>
|
||||
#include <pxr/usd/usd/apiSchemaBase.h>
|
||||
#include <pxr/usd/usd/prim.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
+11
-11
@@ -17,17 +17,17 @@
|
||||
|
||||
/// \file mjcPhysics/siteAPI.h
|
||||
|
||||
#include "./api.h"
|
||||
#include "pxr/base/gf/matrix4d.h"
|
||||
#include "pxr/base/gf/vec3d.h"
|
||||
#include "pxr/base/gf/vec3f.h"
|
||||
#include "pxr/base/tf/token.h"
|
||||
#include "pxr/base/tf/type.h"
|
||||
#include "pxr/base/vt/value.h"
|
||||
#include "pxr/pxr.h"
|
||||
#include "pxr/usd/usd/apiSchemaBase.h"
|
||||
#include "pxr/usd/usd/prim.h"
|
||||
#include "pxr/usd/usd/stage.h"
|
||||
#include <mujoco/experimental/usd/mjcPhysics/api.h>
|
||||
#include <pxr/base/gf/matrix4d.h>
|
||||
#include <pxr/base/gf/vec3d.h>
|
||||
#include <pxr/base/gf/vec3f.h>
|
||||
#include <pxr/base/tf/token.h>
|
||||
#include <pxr/base/tf/type.h>
|
||||
#include <pxr/base/vt/value.h>
|
||||
#include <pxr/pxr.h>
|
||||
#include <pxr/usd/usd/apiSchemaBase.h>
|
||||
#include <pxr/usd/usd/prim.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
+110
-15
@@ -26,10 +26,10 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "./api.h"
|
||||
#include "pxr/base/tf/staticData.h"
|
||||
#include "pxr/base/tf/token.h"
|
||||
#include "pxr/pxr.h"
|
||||
#include <mujoco/experimental/usd/mjcPhysics/api.h>
|
||||
#include <pxr/base/tf/staticData.h>
|
||||
#include <pxr/base/tf/token.h>
|
||||
#include <pxr/pxr.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
@@ -63,7 +63,8 @@ struct MjcPhysicsTokensType {
|
||||
/// Fallback value for MjcPhysicsSceneAPI::GetJacobianAttr(), Fallback value
|
||||
/// for MjcPhysicsActuatorAPI::GetMjcActLimitedAttr(), Fallback value for
|
||||
/// MjcPhysicsActuatorAPI::GetMjcCtrlLimitedAttr(), Fallback value for
|
||||
/// MjcPhysicsActuatorAPI::GetMjcForceLimitedAttr(), This token represents
|
||||
/// MjcPhysicsActuatorAPI::GetMjcForceLimitedAttr(), Fallback value for
|
||||
/// MjcPhysicsJointAPI::GetMjcActuatorfrclimitedAttr(), This token represents
|
||||
/// the auto constraint Jacobian and matrices computed from it.
|
||||
const TfToken auto_;
|
||||
/// \brief "cg"
|
||||
@@ -98,7 +99,8 @@ struct MjcPhysicsTokensType {
|
||||
///
|
||||
/// Possible value for MjcPhysicsActuatorAPI::GetMjcActLimitedAttr(), Possible
|
||||
/// value for MjcPhysicsActuatorAPI::GetMjcCtrlLimitedAttr(), Possible value
|
||||
/// for MjcPhysicsActuatorAPI::GetMjcForceLimitedAttr()
|
||||
/// for MjcPhysicsActuatorAPI::GetMjcForceLimitedAttr(), Possible value for
|
||||
/// MjcPhysicsJointAPI::GetMjcActuatorfrclimitedAttr()
|
||||
const TfToken false_;
|
||||
/// \brief "filter"
|
||||
///
|
||||
@@ -130,6 +132,10 @@ struct MjcPhysicsTokensType {
|
||||
///
|
||||
/// Fallback value for MjcPhysicsMeshCollisionAPI::GetInertiaAttr()
|
||||
const TfToken legacy;
|
||||
/// \brief "mjc:act"
|
||||
///
|
||||
/// MjcPhysicsKeyframe
|
||||
const TfToken mjcAct;
|
||||
/// \brief "mjc:actDim"
|
||||
///
|
||||
/// MjcPhysicsActuatorAPI
|
||||
@@ -150,6 +156,26 @@ struct MjcPhysicsTokensType {
|
||||
///
|
||||
/// MjcPhysicsActuatorAPI
|
||||
const TfToken mjcActRangeMin;
|
||||
/// \brief "mjc:actuatorfrclimited"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcActuatorfrclimited;
|
||||
/// \brief "mjc:actuatorfrcrange:max"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcActuatorfrcrangeMax;
|
||||
/// \brief "mjc:actuatorfrcrange:min"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcActuatorfrcrangeMin;
|
||||
/// \brief "mjc:actuatorgravcomp"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcActuatorgravcomp;
|
||||
/// \brief "mjc:armature"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcArmature;
|
||||
/// \brief "mjc:biasPrm"
|
||||
///
|
||||
/// MjcPhysicsActuatorAPI
|
||||
@@ -162,10 +188,10 @@ struct MjcPhysicsTokensType {
|
||||
///
|
||||
/// MjcPhysicsActuatorAPI
|
||||
const TfToken mjcCrankLength;
|
||||
/// \brief "mjc:crankSite"
|
||||
/// \brief "mjc:ctrl"
|
||||
///
|
||||
/// MjcPhysicsActuatorAPI
|
||||
const TfToken mjcCrankSite;
|
||||
/// MjcPhysicsKeyframe
|
||||
const TfToken mjcCtrl;
|
||||
/// \brief "mjc:ctrlLimited"
|
||||
///
|
||||
/// MjcPhysicsActuatorAPI
|
||||
@@ -178,6 +204,10 @@ struct MjcPhysicsTokensType {
|
||||
///
|
||||
/// MjcPhysicsActuatorAPI
|
||||
const TfToken mjcCtrlRangeMin;
|
||||
/// \brief "mjc:damping"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcDamping;
|
||||
/// \brief "mjc:dynPrm"
|
||||
///
|
||||
/// MjcPhysicsActuatorAPI
|
||||
@@ -290,6 +320,10 @@ struct MjcPhysicsTokensType {
|
||||
///
|
||||
/// MjcPhysicsActuatorAPI
|
||||
const TfToken mjcForceRangeMin;
|
||||
/// \brief "mjc:frictionloss"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcFrictionloss;
|
||||
/// \brief "mjc:gainPrm"
|
||||
///
|
||||
/// MjcPhysicsActuatorAPI
|
||||
@@ -318,6 +352,18 @@ struct MjcPhysicsTokensType {
|
||||
///
|
||||
/// MjcPhysicsActuatorAPI
|
||||
const TfToken mjcLengthRangeMin;
|
||||
/// \brief "mjc:margin"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcMargin;
|
||||
/// \brief "mjc:mpos"
|
||||
///
|
||||
/// MjcPhysicsKeyframe
|
||||
const TfToken mjcMpos;
|
||||
/// \brief "mjc:mquat"
|
||||
///
|
||||
/// MjcPhysicsKeyframe
|
||||
const TfToken mjcMquat;
|
||||
/// \brief "mjc:option:actuatorgroupdisable"
|
||||
///
|
||||
/// MjcPhysicsSceneAPI
|
||||
@@ -422,6 +468,18 @@ struct MjcPhysicsTokensType {
|
||||
///
|
||||
/// MjcPhysicsSceneAPI
|
||||
const TfToken mjcOptionWind;
|
||||
/// \brief "mjc:qpos"
|
||||
///
|
||||
/// MjcPhysicsKeyframe
|
||||
const TfToken mjcQpos;
|
||||
/// \brief "mjc:qvel"
|
||||
///
|
||||
/// MjcPhysicsKeyframe
|
||||
const TfToken mjcQvel;
|
||||
/// \brief "mjc:ref"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcRef;
|
||||
/// \brief "mjc:refSite"
|
||||
///
|
||||
/// MjcPhysicsActuatorAPI
|
||||
@@ -434,6 +492,34 @@ struct MjcPhysicsTokensType {
|
||||
///
|
||||
/// MjcPhysicsActuatorAPI
|
||||
const TfToken mjcSliderSite;
|
||||
/// \brief "mjc:solimpfriction"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcSolimpfriction;
|
||||
/// \brief "mjc:solimplimit"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcSolimplimit;
|
||||
/// \brief "mjc:solreffriction"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcSolreffriction;
|
||||
/// \brief "mjc:solreflimit"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcSolreflimit;
|
||||
/// \brief "mjc:springdamper"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcSpringdamper;
|
||||
/// \brief "mjc:springref"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcSpringref;
|
||||
/// \brief "mjc:stiffness"
|
||||
///
|
||||
/// MjcPhysicsJointAPI
|
||||
const TfToken mjcStiffness;
|
||||
/// \brief "muscle"
|
||||
///
|
||||
/// Possible value for MjcPhysicsActuatorAPI::GetMjcBiasTypeAttr(), Possible
|
||||
@@ -478,7 +564,8 @@ struct MjcPhysicsTokensType {
|
||||
///
|
||||
/// Possible value for MjcPhysicsActuatorAPI::GetMjcActLimitedAttr(), Possible
|
||||
/// value for MjcPhysicsActuatorAPI::GetMjcCtrlLimitedAttr(), Possible value
|
||||
/// for MjcPhysicsActuatorAPI::GetMjcForceLimitedAttr()
|
||||
/// for MjcPhysicsActuatorAPI::GetMjcForceLimitedAttr(), Possible value for
|
||||
/// MjcPhysicsJointAPI::GetMjcActuatorfrclimitedAttr()
|
||||
const TfToken true_;
|
||||
/// \brief "user"
|
||||
///
|
||||
@@ -488,23 +575,31 @@ struct MjcPhysicsTokensType {
|
||||
const TfToken user;
|
||||
/// \brief "CollisionAPI"
|
||||
///
|
||||
/// Schema identifer and family for MjcPhysicsCollisionAPI
|
||||
/// Schema identifier and family for MjcPhysicsCollisionAPI
|
||||
const TfToken CollisionAPI;
|
||||
/// \brief "Keyframe"
|
||||
///
|
||||
/// Schema identifier and family for MjcPhysicsKeyframe
|
||||
const TfToken Keyframe;
|
||||
/// \brief "MeshCollisionAPI"
|
||||
///
|
||||
/// Schema identifer and family for MjcPhysicsMeshCollisionAPI
|
||||
/// Schema identifier and family for MjcPhysicsMeshCollisionAPI
|
||||
const TfToken MeshCollisionAPI;
|
||||
/// \brief "PhysicsActuatorAPI"
|
||||
///
|
||||
/// Schema identifer and family for MjcPhysicsActuatorAPI
|
||||
/// Schema identifier and family for MjcPhysicsActuatorAPI
|
||||
const TfToken PhysicsActuatorAPI;
|
||||
/// \brief "PhysicsJointsAPI"
|
||||
///
|
||||
/// Schema identifier and family for MjcPhysicsJointAPI
|
||||
const TfToken PhysicsJointsAPI;
|
||||
/// \brief "SceneAPI"
|
||||
///
|
||||
/// Schema identifer and family for MjcPhysicsSceneAPI
|
||||
/// Schema identifier and family for MjcPhysicsSceneAPI
|
||||
const TfToken SceneAPI;
|
||||
/// \brief "SiteAPI"
|
||||
///
|
||||
/// Schema identifer and family for MjcPhysicsSiteAPI
|
||||
/// Schema identifier and family for MjcPhysicsSiteAPI
|
||||
const TfToken SiteAPI;
|
||||
/// A vector of all of the tokens listed above.
|
||||
const std::vector<TfToken> allTokens;
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright 2025 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_EXPERIMENTAL_SRC_USD_USD_TO_MJSPEC_H_
|
||||
#define MUJOCO_EXPERIMENTAL_SRC_USD_USD_TO_MJSPEC_H_
|
||||
|
||||
#include <mujoco/mujoco.h>
|
||||
#include <pxr/usd/usd/common.h>
|
||||
|
||||
// Given a USD stage, this function will do a best effort conversion to
|
||||
// mjSpec.
|
||||
//
|
||||
// Particular care is taken for physics data to be lossless but visual
|
||||
// data such as materials may be lossy.
|
||||
MJAPI mjSpec* mj_parseUSDStage(pxr::UsdStageRefPtr stage);
|
||||
|
||||
#endif // MUJOCO_EXPERIMENTAL_SRC_USD_USD_TO_MJSPEC_H_
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2025 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_SRC_EXPERIMENTAL_USD_WRITER_H_
|
||||
#define MUJOCO_SRC_EXPERIMENTAL_USD_WRITER_H_
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <mujoco/mujoco.h>
|
||||
#include <pxr/usd/sdf/path.h>
|
||||
#include <pxr/usd/usd/common.h>
|
||||
|
||||
namespace mujoco {
|
||||
namespace usd {
|
||||
using PoseSinkFn =
|
||||
std::function<void(const mjData* const, std::vector<pxr::SdfPath>)>;
|
||||
|
||||
class Writer {
|
||||
public:
|
||||
Writer(pxr::UsdStageRefPtr stage, mjSpec* spec, mjModel_* model);
|
||||
~Writer();
|
||||
Writer(const Writer&) = delete;
|
||||
Writer& operator=(const Writer&) = delete;
|
||||
|
||||
void Update(const mjData* const data);
|
||||
void AddSink(PoseSinkFn sink_fn);
|
||||
|
||||
private:
|
||||
void BuildMjUsdMapping();
|
||||
|
||||
pxr::UsdStageRefPtr stage_;
|
||||
std::vector<pxr::SdfPath> body_id_to_path_;
|
||||
mjSpec* spec_ = nullptr;
|
||||
mjModel_* model_ = nullptr;
|
||||
std::vector<PoseSinkFn> pose_sinks_;
|
||||
};
|
||||
} // namespace usd
|
||||
} // namespace mujoco
|
||||
|
||||
#endif // MUJOCO_SRC_EXPERIMENTAL_USD_WRITER_H_
|
||||
@@ -452,8 +452,8 @@ typedef struct mjLROpt_ mjLROpt;
|
||||
|
||||
//---------------------------------- mjVFS ---------------------------------------------------------
|
||||
|
||||
struct mjVFS_ { // virtual file system for loading from memory
|
||||
void* impl_; // internal pointer to VFS memory
|
||||
struct mjVFS_ { // virtual file system for loading from memory
|
||||
void* impl_; // internal pointer to VFS memory
|
||||
};
|
||||
typedef struct mjVFS_ mjVFS;
|
||||
|
||||
@@ -508,7 +508,8 @@ typedef struct mjOption_ mjOption;
|
||||
|
||||
struct mjVisual_ { // visualization options
|
||||
struct { // global parameters
|
||||
int orthographic; // is the free camera orthographic (0: no, 1: yes)
|
||||
int cameraid; // initial camera id (-1: free)
|
||||
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)
|
||||
@@ -630,6 +631,7 @@ struct mjModel_ {
|
||||
int nbvh; // number of total bounding volumes in all bodies
|
||||
int nbvhstatic; // number of static bounding volumes (aabb stored in mjModel)
|
||||
int nbvhdynamic; // number of dynamic bounding volumes (aabb stored in mjData)
|
||||
int noct; // number of total octree cells in all meshes
|
||||
int njnt; // number of joints
|
||||
int ngeom; // number of geoms
|
||||
int nsite; // number of sites
|
||||
@@ -763,6 +765,11 @@ struct mjModel_ {
|
||||
int* bvh_nodeid; // geom or elem id of node; -1: non-leaf (nbvh x 1)
|
||||
mjtNum* bvh_aabb; // local bounding box (center, size) (nbvhstatic x 6)
|
||||
|
||||
// octree spatial partitioning
|
||||
int* oct_depth; // depth in the octree (noct x 1)
|
||||
int* oct_child; // children of octree node (noct x 8)
|
||||
mjtNum* oct_aabb; // octree node bounding box (center, size) (noct x 6)
|
||||
|
||||
// joints
|
||||
int* jnt_type; // type of joint (mjtJoint) (njnt x 1)
|
||||
int* jnt_qposadr; // start addr in 'qpos' for joint's data (njnt x 1)
|
||||
@@ -950,6 +957,8 @@ struct mjModel_ {
|
||||
int* mesh_facenum; // number of faces (nmesh x 1)
|
||||
int* mesh_bvhadr; // address of bvh root (nmesh x 1)
|
||||
int* mesh_bvhnum; // number of bvh (nmesh x 1)
|
||||
int* mesh_octadr; // address of octree root (nmesh x 1)
|
||||
int* mesh_octnum; // number of octree nodes (nmesh x 1)
|
||||
int* mesh_normaladr; // first normal address (nmesh x 1)
|
||||
int* mesh_normalnum; // number of normals (nmesh x 1)
|
||||
int* mesh_texcoordadr; // texcoord data address; -1: no texcoord (nmesh x 1)
|
||||
|
||||
@@ -292,6 +292,7 @@ struct mjvOption_ { // abstract visualization options
|
||||
mjtByte skingroup[mjNGROUP]; // skin visualization by group
|
||||
mjtByte flags[mjNVISFLAG]; // visualization flags (indexed by mjtVisFlag)
|
||||
int bvh_depth; // depth of the bounding volume hierarchy to be visualized
|
||||
int oct_depth; // depth of the octree to be visualized
|
||||
int flex_layer; // element layer to be visualized for 3D flex
|
||||
};
|
||||
typedef struct mjvOption_ mjvOption;
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
X( nbvh ) \
|
||||
X( nbvhstatic ) \
|
||||
X( nbvhdynamic ) \
|
||||
X( noct ) \
|
||||
X( njnt ) \
|
||||
X( ngeom ) \
|
||||
X( nsite ) \
|
||||
@@ -216,6 +217,9 @@
|
||||
X ( int, bvh_child, nbvh, 2 ) \
|
||||
X ( int, bvh_nodeid, nbvh, 1 ) \
|
||||
X ( mjtNum, bvh_aabb, nbvhstatic, 6 ) \
|
||||
X ( int, oct_depth, noct, 1 ) \
|
||||
X ( int, oct_child, noct, 8 ) \
|
||||
X ( mjtNum, oct_aabb, noct, 6 ) \
|
||||
X ( int, jnt_type, njnt, 1 ) \
|
||||
X ( int, jnt_qposadr, njnt, 1 ) \
|
||||
X ( int, jnt_dofadr, njnt, 1 ) \
|
||||
@@ -390,6 +394,8 @@
|
||||
X ( int, mesh_facenum, nmesh, 1 ) \
|
||||
X ( int, mesh_bvhadr, nmesh, 1 ) \
|
||||
X ( int, mesh_bvhnum, nmesh, 1 ) \
|
||||
X ( int, mesh_octadr, nmesh, 1 ) \
|
||||
X ( int, mesh_octnum, nmesh, 1 ) \
|
||||
X ( int, mesh_graphadr, nmesh, 1 ) \
|
||||
X ( mjtNum, mesh_scale, nmesh, 3 ) \
|
||||
X ( mjtNum, mesh_pos, nmesh, 3 ) \
|
||||
|
||||
+35
-8
@@ -16,7 +16,7 @@
|
||||
#define MUJOCO_MUJOCO_H_
|
||||
|
||||
// header version; should match the library version as returned by mj_version()
|
||||
#define mjVERSION_HEADER 333
|
||||
#define mjVERSION_HEADER 334
|
||||
|
||||
// needed to define size_t, fabs and log10
|
||||
#include <stdlib.h>
|
||||
@@ -1411,11 +1411,6 @@ MJAPI void mju_taskJoin(mjTask* task);
|
||||
MJAPI mjsElement* mjs_attach(mjsElement* parent, const mjsElement* child,
|
||||
const char* prefix, const char* suffix);
|
||||
|
||||
// Delete body and descendants from mjSpec, remove all references, return 0 on success.
|
||||
MJAPI int mjs_detachBody(mjSpec* s, mjsBody* b);
|
||||
|
||||
// Delete default class and descendants from mjSpec, remove all references, return 0 on success.
|
||||
MJAPI int mjs_detachDefault(mjSpec* s, mjsDefault* d);
|
||||
|
||||
//---------------------------------- Tree elements -------------------------------------------------
|
||||
|
||||
@@ -1443,8 +1438,8 @@ MJAPI mjsLight* mjs_addLight(mjsBody* body, const mjsDefault* def);
|
||||
// Add frame to body.
|
||||
MJAPI mjsFrame* mjs_addFrame(mjsBody* body, mjsFrame* parentframe);
|
||||
|
||||
// Delete object corresponding to the given element, return 0 on success.
|
||||
MJAPI int mjs_delete(mjsElement* element);
|
||||
// Remove object corresponding to the given element, return 0 on success.
|
||||
MJAPI int mjs_delete(mjSpec* spec, mjsElement* element);
|
||||
|
||||
|
||||
//---------------------------------- Non-tree elements ---------------------------------------------
|
||||
@@ -1501,6 +1496,38 @@ MJAPI mjsPlugin* mjs_addPlugin(mjSpec* s);
|
||||
MJAPI mjsDefault* mjs_addDefault(mjSpec* s, const char* classname, const mjsDefault* parent);
|
||||
|
||||
|
||||
//---------------------------------- Set actuator parameters ---------------------------------------
|
||||
|
||||
// Set actuator to motor, return error if any.
|
||||
MJAPI const char* mjs_setToMotor(mjsActuator* actuator);
|
||||
|
||||
// Set actuator to position, return error if any.
|
||||
MJAPI const char* mjs_setToPosition(mjsActuator* actuator, double kp, double kv[1],
|
||||
double dampratio[1], double timeconst[1], double inheritrange);
|
||||
|
||||
// Set actuator to integrated velocity, return error if any.
|
||||
MJAPI const char* mjs_setToIntVelocity(mjsActuator* actuator, double kp, double kv[1],
|
||||
double dampratio[1], double timeconst[1], double inheritrange);
|
||||
|
||||
// Set actuator to velocity servo, return error if any.
|
||||
MJAPI const char* mjs_setToVelocity(mjsActuator* actuator, double kv);
|
||||
|
||||
// Set actuator to activate damper, return error if any.
|
||||
MJAPI const char* mjs_setToDamper(mjsActuator* actuator, double kv);
|
||||
|
||||
// Set actuator to hydraulic or pneumatic cylinder, return error if any.
|
||||
MJAPI const char* mjs_setToCylinder(mjsActuator* actuator, double timeconst,
|
||||
double bias, double area, double diameter);
|
||||
|
||||
// Set actuator to muscle, return error if any.a
|
||||
MJAPI const char* mjs_setToMuscle(mjsActuator* actuator, double timeconst[2], double tausmooth,
|
||||
double range[2], double force, double scale, double lmin,
|
||||
double lmax, double vmax, double fpmax, double fvmax);
|
||||
|
||||
// Set actuator to active adhesion, return error if any.
|
||||
MJAPI const char* mjs_setToAdhesion(mjsActuator* actuator, double gain);
|
||||
|
||||
|
||||
//---------------------------------- Assets --------------------------------------------------------
|
||||
|
||||
// Add mesh.
|
||||
|
||||
@@ -48,6 +48,8 @@ from mujoco.mjx._src.smooth import rne
|
||||
from mujoco.mjx._src.smooth import rne_postconstraint
|
||||
from mujoco.mjx._src.smooth import subtree_vel
|
||||
from mujoco.mjx._src.smooth import tendon
|
||||
from mujoco.mjx._src.smooth import tendon_armature
|
||||
from mujoco.mjx._src.smooth import tendon_bias
|
||||
from mujoco.mjx._src.smooth import transmission
|
||||
from mujoco.mjx._src.solver import solve
|
||||
from mujoco.mjx._src.support import apply_ft
|
||||
|
||||
@@ -73,6 +73,7 @@ def fwd_position(m: Model, d: Data) -> Data:
|
||||
d = smooth.camlight(m, d)
|
||||
d = smooth.tendon(m, d)
|
||||
d = smooth.crb(m, d)
|
||||
d = smooth.tendon_armature(m, d)
|
||||
d = smooth.factor_m(m, d)
|
||||
d = collision_driver.collision(m, d)
|
||||
d = constraint.make_constraint(m, d)
|
||||
@@ -93,6 +94,7 @@ def fwd_velocity(m: Model, d: Data) -> Data:
|
||||
d = smooth.com_vel(m, d)
|
||||
d = passive.passive(m, d)
|
||||
d = smooth.rne(m, d)
|
||||
d = smooth.tendon_bias(m, d)
|
||||
return d
|
||||
|
||||
|
||||
|
||||
@@ -93,11 +93,15 @@ def inverse(m: Model, d: Data) -> Data:
|
||||
d = discrete_acc(m, d)
|
||||
|
||||
d = inv_constraint(m, d)
|
||||
d = smooth.rne(m, d, flg_acc=True)
|
||||
d = smooth.rne(m, d)
|
||||
d = smooth.tendon_bias(m, d)
|
||||
d = sensor.sensor_acc(m, d)
|
||||
|
||||
qfrc_inverse = (
|
||||
d.qfrc_bias + m.dof_armature * d.qacc - d.qfrc_passive - d.qfrc_constraint
|
||||
d.qfrc_bias
|
||||
+ support.mul_m(m, d, d.qacc)
|
||||
- d.qfrc_passive
|
||||
- d.qfrc_constraint
|
||||
)
|
||||
|
||||
if m.opt.enableflags & EnableBit.INVDISCRETE:
|
||||
|
||||
@@ -19,6 +19,7 @@ from jax import numpy as jp
|
||||
import mujoco
|
||||
from mujoco import mjx
|
||||
from mujoco.mjx._src import support
|
||||
from mujoco.mjx._src import test_util
|
||||
import numpy as np
|
||||
|
||||
# tolerance for difference between MuJoCo and MJX calculations - mostly
|
||||
@@ -109,6 +110,41 @@ class InverseTest(parameterized.TestCase):
|
||||
self.assertLess(fwdinv1, 1.0e-3)
|
||||
_assert_eq(dxinv.qacc, dx.qacc, 'qacc')
|
||||
|
||||
def test_inverse_tendon_armature(self):
|
||||
m = test_util.load_test_file('tendon/armature.xml')
|
||||
|
||||
d = mujoco.MjData(m)
|
||||
d.qvel = np.random.uniform(low=-0.01, high=0.01, size=d.qvel.shape)
|
||||
d.ctrl = np.random.uniform(low=-0.01, high=0.01, size=d.ctrl.shape)
|
||||
d.qfrc_applied = np.random.uniform(
|
||||
low=-0.01, high=0.01, size=d.qfrc_applied.shape
|
||||
)
|
||||
d.xfrc_applied = np.random.uniform(
|
||||
low=-0.01, high=0.01, size=d.xfrc_applied.shape
|
||||
)
|
||||
mujoco.mj_step(m, d, 10)
|
||||
|
||||
mx = mjx.put_model(m)
|
||||
dx = mjx.put_data(m, d)
|
||||
|
||||
dx = mjx.forward(mx, dx)
|
||||
dxinv = mjx.inverse(mx, dx)
|
||||
|
||||
fwdinv0 = jp.linalg.norm(
|
||||
dxinv.qfrc_constraint - dx.qfrc_constraint, ord=np.inf
|
||||
)
|
||||
fwdinv1 = jp.linalg.norm(
|
||||
dxinv.qfrc_inverse
|
||||
- (
|
||||
dx.qfrc_applied + dx.qfrc_actuator + support.xfrc_accumulate(mx, dx)
|
||||
),
|
||||
ord=np.inf,
|
||||
)
|
||||
|
||||
self.assertLess(fwdinv0, 1.0e-3)
|
||||
self.assertLess(fwdinv1, 1.0e-3)
|
||||
_assert_eq(dxinv.qacc, dx.qacc, 'qacc')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
absltest.main()
|
||||
|
||||
+108
-118
@@ -41,51 +41,51 @@ def _is_cuda_gpu_device(device: jax.Device) -> bool:
|
||||
return device in cuda_devices
|
||||
|
||||
|
||||
def _resolve_backend_impl(
|
||||
def _resolve_impl(
|
||||
device: jax.Device,
|
||||
) -> types.BackendImpl:
|
||||
"""Pick a default backend impl based on the device specified."""
|
||||
) -> types.Impl:
|
||||
"""Pick a default implementation based on the device specified."""
|
||||
if _is_cuda_gpu_device(device):
|
||||
# TODO(btaba): Remove flag once Warp is ready to launch.
|
||||
mjx_warp_enabled = os.environ.get('MJX_WARP_ENABLED', 'f').lower() == 'true'
|
||||
if mjx_warp_enabled:
|
||||
logging.debug('Picking default backend implementation: Warp.')
|
||||
return types.BackendImpl.WARP
|
||||
logging.debug('Picking default implementation: Warp.')
|
||||
return types.Impl.WARP
|
||||
logging.info('MJX Warp is disabled via MJX_WARP_ENABLED=false.')
|
||||
|
||||
if device.platform in ('gpu', 'tpu'):
|
||||
logging.debug('Picking default backend implementation: JAX.')
|
||||
return types.BackendImpl.JAX
|
||||
logging.debug('Picking default implementation: JAX.')
|
||||
return types.Impl.JAX
|
||||
|
||||
if device.platform == 'cpu':
|
||||
mjx_c_default = (
|
||||
os.environ.get('MJX_C_DEFAULT_ENABLED', 'f').lower() == 'true'
|
||||
)
|
||||
if mjx_c_default:
|
||||
logging.debug('Picking default backend implementation: C.')
|
||||
return types.BackendImpl.C
|
||||
return types.BackendImpl.JAX
|
||||
logging.debug('Picking default implementation: C.')
|
||||
return types.Impl.C
|
||||
return types.Impl.JAX
|
||||
|
||||
raise ValueError(f'Unsupported device: {device}')
|
||||
|
||||
|
||||
def _resolve_device(
|
||||
backend_impl: types.BackendImpl,
|
||||
impl: types.Impl,
|
||||
) -> jax.Device:
|
||||
"""Resolves a device based on the backend implementation."""
|
||||
backend_impl = types.BackendImpl(backend_impl)
|
||||
if backend_impl == types.BackendImpl.JAX:
|
||||
"""Resolves a device based on the implementation."""
|
||||
impl = types.Impl(impl)
|
||||
if impl == types.Impl.JAX:
|
||||
device_0 = jax.devices()[0]
|
||||
logging.debug('Picking default device: %s.', device_0)
|
||||
return device_0
|
||||
|
||||
if backend_impl == types.BackendImpl.C:
|
||||
if impl == types.Impl.C:
|
||||
cpu_0 = jax.devices('cpu')[0]
|
||||
logging.debug('Picking default device: %s', cpu_0)
|
||||
return cpu_0
|
||||
|
||||
if backend_impl == types.BackendImpl.WARP:
|
||||
# WARP backend requires a CUDA GPU.
|
||||
if impl == types.Impl.WARP:
|
||||
# WARP implementation requires a CUDA GPU.
|
||||
cuda_gpus = [d for d in jax.devices('cuda')]
|
||||
if not cuda_gpus:
|
||||
raise AssertionError(
|
||||
@@ -96,64 +96,64 @@ def _resolve_device(
|
||||
logging.debug('Picking default device: %s', cuda_gpus[0])
|
||||
return cuda_gpus[0]
|
||||
|
||||
raise ValueError(f'Unsupported backend implementation: {backend_impl}')
|
||||
raise ValueError(f'Unsupported implementation: {impl}')
|
||||
|
||||
|
||||
def _check_backend_impl_device_compatibility(
|
||||
backend_impl: Union[str, types.BackendImpl],
|
||||
def _check_impl_device_compatibility(
|
||||
impl: Union[str, types.Impl],
|
||||
device: jax.Device,
|
||||
) -> None:
|
||||
"""Checks that the backend implementation is compatible with the device."""
|
||||
if backend_impl is None:
|
||||
raise ValueError('No backend implementation specified.')
|
||||
"""Checks that the implementation is compatible with the device."""
|
||||
if impl is None:
|
||||
raise ValueError('No implementation specified.')
|
||||
|
||||
backend_impl = types.BackendImpl(backend_impl)
|
||||
impl = types.Impl(impl)
|
||||
|
||||
if backend_impl == types.BackendImpl.WARP:
|
||||
if impl == types.Impl.WARP:
|
||||
if not _is_cuda_gpu_device(device):
|
||||
raise AssertionError(
|
||||
'Warp backend implementation requires a CUDA GPU device, got '
|
||||
'Warp implementation requires a CUDA GPU device, got '
|
||||
f'{device}.'
|
||||
)
|
||||
|
||||
mjx_warp_enabled = os.environ.get('MJX_WARP_ENABLED', 'f').lower() == 'true'
|
||||
if not mjx_warp_enabled:
|
||||
raise AssertionError(
|
||||
'Warp backend implementation is disabled via MJX_WARP_ENABLED=false.'
|
||||
'Warp implementation is disabled via MJX_WARP_ENABLED=false.'
|
||||
)
|
||||
|
||||
is_cpu_device = device.platform == 'cpu'
|
||||
if backend_impl == types.BackendImpl.C:
|
||||
if impl == types.Impl.C:
|
||||
if not is_cpu_device:
|
||||
raise AssertionError(
|
||||
f'C backend implementation requires a CPU device, got {device}.'
|
||||
f'C implementation requires a CPU device, got {device}.'
|
||||
)
|
||||
|
||||
# NB: JAX backend works with any device.
|
||||
# NB: JAX implementation works with any device.
|
||||
|
||||
|
||||
def _resolve_backend_impl_and_device(
|
||||
backend_impl: Optional[Union[str, types.BackendImpl]],
|
||||
def _resolve_impl_and_device(
|
||||
impl: Optional[Union[str, types.Impl]],
|
||||
device: Optional[jax.Device] = None,
|
||||
) -> Tuple[types.BackendImpl, jax.Device]:
|
||||
"""Resolves a backend implementation and device."""
|
||||
if backend_impl:
|
||||
backend_impl = types.BackendImpl(backend_impl)
|
||||
) -> Tuple[types.Impl, jax.Device]:
|
||||
"""Resolves a implementation and device."""
|
||||
if impl:
|
||||
impl = types.Impl(impl)
|
||||
|
||||
has_backend_impl, has_device = backend_impl is not None, device is not None
|
||||
if (has_backend_impl, has_device) == (True, True):
|
||||
has_impl, has_device = impl is not None, device is not None
|
||||
if (has_impl, has_device) == (True, True):
|
||||
pass
|
||||
elif (has_backend_impl, has_device) == (True, False):
|
||||
device = _resolve_device(backend_impl)
|
||||
elif (has_backend_impl, has_device) == (False, True):
|
||||
backend_impl = _resolve_backend_impl(device)
|
||||
elif (has_impl, has_device) == (True, False):
|
||||
device = _resolve_device(impl)
|
||||
elif (has_impl, has_device) == (False, True):
|
||||
impl = _resolve_impl(device)
|
||||
else:
|
||||
device = jax.devices(jax.default_backend())[0]
|
||||
logging.info('Using JAX default device: %s.', device)
|
||||
backend_impl = _resolve_backend_impl(device)
|
||||
impl = _resolve_impl(device)
|
||||
|
||||
_check_backend_impl_device_compatibility(backend_impl, device)
|
||||
return backend_impl, device # pytype: disable=bad-return-type
|
||||
_check_impl_device_compatibility(impl, device)
|
||||
return impl, device # pytype: disable=bad-return-type
|
||||
|
||||
|
||||
def _strip_weak_type(tree):
|
||||
@@ -167,7 +167,7 @@ def _strip_weak_type(tree):
|
||||
|
||||
def _put_option(
|
||||
o: mujoco.MjOption,
|
||||
backend_impl: types.BackendImpl,
|
||||
impl: types.Impl,
|
||||
impl_fields: Optional[dict[str, Any]] = None,
|
||||
) -> types.Option:
|
||||
"""Returns mjx.Option given mujoco.MjOption."""
|
||||
@@ -195,7 +195,7 @@ def _put_option(
|
||||
fields['disableflags'] = types.DisableBit(o.disableflags)
|
||||
fields['enableflags'] = types.EnableBit(o.enableflags)
|
||||
|
||||
if backend_impl == types.BackendImpl.JAX:
|
||||
if impl == types.Impl.JAX:
|
||||
has_fluid_params = o.density > 0 or o.viscosity > 0 or o.wind.any()
|
||||
implicitfast = o.integrator == mujoco.mjtIntegrator.mjINT_IMPLICITFAST
|
||||
if implicitfast and has_fluid_params:
|
||||
@@ -203,12 +203,12 @@ def _put_option(
|
||||
fields['has_fluid_params'] = has_fluid_params
|
||||
return types.OptionJAX(**fields, **(impl_fields or {}))
|
||||
|
||||
if backend_impl == types.BackendImpl.C:
|
||||
if impl == types.Impl.C:
|
||||
c_field_keys = types.OptionC.__annotations__.keys() - fields.keys()
|
||||
c_fields = {k: getattr(o, k, None) for k in c_field_keys}
|
||||
return types.OptionC(**fields, **c_fields, **(impl_fields or {}))
|
||||
|
||||
raise NotImplementedError(f'Unsupported backend: {backend_impl}')
|
||||
raise NotImplementedError(f'Unsupported implementation: {impl}')
|
||||
|
||||
|
||||
def _put_statistic(s: mujoco.MjStatistic) -> types.Statistic:
|
||||
@@ -248,23 +248,6 @@ def _put_model_jax(
|
||||
if t == mujoco.mjtGeom.mjGEOM_MESH:
|
||||
mesh_geomid.add(g)
|
||||
|
||||
# check for unsupported sensor and equality constraint combinations
|
||||
sensor_rne_postconstraint = (
|
||||
np.any(m.sensor_type == types.SensorType.ACCELEROMETER)
|
||||
| np.any(m.sensor_type == types.SensorType.FORCE)
|
||||
| np.any(m.sensor_type == types.SensorType.TORQUE)
|
||||
| np.any(m.sensor_type == types.SensorType.FRAMELINACC)
|
||||
| np.any(m.sensor_type == types.SensorType.FRAMEANGACC)
|
||||
)
|
||||
eq_connect_weld = np.any(m.eq_type == types.EqType.CONNECT) | np.any(
|
||||
m.eq_type == types.EqType.WELD
|
||||
)
|
||||
if sensor_rne_postconstraint and eq_connect_weld:
|
||||
raise NotImplementedError(
|
||||
'rne_postconstraint not implemented with equality constraints:'
|
||||
' connect, weld.'
|
||||
)
|
||||
|
||||
for enum_field, enum_type, mj_type in (
|
||||
(m.actuator_biastype, types.BiasType, mujoco.mjtBias),
|
||||
(m.actuator_dyntype, types.DynType, mujoco.mjtDyn),
|
||||
@@ -283,7 +266,7 @@ def _put_model_jax(
|
||||
mj_field_names = {f.name for f in types.Model.fields() if f.name != '_impl'}
|
||||
fields = {f: getattr(m, f) for f in mj_field_names}
|
||||
fields['cam_mat0'] = fields['cam_mat0'].reshape((-1, 3, 3))
|
||||
fields['opt'] = _put_option(m.opt, types.BackendImpl.JAX)
|
||||
fields['opt'] = _put_option(m.opt, types.Impl.JAX)
|
||||
fields['stat'] = _put_statistic(m.stat)
|
||||
|
||||
fields_jax = {}
|
||||
@@ -340,7 +323,7 @@ def _put_model_c(
|
||||
mj_field_names = {f.name for f in types.Model.fields() if f.name != '_impl'}
|
||||
fields = {f: getattr(m, f) for f in mj_field_names}
|
||||
fields['cam_mat0'] = fields['cam_mat0'].reshape((-1, 3, 3))
|
||||
fields['opt'] = _put_option(m.opt, backend_impl=types.BackendImpl.C)
|
||||
fields['opt'] = _put_option(m.opt, impl=types.Impl.C)
|
||||
fields['stat'] = _put_statistic(m.stat)
|
||||
|
||||
c_impl_keys = (
|
||||
@@ -359,7 +342,7 @@ def _put_model_c(
|
||||
def put_model(
|
||||
m: mujoco.MjModel,
|
||||
device: Optional[jax.Device] = None,
|
||||
backend_impl: Optional[Union[str, types.BackendImpl]] = None,
|
||||
impl: Optional[Union[str, types.Impl]] = None,
|
||||
_full_compat: bool = False, # pylint: disable=invalid-name
|
||||
) -> types.Model:
|
||||
"""Puts mujoco.MjModel onto a device, resulting in mjx.Model.
|
||||
@@ -367,7 +350,7 @@ def put_model(
|
||||
Args:
|
||||
m: the model to put onto device
|
||||
device: which device to use - if unspecified picks the default device
|
||||
backend_impl: backend implementation to use
|
||||
impl: implementation to use
|
||||
_full_compat: put all MjModel fields onto device irrespective of MJX support
|
||||
This is an experimental feature. Avoid using it for now.
|
||||
|
||||
@@ -375,28 +358,29 @@ def put_model(
|
||||
an mjx.Model placed on device
|
||||
|
||||
Raises:
|
||||
ValueError: if backend_impl is not supported
|
||||
ValueError: if impl is not supported
|
||||
DeprecationWarning: if _full_compat is True
|
||||
"""
|
||||
|
||||
if _full_compat:
|
||||
warnings.warn(
|
||||
'mjx.put_model(..., _full_compat=True) is deprecated. Use'
|
||||
' mjx.put_model(..., backend_impl=types.BackendImpl.C) instead.',
|
||||
'mjx.put_model(..., _full_compat=True) is deprecated and will be'
|
||||
' removed in MuJoCo >=3.4. Use mjx.put_model(..., impl=types.Impl.C)'
|
||||
' instead.',
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
backend_impl = types.BackendImpl.C
|
||||
impl = types.Impl.C
|
||||
|
||||
backend_impl, device = _resolve_backend_impl_and_device(backend_impl, device)
|
||||
if backend_impl == types.BackendImpl.JAX:
|
||||
impl, device = _resolve_impl_and_device(impl, device)
|
||||
if impl == types.Impl.JAX:
|
||||
return _put_model_jax(m, device)
|
||||
elif backend_impl == types.BackendImpl.C:
|
||||
elif impl == types.Impl.C:
|
||||
return _put_model_c(m, device)
|
||||
elif backend_impl == types.BackendImpl.WARP:
|
||||
raise NotImplementedError('Warp backend not implemented yet.')
|
||||
elif impl == types.Impl.WARP:
|
||||
raise NotImplementedError('Warp implementation not implemented yet.')
|
||||
else:
|
||||
raise ValueError(f'Unsupported backend implementation: {backend_impl}')
|
||||
raise ValueError(f'Unsupported implementation: {impl}')
|
||||
|
||||
|
||||
def _make_data_public_fields(m: types.Model) -> Dict[str, Any]:
|
||||
@@ -476,7 +460,7 @@ def _make_data_contact_jax(
|
||||
|
||||
|
||||
def _make_data_jax(
|
||||
m: types.Model,
|
||||
m: Union[types.Model, mujoco.MjModel],
|
||||
device: Optional[jax.Device] = None,
|
||||
) -> types.Data:
|
||||
"""Allocate and initialize Data for the JAX implementation."""
|
||||
@@ -564,7 +548,7 @@ def _make_data_jax(
|
||||
|
||||
|
||||
def _make_data_c(
|
||||
m: types.Model,
|
||||
m: Union[types.Model, mujoco.MjModel],
|
||||
device: Optional[jax.Device] = None,
|
||||
) -> types.Data:
|
||||
"""Allocate and initialize Data for the C implementation."""
|
||||
@@ -582,11 +566,14 @@ def _make_data_c(
|
||||
# TODO(stunya): remove the JAX contact from C data.
|
||||
contact = _make_data_contact_jax(dim, efc_address)
|
||||
|
||||
nflexvert = m.nflexvert
|
||||
nflexedge = m.nflexedge
|
||||
nflexelem = m.nflexelem
|
||||
nbvh = m.nbvh
|
||||
nbvhdynamic = m.nbvhdynamic
|
||||
def get(m, name: str):
|
||||
return getattr(m._impl, name) if hasattr(m, '_impl') else getattr(m, name) # pylint: disable=protected-access
|
||||
|
||||
nflexvert = get(m, 'nflexvert')
|
||||
nflexedge = get(m, 'nflexedge')
|
||||
nflexelem = get(m, 'nflexelem')
|
||||
nbvh = get(m, 'nbvh')
|
||||
nbvhdynamic = get(m, 'nbvhdynamic')
|
||||
zero_impl_fields = {
|
||||
'solver_niter': (int_,),
|
||||
'cdof': (m.nv, 6, float_),
|
||||
@@ -626,7 +613,7 @@ def _make_data_c(
|
||||
'qLDiagInv': (m.nv, float_),
|
||||
'ten_velocity': (m.ntendon, float_),
|
||||
'actuator_velocity': (m.nu, float_),
|
||||
'plugin_data': (m.nplugin, np.uint64),
|
||||
'plugin_data': (get(m, 'nplugin'), np.uint64),
|
||||
'B_rownnz': (m.nbody, np.int32),
|
||||
'B_rowadr': (m.nbody, np.int32),
|
||||
'B_colind': (m.nB, np.int32),
|
||||
@@ -696,7 +683,7 @@ def _make_data_c(
|
||||
def make_data(
|
||||
m: Union[types.Model, mujoco.MjModel],
|
||||
device: Optional[jax.Device] = None,
|
||||
backend_impl: Optional[Union[str, types.BackendImpl]] = None,
|
||||
impl: Optional[Union[str, types.Impl]] = None,
|
||||
_full_compat: bool = False, # pylint: disable=invalid-name
|
||||
) -> types.Data:
|
||||
"""Allocate and initialize Data.
|
||||
@@ -704,7 +691,7 @@ def make_data(
|
||||
Args:
|
||||
m: the model to use
|
||||
device: which device to use - if unspecified picks the default device
|
||||
backend_impl: backend implementation to use
|
||||
impl: implementation to use ('jax', 'warp')
|
||||
_full_compat: put all fields onto device irrespective of MJX support This is
|
||||
an experimental feature. Avoid using it for now. If using this flag, also
|
||||
use _full_compat for put_model.
|
||||
@@ -713,35 +700,34 @@ def make_data(
|
||||
an initialized mjx.Data placed on device
|
||||
|
||||
Raises:
|
||||
ValueError: if the model's backend_impl does not match the make_data
|
||||
backend_impl
|
||||
NotImplementedError: if the backend_impl is not implemented yet
|
||||
ValueError: if the model's impl does not match the make_data impl
|
||||
NotImplementedError: if the impl is not implemented yet
|
||||
DeprecationWarning: if _full_compat is used
|
||||
"""
|
||||
if _full_compat:
|
||||
warnings.warn(
|
||||
'mjx.make_data(..., _full_compat=True) is deprecated. Use'
|
||||
' mjx.make_data(..., backend_impl=types.BackendImpl.C) instead.',
|
||||
' mjx.make_data(..., impl=types.Impl.C) instead.',
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
backend_impl = types.BackendImpl.C
|
||||
impl = types.Impl.C
|
||||
|
||||
backend_impl, device = _resolve_backend_impl_and_device(backend_impl, device)
|
||||
impl, device = _resolve_impl_and_device(impl, device)
|
||||
|
||||
if isinstance(m, types.Model) and m.backend_impl != backend_impl:
|
||||
if isinstance(m, types.Model) and m.impl != impl:
|
||||
raise ValueError(
|
||||
f'Model backend_impl {m.backend_impl} does not match make_data '
|
||||
f'backend_impl {backend_impl}.'
|
||||
f'Model impl {m.impl} does not match make_data '
|
||||
f'implementation {impl}.'
|
||||
)
|
||||
|
||||
if backend_impl == types.BackendImpl.JAX:
|
||||
if impl == types.Impl.JAX:
|
||||
return _make_data_jax(m, device)
|
||||
elif backend_impl == types.BackendImpl.C:
|
||||
elif impl == types.Impl.C:
|
||||
return _make_data_c(m, device)
|
||||
|
||||
raise NotImplementedError(
|
||||
f'make_data for backend_impl "{backend_impl}" not implemented yet.'
|
||||
f'make_data for implementation "{impl}" not implemented yet.'
|
||||
)
|
||||
|
||||
|
||||
@@ -951,7 +937,7 @@ def _put_data_c(
|
||||
if hasattr(d, f.name)
|
||||
}
|
||||
|
||||
# TODO(stunya): support islanding via C backend impl.
|
||||
# TODO(stunya): support islanding via C impl.
|
||||
impl_fields['solver_niter'] = impl_fields['solver_niter'][0]
|
||||
|
||||
# TODO(btaba): remove dense actuator moment.
|
||||
@@ -1039,7 +1025,7 @@ def put_data(
|
||||
m: mujoco.MjModel,
|
||||
d: mujoco.MjData,
|
||||
device: Optional[jax.Device] = None,
|
||||
backend_impl: Optional[Union[str, types.BackendImpl]] = None,
|
||||
impl: Optional[Union[str, types.Impl]] = None,
|
||||
_full_compat: bool = False, # pylint: disable=invalid-name
|
||||
) -> types.Data:
|
||||
"""Puts mujoco.MjData onto a device, resulting in mjx.Data.
|
||||
@@ -1048,7 +1034,7 @@ def put_data(
|
||||
m: the model to use
|
||||
d: the data to put on device
|
||||
device: which device to use - if unspecified picks the default device
|
||||
backend_impl: backend implementation to use
|
||||
impl: implementation to use ('jax', 'warp')
|
||||
_full_compat: put all MjModel fields onto device irrespective of MJX support
|
||||
This is an experimental feature. Avoid using it for now. If using this
|
||||
flag, also use _full_compat for put_model.
|
||||
@@ -1059,20 +1045,20 @@ def put_data(
|
||||
if _full_compat:
|
||||
warnings.warn(
|
||||
'mjx.put_data(..., _full_compat=True) is deprecated. Use'
|
||||
' mjx.put_data(..., backend_impl=types.BackendImpl.C) instead.',
|
||||
' mjx.put_data(..., impl=types.Impl.C) instead.',
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
backend_impl = types.BackendImpl.C
|
||||
impl = types.Impl.C
|
||||
|
||||
backend_impl, device = _resolve_backend_impl_and_device(backend_impl, device)
|
||||
if backend_impl == types.BackendImpl.JAX:
|
||||
impl, device = _resolve_impl_and_device(impl, device)
|
||||
if impl == types.Impl.JAX:
|
||||
return _put_data_jax(m, d, device)
|
||||
elif backend_impl == types.BackendImpl.C:
|
||||
elif impl == types.Impl.C:
|
||||
return _put_data_c(m, d, device)
|
||||
|
||||
raise NotImplementedError(
|
||||
f'put_data for backend_impl "{backend_impl}" not implemented yet.'
|
||||
f'put_data for implementation "{impl}" not implemented yet.'
|
||||
)
|
||||
|
||||
|
||||
@@ -1097,7 +1083,7 @@ def _get_data_into(
|
||||
batch_size = d.qpos.shape[0] if batched else 1
|
||||
|
||||
dof_i, dof_j = [], []
|
||||
if d.backend_impl == types.BackendImpl.JAX:
|
||||
if d.impl == types.Impl.JAX:
|
||||
for i in range(m.nv):
|
||||
j = i
|
||||
while j > -1:
|
||||
@@ -1116,13 +1102,13 @@ def _get_data_into(
|
||||
if ncon != result_i.ncon or nefc != result_i.nefc or nj != result_i.nJ:
|
||||
mujoco._functions._realloc_con_efc(result_i, ncon=ncon, nefc=nefc, nJ=nj) # pylint: disable=protected-access
|
||||
|
||||
if d.backend_impl == types.BackendImpl.JAX:
|
||||
if d.impl == types.Impl.JAX:
|
||||
all_fields = types.Data.fields() + types.DataJAX.fields()
|
||||
elif d.backend_impl == types.BackendImpl.C:
|
||||
elif d.impl == types.Impl.C:
|
||||
all_fields = types.Data.fields() + types.DataC.fields()
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
f'get_data_into for backend_impl "{d.backend_impl}" not implemented'
|
||||
f'get_data_into for implementation "{d.impl}" not implemented'
|
||||
' yet.'
|
||||
)
|
||||
|
||||
@@ -1188,7 +1174,7 @@ def _get_data_into(
|
||||
value = value.reshape(-1)
|
||||
elif field.name.startswith('efc_'):
|
||||
value = value[efc_active]
|
||||
if d.backend_impl == types.BackendImpl.JAX:
|
||||
if d.impl == types.Impl.JAX:
|
||||
if field.name == 'qM' and not support.is_sparse(m):
|
||||
value = value[dof_i, dof_j]
|
||||
elif field.name == 'qLD' and not support.is_sparse(m):
|
||||
@@ -1207,6 +1193,10 @@ def _get_data_into(
|
||||
else:
|
||||
setattr(result_i, field.name, value)
|
||||
|
||||
# TODO(taylorhowell): remove mapping once qM is deprecated
|
||||
# map inertia (sparse) to reduced inertia (compressed sparse) representation
|
||||
result_i.M[:] = result_i.qM[result_i.mapM2M]
|
||||
|
||||
# recalculate qLD and qLDiagInv as MJX and MuJoCo have different
|
||||
# representations of the Cholesky decomposition.
|
||||
mujoco.mj_factorM(m, result_i)
|
||||
@@ -1226,12 +1216,12 @@ def get_data_into(
|
||||
|
||||
d = jax.device_get(d)
|
||||
|
||||
if d.backend_impl in (types.BackendImpl.JAX, types.BackendImpl.C):
|
||||
if d.impl in (types.Impl.JAX, types.Impl.C):
|
||||
# TODO(stunya): Split out _get_data_into once codepaths diverge enough.
|
||||
return _get_data_into(result, m, d)
|
||||
|
||||
raise NotImplementedError(
|
||||
f'get_data_into for backend_impl "{d.backend_impl}" not implemented yet.'
|
||||
f'get_data_into for implementation "{d.impl}" not implemented yet.'
|
||||
)
|
||||
|
||||
|
||||
|
||||
+132
-144
@@ -26,8 +26,9 @@ from mujoco.mjx._src import io as mjx_io
|
||||
from mujoco.mjx._src import test_util
|
||||
|
||||
# pylint: disable=g-importing-member
|
||||
from mujoco.mjx._src.types import BackendImpl
|
||||
from mujoco.mjx._src.types import ConeType
|
||||
from mujoco.mjx._src.types import Impl
|
||||
from mujoco.mjx._src.types import JacobianType
|
||||
# pylint: enable=g-importing-member
|
||||
import numpy as np
|
||||
|
||||
@@ -114,11 +115,11 @@ class ModelIOTest(parameterized.TestCase):
|
||||
|
||||
@parameterized.product(
|
||||
xml=(_MULTIPLE_CONVEX_OBJECTS, _MULTIPLE_CONSTRAINTS),
|
||||
backend_impl=('jax', 'c'),
|
||||
impl=('jax', 'c'),
|
||||
)
|
||||
def test_put_model(self, xml, backend_impl):
|
||||
def test_put_model(self, xml, impl):
|
||||
m = mujoco.MjModel.from_xml_string(xml)
|
||||
mx = mjx.put_model(m, backend_impl=backend_impl)
|
||||
mx = mjx.put_model(m, impl=impl)
|
||||
|
||||
def assert_not_weak_type(x):
|
||||
if isinstance(x, jax.Array):
|
||||
@@ -140,10 +141,10 @@ class ModelIOTest(parameterized.TestCase):
|
||||
self.assertEqual(mx.nM, m.nM)
|
||||
self.assertAlmostEqual(mx.opt.timestep, m.opt.timestep)
|
||||
|
||||
if backend_impl == 'jax':
|
||||
if impl == 'jax':
|
||||
# fields restricted to MuJoCo should not be populated
|
||||
self.assertFalse(hasattr(mx, 'bvh_aabb'))
|
||||
elif backend_impl == 'c':
|
||||
elif impl == 'c':
|
||||
# Options specific to C are populated.
|
||||
self.assertEqual(mx.opt.apirate, m.opt.apirate)
|
||||
# Fields private to C backend impl are populated.
|
||||
@@ -177,7 +178,7 @@ class ModelIOTest(parameterized.TestCase):
|
||||
mujoco.MjModel.from_xml_string(
|
||||
'<mujoco><option viscosity="3.0"/><worldbody/></mujoco>'
|
||||
),
|
||||
backend_impl='jax',
|
||||
impl='jax',
|
||||
)
|
||||
self.assertTrue(m.opt.has_fluid_params)
|
||||
|
||||
@@ -218,7 +219,7 @@ class ModelIOTest(parameterized.TestCase):
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>"""),
|
||||
backend_impl='jax',
|
||||
impl='jax',
|
||||
)
|
||||
|
||||
def test_implicitfast_fluid_not_implemented(self):
|
||||
@@ -229,18 +230,18 @@ class ModelIOTest(parameterized.TestCase):
|
||||
<option viscosity="3.0" integrator="implicitfast"/>
|
||||
<worldbody/>
|
||||
</mujoco>"""),
|
||||
backend_impl='jax',
|
||||
impl='jax',
|
||||
)
|
||||
|
||||
def test_wrap_inside(self):
|
||||
m = test_util.load_test_file('tendon/wrap_sidesite.xml')
|
||||
mx0 = mjx.put_model(m, backend_impl='jax')
|
||||
mx0 = mjx.put_model(m, impl='jax')
|
||||
np.testing.assert_equal(
|
||||
mx0._impl.is_wrap_inside,
|
||||
np.array([1, 0, 1, 0, 1, 1, 0]),
|
||||
)
|
||||
m.site_pos[2] = m.site_pos[1]
|
||||
mx1 = mjx.put_model(m, backend_impl='jax')
|
||||
mx1 = mjx.put_model(m, impl='jax')
|
||||
np.testing.assert_equal(
|
||||
mx1._impl.is_wrap_inside,
|
||||
np.array([0, 0, 1, 0, 1, 0, 0]),
|
||||
@@ -251,10 +252,10 @@ class DataIOTest(parameterized.TestCase):
|
||||
"""IO tests for mjx.Data."""
|
||||
|
||||
@parameterized.parameters('jax', 'c')
|
||||
def test_make_data(self, backend_impl: str):
|
||||
def test_make_data(self, impl: str):
|
||||
"""Test that make_data returns the correct shapes."""
|
||||
m = mujoco.MjModel.from_xml_string(_MULTIPLE_CONVEX_OBJECTS)
|
||||
d = mjx.make_data(m, backend_impl=backend_impl)
|
||||
d = mjx.make_data(m, impl=impl)
|
||||
|
||||
nq = 22
|
||||
nbody = 5
|
||||
@@ -312,34 +313,34 @@ class DataIOTest(parameterized.TestCase):
|
||||
self.assertEqual(d.qfrc_inverse.shape, (nv,))
|
||||
self.assertEqual(d._impl.efc_force.shape, (nefc,))
|
||||
|
||||
if backend_impl == 'jax':
|
||||
if impl == 'jax':
|
||||
self.assertEqual(d._impl.qM.shape, (nv, nv))
|
||||
self.assertEqual(d._impl.qLD.shape, (nv, nv))
|
||||
self.assertEqual(d._impl.qLDiagInv.shape, (0,))
|
||||
elif backend_impl == 'c':
|
||||
elif impl == 'c':
|
||||
self.assertEqual(d._impl.qM.shape, (nm,))
|
||||
self.assertEqual(d._impl.qLD.shape, (nm,))
|
||||
self.assertEqual(d._impl.qLDiagInv.shape, (nv,))
|
||||
|
||||
# test sparse
|
||||
m.opt.jacobian = mujoco.mjtJacobian.mjJAC_SPARSE
|
||||
d = mjx.make_data(m, backend_impl=backend_impl)
|
||||
d = mjx.make_data(m, impl=impl)
|
||||
self.assertEqual(d._impl.qM.shape, (nm,))
|
||||
self.assertEqual(d._impl.qLD.shape, (nm,))
|
||||
self.assertEqual(d._impl.qLDiagInv.shape, (nv,))
|
||||
|
||||
if backend_impl == 'c':
|
||||
if impl == 'c':
|
||||
# check C specific fields
|
||||
self.assertEqual(d._impl.light_xpos.shape, (m.nlight, 3))
|
||||
self.assertEqual(d._impl.bvh_active.shape, (m.nbvh,))
|
||||
|
||||
@parameterized.parameters('jax', 'c')
|
||||
def test_put_data(self, backend_impl: str):
|
||||
def test_put_data(self, impl: str):
|
||||
"""Test that put_data puts the correct data for dense and sparse."""
|
||||
m = mujoco.MjModel.from_xml_string(_MULTIPLE_CONSTRAINTS)
|
||||
d = mujoco.MjData(m)
|
||||
mujoco.mj_step(m, d, 2)
|
||||
dx = mjx.put_data(m, d, backend_impl=backend_impl)
|
||||
dx = mjx.put_data(m, d, impl=impl)
|
||||
|
||||
# check a few fields
|
||||
np.testing.assert_allclose(dx.qpos, d.qpos)
|
||||
@@ -356,12 +357,12 @@ class DataIOTest(parameterized.TestCase):
|
||||
)
|
||||
)
|
||||
|
||||
if backend_impl == 'jax':
|
||||
if impl == 'jax':
|
||||
# check that qM is transformed properly
|
||||
qm = np.zeros((m.nv, m.nv), dtype=np.float64)
|
||||
mujoco.mj_fullM(m, qm, d.qM)
|
||||
np.testing.assert_allclose(qm, mjx.full_m(mjx.put_model(m), dx))
|
||||
elif backend_impl == 'c':
|
||||
elif impl == 'c':
|
||||
np.testing.assert_allclose(dx._impl.qM, d.qM)
|
||||
np.testing.assert_allclose(dx._impl.qLD, d.qLD)
|
||||
np.testing.assert_allclose(dx._impl.qLDiagInv, d.qLDiagInv)
|
||||
@@ -417,7 +418,7 @@ class DataIOTest(parameterized.TestCase):
|
||||
m.opt.jacobian = mujoco.mjtJacobian.mjJAC_SPARSE
|
||||
d = mujoco.MjData(m)
|
||||
mujoco.mj_step(m, d, 2)
|
||||
dx_sparse = mjx.put_data(m, d, backend_impl=backend_impl)
|
||||
dx_sparse = mjx.put_data(m, d, impl=impl)
|
||||
np.testing.assert_allclose(dx_sparse._impl.efc_J, dx._impl.efc_J, atol=1e-8)
|
||||
|
||||
# check sparse mass matrices are correct
|
||||
@@ -431,25 +432,25 @@ class DataIOTest(parameterized.TestCase):
|
||||
m.opt.jacobian = mujoco.mjtJacobian.mjJAC_DENSE
|
||||
d = mujoco.MjData(m)
|
||||
mujoco.mj_step(m, d, 2)
|
||||
dx_from_dense = mjx.put_data(m, d, backend_impl=backend_impl)
|
||||
if backend_impl == 'jax':
|
||||
dx_from_dense = mjx.put_data(m, d, impl=impl)
|
||||
if impl == 'jax':
|
||||
qm = np.zeros((m.nv, m.nv))
|
||||
mujoco.mj_fullM(m, qm, d.qM)
|
||||
np.testing.assert_allclose(dx_from_dense._impl.qM, qm, atol=1e-8)
|
||||
elif backend_impl == 'c':
|
||||
elif impl == 'c':
|
||||
np.testing.assert_allclose(dx_from_dense._impl.qM, d.qM, atol=1e-8)
|
||||
|
||||
@parameterized.parameters(
|
||||
('jax', False), ('jax', True), ('c', False), ('c', True)
|
||||
)
|
||||
def test_get_data(self, backend_impl: str, sparse: bool):
|
||||
def test_get_data(self, impl: str, sparse: bool):
|
||||
"""Test that get_data makes correct MjData."""
|
||||
m = mujoco.MjModel.from_xml_string(_MULTIPLE_CONSTRAINTS)
|
||||
if sparse:
|
||||
m.opt.jacobian = mujoco.mjtJacobian.mjJAC_SPARSE
|
||||
d = mujoco.MjData(m)
|
||||
mujoco.mj_step(m, d, 2)
|
||||
dx = mjx.put_data(m, d, backend_impl=backend_impl)
|
||||
dx = mjx.put_data(m, d, impl=impl)
|
||||
d_2: mujoco.MjData = mjx.get_data(m, dx)
|
||||
|
||||
# check a few fields
|
||||
@@ -505,7 +506,7 @@ class DataIOTest(parameterized.TestCase):
|
||||
np.testing.assert_allclose(d_2.efc_aref, d.efc_aref)
|
||||
np.testing.assert_allclose(d_2.contact.efc_address, d.contact.efc_address)
|
||||
|
||||
if backend_impl == 'c':
|
||||
if impl == 'c':
|
||||
# check fields specific to the C implementation
|
||||
np.testing.assert_allclose(d_2.bvh_active, d.bvh_active)
|
||||
|
||||
@@ -540,13 +541,13 @@ class DataIOTest(parameterized.TestCase):
|
||||
mjx.get_data(m, dx)
|
||||
|
||||
@parameterized.parameters('jax', 'c')
|
||||
def test_get_data_batched(self, backend_impl):
|
||||
def test_get_data_batched(self, impl):
|
||||
"""Test that get_data makes correct List[MjData] for batched Data."""
|
||||
|
||||
m = mujoco.MjModel.from_xml_string(_MULTIPLE_CONSTRAINTS)
|
||||
d = mujoco.MjData(m)
|
||||
mujoco.mj_step(m, d, 2)
|
||||
dx = mjx.put_data(m, d, backend_impl=backend_impl)
|
||||
dx = mjx.put_data(m, d, impl=impl)
|
||||
# second data in batch has contact dist > 0, disables contact
|
||||
dx_b = jax.tree_util.tree_map(lambda x: jp.stack((x, x + 0.05)), dx)
|
||||
ds = mjx.get_data(m, dx_b)
|
||||
@@ -557,13 +558,13 @@ class DataIOTest(parameterized.TestCase):
|
||||
self.assertEqual(ds[1].ncon, 0)
|
||||
|
||||
@parameterized.parameters('jax', 'c')
|
||||
def test_get_data_into(self, backend_impl):
|
||||
def test_get_data_into(self, impl):
|
||||
"""Test that get_data_into correctly populates an MjData."""
|
||||
|
||||
m = mujoco.MjModel.from_xml_string(_MULTIPLE_CONSTRAINTS)
|
||||
d = mujoco.MjData(m)
|
||||
mujoco.mj_step(m, d, 2)
|
||||
dx = mjx.put_data(m, d, backend_impl=backend_impl)
|
||||
dx = mjx.put_data(m, d, impl=impl)
|
||||
d_2 = mujoco.MjData(m)
|
||||
mjx.get_data_into(d_2, m, dx)
|
||||
|
||||
@@ -580,32 +581,32 @@ class DataIOTest(parameterized.TestCase):
|
||||
np.testing.assert_allclose(d_2.contact.frame, d.contact.frame)
|
||||
|
||||
@parameterized.parameters('jax', 'c')
|
||||
def test_get_data_into_wrong_shape(self, backend_impl):
|
||||
def test_get_data_into_wrong_shape(self, impl):
|
||||
"""Tests that get_data_into throwsif input and output shapes don't match."""
|
||||
|
||||
m = mujoco.MjModel.from_xml_string(_MULTIPLE_CONSTRAINTS)
|
||||
d = mujoco.MjData(m)
|
||||
mujoco.mj_step(m, d, 2)
|
||||
dx = mjx.put_data(m, d, backend_impl=backend_impl)
|
||||
dx = mjx.put_data(m, d, impl=impl)
|
||||
m_2 = mujoco.MjModel.from_xml_string(_MULTIPLE_CONVEX_OBJECTS)
|
||||
d_2 = mujoco.MjData(m_2)
|
||||
with self.assertRaisesRegex(ValueError, r'Input field.*has shape.*'):
|
||||
mjx.get_data_into(d_2, m, dx)
|
||||
|
||||
@parameterized.parameters('jax', 'c')
|
||||
def test_make_matches_put(self, backend_impl):
|
||||
def test_make_matches_put(self, impl):
|
||||
"""Test that make_data produces a pytree that matches put_data."""
|
||||
m = mujoco.MjModel.from_xml_string(_MULTIPLE_CONSTRAINTS)
|
||||
d = mujoco.MjData(m)
|
||||
mujoco.mj_step(m, d, 2)
|
||||
dx = mjx.put_data(m, d, backend_impl=backend_impl)
|
||||
dx = mjx.put_data(m, d, impl=impl)
|
||||
|
||||
step_fn = lambda d: d.replace(time=d.time + 1)
|
||||
step_fn_jit = jax.jit(step_fn).lower(dx).compile()
|
||||
|
||||
# placing an MjData onto device should yield the same treedef mjx.Data as
|
||||
# calling make_data. they should be interchangeable for jax functions:
|
||||
step_fn_jit(mjx.make_data(m, backend_impl=backend_impl))
|
||||
step_fn_jit(mjx.make_data(m, impl=impl))
|
||||
|
||||
def test_contact_elliptic_condim1(self):
|
||||
"""Test that condim=1 with ConeType.ELLIPTIC is not implemented."""
|
||||
@@ -624,37 +625,24 @@ class DataIOTest(parameterized.TestCase):
|
||||
with self.assertRaises(NotImplementedError):
|
||||
mjx.make_data(m)
|
||||
|
||||
@parameterized.product(
|
||||
sensor=['accelerometer', 'force', 'torque'], equality=['connect', 'weld']
|
||||
)
|
||||
def test_sensor_constraint_compatibility(self, sensor, equality):
|
||||
"""Test unsupported sensor and equality constraint combinations."""
|
||||
equality_constraint = f'{equality} body1="body1" body2="body2"'
|
||||
if equality == 'connect':
|
||||
equality_constraint += ' anchor="0 0 0"'
|
||||
m = mujoco.MjModel.from_xml_string(f"""
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<body name="body1">
|
||||
<freejoint/>
|
||||
<geom size="0.1"/>
|
||||
<site name="site1"/>
|
||||
</body>
|
||||
<body name="body2">
|
||||
<freejoint/>
|
||||
<geom size="0.1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
<equality>
|
||||
<{equality_constraint}/>
|
||||
</equality>
|
||||
<sensor>
|
||||
<{sensor} site="site1"/>
|
||||
</sensor>
|
||||
</mujoco>
|
||||
""")
|
||||
with self.assertRaises(NotImplementedError):
|
||||
mjx.put_model(m, backend_impl='jax')
|
||||
@parameterized.parameters(JacobianType.DENSE, JacobianType.SPARSE)
|
||||
def test_qm_mapm2m(self, jacobian):
|
||||
"""Test that qM is mapped to M."""
|
||||
m = test_util.load_test_file('humanoid/humanoid.xml')
|
||||
m.opt.jacobian = jacobian
|
||||
d = mujoco.MjData(m)
|
||||
mx = mjx.put_model(m, impl='jax')
|
||||
dx = mjx.make_data(m, impl='jax')
|
||||
dx = mjx.forward(mx, dx)
|
||||
|
||||
mjx.get_data_into(d, m, dx)
|
||||
|
||||
res_mj = np.zeros((1, m.nv))
|
||||
mujoco.mj_solveM(m, d, res_mj, np.ones((1, m.nv)))
|
||||
|
||||
res = mjx._src.smooth.solve_m(mx, dx, jp.ones(m.nv))
|
||||
|
||||
np.testing.assert_allclose(res_mj[0], res, rtol=1e-3, atol=1e-3)
|
||||
|
||||
|
||||
class FullCompatTest(parameterized.TestCase):
|
||||
@@ -678,71 +666,71 @@ class FullCompatTest(parameterized.TestCase):
|
||||
m = mujoco.MjModel.from_xml_string(xml)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
out = mjx_io.put_model(m, _full_compat=True)
|
||||
self.assertEqual(out.backend_impl, BackendImpl.C)
|
||||
self.assertEqual(out.impl, Impl.C)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
out = mjx_io.make_data(m, _full_compat=True)
|
||||
self.assertEqual(out.backend_impl, BackendImpl.C)
|
||||
self.assertEqual(out.impl, Impl.C)
|
||||
|
||||
|
||||
# Test cases for `_resolve_backend_impl_and_device` where the device is
|
||||
# Test cases for `_resolve_impl_and_device` where the device is
|
||||
# specified by the user and the device is available.
|
||||
_DEVICE_TEST_CASES = [
|
||||
# Arguments use the following format:
|
||||
# (device_type_str, backend_impl_str,
|
||||
# (expected_device, expected_backend_impl)))
|
||||
# (device_type_str, impl_str,
|
||||
# (expected_device, expected_impl)))
|
||||
# No backend specified.
|
||||
('cpu', None, ('cpu', BackendImpl.C)),
|
||||
('gpu-notnvidia', None, ('gpu', BackendImpl.JAX)),
|
||||
('gpu-nvidia', None, ('gpu', BackendImpl.WARP)),
|
||||
('tpu', None, ('tpu', BackendImpl.JAX)),
|
||||
('cpu', None, ('cpu', Impl.C)),
|
||||
('gpu-notnvidia', None, ('gpu', Impl.JAX)),
|
||||
('gpu-nvidia', None, ('gpu', Impl.WARP)),
|
||||
('tpu', None, ('tpu', Impl.JAX)),
|
||||
# JAX backend specified.
|
||||
('cpu', 'jax', ('cpu', BackendImpl.JAX)),
|
||||
('gpu-notnvidia', 'jax', ('gpu', BackendImpl.JAX)),
|
||||
('gpu-nvidia', 'jax', ('gpu', BackendImpl.JAX)),
|
||||
('tpu', 'jax', ('tpu', BackendImpl.JAX)),
|
||||
('cpu', 'jax', ('cpu', Impl.JAX)),
|
||||
('gpu-notnvidia', 'jax', ('gpu', Impl.JAX)),
|
||||
('gpu-nvidia', 'jax', ('gpu', Impl.JAX)),
|
||||
('tpu', 'jax', ('tpu', Impl.JAX)),
|
||||
# WARP backend specified.
|
||||
('cpu', 'warp', ('cpu', 'error')),
|
||||
('gpu-notnvidia', 'warp', ('cpu', 'error')),
|
||||
('gpu-nvidia', 'warp', ('gpu', BackendImpl.WARP)),
|
||||
('gpu-nvidia', 'warp', ('gpu', Impl.WARP)),
|
||||
('tpu', 'warp', ('tpu', 'error')),
|
||||
# C backend specified.
|
||||
('cpu', 'c', ('cpu', BackendImpl.C)),
|
||||
('cpu', 'c', ('cpu', Impl.C)),
|
||||
('gpu-notnvidia', 'c', ('cpu', 'error')),
|
||||
('gpu-nvidia', 'c', ('cpu', 'error')),
|
||||
('tpu', 'c', ('tpu', 'error')),
|
||||
]
|
||||
|
||||
# Test cases for `_resolve_backend_impl_and_device` where the user does NOT
|
||||
# Test cases for `_resolve_impl_and_device` where the user does NOT
|
||||
# specify a device. We mock the JAX default device.
|
||||
_DEFAULT_DEVICE_TEST_CASES = [
|
||||
# Arguments use the following format:
|
||||
# (jax.default_device, backend_impl_str,
|
||||
# (expected_device, expected_backend_impl))
|
||||
# (jax.default_device, impl_str,
|
||||
# (expected_device, expected_impl))
|
||||
# No backend impl specified.
|
||||
('cpu', None, ('cpu', BackendImpl.C)),
|
||||
('gpu-notnvidia', None, ('gpu', BackendImpl.JAX)),
|
||||
('gpu-nvidia', None, ('gpu', BackendImpl.WARP)),
|
||||
('tpu', None, ('tpu', BackendImpl.JAX)),
|
||||
('cpu', None, ('cpu', Impl.C)),
|
||||
('gpu-notnvidia', None, ('gpu', Impl.JAX)),
|
||||
('gpu-nvidia', None, ('gpu', Impl.WARP)),
|
||||
('tpu', None, ('tpu', Impl.JAX)),
|
||||
# JAX backend impl specified.
|
||||
('cpu', 'jax', ('cpu', BackendImpl.JAX)),
|
||||
('gpu-notnvidia', 'jax', ('gpu', BackendImpl.JAX)),
|
||||
('gpu-nvidia', 'jax', ('gpu', BackendImpl.JAX)),
|
||||
('tpu', 'jax', ('tpu', BackendImpl.JAX)),
|
||||
('cpu', 'jax', ('cpu', Impl.JAX)),
|
||||
('gpu-notnvidia', 'jax', ('gpu', Impl.JAX)),
|
||||
('gpu-nvidia', 'jax', ('gpu', Impl.JAX)),
|
||||
('tpu', 'jax', ('tpu', Impl.JAX)),
|
||||
# WARP backend impl specified.
|
||||
('cpu', 'warp', ('cpu', 'error')),
|
||||
('gpu-notnvidia', 'warp', ('cpu', 'error')),
|
||||
('gpu-nvidia', 'warp', ('gpu', BackendImpl.WARP)),
|
||||
('gpu-nvidia', 'warp', ('gpu', Impl.WARP)),
|
||||
('tpu', 'warp', ('tpu', 'error')),
|
||||
# C backend impl specified, CPU should always be available.
|
||||
('cpu', 'c', ('cpu', BackendImpl.C)),
|
||||
('gpu-notnvidia', 'c', ('cpu', BackendImpl.C)),
|
||||
('gpu-nvidia', 'c', ('cpu', BackendImpl.C)),
|
||||
('tpu', 'c', ('cpu', BackendImpl.C)),
|
||||
('cpu', 'c', ('cpu', Impl.C)),
|
||||
('gpu-notnvidia', 'c', ('cpu', Impl.C)),
|
||||
('gpu-nvidia', 'c', ('cpu', Impl.C)),
|
||||
('tpu', 'c', ('cpu', Impl.C)),
|
||||
]
|
||||
|
||||
|
||||
class ResolveBackendImplAndDeviceTest(parameterized.TestCase):
|
||||
"""Tests for the _resolve_backend_impl_and_device function."""
|
||||
class ResolveImplAndDeviceTest(parameterized.TestCase):
|
||||
"""Tests for the _resolve_impl_and_device function."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
@@ -783,7 +771,7 @@ class ResolveBackendImplAndDeviceTest(parameterized.TestCase):
|
||||
def test_resolve_with_device(
|
||||
self,
|
||||
device_type_str,
|
||||
backend_impl_str,
|
||||
impl_str,
|
||||
expected,
|
||||
):
|
||||
"""Tests various combinations of device and backend impls."""
|
||||
@@ -811,21 +799,21 @@ class ResolveBackendImplAndDeviceTest(parameterized.TestCase):
|
||||
|
||||
self.mock_jax_devices.side_effect = devices_side_effect
|
||||
|
||||
expected_device, expected_backend_impl = expected
|
||||
if expected_backend_impl == 'error':
|
||||
expected_device, expected_impl = expected
|
||||
if expected_impl == 'error':
|
||||
with self.assertRaises(AssertionError):
|
||||
mjx_io._resolve_backend_impl_and_device(
|
||||
backend_impl=backend_impl_str, device=input_device
|
||||
mjx_io._resolve_impl_and_device(
|
||||
impl=impl_str, device=input_device
|
||||
)
|
||||
return
|
||||
|
||||
actual_backend_impl, actual_device = (
|
||||
mjx_io._resolve_backend_impl_and_device(
|
||||
backend_impl=backend_impl_str, device=input_device
|
||||
actual_impl, actual_device = (
|
||||
mjx_io._resolve_impl_and_device(
|
||||
impl=impl_str, device=input_device
|
||||
)
|
||||
)
|
||||
|
||||
self.assertEqual(actual_backend_impl, expected_backend_impl)
|
||||
self.assertEqual(actual_impl, expected_impl)
|
||||
self.assertIsNotNone(actual_device)
|
||||
self.assertEqual(actual_device.platform, expected_device)
|
||||
|
||||
@@ -839,7 +827,7 @@ class ResolveBackendImplAndDeviceTest(parameterized.TestCase):
|
||||
def test_resolve_without_device(
|
||||
self,
|
||||
default_device_str,
|
||||
backend_impl_str,
|
||||
impl_str,
|
||||
expected,
|
||||
):
|
||||
"""Tests various combinations of jax.default_device and backend impls."""
|
||||
@@ -878,32 +866,32 @@ class ResolveBackendImplAndDeviceTest(parameterized.TestCase):
|
||||
lambda: default_device_side_effect_str
|
||||
)
|
||||
|
||||
expected_device, expected_backend_impl = expected
|
||||
expected_device, expected_impl = expected
|
||||
if (
|
||||
expected_backend_impl == 'error'
|
||||
expected_impl == 'error'
|
||||
and default_device_str != 'gpu-nvidia'
|
||||
and backend_impl_str == 'warp'
|
||||
and impl_str == 'warp'
|
||||
):
|
||||
with self.assertRaisesRegex(RuntimeError, 'cuda backend not supported'):
|
||||
mjx_io._resolve_backend_impl_and_device(
|
||||
backend_impl=backend_impl_str, device=None
|
||||
mjx_io._resolve_impl_and_device(
|
||||
impl=impl_str, device=None
|
||||
)
|
||||
return
|
||||
|
||||
if expected_backend_impl == 'error':
|
||||
if expected_impl == 'error':
|
||||
with self.assertRaises(AssertionError):
|
||||
mjx_io._resolve_backend_impl_and_device(
|
||||
backend_impl=backend_impl_str, device=None
|
||||
mjx_io._resolve_impl_and_device(
|
||||
impl=impl_str, device=None
|
||||
)
|
||||
return
|
||||
|
||||
actual_backend_impl, actual_device = (
|
||||
mjx_io._resolve_backend_impl_and_device(
|
||||
backend_impl=backend_impl_str, device=None
|
||||
actual_impl, actual_device = (
|
||||
mjx_io._resolve_impl_and_device(
|
||||
impl=impl_str, device=None
|
||||
)
|
||||
)
|
||||
|
||||
self.assertEqual(actual_backend_impl, expected_backend_impl)
|
||||
self.assertEqual(actual_impl, expected_impl)
|
||||
self.assertIsNotNone(actual_device)
|
||||
self.assertEqual(actual_device.platform, expected_device)
|
||||
|
||||
@@ -918,26 +906,26 @@ class ResolveBackendImplAndDeviceTest(parameterized.TestCase):
|
||||
self.mock_default_backend.side_effect = lambda: 'gpu'
|
||||
|
||||
# Default to JAX instead of WARP on NVIDIA GPU.
|
||||
backend_impl, device = mjx_io._resolve_backend_impl_and_device(
|
||||
backend_impl=None, device=None
|
||||
impl, device = mjx_io._resolve_impl_and_device(
|
||||
impl=None, device=None
|
||||
)
|
||||
self.assertEqual(backend_impl, BackendImpl.JAX)
|
||||
self.assertEqual(impl, Impl.JAX)
|
||||
self.assertEqual(device.platform, 'gpu')
|
||||
|
||||
# Specifying an NVIDIA GPU should still choose JAX.
|
||||
backend_impl, device = mjx_io._resolve_backend_impl_and_device(
|
||||
backend_impl=None, device=self.mock_nvidia_gpu
|
||||
impl, device = mjx_io._resolve_impl_and_device(
|
||||
impl=None, device=self.mock_nvidia_gpu
|
||||
)
|
||||
self.assertEqual(backend_impl, BackendImpl.JAX)
|
||||
self.assertEqual(impl, Impl.JAX)
|
||||
self.assertEqual(device.platform, 'gpu')
|
||||
|
||||
# Requesting warp explicitly should fail since it is disabled.
|
||||
with self.assertRaises(AssertionError):
|
||||
mjx_io._resolve_backend_impl_and_device(
|
||||
backend_impl='warp', device=self.mock_nvidia_gpu
|
||||
mjx_io._resolve_impl_and_device(
|
||||
impl='warp', device=self.mock_nvidia_gpu
|
||||
)
|
||||
with self.assertRaises(AssertionError):
|
||||
mjx_io._resolve_backend_impl_and_device(backend_impl='warp', device=None)
|
||||
mjx_io._resolve_impl_and_device(impl='warp', device=None)
|
||||
|
||||
@mock.patch.dict(os.environ, {'MJX_C_DEFAULT_ENABLED': 'false'})
|
||||
def test_resolve_c_disabled(self):
|
||||
@@ -950,30 +938,30 @@ class ResolveBackendImplAndDeviceTest(parameterized.TestCase):
|
||||
self.mock_default_backend.side_effect = lambda: 'cpu'
|
||||
|
||||
# Default to JAX instead of C on CPU.
|
||||
backend_impl, device = mjx_io._resolve_backend_impl_and_device(
|
||||
backend_impl=None, device=None
|
||||
impl, device = mjx_io._resolve_impl_and_device(
|
||||
impl=None, device=None
|
||||
)
|
||||
self.assertEqual(backend_impl, BackendImpl.JAX)
|
||||
self.assertEqual(impl, Impl.JAX)
|
||||
self.assertEqual(device.platform, 'cpu')
|
||||
|
||||
# Specifing CPU should still choose JAX.
|
||||
backend_impl, device = mjx_io._resolve_backend_impl_and_device(
|
||||
backend_impl=None, device=self.mock_cpu
|
||||
impl, device = mjx_io._resolve_impl_and_device(
|
||||
impl=None, device=self.mock_cpu
|
||||
)
|
||||
self.assertEqual(backend_impl, BackendImpl.JAX)
|
||||
self.assertEqual(impl, Impl.JAX)
|
||||
self.assertEqual(device.platform, 'cpu')
|
||||
|
||||
# Specifying C should choose C!
|
||||
backend_impl, device = mjx_io._resolve_backend_impl_and_device(
|
||||
backend_impl='c', device=None
|
||||
impl, device = mjx_io._resolve_impl_and_device(
|
||||
impl='c', device=None
|
||||
)
|
||||
self.assertEqual(backend_impl, BackendImpl.C)
|
||||
self.assertEqual(impl, Impl.C)
|
||||
self.assertEqual(device.platform, 'cpu')
|
||||
|
||||
backend_impl, device = mjx_io._resolve_backend_impl_and_device(
|
||||
backend_impl='c', device=self.mock_cpu
|
||||
impl, device = mjx_io._resolve_impl_and_device(
|
||||
impl='c', device=self.mock_cpu
|
||||
)
|
||||
self.assertEqual(backend_impl, BackendImpl.C)
|
||||
self.assertEqual(impl, Impl.C)
|
||||
self.assertEqual(device.platform, 'cpu')
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ from mujoco.mjx._src import math
|
||||
from mujoco.mjx._src import ray
|
||||
from mujoco.mjx._src import smooth
|
||||
from mujoco.mjx._src import support
|
||||
from mujoco.mjx._src.types import BackendImpl
|
||||
from mujoco.mjx._src.types import Impl
|
||||
from mujoco.mjx._src.types import Data
|
||||
from mujoco.mjx._src.types import DataJAX
|
||||
from mujoco.mjx._src.types import DisableBit
|
||||
|
||||
@@ -29,6 +29,7 @@ from mujoco.mjx._src.types import EqType
|
||||
from mujoco.mjx._src.types import JointType
|
||||
from mujoco.mjx._src.types import Model
|
||||
from mujoco.mjx._src.types import ModelJAX
|
||||
from mujoco.mjx._src.types import ObjType
|
||||
from mujoco.mjx._src.types import TrnType
|
||||
from mujoco.mjx._src.types import WrapType
|
||||
# pylint: enable=g-importing-member
|
||||
@@ -659,11 +660,126 @@ def rne_postconstraint(m: Model, d: Data) -> Data:
|
||||
cfrc_contact.reshape((-1, 6))
|
||||
)
|
||||
|
||||
# TODO(taylorhowell): connect and weld constraints
|
||||
if np.any(m.eq_type == EqType.CONNECT):
|
||||
raise NotImplementedError('Connect constraints are not implemented.')
|
||||
if np.any(m.eq_type == EqType.WELD):
|
||||
raise NotImplementedError('Weld constraints are not implemented.')
|
||||
# cfrc_ext += connect, weld
|
||||
cfrc_ext_equality = []
|
||||
cfrc_ext_equality_adr = []
|
||||
|
||||
connect_id = m.eq_type == EqType.CONNECT
|
||||
nconnect = connect_id.sum()
|
||||
|
||||
if nconnect:
|
||||
cfrc_connect_force = d._impl.efc_force[: 3 * nconnect].reshape(
|
||||
(nconnect, 3)
|
||||
)
|
||||
|
||||
is_site = m.eq_objtype == ObjType.SITE
|
||||
body1id = np.copy(m.eq_obj1id)
|
||||
body2id = np.copy(m.eq_obj2id)
|
||||
pos1 = m.eq_data[:, :3]
|
||||
pos2 = m.eq_data[:, 3:6]
|
||||
|
||||
if m.nsite:
|
||||
body1id[is_site] = m.site_bodyid[m.eq_obj1id[is_site]]
|
||||
body2id[is_site] = m.site_bodyid[m.eq_obj2id[is_site]]
|
||||
pos1 = jp.where(is_site[:, None], m.site_pos[m.eq_obj1id], pos1)
|
||||
pos2 = jp.where(is_site[:, None], m.site_pos[m.eq_obj2id], pos2)
|
||||
|
||||
# body 1
|
||||
k1_connect = body1id[connect_id]
|
||||
k1_connect_mask = k1_connect != 0
|
||||
offset1_connect = pos1[connect_id]
|
||||
|
||||
pos1_connect = jax.vmap(lambda pnt, mat, vec: mat @ pnt + vec)(
|
||||
offset1_connect, d.xmat[k1_connect], d.xpos[k1_connect]
|
||||
)
|
||||
subtree_com1_connect = d.subtree_com[jp.array(m.body_rootid)[k1_connect]]
|
||||
cfrc_com1_connect = jax.vmap(
|
||||
lambda dif, frc, mask: mask * jp.concatenate([-jp.cross(dif, frc), frc])
|
||||
)(subtree_com1_connect - pos1_connect, cfrc_connect_force, k1_connect_mask)
|
||||
|
||||
# body 2
|
||||
k2_connect = body2id[connect_id]
|
||||
k2_connect_mask = -1 * (k2_connect != 0)
|
||||
offset2_connect = pos2[connect_id]
|
||||
|
||||
pos2_connect = jax.vmap(lambda pnt, mat, vec: mat @ pnt + vec)(
|
||||
offset2_connect, d.xmat[k2_connect], d.xpos[k2_connect]
|
||||
)
|
||||
subtree_com2_connect = d.subtree_com[jp.array(m.body_rootid)[k2_connect]]
|
||||
cfrc_com2_connect = jax.vmap(
|
||||
lambda dif, frc, mask: mask * jp.concatenate([-jp.cross(dif, frc), frc])
|
||||
)(subtree_com2_connect - pos2_connect, cfrc_connect_force, k2_connect_mask)
|
||||
|
||||
cfrc_ext_equality.append(jp.vstack([cfrc_com1_connect, cfrc_com2_connect]))
|
||||
cfrc_ext_equality_adr.append(jp.concatenate([k1_connect, k2_connect]))
|
||||
|
||||
weld_id = m.eq_type == EqType.WELD
|
||||
nweld = weld_id.sum()
|
||||
|
||||
if nweld:
|
||||
cfrc_weld = d._impl.efc_force[
|
||||
3 * nconnect : 3 * nconnect + 6 * nweld
|
||||
].reshape((nweld, 6))
|
||||
cfrc_weld_force = cfrc_weld[:, :3]
|
||||
cfrc_weld_torque = cfrc_weld[:, 3:]
|
||||
|
||||
is_site = m.eq_objtype == ObjType.SITE
|
||||
body1id = np.copy(m.eq_obj1id)
|
||||
body2id = np.copy(m.eq_obj2id)
|
||||
pos1 = m.eq_data[:, 3:6]
|
||||
pos2 = m.eq_data[:, :3]
|
||||
|
||||
if m.nsite:
|
||||
body1id[is_site] = m.site_bodyid[m.eq_obj1id[is_site]]
|
||||
body2id[is_site] = m.site_bodyid[m.eq_obj2id[is_site]]
|
||||
pos1 = jp.where(is_site[:, None], m.site_pos[m.eq_obj1id], pos1)
|
||||
pos2 = jp.where(is_site[:, None], m.site_pos[m.eq_obj2id], pos2)
|
||||
|
||||
# body 1
|
||||
k1_weld = body1id[weld_id]
|
||||
k1_weld_mask = k1_weld != 0
|
||||
offset1_weld = pos1[weld_id]
|
||||
|
||||
pos1_weld = jax.vmap(lambda pnt, mat, vec: mat @ pnt + vec)(
|
||||
offset1_weld, d.xmat[k1_weld], d.xpos[k1_weld]
|
||||
)
|
||||
subtree_com1_weld = d.subtree_com[jp.array(m.body_rootid)[k1_weld]]
|
||||
cfrc_com1_weld = jax.vmap(
|
||||
lambda dif, frc, trq, mask: mask
|
||||
* jp.concatenate([trq - jp.cross(dif, frc), frc])
|
||||
)(
|
||||
subtree_com1_weld - pos1_weld,
|
||||
cfrc_weld_force,
|
||||
cfrc_weld_torque,
|
||||
k1_weld_mask,
|
||||
)
|
||||
|
||||
# body 2
|
||||
k2_weld = body2id[weld_id]
|
||||
k2_weld_mask = -1 * (k2_weld != 0)
|
||||
offset2_weld = pos2[weld_id]
|
||||
|
||||
pos2_weld = jax.vmap(lambda pnt, mat, vec: mat @ pnt + vec)(
|
||||
offset2_weld, d.xmat[k2_weld], d.xpos[k2_weld]
|
||||
)
|
||||
subtree_com2_weld = d.subtree_com[jp.array(m.body_rootid)[k2_weld]]
|
||||
cfrc_com2_weld = jax.vmap(
|
||||
lambda dif, frc, trq, mask: mask
|
||||
* jp.concatenate([trq - jp.cross(dif, frc), frc])
|
||||
)(
|
||||
subtree_com2_weld - pos2_weld,
|
||||
cfrc_weld_force,
|
||||
cfrc_weld_torque,
|
||||
k2_weld_mask,
|
||||
)
|
||||
|
||||
cfrc_ext_equality.append(jp.vstack([cfrc_com1_weld, cfrc_com2_weld]))
|
||||
cfrc_ext_equality_adr.append(jp.concatenate([k1_weld, k2_weld]))
|
||||
|
||||
if nconnect or nweld:
|
||||
cfrc_ext = cfrc_ext.at[jp.concatenate(cfrc_ext_equality_adr)].add(
|
||||
jp.vstack(cfrc_ext_equality)
|
||||
)
|
||||
|
||||
# forward pass over bodies: compute cacc, cfrc_int
|
||||
def _forward(carry, cfrc_ext, cinert, cvel, body_dofadr, body_dofnum):
|
||||
@@ -1184,3 +1300,158 @@ def transmission(m: Model, d: Data) -> Data:
|
||||
{'_impl.actuator_length': length, '_impl.actuator_moment': moment}
|
||||
)
|
||||
return d
|
||||
|
||||
|
||||
def tendon_armature(m: Model, d: Data) -> Data:
|
||||
"""Add tendon armature to qM."""
|
||||
if not isinstance(m._impl, ModelJAX) or not isinstance(d._impl, DataJAX):
|
||||
raise ValueError('tendon_armature requires JAX backend implementation.')
|
||||
|
||||
if not m.ntendon:
|
||||
return d
|
||||
|
||||
# TODO(taylorhowell): if sparse, compute sparse JTAJ
|
||||
JTAJ = d._impl.ten_J.T @ jax.vmap(jp.multiply)(
|
||||
d._impl.ten_J, m.tendon_armature
|
||||
)
|
||||
|
||||
if support.is_sparse(m):
|
||||
ij = []
|
||||
for i in range(m.nv):
|
||||
j = i
|
||||
while j > -1:
|
||||
ij.append((i, j))
|
||||
j = m.dof_parentid[j]
|
||||
|
||||
i, j = (jp.array(x) for x in zip(*ij))
|
||||
JTAJ = JTAJ[(i, j)]
|
||||
|
||||
return d.tree_replace({'_impl.qM': d._impl.qM + JTAJ})
|
||||
|
||||
|
||||
def tendon_dot(m: Model, d: Data) -> jax.Array:
|
||||
"""Compute time derivative of dense tendon Jacobian for one tendon."""
|
||||
if not isinstance(m._impl, ModelJAX) or not isinstance(d._impl, DataJAX):
|
||||
raise ValueError('tendon_dot requires JAX backend implementation.')
|
||||
|
||||
ten_Jdot = jp.zeros((m.ntendon, m.nv)) # pylint: disable=invalid-name
|
||||
|
||||
if not m.ntendon:
|
||||
return ten_Jdot
|
||||
|
||||
# process pulleys
|
||||
(wrap_id_pulley,) = np.nonzero(m.wrap_type == WrapType.PULLEY)
|
||||
|
||||
divisor = np.ones(m.nwrap)
|
||||
for adr, num in zip(m.tendon_adr, m.tendon_num):
|
||||
for id_pulley in wrap_id_pulley:
|
||||
if adr <= id_pulley < adr + num:
|
||||
divisor[id_pulley : adr + num] = np.maximum(
|
||||
mujoco.mjMINVAL, m.wrap_prm[id_pulley]
|
||||
)
|
||||
|
||||
# process spatial tendon sites
|
||||
(wrap_id_site,) = np.nonzero(m.wrap_type == WrapType.SITE)
|
||||
|
||||
# find consecutive sites, skipping tendon transitions
|
||||
(pair_id,) = np.nonzero(np.diff(wrap_id_site) == 1)
|
||||
wrap_id_site_pair = np.setdiff1d(wrap_id_site[pair_id], m.tendon_adr[1:] - 1)
|
||||
wrap_objid_site0 = m.wrap_objid[wrap_id_site_pair]
|
||||
wrap_objid_site1 = m.wrap_objid[wrap_id_site_pair + 1]
|
||||
site_bodyid0 = m.site_bodyid[wrap_objid_site0]
|
||||
site_bodyid1 = m.site_bodyid[wrap_objid_site1]
|
||||
site_xpos0 = d.site_xpos[wrap_objid_site0]
|
||||
site_xpos1 = d.site_xpos[wrap_objid_site1]
|
||||
subtree_com0 = d.subtree_com[m.body_rootid[site_bodyid0]]
|
||||
subtree_com1 = d.subtree_com[m.body_rootid[site_bodyid1]]
|
||||
site_vel0 = jax.vmap(lambda a, b: a[3:] - jp.cross(b, a[:3]))(
|
||||
d.cvel[site_bodyid0], site_xpos0 - subtree_com0
|
||||
)
|
||||
site_vel1 = jax.vmap(lambda a, b: a[3:] - jp.cross(b, a[:3]))(
|
||||
d.cvel[site_bodyid1], site_xpos1 - subtree_com1
|
||||
)
|
||||
|
||||
@jax.vmap
|
||||
def _momentdot(wpnt0, wpnt1, wvel0, wvel1, body0, body1):
|
||||
# dpnt = 3D position difference, normalize
|
||||
dpnt = wpnt1 - wpnt0
|
||||
norm = math.norm(dpnt)
|
||||
dpnt = jp.where(
|
||||
norm < mujoco.mjMINVAL, jp.array([1.0, 0.0, 0.0]), dpnt / norm
|
||||
)
|
||||
|
||||
# dvel = d / dt(dpnt)
|
||||
dvel = wvel1 - wvel0
|
||||
dot = jp.dot(dpnt, dvel)
|
||||
dvel += dpnt * -dot
|
||||
dvel = jp.where(norm > mujoco.mjMINVAL, dvel / norm, 0.0)
|
||||
|
||||
# get endpoint JacobianDots, subtract
|
||||
jacp1, _ = support.jac_dot(m, d, wpnt0, body0)
|
||||
jacp2, _ = support.jac_dot(m, d, wpnt1, body1)
|
||||
jacdif = jacp2 - jacp1
|
||||
|
||||
# chain rule, first term: Jdot += d / dt(jac2 - jac1) * dpnt
|
||||
tmp0 = jacdif @ dpnt
|
||||
|
||||
# get endpoint Jacobians, subtract
|
||||
jacp1, _ = support.jac(m, d, wpnt0, body0)
|
||||
jacp2, _ = support.jac(m, d, wpnt1, body1)
|
||||
jacdif = jacp2 - jacp1
|
||||
|
||||
# chain rule, second term: Jdot += (jac2 - jac1) * d/dt (dpnt)
|
||||
tmp1 = jacdif @ dvel
|
||||
|
||||
return jp.where(body0 != body1, tmp0 + tmp1, jp.zeros(m.nv))
|
||||
|
||||
momentdots = _momentdot(
|
||||
site_xpos0,
|
||||
site_xpos1,
|
||||
site_vel0,
|
||||
site_vel1,
|
||||
site_bodyid0,
|
||||
site_bodyid1,
|
||||
)
|
||||
|
||||
if wrap_id_site_pair.size:
|
||||
divisor_site_pair = divisor[wrap_id_site_pair]
|
||||
momentdots /= divisor_site_pair[:, None]
|
||||
|
||||
tendon_nsite = np.array([
|
||||
sum((wrap_id_site_pair >= adr) & (wrap_id_site_pair < adr + num))
|
||||
for adr, num in zip(m.tendon_adr, m.tendon_num)
|
||||
])
|
||||
tendon_has_site = tendon_nsite > 0
|
||||
(tendon_id_site,) = np.nonzero(tendon_has_site)
|
||||
tendon_nsite = tendon_nsite[tendon_has_site]
|
||||
tendon_with_site = tendon_nsite.size
|
||||
ten_site_id = np.repeat(np.arange(tendon_with_site), tendon_nsite)
|
||||
|
||||
momentdot = jax.ops.segment_sum(momentdots, ten_site_id, tendon_with_site)
|
||||
ten_Jdot = ten_Jdot.at[tendon_id_site].set(momentdot) # pylint: disable=invalid-name
|
||||
|
||||
# TODO(taylorhowell): time derivatives for geoms
|
||||
|
||||
return ten_Jdot
|
||||
|
||||
|
||||
def tendon_bias(m: Model, d: Data) -> Data:
|
||||
"""Add bias force due to tendon armature."""
|
||||
if not isinstance(m._impl, ModelJAX) or not isinstance(d._impl, DataJAX):
|
||||
raise ValueError('tendon_bias requires JAX backend implementation.')
|
||||
|
||||
if not m.ntendon:
|
||||
return d
|
||||
|
||||
# get dense d/dt(tendon Jacobian) for each tendon
|
||||
ten_Jdot = tendon_dot(m, d) # pylint: disable=invalid-name
|
||||
|
||||
# add bias term: qfrc += ten_J * armature * ten_Jdot @ qvel
|
||||
coef = m.tendon_armature * jp.dot(ten_Jdot, d.qvel)
|
||||
|
||||
return d.tree_replace({
|
||||
'qfrc_bias': (
|
||||
d.qfrc_bias
|
||||
+ jp.sum(jax.vmap(jp.multiply)(d._impl.ten_J, coef), axis=0)
|
||||
)
|
||||
})
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
from absl.testing import absltest
|
||||
from absl.testing import parameterized
|
||||
import jax
|
||||
from jax import numpy as jp
|
||||
import mujoco
|
||||
from mujoco import mjx
|
||||
from mujoco.mjx._src import test_util
|
||||
from mujoco.mjx._src.types import ConeType # pylint: disable=g-importing-member
|
||||
from mujoco.mjx._src.types import JacobianType # pylint: disable=g-importing-member
|
||||
import numpy as np
|
||||
|
||||
# tolerance for difference between MuJoCo and MJX smooth calculations - mostly
|
||||
@@ -228,21 +230,98 @@ class SmoothTest(absltest.TestCase):
|
||||
|
||||
|
||||
class RnePostConstraintTest(parameterized.TestCase):
|
||||
_CONNECT_SITE = """
|
||||
<equality>
|
||||
<connect site1="site1" site2="site2"/>
|
||||
</equality>
|
||||
"""
|
||||
_CONNECT_BODY = """
|
||||
<equality>
|
||||
<connect body1="body1" body2="body2" anchor="1 2 3"/>
|
||||
</equality>
|
||||
"""
|
||||
_WELD_SITE = """
|
||||
<equality>
|
||||
<weld site1="site1" site2="site2"/>
|
||||
</equality>
|
||||
"""
|
||||
_WELD_BODY = """
|
||||
<equality>
|
||||
<weld body1="body1" body2="body2"/>
|
||||
</equality>
|
||||
"""
|
||||
_CONNECT_SITE_WELD_SITE = """
|
||||
<equality>
|
||||
<connect site1="site1" site2="site2"/>
|
||||
<weld site1="site1" site2="site2"/>
|
||||
</equality>
|
||||
"""
|
||||
_WELD_SITE_CONNECT_SITE = """
|
||||
<equality>
|
||||
<weld site1="site1" site2="site2"/>
|
||||
<connect site1="site1" site2="site2"/>
|
||||
</equality>
|
||||
"""
|
||||
_WELD_SITE_CONNECT_SITE_WELD_BODY = """
|
||||
<equality>
|
||||
<weld site1="site1" site2="site2"/>
|
||||
<connect site1="site1" site2="site2"/>
|
||||
<weld body1="body1" body2="body2"/>
|
||||
</equality>
|
||||
"""
|
||||
_CONNECT_SITE_WELD_SITE_WELD_BODY = """
|
||||
<equality>
|
||||
<connect site1="site1" site2="site2"/>
|
||||
<weld site1="site1" site2="site2"/>
|
||||
<weld body1="body1" body2="body2"/>
|
||||
</equality>
|
||||
"""
|
||||
_CONNECT_SITE_CONNECT_BODY_CONNECT_WELD = """
|
||||
<equality>
|
||||
<connect site1="site1" site2="site2"/>
|
||||
<connect body1="body1" body2="body2" anchor="1 2 3"/>
|
||||
<weld body1="body1" body2="body2"/>
|
||||
</equality>
|
||||
"""
|
||||
|
||||
@parameterized.parameters(ConeType)
|
||||
def test_rnepostconstraint(self, cone_type):
|
||||
@parameterized.parameters(
|
||||
('', ConeType.PYRAMIDAL, None),
|
||||
('', ConeType.ELLIPTIC, None),
|
||||
(_CONNECT_SITE, ConeType.PYRAMIDAL, None),
|
||||
(_CONNECT_BODY, ConeType.PYRAMIDAL, None),
|
||||
(_WELD_SITE, ConeType.PYRAMIDAL, None),
|
||||
(_WELD_BODY, ConeType.PYRAMIDAL, None),
|
||||
(_CONNECT_SITE_WELD_SITE, ConeType.PYRAMIDAL, None),
|
||||
(
|
||||
_WELD_SITE_CONNECT_SITE,
|
||||
ConeType.PYRAMIDAL,
|
||||
np.array([6, 7, 8, 0, 1, 2, 3, 4, 5]),
|
||||
),
|
||||
(
|
||||
_WELD_SITE_CONNECT_SITE_WELD_BODY,
|
||||
ConeType.PYRAMIDAL,
|
||||
np.array([6, 7, 8, 0, 1, 2, 3, 4, 5]),
|
||||
),
|
||||
(_CONNECT_SITE_WELD_SITE_WELD_BODY, ConeType.PYRAMIDAL, None),
|
||||
(_CONNECT_SITE_CONNECT_BODY_CONNECT_WELD, ConeType.PYRAMIDAL, None),
|
||||
)
|
||||
def test_rnepostconstraint(self, equality, cone_type, efc_map):
|
||||
"""Tests MJX rne_postconstraint function to match MuJoCo mj_rnePostConstraint."""
|
||||
|
||||
m = mujoco.MjModel.from_xml_string("""
|
||||
m = mujoco.MjModel.from_xml_string(f"""
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<geom name="floor" size="10 10 .05" type="plane"/>
|
||||
<body pos="0 0 1">
|
||||
<site name="site1"/>
|
||||
<body name="body1">
|
||||
</body>
|
||||
<body pos="0 0 1" name="body2">
|
||||
<joint type="ball" damping="1"/>
|
||||
<geom type="capsule" size="0.1 0.5" fromto="0 0 0 0.5 0 0" condim="1"/>
|
||||
<body pos="0.5 0 0">
|
||||
<joint type="ball" damping="1"/>
|
||||
<geom type="capsule" size="0.1 0.5" fromto="0 0 0 0.5 0 0" condim="3"/>
|
||||
<site name="site2"/>
|
||||
</body>
|
||||
</body>
|
||||
<body pos="0 1 1">
|
||||
@@ -254,6 +333,7 @@ class RnePostConstraintTest(parameterized.TestCase):
|
||||
</body>
|
||||
</body>
|
||||
</worldbody>
|
||||
{equality}
|
||||
<keyframe>
|
||||
<key qpos='0.424577 0.450592 0.451703 -0.642391 0.729379 0.545151 0.407756 0.0674697 0.424577 1.450592 0.451703 -0.642391 0.729379 0.545151 0.407756 0.0674697'/>
|
||||
</keyframe>
|
||||
@@ -271,6 +351,11 @@ class RnePostConstraintTest(parameterized.TestCase):
|
||||
mx = mjx.put_model(m)
|
||||
dx = mjx.put_data(m, d)
|
||||
|
||||
if efc_map is not None:
|
||||
efc_force = d.efc_force.copy()
|
||||
efc_force[: len(efc_map)] = d.efc_force[efc_map]
|
||||
dx = dx.tree_replace({'_impl.efc_force': jp.array(efc_force)})
|
||||
|
||||
# rne postconstraint
|
||||
mujoco.mj_rnePostConstraint(m, d)
|
||||
dx = jax.jit(mjx.rne_postconstraint)(mx, dx)
|
||||
@@ -316,6 +401,36 @@ class TendonTest(parameterized.TestCase):
|
||||
_assert_eq(d.wrap_obj, dx._impl.wrap_obj, 'wrap_obj')
|
||||
_assert_eq(d.wrap_xpos, dx._impl.wrap_xpos, 'wrap_xpos')
|
||||
|
||||
@parameterized.parameters(JacobianType.DENSE, JacobianType.SPARSE)
|
||||
def test_tendon_armature(self, jacobian):
|
||||
"""Tests MJX tendon armature matches MuJoCo."""
|
||||
m = test_util.load_test_file('tendon/armature.xml')
|
||||
m.opt.jacobian = jacobian
|
||||
d = mujoco.MjData(m)
|
||||
mujoco.mj_resetDataKeyframe(m, d, 0)
|
||||
mujoco.mj_forward(m, d)
|
||||
|
||||
mx = mjx.put_model(m)
|
||||
dx = mjx.put_data(m, d)
|
||||
|
||||
dx = dx.tree_replace(
|
||||
{'_impl.qM': jp.zeros((m.nv, m.nv)), 'qfrc_bias': jp.zeros(m.nv)}
|
||||
)
|
||||
|
||||
dx = mjx.crb(mx, dx)
|
||||
dx = mjx.tendon_armature(mx, dx)
|
||||
|
||||
if jacobian == JacobianType.DENSE:
|
||||
qM = np.zeros((m.nv, m.nv)) # pylint: disable=invalid-name
|
||||
mujoco.mj_fullM(m, qM, d.qM)
|
||||
else:
|
||||
qM = d.qM # pylint: disable=invalid-name
|
||||
_assert_eq(dx._impl.qM, qM, 'qM')
|
||||
|
||||
dx = mjx.rne(mx, dx)
|
||||
dx = mjx.tendon_bias(mx, dx)
|
||||
_assert_eq(dx.qfrc_bias, d.qfrc_bias, 'qfrc_bias')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
absltest.main()
|
||||
|
||||
@@ -403,7 +403,9 @@ def _update_gradient(m: Model, d: Data, ctx: Context) -> Context:
|
||||
else:
|
||||
h = (d._impl.efc_J.T * d._impl.efc_D * ctx.active) @ d._impl.efc_J
|
||||
h = support.full_m(m, d) + h
|
||||
h_ = jax.scipy.linalg.cho_factor(h)
|
||||
# Symmetrize to reduce the chance of numerical issues in cholesky.
|
||||
h_sym = (h + h.T) * 0.5
|
||||
h_ = jax.scipy.linalg.cho_factor(h_sym)
|
||||
mgrad = jax.scipy.linalg.cho_solve(h_, grad)
|
||||
else:
|
||||
raise NotImplementedError(f'unsupported solver type: {m.opt.solver}')
|
||||
|
||||
@@ -142,6 +142,7 @@ def jac(
|
||||
m: Model, d: Data, point: jax.Array, body_id: jax.Array
|
||||
) -> Tuple[jax.Array, jax.Array]:
|
||||
"""Compute pair of (NV, 3) Jacobians of global point attached to body."""
|
||||
# TODO(taylorhowell): statically construct mask
|
||||
fn = lambda carry, b: b if carry is None else b + carry
|
||||
mask = (jp.arange(m.nbody) == body_id) * 1
|
||||
mask = scan.body_tree(m, fn, 'b', 'b', mask, reverse=True)
|
||||
@@ -155,6 +156,42 @@ def jac(
|
||||
return jacp, jacr
|
||||
|
||||
|
||||
def jac_dot(
|
||||
m: Model, d: Data, point: jax.Array, body_id: jax.Array
|
||||
) -> Tuple[jax.Array, jax.Array]:
|
||||
"""Compute pair of (NV, 3) Jacobian time derivatives of global point attached to body."""
|
||||
# TODO(taylorhowell): statically construct mask
|
||||
fn = lambda carry, b: b if carry is None else b + carry
|
||||
mask = (jp.arange(m.nbody) == body_id) * 1
|
||||
mask = scan.body_tree(m, fn, 'b', 'b', mask, reverse=True)
|
||||
mask = mask[jp.array(m.dof_bodyid)] > 0
|
||||
|
||||
offset = point - d.subtree_com[jp.array(m.body_rootid)[body_id]]
|
||||
pvel_lin = d.cvel[body_id][3:] - jp.cross(offset, d.cvel[body_id][:3])
|
||||
|
||||
cdof = d._impl.cdof
|
||||
cdof_dot = d._impl.cdof_dot
|
||||
|
||||
# check for quaternion
|
||||
jnt_type = m.jnt_type[m.dof_jntid]
|
||||
dof_adr = m.jnt_dofadr[m.dof_jntid]
|
||||
is_quat = (jnt_type == JointType.BALL) | (
|
||||
jnt_type == JointType.FREE & (np.arange(m.nv) >= dof_adr + 3)
|
||||
)
|
||||
|
||||
# compute cdof_dot for quaternion (use current body cvel)
|
||||
cdof_dot_quat = jax.vmap(math.motion_cross)(d.cvel[m.dof_bodyid], cdof)
|
||||
cdof_dot = jp.where(is_quat[:, None], cdof_dot_quat, cdof_dot)
|
||||
|
||||
jacp = jax.vmap(
|
||||
lambda a, b: a[3:] + jp.cross(a[:3], offset) + jp.cross(b[:3], pvel_lin)
|
||||
)(cdof_dot, cdof)
|
||||
jacp = jax.vmap(jp.multiply)(jacp, mask)
|
||||
jacr = jax.vmap(jp.multiply)(cdof_dot[:, :3], mask) # pytype: disable=attribute-error
|
||||
|
||||
return jacp, jacr
|
||||
|
||||
|
||||
def apply_ft(
|
||||
m: Model,
|
||||
d: Data,
|
||||
|
||||
@@ -379,6 +379,19 @@ class SupportTest(parameterized.TestCase):
|
||||
' 15297169659434471387 != 2785811613804955188',
|
||||
)
|
||||
|
||||
# what happens when we bind to an actuator that was removed?
|
||||
bygone_actuators = []
|
||||
for act in s.actuators:
|
||||
bygone_actuators.append(act)
|
||||
s.delete(act)
|
||||
m = s.compile()
|
||||
d = mujoco.MjData(m)
|
||||
mx = mjx.put_model(m)
|
||||
dx = mjx.put_data(m, d)
|
||||
dx = mjx.step(mx, dx)
|
||||
with self.assertRaisesRegex(KeyError, 'invalid id: -1'):
|
||||
dx.bind(mx, bygone_actuators)
|
||||
|
||||
_CONTACTS = """
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
|
||||
@@ -24,8 +24,8 @@ from mujoco.mjx._src.dataclasses import PyTreeNode # pylint: disable=g-importin
|
||||
import numpy as np
|
||||
|
||||
|
||||
class BackendImpl(enum.Enum):
|
||||
"""Backend implementation to use."""
|
||||
class Impl(enum.Enum):
|
||||
"""Implementation to use."""
|
||||
|
||||
C = 'c'
|
||||
JAX = 'jax'
|
||||
@@ -34,7 +34,7 @@ class BackendImpl(enum.Enum):
|
||||
@classmethod
|
||||
def _missing_(cls, value):
|
||||
# This method is called only when lookup by value fails
|
||||
# (e.g., BackendImpl('JAX') fails initially because 'JAX' != 'jax')
|
||||
# (e.g., Impl('JAX') fails initially because 'JAX' != 'jax')
|
||||
if not isinstance(value, str):
|
||||
return None
|
||||
for member in cls:
|
||||
@@ -871,10 +871,10 @@ class Model(PyTreeNode):
|
||||
_impl: Union[ModelC, ModelJAX]
|
||||
|
||||
@property
|
||||
def backend_impl(self) -> BackendImpl:
|
||||
def impl(self) -> Impl:
|
||||
return {
|
||||
ModelC: BackendImpl.C,
|
||||
ModelJAX: BackendImpl.JAX,
|
||||
ModelC: Impl.C,
|
||||
ModelJAX: Impl.JAX,
|
||||
}[type(self._impl)]
|
||||
|
||||
def __getattr__(self, name: str):
|
||||
@@ -1119,10 +1119,10 @@ class Data(PyTreeNode):
|
||||
_impl: Union[DataC, DataJAX]
|
||||
|
||||
@property
|
||||
def backend_impl(self) -> BackendImpl:
|
||||
def impl(self) -> Impl:
|
||||
return {
|
||||
DataC: BackendImpl.C,
|
||||
DataJAX: BackendImpl.JAX,
|
||||
DataC: Impl.C,
|
||||
DataJAX: Impl.JAX,
|
||||
}[type(self._impl)]
|
||||
|
||||
def __getattr__(self, name: str):
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<site name="site0" pos="1 0 1"/>
|
||||
<body>
|
||||
<joint type="slide" axis="0 0 1"/>
|
||||
<joint type="hinge" axis="0 1 0"/>
|
||||
<geom type="box" size="0.1 0.1 0.1" mass="1" pos="1 0 0"/>
|
||||
<site name="site1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
<tendon>
|
||||
<spatial armature="123">
|
||||
<site site="site0"/>
|
||||
<site site="site1"/>
|
||||
</spatial>
|
||||
<spatial armature="456">
|
||||
<site site="site0"/>
|
||||
<site site="site1"/>
|
||||
</spatial>
|
||||
</tendon>
|
||||
<keyframe>
|
||||
<key qpos="1.2345 1.2345" qvel="1.2345 1.2345"/>
|
||||
</keyframe>
|
||||
</mujoco>
|
||||
+4
-4
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name="mujoco-mjx"
|
||||
version = "3.3.3"
|
||||
version = "3.3.4"
|
||||
authors = [
|
||||
{name = "Google DeepMind", email = "mujoco@deepmind.com"},
|
||||
]
|
||||
@@ -30,7 +30,7 @@ dependencies = [
|
||||
"etils[epath]",
|
||||
"jax",
|
||||
"jaxlib",
|
||||
"mujoco>=3.3.3.dev0",
|
||||
"mujoco>=3.3.4.dev0",
|
||||
"scipy",
|
||||
"trimesh",
|
||||
]
|
||||
@@ -41,9 +41,9 @@ 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.3.3"
|
||||
Documentation = "https://mujoco.readthedocs.io/en/3.3.4"
|
||||
Repository = "https://github.com/google-deepmind/mujoco/tree/main/mjx"
|
||||
Changelog = "https://mujoco.readthedocs.io/en/3.3.3/changelog.html"
|
||||
Changelog = "https://mujoco.readthedocs.io/en/3.3.4/changelog.html"
|
||||
|
||||
[tool.isort]
|
||||
force_single_line = true
|
||||
|
||||
@@ -22,6 +22,12 @@
|
||||
|
||||
<statistic center="0 -.3 1" extent="2.5"/>
|
||||
|
||||
<asset>
|
||||
<texture name="texcyl" type="2d" builtin="checker" rgb1=".3 .3 .3" rgb2=".15 0.15 0.15"
|
||||
width="512" height="512" mark="cross" markrgb=".22 .22 .22"/>
|
||||
<material name="matcyl" reflectance="0.3" texture="texcyl" texrepeat="3 3" texuniform="true"/>
|
||||
</asset>
|
||||
|
||||
<worldbody>
|
||||
<flexcomp name="cable" type="circle" count="40 1 1" spacing=".15 1 1" dim="1"
|
||||
radius="0.02" pos="0 0 1" rgba="1 0 0 1">
|
||||
@@ -30,12 +36,12 @@
|
||||
<body name="left" pos="-.7 0 1">
|
||||
<joint name="expand_left" type="slide" axis="-1 0 0" range="0 2" damping="20"/>
|
||||
<joint name="rotate" type="hinge" axis="0 0 1"/>
|
||||
<geom type="cylinder" size=".2 .2" density="1"/>
|
||||
<geom type="cylinder" size=".2 .2" density="1" material="matcyl"/>
|
||||
</body>
|
||||
<body name="right" pos=".7 0 1">
|
||||
<joint name="expand_right" type="slide" axis="1 0 0" range="0 2" damping="20"/>
|
||||
<joint type="hinge" axis="0 0 1"/>
|
||||
<geom type="cylinder" size=".2 .2" density="1"/>
|
||||
<geom type="cylinder" size=".2 .2" density="1" material="matcyl"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<mujoco>
|
||||
<compiler texturedir="asset"/>
|
||||
|
||||
<asset>
|
||||
<texture name="texspot" type="2d" file="spot.png"/>
|
||||
<material name="matspot" texture="texspot"/>
|
||||
<mesh name="spot" file="asset/spot.obj"/>
|
||||
</asset>
|
||||
|
||||
<option sdf_iterations="20" sdf_initpoints="40"/>
|
||||
|
||||
<visual>
|
||||
<map force="1000"/>
|
||||
</visual>
|
||||
|
||||
<default>
|
||||
<geom solref="0.01 1" solimp=".95 .99 .0001" friction="0.5"/>
|
||||
</default>
|
||||
|
||||
<statistic meansize="0.2"/>
|
||||
|
||||
<include file="scene.xml"/>
|
||||
|
||||
<worldbody>
|
||||
<body euler="90 0 0" pos="0 0 .7">
|
||||
<geom type="sdf" name="cow1" mesh="spot" material="matspot"/>
|
||||
</body>
|
||||
<light name="left" pos="0 0 1"/>
|
||||
<light name="right" pos="1 0 1"/>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
@@ -213,14 +213,21 @@ TouchStress::TouchStress(const mjModel* m, mjData* d, int instance,
|
||||
|
||||
// Get parent weld id.
|
||||
int site_id = m->sensor_objid[id_];
|
||||
int parent_body = m->body_weldid[m->site_bodyid[site_id]];
|
||||
int parent_body = m->site_bodyid[site_id];
|
||||
parent_weld_ = m->body_weldid[parent_body];
|
||||
|
||||
// Get geom id.
|
||||
if (m->body_geomnum[parent_body] != 1) {
|
||||
mju_error("Touch sensor must be attached to a body with exactly one geom");
|
||||
int collision_geoms = 0;
|
||||
for (int i = 0; i < m->body_geomnum[parent_body]; ++i) {
|
||||
int geom_id = m->body_geomadr[parent_body]+i;
|
||||
if (m->geom_contype[geom_id] || m->geom_conaffinity[geom_id]) {
|
||||
collision_geoms++;
|
||||
geom_id_ = geom_id;
|
||||
}
|
||||
}
|
||||
if (collision_geoms == 0) {
|
||||
mju_error("Touch sensor requires a body with at least one collision geom");
|
||||
}
|
||||
geom_id_ = m->body_geomadr[parent_body];
|
||||
|
||||
// Create bin edges.
|
||||
x_edges_.assign(size[0] + 1, 0);
|
||||
@@ -236,7 +243,7 @@ TouchStress::TouchStress(const mjModel* m, mjData* d, int instance,
|
||||
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] = m->geom_size[3*geom_id_];
|
||||
aer[2] = m->geom_rbound[geom_id_];
|
||||
SphericalToCartesian(aer, pos_.data() + 3 * (i * size[1] + j));
|
||||
dist_[i*size[1]+j] = mju_abs(aer[2]);
|
||||
TangentFrame(aer, mat_.data() + 9 * (i * size[1] + j));
|
||||
@@ -302,6 +309,11 @@ void TouchStress::Compute(const mjModel* m, mjData* d, int instance) {
|
||||
geomtype[0] = (mjtGeom)m->geom_type[geom];
|
||||
}
|
||||
|
||||
// Skip mesh geoms.
|
||||
if (geomtype[0] == mjGEOM_MESH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set SDF parameters.
|
||||
mjSDF geom_sdf;
|
||||
geom_sdf.id = &sdf_instance[0];
|
||||
|
||||
+6
-6
@@ -1827,7 +1827,7 @@
|
||||
"\n",
|
||||
"# Remove all bodies in the list from the spec\n",
|
||||
"for body in delete_list:\n",
|
||||
" spec.detach_body(body)\n",
|
||||
" spec.delete(body)\n",
|
||||
"\n",
|
||||
"# # Add another humanoid\n",
|
||||
"spec_humanoid = mj.MjSpec.from_file(humanoid_file)\n",
|
||||
@@ -1900,8 +1900,8 @@
|
||||
"shoulder_right = torso.add_frame(pos=arm_right.pos)\n",
|
||||
"\n",
|
||||
"# Remove the arms\n",
|
||||
"spec.detach_body(arm_left)\n",
|
||||
"spec.detach_body(arm_right)\n",
|
||||
"spec.delete(arm_left)\n",
|
||||
"spec.delete(arm_right)\n",
|
||||
"\n",
|
||||
"# Add new legs\n",
|
||||
"shoulder_left.attach_body(leg_left, 'shoulder', 'left')\n",
|
||||
@@ -1942,7 +1942,7 @@
|
||||
"arm_right = spec.body('upper_arm_right')\n",
|
||||
"torso = spec.body('torso')\n",
|
||||
"shoulder_right = torso.add_frame(pos=arm_right.pos, quat=[0, 0.8509035, 0, 0.525322])\n",
|
||||
"spec.detach_body(arm_right)\n",
|
||||
"spec.delete(arm_right)\n",
|
||||
"\n",
|
||||
"# Attach Franka arm to humanoid\n",
|
||||
"franka_arm = franka.body('fr3_link2')\n",
|
||||
@@ -2000,7 +2000,7 @@
|
||||
"\n",
|
||||
"# Delete all key frames to avoid name conflicts\n",
|
||||
"while humanoid.keys:\n",
|
||||
" humanoid.keys[-1].delete()\n",
|
||||
" humanoid.delete(keys[-1])\n",
|
||||
"\n",
|
||||
"# Create a grid of humanoids by attaching humanoid to spec multiple times\n",
|
||||
"for i in range(4):\n",
|
||||
@@ -2335,7 +2335,7 @@
|
||||
"fly = mj.MjSpec.from_file(fly_file)\n",
|
||||
"# Remove lights from fly so they are not duplicated in line-up\n",
|
||||
"for light in fly.lights:\n",
|
||||
" light.delete()\n",
|
||||
" fly.delete(light)\n",
|
||||
"\n",
|
||||
"small_fly = scale_spec(fly, 1.25)\n",
|
||||
"large_fly = scale_spec(fly, 2)\n",
|
||||
|
||||
@@ -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.3.3.dylib
|
||||
${MUJOCO_FRAMEWORK}/mujoco.framework/Versions/A/libmujoco.3.3.4.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.3.3 HINTS ${MUJOCO_LIBRARY_DIR} REQUIRED
|
||||
MUJOCO_LIBRARY mujoco mujoco.3.3.4 HINTS ${MUJOCO_LIBRARY_DIR} REQUIRED
|
||||
)
|
||||
find_path(MUJOCO_INCLUDE mujoco/mujoco.h HINTS ${MUJOCO_INCLUDE_DIR} REQUIRED)
|
||||
message("MuJoCo is at ${MUJOCO_LIBRARY}")
|
||||
@@ -140,7 +140,7 @@ findorfetch(
|
||||
GIT_REPO
|
||||
https://github.com/abseil/abseil-cpp
|
||||
GIT_TAG
|
||||
d9e4955c65cd4367dd6bf46f4ccb8cd3d100540b # LTS 20250127.1
|
||||
bc257a88f7c1939f24e0379f14a3589e926c950c # LTS 20250512.0
|
||||
TARGETS
|
||||
${MUJOCO_PYTHON_ABSL_TARGETS}
|
||||
EXCLUDE_FROM_ALL
|
||||
@@ -173,7 +173,7 @@ findorfetch(
|
||||
GIT_REPO
|
||||
https://gitlab.com/libeigen/eigen
|
||||
GIT_TAG
|
||||
464c1d097891a1462ab28bf8bb763c1683883892
|
||||
d0b490ee091629068e0c11953419eb089f9e6bb2
|
||||
TARGETS
|
||||
Eigen3::Eigen
|
||||
EXCLUDE_FROM_ALL
|
||||
|
||||
@@ -8987,46 +8987,6 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
|
||||
),
|
||||
doc='Attach child to a parent, return the attached element if success or NULL otherwise.', # pylint: disable=line-too-long
|
||||
)),
|
||||
('mjs_detachBody',
|
||||
FunctionDecl(
|
||||
name='mjs_detachBody',
|
||||
return_type=ValueType(name='int'),
|
||||
parameters=(
|
||||
FunctionParameterDecl(
|
||||
name='s',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjSpec'),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='b',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjsBody'),
|
||||
),
|
||||
),
|
||||
),
|
||||
doc='Delete body and descendants from mjSpec, remove all references, return 0 on success.', # pylint: disable=line-too-long
|
||||
)),
|
||||
('mjs_detachDefault',
|
||||
FunctionDecl(
|
||||
name='mjs_detachDefault',
|
||||
return_type=ValueType(name='int'),
|
||||
parameters=(
|
||||
FunctionParameterDecl(
|
||||
name='s',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjSpec'),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='d',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjsDefault'),
|
||||
),
|
||||
),
|
||||
),
|
||||
doc='Delete default class and descendants from mjSpec, remove all references, return 0 on success.', # pylint: disable=line-too-long
|
||||
)),
|
||||
('mjs_addBody',
|
||||
FunctionDecl(
|
||||
name='mjs_addBody',
|
||||
@@ -9202,6 +9162,12 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
|
||||
name='mjs_delete',
|
||||
return_type=ValueType(name='int'),
|
||||
parameters=(
|
||||
FunctionParameterDecl(
|
||||
name='spec',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjSpec'),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='element',
|
||||
type=PointerType(
|
||||
@@ -9209,7 +9175,7 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
|
||||
),
|
||||
),
|
||||
),
|
||||
doc='Delete object corresponding to the given element, return 0 on success.', # pylint: disable=line-too-long
|
||||
doc='Remove object corresponding to the given element, return 0 on success.', # pylint: disable=line-too-long
|
||||
)),
|
||||
('mjs_addActuator',
|
||||
FunctionDecl(
|
||||
@@ -9551,6 +9517,266 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
|
||||
),
|
||||
doc='Add default.',
|
||||
)),
|
||||
('mjs_setToMotor',
|
||||
FunctionDecl(
|
||||
name='mjs_setToMotor',
|
||||
return_type=PointerType(
|
||||
inner_type=ValueType(name='char', is_const=True),
|
||||
),
|
||||
parameters=(
|
||||
FunctionParameterDecl(
|
||||
name='actuator',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjsActuator'),
|
||||
),
|
||||
),
|
||||
),
|
||||
doc='Set actuator to motor, return error if any.',
|
||||
)),
|
||||
('mjs_setToPosition',
|
||||
FunctionDecl(
|
||||
name='mjs_setToPosition',
|
||||
return_type=PointerType(
|
||||
inner_type=ValueType(name='char', is_const=True),
|
||||
),
|
||||
parameters=(
|
||||
FunctionParameterDecl(
|
||||
name='actuator',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjsActuator'),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='kp',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='kv',
|
||||
type=ArrayType(
|
||||
inner_type=ValueType(name='double'),
|
||||
extents=(1,),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='dampratio',
|
||||
type=ArrayType(
|
||||
inner_type=ValueType(name='double'),
|
||||
extents=(1,),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='timeconst',
|
||||
type=ArrayType(
|
||||
inner_type=ValueType(name='double'),
|
||||
extents=(1,),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='inheritrange',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
),
|
||||
doc='Set actuator to position, return error if any.',
|
||||
)),
|
||||
('mjs_setToIntVelocity',
|
||||
FunctionDecl(
|
||||
name='mjs_setToIntVelocity',
|
||||
return_type=PointerType(
|
||||
inner_type=ValueType(name='char', is_const=True),
|
||||
),
|
||||
parameters=(
|
||||
FunctionParameterDecl(
|
||||
name='actuator',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjsActuator'),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='kp',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='kv',
|
||||
type=ArrayType(
|
||||
inner_type=ValueType(name='double'),
|
||||
extents=(1,),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='dampratio',
|
||||
type=ArrayType(
|
||||
inner_type=ValueType(name='double'),
|
||||
extents=(1,),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='timeconst',
|
||||
type=ArrayType(
|
||||
inner_type=ValueType(name='double'),
|
||||
extents=(1,),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='inheritrange',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
),
|
||||
doc='Set actuator to integrated velocity, return error if any.',
|
||||
)),
|
||||
('mjs_setToVelocity',
|
||||
FunctionDecl(
|
||||
name='mjs_setToVelocity',
|
||||
return_type=PointerType(
|
||||
inner_type=ValueType(name='char', is_const=True),
|
||||
),
|
||||
parameters=(
|
||||
FunctionParameterDecl(
|
||||
name='actuator',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjsActuator'),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='kv',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
),
|
||||
doc='Set actuator to velocity servo, return error if any.',
|
||||
)),
|
||||
('mjs_setToDamper',
|
||||
FunctionDecl(
|
||||
name='mjs_setToDamper',
|
||||
return_type=PointerType(
|
||||
inner_type=ValueType(name='char', is_const=True),
|
||||
),
|
||||
parameters=(
|
||||
FunctionParameterDecl(
|
||||
name='actuator',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjsActuator'),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='kv',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
),
|
||||
doc='Set actuator to activate damper, return error if any.',
|
||||
)),
|
||||
('mjs_setToCylinder',
|
||||
FunctionDecl(
|
||||
name='mjs_setToCylinder',
|
||||
return_type=PointerType(
|
||||
inner_type=ValueType(name='char', is_const=True),
|
||||
),
|
||||
parameters=(
|
||||
FunctionParameterDecl(
|
||||
name='actuator',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjsActuator'),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='timeconst',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='bias',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='area',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='diameter',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
),
|
||||
doc='Set actuator to hydraulic or pneumatic cylinder, return error if any.', # pylint: disable=line-too-long
|
||||
)),
|
||||
('mjs_setToMuscle',
|
||||
FunctionDecl(
|
||||
name='mjs_setToMuscle',
|
||||
return_type=PointerType(
|
||||
inner_type=ValueType(name='char', is_const=True),
|
||||
),
|
||||
parameters=(
|
||||
FunctionParameterDecl(
|
||||
name='actuator',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjsActuator'),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='timeconst',
|
||||
type=ArrayType(
|
||||
inner_type=ValueType(name='double'),
|
||||
extents=(2,),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='tausmooth',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='range',
|
||||
type=ArrayType(
|
||||
inner_type=ValueType(name='double'),
|
||||
extents=(2,),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='force',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='scale',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='lmin',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='lmax',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='vmax',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='fpmax',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='fvmax',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
),
|
||||
doc='Set actuator to muscle, return error if any.a',
|
||||
)),
|
||||
('mjs_setToAdhesion',
|
||||
FunctionDecl(
|
||||
name='mjs_setToAdhesion',
|
||||
return_type=PointerType(
|
||||
inner_type=ValueType(name='char', is_const=True),
|
||||
),
|
||||
parameters=(
|
||||
FunctionParameterDecl(
|
||||
name='actuator',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjsActuator'),
|
||||
),
|
||||
),
|
||||
FunctionParameterDecl(
|
||||
name='gain',
|
||||
type=ValueType(name='double'),
|
||||
),
|
||||
),
|
||||
doc='Set actuator to active adhesion, return error if any.',
|
||||
)),
|
||||
('mjs_addMesh',
|
||||
FunctionDecl(
|
||||
name='mjs_addMesh',
|
||||
|
||||
@@ -278,6 +278,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
||||
name='global',
|
||||
type=AnonymousStructDecl(
|
||||
fields=(
|
||||
StructFieldDecl(
|
||||
name='cameraid',
|
||||
type=ValueType(name='int'),
|
||||
doc='initial camera id (-1: free)',
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='orthographic',
|
||||
type=ValueType(name='int'),
|
||||
@@ -868,6 +873,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
||||
type=ValueType(name='int'),
|
||||
doc='number of dynamic bounding volumes (aabb stored in mjData)', # pylint: disable=line-too-long
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='noct',
|
||||
type=ValueType(name='int'),
|
||||
doc='number of total octree cells in all meshes',
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='njnt',
|
||||
type=ValueType(name='int'),
|
||||
@@ -1555,6 +1565,30 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
||||
doc='local bounding box (center, size)',
|
||||
array_extent=('nbvhstatic', 6),
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='oct_depth',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='int'),
|
||||
),
|
||||
doc='depth in the octree',
|
||||
array_extent=('noct',),
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='oct_child',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='int'),
|
||||
),
|
||||
doc='children of octree node',
|
||||
array_extent=('noct', 8),
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='oct_aabb',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjtNum'),
|
||||
),
|
||||
doc='octree node bounding box (center, size)',
|
||||
array_extent=('noct', 6),
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='jnt_type',
|
||||
type=PointerType(
|
||||
@@ -2915,6 +2949,22 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
||||
doc='number of bvh',
|
||||
array_extent=('nmesh',),
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='mesh_octadr',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='int'),
|
||||
),
|
||||
doc='address of octree root',
|
||||
array_extent=('nmesh',),
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='mesh_octnum',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='int'),
|
||||
),
|
||||
doc='number of octree nodes',
|
||||
array_extent=('nmesh',),
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='mesh_normaladr',
|
||||
type=PointerType(
|
||||
@@ -6868,6 +6918,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
||||
type=ValueType(name='int'),
|
||||
doc='depth of the bounding volume hierarchy to be visualized',
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='oct_depth',
|
||||
type=ValueType(name='int'),
|
||||
doc='depth of the octree to be visualized',
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='flex_layer',
|
||||
type=ValueType(name='int'),
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.mujoco.mjpython</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>3.3.3</string>
|
||||
<string>3.3.4</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>3.3.3</string>
|
||||
<string>3.3.4</string>
|
||||
<key>CFBundleLongVersionString</key>
|
||||
<string>3.3.3</string>
|
||||
<string>3.3.4</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.3.3</string>
|
||||
<string>3.3.4</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>mjpython</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
|
||||
@@ -336,6 +336,7 @@ PYBIND11_MODULE(_simulate, pymodule) {
|
||||
CallIfNotNull(&mujoco::Simulate::LoadMessageClear),
|
||||
py::call_guard<py::gil_scoped_release>())
|
||||
.def("sync", CallIfNotNull(&mujoco::Simulate::Sync),
|
||||
py::arg("state_only") = false,
|
||||
py::call_guard<py::gil_scoped_release>())
|
||||
.def("add_to_history", CallIfNotNull(&mujoco::Simulate::AddToHistory),
|
||||
py::call_guard<py::gil_scoped_release>())
|
||||
|
||||
+162
-38
@@ -396,8 +396,8 @@ PYBIND11_MODULE(_specs, m) {
|
||||
return mjs_addDefault(spec->ptr, classname.c_str(), parent);
|
||||
},
|
||||
py::return_value_policy::reference_internal);
|
||||
mjSpec.def("detach_default", [](MjSpec& self, raw::MjsDefault& def) {
|
||||
if (mjs_detachDefault(self.ptr, &def) != 0) {
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsDefault& def) {
|
||||
if (mjs_delete(self.ptr, def.element) != 0) {
|
||||
throw pybind11::value_error(mjs_getError(self.ptr));
|
||||
}
|
||||
});
|
||||
@@ -407,8 +407,8 @@ PYBIND11_MODULE(_specs, m) {
|
||||
return mjs_getSpecDefault(self.ptr);
|
||||
},
|
||||
py::return_value_policy::reference_internal);
|
||||
mjSpec.def("detach_body", [](MjSpec& self, raw::MjsBody& body) {
|
||||
mjs_detachBody(self.ptr, &body);
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsBody& body) {
|
||||
mjs_delete(self.ptr, body.element);
|
||||
});
|
||||
mjSpec.def(
|
||||
"attach",
|
||||
@@ -759,7 +759,9 @@ PYBIND11_MODULE(_specs, m) {
|
||||
|
||||
|
||||
// ============================= MJSFRAME ====================================
|
||||
mjsFrame.def("delete", [](raw::MjsFrame& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsFrame& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
mjsFrame.def("set_frame", [](raw::MjsFrame& self, raw::MjsFrame& frame) {
|
||||
if (mjs_setFrame(self.element, &frame) != 0) {
|
||||
throw pybind11::value_error(mjs_getError(mjs_getSpec(self.element)));
|
||||
@@ -796,7 +798,9 @@ PYBIND11_MODULE(_specs, m) {
|
||||
py::return_value_policy::reference_internal);
|
||||
|
||||
// ============================= MJSGEOM =====================================
|
||||
mjsGeom.def("delete", [](raw::MjsGeom& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsGeom& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
mjsGeom.def("set_frame", [](raw::MjsGeom& self, raw::MjsFrame& frame) {
|
||||
if (mjs_setFrame(self.element, &frame) != 0) {
|
||||
throw pybind11::value_error(mjs_getError(mjs_getSpec(self.element)));
|
||||
@@ -824,7 +828,9 @@ PYBIND11_MODULE(_specs, m) {
|
||||
py::return_value_policy::reference_internal);
|
||||
|
||||
// ============================= MJSJOINT ====================================
|
||||
mjsJoint.def("delete", [](raw::MjsJoint& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsJoint& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
mjsJoint.def("set_frame", [](raw::MjsJoint& self, raw::MjsFrame& frame) {
|
||||
if (mjs_setFrame(self.element, &frame) != 0) {
|
||||
throw pybind11::value_error(mjs_getError(mjs_getSpec(self.element)));
|
||||
@@ -852,7 +858,9 @@ PYBIND11_MODULE(_specs, m) {
|
||||
py::return_value_policy::reference_internal);
|
||||
|
||||
// ============================= MJSSITE =====================================
|
||||
mjsSite.def("delete", [](raw::MjsSite& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsSite& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
mjsSite.def("set_frame", [](raw::MjsSite& self, raw::MjsFrame& frame) {
|
||||
if (mjs_setFrame(self.element, &frame) != 0) {
|
||||
throw pybind11::value_error(mjs_getError(mjs_getSpec(self.element)));
|
||||
@@ -897,8 +905,9 @@ PYBIND11_MODULE(_specs, m) {
|
||||
py::return_value_policy::reference_internal);
|
||||
|
||||
// ============================= MJSCAMERA ===================================
|
||||
mjsCamera.def("delete",
|
||||
[](raw::MjsCamera& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsCamera& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
mjsCamera.def("set_frame", [](raw::MjsCamera& self, raw::MjsFrame& frame) {
|
||||
if (mjs_setFrame(self.element, &frame) != 0) {
|
||||
throw pybind11::value_error(mjs_getError(mjs_getSpec(self.element)));
|
||||
@@ -926,7 +935,9 @@ PYBIND11_MODULE(_specs, m) {
|
||||
py::return_value_policy::reference_internal);
|
||||
|
||||
// ============================= MJSLIGHT ====================================
|
||||
mjsLight.def("delete", [](raw::MjsLight& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsLight& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
mjsLight.def("set_frame", [](raw::MjsLight& self, raw::MjsFrame& frame) {
|
||||
if (mjs_setFrame(self.element, &frame) != 0) {
|
||||
throw pybind11::value_error(mjs_getError(mjs_getSpec(self.element)));
|
||||
@@ -954,8 +965,9 @@ PYBIND11_MODULE(_specs, m) {
|
||||
py::return_value_policy::reference_internal);
|
||||
|
||||
// ============================= MJSMATERIAL =================================
|
||||
mjsMaterial.def("delete",
|
||||
[](raw::MjsMaterial& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsMaterial& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
mjsMaterial.def_property(
|
||||
"classname",
|
||||
[](raw::MjsMaterial& self) -> raw::MjsDefault* {
|
||||
@@ -966,7 +978,9 @@ PYBIND11_MODULE(_specs, m) {
|
||||
});
|
||||
|
||||
// ============================= MJSMESH =====================================
|
||||
mjsMesh.def("delete", [](raw::MjsMesh& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsMesh& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
mjsMesh.def_property(
|
||||
"classname",
|
||||
[](raw::MjsMesh& self) -> raw::MjsDefault* {
|
||||
@@ -977,7 +991,9 @@ PYBIND11_MODULE(_specs, m) {
|
||||
});
|
||||
|
||||
// ============================= MJSPAIR =====================================
|
||||
mjsPair.def("delete", [](raw::MjsPair& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsPair& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
mjsPair.def_property(
|
||||
"classname",
|
||||
[](raw::MjsPair& self) -> raw::MjsDefault* {
|
||||
@@ -988,8 +1004,9 @@ PYBIND11_MODULE(_specs, m) {
|
||||
});
|
||||
|
||||
// ============================= MJSEQUAL ====================================
|
||||
mjsEquality.def("delete",
|
||||
[](raw::MjsEquality& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsEquality& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
mjsEquality.def_property(
|
||||
"classname",
|
||||
[](raw::MjsEquality& self) -> raw::MjsDefault* {
|
||||
@@ -1000,8 +1017,9 @@ PYBIND11_MODULE(_specs, m) {
|
||||
});
|
||||
|
||||
// ============================= MJSACTUATOR =================================
|
||||
mjsActuator.def("delete",
|
||||
[](raw::MjsActuator& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsActuator& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
mjsActuator.def_property(
|
||||
"classname",
|
||||
[](raw::MjsActuator& self) -> raw::MjsDefault* {
|
||||
@@ -1010,10 +1028,100 @@ PYBIND11_MODULE(_specs, m) {
|
||||
[](raw::MjsActuator& self, raw::MjsDefault& default_) -> void {
|
||||
mjs_setDefault(self.element, &default_);
|
||||
});
|
||||
mjsActuator.def("set_to_motor", [](raw::MjsActuator* self) {
|
||||
std::string err = mjs_setToMotor(self);
|
||||
if (!err.empty()) {
|
||||
throw pybind11::value_error(err);
|
||||
}
|
||||
});
|
||||
mjsActuator.def(
|
||||
"set_to_position",
|
||||
[](raw::MjsActuator* self, double kp, double kv, double dampratio,
|
||||
double timeconst, bool inheritrange) {
|
||||
std::string err = mjs_setToPosition(
|
||||
self, kp, kv == -1 ? nullptr : &kv,
|
||||
dampratio == -1 ? nullptr : &dampratio,
|
||||
timeconst == -1 ? nullptr : &timeconst, inheritrange);
|
||||
if (!err.empty()) {
|
||||
throw pybind11::value_error(err);
|
||||
}
|
||||
},
|
||||
py::arg("kp"), py::arg("kv") = -1, py::arg("dampratio") = -1,
|
||||
py::arg("timeconst") = -1, py::arg("inheritrange") = false);
|
||||
mjsActuator.def(
|
||||
"set_to_intvelocity",
|
||||
[](raw::MjsActuator* self, double kp, double kv, double dampratio,
|
||||
double timeconst, bool inheritrange) {
|
||||
std::string err = mjs_setToIntVelocity(
|
||||
self, kp, kv == -1 ? nullptr : &kv,
|
||||
dampratio == -1 ? nullptr : &dampratio,
|
||||
timeconst == -1 ? nullptr : &timeconst, inheritrange);
|
||||
if (!err.empty()) {
|
||||
throw pybind11::value_error(err);
|
||||
}
|
||||
},
|
||||
py::arg("kp"), py::arg("kv") = -1, py::arg("dampratio") = -1,
|
||||
py::arg("timeconst") = -1, py::arg("inheritrange") = false);
|
||||
mjsActuator.def(
|
||||
"set_to_velocity",
|
||||
[](raw::MjsActuator* self, double kv) {
|
||||
std::string err = mjs_setToVelocity(self, kv);
|
||||
if (!err.empty()) {
|
||||
throw pybind11::value_error(err);
|
||||
}
|
||||
},
|
||||
py::arg("kv"));
|
||||
mjsActuator.def(
|
||||
"set_to_damper",
|
||||
[](raw::MjsActuator* self, double kv) {
|
||||
std::string err = mjs_setToDamper(self, kv);
|
||||
if (!err.empty()) {
|
||||
throw pybind11::value_error(err);
|
||||
}
|
||||
},
|
||||
py::arg("kv"));
|
||||
mjsActuator.def(
|
||||
"set_to_cylinder",
|
||||
[](raw::MjsActuator* self, double timeconst, double bias, double area,
|
||||
double diameter) {
|
||||
std::string err =
|
||||
mjs_setToCylinder(self, timeconst, bias, area, diameter);
|
||||
if (!err.empty()) {
|
||||
throw pybind11::value_error(err);
|
||||
}
|
||||
},
|
||||
py::arg("timeconst"), py::arg("bias"), py::arg("area"),
|
||||
py::arg("diameter") = -1);
|
||||
mjsActuator.def(
|
||||
"set_to_muscle",
|
||||
[](raw::MjsActuator* self, double timeconst[2], double tausmooth,
|
||||
double range[2], double force, double scale, double lmin, double lmax,
|
||||
double vmax, double fpmax, double fvmax) {
|
||||
std::string err =
|
||||
mjs_setToMuscle(self, timeconst, tausmooth, range, force, scale,
|
||||
lmin, lmax, vmax, fpmax, fvmax);
|
||||
if (!err.empty()) {
|
||||
throw pybind11::value_error(err);
|
||||
}
|
||||
},
|
||||
py::arg("timeconst") = -1, py::arg("tausmooth"),
|
||||
py::arg("range") = std::array<double, 2>{-1, -1}, py::arg("force") = -1,
|
||||
py::arg("scale") = -1, py::arg("lmin") = -1, py::arg("lmax") = -1,
|
||||
py::arg("vmax") = -1, py::arg("fpmax") = -1, py::arg("fvmax") = -1);
|
||||
mjsActuator.def(
|
||||
"set_to_adhesion",
|
||||
[](raw::MjsActuator* self, double gain) {
|
||||
std::string err = mjs_setToAdhesion(self, gain);
|
||||
if (!err.empty()) {
|
||||
throw pybind11::value_error(err);
|
||||
}
|
||||
},
|
||||
py::arg("gain"));
|
||||
|
||||
// ============================= MJSTENDON ===================================
|
||||
mjsTendon.def("delete",
|
||||
[](raw::MjsTendon& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsTendon& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
mjsTendon.def(
|
||||
"default",
|
||||
[](raw::MjsTendon& self) -> raw::MjsDefault* {
|
||||
@@ -1046,39 +1154,54 @@ PYBIND11_MODULE(_specs, m) {
|
||||
py::return_value_policy::reference_internal);
|
||||
|
||||
// ============================= MJSSENSOR ===================================
|
||||
mjsSensor.def("delete",
|
||||
[](raw::MjsSensor& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsSensor& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
|
||||
// ============================= MJSFLEX =====================================
|
||||
mjsFlex.def("delete", [](raw::MjsFlex& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsFlex& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
|
||||
// ============================= MJSHFIELD ===================================
|
||||
mjsHField.def("delete",
|
||||
[](raw::MjsHField& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsHField& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
|
||||
// ============================= MJSSKIN =====================================
|
||||
mjsSkin.def("delete", [](raw::MjsSkin& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsSkin& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
|
||||
// ============================= MJSTEXTURE ==================================
|
||||
mjsTexture.def("delete",
|
||||
[](raw::MjsTexture& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsTexture& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
|
||||
// ============================= MJSKEY ======================================
|
||||
mjsKey.def("delete", [](raw::MjsKey& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsKey& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
|
||||
// ============================= MJSTEXT =====================================
|
||||
mjsText.def("delete", [](raw::MjsText& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsText& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
|
||||
// ============================= MJSNUMERIC ==================================
|
||||
mjsNumeric.def("delete",
|
||||
[](raw::MjsNumeric& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsNumeric& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
|
||||
// ============================= MJSEXCLUDE ==================================
|
||||
mjsExclude.def("delete",
|
||||
[](raw::MjsExclude& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsExclude& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
|
||||
// ============================= MJSTUPLE ====================================
|
||||
mjsTuple.def("delete", [](raw::MjsTuple& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsTuple& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
|
||||
// ============================= MJSPLUGIN ===================================
|
||||
mjsPlugin.def_property(
|
||||
@@ -1087,8 +1210,9 @@ PYBIND11_MODULE(_specs, m) {
|
||||
[](raw::MjsPlugin& self, raw::MjsPlugin* other) {
|
||||
self.element = other->element;
|
||||
});
|
||||
mjsPlugin.def("delete",
|
||||
[](raw::MjsPlugin& self) { mjs_delete(self.element); });
|
||||
mjSpec.def("delete", [](MjSpec& self, raw::MjsPlugin& obj) {
|
||||
mjs_delete(self.ptr, obj.element);
|
||||
});
|
||||
mjsPlugin.def_property(
|
||||
"config",
|
||||
[](raw::MjsPlugin& self) -> py::dict {
|
||||
|
||||
@@ -604,7 +604,7 @@ class SpecsTest(absltest.TestCase):
|
||||
|
||||
# test delete default
|
||||
def1 = spec.find_default('def1')
|
||||
spec.detach_default(def1)
|
||||
spec.delete(def1)
|
||||
def1 = spec.find_default('def1')
|
||||
self.assertIsNone(def1)
|
||||
|
||||
@@ -838,9 +838,9 @@ class SpecsTest(absltest.TestCase):
|
||||
self.assertIsNotNone(site)
|
||||
self.assertEqual(site, spec.site('head'))
|
||||
|
||||
site.delete()
|
||||
spec.sensors[-1].delete()
|
||||
spec.sensors[-1].delete()
|
||||
spec.delete(site)
|
||||
spec.delete(spec.sensors[-1])
|
||||
spec.delete(spec.sensors[-1])
|
||||
|
||||
model = spec.compile()
|
||||
self.assertIsNotNone(model)
|
||||
@@ -861,7 +861,7 @@ class SpecsTest(absltest.TestCase):
|
||||
|
||||
body = spec.worldbody.add_body()
|
||||
body.plugin = plugin
|
||||
body.plugin.plugin_name = 'mujoco.elasticity.cable'
|
||||
body.plugin.name = 'instance_name'
|
||||
body.plugin.active = True
|
||||
|
||||
geom = body.add_geom()
|
||||
@@ -930,7 +930,7 @@ class SpecsTest(absltest.TestCase):
|
||||
""")
|
||||
plugin = spec.plugins[0]
|
||||
self.assertIsNotNone(plugin)
|
||||
plugin.delete()
|
||||
spec.delete(plugin)
|
||||
|
||||
model = spec.compile()
|
||||
self.assertIsNotNone(model)
|
||||
@@ -1001,6 +1001,14 @@ class SpecsTest(absltest.TestCase):
|
||||
texture.data = np.zeros((2, 2, 3), dtype=np.uint8).tobytes()
|
||||
spec.compile()
|
||||
|
||||
def test_find_unnamed_texture(self):
|
||||
spec = mujoco.MjSpec()
|
||||
texture_file = spec.add_texture(file='file.png')
|
||||
texture_name = spec.add_texture(name='name')
|
||||
self.assertEqual(spec.texture('file'), texture_file)
|
||||
self.assertEqual(spec.texture('name'), texture_name)
|
||||
self.assertIsNone(spec.texture('none'))
|
||||
|
||||
def test_attach_units(self):
|
||||
child = mujoco.MjSpec()
|
||||
parent = mujoco.MjSpec()
|
||||
@@ -1232,5 +1240,61 @@ class SpecsTest(absltest.TestCase):
|
||||
self.assertGreater(spec3._address, 0)
|
||||
self.assertLen({spec1._address, spec2._address, spec3._address}, 3)
|
||||
|
||||
def test_actuator_shortname(self):
|
||||
spec = mujoco.MjSpec()
|
||||
actuator = spec.add_actuator(
|
||||
gainprm=np.zeros((10, 1)),
|
||||
dyntype=mujoco.mjtDyn.mjDYN_FILTER,
|
||||
gaintype=mujoco.mjtGain.mjGAIN_AFFINE,
|
||||
biastype=mujoco.mjtBias.mjBIAS_AFFINE,
|
||||
)
|
||||
actuator.set_to_motor()
|
||||
self.assertEqual(actuator.gainprm[0], 1)
|
||||
self.assertEqual(actuator.dyntype, mujoco.mjtDyn.mjDYN_NONE)
|
||||
self.assertEqual(actuator.gaintype, mujoco.mjtGain.mjGAIN_FIXED)
|
||||
self.assertEqual(actuator.biastype, mujoco.mjtBias.mjBIAS_NONE)
|
||||
|
||||
actuator.set_to_position(kp=2.0, kv=3.0, timeconst=4.0, inheritrange=True)
|
||||
self.assertEqual(actuator.gainprm[0], 2)
|
||||
self.assertEqual(actuator.biasprm[1], -2)
|
||||
self.assertEqual(actuator.biasprm[2], -3)
|
||||
self.assertEqual(actuator.dynprm[0], 4)
|
||||
self.assertEqual(actuator.dyntype, mujoco.mjtDyn.mjDYN_FILTEREXACT)
|
||||
self.assertEqual(actuator.gaintype, mujoco.mjtGain.mjGAIN_FIXED)
|
||||
self.assertEqual(actuator.biastype, mujoco.mjtBias.mjBIAS_AFFINE)
|
||||
self.assertEqual(actuator.inheritrange, True)
|
||||
|
||||
actuator.set_to_intvelocity(
|
||||
kp=2.0, kv=3.0, timeconst=4.0, inheritrange=True
|
||||
)
|
||||
self.assertEqual(actuator.gainprm[0], 2)
|
||||
self.assertEqual(actuator.biasprm[1], -2)
|
||||
self.assertEqual(actuator.biasprm[2], -3)
|
||||
self.assertEqual(actuator.dynprm[0], 4)
|
||||
self.assertEqual(actuator.dyntype, mujoco.mjtDyn.mjDYN_INTEGRATOR)
|
||||
self.assertEqual(actuator.gaintype, mujoco.mjtGain.mjGAIN_FIXED)
|
||||
self.assertEqual(actuator.biastype, mujoco.mjtBias.mjBIAS_AFFINE)
|
||||
self.assertEqual(actuator.inheritrange, True)
|
||||
|
||||
actuator.set_to_velocity(kv=5.0)
|
||||
self.assertEqual(actuator.gainprm[0], 5)
|
||||
self.assertEqual(actuator.biasprm[2], -5)
|
||||
self.assertEqual(actuator.dyntype, mujoco.mjtDyn.mjDYN_NONE)
|
||||
self.assertEqual(actuator.gaintype, mujoco.mjtGain.mjGAIN_FIXED)
|
||||
self.assertEqual(actuator.biastype, mujoco.mjtBias.mjBIAS_AFFINE)
|
||||
|
||||
actuator.set_to_damper(kv=6.0)
|
||||
self.assertEqual(actuator.gainprm[0], 0)
|
||||
self.assertEqual(actuator.gainprm[2], -6)
|
||||
self.assertEqual(actuator.dyntype, mujoco.mjtDyn.mjDYN_NONE)
|
||||
self.assertEqual(actuator.gaintype, mujoco.mjtGain.mjGAIN_AFFINE)
|
||||
self.assertEqual(actuator.biastype, mujoco.mjtBias.mjBIAS_NONE)
|
||||
|
||||
actuator.set_to_adhesion(gain=7.0)
|
||||
self.assertEqual(actuator.gainprm[0], 7)
|
||||
self.assertEqual(actuator.dyntype, mujoco.mjtDyn.mjDYN_NONE)
|
||||
self.assertEqual(actuator.gaintype, mujoco.mjtGain.mjGAIN_FIXED)
|
||||
self.assertEqual(actuator.biastype, mujoco.mjtBias.mjBIAS_NONE)
|
||||
|
||||
if __name__ == '__main__':
|
||||
absltest.main()
|
||||
|
||||
@@ -175,6 +175,7 @@ PYBIND11_MODULE(_structs, m) {
|
||||
});
|
||||
DefineStructFunctions(mjVisualGlobal);
|
||||
#define X(var) mjVisualGlobal.def_readwrite(#var, &raw::MjVisualGlobal::var)
|
||||
X(cameraid);
|
||||
X(orthographic);
|
||||
X(fovy);
|
||||
X(ipd);
|
||||
@@ -1109,6 +1110,7 @@ This is useful for example when the MJB is not available as a file on disk.)"));
|
||||
X(label);
|
||||
X(frame);
|
||||
X(bvh_depth);
|
||||
X(oct_depth);
|
||||
X(flex_layer);
|
||||
#undef X
|
||||
|
||||
|
||||
@@ -230,10 +230,10 @@ class Handle:
|
||||
return sim.lock()
|
||||
return contextlib.nullcontext()
|
||||
|
||||
def sync(self):
|
||||
def sync(self, state_only: bool = False):
|
||||
sim = self._get_sim()
|
||||
if sim is not None:
|
||||
sim.sync() # locks internally
|
||||
sim.sync(state_only) # locks internally
|
||||
|
||||
def update_hfield(self, hfieldid: int):
|
||||
sim = self._get_sim()
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "mujoco"
|
||||
version = "3.3.3"
|
||||
version = "3.3.4"
|
||||
authors = [
|
||||
{name = "Google DeepMind", email = "mujoco@deepmind.com"},
|
||||
]
|
||||
@@ -35,9 +35,9 @@ dynamic = ["readme", "scripts"]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/google-deepmind/mujoco"
|
||||
Documentation = "https://mujoco.readthedocs.io/en/3.3.3"
|
||||
Documentation = "https://mujoco.readthedocs.io/en/3.3.4"
|
||||
Repository = "https://github.com/google-deepmind/mujoco"
|
||||
Changelog = "https://mujoco.readthedocs.io/en/3.3.3/changelog.html"
|
||||
Changelog = "https://mujoco.readthedocs.io/en/3.3.4/changelog.html"
|
||||
|
||||
[tool.setuptools]
|
||||
include-package-data = false
|
||||
|
||||
+197
-78
@@ -5,6 +5,7 @@
|
||||
"id": "6adc68e0-a943-44ab-9af5-4bc62cc19f34",
|
||||
"metadata": {
|
||||
"editable": true,
|
||||
"id": "6adc68e0-a943-44ab-9af5-4bc62cc19f34",
|
||||
"tags": []
|
||||
},
|
||||
"source": [
|
||||
@@ -16,7 +17,7 @@
|
||||
"\n",
|
||||
"This notebook describes the `rollout` module included in the MuJoCo Python library. It performs simulation \"rollouts\" with an underlying C++ function. The rollouts can be multithreaded.\n",
|
||||
"\n",
|
||||
"Below, the usage of each argument is explained with examples. Then some examples for advanced use cases are provided. Finally, `rollout` is benchmarked against pure python and MJX. \n",
|
||||
"Below, the usage of each argument is explained with examples. Then some examples for advanced use cases are provided. Finally, `rollout` is benchmarked against pure python and MJX.\n",
|
||||
"\n",
|
||||
"Note the benchmarks were designed to run on >16 thread CPU and an RTX 4090 or A100. They do not run in a reasonable amount of time on a typical free colab runtime.\n",
|
||||
"\n",
|
||||
@@ -41,6 +42,7 @@
|
||||
"id": "5d8a6604-0948-4a42-a48d-249c7f0c462b",
|
||||
"metadata": {
|
||||
"editable": true,
|
||||
"id": "5d8a6604-0948-4a42-a48d-249c7f0c462b",
|
||||
"tags": []
|
||||
},
|
||||
"source": [
|
||||
@@ -53,6 +55,7 @@
|
||||
"id": "0f9fbad1-59d0-40ac-b2b6-99f37313670f",
|
||||
"metadata": {
|
||||
"editable": true,
|
||||
"id": "0f9fbad1-59d0-40ac-b2b6-99f37313670f",
|
||||
"tags": [
|
||||
"hide-input"
|
||||
]
|
||||
@@ -154,7 +157,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fc69d0f4",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "fc69d0f4"
|
||||
},
|
||||
"source": [
|
||||
"# Helper Functions"
|
||||
]
|
||||
@@ -165,6 +170,7 @@
|
||||
"id": "082482c7",
|
||||
"metadata": {
|
||||
"editable": true,
|
||||
"id": "082482c7",
|
||||
"tags": [
|
||||
"hide-input"
|
||||
]
|
||||
@@ -251,7 +257,7 @@
|
||||
" light.cutoff = 45\n",
|
||||
" light.diffuse = [0.8, 0.8, 0.8]\n",
|
||||
" light.dir = [0, 0, -1]\n",
|
||||
" light.directional = 0\n",
|
||||
" light.type = mujoco.mjtLightType.mjLIGHT_SPOT\n",
|
||||
" light.exponent = 10\n",
|
||||
" light.headlight = 0\n",
|
||||
" light.specular = [0.3, 0.3, 0.3]\n",
|
||||
@@ -267,7 +273,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c0570c2c",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "c0570c2c"
|
||||
},
|
||||
"source": [
|
||||
"# Using `rollout`\n",
|
||||
"\n",
|
||||
@@ -280,9 +288,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "849b93e5",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "849b93e5"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#@title Benchmarked models\n",
|
||||
@@ -368,7 +378,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "55d171f7-541b-4441-aa18-da86d6716410",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "55d171f7-541b-4441-aa18-da86d6716410"
|
||||
},
|
||||
"source": [
|
||||
"## Usage\n",
|
||||
"\n",
|
||||
@@ -380,9 +392,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "9cd2f94a-11df-4247-986c-5a56af69a1f5",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "9cd2f94a-11df-4247-986c-5a56af69a1f5"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(rollout.rollout.__doc__)"
|
||||
@@ -392,6 +406,7 @@
|
||||
"cell_type": "markdown",
|
||||
"id": "b6f7a094-8352-4b07-99ee-5278e3036cd5",
|
||||
"metadata": {
|
||||
"id": "b6f7a094-8352-4b07-99ee-5278e3036cd5",
|
||||
"tags": []
|
||||
},
|
||||
"source": [
|
||||
@@ -403,9 +418,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "849af5f2-9de1-4cb9-bc3a-c9b7acf0e3fe",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "849af5f2-9de1-4cb9-bc3a-c9b7acf0e3fe"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"nbatch = 100 # Simulate this many tops\n",
|
||||
@@ -437,16 +454,20 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "aa2cf151-bf9a-4a23-b7fe-6a766979d93f",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "aa2cf151-bf9a-4a23-b7fe-6a766979d93f"
|
||||
},
|
||||
"source": [
|
||||
"Our model has an angular velocity sensor the middle of the top. Let's plot the response using the `sensordata` array that rollout returns."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "957b8566-da31-410b-b385-e78241c5247a",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "957b8566-da31-410b-b385-e78241c5247a"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"plt.figure(figsize=(12, 8))\n",
|
||||
@@ -462,7 +483,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "58044bc1-f98c-4bbf-a703-40ba075552a0",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "58044bc1-f98c-4bbf-a703-40ba075552a0"
|
||||
},
|
||||
"source": [
|
||||
"### Example: different models\n",
|
||||
"100 gray tops is kind of boring. It would be better if they were colorful and different sizes!\n",
|
||||
@@ -474,9 +497,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "7c39e79e-8942-4fea-b306-ea0cb3c826e2",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "7c39e79e-8942-4fea-b306-ea0cb3c826e2"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Make 100 tippe tops with different colors and sizes\n",
|
||||
@@ -544,16 +569,20 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cf485c08-72be-4169-89b6-9d93df8ebbe3",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "cf485c08-72be-4169-89b6-9d93df8ebbe3"
|
||||
},
|
||||
"source": [
|
||||
"Because the models are now different, the measurements of the gyro sensor are not consistent even though the initial state for each rollout was the same."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "b8a5d3d4-24e7-41a1-b3bd-7b63c1812b03",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "b8a5d3d4-24e7-41a1-b3bd-7b63c1812b03"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"plt.figure(figsize=(12, 8))\n",
|
||||
@@ -569,7 +598,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3841a669-6cd1-427e-a629-20a10a6e3a34",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "3841a669-6cd1-427e-a629-20a10a6e3a34"
|
||||
},
|
||||
"source": [
|
||||
"### Example: control inputs\n",
|
||||
"Open loop controls can be passed to `rollout` via the `control` argument. If passed, `nstep` no longer needs to be specified as it can be inferred from the size of `control`.\n",
|
||||
@@ -579,9 +610,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "2a184873-8d24-45da-b444-8d21f5dcd733",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "2a184873-8d24-45da-b444-8d21f5dcd733"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Episode parameters.\n",
|
||||
@@ -632,7 +665,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4d89e4fb-7711-4d23-8ff3-eb5030fa8bf7",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "4d89e4fb-7711-4d23-8ff3-eb5030fa8bf7"
|
||||
},
|
||||
"source": [
|
||||
"`rollout`'s `control_spec` argument can be used to indicate `control` contains values for actuators, generalized forces, cartesian forces, mocap poses, and/or the activation/deactivation of equality constraints. Internally, this is managed through [mj_setState](https://mujoco.readthedocs.io/en/stable/APIreference/APIfunctions.html#mj-setstate) and `control_spec` corresponds to `mj_setState`'s `spec` argument.\n",
|
||||
"\n",
|
||||
@@ -641,9 +676,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "4b02bb61-912d-47de-a956-aadfcd4c5cd5",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "4b02bb61-912d-47de-a956-aadfcd4c5cd5"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"xfrc_size = mujoco.mj_stateSize(humanoid_model, mujoco.mjtState.mjSTATE_XFRC_APPLIED)\n",
|
||||
@@ -676,7 +713,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0961c3ec-a691-4875-9a55-227a3d29c472",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "0961c3ec-a691-4875-9a55-227a3d29c472"
|
||||
},
|
||||
"source": [
|
||||
"# Advanced usage"
|
||||
]
|
||||
@@ -684,7 +723,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "VfYIyXWcLKfg",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "VfYIyXWcLKfg"
|
||||
},
|
||||
"source": [
|
||||
"## skip_checks\n",
|
||||
"\n",
|
||||
@@ -706,9 +747,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "d02cc8e8-63cd-4852-ab3c-364a18025a95",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "d02cc8e8-63cd-4852-ab3c-364a18025a95"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"nbatch = 1000\n",
|
||||
@@ -752,7 +795,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "92627030-4726-4689-be8b-f1ba75905104",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "92627030-4726-4689-be8b-f1ba75905104"
|
||||
},
|
||||
"source": [
|
||||
"As expected, as `nstep` increases, the benefits of using skip checks fades quickly. However, at low nstep and high batch sizes, it can make a significant difference.\n",
|
||||
"\n",
|
||||
@@ -762,7 +807,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d32a77b5-24bd-4d17-80ac-15cc4d03731c",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "d32a77b5-24bd-4d17-80ac-15cc4d03731c"
|
||||
},
|
||||
"source": [
|
||||
"## Reusing threadpools (`Rollout` class)\n",
|
||||
"\n",
|
||||
@@ -773,9 +820,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "dd05bbdf-f389-4e4e-b389-d47fe976cb49",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "dd05bbdf-f389-4e4e-b389-d47fe976cb49"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"nbatch = 100\n",
|
||||
@@ -813,7 +862,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9b3e14a1-71f3-430d-a3c2-1aadcf6c2671",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "9b3e14a1-71f3-430d-a3c2-1aadcf6c2671"
|
||||
},
|
||||
"source": [
|
||||
"## Reusing threadpools (`rollout` method)\n",
|
||||
"\n",
|
||||
@@ -824,9 +875,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "b6aa6801",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "b6aa6801"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"nbatch = 1000\n",
|
||||
@@ -846,16 +899,20 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "144378d3",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "144378d3"
|
||||
},
|
||||
"source": [
|
||||
"Second, if `rollout` reuses the same threadpool between calls, it is no longer safe to call `rollout` from multiple threads. For example the following is not allowed (the offending lines are commented out to avoid crashing the interpreter):"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "7f46a6d8",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "7f46a6d8"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"thread1 = threading.Thread(target=lambda: rollout.rollout(top_model, top_datas, initial_states, nstep=nstep, persistent_pool=True))\n",
|
||||
@@ -871,7 +928,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "78c1f864-5238-4e27-a7ec-d03c45484d9a",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "78c1f864-5238-4e27-a7ec-d03c45484d9a"
|
||||
},
|
||||
"source": [
|
||||
"## chunk_size\n",
|
||||
"\n",
|
||||
@@ -882,9 +941,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "a1be8f93",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "a1be8f93"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"nbatch = 100\n",
|
||||
@@ -928,7 +989,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "84c746e0-5d2e-47dc-ac76-f2b6f790b7c7",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "84c746e0-5d2e-47dc-ac76-f2b6f790b7c7"
|
||||
},
|
||||
"source": [
|
||||
"## Warmstarting\n",
|
||||
"\n",
|
||||
@@ -941,9 +1004,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "d4d9f660-f83c-432e-a579-124a7ecab4fb",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "d4d9f660-f83c-432e-a579-124a7ecab4fb"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"top_model_cg = copy.copy(top_model)\n",
|
||||
@@ -1004,7 +1069,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7c2cf4fa",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "7c2cf4fa"
|
||||
},
|
||||
"source": [
|
||||
"As expected, the middle animation (with warmstarting) matches the continuous rollout on the left. However, the model that did not use warmstarting diverged."
|
||||
]
|
||||
@@ -1012,7 +1079,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7944637f",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "7944637f"
|
||||
},
|
||||
"source": [
|
||||
"# Benchmarks\n",
|
||||
"\n",
|
||||
@@ -1029,9 +1098,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "cb6355dd",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "cb6355dd"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def python_rollout(model, data, nbatch, nstep):\n",
|
||||
@@ -1043,7 +1114,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6fe4a78b",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "6fe4a78b"
|
||||
},
|
||||
"source": [
|
||||
"To run nbatch rollouts with `rollout`, we need to make an array of nbatch initial states to start the rollouts from.\n",
|
||||
"\n",
|
||||
@@ -1055,9 +1128,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "74f143e2",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "74f143e2"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def nthread_rollout(model, data, nbatch, nstep, nthread, rollout_):\n",
|
||||
@@ -1071,7 +1146,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b75dc44c",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "b75dc44c"
|
||||
},
|
||||
"source": [
|
||||
"Next, we benchmark the Python loop and `rollout` in both single threaded and multithreaded modes. The three benchmarks take about 2.5 minutes in total to run in total on an AMD 5800X3D."
|
||||
]
|
||||
@@ -1081,7 +1158,8 @@
|
||||
"execution_count": 0,
|
||||
"id": "0301e3ee",
|
||||
"metadata": {
|
||||
"cellView": "form"
|
||||
"cellView": "form",
|
||||
"id": "0301e3ee"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -1204,16 +1282,20 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "08fb0c12",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "08fb0c12"
|
||||
},
|
||||
"source": [
|
||||
"### Tippe Top Benchmark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "f7e54830",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "f7e54830"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"nominal_nbatch = 256 # Batch size to use when testing different nstep\n",
|
||||
@@ -1232,16 +1314,20 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "edefb26e",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "edefb26e"
|
||||
},
|
||||
"source": [
|
||||
"### Humanoid Benchmark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "c9e58c6c",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "c9e58c6c"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"nominal_nbatch = 256 # Batch size to use when testing different nstep\n",
|
||||
@@ -1260,16 +1346,20 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "468903bb",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "468903bb"
|
||||
},
|
||||
"source": [
|
||||
"### Humanoid100 Benchmark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "83d775d4",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "83d775d4"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"nominal_nbatch = 128 # Batch size to use when testing different nstep\n",
|
||||
@@ -1293,7 +1383,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d1133084",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "d1133084"
|
||||
},
|
||||
"source": [
|
||||
"# MJX versus `rollout`"
|
||||
]
|
||||
@@ -1301,7 +1393,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c1638f2d",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "c1638f2d"
|
||||
},
|
||||
"source": [
|
||||
"Next we will benchmark `rollout` and MJX using the tippe top and humanoid models (humanoid100 is not supported by MJX).\n",
|
||||
"\n",
|
||||
@@ -1315,7 +1409,8 @@
|
||||
"execution_count": 0,
|
||||
"id": "7c86d157",
|
||||
"metadata": {
|
||||
"cellView": "form"
|
||||
"cellView": "form",
|
||||
"id": "7c86d157"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -1436,16 +1531,20 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a2dafd2e",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "a2dafd2e"
|
||||
},
|
||||
"source": [
|
||||
"### MJX Tippe Top Benchmark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "98c580b0",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "98c580b0"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"nominal_nbatch = 16384 # Batch size to use when testing different nstep\n",
|
||||
@@ -1461,16 +1560,20 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "205da5da",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "205da5da"
|
||||
},
|
||||
"source": [
|
||||
"### MJX Humanoid Benchmark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "53166ae1",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "53166ae1"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"nominal_nbatch = 4096 # Batch size to use when testing different nstep\n",
|
||||
@@ -1486,7 +1589,9 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fb2caa72",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "fb2caa72"
|
||||
},
|
||||
"source": [
|
||||
"### MJX Multiple Humanoids in one model\n",
|
||||
"\n",
|
||||
@@ -1499,9 +1604,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "3d6be608",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "3d6be608"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"max_humanoids = 10\n",
|
||||
@@ -1549,9 +1656,11 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 0,
|
||||
"id": "b6c5fc2e",
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"id": "b6c5fc2e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#@title Plot MJX nhumanoid benchmark\n",
|
||||
@@ -1584,6 +1693,16 @@
|
||||
"\n",
|
||||
"plot_mjx_nhumanoid_benchmark(t_rollout, t_mjx, nbatch, nstep, max_humanoids)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 0,
|
||||
"id": "UW0aoKXK7ALd",
|
||||
"metadata": {
|
||||
"id": "UW0aoKXK7ALd"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
@@ -24,7 +24,7 @@ set(MSVC_INCREMENTAL_DEFAULT ON)
|
||||
|
||||
project(
|
||||
mujoco_samples
|
||||
VERSION 3.3.3
|
||||
VERSION 3.3.4
|
||||
DESCRIPTION "MuJoCo samples binaries"
|
||||
HOMEPAGE_URL "https://mujoco.org"
|
||||
)
|
||||
|
||||
+25
-1
@@ -29,7 +29,7 @@ set(MUJOCO_DEP_VERSION_lodepng
|
||||
|
||||
project(
|
||||
mujoco_simulate
|
||||
VERSION 3.3.3
|
||||
VERSION 3.3.4
|
||||
DESCRIPTION "MuJoCo simulate binaries"
|
||||
HOMEPAGE_URL "https://mujoco.org"
|
||||
)
|
||||
@@ -183,6 +183,14 @@ if(SIMULATE_BUILD_EXECUTABLE)
|
||||
lodepng
|
||||
)
|
||||
|
||||
if (MUJOCO_WITH_USD)
|
||||
target_link_libraries(
|
||||
simulate
|
||||
mujoco::usd
|
||||
mujoco::usd::mjcf
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_options(simulate PRIVATE ${MUJOCO_SIMULATE_LINK_OPTIONS})
|
||||
|
||||
if(APPLE AND MUJOCO_BUILD_MACOS_FRAMEWORKS)
|
||||
@@ -249,6 +257,22 @@ if(SIMULATE_BUILD_EXECUTABLE)
|
||||
MUJOCO_ENABLE_RPATH
|
||||
)
|
||||
|
||||
if (MUJOCO_WITH_USD)
|
||||
target_compile_definitions(simulate PUBLIC SIMULATE_WITH_USD)
|
||||
|
||||
# Add support to RPATH for the samples.
|
||||
target_add_rpath(
|
||||
TARGETS
|
||||
simulate
|
||||
INSTALL_DIRECTORY
|
||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}"
|
||||
LIB_DIRS
|
||||
${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/mujocoUsd ${USD_DIR}/lib
|
||||
DEPENDS
|
||||
MUJOCO_ENABLE_RPATH
|
||||
)
|
||||
endif()
|
||||
|
||||
install(
|
||||
TARGETS simulate
|
||||
EXPORT ${PROJECT_NAME}
|
||||
|
||||
+51
-4
@@ -25,6 +25,12 @@
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#if defined(SIMULATE_WITH_USD)
|
||||
#include <mujoco/experimental/usd/usd.h>
|
||||
#include <pxr/pxr.h>
|
||||
#include <pxr/usd/usd/common.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
#endif
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "glfw_adapter.h"
|
||||
#include "simulate.h"
|
||||
@@ -224,13 +230,49 @@ mjModel* LoadModel(const char* file, mj::Simulate& sim) {
|
||||
char loadError[kErrorLength] = "";
|
||||
mjModel* mnew = 0;
|
||||
auto load_start = mj::Simulate::Clock::now();
|
||||
if (mju::strlen_arr(filename)>4 &&
|
||||
!std::strncmp(filename + mju::strlen_arr(filename) - 4, ".mjb",
|
||||
mju::sizeof_arr(filename) - mju::strlen_arr(filename)+4)) {
|
||||
|
||||
std::string filename_str(filename);
|
||||
std::string extension;
|
||||
size_t dot_pos = filename_str.rfind('.');
|
||||
|
||||
if (dot_pos != std::string::npos && dot_pos < filename_str.length() - 1) {
|
||||
extension = filename_str.substr(dot_pos);
|
||||
}
|
||||
|
||||
if (extension == ".mjb") {
|
||||
mnew = mj_loadModel(filename, nullptr);
|
||||
if (!mnew) {
|
||||
mju::strcpy_arr(loadError, "could not load binary model");
|
||||
}
|
||||
#if defined(SIMULATE_WITH_USD)
|
||||
} else if (extension == ".usda" || extension == ".usd" ||
|
||||
extension == ".usdc" || extension == ".usdz" ) {
|
||||
auto stage = pxr::UsdStage::Open(filename);
|
||||
if (!stage) {
|
||||
mju::strcpy_arr(loadError, "could not open USD stage");
|
||||
} else {
|
||||
mjSpec* spec = mj_parseUSDStage(stage);
|
||||
if (!spec) {
|
||||
mju::strcpy_arr(loadError, "could not parse USD stage to mjSpec");
|
||||
} else {
|
||||
mjModel* model = mj_compile(spec, nullptr);
|
||||
if (!model) {
|
||||
mju::strcpy_arr(loadError,
|
||||
"could not compile USD parsed mjSpec to mjModel:\n");
|
||||
mju::strcat_arr(loadError, mjs_getError(spec));
|
||||
} else {
|
||||
// handle compile warning
|
||||
if (mjs_isWarning(spec)) {
|
||||
mju::strcpy_arr(
|
||||
loadError,
|
||||
"warning while compiling USD parsed mjSpec to mjModel:\n");
|
||||
mju::strcat_arr(loadError, mjs_getError(spec));
|
||||
}
|
||||
}
|
||||
mnew = model;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
mnew = mj_loadXML(filename, nullptr, loadError, kErrorLength);
|
||||
|
||||
@@ -353,7 +395,7 @@ void PhysicsLoop(mj::Simulate& sim) {
|
||||
// requested slow-down factor
|
||||
double slowdown = 100 / sim.percentRealTime[sim.real_time_index];
|
||||
|
||||
// misalignment condition: distance from target sim time is bigger than syncmisalign
|
||||
// misalignment condition: distance from target sim time is bigger than syncMisalign
|
||||
bool misaligned =
|
||||
std::abs(Seconds(elapsedCPU).count()/slowdown - elapsedSim) > syncMisalign;
|
||||
|
||||
@@ -495,6 +537,11 @@ int main(int argc, char** argv) {
|
||||
// scan for libraries in the plugin directory to load additional plugins
|
||||
scanPluginLibraries();
|
||||
|
||||
#if defined(SIMULATE_WITH_USD)
|
||||
// If USD is used, print the version.
|
||||
std::printf("OpenUSD version v%d.%02d\n", PXR_MINOR_VERSION, PXR_PATCH_VERSION);
|
||||
#endif
|
||||
|
||||
mjvCamera cam;
|
||||
mjv_defaultCamera(&cam);
|
||||
|
||||
|
||||
+83
-5
@@ -112,6 +112,7 @@ enum {
|
||||
// right ui
|
||||
SECT_JOINT = 0,
|
||||
SECT_CONTROL,
|
||||
SECT_EQUALITY,
|
||||
NSECT1
|
||||
};
|
||||
|
||||
@@ -1127,6 +1128,36 @@ void MakeControlSection(mj::Simulate* sim) {
|
||||
}
|
||||
}
|
||||
|
||||
// make equality section of UI
|
||||
void MakeEqualitySection(mj::Simulate* sim) {
|
||||
mjuiDef defEquality[] = {
|
||||
{mjITEM_SECTION, "Equality", mjPRESERVE, nullptr, "AE"},
|
||||
{mjITEM_END}
|
||||
};
|
||||
mjuiDef defCheckBox[] = {
|
||||
{mjITEM_CHECKBYTE, "", 2, nullptr, ""},
|
||||
{mjITEM_END}
|
||||
};
|
||||
|
||||
// add section
|
||||
mjui_add(&sim->ui1, defEquality);
|
||||
|
||||
// add equalities, exit if UI limit reached
|
||||
for (int i= 0; i < sim->m_->neq && i<mjMAXUIITEM; i++) {
|
||||
// set data
|
||||
defCheckBox[0].pdata = &sim->d_->eq_active[i];
|
||||
|
||||
// set name
|
||||
if (!sim->equality_names_[i].empty()) {
|
||||
mju::strcpy_arr(defCheckBox[0].name, sim->equality_names_[i].c_str());
|
||||
} else {
|
||||
mju::sprintf_arr(defCheckBox[0].name, "equality %d", i);
|
||||
}
|
||||
|
||||
mjui_add(&sim->ui1, defCheckBox);
|
||||
}
|
||||
}
|
||||
|
||||
// make model-dependent UI sections
|
||||
void MakeUiSections(mj::Simulate* sim, const mjModel* m, const mjData* d) {
|
||||
// clear model-dependent sections of UI
|
||||
@@ -1140,14 +1171,23 @@ void MakeUiSections(mj::Simulate* sim, const mjModel* m, const mjData* d) {
|
||||
MakeGroupSection(sim);
|
||||
MakeJointSection(sim);
|
||||
MakeControlSection(sim);
|
||||
MakeEqualitySection(sim);
|
||||
}
|
||||
|
||||
//---------------------------------- utility functions ---------------------------------------------
|
||||
|
||||
// align and scale view
|
||||
void AlignAndScaleView(mj::Simulate* sim, const mjModel* m) {
|
||||
// use default free camera parameters
|
||||
mjv_defaultFreeCamera(m, &sim->cam);
|
||||
// if the id is valid, use the initial fixed camera
|
||||
if (m->vis.global.cameraid >= 0 && m->vis.global.cameraid < m->ncam) {
|
||||
sim->cam.fixedcamid = m->vis.global.cameraid;
|
||||
sim->cam.type = mjCAMERA_FIXED;
|
||||
}
|
||||
|
||||
// otherwise use default free camera
|
||||
else {
|
||||
mjv_defaultFreeCamera(m, &sim->cam);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1872,7 +1912,7 @@ Simulate::Simulate(std::unique_ptr<PlatformUIAdapter> platform_ui,
|
||||
//------------------------- Synchronize render and physics threads ---------------------------------
|
||||
|
||||
// operations which require holding the mutex, prevents racing with physics thread
|
||||
void Simulate::Sync() {
|
||||
void Simulate::Sync(bool state_only) {
|
||||
MutexLock lock(this->mtx);
|
||||
|
||||
if (!m_) {
|
||||
@@ -1931,6 +1971,18 @@ void Simulate::Sync() {
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_->neq; ++i) {
|
||||
if (eq_active_[i] != eq_active_prev_[i]) {
|
||||
d_->eq_active[i] = eq_active_[i];
|
||||
} else {
|
||||
eq_active_[i] = d_->eq_active[i];
|
||||
}
|
||||
if (eq_active_prev_[i] != eq_active_[i]) {
|
||||
pending_.ui_update_equality = true;
|
||||
eq_active_prev_[i] = eq_active_[i];
|
||||
}
|
||||
}
|
||||
|
||||
// in passive mode, synchronize user's mjModel with changes made via the UI
|
||||
if (is_passive_) {
|
||||
// synchronize mjModel.opt
|
||||
@@ -2107,8 +2159,17 @@ void Simulate::Sync() {
|
||||
if (!is_passive_) {
|
||||
mjv_updateScene(m_, d_, &this->opt, &this->pert, &this->cam, mjCAT_ALL, &this->scn);
|
||||
} else {
|
||||
mjv_copyModel(m_passive_, m_);
|
||||
mjv_copyData(d_passive_, m_passive_, d_);
|
||||
if (state_only) {
|
||||
int state_size = mj_stateSize(m_, mjSTATE_INTEGRATION);
|
||||
mjtNum* state = new mjtNum[state_size];
|
||||
mj_getState(m_, d_, state, mjSTATE_INTEGRATION);
|
||||
mj_setState(m_passive_, d_passive_, state, mjSTATE_INTEGRATION);
|
||||
mj_forward(m_passive_, d_passive_);
|
||||
delete[] state;
|
||||
} else {
|
||||
mjv_copyModel(m_passive_, m_);
|
||||
mjv_copyData(d_passive_, m_passive_, d_);
|
||||
}
|
||||
|
||||
// append geoms from user_scn to scratch space
|
||||
if (user_scn) {
|
||||
@@ -2261,6 +2322,12 @@ void Simulate::LoadOnRenderThread() {
|
||||
actuator_names_.emplace_back(this->m_->names + this->m_->name_actuatoradr[i]);
|
||||
}
|
||||
|
||||
equality_names_.clear();
|
||||
equality_names_.reserve(this->m_->neq);
|
||||
for (int i = 0; i < this->m_->neq; ++i) {
|
||||
equality_names_.emplace_back(this->m_->names + this->m_->name_eqadr[i]);
|
||||
}
|
||||
|
||||
qpos_.resize(this->m_->nq);
|
||||
std::memcpy(qpos_.data(), this->d_->qpos, sizeof(this->d_->qpos[0]) * this->m_->nq);
|
||||
qpos_prev_ = qpos_;
|
||||
@@ -2269,6 +2336,10 @@ void Simulate::LoadOnRenderThread() {
|
||||
std::memcpy(ctrl_.data(), this->d_->ctrl, sizeof(this->d_->ctrl[0]) * this->m_->nu);
|
||||
ctrl_prev_ = ctrl_;
|
||||
|
||||
eq_active_.resize(this->m_->neq);
|
||||
std::memcpy(eq_active_.data(), this->d_->eq_active, sizeof(this->d_->eq_active[0]) * this->m_->neq);
|
||||
eq_active_prev_ = eq_active_;
|
||||
|
||||
// allocate history buffer: smaller of {2000 states, 100 MB}
|
||||
if (!this->is_passive_) {
|
||||
constexpr int kMaxHistoryBytes = 1e8;
|
||||
@@ -2518,6 +2589,13 @@ void Simulate::Render() {
|
||||
pending_.ui_update_ctrl = false;
|
||||
}
|
||||
|
||||
if (pending_.ui_update_equality) {
|
||||
if (this->ui1_enable && this->ui1.sect[SECT_EQUALITY].state) {
|
||||
mjui_update(SECT_EQUALITY, -1, &this->ui1, &this->uistate, &this->platform_ui->mjr_context());
|
||||
}
|
||||
pending_.ui_update_equality = false;
|
||||
}
|
||||
|
||||
// render scene
|
||||
mjr_render(rect, &this->scn, &this->platform_ui->mjr_context());
|
||||
|
||||
|
||||
+9
-3
@@ -54,9 +54,10 @@ class Simulate {
|
||||
std::unique_ptr<PlatformUIAdapter> platform_ui_adapter,
|
||||
mjvCamera* cam, mjvOption* opt, mjvPerturb* pert, bool is_passive);
|
||||
|
||||
// Synchronize mjModel and mjData state with UI inputs, and update
|
||||
// visualization.
|
||||
void Sync();
|
||||
// Synchronize state with UI inputs, and update visualization. If state_only
|
||||
// is false mjData and mjModel will be updated, otherwise only the subset of
|
||||
// mjData corresponding to mjSTATE_INTEGRATION will be synced.
|
||||
void Sync(bool state_only = false);
|
||||
|
||||
void UpdateHField(int hfieldid);
|
||||
void UpdateMesh(int meshid);
|
||||
@@ -122,6 +123,8 @@ class Simulate {
|
||||
std::vector<std::optional<std::pair<mjtNum, mjtNum>>> actuator_ctrlrange_;
|
||||
std::vector<std::string> actuator_names_;
|
||||
|
||||
std::vector<std::string> equality_names_;
|
||||
|
||||
std::vector<mjtNum> history_; // history buffer (nhistory x state_size)
|
||||
|
||||
// mjModel and mjData fields that can be modified by the user through the GUI
|
||||
@@ -129,6 +132,8 @@ class Simulate {
|
||||
std::vector<mjtNum> qpos_prev_;
|
||||
std::vector<mjtNum> ctrl_;
|
||||
std::vector<mjtNum> ctrl_prev_;
|
||||
std::vector<mjtByte> eq_active_;
|
||||
std::vector<mjtByte> eq_active_prev_;
|
||||
|
||||
// in passive mode the user owns m_ and d_, these "passive" instances are
|
||||
// owned by Simulate, updated from the user by the Sync() method
|
||||
@@ -167,6 +172,7 @@ class Simulate {
|
||||
bool ui_update_visualization;
|
||||
bool ui_update_joint;
|
||||
bool ui_update_ctrl;
|
||||
bool ui_update_equality;
|
||||
bool ui_remake_ctrl;
|
||||
} pending_ = {};
|
||||
|
||||
|
||||
@@ -36,6 +36,19 @@
|
||||
|
||||
//---------------------------- primitives sdf ---------------------------------------------
|
||||
|
||||
static void radialField3d(mjtNum field[3], const mjtNum a[3], const mjtNum x[3],
|
||||
const mjtNum size[3]) {
|
||||
field[0] = -size[0] / a[0];
|
||||
field[1] = -size[1] / a[1];
|
||||
field[2] = -size[2] / a[2];
|
||||
mju_normalize3(field);
|
||||
|
||||
// flip sign if necessary
|
||||
if (x[0] < 0) field[0] = -field[0];
|
||||
if (x[1] < 0) field[1] = -field[1];
|
||||
if (x[2] < 0) field[2] = -field[2];
|
||||
}
|
||||
|
||||
static mjtNum geomDistance(const mjModel* m, const mjData* d, const mjpPlugin* p,
|
||||
int i, const mjtNum x[3], mjtGeom type) {
|
||||
mjtNum a[3], b[3];
|
||||
@@ -48,13 +61,23 @@ static mjtNum geomDistance(const mjModel* m, const mjData* d, const mjpPlugin* p
|
||||
case mjGEOM_SPHERE:
|
||||
return mju_norm3(x) - size[0];
|
||||
case mjGEOM_BOX:
|
||||
// compute shortest distance to box surface if outside, otherwise
|
||||
// intersect with a unit gradient that linearly rotates from radial to the face normals
|
||||
a[0] = mju_abs(x[0]) - size[0];
|
||||
a[1] = mju_abs(x[1]) - size[1];
|
||||
a[2] = mju_abs(x[2]) - size[2];
|
||||
b[0] = mju_max(a[0], 0);
|
||||
b[1] = mju_max(a[1], 0);
|
||||
b[2] = mju_max(a[2], 0);
|
||||
return mju_norm3(b) + mju_min(mju_max(a[0], mju_max(a[1], a[2])), 0);
|
||||
if (a[0] >= 0 || a[1] >= 0 || a[2] >= 0) {
|
||||
b[0] = mju_max(a[0], 0);
|
||||
b[1] = mju_max(a[1], 0);
|
||||
b[2] = mju_max(a[2], 0);
|
||||
return mju_norm3(b) + mju_min(mju_max(a[0], mju_max(a[1], a[2])), 0);
|
||||
}
|
||||
radialField3d(b, a, x, size);
|
||||
mjtNum t[3];
|
||||
t[0] = -a[0] / mju_abs(b[0]);
|
||||
t[1] = -a[1] / mju_abs(b[1]);
|
||||
t[2] = -a[2] / mju_abs(b[2]);
|
||||
return -mju_min(t[0], mju_min(t[1], t[2])) * mju_norm3(b);
|
||||
case mjGEOM_CAPSULE:
|
||||
a[0] = x[0];
|
||||
a[1] = x[1];
|
||||
@@ -111,7 +134,7 @@ static void geomGradient(mjtNum gradient[3], const mjModel* m, const mjData* d,
|
||||
int k = a[0] > a[1] ? 0 : 1;
|
||||
int l = a[2] > a[k] ? 2 : k;
|
||||
if (a[l] < 0) {
|
||||
gradient[l] = x[l] / mju_abs(x[l]);
|
||||
radialField3d(gradient, a, x, size);
|
||||
} else {
|
||||
b[0] = mju_max(a[0], 0);
|
||||
b[1] = mju_max(a[1], 0);
|
||||
|
||||
+239
-240
@@ -430,244 +430,246 @@ void mj_instantiateEquality(const mjModel* m, mjData* d) {
|
||||
|
||||
// find active equality constraints
|
||||
for (int i=0; i < m->neq; i++) {
|
||||
if (d->eq_active[i]) {
|
||||
// get constraint data
|
||||
data = m->eq_data + mjNEQDATA*i;
|
||||
id[0] = m->eq_obj1id[i];
|
||||
id[1] = m->eq_obj2id[i];
|
||||
size = 0;
|
||||
NV = 0;
|
||||
NV2 = 0;
|
||||
int body_id[2];
|
||||
if (!d->eq_active[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// process according to type
|
||||
switch ((mjtEq) m->eq_type[i]) {
|
||||
case mjEQ_CONNECT: // connect bodies with ball joint
|
||||
// find global points, body semantic
|
||||
if (m->eq_objtype[i] == mjOBJ_BODY) {
|
||||
for (int j=0; j < 2; j++) {
|
||||
mju_mulMatVec3(pos[j], d->xmat + 9*id[j], data + 3*j);
|
||||
mju_addTo3(pos[j], d->xpos + 3*id[j]);
|
||||
body_id[j] = id[j];
|
||||
}
|
||||
// get constraint data
|
||||
data = m->eq_data + mjNEQDATA*i;
|
||||
id[0] = m->eq_obj1id[i];
|
||||
id[1] = m->eq_obj2id[i];
|
||||
size = 0;
|
||||
NV = 0;
|
||||
NV2 = 0;
|
||||
int body_id[2];
|
||||
|
||||
// process according to type
|
||||
switch ((mjtEq) m->eq_type[i]) {
|
||||
case mjEQ_CONNECT: // connect bodies with ball joint
|
||||
// find global points, body semantic
|
||||
if (m->eq_objtype[i] == mjOBJ_BODY) {
|
||||
for (int j=0; j < 2; j++) {
|
||||
mju_mulMatVec3(pos[j], d->xmat + 9*id[j], data + 3*j);
|
||||
mju_addTo3(pos[j], d->xpos + 3*id[j]);
|
||||
body_id[j] = id[j];
|
||||
}
|
||||
|
||||
// find global points, site semantic
|
||||
else {
|
||||
for (int j=0; j < 2; j++) {
|
||||
mju_copy3(pos[j], d->site_xpos + 3*id[j]);
|
||||
body_id[j] = m->site_bodyid[id[j]];
|
||||
}
|
||||
}
|
||||
|
||||
// compute position error
|
||||
mju_sub3(cpos, pos[0], pos[1]);
|
||||
|
||||
// compute Jacobian difference (opposite of contact: 0 - 1)
|
||||
NV = mj_jacDifPair(m, d, chain, body_id[1], body_id[0], pos[1], pos[0],
|
||||
jac[1], jac[0], jacdif, NULL, NULL, NULL);
|
||||
|
||||
// copy difference into jac[0]
|
||||
mju_copy(jac[0], jacdif, 3*NV);
|
||||
|
||||
size = 3;
|
||||
break;
|
||||
|
||||
case mjEQ_WELD: // fix relative position and orientation
|
||||
// find global points, body semantic
|
||||
if (m->eq_objtype[i] == mjOBJ_BODY) {
|
||||
for (int j=0; j < 2; j++) {
|
||||
mjtNum* anchor = data + 3*(1-j);
|
||||
mju_mulMatVec3(pos[j], d->xmat + 9*id[j], anchor);
|
||||
mju_addTo3(pos[j], d->xpos + 3*id[j]);
|
||||
body_id[j] = id[j];
|
||||
}
|
||||
}
|
||||
|
||||
// find global points, site semantic
|
||||
else {
|
||||
for (int j=0; j < 2; j++) {
|
||||
mju_copy3(pos[j], d->site_xpos + 3*id[j]);
|
||||
body_id[j] = m->site_bodyid[id[j]];
|
||||
}
|
||||
}
|
||||
|
||||
// compute position error
|
||||
mju_sub3(cpos, pos[0], pos[1]);
|
||||
|
||||
// get torquescale coefficient
|
||||
mjtNum torquescale = data[10];
|
||||
|
||||
// compute error Jacobian (opposite of contact: 0 - 1)
|
||||
NV = mj_jacDifPair(m, d, chain, body_id[1], body_id[0], pos[1], pos[0],
|
||||
jac[1], jac[0], jacdif,
|
||||
jac[1]+3*nv, jac[0]+3*nv, jacdif+3*nv);
|
||||
|
||||
// copy difference into jac[0], compress translation:rotation if sparse
|
||||
mju_copy(jac[0], jacdif, 3*NV);
|
||||
mju_copy(jac[0]+3*NV, jacdif+3*nv, 3*NV);
|
||||
|
||||
// orientation, body semantic
|
||||
if (m->eq_objtype[i] == mjOBJ_BODY) {
|
||||
// compute orientation error: neg(q1) * q0 * relpose (axis components only)
|
||||
mjtNum* relpose = data+6;
|
||||
mju_mulQuat(quat, d->xquat+4*id[0], relpose); // quat = q0*relpose
|
||||
mju_negQuat(quat1, d->xquat+4*id[1]); // quat1 = neg(q1)
|
||||
}
|
||||
|
||||
// orientation, site semantic
|
||||
else {
|
||||
mjtNum quat_site1[4];
|
||||
mju_mulQuat(quat, d->xquat+4*body_id[0], m->site_quat+4*id[0]);
|
||||
mju_mulQuat(quat_site1, d->xquat+4*body_id[1], m->site_quat+4*id[1]);
|
||||
mju_negQuat(quat1, quat_site1);
|
||||
}
|
||||
|
||||
mju_mulQuat(quat2, quat1, quat);
|
||||
mju_scl3(cpos+3, quat2+1, torquescale); // scale axis components by torquescale
|
||||
|
||||
// correct rotation Jacobian: 0.5 * neg(q1) * (jac0-jac1) * q0 * relpose
|
||||
for (int j=0; j < NV; j++) {
|
||||
// axis = [jac0-jac1]_col(j)
|
||||
axis[0] = jac[0][3*NV+j];
|
||||
axis[1] = jac[0][4*NV+j];
|
||||
axis[2] = jac[0][5*NV+j];
|
||||
|
||||
// apply formula
|
||||
mju_mulQuatAxis(quat2, quat1, axis); // quat2 = neg(q1)*(jac0-jac1)
|
||||
mju_mulQuat(quat3, quat2, quat); // quat3 = neg(q1)*(jac0-jac1)*q0*relpose
|
||||
|
||||
// correct Jacobian
|
||||
jac[0][3*NV+j] = 0.5*quat3[1];
|
||||
jac[0][4*NV+j] = 0.5*quat3[2];
|
||||
jac[0][5*NV+j] = 0.5*quat3[3];
|
||||
}
|
||||
|
||||
// scale rotational jacobian by torquescale
|
||||
mju_scl(jac[0]+3*NV, jac[0]+3*NV, torquescale, 3*NV);
|
||||
|
||||
size = 6;
|
||||
break;
|
||||
|
||||
case mjEQ_JOINT: // couple joint values with cubic
|
||||
case mjEQ_TENDON: // couple tendon lengths with cubic
|
||||
// get scalar positions and their Jacobians
|
||||
for (int j=0; j < 1+(id[1] >= 0); j++) {
|
||||
if (m->eq_type[i] == mjEQ_JOINT) { // joint object
|
||||
pos[j][0] = d->qpos[m->jnt_qposadr[id[j]]];
|
||||
ref[j] = m->qpos0[m->jnt_qposadr[id[j]]];
|
||||
|
||||
// make Jacobian: sparse or dense
|
||||
if (issparse) {
|
||||
// add first or second joint
|
||||
if (j == 0) {
|
||||
NV = 1;
|
||||
chain[0] = m->jnt_dofadr[id[j]];
|
||||
jac[j][0] = 1;
|
||||
} else {
|
||||
NV2 = 1;
|
||||
chain2[0] = m->jnt_dofadr[id[j]];
|
||||
jac[j][0] = 1;
|
||||
}
|
||||
} else {
|
||||
mju_zero(jac[j], nv);
|
||||
jac[j][m->jnt_dofadr[id[j]]] = 1;
|
||||
}
|
||||
} else { // tendon object
|
||||
pos[j][0] = d->ten_length[id[j]];
|
||||
ref[j] = m->tendon_length0[id[j]];
|
||||
|
||||
// set tendon_efcadr
|
||||
if (d->tendon_efcadr[id[j]] == -1) {
|
||||
d->tendon_efcadr[id[j]] = i;
|
||||
}
|
||||
|
||||
// copy Jacobian: sparse or dense
|
||||
if (issparse) {
|
||||
// add first or second chain
|
||||
if (j == 0) {
|
||||
NV = d->ten_J_rownnz[id[j]];
|
||||
mju_copyInt(chain, d->ten_J_colind+d->ten_J_rowadr[id[j]], NV);
|
||||
mju_copy(jac[j], d->ten_J+d->ten_J_rowadr[id[j]], NV);
|
||||
} else {
|
||||
NV2 = d->ten_J_rownnz[id[j]];
|
||||
mju_copyInt(chain2, d->ten_J_colind+d->ten_J_rowadr[id[j]], NV2);
|
||||
mju_copy(jac[j], d->ten_J+d->ten_J_rowadr[id[j]], NV2);
|
||||
}
|
||||
} else {
|
||||
mju_copy(jac[j], d->ten_J+id[j]*nv, nv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// both objects defined
|
||||
if (id[1] >= 0) {
|
||||
// compute position error
|
||||
dif = pos[1][0] - ref[1];
|
||||
cpos[0] = pos[0][0] - ref[0] - data[0] -
|
||||
(data[1]*dif + data[2]*dif*dif + data[3]*dif*dif*dif + data[4]*dif*dif*dif*dif);
|
||||
|
||||
// compute derivative
|
||||
deriv = data[1] + 2*data[2]*dif + 3*data[3]*dif*dif + 4*data[4]*dif*dif*dif;
|
||||
|
||||
// compute Jacobian: sparse or dense
|
||||
if (issparse) {
|
||||
NV = mju_combineSparse(jac[0], jac[1], 1, -deriv, NV, NV2, chain,
|
||||
chain2, sparse_buf, buf_ind);
|
||||
} else {
|
||||
mju_addToScl(jac[0], jac[1], -deriv, nv);
|
||||
}
|
||||
}
|
||||
|
||||
// only one object defined
|
||||
else {
|
||||
// compute position error
|
||||
cpos[0] = pos[0][0] - ref[0] - data[0];
|
||||
|
||||
// jac[0] already has the correct Jacobian
|
||||
}
|
||||
|
||||
size = 1;
|
||||
break;
|
||||
|
||||
case mjEQ_FLEX:
|
||||
flex_edgeadr = m->flex_edgeadr[id[0]];
|
||||
flex_edgenum = m->flex_edgenum[id[0]];
|
||||
// add one constraint per non-rigid edge
|
||||
for (int e=flex_edgeadr; e < flex_edgeadr+flex_edgenum; e++) {
|
||||
// skip rigid
|
||||
if (m->flexedge_rigid[e]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// position error
|
||||
cpos[0] = d->flexedge_length[e] - m->flexedge_length0[e];
|
||||
|
||||
// add constraint: sparse or dense
|
||||
if (issparse) {
|
||||
mj_addConstraint(m, d, d->flexedge_J+d->flexedge_J_rowadr[e], cpos, 0, 0,
|
||||
1, mjCNSTR_EQUALITY, i,
|
||||
d->flexedge_J_rownnz[e],
|
||||
d->flexedge_J_colind+d->flexedge_J_rowadr[e]);
|
||||
} else {
|
||||
mj_addConstraint(m, d, d->flexedge_J+e*nv, cpos, 0, 0,
|
||||
1, mjCNSTR_EQUALITY, i,
|
||||
0, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: // SHOULD NOT OCCUR
|
||||
mjERROR("invalid equality constraint type %d", m->eq_type[i]);
|
||||
}
|
||||
|
||||
// add constraint
|
||||
if (size) {
|
||||
mj_addConstraint(m, d, jac[0], cpos, 0, 0,
|
||||
size, mjCNSTR_EQUALITY, i,
|
||||
issparse ? NV : 0,
|
||||
issparse ? chain : NULL);
|
||||
// find global points, site semantic
|
||||
else {
|
||||
for (int j=0; j < 2; j++) {
|
||||
mju_copy3(pos[j], d->site_xpos + 3*id[j]);
|
||||
body_id[j] = m->site_bodyid[id[j]];
|
||||
}
|
||||
}
|
||||
|
||||
// compute position error
|
||||
mju_sub3(cpos, pos[0], pos[1]);
|
||||
|
||||
// compute Jacobian difference (opposite of contact: 0 - 1)
|
||||
NV = mj_jacDifPair(m, d, chain, body_id[1], body_id[0], pos[1], pos[0],
|
||||
jac[1], jac[0], jacdif, NULL, NULL, NULL);
|
||||
|
||||
// copy difference into jac[0]
|
||||
mju_copy(jac[0], jacdif, 3*NV);
|
||||
|
||||
size = 3;
|
||||
break;
|
||||
|
||||
case mjEQ_WELD: // fix relative position and orientation
|
||||
// find global points, body semantic
|
||||
if (m->eq_objtype[i] == mjOBJ_BODY) {
|
||||
for (int j=0; j < 2; j++) {
|
||||
mjtNum* anchor = data + 3*(1-j);
|
||||
mju_mulMatVec3(pos[j], d->xmat + 9*id[j], anchor);
|
||||
mju_addTo3(pos[j], d->xpos + 3*id[j]);
|
||||
body_id[j] = id[j];
|
||||
}
|
||||
}
|
||||
|
||||
// find global points, site semantic
|
||||
else {
|
||||
for (int j=0; j < 2; j++) {
|
||||
mju_copy3(pos[j], d->site_xpos + 3*id[j]);
|
||||
body_id[j] = m->site_bodyid[id[j]];
|
||||
}
|
||||
}
|
||||
|
||||
// compute position error
|
||||
mju_sub3(cpos, pos[0], pos[1]);
|
||||
|
||||
// get torquescale coefficient
|
||||
mjtNum torquescale = data[10];
|
||||
|
||||
// compute error Jacobian (opposite of contact: 0 - 1)
|
||||
NV = mj_jacDifPair(m, d, chain, body_id[1], body_id[0], pos[1], pos[0],
|
||||
jac[1], jac[0], jacdif,
|
||||
jac[1]+3*nv, jac[0]+3*nv, jacdif+3*nv);
|
||||
|
||||
// copy difference into jac[0], compress translation:rotation if sparse
|
||||
mju_copy(jac[0], jacdif, 3*NV);
|
||||
mju_copy(jac[0]+3*NV, jacdif+3*nv, 3*NV);
|
||||
|
||||
// orientation, body semantic
|
||||
if (m->eq_objtype[i] == mjOBJ_BODY) {
|
||||
// compute orientation error: neg(q1) * q0 * relpose (axis components only)
|
||||
mjtNum* relpose = data+6;
|
||||
mju_mulQuat(quat, d->xquat+4*id[0], relpose); // quat = q0*relpose
|
||||
mju_negQuat(quat1, d->xquat+4*id[1]); // quat1 = neg(q1)
|
||||
}
|
||||
|
||||
// orientation, site semantic
|
||||
else {
|
||||
mjtNum quat_site1[4];
|
||||
mju_mulQuat(quat, d->xquat+4*body_id[0], m->site_quat+4*id[0]);
|
||||
mju_mulQuat(quat_site1, d->xquat+4*body_id[1], m->site_quat+4*id[1]);
|
||||
mju_negQuat(quat1, quat_site1);
|
||||
}
|
||||
|
||||
mju_mulQuat(quat2, quat1, quat);
|
||||
mju_scl3(cpos+3, quat2+1, torquescale); // scale axis components by torquescale
|
||||
|
||||
// correct rotation Jacobian: 0.5 * neg(q1) * (jac0-jac1) * q0 * relpose
|
||||
for (int j=0; j < NV; j++) {
|
||||
// axis = [jac0-jac1]_col(j)
|
||||
axis[0] = jac[0][3*NV+j];
|
||||
axis[1] = jac[0][4*NV+j];
|
||||
axis[2] = jac[0][5*NV+j];
|
||||
|
||||
// apply formula
|
||||
mju_mulQuatAxis(quat2, quat1, axis); // quat2 = neg(q1)*(jac0-jac1)
|
||||
mju_mulQuat(quat3, quat2, quat); // quat3 = neg(q1)*(jac0-jac1)*q0*relpose
|
||||
|
||||
// correct Jacobian
|
||||
jac[0][3*NV+j] = 0.5*quat3[1];
|
||||
jac[0][4*NV+j] = 0.5*quat3[2];
|
||||
jac[0][5*NV+j] = 0.5*quat3[3];
|
||||
}
|
||||
|
||||
// scale rotational jacobian by torquescale
|
||||
mju_scl(jac[0]+3*NV, jac[0]+3*NV, torquescale, 3*NV);
|
||||
|
||||
size = 6;
|
||||
break;
|
||||
|
||||
case mjEQ_JOINT: // couple joint values with cubic
|
||||
case mjEQ_TENDON: // couple tendon lengths with cubic
|
||||
// get scalar positions and their Jacobians
|
||||
for (int j=0; j < 1+(id[1] >= 0); j++) {
|
||||
if (m->eq_type[i] == mjEQ_JOINT) { // joint object
|
||||
pos[j][0] = d->qpos[m->jnt_qposadr[id[j]]];
|
||||
ref[j] = m->qpos0[m->jnt_qposadr[id[j]]];
|
||||
|
||||
// make Jacobian: sparse or dense
|
||||
if (issparse) {
|
||||
// add first or second joint
|
||||
if (j == 0) {
|
||||
NV = 1;
|
||||
chain[0] = m->jnt_dofadr[id[j]];
|
||||
jac[j][0] = 1;
|
||||
} else {
|
||||
NV2 = 1;
|
||||
chain2[0] = m->jnt_dofadr[id[j]];
|
||||
jac[j][0] = 1;
|
||||
}
|
||||
} else {
|
||||
mju_zero(jac[j], nv);
|
||||
jac[j][m->jnt_dofadr[id[j]]] = 1;
|
||||
}
|
||||
} else { // tendon object
|
||||
pos[j][0] = d->ten_length[id[j]];
|
||||
ref[j] = m->tendon_length0[id[j]];
|
||||
|
||||
// set tendon_efcadr
|
||||
if (d->tendon_efcadr[id[j]] == -1) {
|
||||
d->tendon_efcadr[id[j]] = i;
|
||||
}
|
||||
|
||||
// copy Jacobian: sparse or dense
|
||||
if (issparse) {
|
||||
// add first or second chain
|
||||
if (j == 0) {
|
||||
NV = d->ten_J_rownnz[id[j]];
|
||||
mju_copyInt(chain, d->ten_J_colind+d->ten_J_rowadr[id[j]], NV);
|
||||
mju_copy(jac[j], d->ten_J+d->ten_J_rowadr[id[j]], NV);
|
||||
} else {
|
||||
NV2 = d->ten_J_rownnz[id[j]];
|
||||
mju_copyInt(chain2, d->ten_J_colind+d->ten_J_rowadr[id[j]], NV2);
|
||||
mju_copy(jac[j], d->ten_J+d->ten_J_rowadr[id[j]], NV2);
|
||||
}
|
||||
} else {
|
||||
mju_copy(jac[j], d->ten_J+id[j]*nv, nv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// both objects defined
|
||||
if (id[1] >= 0) {
|
||||
// compute position error
|
||||
dif = pos[1][0] - ref[1];
|
||||
cpos[0] = pos[0][0] - ref[0] - data[0] -
|
||||
(data[1]*dif + data[2]*dif*dif + data[3]*dif*dif*dif + data[4]*dif*dif*dif*dif);
|
||||
|
||||
// compute derivative
|
||||
deriv = data[1] + 2*data[2]*dif + 3*data[3]*dif*dif + 4*data[4]*dif*dif*dif;
|
||||
|
||||
// compute Jacobian: sparse or dense
|
||||
if (issparse) {
|
||||
NV = mju_combineSparse(jac[0], jac[1], 1, -deriv, NV, NV2, chain,
|
||||
chain2, sparse_buf, buf_ind);
|
||||
} else {
|
||||
mju_addToScl(jac[0], jac[1], -deriv, nv);
|
||||
}
|
||||
}
|
||||
|
||||
// only one object defined
|
||||
else {
|
||||
// compute position error
|
||||
cpos[0] = pos[0][0] - ref[0] - data[0];
|
||||
|
||||
// jac[0] already has the correct Jacobian
|
||||
}
|
||||
|
||||
size = 1;
|
||||
break;
|
||||
|
||||
case mjEQ_FLEX:
|
||||
flex_edgeadr = m->flex_edgeadr[id[0]];
|
||||
flex_edgenum = m->flex_edgenum[id[0]];
|
||||
// add one constraint per non-rigid edge
|
||||
for (int e=flex_edgeadr; e < flex_edgeadr+flex_edgenum; e++) {
|
||||
// skip rigid
|
||||
if (m->flexedge_rigid[e]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// position error
|
||||
cpos[0] = d->flexedge_length[e] - m->flexedge_length0[e];
|
||||
|
||||
// add constraint: sparse or dense
|
||||
if (issparse) {
|
||||
mj_addConstraint(m, d, d->flexedge_J+d->flexedge_J_rowadr[e], cpos, 0, 0,
|
||||
1, mjCNSTR_EQUALITY, i,
|
||||
d->flexedge_J_rownnz[e],
|
||||
d->flexedge_J_colind+d->flexedge_J_rowadr[e]);
|
||||
} else {
|
||||
mj_addConstraint(m, d, d->flexedge_J+e*nv, cpos, 0, 0,
|
||||
1, mjCNSTR_EQUALITY, i,
|
||||
0, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: // SHOULD NOT OCCUR
|
||||
mjERROR("invalid equality constraint type %d", m->eq_type[i]);
|
||||
}
|
||||
|
||||
// add constraint
|
||||
if (size) {
|
||||
mj_addConstraint(m, d, jac[0], cpos, 0, 0,
|
||||
size, mjCNSTR_EQUALITY, i,
|
||||
issparse ? NV : 0,
|
||||
issparse ? chain : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1388,7 +1390,7 @@ static void getimpedance(const mjtNum* solimp, mjtNum pos, mjtNum margin,
|
||||
yP = solimp[4] * a*power(x, solimp[4]-1);
|
||||
}
|
||||
|
||||
// y(x) = 1-b*(1-x)^p is x>midpoint
|
||||
// y(x) = 1-b*(1-x)^p if x>midpoint
|
||||
else {
|
||||
mjtNum b = 1/power(1-solimp[3], solimp[4]-1);
|
||||
y = 1-b*power(1-x, solimp[4]);
|
||||
@@ -2193,12 +2195,9 @@ void mj_projectConstraint(const mjModel* m, mjData* d) {
|
||||
}
|
||||
|
||||
// pre-count A nonzeros (compute AR_rownnz, AR_rowadr)
|
||||
mju_sqrMatTDSparseCount(d->efc_AR_rownnz, d->efc_AR_rowadr, nefc,
|
||||
BT_rownnz, BT_rowadr, BT_colind,
|
||||
B_rownnz, B_rowadr, B_colind, B_rowsuper, d, /*flg_upper=*/1);
|
||||
|
||||
// nA = total number of nonzeros in A
|
||||
d->nA = d->efc_AR_rownnz[nefc - 1] + d->efc_AR_rowadr[nefc - 1];
|
||||
d->nA = mju_sqrMatTDSparseCount(d->efc_AR_rownnz, d->efc_AR_rowadr, nefc,
|
||||
BT_rownnz, BT_rowadr, BT_colind,
|
||||
B_rownnz, B_rowadr, B_colind, B_rowsuper, d, /*flg_upper=*/1);
|
||||
|
||||
// allocate A values and column indices on arena
|
||||
d->efc_AR = mj_arenaAllocByte(d, sizeof(mjtNum) * d->nA, _Alignof(mjtNum));
|
||||
|
||||
@@ -1469,9 +1469,12 @@ void mj_transmission(const mjModel* m, mjData* d) {
|
||||
|
||||
//-------------------------- inertia ---------------------------------------------------------------
|
||||
|
||||
// add tendon armature to qM
|
||||
// add tendon armature to M
|
||||
void mj_tendonArmature(const mjModel* m, mjData* d) {
|
||||
int nv = m->nv, ntendon = m->ntendon, issparse = mj_isSparse(m);
|
||||
const int* M_rownnz = d->M_rownnz;
|
||||
const int* M_rowadr = d->M_rowadr;
|
||||
const int* M_colind = d->M_colind;
|
||||
|
||||
for (int k=0; k < ntendon; k++) {
|
||||
mjtNum armature = m->tendon_armature[k];
|
||||
@@ -1482,11 +1485,19 @@ void mj_tendonArmature(const mjModel* m, mjData* d) {
|
||||
|
||||
// dense
|
||||
if (!issparse) {
|
||||
// M += armature * ten_J' * ten_J
|
||||
mjtNum* ten_J = d->ten_J + nv*k;
|
||||
for (int i=0; i < m->nv; i++) {
|
||||
int Madr = m->dof_Madr[i];
|
||||
for (int j = i; j >= 0; j = m->dof_parentid[j]) {
|
||||
d->qM[Madr++] += armature * ten_J[j] * ten_J[i];
|
||||
for (int i=0; i < nv; i++) {
|
||||
mjtNum ten_J_i = ten_J[i];
|
||||
if (!ten_J_i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// M[i,:] += armature * ten_J[i] * ten_J
|
||||
int start = M_rowadr[i];
|
||||
int end = start + M_rownnz[i];
|
||||
for (int adr = start; adr < end; adr++) {
|
||||
d->M[adr] += armature * ten_J_i * ten_J[M_colind[adr]];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1494,29 +1505,24 @@ void mj_tendonArmature(const mjModel* m, mjData* d) {
|
||||
// sparse
|
||||
else {
|
||||
// get sparse info for tendon k
|
||||
int rowadr = d->ten_J_rowadr[k];
|
||||
int rownnz = d->ten_J_rownnz[k];
|
||||
const int* colind = d->ten_J_colind + rowadr;
|
||||
mjtNum* ten_J = d->ten_J + rowadr;
|
||||
int J_rowadr = d->ten_J_rowadr[k];
|
||||
int J_rownnz = d->ten_J_rownnz[k];
|
||||
const int* J_colind = d->ten_J_colind + J_rowadr;
|
||||
mjtNum* ten_J = d->ten_J + J_rowadr;
|
||||
|
||||
// iterate forward on nonzero rows i
|
||||
for (int adr_i=0; adr_i < rownnz; adr_i++) {
|
||||
int i = colind[adr_i];
|
||||
int Madr = m->dof_Madr[i];
|
||||
int adr_j = rownnz - 1;
|
||||
|
||||
// iterate backward on ancestors of i, find matching column j
|
||||
for (int j = i; j >= 0; j = m->dof_parentid[j]) {
|
||||
// reduce adr_j until column index is no bigger than j
|
||||
while (colind[adr_j] > j && adr_j >= 0) {
|
||||
adr_j--;
|
||||
}
|
||||
|
||||
// found match, update qM
|
||||
if (colind[adr_j] == j) {
|
||||
d->qM[Madr++] += armature * ten_J[adr_j] * ten_J[adr_i];
|
||||
}
|
||||
// M += armature * ten_J' * ten_J
|
||||
for (int j=0; j < J_rownnz; j++) {
|
||||
mjtNum ten_J_i = ten_J[j];
|
||||
if (!ten_J_i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// M[i,:] += armature * ten_J[i] * ten_J
|
||||
int i = J_colind[j];
|
||||
int M_adr = M_rowadr[i];
|
||||
mju_addToSclSparseInc(d->M + M_adr, ten_J,
|
||||
M_rownnz[i], M_colind + M_adr,
|
||||
J_rownnz, J_colind, armature * ten_J_i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1526,22 +1532,22 @@ void mj_tendonArmature(const mjModel* m, mjData* d) {
|
||||
|
||||
// composite rigid body inertia algorithm
|
||||
void mj_crb(const mjModel* m, mjData* d) {
|
||||
int nv = m->nv;
|
||||
mjtNum buf[6];
|
||||
mjtNum* crb = d->crb;
|
||||
int last_body = m->nbody - 1, nv = m->nv;
|
||||
|
||||
// crb = cinert
|
||||
mju_copy(crb, d->cinert, 10*m->nbody);
|
||||
|
||||
// backward pass over bodies, accumulate composite inertias
|
||||
for (int i=last_body; i > 0; i--) {
|
||||
for (int i=m->nbody - 1; i > 0; i--) {
|
||||
if (m->body_parentid[i] > 0) {
|
||||
mju_addTo(crb+10*m->body_parentid[i], crb+10*i, 10);
|
||||
}
|
||||
}
|
||||
|
||||
// clear qM
|
||||
mju_zero(d->qM, m->nM);
|
||||
// clear M
|
||||
mju_zero(d->M, m->nC);
|
||||
|
||||
// dense forward pass over dofs
|
||||
for (int i=0; i < nv; i++) {
|
||||
@@ -1549,7 +1555,7 @@ void mj_crb(const mjModel* m, mjData* d) {
|
||||
if (m->dof_simplenum[i]) {
|
||||
int n = i + m->dof_simplenum[i];
|
||||
for (; i < n; i++) {
|
||||
d->qM[m->dof_Madr[i]] = m->dof_M0[i];
|
||||
d->M[d->M_rowadr[i]] = m->dof_M0[i];
|
||||
}
|
||||
|
||||
// finish or else fall through with next row
|
||||
@@ -1559,8 +1565,8 @@ void mj_crb(const mjModel* m, mjData* d) {
|
||||
}
|
||||
|
||||
// init M(i,i) with armature inertia
|
||||
int Madr_ij = m->dof_Madr[i];
|
||||
d->qM[Madr_ij] = m->dof_armature[i];
|
||||
int Madr_ij = d->M_rowadr[i] + d->M_rownnz[i] - 1;
|
||||
d->M[Madr_ij] = m->dof_armature[i];
|
||||
|
||||
// precompute buf = crb_body_i * cdof_i
|
||||
mju_mulInertVec(buf, crb+10*m->dof_bodyid[i], d->cdof+6*i);
|
||||
@@ -1568,7 +1574,7 @@ void mj_crb(const mjModel* m, mjData* d) {
|
||||
// sparse backward pass over ancestors
|
||||
for (int j=i; j >= 0; j = m->dof_parentid[j]) {
|
||||
// M(i,j) += cdof_j * (crb_body_i * cdof_i)
|
||||
d->qM[Madr_ij++] += mju_dot(d->cdof+6*j, buf, 6);
|
||||
d->M[Madr_ij--] += mju_dot(d->cdof+6*j, buf, 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1579,7 +1585,7 @@ void mj_makeM(const mjModel* m, mjData* d) {
|
||||
TM_START;
|
||||
mj_crb(m, d);
|
||||
mj_tendonArmature(m, d);
|
||||
mju_gather(d->M, d->qM, d->mapM2M, m->nC);
|
||||
mju_scatter(d->qM, d->M, d->mapM2M, m->nC);
|
||||
TM_END(mjTIMER_POS_INERTIA);
|
||||
}
|
||||
|
||||
|
||||
@@ -173,9 +173,7 @@ void mj_fwdPosition(const mjModel* m, mjData* d) {
|
||||
|
||||
TM_RESTART;
|
||||
mj_makeConstraint(m, d);
|
||||
if (mjENABLED(mjENBL_ISLAND)) {
|
||||
mj_island(m, d);
|
||||
}
|
||||
mj_island(m, d);
|
||||
TM_END(mjTIMER_POS_MAKE);
|
||||
|
||||
TM_RESTART;
|
||||
|
||||
@@ -46,8 +46,8 @@ void mj_invPosition(const mjModel* m, mjData* d) {
|
||||
mj_tendon(m, d);
|
||||
TM_END(mjTIMER_POS_KINEMATICS);
|
||||
|
||||
mj_makeM(m, d); // timed internally (POS_INERTIA)
|
||||
mj_factorM(m, d); // timed internally (POS_INERTIA)
|
||||
mj_makeM(m, d); // timed internally (POS_INERTIA)
|
||||
mj_factorM(m, d); // timed internally (POS_INERTIA)
|
||||
|
||||
mj_collision(m, d); // timed internally (POS_COLLISION)
|
||||
|
||||
@@ -226,15 +226,22 @@ void mj_inverseSkip(const mjModel* m, mjData* d,
|
||||
|
||||
// acceleration-dependent
|
||||
mj_invConstraint(m, d);
|
||||
mj_rne(m, d, 1, d->qfrc_inverse);
|
||||
|
||||
// sum of bias forces in qfrc_inverse = centripetal + Coriolis + tendon bias
|
||||
mj_rne(m, d, 0, d->qfrc_inverse);
|
||||
mj_tendonBias(m, d, d->qfrc_inverse);
|
||||
|
||||
if (!skipsensor) {
|
||||
mj_sensorAcc(m, d);
|
||||
}
|
||||
|
||||
// qfrc_inverse += armature*qacc - qfrc_passive - qfrc_constraint
|
||||
// compute Ma = M*qacc
|
||||
mjtNum* Ma = mjSTACKALLOC(d, nv, mjtNum);
|
||||
mj_mulM(m, d, Ma, d->qacc);
|
||||
|
||||
// qfrc_inverse += Ma - qfrc_passive - qfrc_constraint
|
||||
for (int i=0; i < nv; i++) {
|
||||
d->qfrc_inverse[i] += m->dof_armature[i]*d->qacc[i]
|
||||
- d->qfrc_passive[i] - d->qfrc_constraint[i];
|
||||
d->qfrc_inverse[i] += Ma[i] - d->qfrc_passive[i] - d->qfrc_constraint[i];
|
||||
}
|
||||
|
||||
if (mjENABLED(mjENBL_INVDISCRETE)) {
|
||||
|
||||
@@ -183,6 +183,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.cameraid = -1;
|
||||
vis->global.orthographic = 0;
|
||||
vis->global.fovy = 45;
|
||||
vis->global.ipd = 0.068;
|
||||
@@ -459,7 +460,7 @@ static void freeModelBuffers(mjModel* m) {
|
||||
// allocate and initialize mjModel structure
|
||||
void mj_makeModel(mjModel** dest,
|
||||
int nq, int nv, int nu, int na, int nbody, int nbvh,
|
||||
int nbvhstatic, int nbvhdynamic, int njnt, int ngeom, int nsite, int ncam,
|
||||
int nbvhstatic, int nbvhdynamic, int noct, int njnt, int ngeom, int nsite, int ncam,
|
||||
int nlight, int nflex, int nflexnode, int nflexvert, int nflexedge, int nflexelem,
|
||||
int nflexelemdata, int nflexelemedge, int nflexshelldata, int nflexevpair, int nflextexcoord,
|
||||
int nmesh, int nmeshvert, int nmeshnormal, int nmeshtexcoord, int nmeshface,
|
||||
@@ -498,6 +499,7 @@ void mj_makeModel(mjModel** dest,
|
||||
m->nbvh = nbvh;
|
||||
m->nbvhstatic = nbvhstatic;
|
||||
m->nbvhdynamic = nbvhdynamic;
|
||||
m->noct = noct;
|
||||
m->njnt = njnt;
|
||||
m->ngeom = ngeom;
|
||||
m->nsite = nsite;
|
||||
@@ -638,7 +640,7 @@ mjModel* mj_copyModel(mjModel* dest, const mjModel* src) {
|
||||
if (!dest) {
|
||||
mj_makeModel(&dest,
|
||||
src->nq, src->nv, src->nu, src->na, src->nbody, src->nbvh,
|
||||
src->nbvhstatic, src->nbvhdynamic, src->njnt, src->ngeom, src->nsite,
|
||||
src->nbvhstatic, src->nbvhdynamic, src->noct, src->njnt, src->ngeom, src->nsite,
|
||||
src->ncam, src->nlight, src->nflex, src->nflexnode, src->nflexvert, src->nflexedge,
|
||||
src->nflexelem, src->nflexelemdata, src->nflexelemedge, src->nflexshelldata,
|
||||
src->nflexevpair, src->nflextexcoord, src->nmesh, src->nmeshvert,
|
||||
@@ -834,7 +836,7 @@ mjModel* mj_loadModelBuffer(const void* buffer, int buffer_sz) {
|
||||
ints[42], ints[43], ints[44], ints[45], ints[46], ints[47], ints[48],
|
||||
ints[49], ints[50], ints[51], ints[52], ints[53], ints[54], ints[55],
|
||||
ints[56], ints[57], ints[58], ints[59], ints[60], ints[61], ints[62],
|
||||
ints[63], ints[64], ints[65], ints[66], ints[67], ints[68]);
|
||||
ints[63], ints[64], ints[65], ints[66], ints[67], ints[68], ints[69]);
|
||||
if (!m || m->nbuffer != sizes[getnsize()-1]) {
|
||||
mju_warning("Corrupted model, wrong size parameters");
|
||||
mj_deleteModel(m);
|
||||
@@ -1989,6 +1991,9 @@ static void _resetData(const mjModel* m, mjData* d, unsigned char debug_value) {
|
||||
mju_zero(d->mocap_pos, 3*m->nmocap);
|
||||
mju_zero(d->mocap_quat, 4*m->nmocap);
|
||||
|
||||
// zero out qM, special case because scattering from M skips simple body off-diagonals
|
||||
mju_zero(d->qM, m->nM);
|
||||
|
||||
// copy qpos0 from model
|
||||
if (m->qpos0) {
|
||||
memcpy(d->qpos, m->qpos0, m->nq*sizeof(mjtNum));
|
||||
|
||||
@@ -52,7 +52,7 @@ void mj_defaultStatistic(mjStatistic* stat);
|
||||
|
||||
// allocate mjModel
|
||||
void mj_makeModel(mjModel** dest,
|
||||
int nq, int nv, int nu, int na, int nbody, int nbvh, int nbvhstatic, int nbvhdynamic,
|
||||
int nq, int nv, int nu, int na, int nbody, int nbvh, int nbvhstatic, int nbvhdynamic, int noct,
|
||||
int njnt, int ngeom, int nsite, int ncam, int nlight, int nflex, int nflexnode, int nflexvert,
|
||||
int nflexedge, int nflexelem, int nflexelemdata, int nflexelemedge, int nflexshelldata,
|
||||
int nflexevpair, int nflextexcoord, int nmesh, int nmeshvert, int nmeshnormal,
|
||||
|
||||
+28
-44
@@ -141,29 +141,6 @@ int mj_floodFill(int* island, int nr, const int* rownnz, const int* rowadr, cons
|
||||
|
||||
|
||||
|
||||
// return upper bound on number of tree-tree edges
|
||||
static int countMaxEdge(const mjModel* m, const mjData* d) {
|
||||
int nedge_max = 0;
|
||||
nedge_max += 2*d->ncon; // contact: 2 edges
|
||||
nedge_max += 2*d->ne; // equality: 2 edges
|
||||
nedge_max += d->nl; // limit: 1 edges (always within same tree)
|
||||
nedge_max += d->nf; // joint friction: 1 edge (always within same tree)
|
||||
|
||||
// tendon limits and friction add up to tendon_num edges
|
||||
for (int i=0; i < m->ntendon; i++) {
|
||||
if (m->tendon_frictionloss[i]) {
|
||||
nedge_max += m->tendon_num[i];
|
||||
}
|
||||
if (m->tendon_limited[i]) {
|
||||
nedge_max += m->tendon_num[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nedge_max;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// return id of next tree in Jacobian row i that is different from tree, -1 if not found
|
||||
// start search from *index
|
||||
// write the index of the found tree to *index
|
||||
@@ -242,21 +219,27 @@ static int treeFirst(const mjModel* m, const mjData* d, int tree[2], int i) {
|
||||
if (efc_type == mjCNSTR_CONTACT_FRICTIONLESS ||
|
||||
efc_type == mjCNSTR_CONTACT_PYRAMIDAL ||
|
||||
efc_type == mjCNSTR_CONTACT_ELLIPTIC) {
|
||||
tree[0] = m->body_treeid[m->geom_bodyid[d->contact[efc_id].geom[0]]];
|
||||
tree[1] = m->body_treeid[m->geom_bodyid[d->contact[efc_id].geom[1]]];
|
||||
int g1 = d->contact[efc_id].geom[0];
|
||||
int g2 = d->contact[efc_id].geom[1];
|
||||
|
||||
// handle static bodies
|
||||
if (tree[0] < 0) {
|
||||
if (tree[1] < 0) {
|
||||
mjERROR("contact %d is between two static bodies", efc_id); // SHOULD NOT OCCUR
|
||||
} else {
|
||||
int tmp = tree[0];
|
||||
tree[0] = tree[1];
|
||||
tree[1] = tmp;
|
||||
// no shortcut for flex contacts (handled in the generic case)
|
||||
if (g1 >=0 && g2 >= 0) {
|
||||
tree[0] = m->body_treeid[m->geom_bodyid[g1]];
|
||||
tree[1] = m->body_treeid[m->geom_bodyid[g2]];
|
||||
|
||||
// handle static bodies
|
||||
if (tree[0] < 0) {
|
||||
if (tree[1] < 0) {
|
||||
mjERROR("contact %d is between two static bodies", efc_id); // SHOULD NOT OCCUR
|
||||
} else {
|
||||
int tmp = tree[0];
|
||||
tree[0] = tree[1];
|
||||
tree[1] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// connect or weld constraints
|
||||
@@ -373,9 +356,12 @@ static int findEdges(const mjModel* m, const mjData* d, int* treenedge, int* edg
|
||||
|
||||
int nedge = 0;
|
||||
for (int i=0; i < nefc; i++) {
|
||||
// row i is still in the same constraint: skip
|
||||
// row i is still in the same constraint: skip it,
|
||||
if (efc_type == d->efc_type[i] && efc_id == d->efc_id[i]) {
|
||||
continue;
|
||||
// unless it is a flex equality, where the tree pattern changes per dof
|
||||
if (!(efc_type == mjCNSTR_EQUALITY && m->eq_type[efc_id] == mjEQ_FLEX)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
efc_type = d->efc_type[i];
|
||||
efc_id = d->efc_id[i];
|
||||
@@ -425,21 +411,19 @@ void mj_island(const mjModel* m, mjData* d) {
|
||||
int nv = m->nv, nefc = d->nefc, ntree=m->ntree;
|
||||
|
||||
// no constraints: quick return
|
||||
if (!nefc || m->nflex) { // TODO: add flex support to island discovery
|
||||
d->nisland = 0;
|
||||
d->nidof = 0;
|
||||
if (!mjENABLED(mjENBL_ISLAND) || !nefc) {
|
||||
d->nisland = d->nidof = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
mj_markStack(d);
|
||||
|
||||
// allocate edge array
|
||||
int nedge_max = countMaxEdge(m, d);
|
||||
int* edge = mjSTACKALLOC(d, 2*nedge_max, int);
|
||||
// allocate edge array, nJ is an upper bound
|
||||
int* edge = mjSTACKALLOC(d, 2*d->nJ, int);
|
||||
|
||||
// get tree-tree edges and rownnz counts from efc arrays
|
||||
int* rownnz = mjSTACKALLOC(d, ntree, int); // number of edges per tree
|
||||
int nedge = findEdges(m, d, rownnz, edge, nedge_max);
|
||||
int nedge = findEdges(m, d, rownnz, edge, d->nJ);
|
||||
|
||||
// compute starting address of tree's column indices while resetting rownnz
|
||||
int* rowadr = mjSTACKALLOC(d, ntree, int);
|
||||
|
||||
@@ -1533,15 +1533,14 @@ static void MakeHessian(mjData* d, mjCGContext* ctx) {
|
||||
|
||||
// sparse
|
||||
if (ctx->is_sparse) {
|
||||
// initialize Hessian rowadr, rownnz
|
||||
mju_sqrMatTDSparseCount(ctx->H_rownnz, ctx->H_rowadr, nv,
|
||||
ctx->J_rownnz, ctx->J_rowadr, ctx->J_colind,
|
||||
ctx->JT_rownnz, ctx->JT_rowadr, ctx->JT_colind,
|
||||
ctx->JT_rowsuper, d, /*flg_upper=*/0);
|
||||
// initialize Hessian rowadr, rownnz; get total nonzeros
|
||||
ctx->nH = mju_sqrMatTDSparseCount(ctx->H_rownnz, ctx->H_rowadr, nv,
|
||||
ctx->J_rownnz, ctx->J_rowadr, ctx->J_colind,
|
||||
ctx->JT_rownnz, ctx->JT_rowadr, ctx->JT_colind,
|
||||
ctx->JT_rowsuper, d, /*flg_upper=*/0);
|
||||
|
||||
// add nC to Hessian total nonzeros (unavoidable overcounting since H_colind is still unknown)
|
||||
ctx->nH = ctx->M_rowadr[nv - 1] + ctx->M_rownnz[nv - 1] +
|
||||
ctx->H_rowadr[nv - 1] + ctx->H_rownnz[nv - 1];
|
||||
// add M nonzeros to Hessian total (unavoidable overcounting since H_colind is still unknown)
|
||||
ctx->nH += ctx->M_rowadr[nv - 1] + ctx->M_rownnz[nv - 1];
|
||||
|
||||
// shift H row addresses to make room for C
|
||||
int shift = 0;
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
|
||||
//-------------------------- Constants -------------------------------------------------------------
|
||||
|
||||
#define mjVERSION 333
|
||||
#define mjVERSIONSTRING "3.3.3"
|
||||
#define mjVERSION 334
|
||||
#define mjVERSIONSTRING "3.3.4"
|
||||
|
||||
// names of disable flags
|
||||
const char* mjDISABLESTRING[mjNDISABLE] = {
|
||||
|
||||
@@ -636,11 +636,11 @@ void mju_superSparse(int nr, int* rowsuper,
|
||||
}
|
||||
|
||||
|
||||
// precount res_rownnz and precompute res_rowadr for mju_sqrMatTDSparse
|
||||
void mju_sqrMatTDSparseCount(int* res_rownnz, int* res_rowadr, int nr,
|
||||
const int* rownnz, const int* rowadr, const int* colind,
|
||||
const int* rownnzT, const int* rowadrT, const int* colindT,
|
||||
const int* rowsuperT, mjData* d, int flg_upper) {
|
||||
// precount res_rownnz and precompute res_rowadr for mju_sqrMatTDSparse, return total non-zeros
|
||||
int mju_sqrMatTDSparseCount(int* res_rownnz, int* res_rowadr, int nr,
|
||||
const int* rownnz, const int* rowadr, const int* colind,
|
||||
const int* rownnzT, const int* rowadrT, const int* colindT,
|
||||
const int* rowsuperT, mjData* d, int flg_upper) {
|
||||
mj_markStack(d);
|
||||
int* chain = mjSTACKALLOC(d, 2*nr, int);
|
||||
int nchain = 0;
|
||||
@@ -726,6 +726,8 @@ void mju_sqrMatTDSparseCount(int* res_rownnz, int* res_rowadr, int nr,
|
||||
}
|
||||
|
||||
mj_freeStack(d);
|
||||
|
||||
return res_rowadr[nr-1] + res_rownnz[nr-1];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -120,11 +120,11 @@ MJAPI void mju_sqrMatTDSparse_row(mjtNum* res, const mjtNum* mat, const mjtNum*
|
||||
const int* colindT, const int* rowsuperT,
|
||||
mjData* d, int* diagind);
|
||||
|
||||
// precount res_rownnz and precompute res_rowadr for mju_sqrMatTDSparse
|
||||
MJAPI void mju_sqrMatTDSparseCount(int* res_rownnz, int* res_rowadr, int nr,
|
||||
const int* rownnz, const int* rowadr, const int* colind,
|
||||
const int* rownnzT, const int* rowadrT, const int* colindT,
|
||||
const int* rowsuperT, mjData* d, int flg_upper);
|
||||
// precount res_rownnz and precompute res_rowadr for mju_sqrMatTDSparse, return total non-zeros
|
||||
MJAPI int mju_sqrMatTDSparseCount(int* res_rownnz, int* res_rowadr, int nr,
|
||||
const int* rownnz, const int* rowadr, const int* colind,
|
||||
const int* rownnzT, const int* rowadrT, const int* colindT,
|
||||
const int* rowsuperT, mjData* d, int flg_upper);
|
||||
|
||||
// precompute res_rowadr for mju_sqrMatTDSparse using uncompressed memory
|
||||
MJAPI void mju_sqrMatTDUncompressedInit(int* res_rowadr, int nc);
|
||||
|
||||
@@ -763,7 +763,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
|
||||
if (vopt->flags[mjVIS_MESHBVH]) {
|
||||
for (int geomid = 0; geomid < m->ngeom; geomid++) {
|
||||
int meshid = m->geom_dataid[geomid];
|
||||
if (meshid == -1) {
|
||||
if (m->geom_type[geomid] == mjGEOM_SDF || meshid == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -806,6 +806,43 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
|
||||
}
|
||||
}
|
||||
|
||||
// mesh octree
|
||||
category = mjCAT_DECOR;
|
||||
objtype = mjOBJ_UNKNOWN;
|
||||
if (vopt->flags[mjVIS_MESHBVH]) {
|
||||
for (int geomid = 0; geomid < m->ngeom; geomid++) {
|
||||
int meshid = m->geom_dataid[geomid];
|
||||
if (m->geom_type[geomid] != mjGEOM_SDF || meshid == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int b = 0; b < m->mesh_octnum[meshid]; b++) {
|
||||
int i = b + m->mesh_octadr[meshid];
|
||||
|
||||
START
|
||||
if (m->oct_depth[i] != vopt->bvh_depth) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// box color
|
||||
const float* rgba = m->vis.rgba.bv;
|
||||
|
||||
// get xpos, xmat, size
|
||||
const mjtNum* xpos = d->geom_xpos + 3 * geomid;
|
||||
const mjtNum* xmat = d->geom_xmat + 9 * geomid;
|
||||
const mjtNum *size = m->oct_aabb + 6*i + 3;
|
||||
|
||||
// offset xpos with aabb center (not always at geom origin)
|
||||
const mjtNum *center = m->oct_aabb + 6*i;
|
||||
mjtNum pos[3];
|
||||
mju_mulMatVec3(pos, xmat, center);
|
||||
mju_addTo3(pos, xpos);
|
||||
mjv_initGeom(thisgeom, mjGEOM_LINEBOX, size, pos, xmat, rgba);
|
||||
FINISH
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// inertia
|
||||
objtype = mjOBJ_BODY;
|
||||
if (vopt->flags[mjVIS_INERTIA]) {
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
# Copyright 2025 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
|
||||
#
|
||||
# https://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.
|
||||
|
||||
# --- Global Configuration ---
|
||||
# Plugin target names (used for library and plugInfo.json)
|
||||
set(MJCF_PLUGIN_TARGET_NAME usdMjcf)
|
||||
set(MJC_PHYSICS_PLUGIN_TARGET_NAME mjcPhysics)
|
||||
set(MJ_USD_TARGET_NAME mj_usd)
|
||||
|
||||
# Installation directory for USD plugins
|
||||
set(MJ_USD_INSTALL_DIR_LIB ${CMAKE_INSTALL_LIBDIR}/mujocoUsd)
|
||||
|
||||
# Common OpenUSD libraries
|
||||
set(OPENUSD_CORE_LIBS
|
||||
usd ar kind tf gf vt usdShade usdLux usdGeom usdImaging usdPhysics
|
||||
)
|
||||
|
||||
# We need to set the visibility to default until core type symbol visibility
|
||||
# is resolved in OpenUSD https://github.com/PixarAnimationStudios/OpenUSD/issues/1475
|
||||
set(DEFAULT_CXX_VISIBILITY_PROPS
|
||||
CXX_VISIBILITY_PRESET default
|
||||
)
|
||||
|
||||
# --- Helper Functions ---
|
||||
function(configure_and_install_usd_plugin_info plugin_name source_subpath install_base_dir)
|
||||
# Determine shared library prefix
|
||||
if(CMAKE_SHARED_LIBRARY_PREFIX)
|
||||
set(LIB_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX})
|
||||
else()
|
||||
set(LIB_PREFIX "")
|
||||
endif()
|
||||
|
||||
set(PLUG_INFO_LIBRARY_PATH "../../${LIB_PREFIX}${plugin_name}${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
set(OUTPUT_DIR "${CMAKE_BINARY_DIR}/${install_base_dir}/resources/${plugin_name}")
|
||||
set(OUTPUT_FILE "${OUTPUT_DIR}/plugInfo.json")
|
||||
|
||||
# Create the output directory if it doesn't exist
|
||||
file(MAKE_DIRECTORY "${OUTPUT_DIR}")
|
||||
|
||||
# Configure the plugInfo.json file to replace @PLUG_INFO_LIBRARY_PATH@ instances.
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${source_subpath}/plugInfo.json"
|
||||
"${OUTPUT_FILE}"
|
||||
@ONLY
|
||||
)
|
||||
|
||||
install(FILES "${OUTPUT_FILE}"
|
||||
DESTINATION "${install_base_dir}/resources/${plugin_name}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# Function to apply Houdini-specific link directories and include paths
|
||||
function(configure_houdini_target target_name link_scope include_scope)
|
||||
set(HOUDINI_LIBS_DIR "${HOUDINI_HFS_DIR}/../Libraries")
|
||||
get_filename_component(HOUDINI_LIBS_DIR "${HOUDINI_LIBS_DIR}" ABSOLUTE) # Normalize the path
|
||||
|
||||
# Assume everyone using Houdini on 3.11 for now.
|
||||
set(USD_MJCF_PYTHON_LIB python3.11)
|
||||
set(USD_MJCF_PYTHON_LIB_NUMBER python311) # For boost library names
|
||||
set(PYTHON_LIB "${HOUDINI_HFS_DIR}/Frameworks/Python.framework/Versions/3.11/Python")
|
||||
set(PXR_LIB_PREFIX "pxr_")
|
||||
|
||||
# Houdini-specific PXR and other libraries
|
||||
set(HOUDINI_SPECIFIC_LIBS
|
||||
${PXR_LIB_PREFIX}usd
|
||||
${PXR_LIB_PREFIX}ar
|
||||
${PXR_LIB_PREFIX}kind
|
||||
${PXR_LIB_PREFIX}tf
|
||||
${PXR_LIB_PREFIX}gf
|
||||
${PXR_LIB_PREFIX}vt
|
||||
${PXR_LIB_PREFIX}sdf
|
||||
${PXR_LIB_PREFIX}usdShade
|
||||
${PXR_LIB_PREFIX}usdLux
|
||||
${PXR_LIB_PREFIX}usdGeom
|
||||
${PXR_LIB_PREFIX}usdImaging
|
||||
${PXR_LIB_PREFIX}usdPhysics
|
||||
tbb
|
||||
hboost_${USD_MJCF_PYTHON_LIB_NUMBER}
|
||||
${PYTHON_LIB}
|
||||
)
|
||||
|
||||
target_link_directories(${target_name} ${link_scope} ${HOUDINI_LIBS_DIR})
|
||||
target_include_directories(${target_name} ${include_scope}
|
||||
"${HOUDINI_HFS_DIR}/toolkit/include"
|
||||
"${HOUDINI_HFS_DIR}/toolkit/include/python3.11"
|
||||
)
|
||||
target_link_libraries(${target_name} ${link_scope}
|
||||
${HOUDINI_SPECIFIC_LIBS}
|
||||
mujoco
|
||||
tinyxml2
|
||||
)
|
||||
endfunction()
|
||||
|
||||
## usdMjcf
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
|
||||
# The list of RPATHs:
|
||||
# 1. $ORIGIN: For libmjcPhysics.so (since it's in the same install dir)
|
||||
# 2. Path to OpenUSD libraries: Typically ${USD_DIR}/lib
|
||||
# 3. Path to MuJoCo library: Assuming it's in ${MUJOCO_INSTALL_DIR}/lib
|
||||
if(APPLE)
|
||||
set(RPATH_LIST "@loader_path")
|
||||
# Add OpenUSD lib to RPATH for macOS
|
||||
if(DEFINED USD_DIR AND EXISTS "${USD_DIR}/lib")
|
||||
list(APPEND RPATH_LIST "${USD_DIR}/lib")
|
||||
endif()
|
||||
# Add MuJoCo lib to RPATH for macOS
|
||||
if(DEFINED MUJOCO_INSTALL_DIR AND EXISTS "${MUJOCO_INSTALL_DIR}/lib")
|
||||
list(APPEND RPATH_LIST "${MUJOCO_INSTALL_DIR}/lib")
|
||||
endif()
|
||||
|
||||
string(JOIN ":" CMAKE_INSTALL_RPATH "${RPATH_LIST}") # macOS uses colon for RPATH separator
|
||||
message(STATUS "Final CMAKE_INSTALL_RPATH: ${CMAKE_INSTALL_RPATH}")
|
||||
elseif(UNIX)
|
||||
|
||||
# For adjacent libs.
|
||||
set(RPATH_LIST "\$ORIGIN")
|
||||
|
||||
# Add OpenUSD library directory
|
||||
if(DEFINED USD_DIR AND EXISTS "${USD_DIR}/lib")
|
||||
list(APPEND RPATH_LIST "${USD_DIR}/lib")
|
||||
message(STATUS "Adding OpenUSD lib to RPATH: ${USD_DIR}/lib")
|
||||
else()
|
||||
message(WARNING "USD_DIR is not defined or ${USD_DIR}/lib does not exist. OpenUSD libraries might not be found via RPATH.")
|
||||
endif()
|
||||
|
||||
# Add MuJoCo library directory
|
||||
if(DEFINED MUJOCO_INSTALL_DIR AND EXISTS "${MUJOCO_INSTALL_DIR}/lib")
|
||||
list(APPEND RPATH_LIST "${MUJOCO_INSTALL_DIR}/lib")
|
||||
message(STATUS "Adding MuJoCo lib to RPATH: ${MUJOCO_INSTALL_DIR}/lib")
|
||||
elseif(DEFINED MUJOCO_INSTALL_DIR AND EXISTS "${MUJOCO_INSTALL_DIR}/bin")
|
||||
list(APPEND RPATH_LIST "${MUJOCO_INSTALL_DIR}/bin")
|
||||
message(STATUS "Adding MuJoCo bin to RPATH: ${MUJOCO_INSTALL_DIR}/bin")
|
||||
endif()
|
||||
|
||||
# Set the final RPATH for installation
|
||||
string(JOIN ";" CMAKE_INSTALL_RPATH "${RPATH_LIST}")
|
||||
message(STATUS "Final CMAKE_INSTALL_RPATH: ${CMAKE_INSTALL_RPATH}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
|
||||
add_library(${MJCF_PLUGIN_TARGET_NAME} SHARED)
|
||||
add_library(mujoco::usd::mjcf ALIAS ${MJCF_PLUGIN_TARGET_NAME})
|
||||
target_sources(${MJCF_PLUGIN_TARGET_NAME} PRIVATE
|
||||
plugins/mjcf/mjcf_file_format.cc
|
||||
plugins/mjcf/mjcf_file_format.h
|
||||
plugins/mjcf/mujoco_to_usd.cc
|
||||
plugins/mjcf/mujoco_to_usd.h
|
||||
plugins/mjcf/utils.cc
|
||||
plugins/mjcf/utils.h
|
||||
)
|
||||
set_target_properties(${MJCF_PLUGIN_TARGET_NAME} PROPERTIES
|
||||
OUTPUT_NAME ${MJCF_PLUGIN_TARGET_NAME}
|
||||
${DEFAULT_CXX_VISIBILITY_PROPS}
|
||||
)
|
||||
target_include_directories(${MJCF_PLUGIN_TARGET_NAME} PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/plugins"
|
||||
)
|
||||
|
||||
## mjcPhysics
|
||||
|
||||
add_library(${MJC_PHYSICS_PLUGIN_TARGET_NAME} SHARED)
|
||||
target_sources(${MJC_PHYSICS_PLUGIN_TARGET_NAME} PRIVATE
|
||||
mjcPhysics/actuatorAPI.cpp
|
||||
mjcPhysics/collisionAPI.cpp
|
||||
mjcPhysics/meshCollisionAPI.cpp
|
||||
mjcPhysics/sceneAPI.cpp
|
||||
mjcPhysics/siteAPI.cpp
|
||||
mjcPhysics/tokens.cpp
|
||||
)
|
||||
set_target_properties(${MJC_PHYSICS_PLUGIN_TARGET_NAME} PROPERTIES
|
||||
OUTPUT_NAME ${MJC_PHYSICS_PLUGIN_TARGET_NAME}
|
||||
${DEFAULT_CXX_VISIBILITY_PROPS}
|
||||
)
|
||||
target_include_directories(${MJC_PHYSICS_PLUGIN_TARGET_NAME} PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/mjcPhysics"
|
||||
)
|
||||
|
||||
## mj_usd
|
||||
|
||||
add_library(${MJ_USD_TARGET_NAME} SHARED)
|
||||
add_library(mujoco::usd ALIAS ${MJ_USD_TARGET_NAME})
|
||||
target_sources(${MJ_USD_TARGET_NAME} PRIVATE
|
||||
writer.cc
|
||||
layer_sink.cc
|
||||
usd_to_mjspec.cc
|
||||
utils.cc
|
||||
)
|
||||
|
||||
|
||||
if (USD_DIR)
|
||||
find_package(pxr REQUIRED)
|
||||
|
||||
target_link_libraries(${MJC_PHYSICS_PLUGIN_TARGET_NAME} PRIVATE
|
||||
${OPENUSD_CORE_LIBS}
|
||||
mujoco
|
||||
tinyxml2
|
||||
)
|
||||
|
||||
target_link_libraries(${MJCF_PLUGIN_TARGET_NAME} PRIVATE
|
||||
${OPENUSD_CORE_LIBS}
|
||||
mujoco
|
||||
tinyxml2
|
||||
${MJC_PHYSICS_PLUGIN_TARGET_NAME}
|
||||
)
|
||||
|
||||
target_link_libraries(${MJ_USD_TARGET_NAME} PUBLIC
|
||||
${OPENUSD_CORE_LIBS}
|
||||
mujoco
|
||||
tinyxml2
|
||||
${MJC_PHYSICS_PLUGIN_TARGET_NAME}
|
||||
)
|
||||
elseif (HOUDINI_HFS_DIR)
|
||||
message(STATUS "Configuring for Houdini target...")
|
||||
|
||||
# In Houdini, the Houdini package we would typically use via find_package
|
||||
# does not have all the USD dependencies that we need (namely UsdPhysics)
|
||||
# so we need to manually link all the required libraries.
|
||||
configure_houdini_target(${MJC_PHYSICS_PLUGIN_TARGET_NAME} PRIVATE PRIVATE)
|
||||
configure_houdini_target(${MJCF_PLUGIN_TARGET_NAME} PRIVATE PRIVATE)
|
||||
configure_houdini_target(${MJ_USD_TARGET_NAME} PUBLIC PUBLIC)
|
||||
|
||||
# Re-add inter-plugin dependencies after Houdini-specific linking
|
||||
target_link_libraries(${MJCF_PLUGIN_TARGET_NAME} PRIVATE ${MJC_PHYSICS_PLUGIN_TARGET_NAME})
|
||||
target_link_libraries(${MJ_USD_TARGET_NAME} PUBLIC ${MJC_PHYSICS_PLUGIN_TARGET_NAME})
|
||||
|
||||
endif()
|
||||
|
||||
## Installation
|
||||
|
||||
message(STATUS "Mujoco USD plugins will be installed to: ${CMAKE_INSTALL_PREFIX}/${MJ_USD_INSTALL_DIR_LIB}")
|
||||
message(STATUS "Make sure PXR_PLUGINPATH_NAME includes: ${CMAKE_INSTALL_PREFIX}/${MJ_USD_INSTALL_DIR_LIB}/*/resources")
|
||||
|
||||
# Generate and install plugInfo.json for each plugin
|
||||
configure_and_install_usd_plugin_info(
|
||||
${MJCF_PLUGIN_TARGET_NAME}
|
||||
plugins/mjcf
|
||||
${MJ_USD_INSTALL_DIR_LIB}
|
||||
)
|
||||
configure_and_install_usd_plugin_info(
|
||||
${MJC_PHYSICS_PLUGIN_TARGET_NAME}
|
||||
mjcPhysics
|
||||
${MJ_USD_INSTALL_DIR_LIB}
|
||||
)
|
||||
|
||||
# Install specific resources that are not plugInfo.json (like generatedSchema.usda)
|
||||
install(FILES
|
||||
mjcPhysics/generatedSchema.usda
|
||||
DESTINATION ${MJ_USD_INSTALL_DIR_LIB}/resources/mjcPhysics
|
||||
)
|
||||
|
||||
# Install shared libraries
|
||||
install(TARGETS
|
||||
${MJCF_PLUGIN_TARGET_NAME}
|
||||
${MJC_PHYSICS_PLUGIN_TARGET_NAME}
|
||||
${MJ_USD_TARGET_NAME}
|
||||
LIBRARY DESTINATION ${MJ_USD_INSTALL_DIR_LIB}
|
||||
)
|
||||
@@ -0,0 +1,132 @@
|
||||
// Copyright 2025 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.
|
||||
|
||||
#include <mujoco/experimental/usd/layer_sink.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <mujoco/mujoco.h>
|
||||
#include <pxr/base/gf/declare.h>
|
||||
#include <pxr/base/gf/matrix4d.h>
|
||||
#include <pxr/base/gf/quaternion.h>
|
||||
#include <pxr/base/gf/rotation.h>
|
||||
#include <pxr/base/gf/transform.h>
|
||||
#include <pxr/base/tf/staticTokens.h>
|
||||
#include <pxr/base/tf/token.h>
|
||||
#include <pxr/base/vt/types.h>
|
||||
#include <pxr/base/vt/value.h>
|
||||
#include <pxr/pxr.h>
|
||||
#include <pxr/usd/sdf/attributeSpec.h>
|
||||
#include <pxr/usd/sdf/changeBlock.h>
|
||||
#include <pxr/usd/sdf/childrenPolicies.h>
|
||||
#include <pxr/usd/sdf/primSpec.h>
|
||||
#include <pxr/usd/sdf/types.h>
|
||||
#include <pxr/usd/sdf/valueTypeName.h>
|
||||
#include <pxr/usd/usd/common.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
#include <pxr/usd/usd/timeCode.h>
|
||||
#include <pxr/usd/usdGeom/tokens.h>
|
||||
#include <pxr/usd/usdGeom/xformCache.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
TF_DEFINE_PRIVATE_TOKENS(_layer_sink_tokens,
|
||||
((xformOpTransform,
|
||||
"xformOp:transform:mujoco"))(Xform));
|
||||
PXR_NAMESPACE_CLOSE_SCOPE
|
||||
|
||||
namespace {
|
||||
pxr::SdfAttributeSpecHandle GetOrCreateAttribute(
|
||||
pxr::SdfLayerHandle layer, pxr::SdfPrimSpecHandle prim_spec,
|
||||
const pxr::SdfPath& path, const pxr::TfToken& token,
|
||||
const pxr::SdfValueTypeName& type, pxr::SdfVariability variability) {
|
||||
// Find or create transform attribute.
|
||||
pxr::SdfAttributeSpecHandle attr =
|
||||
layer->GetAttributeAtPath(path.AppendProperty(token));
|
||||
|
||||
if (!attr) {
|
||||
attr = pxr::SdfAttributeSpec::New(prim_spec, token, type, variability);
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mujoco {
|
||||
namespace usd {
|
||||
LayerSink::LayerSink(pxr::UsdStageRefPtr stage) : stage_(stage) {}
|
||||
|
||||
void LayerSink::Update(const mjData* const data,
|
||||
std::vector<pxr::SdfPath> body_paths) {
|
||||
pxr::SdfLayerHandle layer = stage_->GetEditTarget().GetLayer();
|
||||
|
||||
pxr::UsdTimeCode timecode = data->time * layer->GetTimeCodesPerSecond();
|
||||
pxr::UsdGeomXformCache xform_cache(timecode);
|
||||
|
||||
pxr::SdfChangeBlock change_block;
|
||||
// TODO(shaves) this can be parallelised.
|
||||
for (int i = 0; i < body_paths.size(); i++) {
|
||||
const pxr::SdfPath& path = body_paths[i];
|
||||
|
||||
// Author transform timesample
|
||||
// Convert pose data.
|
||||
mjtNum* xpos = &data->xpos[i * 3];
|
||||
mjtNum* xquat = &data->xquat[i * 4];
|
||||
pxr::GfVec3d translation(xpos[0], xpos[1], xpos[2]);
|
||||
pxr::GfVec3d imag_part(xquat[1], xquat[2], xquat[3]);
|
||||
// Some bodies such as the world body don't have mapped USD prims to
|
||||
// transform.
|
||||
if (path.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pxr::SdfPrimSpecHandle prim_spec = pxr::SdfCreatePrimInLayer(layer, path);
|
||||
|
||||
// Find or create transform attribute.
|
||||
pxr::SdfAttributeSpecHandle xform_attr = GetOrCreateAttribute(
|
||||
layer, prim_spec, path, pxr::_layer_sink_tokens->xformOpTransform,
|
||||
pxr::SdfValueTypeNames->Matrix4d, pxr::SdfVariabilityVarying);
|
||||
|
||||
pxr::GfQuaternion quat(xquat[0], imag_part);
|
||||
pxr::GfRotation rotation(quat);
|
||||
|
||||
// Identities
|
||||
pxr::GfVec3d scale(1.0);
|
||||
pxr::GfVec3d pivot_position(0);
|
||||
pxr::GfRotation pivot_rotation(pxr::GfQuaternion::GetIdentity());
|
||||
|
||||
// Set time sample
|
||||
pxr::GfTransform xform(translation, rotation, scale, pivot_position,
|
||||
pivot_rotation);
|
||||
pxr::GfMatrix4d parent_xform =
|
||||
xform_cache.GetParentToWorldTransform(stage_->GetPrimAtPath(path));
|
||||
pxr::GfMatrix4d relative_xform =
|
||||
xform.GetMatrix() * parent_xform.GetInverse();
|
||||
layer->SetTimeSample(xform_attr->GetPath(), timecode.GetValue(),
|
||||
relative_xform);
|
||||
|
||||
// Create xformop_order attribute if missing.
|
||||
pxr::SdfAttributeSpecHandle op_order_attr = GetOrCreateAttribute(
|
||||
layer, prim_spec, path, pxr::UsdGeomTokens->xformOpOrder,
|
||||
pxr::SdfValueTypeNames->TokenArray, pxr::SdfVariabilityUniform);
|
||||
|
||||
// Override all local transforms so that this is the absolute position.
|
||||
// We don't reset the xform stack here, so parent transforms will still
|
||||
// affect the world pose.
|
||||
const pxr::VtTokenArray xformop_order(
|
||||
{pxr::_layer_sink_tokens->xformOpTransform});
|
||||
|
||||
op_order_attr->SetDefaultValue(pxr::VtValue(xformop_order));
|
||||
}
|
||||
}
|
||||
} // namespace usd
|
||||
} // namespace mujoco
|
||||
@@ -12,12 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "./actuatorAPI.h"
|
||||
#include <mujoco/experimental/usd/mjcPhysics/actuatorAPI.h>
|
||||
|
||||
#include "pxr/usd/sdf/assetPath.h"
|
||||
#include "pxr/usd/sdf/types.h"
|
||||
#include "pxr/usd/usd/schemaRegistry.h"
|
||||
#include "pxr/usd/usd/typed.h"
|
||||
#include <pxr/usd/sdf/assetPath.h>
|
||||
#include <pxr/usd/sdf/types.h>
|
||||
#include <pxr/usd/usd/schemaRegistry.h>
|
||||
#include <pxr/usd/usd/typed.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
@@ -325,15 +325,6 @@ UsdRelationship MjcPhysicsActuatorAPI::CreateMjcRefSiteRel() const {
|
||||
/* custom = */ false);
|
||||
}
|
||||
|
||||
UsdRelationship MjcPhysicsActuatorAPI::GetMjcCrankSiteRel() const {
|
||||
return GetPrim().GetRelationship(MjcPhysicsTokens->mjcCrankSite);
|
||||
}
|
||||
|
||||
UsdRelationship MjcPhysicsActuatorAPI::CreateMjcCrankSiteRel() const {
|
||||
return GetPrim().CreateRelationship(MjcPhysicsTokens->mjcCrankSite,
|
||||
/* custom = */ false);
|
||||
}
|
||||
|
||||
UsdRelationship MjcPhysicsActuatorAPI::GetMjcSliderSiteRel() const {
|
||||
return GetPrim().GetRelationship(MjcPhysicsTokens->mjcSliderSite);
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "./collisionAPI.h"
|
||||
#include <mujoco/experimental/usd/mjcPhysics/collisionAPI.h>
|
||||
|
||||
#include "pxr/usd/sdf/assetPath.h"
|
||||
#include "pxr/usd/sdf/types.h"
|
||||
#include "pxr/usd/usd/schemaRegistry.h"
|
||||
#include "pxr/usd/usd/typed.h"
|
||||
#include <pxr/usd/sdf/assetPath.h>
|
||||
#include <pxr/usd/sdf/types.h>
|
||||
#include <pxr/usd/usd/schemaRegistry.h>
|
||||
#include <pxr/usd/usd/typed.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
|
||||
@@ -277,9 +277,6 @@ class "PhysicsActuatorAPI" (
|
||||
uniform double mjc:crankLength = 0 (
|
||||
doc = "Used only for the slider-crank transmission type. Specifies the length of the connecting rod. The compiler expects this value to be positive when a slider-crank transmission is present."
|
||||
)
|
||||
rel mjc:crankSite (
|
||||
doc = "If specified, the actuator acts on a slider-crank mechanism which is implicitly determined by the actuator (i.e., it is not a separate model element). The target site corresponds to the pin joining the crank and the connecting rod."
|
||||
)
|
||||
uniform token mjc:ctrlLimited = "auto" (
|
||||
allowedTokens = ["false", "true", "auto"]
|
||||
doc = "If true, the control input to this actuator is automatically clamped to ctrlrange at runtime. If false, control input clamping is disabled. If 'auto' and autolimits is set in compiler, control clamping will automatically be set to true if ctrlrange is defined without explicitly setting this attribute to 'true'. Note that control input clamping can also be globally disabled with the clampctrl attribute of option/flag."
|
||||
@@ -334,3 +331,82 @@ class "PhysicsActuatorAPI" (
|
||||
)
|
||||
}
|
||||
|
||||
class Keyframe "Keyframe" (
|
||||
doc = "Represents time independent keyframe values."
|
||||
)
|
||||
{
|
||||
double[] mjc:act (
|
||||
doc = "Vector of actuator activations, copied into mjData.act when the simulation state is set to this keyframe."
|
||||
)
|
||||
double[] mjc:ctrl (
|
||||
doc = "Vector of controls, copied into mjData.ctrl when the simulation state is set to this keyframe."
|
||||
)
|
||||
double[] mjc:mpos (
|
||||
doc = "Vector of mocap body positions, copied into mjData.mocap_pos when the simulation state is set to this keyframe."
|
||||
)
|
||||
double[] mjc:mquat (
|
||||
doc = "Vector of mocap body quaternions, copied into mjData.mocap_quat when the simulation state is set to this keyframe."
|
||||
)
|
||||
double[] mjc:qpos (
|
||||
doc = "Vector of joint positions, copied into mjData.qpos when the simulation state is set to this keyframe."
|
||||
)
|
||||
double[] mjc:qvel (
|
||||
doc = "Vector of joint velocities, copied into mjData.qvel when the simulation state is set to this keyframe."
|
||||
)
|
||||
}
|
||||
|
||||
class "PhysicsJointsAPI" (
|
||||
doc = "API describing a Mujoco joint."
|
||||
)
|
||||
{
|
||||
uniform token mjc:actuatorfrclimited = "auto" (
|
||||
allowedTokens = ["false", "true", "auto"]
|
||||
doc = "This attribute specifies whether actuator forces acting on the joint should be clamped. See Force limits for details. It is available only for scalar joints (hinge and slider) and ignored for ball and free joints. This attribute interacts with the actuatorfrcrange attribute. If this attribute is 'false', actuator force clamping is disabled. If it is 'true', actuator force clamping is enabled. If this attribute is 'auto', and autolimits is set in compiler, actuator force clamping will be enabled if actuatorfrcrange is defined."
|
||||
)
|
||||
uniform double mjc:actuatorfrcrange:max = 0 (
|
||||
doc = "Maximum range for clamping total actuator forces acting on this joint. See Force limits for details. It is available only for scalar joints (hinge and slider) and ignored for ball and free joints. The compiler expects the first value to be smaller than the second value. Setting this attribute without specifying actuatorfrclimited is an error if compiler-autolimits is 'false'."
|
||||
)
|
||||
uniform double mjc:actuatorfrcrange:min = 0 (
|
||||
doc = "Minimum range for clamping total actuator forces acting on this joint. See Force limits for details. It is available only for scalar joints (hinge and slider) and ignored for ball and free joints. The compiler expects the first value to be smaller than the second value. Setting this attribute without specifying actuatorfrclimited is an error if compiler-autolimits is 'false'."
|
||||
)
|
||||
uniform bool mjc:actuatorgravcomp = 0 (
|
||||
doc = "If this flag is enabled, gravity compensation applied to this joint is added to actuator forces (mjData.qfrc_actuator) rather than passive forces (mjData.qfrc_passive). Notionally, this means that gravity compensation is the result of a control system rather than natural buoyancy. In practice, enabling this flag is useful when joint-level actuator force clamping is used. In this case, the total actuation force applied on a joint, including gravity compensation, is guaranteed to not exceed the specified limits. See Force limits and actuatorfrcrange for more details on this type of force limit."
|
||||
)
|
||||
uniform double mjc:armature = 0 (
|
||||
doc = "Additional inertia associated with movement of the joint that is not due to body mass. This added inertia is usually due to a rotor (a.k.a armature) spinning faster than the joint itself due to a geared transmission. The value applies to all degrees of freedom created by this joint. Besides increasing the realism of joints with geared transmission, positive armature significantly improves simulation stability, even for small values, and is a recommended possible fix when encountering stability issues."
|
||||
)
|
||||
uniform double mjc:damping = 0 (
|
||||
doc = "Damping applied to all degrees of freedom created by this joint. Unlike friction loss which is computed by the constraint solver, damping is simply a force linear in velocity. It is included in the passive forces. Despite this simplicity, larger damping values can make numerical integrators unstable, which is why our Euler integrator handles damping implicitly. See Integration in the Computation chapter."
|
||||
)
|
||||
uniform double mjc:frictionloss = 0 (
|
||||
doc = "Friction loss due to dry friction. This value is the same for all degrees of freedom created by this joint. Semantically friction loss does not make sense for free joints, but the compiler allows it. To enable friction loss, set this attribute to a positive value."
|
||||
)
|
||||
uniform double mjc:margin = 0 (
|
||||
doc = "The distance threshold below which limits become active. Recall that the Constraint solver normally generates forces as soon as a constraint becomes active, even if the margin parameter makes that happen at a distance. This attribute together with solreflimit and solimplimit can be used to model a soft joint limit."
|
||||
)
|
||||
uniform double mjc:ref = 0 (
|
||||
doc = "The reference position or angle of the joint. This attribute is only used for slide and hinge joints. It defines the joint value corresponding to the initial model configuration. The amount of spatial transformation that the joint applies at runtime equals the current joint value stored in mjData.qpos minus this reference value stored in mjModel.qpos0. The meaning of these vectors was discussed in the Stand-alone section in the Overview chapter."
|
||||
)
|
||||
uniform double[] mjc:solimpfriction = [0.9, 0.95, 0.001, 0.5, 2] (
|
||||
doc = "Constraint solver parameters for simulating dry friction."
|
||||
)
|
||||
uniform double[] mjc:solimplimit = [0.9, 0.95, 0.001, 0.5, 2] (
|
||||
doc = "Constraint solver parameters for simulating joint limits."
|
||||
)
|
||||
uniform double[] mjc:solreffriction = [0.02, 1] (
|
||||
doc = "Constraint solver parameters for simulating dry friction."
|
||||
)
|
||||
uniform double[] mjc:solreflimit = [0.02, 1] (
|
||||
doc = "Constraint solver parameters for simulating joint limits."
|
||||
)
|
||||
uniform double[] mjc:springdamper = [0, 0] (
|
||||
doc = "When both numbers are positive, the compiler will override any stiffness and damping values specified with the attributes below, and will instead set them automatically so that the resulting mass-spring-damper for this joint has the desired time constant (first value) and damping ratio (second value). This is done by taking into account the joint inertia in the model reference configuration. Note that the format is the same as the solref parameter of the constraint solver."
|
||||
)
|
||||
uniform double mjc:springref = 0 (
|
||||
doc = "The joint position or angle in which the joint spring (if any) achieves equilibrium. Similar to the vector mjModel.qpos0 which stores all joint reference values specified with the ref attribute above, all spring reference values specified with this attribute are stored in the vector mjModel.qpos_spring. The model configuration corresponding to mjModel.qpos_spring is also used to compute the spring reference lengths of all tendons, stored in mjModel.tendon_lengthspring. This is because tendons can also have springs."
|
||||
)
|
||||
uniform double mjc:stiffness = 0 (
|
||||
doc = "Joint stiffness. If this value is positive, a spring will be created with equilibrium position given by springref below. The spring force is computed along with the other passive forces."
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
// Copyright 2025 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.
|
||||
|
||||
#include <mujoco/experimental/usd/mjcPhysics/jointAPI.h>
|
||||
|
||||
#include <pxr/usd/sdf/assetPath.h>
|
||||
#include <pxr/usd/sdf/types.h>
|
||||
#include <pxr/usd/usd/schemaRegistry.h>
|
||||
#include <pxr/usd/usd/typed.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
// Register the schema with the TfType system.
|
||||
TF_REGISTRY_FUNCTION(TfType) {
|
||||
TfType::Define<MjcPhysicsJointAPI, TfType::Bases<UsdAPISchemaBase> >();
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
MjcPhysicsJointAPI::~MjcPhysicsJointAPI() {}
|
||||
|
||||
/* static */
|
||||
MjcPhysicsJointAPI MjcPhysicsJointAPI::Get(const UsdStagePtr &stage,
|
||||
const SdfPath &path) {
|
||||
if (!stage) {
|
||||
TF_CODING_ERROR("Invalid stage");
|
||||
return MjcPhysicsJointAPI();
|
||||
}
|
||||
return MjcPhysicsJointAPI(stage->GetPrimAtPath(path));
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
UsdSchemaKind MjcPhysicsJointAPI::_GetSchemaKind() const {
|
||||
return MjcPhysicsJointAPI::schemaKind;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool MjcPhysicsJointAPI::CanApply(const UsdPrim &prim, std::string *whyNot) {
|
||||
return prim.CanApplyAPI<MjcPhysicsJointAPI>(whyNot);
|
||||
}
|
||||
|
||||
/* static */
|
||||
MjcPhysicsJointAPI MjcPhysicsJointAPI::Apply(const UsdPrim &prim) {
|
||||
if (prim.ApplyAPI<MjcPhysicsJointAPI>()) {
|
||||
return MjcPhysicsJointAPI(prim);
|
||||
}
|
||||
return MjcPhysicsJointAPI();
|
||||
}
|
||||
|
||||
/* static */
|
||||
const TfType &MjcPhysicsJointAPI::_GetStaticTfType() {
|
||||
static TfType tfType = TfType::Find<MjcPhysicsJointAPI>();
|
||||
return tfType;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool MjcPhysicsJointAPI::_IsTypedSchema() {
|
||||
static bool isTyped = _GetStaticTfType().IsA<UsdTyped>();
|
||||
return isTyped;
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
const TfType &MjcPhysicsJointAPI::_GetTfType() const {
|
||||
return _GetStaticTfType();
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcSpringdamperAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcSpringdamper);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcSpringdamperAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcSpringdamper, SdfValueTypeNames->DoubleArray,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcSolreflimitAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcSolreflimit);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcSolreflimitAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcSolreflimit, SdfValueTypeNames->DoubleArray,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcSolimplimitAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcSolimplimit);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcSolimplimitAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcSolimplimit, SdfValueTypeNames->DoubleArray,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcSolreffrictionAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcSolreffriction);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcSolreffrictionAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcSolreffriction, SdfValueTypeNames->DoubleArray,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcSolimpfrictionAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcSolimpfriction);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcSolimpfrictionAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcSolimpfriction, SdfValueTypeNames->DoubleArray,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcStiffnessAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcStiffness);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcStiffnessAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcStiffness, SdfValueTypeNames->Double,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcActuatorfrcrangeMinAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcActuatorfrcrangeMin);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcActuatorfrcrangeMinAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcActuatorfrcrangeMin, SdfValueTypeNames->Double,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcActuatorfrcrangeMaxAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcActuatorfrcrangeMax);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcActuatorfrcrangeMaxAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcActuatorfrcrangeMax, SdfValueTypeNames->Double,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcActuatorfrclimitedAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcActuatorfrclimited);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcActuatorfrclimitedAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcActuatorfrclimited, SdfValueTypeNames->Token,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcActuatorgravcompAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcActuatorgravcomp);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcActuatorgravcompAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcActuatorgravcomp, SdfValueTypeNames->Bool,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcMarginAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcMargin);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcMarginAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcMargin, SdfValueTypeNames->Double,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcRefAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcRef);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcRefAttr(VtValue const &defaultValue,
|
||||
bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcRef, SdfValueTypeNames->Double,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcSpringrefAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcSpringref);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcSpringrefAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcSpringref, SdfValueTypeNames->Double,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcArmatureAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcArmature);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcArmatureAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcArmature, SdfValueTypeNames->Double,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcDampingAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcDamping);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcDampingAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcDamping, SdfValueTypeNames->Double,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::GetMjcFrictionlossAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcFrictionloss);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsJointAPI::CreateMjcFrictionlossAttr(
|
||||
VtValue const &defaultValue, bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcFrictionloss, SdfValueTypeNames->Double,
|
||||
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
namespace {
|
||||
static inline TfTokenVector _ConcatenateAttributeNames(
|
||||
const TfTokenVector &left, const TfTokenVector &right) {
|
||||
TfTokenVector result;
|
||||
result.reserve(left.size() + right.size());
|
||||
result.insert(result.end(), left.begin(), left.end());
|
||||
result.insert(result.end(), right.begin(), right.end());
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/*static*/
|
||||
const TfTokenVector &MjcPhysicsJointAPI::GetSchemaAttributeNames(
|
||||
bool includeInherited) {
|
||||
static TfTokenVector localNames = {
|
||||
MjcPhysicsTokens->mjcSpringdamper,
|
||||
MjcPhysicsTokens->mjcSolreflimit,
|
||||
MjcPhysicsTokens->mjcSolimplimit,
|
||||
MjcPhysicsTokens->mjcSolreffriction,
|
||||
MjcPhysicsTokens->mjcSolimpfriction,
|
||||
MjcPhysicsTokens->mjcStiffness,
|
||||
MjcPhysicsTokens->mjcActuatorfrcrangeMin,
|
||||
MjcPhysicsTokens->mjcActuatorfrcrangeMax,
|
||||
MjcPhysicsTokens->mjcActuatorfrclimited,
|
||||
MjcPhysicsTokens->mjcActuatorgravcomp,
|
||||
MjcPhysicsTokens->mjcMargin,
|
||||
MjcPhysicsTokens->mjcRef,
|
||||
MjcPhysicsTokens->mjcSpringref,
|
||||
MjcPhysicsTokens->mjcArmature,
|
||||
MjcPhysicsTokens->mjcDamping,
|
||||
MjcPhysicsTokens->mjcFrictionloss,
|
||||
};
|
||||
static TfTokenVector allNames = _ConcatenateAttributeNames(
|
||||
UsdAPISchemaBase::GetSchemaAttributeNames(true), localNames);
|
||||
|
||||
if (includeInherited)
|
||||
return allNames;
|
||||
else
|
||||
return localNames;
|
||||
}
|
||||
|
||||
PXR_NAMESPACE_CLOSE_SCOPE
|
||||
|
||||
// ===================================================================== //
|
||||
// Feel free to add custom code below this line. It will be preserved by
|
||||
// the code generator.
|
||||
//
|
||||
// Just remember to wrap code in the appropriate delimiters:
|
||||
// 'PXR_NAMESPACE_OPEN_SCOPE', 'PXR_NAMESPACE_CLOSE_SCOPE'.
|
||||
// ===================================================================== //
|
||||
// --(BEGIN CUSTOM CODE)--
|
||||
@@ -0,0 +1,185 @@
|
||||
// Copyright 2025 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.
|
||||
|
||||
#include <mujoco/experimental/usd/mjcPhysics/keyframe.h>
|
||||
|
||||
#include <pxr/usd/sdf/assetPath.h>
|
||||
#include <pxr/usd/sdf/types.h>
|
||||
#include <pxr/usd/usd/schemaRegistry.h>
|
||||
#include <pxr/usd/usd/typed.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
// Register the schema with the TfType system.
|
||||
TF_REGISTRY_FUNCTION(TfType) {
|
||||
TfType::Define<MjcPhysicsKeyframe, TfType::Bases<UsdTyped> >();
|
||||
|
||||
// Register the usd prim typename as an alias under UsdSchemaBase. This
|
||||
// enables one to call
|
||||
// TfType::Find<UsdSchemaBase>().FindDerivedByName("Keyframe")
|
||||
// to find TfType<MjcPhysicsKeyframe>, which is how IsA queries are
|
||||
// answered.
|
||||
TfType::AddAlias<UsdSchemaBase, MjcPhysicsKeyframe>("Keyframe");
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
MjcPhysicsKeyframe::~MjcPhysicsKeyframe() {}
|
||||
|
||||
/* static */
|
||||
MjcPhysicsKeyframe MjcPhysicsKeyframe::Get(const UsdStagePtr &stage,
|
||||
const SdfPath &path) {
|
||||
if (!stage) {
|
||||
TF_CODING_ERROR("Invalid stage");
|
||||
return MjcPhysicsKeyframe();
|
||||
}
|
||||
return MjcPhysicsKeyframe(stage->GetPrimAtPath(path));
|
||||
}
|
||||
|
||||
/* static */
|
||||
MjcPhysicsKeyframe MjcPhysicsKeyframe::Define(const UsdStagePtr &stage,
|
||||
const SdfPath &path) {
|
||||
static TfToken usdPrimTypeName("Keyframe");
|
||||
if (!stage) {
|
||||
TF_CODING_ERROR("Invalid stage");
|
||||
return MjcPhysicsKeyframe();
|
||||
}
|
||||
return MjcPhysicsKeyframe(stage->DefinePrim(path, usdPrimTypeName));
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
UsdSchemaKind MjcPhysicsKeyframe::_GetSchemaKind() const {
|
||||
return MjcPhysicsKeyframe::schemaKind;
|
||||
}
|
||||
|
||||
/* static */
|
||||
const TfType &MjcPhysicsKeyframe::_GetStaticTfType() {
|
||||
static TfType tfType = TfType::Find<MjcPhysicsKeyframe>();
|
||||
return tfType;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool MjcPhysicsKeyframe::_IsTypedSchema() {
|
||||
static bool isTyped = _GetStaticTfType().IsA<UsdTyped>();
|
||||
return isTyped;
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
const TfType &MjcPhysicsKeyframe::_GetTfType() const {
|
||||
return _GetStaticTfType();
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsKeyframe::GetMjcQposAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcQpos);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsKeyframe::CreateMjcQposAttr(VtValue const &defaultValue,
|
||||
bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcQpos, SdfValueTypeNames->DoubleArray,
|
||||
/* custom = */ false, SdfVariabilityVarying, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsKeyframe::GetMjcQvelAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcQvel);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsKeyframe::CreateMjcQvelAttr(VtValue const &defaultValue,
|
||||
bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcQvel, SdfValueTypeNames->DoubleArray,
|
||||
/* custom = */ false, SdfVariabilityVarying, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsKeyframe::GetMjcActAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcAct);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsKeyframe::CreateMjcActAttr(VtValue const &defaultValue,
|
||||
bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcAct, SdfValueTypeNames->DoubleArray,
|
||||
/* custom = */ false, SdfVariabilityVarying, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsKeyframe::GetMjcCtrlAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcCtrl);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsKeyframe::CreateMjcCtrlAttr(VtValue const &defaultValue,
|
||||
bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcCtrl, SdfValueTypeNames->DoubleArray,
|
||||
/* custom = */ false, SdfVariabilityVarying, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsKeyframe::GetMjcMposAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcMpos);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsKeyframe::CreateMjcMposAttr(VtValue const &defaultValue,
|
||||
bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcMpos, SdfValueTypeNames->DoubleArray,
|
||||
/* custom = */ false, SdfVariabilityVarying, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsKeyframe::GetMjcMquatAttr() const {
|
||||
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcMquat);
|
||||
}
|
||||
|
||||
UsdAttribute MjcPhysicsKeyframe::CreateMjcMquatAttr(VtValue const &defaultValue,
|
||||
bool writeSparsely) const {
|
||||
return UsdSchemaBase::_CreateAttr(
|
||||
MjcPhysicsTokens->mjcMquat, SdfValueTypeNames->DoubleArray,
|
||||
/* custom = */ false, SdfVariabilityVarying, defaultValue, writeSparsely);
|
||||
}
|
||||
|
||||
namespace {
|
||||
static inline TfTokenVector _ConcatenateAttributeNames(
|
||||
const TfTokenVector &left, const TfTokenVector &right) {
|
||||
TfTokenVector result;
|
||||
result.reserve(left.size() + right.size());
|
||||
result.insert(result.end(), left.begin(), left.end());
|
||||
result.insert(result.end(), right.begin(), right.end());
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/*static*/
|
||||
const TfTokenVector &MjcPhysicsKeyframe::GetSchemaAttributeNames(
|
||||
bool includeInherited) {
|
||||
static TfTokenVector localNames = {
|
||||
MjcPhysicsTokens->mjcQpos, MjcPhysicsTokens->mjcQvel,
|
||||
MjcPhysicsTokens->mjcAct, MjcPhysicsTokens->mjcCtrl,
|
||||
MjcPhysicsTokens->mjcMpos, MjcPhysicsTokens->mjcMquat,
|
||||
};
|
||||
static TfTokenVector allNames = _ConcatenateAttributeNames(
|
||||
UsdTyped::GetSchemaAttributeNames(true), localNames);
|
||||
|
||||
if (includeInherited)
|
||||
return allNames;
|
||||
else
|
||||
return localNames;
|
||||
}
|
||||
|
||||
PXR_NAMESPACE_CLOSE_SCOPE
|
||||
|
||||
// ===================================================================== //
|
||||
// Feel free to add custom code below this line. It will be preserved by
|
||||
// the code generator.
|
||||
//
|
||||
// Just remember to wrap code in the appropriate delimiters:
|
||||
// 'PXR_NAMESPACE_OPEN_SCOPE', 'PXR_NAMESPACE_CLOSE_SCOPE'.
|
||||
// ===================================================================== //
|
||||
// --(BEGIN CUSTOM CODE)--
|
||||
@@ -12,12 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "./meshCollisionAPI.h"
|
||||
#include <mujoco/experimental/usd/mjcPhysics/meshCollisionAPI.h>
|
||||
|
||||
#include "pxr/usd/sdf/assetPath.h"
|
||||
#include "pxr/usd/sdf/types.h"
|
||||
#include "pxr/usd/usd/schemaRegistry.h"
|
||||
#include "pxr/usd/usd/typed.h"
|
||||
#include <pxr/usd/sdf/assetPath.h>
|
||||
#include <pxr/usd/sdf/types.h>
|
||||
#include <pxr/usd/usd/schemaRegistry.h>
|
||||
#include <pxr/usd/usd/typed.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#Portions of this file auto - generated by usdGenSchema.
|
||||
#Edits will survive regeneration except for comments and
|
||||
#changes to types with autoGenerated = true.
|
||||
{
|
||||
"Plugins": [
|
||||
{
|
||||
@@ -26,6 +23,26 @@
|
||||
],
|
||||
"schemaKind": "singleApplyAPI"
|
||||
},
|
||||
"MjcPhysicsJointAPI": {
|
||||
"alias": {
|
||||
"UsdSchemaBase": "PhysicsJointsAPI"
|
||||
},
|
||||
"autoGenerated": true,
|
||||
"bases": [
|
||||
"UsdAPISchemaBase"
|
||||
],
|
||||
"schemaKind": "singleApplyAPI"
|
||||
},
|
||||
"MjcPhysicsKeyframe": {
|
||||
"alias": {
|
||||
"UsdSchemaBase": "Keyframe"
|
||||
},
|
||||
"autoGenerated": true,
|
||||
"bases": [
|
||||
"UsdTyped"
|
||||
],
|
||||
"schemaKind": "concreteTyped"
|
||||
},
|
||||
"MjcPhysicsMeshCollisionAPI": {
|
||||
"alias": {
|
||||
"UsdSchemaBase": "MeshCollisionAPI"
|
||||
@@ -58,7 +75,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"LibraryPath": "",
|
||||
"LibraryPath": "@PLUG_INFO_LIBRARY_PATH@",
|
||||
"Name": "mjcPhysics",
|
||||
"ResourcePath": "",
|
||||
"Root": ".",
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "./sceneAPI.h"
|
||||
#include <mujoco/experimental/usd/mjcPhysics/sceneAPI.h>
|
||||
|
||||
#include "pxr/usd/sdf/assetPath.h"
|
||||
#include "pxr/usd/sdf/types.h"
|
||||
#include "pxr/usd/usd/schemaRegistry.h"
|
||||
#include "pxr/usd/usd/typed.h"
|
||||
#include <pxr/usd/sdf/assetPath.h>
|
||||
#include <pxr/usd/sdf/types.h>
|
||||
#include <pxr/usd/usd/schemaRegistry.h>
|
||||
#include <pxr/usd/usd/typed.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
|
||||
@@ -663,3 +663,110 @@ class "PhysicsActuatorAPI"
|
||||
}
|
||||
|
||||
|
||||
class Keyframe "Keyframe"
|
||||
(
|
||||
doc = """Represents time independent keyframe values."""
|
||||
|
||||
inherits = </Typed>
|
||||
)
|
||||
{
|
||||
double[] mjc:qpos (
|
||||
doc = "Vector of joint positions, copied into mjData.qpos when the simulation state is set to this keyframe."
|
||||
)
|
||||
|
||||
double[] mjc:qvel (
|
||||
doc = "Vector of joint velocities, copied into mjData.qvel when the simulation state is set to this keyframe."
|
||||
)
|
||||
|
||||
double[] mjc:act (
|
||||
doc = "Vector of actuator activations, copied into mjData.act when the simulation state is set to this keyframe."
|
||||
)
|
||||
|
||||
double[] mjc:ctrl (
|
||||
doc = "Vector of controls, copied into mjData.ctrl when the simulation state is set to this keyframe."
|
||||
)
|
||||
|
||||
double[] mjc:mpos (
|
||||
doc = "Vector of mocap body positions, copied into mjData.mocap_pos when the simulation state is set to this keyframe."
|
||||
)
|
||||
|
||||
double[] mjc:mquat (
|
||||
doc = "Vector of mocap body quaternions, copied into mjData.mocap_quat when the simulation state is set to this keyframe."
|
||||
)
|
||||
}
|
||||
|
||||
class "PhysicsJointsAPI"
|
||||
(
|
||||
customData = {
|
||||
string className = "JointAPI"
|
||||
}
|
||||
doc = """API describing a Mujoco joint."""
|
||||
|
||||
inherits = </APISchemaBase>
|
||||
)
|
||||
{
|
||||
uniform double[] mjc:springdamper = [0, 0] (
|
||||
doc = "When both numbers are positive, the compiler will override any stiffness and damping values specified with the attributes below, and will instead set them automatically so that the resulting mass-spring-damper for this joint has the desired time constant (first value) and damping ratio (second value). This is done by taking into account the joint inertia in the model reference configuration. Note that the format is the same as the solref parameter of the constraint solver."
|
||||
)
|
||||
|
||||
uniform double[] mjc:solreflimit = [0.02, 1.0] (
|
||||
doc = "Constraint solver parameters for simulating joint limits."
|
||||
)
|
||||
|
||||
uniform double[] mjc:solimplimit = [0.9, 0.95, 0.001, 0.5, 2.0] (
|
||||
doc = "Constraint solver parameters for simulating joint limits."
|
||||
)
|
||||
|
||||
uniform double[] mjc:solreffriction = [0.02, 1.0] (
|
||||
doc = "Constraint solver parameters for simulating dry friction."
|
||||
)
|
||||
|
||||
uniform double[] mjc:solimpfriction = [0.9, 0.95, 0.001, 0.5, 2.0] (
|
||||
doc = "Constraint solver parameters for simulating dry friction."
|
||||
)
|
||||
|
||||
uniform double mjc:stiffness = 0 (
|
||||
doc = "Joint stiffness. If this value is positive, a spring will be created with equilibrium position given by springref below. The spring force is computed along with the other passive forces."
|
||||
)
|
||||
|
||||
uniform double mjc:actuatorfrcrange:min = 0 (
|
||||
doc = "Minimum range for clamping total actuator forces acting on this joint. See Force limits for details. It is available only for scalar joints (hinge and slider) and ignored for ball and free joints. The compiler expects the first value to be smaller than the second value. Setting this attribute without specifying actuatorfrclimited is an error if compiler-autolimits is 'false'."
|
||||
)
|
||||
|
||||
uniform double mjc:actuatorfrcrange:max = 0 (
|
||||
doc = "Maximum range for clamping total actuator forces acting on this joint. See Force limits for details. It is available only for scalar joints (hinge and slider) and ignored for ball and free joints. The compiler expects the first value to be smaller than the second value. Setting this attribute without specifying actuatorfrclimited is an error if compiler-autolimits is 'false'."
|
||||
)
|
||||
|
||||
uniform token mjc:actuatorfrclimited = "auto" (
|
||||
doc = "This attribute specifies whether actuator forces acting on the joint should be clamped. See Force limits for details. It is available only for scalar joints (hinge and slider) and ignored for ball and free joints. This attribute interacts with the actuatorfrcrange attribute. If this attribute is 'false', actuator force clamping is disabled. If it is 'true', actuator force clamping is enabled. If this attribute is 'auto', and autolimits is set in compiler, actuator force clamping will be enabled if actuatorfrcrange is defined."
|
||||
allowedTokens = ["false", "true", "auto"]
|
||||
)
|
||||
|
||||
uniform bool mjc:actuatorgravcomp = false (
|
||||
doc = "If this flag is enabled, gravity compensation applied to this joint is added to actuator forces (mjData.qfrc_actuator) rather than passive forces (mjData.qfrc_passive). Notionally, this means that gravity compensation is the result of a control system rather than natural buoyancy. In practice, enabling this flag is useful when joint-level actuator force clamping is used. In this case, the total actuation force applied on a joint, including gravity compensation, is guaranteed to not exceed the specified limits. See Force limits and actuatorfrcrange for more details on this type of force limit."
|
||||
)
|
||||
|
||||
uniform double mjc:margin = 0 (
|
||||
doc = "The distance threshold below which limits become active. Recall that the Constraint solver normally generates forces as soon as a constraint becomes active, even if the margin parameter makes that happen at a distance. This attribute together with solreflimit and solimplimit can be used to model a soft joint limit."
|
||||
)
|
||||
|
||||
uniform double mjc:ref = 0 (
|
||||
doc = "The reference position or angle of the joint. This attribute is only used for slide and hinge joints. It defines the joint value corresponding to the initial model configuration. The amount of spatial transformation that the joint applies at runtime equals the current joint value stored in mjData.qpos minus this reference value stored in mjModel.qpos0. The meaning of these vectors was discussed in the Stand-alone section in the Overview chapter."
|
||||
)
|
||||
|
||||
uniform double mjc:springref = 0 (
|
||||
doc = "The joint position or angle in which the joint spring (if any) achieves equilibrium. Similar to the vector mjModel.qpos0 which stores all joint reference values specified with the ref attribute above, all spring reference values specified with this attribute are stored in the vector mjModel.qpos_spring. The model configuration corresponding to mjModel.qpos_spring is also used to compute the spring reference lengths of all tendons, stored in mjModel.tendon_lengthspring. This is because tendons can also have springs."
|
||||
)
|
||||
|
||||
uniform double mjc:armature = 0 (
|
||||
doc = "Additional inertia associated with movement of the joint that is not due to body mass. This added inertia is usually due to a rotor (a.k.a armature) spinning faster than the joint itself due to a geared transmission. The value applies to all degrees of freedom created by this joint. Besides increasing the realism of joints with geared transmission, positive armature significantly improves simulation stability, even for small values, and is a recommended possible fix when encountering stability issues."
|
||||
)
|
||||
|
||||
uniform double mjc:damping = 0 (
|
||||
doc = "Damping applied to all degrees of freedom created by this joint. Unlike friction loss which is computed by the constraint solver, damping is simply a force linear in velocity. It is included in the passive forces. Despite this simplicity, larger damping values can make numerical integrators unstable, which is why our Euler integrator handles damping implicitly. See Integration in the Computation chapter."
|
||||
)
|
||||
|
||||
uniform double mjc:frictionloss = 0 (
|
||||
doc = "Friction loss due to dry friction. This value is the same for all degrees of freedom created by this joint. Semantically friction loss does not make sense for free joints, but the compiler allows it. To enable friction loss, set this attribute to a positive value."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "./siteAPI.h"
|
||||
#include <mujoco/experimental/usd/mjcPhysics/siteAPI.h>
|
||||
|
||||
#include "pxr/usd/sdf/assetPath.h"
|
||||
#include "pxr/usd/sdf/types.h"
|
||||
#include "pxr/usd/usd/schemaRegistry.h"
|
||||
#include "pxr/usd/usd/typed.h"
|
||||
#include <pxr/usd/sdf/assetPath.h>
|
||||
#include <pxr/usd/sdf/types.h>
|
||||
#include <pxr/usd/usd/schemaRegistry.h>
|
||||
#include <pxr/usd/usd/typed.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "./tokens.h"
|
||||
#include <mujoco/experimental/usd/mjcPhysics/tokens.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
@@ -33,18 +33,25 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
|
||||
implicitfast("implicitfast", TfToken::Immortal),
|
||||
integrator("integrator", TfToken::Immortal),
|
||||
legacy("legacy", TfToken::Immortal),
|
||||
mjcAct("mjc:act", TfToken::Immortal),
|
||||
mjcActDim("mjc:actDim", TfToken::Immortal),
|
||||
mjcActEarly("mjc:actEarly", TfToken::Immortal),
|
||||
mjcActLimited("mjc:actLimited", TfToken::Immortal),
|
||||
mjcActRangeMax("mjc:actRange:max", TfToken::Immortal),
|
||||
mjcActRangeMin("mjc:actRange:min", TfToken::Immortal),
|
||||
mjcActuatorfrclimited("mjc:actuatorfrclimited", TfToken::Immortal),
|
||||
mjcActuatorfrcrangeMax("mjc:actuatorfrcrange:max", TfToken::Immortal),
|
||||
mjcActuatorfrcrangeMin("mjc:actuatorfrcrange:min", TfToken::Immortal),
|
||||
mjcActuatorgravcomp("mjc:actuatorgravcomp", TfToken::Immortal),
|
||||
mjcArmature("mjc:armature", TfToken::Immortal),
|
||||
mjcBiasPrm("mjc:biasPrm", TfToken::Immortal),
|
||||
mjcBiasType("mjc:biasType", TfToken::Immortal),
|
||||
mjcCrankLength("mjc:crankLength", TfToken::Immortal),
|
||||
mjcCrankSite("mjc:crankSite", TfToken::Immortal),
|
||||
mjcCtrl("mjc:ctrl", TfToken::Immortal),
|
||||
mjcCtrlLimited("mjc:ctrlLimited", TfToken::Immortal),
|
||||
mjcCtrlRangeMax("mjc:ctrlRange:max", TfToken::Immortal),
|
||||
mjcCtrlRangeMin("mjc:ctrlRange:min", TfToken::Immortal),
|
||||
mjcDamping("mjc:damping", TfToken::Immortal),
|
||||
mjcDynPrm("mjc:dynPrm", TfToken::Immortal),
|
||||
mjcDynType("mjc:dynType", TfToken::Immortal),
|
||||
mjcFlagActuation("mjc:flag:actuation", TfToken::Immortal),
|
||||
@@ -73,6 +80,7 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
|
||||
mjcForceLimited("mjc:forceLimited", TfToken::Immortal),
|
||||
mjcForceRangeMax("mjc:forceRange:max", TfToken::Immortal),
|
||||
mjcForceRangeMin("mjc:forceRange:min", TfToken::Immortal),
|
||||
mjcFrictionloss("mjc:frictionloss", TfToken::Immortal),
|
||||
mjcGainPrm("mjc:gainPrm", TfToken::Immortal),
|
||||
mjcGainType("mjc:gainType", TfToken::Immortal),
|
||||
mjcGear("mjc:gear", TfToken::Immortal),
|
||||
@@ -80,6 +88,9 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
|
||||
mjcJointInParent("mjc:jointInParent", TfToken::Immortal),
|
||||
mjcLengthRangeMax("mjc:lengthRange:max", TfToken::Immortal),
|
||||
mjcLengthRangeMin("mjc:lengthRange:min", TfToken::Immortal),
|
||||
mjcMargin("mjc:margin", TfToken::Immortal),
|
||||
mjcMpos("mjc:mpos", TfToken::Immortal),
|
||||
mjcMquat("mjc:mquat", TfToken::Immortal),
|
||||
mjcOptionActuatorgroupdisable("mjc:option:actuatorgroupdisable",
|
||||
TfToken::Immortal),
|
||||
mjcOptionApirate("mjc:option:apirate", TfToken::Immortal),
|
||||
@@ -109,9 +120,19 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
|
||||
mjcOptionTolerance("mjc:option:tolerance", TfToken::Immortal),
|
||||
mjcOptionViscosity("mjc:option:viscosity", TfToken::Immortal),
|
||||
mjcOptionWind("mjc:option:wind", TfToken::Immortal),
|
||||
mjcQpos("mjc:qpos", TfToken::Immortal),
|
||||
mjcQvel("mjc:qvel", TfToken::Immortal),
|
||||
mjcRef("mjc:ref", TfToken::Immortal),
|
||||
mjcRefSite("mjc:refSite", TfToken::Immortal),
|
||||
mjcShellinertia("mjc:shellinertia", TfToken::Immortal),
|
||||
mjcSliderSite("mjc:sliderSite", TfToken::Immortal),
|
||||
mjcSolimpfriction("mjc:solimpfriction", TfToken::Immortal),
|
||||
mjcSolimplimit("mjc:solimplimit", TfToken::Immortal),
|
||||
mjcSolreffriction("mjc:solreffriction", TfToken::Immortal),
|
||||
mjcSolreflimit("mjc:solreflimit", TfToken::Immortal),
|
||||
mjcSpringdamper("mjc:springdamper", TfToken::Immortal),
|
||||
mjcSpringref("mjc:springref", TfToken::Immortal),
|
||||
mjcStiffness("mjc:stiffness", TfToken::Immortal),
|
||||
muscle("muscle", TfToken::Immortal),
|
||||
newton("newton", TfToken::Immortal),
|
||||
none("none", TfToken::Immortal),
|
||||
@@ -123,8 +144,10 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
|
||||
true_("true", TfToken::Immortal),
|
||||
user("user", TfToken::Immortal),
|
||||
CollisionAPI("CollisionAPI", TfToken::Immortal),
|
||||
Keyframe("Keyframe", TfToken::Immortal),
|
||||
MeshCollisionAPI("MeshCollisionAPI", TfToken::Immortal),
|
||||
PhysicsActuatorAPI("PhysicsActuatorAPI", TfToken::Immortal),
|
||||
PhysicsJointsAPI("PhysicsJointsAPI", TfToken::Immortal),
|
||||
SceneAPI("SceneAPI", TfToken::Immortal),
|
||||
SiteAPI("SiteAPI", TfToken::Immortal),
|
||||
allTokens({affine,
|
||||
@@ -143,18 +166,25 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
|
||||
implicitfast,
|
||||
integrator,
|
||||
legacy,
|
||||
mjcAct,
|
||||
mjcActDim,
|
||||
mjcActEarly,
|
||||
mjcActLimited,
|
||||
mjcActRangeMax,
|
||||
mjcActRangeMin,
|
||||
mjcActuatorfrclimited,
|
||||
mjcActuatorfrcrangeMax,
|
||||
mjcActuatorfrcrangeMin,
|
||||
mjcActuatorgravcomp,
|
||||
mjcArmature,
|
||||
mjcBiasPrm,
|
||||
mjcBiasType,
|
||||
mjcCrankLength,
|
||||
mjcCrankSite,
|
||||
mjcCtrl,
|
||||
mjcCtrlLimited,
|
||||
mjcCtrlRangeMax,
|
||||
mjcCtrlRangeMin,
|
||||
mjcDamping,
|
||||
mjcDynPrm,
|
||||
mjcDynType,
|
||||
mjcFlagActuation,
|
||||
@@ -183,6 +213,7 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
|
||||
mjcForceLimited,
|
||||
mjcForceRangeMax,
|
||||
mjcForceRangeMin,
|
||||
mjcFrictionloss,
|
||||
mjcGainPrm,
|
||||
mjcGainType,
|
||||
mjcGear,
|
||||
@@ -190,6 +221,9 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
|
||||
mjcJointInParent,
|
||||
mjcLengthRangeMax,
|
||||
mjcLengthRangeMin,
|
||||
mjcMargin,
|
||||
mjcMpos,
|
||||
mjcMquat,
|
||||
mjcOptionActuatorgroupdisable,
|
||||
mjcOptionApirate,
|
||||
mjcOptionCcd_iterations,
|
||||
@@ -216,9 +250,19 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
|
||||
mjcOptionTolerance,
|
||||
mjcOptionViscosity,
|
||||
mjcOptionWind,
|
||||
mjcQpos,
|
||||
mjcQvel,
|
||||
mjcRef,
|
||||
mjcRefSite,
|
||||
mjcShellinertia,
|
||||
mjcSliderSite,
|
||||
mjcSolimpfriction,
|
||||
mjcSolimplimit,
|
||||
mjcSolreffriction,
|
||||
mjcSolreflimit,
|
||||
mjcSpringdamper,
|
||||
mjcSpringref,
|
||||
mjcStiffness,
|
||||
muscle,
|
||||
newton,
|
||||
none,
|
||||
@@ -230,8 +274,10 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
|
||||
true_,
|
||||
user,
|
||||
CollisionAPI,
|
||||
Keyframe,
|
||||
MeshCollisionAPI,
|
||||
PhysicsActuatorAPI,
|
||||
PhysicsJointsAPI,
|
||||
SceneAPI,
|
||||
SiteAPI}) {}
|
||||
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
# Copyright 2025 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
|
||||
#
|
||||
# https://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.
|
||||
|
||||
|
||||
# Plugin target name (used for library and plugInfo.json)
|
||||
set(MJCF_PLUGIN_TARGET_NAME usdMjcf)
|
||||
|
||||
add_library(${MJCF_PLUGIN_TARGET_NAME} SHARED
|
||||
mjcf/mjcf_file_format.cc
|
||||
mjcf/mjcf_file_format.h
|
||||
mjcf/mujoco_to_usd.cc
|
||||
mjcf/mujoco_to_usd.h
|
||||
mjcf/utils.cc
|
||||
mjcf/utils.h
|
||||
)
|
||||
|
||||
# We need to set the visibility to default until core type symbol visibility
|
||||
# is resolved in OpenUSD https://github.com/PixarAnimationStudios/OpenUSD/issues/1475
|
||||
# Otherwise we will run into issues during composition on MacOS due to std::type_info
|
||||
# comparisons failing for pxr::TfTokenVector and the like that we place in SdfAbstractData.
|
||||
set_target_properties(${MJCF_PLUGIN_TARGET_NAME} PROPERTIES
|
||||
OUTPUT_NAME ${MJCF_PLUGIN_TARGET_NAME}
|
||||
CXX_VISIBILITY_PRESET default
|
||||
)
|
||||
|
||||
target_include_directories(${MJCF_PLUGIN_TARGET_NAME} PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
if (MUJOCO_USD_TARGET STREQUAL "USD")
|
||||
find_package(pxr REQUIRED)
|
||||
|
||||
# --- Link Dependencies ---
|
||||
# Link against the necessary OpenUSD components
|
||||
target_link_libraries(${MJCF_PLUGIN_TARGET_NAME} PRIVATE
|
||||
usd
|
||||
ar
|
||||
kind
|
||||
tf
|
||||
gf
|
||||
vt
|
||||
usdShade
|
||||
usdLux
|
||||
usdGeom
|
||||
usdImaging
|
||||
usdPhysics
|
||||
mujoco
|
||||
tinyxml2
|
||||
)
|
||||
elseif (MUJOCO_USD_TARGET STREQUAL "Houdini")
|
||||
|
||||
if (NOT DEFINED ENV{HFS})
|
||||
message(FATAL_ERROR "Environment variable 'HFS' is not defined: $ENV{HFS}. Please run houdini_setup.")
|
||||
endif()
|
||||
|
||||
# In Houdini, the Houdini package we would typically use via find_package
|
||||
# does not have all the USD dependencies that we need (namely UsdPhysics)
|
||||
# so we need to manually link all the required libraries.
|
||||
|
||||
set(HFS_ENV "$ENV{HFS}")
|
||||
set(HOUDINI_LIBS "${HFS_ENV}/../Libraries")
|
||||
get_filename_component(HOUDINI_LIBS "${HOUDINI_LIBS}" ABSOLUTE) # Normalize the path
|
||||
target_link_directories(${MJCF_PLUGIN_TARGET_NAME} PRIVATE ${HOUDINI_LIBS})
|
||||
|
||||
target_include_directories(${MJCF_PLUGIN_TARGET_NAME} PRIVATE
|
||||
"${HFS_ENV}/toolkit/include"
|
||||
"${HFS_ENV}/toolkit/include/python3.11"
|
||||
)
|
||||
|
||||
# Assume everyone using Houdini on 3.11 for now.
|
||||
set(USD_MJCF_PYTHON_LIB python3.11)
|
||||
set(USD_MJCF_PYTHON_LIB_NUMBER python311)
|
||||
set(PYTHON_LIB "${HFS_ENV}/Frameworks/Python.framework/Versions/3.11/Python")
|
||||
set(PXR_LIB_PREFIX "pxr_")
|
||||
|
||||
# --- Link Dependencies ---
|
||||
# Link against the necessary OpenUSD components
|
||||
target_link_libraries(${MJCF_PLUGIN_TARGET_NAME} PRIVATE
|
||||
${PXR_LIB_PREFIX}usd
|
||||
${PXR_LIB_PREFIX}ar
|
||||
${PXR_LIB_PREFIX}kind
|
||||
${PXR_LIB_PREFIX}tf
|
||||
${PXR_LIB_PREFIX}gf
|
||||
${PXR_LIB_PREFIX}vt
|
||||
${PXR_LIB_PREFIX}sdf
|
||||
${PXR_LIB_PREFIX}usdShade
|
||||
${PXR_LIB_PREFIX}usdLux
|
||||
${PXR_LIB_PREFIX}usdGeom
|
||||
${PXR_LIB_PREFIX}usdImaging
|
||||
${PXR_LIB_PREFIX}usdPhysics
|
||||
tbb
|
||||
hboost_${USD_MJCF_PYTHON_LIB_NUMBER}
|
||||
${PYTHON_LIB}
|
||||
mujoco
|
||||
tinyxml2
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
# --- Generate plugInfo.json ---
|
||||
if(CMAKE_SHARED_LIBRARY_PREFIX)
|
||||
set(LIB_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX}) # Usually "lib" on Unix
|
||||
else()
|
||||
set(LIB_PREFIX "")
|
||||
endif()
|
||||
set(PLUG_INFO_LIBRARY_PATH "${LIB_PREFIX}${MJCF_PLUGIN_TARGET_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
|
||||
# --- Installation ---
|
||||
|
||||
set(USD_PLUGIN_INSTALL_DIR_LIB ${CMAKE_INSTALL_LIBDIR}/usdMjcf)
|
||||
|
||||
message(STATUS "Copying plugInfo.json to ${CMAKE_BINARY_DIR}/${USD_PLUGIN_INSTALL_DIR_LIB}/plugInfo.json")
|
||||
configure_file(
|
||||
mjcf/plugInfo.json
|
||||
${CMAKE_BINARY_DIR}/${USD_PLUGIN_INSTALL_DIR_LIB}/plugInfo.json
|
||||
)
|
||||
|
||||
install(FILES ${CMAKE_BINARY_DIR}/${USD_PLUGIN_INSTALL_DIR_LIB}/plugInfo.json DESTINATION ${USD_PLUGIN_INSTALL_DIR_LIB})
|
||||
|
||||
# Install shared lib and plugInfo to same location for simplicity.
|
||||
install(TARGETS ${MJCF_PLUGIN_TARGET_NAME}
|
||||
LIBRARY DESTINATION ${USD_PLUGIN_INSTALL_DIR_LIB}
|
||||
)
|
||||
|
||||
message(STATUS "USD MJCF Plugin will be installed to: ${CMAKE_INSTALL_PREFIX}/${USD_PLUGIN_INSTALL_DIR_LIB}")
|
||||
message(STATUS "Make sure PXR_PLUGINPATH_NAME includes: ${CMAKE_INSTALL_PREFIX}/${USD_PLUGIN_INSTALL_DIR_LIB}")
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "mjcf/mujoco_to_usd.h"
|
||||
#include "tinyxml2.h"
|
||||
#include <pxr/base/tf/diagnostic.h>
|
||||
#include <pxr/base/tf/enum.h>
|
||||
#include <pxr/base/tf/pathUtils.h>
|
||||
@@ -37,7 +38,6 @@
|
||||
#include <pxr/usd/sdf/fileFormat.h>
|
||||
#include <pxr/usd/sdf/layer.h>
|
||||
#include <pxr/usd/usd/usdaFileFormat.h>
|
||||
#include "tinyxml2.h"
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
|
||||
|
||||
@@ -21,8 +21,9 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <mujoco/experimental/usd/mjcPhysics/tokens.h>
|
||||
#include <mujoco/mjspec.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "third_party/mujoco/src/experimental/usd/mjcPhysics/tokens.h"
|
||||
#include "mjcf/utils.h"
|
||||
#include <pxr/base/arch/attributes.h>
|
||||
#include <pxr/base/gf/matrix4d.h>
|
||||
@@ -54,6 +55,11 @@
|
||||
#include <pxr/usd/usdGeom/metrics.h>
|
||||
#include <pxr/usd/usdGeom/tokens.h>
|
||||
#include <pxr/usd/usdLux/tokens.h>
|
||||
#include <pxr/usd/usdPhysics/fixedJoint.h>
|
||||
#include <pxr/usd/usdPhysics/joint.h>
|
||||
#include <pxr/usd/usdPhysics/prismaticJoint.h>
|
||||
#include <pxr/usd/usdPhysics/revoluteJoint.h>
|
||||
#include <pxr/usd/usdPhysics/sphericalJoint.h>
|
||||
#include <pxr/usd/usdPhysics/tokens.h>
|
||||
#include <pxr/usd/usdShade/tokens.h>
|
||||
#include <pxr/usdImaging/usdImaging/tokens.h>
|
||||
@@ -77,7 +83,7 @@ TF_DEFINE_PRIVATE_TOKENS(kTokens,
|
||||
((light, "Light"))
|
||||
((meshScope, "MeshSources"))
|
||||
((materialsScope, "Materials"))
|
||||
((surface, "PreviewSurface"))
|
||||
((previewSurface, "PreviewSurface"))
|
||||
((world, "World"))
|
||||
((xformOpTransform, "xformOp:transform"))
|
||||
((xformOpScale, "xformOp:scale"))
|
||||
@@ -90,10 +96,18 @@ TF_DEFINE_PRIVATE_TOKENS(kTokens,
|
||||
((inputsWrapS, "inputs:wrapS"))
|
||||
((inputsWrapT, "inputs:wrapT"))
|
||||
((inputsDiffuseColor, "inputs:diffuseColor"))
|
||||
((inputsEmissiveColor, "inputs:emissiveColor"))
|
||||
((outputsRgb, "outputs:rgb"))
|
||||
((outputsR, "outputs:r"))
|
||||
((outputsG, "outputs:g"))
|
||||
((outputsB, "outputs:b"))
|
||||
((inputsMetallic, "inputs:metallic"))
|
||||
((inputsOcclusion, "inputs:occlusion"))
|
||||
((inputsRoughness, "inputs:roughness"))
|
||||
(repeat)
|
||||
((sourceMesh, pxr::UsdGeomTokens->Mesh))
|
||||
((inputsNormal, "inputs:normal"))
|
||||
((joint, "Joint"))
|
||||
);
|
||||
|
||||
// Using to satisfy TF_REGISTRY_FUNCTION macro below and avoid operating in PXR_NS.
|
||||
@@ -157,10 +171,14 @@ class ModelWriter {
|
||||
: spec_(spec), model_(model), data_(data), class_path_("/Bad_Path") {
|
||||
body_paths_ = std::vector<pxr::SdfPath>(model->nbody);
|
||||
site_paths_ = std::vector<pxr::SdfPath>(model->nsite);
|
||||
joint_paths_ = std::vector<pxr::SdfPath>(model->njnt);
|
||||
}
|
||||
~ModelWriter() { mj_deleteModel(model_); }
|
||||
|
||||
void Write(bool write_physics) {
|
||||
// Set working parameters.
|
||||
write_physics_ = write_physics;
|
||||
|
||||
// Create top level class holder.
|
||||
class_path_ = CreateClassSpec(data_, pxr::SdfPath::AbsoluteRootPath(),
|
||||
pxr::TfToken("__class__"));
|
||||
@@ -168,9 +186,6 @@ class ModelWriter {
|
||||
// Create the world body.
|
||||
body_paths_[kWorldIndex] = WriteWorldBody(kWorldIndex);
|
||||
|
||||
// Set working parameters.
|
||||
write_physics_ = write_physics;
|
||||
|
||||
SetLayerMetadata(data_, pxr::SdfFieldKeys->Documentation,
|
||||
"Generated by mujoco model writer.");
|
||||
// Mujoco is Z up by default.
|
||||
@@ -207,6 +222,8 @@ class ModelWriter {
|
||||
std::vector<pxr::SdfPath> body_paths_;
|
||||
// Mapping from Mujoco site id to SdfPath.
|
||||
std::vector<pxr::SdfPath> site_paths_;
|
||||
// Mapping from Mujoco joint id to SdfPath.
|
||||
std::vector<pxr::SdfPath> joint_paths_;
|
||||
// Mapping from mesh names to Mesh prim path.
|
||||
std::unordered_map<std::string, pxr::SdfPath> mesh_paths_;
|
||||
// Whether to write physics data.
|
||||
@@ -540,13 +557,13 @@ class ModelWriter {
|
||||
MjcPhysicsTokens->mjcOptionMagnetic, magnetic);
|
||||
|
||||
pxr::VtArray<double> o_solref(spec_->option.o_solref,
|
||||
spec_->option.o_solref + 2);
|
||||
spec_->option.o_solref + mjNREF);
|
||||
WriteUniformAttribute(physics_scene_path,
|
||||
pxr::SdfValueTypeNames->DoubleArray,
|
||||
MjcPhysicsTokens->mjcOptionO_solref, o_solref);
|
||||
|
||||
pxr::VtArray<double> o_solimp(spec_->option.o_solimp,
|
||||
spec_->option.o_solimp + 5);
|
||||
spec_->option.o_solimp + mjNIMP);
|
||||
WriteUniformAttribute(physics_scene_path,
|
||||
pxr::SdfValueTypeNames->DoubleArray,
|
||||
MjcPhysicsTokens->mjcOptionO_solimp, o_solimp);
|
||||
@@ -630,12 +647,10 @@ class ModelWriter {
|
||||
}
|
||||
}
|
||||
|
||||
pxr::SdfPath AddTextureShader(const pxr::SdfPath &material_path,
|
||||
const char *texture_file) {
|
||||
// Shader "uvmap"
|
||||
pxr::SdfPath AddUVTextureShader(const pxr::SdfPath &material_path,
|
||||
const pxr::TfToken &name) {
|
||||
pxr::SdfPath uvmap_shader_path =
|
||||
CreatePrimSpec(data_, material_path, pxr::TfToken("uvmap"),
|
||||
pxr::UsdShadeTokens->Shader);
|
||||
CreatePrimSpec(data_, material_path, name, pxr::UsdShadeTokens->Shader);
|
||||
|
||||
pxr::SdfPath uvmap_info_id_attr = CreateAttributeSpec(
|
||||
data_, uvmap_shader_path, pxr::UsdShadeTokens->infoId,
|
||||
@@ -652,10 +667,15 @@ class ModelWriter {
|
||||
CreateAttributeSpec(data_, uvmap_shader_path, kTokens->outputsSt,
|
||||
pxr::SdfValueTypeNames->Float2);
|
||||
|
||||
// Shader "texture"
|
||||
return uvmap_st_output_attr;
|
||||
}
|
||||
|
||||
std::vector<pxr::SdfPath> AddTextureShader(
|
||||
const pxr::SdfPath &material_path, const char *texture_file,
|
||||
const pxr::TfToken &name, const pxr::SdfPath &uvmap_st_output_attr,
|
||||
const std::vector<pxr::TfToken> &output_channels) {
|
||||
pxr::SdfPath texture_shader_path =
|
||||
CreatePrimSpec(data_, material_path, pxr::TfToken("texture"),
|
||||
pxr::UsdShadeTokens->Shader);
|
||||
CreatePrimSpec(data_, material_path, name, pxr::UsdShadeTokens->Shader);
|
||||
pxr::SdfPath texture_info_id_attr = CreateAttributeSpec(
|
||||
data_, texture_shader_path, pxr::UsdShadeTokens->infoId,
|
||||
pxr::SdfValueTypeNames->Token, pxr::SdfVariabilityUniform);
|
||||
@@ -683,78 +703,216 @@ class ModelWriter {
|
||||
pxr::SdfValueTypeNames->Token);
|
||||
SetAttributeDefault(data_, texture_wrap_t_attr, kTokens->repeat);
|
||||
|
||||
pxr::SdfPath texture_rgb_output_attr =
|
||||
CreateAttributeSpec(data_, texture_shader_path, kTokens->outputsRgb,
|
||||
pxr::SdfValueTypeNames->Float3);
|
||||
|
||||
return texture_rgb_output_attr;
|
||||
std::vector<pxr::SdfPath> texture_output_attrs;
|
||||
for (const auto &output_channel : output_channels) {
|
||||
pxr::SdfValueTypeName value_type;
|
||||
if (output_channel == kTokens->outputsRgb) {
|
||||
value_type = pxr::SdfValueTypeNames->Float3;
|
||||
} else {
|
||||
// Assume the other specified channels are outputR, outputG, outputB.
|
||||
value_type = pxr::SdfValueTypeNames->Float;
|
||||
}
|
||||
texture_output_attrs.push_back(CreateAttributeSpec(
|
||||
data_, texture_shader_path, output_channel, value_type));
|
||||
}
|
||||
return texture_output_attrs;
|
||||
}
|
||||
|
||||
void WriteMaterial(mjsMaterial *material, const pxr::SdfPath &parent_path) {
|
||||
// Create a Material prim.
|
||||
auto name = GetAvailablePrimName(
|
||||
*material->name, pxr::UsdShadeTokens->Material, parent_path);
|
||||
pxr::SdfPath material_path =
|
||||
CreatePrimSpec(data_, parent_path, name, pxr::UsdShadeTokens->Material);
|
||||
|
||||
// Shader "PreviewSurface"
|
||||
pxr::SdfPath preview_surface_shader_path = CreatePrimSpec(
|
||||
data_, material_path, kTokens->surface, pxr::UsdShadeTokens->Shader);
|
||||
// Create a Shader prim "PreviewSurface" under the Material prim.
|
||||
pxr::SdfPath preview_surface_shader_path =
|
||||
CreatePrimSpec(data_, material_path, kTokens->previewSurface,
|
||||
pxr::UsdShadeTokens->Shader);
|
||||
|
||||
// Set the Shader'sinfoId attribute to UsdPreviewSurface, a standard surface
|
||||
// shader.
|
||||
pxr::SdfPath info_id_attr = CreateAttributeSpec(
|
||||
data_, preview_surface_shader_path, pxr::UsdShadeTokens->infoId,
|
||||
pxr::SdfValueTypeNames->Token, pxr::SdfVariabilityUniform);
|
||||
SetAttributeDefault(data_, info_id_attr,
|
||||
pxr::UsdImagingTokens->UsdPreviewSurface);
|
||||
|
||||
// Connect material's surface output to the preview surface's surface
|
||||
// output.
|
||||
pxr::SdfPath surface_output_attr = CreateAttributeSpec(
|
||||
data_, preview_surface_shader_path, pxr::UsdShadeTokens->outputsSurface,
|
||||
pxr::SdfValueTypeNames->Token);
|
||||
pxr::SdfPath material_surface_output_attr = CreateAttributeSpec(
|
||||
data_, material_path, pxr::UsdShadeTokens->outputsSurface,
|
||||
pxr::SdfValueTypeNames->Token);
|
||||
AddAttributeConnection(data_, material_surface_output_attr,
|
||||
surface_output_attr);
|
||||
|
||||
// Connect material's displacement output to the preview surface's
|
||||
// displacement output.
|
||||
pxr::SdfPath displacement_output_attr =
|
||||
CreateAttributeSpec(data_, preview_surface_shader_path,
|
||||
pxr::UsdShadeTokens->outputsDisplacement,
|
||||
pxr::SdfValueTypeNames->Token);
|
||||
pxr::SdfPath material_displacement_output_attr = CreateAttributeSpec(
|
||||
data_, material_path, pxr::UsdShadeTokens->outputsDisplacement,
|
||||
pxr::SdfValueTypeNames->Token);
|
||||
AddAttributeConnection(data_, material_displacement_output_attr,
|
||||
displacement_output_attr);
|
||||
|
||||
// Add an st (uv) Shader, a prim var reader for the UV coordinates.
|
||||
const pxr::SdfPath &uvmap_st_output_attr =
|
||||
AddUVTextureShader(material_path, pxr::TfToken("uvmap"));
|
||||
const mjStringVec &textures = *(material->textures);
|
||||
|
||||
// Set the values of metallic, roughness and occlusion. These can come from
|
||||
// an ORM packed texture, as individual textures, or as a values defined in
|
||||
// mjsMaterial_ (with the exception of occlusion).
|
||||
pxr::SdfPath metallic_attr = CreateAttributeSpec(
|
||||
data_, preview_surface_shader_path, kTokens->inputsMetallic,
|
||||
pxr::SdfValueTypeNames->Float);
|
||||
pxr::SdfPath roughness_attr = CreateAttributeSpec(
|
||||
data_, preview_surface_shader_path, kTokens->inputsRoughness,
|
||||
pxr::SdfValueTypeNames->Float);
|
||||
// Find the occlusion, roughness, and metallic textures.
|
||||
if (mjTEXROLE_ORM < textures.size()) {
|
||||
std::string orm_texture_name = textures[mjTEXROLE_ORM];
|
||||
mjsTexture *orm_texture = mjs_asTexture(
|
||||
mjs_findElement(spec_, mjOBJ_TEXTURE, orm_texture_name.c_str()));
|
||||
std::string occlusion_texture_name = textures[mjTEXROLE_OCCLUSION];
|
||||
mjsTexture *occlusion_texture = mjs_asTexture(mjs_findElement(
|
||||
spec_, mjOBJ_TEXTURE, occlusion_texture_name.c_str()));
|
||||
std::string roughness_texture_name = textures[mjTEXROLE_ROUGHNESS];
|
||||
mjsTexture *roughness_texture = mjs_asTexture(mjs_findElement(
|
||||
spec_, mjOBJ_TEXTURE, roughness_texture_name.c_str()));
|
||||
std::string metallic_texture_name = textures[mjTEXROLE_METALLIC];
|
||||
mjsTexture *metallic_texture = mjs_asTexture(
|
||||
mjs_findElement(spec_, mjOBJ_TEXTURE, metallic_texture_name.c_str()));
|
||||
if (orm_texture) {
|
||||
// Create the ORM shader and connect its output to the preview
|
||||
// surface ORM attrs.
|
||||
const std::vector<pxr::SdfPath> orm_output_attrs = AddTextureShader(
|
||||
material_path, orm_texture->file->c_str(),
|
||||
pxr::TfToken("orm_packed"), uvmap_st_output_attr,
|
||||
{kTokens->outputsR, kTokens->outputsG, kTokens->outputsB});
|
||||
if (orm_output_attrs.size() == 3) {
|
||||
pxr::SdfPath occlusion_attr = CreateAttributeSpec(
|
||||
data_, preview_surface_shader_path, kTokens->inputsOcclusion,
|
||||
pxr::SdfValueTypeNames->Float);
|
||||
AddAttributeConnection(data_, occlusion_attr, orm_output_attrs[0]);
|
||||
AddAttributeConnection(data_, roughness_attr, orm_output_attrs[1]);
|
||||
AddAttributeConnection(data_, metallic_attr, orm_output_attrs[2]);
|
||||
}
|
||||
} else {
|
||||
if (metallic_texture) {
|
||||
const std::vector<pxr::SdfPath> metallic_output_attrs =
|
||||
AddTextureShader(material_path, metallic_texture->file->c_str(),
|
||||
pxr::TfToken("metallic"), uvmap_st_output_attr,
|
||||
{kTokens->outputsRgb});
|
||||
if (metallic_output_attrs.size() == 1) {
|
||||
AddAttributeConnection(data_, metallic_attr,
|
||||
metallic_output_attrs[0]);
|
||||
}
|
||||
} else {
|
||||
SetAttributeDefault(data_, metallic_attr, material->metallic);
|
||||
}
|
||||
if (roughness_texture) {
|
||||
const std::vector<pxr::SdfPath> roughness_output_attrs =
|
||||
AddTextureShader(material_path, roughness_texture->file->c_str(),
|
||||
pxr::TfToken("roughness"), uvmap_st_output_attr,
|
||||
{kTokens->outputsRgb});
|
||||
if (roughness_output_attrs.size() == 1) {
|
||||
AddAttributeConnection(data_, roughness_attr,
|
||||
roughness_output_attrs[0]);
|
||||
}
|
||||
} else {
|
||||
SetAttributeDefault(data_, roughness_attr, material->roughness);
|
||||
}
|
||||
if (occlusion_texture) {
|
||||
pxr::SdfPath occlusion_attr = CreateAttributeSpec(
|
||||
data_, preview_surface_shader_path, kTokens->inputsOcclusion,
|
||||
pxr::SdfValueTypeNames->Float);
|
||||
const std::vector<pxr::SdfPath> occlusion_output_attrs =
|
||||
AddTextureShader(material_path, occlusion_texture->file->c_str(),
|
||||
pxr::TfToken("occlusion"), uvmap_st_output_attr,
|
||||
{kTokens->outputsRgb});
|
||||
if (occlusion_output_attrs.size() == 1) {
|
||||
AddAttributeConnection(data_, occlusion_attr,
|
||||
occlusion_output_attrs[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find the normal texture if specified.
|
||||
if (mjTEXROLE_NORMAL < textures.size()) {
|
||||
std::string normal_texture_name = textures[mjTEXROLE_NORMAL];
|
||||
mjsTexture *normal_texture = mjs_asTexture(
|
||||
mjs_findElement(spec_, mjOBJ_TEXTURE, normal_texture_name.c_str()));
|
||||
if (normal_texture) {
|
||||
pxr::SdfPath normal_attr = CreateAttributeSpec(
|
||||
data_, preview_surface_shader_path, kTokens->inputsNormal,
|
||||
pxr::SdfValueTypeNames->Normal3f);
|
||||
// Create the normal map shader and connect its output to the preview
|
||||
// surface normal attr.
|
||||
const std::vector<pxr::SdfPath> normal_map_output_attrs =
|
||||
AddTextureShader(material_path, normal_texture->file->c_str(),
|
||||
pxr::TfToken("normal"), uvmap_st_output_attr,
|
||||
{kTokens->outputsRgb});
|
||||
if (normal_map_output_attrs.size() == 1) {
|
||||
AddAttributeConnection(data_, normal_attr,
|
||||
normal_map_output_attrs[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connect an emissive texture if specified.
|
||||
if (mjTEXROLE_EMISSIVE < textures.size()) {
|
||||
std::string emissive_texture_name = textures[mjTEXROLE_EMISSIVE];
|
||||
mjsTexture *emissive_texture = mjs_asTexture(
|
||||
mjs_findElement(spec_, mjOBJ_TEXTURE, emissive_texture_name.c_str()));
|
||||
if (emissive_texture) {
|
||||
pxr::SdfPath emissive_attr = CreateAttributeSpec(
|
||||
data_, preview_surface_shader_path, kTokens->inputsEmissiveColor,
|
||||
pxr::SdfValueTypeNames->Color3f);
|
||||
const std::vector<pxr::SdfPath> emissive_map_output_attrs =
|
||||
AddTextureShader(material_path, emissive_texture->file->c_str(),
|
||||
pxr::TfToken("emissive"), uvmap_st_output_attr,
|
||||
{kTokens->outputsRgb});
|
||||
if (emissive_map_output_attrs.size() == 1) {
|
||||
AddAttributeConnection(data_, emissive_attr,
|
||||
emissive_map_output_attrs[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the value of diffuse color. This can come from a diffuse texture
|
||||
// or as a value defined in mjsMaterial_.
|
||||
pxr::SdfPath diffuse_color_attr = CreateAttributeSpec(
|
||||
data_, preview_surface_shader_path, kTokens->inputsDiffuseColor,
|
||||
pxr::SdfValueTypeNames->Color3f);
|
||||
|
||||
// Find the main texture if specified.
|
||||
std::string main_texture_name = (*material->textures)[mjTEXROLE_RGB];
|
||||
std::string main_texture_name = textures[mjTEXROLE_RGB];
|
||||
mjsTexture *main_texture = mjs_asTexture(
|
||||
mjs_findElement(spec_, mjOBJ_TEXTURE, main_texture_name.c_str()));
|
||||
if (main_texture) {
|
||||
// Create the texture shader and connect it to the diffuse color
|
||||
// attribute.
|
||||
pxr::SdfPath texture_rgb_output_attr =
|
||||
AddTextureShader(material_path, main_texture->file->c_str());
|
||||
AddAttributeConnection(data_, diffuse_color_attr,
|
||||
texture_rgb_output_attr);
|
||||
const std::vector<pxr::SdfPath> texture_diffuse_output_attrs =
|
||||
AddTextureShader(material_path, main_texture->file->c_str(),
|
||||
pxr::TfToken("diffuse"), uvmap_st_output_attr,
|
||||
{kTokens->outputsRgb});
|
||||
if (texture_diffuse_output_attrs.size() == 1) {
|
||||
AddAttributeConnection(data_, diffuse_color_attr,
|
||||
texture_diffuse_output_attrs[0]);
|
||||
}
|
||||
} else {
|
||||
// If no texture is specified, use the rgba diffuse color.
|
||||
SetAttributeDefault(data_, diffuse_color_attr,
|
||||
pxr::GfVec3f(material->rgba[0], material->rgba[1],
|
||||
material->rgba[2]));
|
||||
}
|
||||
|
||||
pxr::SdfPath metallic_attr = CreateAttributeSpec(
|
||||
data_, preview_surface_shader_path, kTokens->inputsMetallic,
|
||||
pxr::SdfValueTypeNames->Float);
|
||||
SetAttributeDefault(data_, metallic_attr, material->metallic);
|
||||
|
||||
pxr::SdfPath material_surface_output_attr = CreateAttributeSpec(
|
||||
data_, material_path, pxr::UsdShadeTokens->outputsSurface,
|
||||
pxr::SdfValueTypeNames->Token);
|
||||
|
||||
AddAttributeConnection(data_, material_surface_output_attr,
|
||||
surface_output_attr);
|
||||
|
||||
pxr::SdfPath material_displacement_output_attr = CreateAttributeSpec(
|
||||
data_, material_path, pxr::UsdShadeTokens->outputsDisplacement,
|
||||
pxr::SdfValueTypeNames->Token);
|
||||
|
||||
AddAttributeConnection(data_, material_displacement_output_attr,
|
||||
displacement_output_attr);
|
||||
}
|
||||
|
||||
void WriteMaterials() {
|
||||
@@ -780,6 +938,9 @@ class ModelWriter {
|
||||
actuator->trntype == mjtTrn::mjTRN_SLIDERCRANK) {
|
||||
int site_id = mj_name2id(model_, mjOBJ_SITE, actuator->target->c_str());
|
||||
transmission_path = site_paths_[site_id];
|
||||
} else if (actuator->trntype == mjtTrn::mjTRN_JOINT) {
|
||||
int joint_id = mj_name2id(model_, mjOBJ_JOINT, actuator->target->c_str());
|
||||
transmission_path = joint_paths_[joint_id];
|
||||
} else {
|
||||
TF_WARN(UnsupportedActuatorTypeError,
|
||||
"Unsupported actuator type for actuator %d",
|
||||
@@ -791,22 +952,23 @@ class ModelWriter {
|
||||
MjcPhysicsTokens->PhysicsActuatorAPI);
|
||||
|
||||
if (!actuator->refsite->empty()) {
|
||||
int refsite_id = mj_name2id(model_, mjOBJ_SITE, actuator->refsite->c_str());
|
||||
int refsite_id =
|
||||
mj_name2id(model_, mjOBJ_SITE, actuator->refsite->c_str());
|
||||
pxr::SdfPath refsite_path = site_paths_[refsite_id];
|
||||
CreateRelationshipSpec(data_, transmission_path,
|
||||
MjcPhysicsTokens->mjcRefSite,
|
||||
refsite_path, pxr::SdfVariabilityUniform);
|
||||
MjcPhysicsTokens->mjcRefSite, refsite_path,
|
||||
pxr::SdfVariabilityUniform);
|
||||
}
|
||||
|
||||
if (!actuator->slidersite->empty()) {
|
||||
int slidersite_id = mj_name2id(model_, mjOBJ_SITE, actuator->slidersite->c_str());
|
||||
int slidersite_id =
|
||||
mj_name2id(model_, mjOBJ_SITE, actuator->slidersite->c_str());
|
||||
pxr::SdfPath slidersite_path = site_paths_[slidersite_id];
|
||||
CreateRelationshipSpec(data_, transmission_path,
|
||||
MjcPhysicsTokens->mjcSliderSite,
|
||||
slidersite_path, pxr::SdfVariabilityUniform);
|
||||
MjcPhysicsTokens->mjcSliderSite, slidersite_path,
|
||||
pxr::SdfVariabilityUniform);
|
||||
}
|
||||
|
||||
|
||||
const std::vector<std::pair<pxr::TfToken, int>> limited_attributes = {
|
||||
{MjcPhysicsTokens->mjcCtrlLimited, actuator->ctrllimited},
|
||||
{MjcPhysicsTokens->mjcForceLimited, actuator->forcelimited},
|
||||
@@ -872,7 +1034,6 @@ class ModelWriter {
|
||||
MjcPhysicsTokens->mjcDynPrm,
|
||||
pxr::VtDoubleArray(actuator->dynprm, actuator->dynprm + 10));
|
||||
|
||||
|
||||
pxr::TfToken gain_type;
|
||||
if (actuator->gaintype == mjtGain::mjGAIN_FIXED) {
|
||||
gain_type = MjcPhysicsTokens->fixed;
|
||||
@@ -1345,6 +1506,296 @@ class ModelWriter {
|
||||
}
|
||||
}
|
||||
|
||||
void WriteJoints(mjsBody *body) {
|
||||
if (!write_physics_) return;
|
||||
|
||||
int body_id = mjs_getId(body->element);
|
||||
if (body_id == kWorldIndex) return;
|
||||
|
||||
mjsJoint *joint = mjs_asJoint(mjs_firstChild(body, mjOBJ_JOINT, false));
|
||||
|
||||
if (!joint) {
|
||||
// If no joint is found, then we pass nullptr to create a FixedJoint.
|
||||
// WriteJoint properly handles the case where the parent is the worldbody.
|
||||
WriteJoint(nullptr, body);
|
||||
} else {
|
||||
WriteJoint(joint, body);
|
||||
if (mjs_asJoint(mjs_nextChild(body, joint->element, false))) {
|
||||
TF_WARN(
|
||||
"Multiple joints found for body %d. Only writing the first one.",
|
||||
body_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write the joint. If null, then a FixedJoint is created.
|
||||
void WriteJoint(mjsJoint *joint, const mjsBody *parent_mj_body) {
|
||||
// Default to fixed joint if joint is null.
|
||||
pxr::TfToken joint_prim_type = pxr::UsdPhysicsTokens->PhysicsFixedJoint;
|
||||
|
||||
int joint_id = -1;
|
||||
if (joint) {
|
||||
joint_id = mjs_getId(joint->element);
|
||||
mjtJoint type = (mjtJoint)model_->jnt_type[joint_id];
|
||||
switch (type) {
|
||||
case mjJNT_FREE:
|
||||
// Free joints are guaranteed to only ever be on the top-level body so
|
||||
// we just write no joint. As a top-level body with no joint it will
|
||||
// be considered a floating-base body.
|
||||
return;
|
||||
case mjJNT_HINGE:
|
||||
joint_prim_type = pxr::UsdPhysicsTokens->PhysicsRevoluteJoint;
|
||||
break;
|
||||
case mjJNT_SLIDE:
|
||||
joint_prim_type = pxr::UsdPhysicsTokens->PhysicsPrismaticJoint;
|
||||
break;
|
||||
default:
|
||||
TF_WARN("Unsupported joint type '%d' for joint '%s'. Skipping.",
|
||||
(int)type, joint->name->c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int body_id = mjs_getId(parent_mj_body->element);
|
||||
|
||||
// the joint connects the current body as body1, to its parent body as
|
||||
// body0.
|
||||
int body1_id_usd = body_id;
|
||||
int body0_id_usd = model_->body_parentid[body_id];
|
||||
|
||||
const pxr::SdfPath &body1_path_usd = body_paths_[body1_id_usd];
|
||||
auto joint_name = joint ? *joint->name : "FixedJoint";
|
||||
pxr::TfToken joint_name_token =
|
||||
GetAvailablePrimName(joint_name, kTokens->joint, body1_path_usd);
|
||||
pxr::SdfPath joint_path = CreatePrimSpec(data_, body1_path_usd,
|
||||
joint_name_token, joint_prim_type);
|
||||
|
||||
// Set body0 and body1 relationships
|
||||
// For the initial joints that connect to the world, we signal this by
|
||||
// keeping the body0 relationship empty.
|
||||
if (body0_id_usd != kWorldIndex) {
|
||||
const pxr::SdfPath &body0_path_usd = body_paths_[body0_id_usd];
|
||||
CreateRelationshipSpec(data_, joint_path,
|
||||
pxr::UsdPhysicsTokens->physicsBody0,
|
||||
body0_path_usd, pxr::SdfVariabilityUniform);
|
||||
}
|
||||
CreateRelationshipSpec(data_, joint_path,
|
||||
pxr::UsdPhysicsTokens->physicsBody1, body1_path_usd,
|
||||
pxr::SdfVariabilityUniform);
|
||||
|
||||
// Joint frame in MuJoCo is defined by jnt_pos and jnt_axis in body1's frame
|
||||
// For FixedJoint, these are both unity.
|
||||
pxr::GfVec3d mj_jnt_pos = pxr::GfVec3d(0.0);
|
||||
pxr::GfVec3d mj_jnt_axis = pxr::GfVec3d(0.0, 0.0, 1.0);
|
||||
if (joint) {
|
||||
mj_jnt_pos = pxr::GfVec3d(&model_->jnt_pos[joint_id * 3]);
|
||||
mj_jnt_axis = pxr::GfVec3d(&model_->jnt_axis[joint_id * 3]);
|
||||
}
|
||||
|
||||
// Local joint frame for body1
|
||||
pxr::GfVec3f local_pos1(mj_jnt_pos);
|
||||
pxr::GfRotation().SetRotateInto(pxr::GfVec3f::ZAxis(), mj_jnt_axis);
|
||||
pxr::GfQuatf local_rot1(
|
||||
pxr::GfRotation()
|
||||
.SetRotateInto(pxr::GfVec3f::ZAxis(), mj_jnt_axis)
|
||||
.GetQuat());
|
||||
|
||||
SetAttributeDefault(
|
||||
data_,
|
||||
CreateAttributeSpec(data_, joint_path,
|
||||
pxr::UsdPhysicsTokens->physicsLocalPos1,
|
||||
pxr::SdfValueTypeNames->Float3),
|
||||
local_pos1);
|
||||
if (joint_prim_type == pxr::UsdPhysicsTokens->PhysicsRevoluteJoint ||
|
||||
joint_prim_type == pxr::UsdPhysicsTokens->PhysicsPrismaticJoint) {
|
||||
SetAttributeDefault(
|
||||
data_,
|
||||
CreateAttributeSpec(data_, joint_path,
|
||||
pxr::UsdPhysicsTokens->physicsLocalRot1,
|
||||
pxr::SdfValueTypeNames->Quatf),
|
||||
local_rot1);
|
||||
} else {
|
||||
SetAttributeDefault(
|
||||
data_,
|
||||
CreateAttributeSpec(data_, joint_path,
|
||||
pxr::UsdPhysicsTokens->physicsLocalRot1,
|
||||
pxr::SdfValueTypeNames->Quatf),
|
||||
pxr::GfQuatf::GetIdentity());
|
||||
}
|
||||
|
||||
// Calculate local joint frame for body0
|
||||
pxr::GfMatrix4d body1_transform_local =
|
||||
MujocoPosQuatToTransform(&model_->body_pos[body1_id_usd * 3],
|
||||
&model_->body_quat[body1_id_usd * 4]);
|
||||
pxr::GfVec3d jnt_pos_parent_local =
|
||||
body1_transform_local.Transform(mj_jnt_pos);
|
||||
pxr::GfVec3d jnt_axis_parent_local =
|
||||
body1_transform_local.TransformDir(mj_jnt_axis);
|
||||
|
||||
pxr::GfVec3f local_pos0(jnt_pos_parent_local);
|
||||
|
||||
SetAttributeDefault(
|
||||
data_,
|
||||
CreateAttributeSpec(data_, joint_path,
|
||||
pxr::UsdPhysicsTokens->physicsLocalPos0,
|
||||
pxr::SdfValueTypeNames->Float3),
|
||||
local_pos0);
|
||||
|
||||
if (joint_prim_type == pxr::UsdPhysicsTokens->PhysicsRevoluteJoint ||
|
||||
joint_prim_type == pxr::UsdPhysicsTokens->PhysicsPrismaticJoint) {
|
||||
pxr::GfQuatf other_rot0(
|
||||
pxr::GfRotation()
|
||||
.SetRotateInto(pxr::GfVec3f::ZAxis(), jnt_axis_parent_local)
|
||||
.GetQuat());
|
||||
|
||||
SetAttributeDefault(
|
||||
data_,
|
||||
CreateAttributeSpec(data_, joint_path,
|
||||
pxr::UsdPhysicsTokens->physicsLocalRot0,
|
||||
pxr::SdfValueTypeNames->Quatf),
|
||||
other_rot0);
|
||||
} else {
|
||||
// Fixed joints have no frame and no axis per se. We simply need the
|
||||
// rotation quaternion of the body its on.
|
||||
SetAttributeDefault(
|
||||
data_,
|
||||
CreateAttributeSpec(data_, joint_path,
|
||||
pxr::UsdPhysicsTokens->physicsLocalRot0,
|
||||
pxr::SdfValueTypeNames->Quatf),
|
||||
body1_transform_local.ExtractRotationQuat());
|
||||
}
|
||||
|
||||
if (joint) {
|
||||
mjtJoint type = (mjtJoint)model_->jnt_type[joint_id];
|
||||
|
||||
// Joint-specific attributes
|
||||
if (type == mjJNT_HINGE || type == mjJNT_SLIDE) {
|
||||
// The joint motion occurs around/along the Z-axis of the joint frame
|
||||
// established by localRot0/1.
|
||||
SetAttributeDefault(
|
||||
data_,
|
||||
CreateAttributeSpec(data_, joint_path,
|
||||
pxr::UsdPhysicsTokens->physicsAxis,
|
||||
pxr::SdfValueTypeNames->Token),
|
||||
pxr::UsdPhysicsTokens->z); // "Z" axis
|
||||
}
|
||||
|
||||
if (model_->jnt_limited[joint_id]) {
|
||||
float lower_limit = model_->jnt_range[joint_id * 2];
|
||||
float upper_limit = model_->jnt_range[joint_id * 2 + 1];
|
||||
|
||||
if (type == mjJNT_HINGE) {
|
||||
// Convert radians to degrees for USD
|
||||
// As per the XML Reference, "mjModel always uses radians"
|
||||
lower_limit *= (180.0 / mjPI);
|
||||
upper_limit *= (180.0 / mjPI);
|
||||
SetAttributeDefault(
|
||||
data_,
|
||||
CreateAttributeSpec(data_, joint_path,
|
||||
pxr::UsdPhysicsTokens->physicsLowerLimit,
|
||||
pxr::SdfValueTypeNames->Float),
|
||||
lower_limit);
|
||||
SetAttributeDefault(
|
||||
data_,
|
||||
CreateAttributeSpec(data_, joint_path,
|
||||
pxr::UsdPhysicsTokens->physicsUpperLimit,
|
||||
pxr::SdfValueTypeNames->Float),
|
||||
upper_limit);
|
||||
} else if (type == mjJNT_SLIDE) {
|
||||
SetAttributeDefault(
|
||||
data_,
|
||||
CreateAttributeSpec(data_, joint_path,
|
||||
pxr::UsdPhysicsTokens->physicsLowerLimit,
|
||||
pxr::SdfValueTypeNames->Float),
|
||||
lower_limit);
|
||||
SetAttributeDefault(
|
||||
data_,
|
||||
CreateAttributeSpec(data_, joint_path,
|
||||
pxr::UsdPhysicsTokens->physicsUpperLimit,
|
||||
pxr::SdfValueTypeNames->Float),
|
||||
upper_limit);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally write the mjcPhysicsJointAPI attributes.
|
||||
ApplyApiSchema(data_, joint_path, MjcPhysicsTokens->PhysicsJointsAPI);
|
||||
|
||||
WriteUniformAttribute(
|
||||
joint_path, pxr::SdfValueTypeNames->DoubleArray,
|
||||
MjcPhysicsTokens->mjcSpringdamper,
|
||||
pxr::VtArray<double>(joint->springdamper, joint->springdamper + 2));
|
||||
|
||||
WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->DoubleArray,
|
||||
MjcPhysicsTokens->mjcSolreflimit,
|
||||
pxr::VtArray<double>(joint->solref_limit,
|
||||
joint->solref_limit + mjNREF));
|
||||
|
||||
WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->DoubleArray,
|
||||
MjcPhysicsTokens->mjcSolimplimit,
|
||||
pxr::VtArray<double>(joint->solimp_limit,
|
||||
joint->solimp_limit + mjNIMP));
|
||||
|
||||
WriteUniformAttribute(
|
||||
joint_path, pxr::SdfValueTypeNames->DoubleArray,
|
||||
MjcPhysicsTokens->mjcSolreffriction,
|
||||
pxr::VtArray<double>(joint->solref_friction,
|
||||
joint->solref_friction + mjNREF));
|
||||
|
||||
WriteUniformAttribute(
|
||||
joint_path, pxr::SdfValueTypeNames->DoubleArray,
|
||||
MjcPhysicsTokens->mjcSolimpfriction,
|
||||
pxr::VtArray<double>(joint->solimp_friction,
|
||||
joint->solimp_friction + mjNIMP));
|
||||
|
||||
WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double,
|
||||
MjcPhysicsTokens->mjcStiffness, joint->stiffness);
|
||||
|
||||
WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double,
|
||||
MjcPhysicsTokens->mjcActuatorfrcrangeMin,
|
||||
joint->actfrcrange[0]);
|
||||
|
||||
WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double,
|
||||
MjcPhysicsTokens->mjcActuatorfrcrangeMax,
|
||||
joint->actfrcrange[1]);
|
||||
|
||||
pxr::TfToken actuatorfrclimited_token = MjcPhysicsTokens->auto_;
|
||||
if (joint->actfrclimited == mjLIMITED_TRUE) {
|
||||
actuatorfrclimited_token = MjcPhysicsTokens->true_;
|
||||
} else if (joint->actfrclimited == mjLIMITED_FALSE) {
|
||||
actuatorfrclimited_token = MjcPhysicsTokens->false_;
|
||||
}
|
||||
WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Token,
|
||||
MjcPhysicsTokens->mjcActuatorfrclimited,
|
||||
actuatorfrclimited_token);
|
||||
|
||||
WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Bool,
|
||||
MjcPhysicsTokens->mjcActuatorgravcomp,
|
||||
static_cast<bool>(joint->actgravcomp));
|
||||
|
||||
WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double,
|
||||
MjcPhysicsTokens->mjcMargin, joint->margin);
|
||||
|
||||
WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double,
|
||||
MjcPhysicsTokens->mjcRef, joint->ref);
|
||||
|
||||
WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double,
|
||||
MjcPhysicsTokens->mjcSpringref, joint->springref);
|
||||
|
||||
WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double,
|
||||
MjcPhysicsTokens->mjcArmature, joint->armature);
|
||||
|
||||
WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double,
|
||||
MjcPhysicsTokens->mjcDamping, joint->damping);
|
||||
|
||||
WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double,
|
||||
MjcPhysicsTokens->mjcFrictionloss,
|
||||
joint->frictionloss);
|
||||
}
|
||||
if (joint_id >= 0) {
|
||||
joint_paths_[joint_id] = joint_path;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteCamera(mjsCamera *spec_cam, const mjsBody *body) {
|
||||
const auto &body_path = body_paths_[mjs_getId(body->element)];
|
||||
auto name = GetAvailablePrimName(*spec_cam->name,
|
||||
@@ -1444,6 +1895,16 @@ class ModelWriter {
|
||||
: pxr::KindTokens->subcomponent;
|
||||
SetPrimKind(data_, body_path, kind);
|
||||
|
||||
// If the parent is not the world body, but is child of the world body
|
||||
// then we need to apply the articulation root API.
|
||||
if (parent_id != kWorldIndex) {
|
||||
int parent_parent_id = mjs_getId(mjs_getParent(parent->element)->element);
|
||||
if (parent_parent_id == kWorldIndex) {
|
||||
ApplyApiSchema(data_, parent_path,
|
||||
pxr::UsdPhysicsTokens->PhysicsArticulationRootAPI);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the PhysicsRigidBodyAPI schema if we are writing physics.
|
||||
if (write_physics_) {
|
||||
// If the body had a mass specified then it must have either inertia or
|
||||
@@ -1486,17 +1947,6 @@ class ModelWriter {
|
||||
|
||||
ApplyApiSchema(data_, body_path,
|
||||
pxr::UsdPhysicsTokens->PhysicsRigidBodyAPI);
|
||||
|
||||
// If the parent is not the world body, but is child of the world body
|
||||
// then we need to apply the articulation root API.
|
||||
if (parent_id != kWorldIndex) {
|
||||
int parent_parent_id =
|
||||
mjs_getId(mjs_getParent(parent->element)->element);
|
||||
if (parent_parent_id == kWorldIndex) {
|
||||
ApplyApiSchema(data_, parent_path,
|
||||
pxr::UsdPhysicsTokens->PhysicsArticulationRootAPI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create classes if necessary
|
||||
@@ -1543,6 +1993,7 @@ class ModelWriter {
|
||||
}
|
||||
WriteSites(body);
|
||||
WriteGeoms(body);
|
||||
WriteJoints(body);
|
||||
WriteCameras(body);
|
||||
WriteLights(body);
|
||||
body = mjs_asBody(mjs_nextElement(spec_, body->element));
|
||||
@@ -1558,6 +2009,7 @@ class ModelWriter {
|
||||
CreatePrimSpec(data_, pxr::SdfPath::AbsoluteRootPath(), name,
|
||||
pxr::UsdGeomTokens->Xform);
|
||||
SetPrimKind(data_, world_group_path, pxr::KindTokens->group);
|
||||
|
||||
return world_group_path;
|
||||
}
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "third_party/mujoco/src/experimental/usd/utils.h"
|
||||
#include <mujoco/experimental/usd/utils.h>
|
||||
|
||||
#include <mujoco/mujoco.h>
|
||||
#include <pxr/usd/sdf/path.h>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user