diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f2c06805..1a207fd9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -347,7 +347,7 @@ jobs: CHATMSG_AUTHOR_EMAIL: ${{ github.event.head_commit.author.email }} CHATMSG_COMMIT_MESSAGE: ${{ github.event.head_commit.message }} CHATMSG_JOB_ID: ${{ matrix.label }} - if: ${{ failure() && github.event_name == 'push' && env.GCHAT_API_URL != '' }} + if: failure() && github.ref_name == 'main' && github.event_name == 'push' && env.GCHAT_API_URL != '' run: bash ./.github/workflows/build_steps.sh notify_team_chat # This job quickly determines if MuJoCo Studio is broken. @@ -406,7 +406,7 @@ jobs: CHATMSG_AUTHOR_EMAIL: ${{ github.event.head_commit.author.email }} CHATMSG_COMMIT_MESSAGE: ${{ github.event.head_commit.message }} CHATMSG_JOB_ID: ${{ matrix.label }} - if: ${{ failure() && github.event_name == 'push' && env.GCHAT_API_URL != '' }} + if: failure() && github.ref_name == 'main' && github.event_name == 'push' && env.GCHAT_API_URL != '' run: bash ./.github/workflows/build_steps.sh notify_team_chat @@ -451,5 +451,5 @@ jobs: CHATMSG_AUTHOR_EMAIL: ${{ github.event.head_commit.author.email }} CHATMSG_COMMIT_MESSAGE: ${{ github.event.head_commit.message }} CHATMSG_JOB_ID: ${{ env.label }} - if: ${{ failure() && github.event_name == 'push' && env.GCHAT_API_URL != '' }} + if: failure() && github.ref_name == 'main' && github.event_name == 'push' && env.GCHAT_API_URL != '' run: bash ./.github/workflows/build_steps.sh notify_team_chat diff --git a/.github/workflows/build_steps.sh b/.github/workflows/build_steps.sh index 6c8877d4..9e5440f9 100755 --- a/.github/workflows/build_steps.sh +++ b/.github/workflows/build_steps.sh @@ -107,8 +107,6 @@ copy_plugins_posix() { mkdir -p ${TMPDIR}/mujoco_install/mujoco_plugin && cp lib/libactuator.* ${TMPDIR}/mujoco_install/mujoco_plugin && cp lib/libelasticity.* ${TMPDIR}/mujoco_install/mujoco_plugin && - cp lib/libobj_decoder.* ${TMPDIR}/mujoco_install/mujoco_plugin && - cp lib/libstl_decoder.* ${TMPDIR}/mujoco_install/mujoco_plugin && cp lib/libsensor.* ${TMPDIR}/mujoco_install/mujoco_plugin && cp lib/libsdf_plugin.* ${TMPDIR}/mujoco_install/mujoco_plugin } @@ -119,8 +117,6 @@ copy_plugins_window() { mkdir -p ${TMPDIR}/mujoco_install/mujoco_plugin && cp bin/Release/actuator.dll ${TMPDIR}/mujoco_install/mujoco_plugin && cp bin/Release/elasticity.dll ${TMPDIR}/mujoco_install/mujoco_plugin && - cp bin/Release/obj_decoder.dll ${TMPDIR}/mujoco_install/mujoco_plugin && - cp bin/Release/stl_decoder.dll ${TMPDIR}/mujoco_install/mujoco_plugin && cp bin/Release/sensor.dll ${TMPDIR}/mujoco_install/mujoco_plugin } @@ -216,25 +212,28 @@ build_test_wasm() { echo "Building and testing WASM bindings..." source emsdk/emsdk_env.sh export PATH="$(pwd)/node_modules/.bin:$PATH" - - echo "Building Multi-Threaded version..." + echo "Build MuJoCo with Emscripten (Multi-Threaded)..." emcmake cmake -B build_wasm_mt \ -DCMAKE_INTERPROCEDURAL_OPTIMIZATION:BOOL=OFF \ -DMUJOCO_WASM_THREADS=ON \ $WASM_CMAKE_ARGS cmake --build build_wasm_mt --parallel $(nproc) + echo "Run bindings tests for Multi-Threaded version..." + npm run test --prefix ./wasm + echo "Moving Multi-Thread version under mt subfolder..." mkdir -p wasm/dist/mt mv wasm/dist/mujoco.* wasm/dist/mt/ - echo "Building Single-Threaded version..." + echo "Build MuJoCo with Emscripten (Single-Threaded)..." emcmake cmake -B build_wasm_st \ -DCMAKE_INTERPROCEDURAL_OPTIMIZATION:BOOL=OFF \ -DMUJOCO_WASM_THREADS=OFF \ $WASM_CMAKE_ARGS cmake --build build_wasm_st --parallel $(nproc) + echo "Run bindings tests for Single-Threaded version..." npm run test --prefix ./wasm } @@ -296,6 +295,32 @@ EOF } +build_mujoco_live() { + echo "Setting up Emscripten SDK..." + source emsdk/emsdk_env.sh + + echo "Building Filament tools, targeting host platform..." + cmake -S . -B build_host -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DUSE_STATIC_LIBCXX=OFF \ + -DMUJOCO_BUILD_STUDIO=ON \ + -DMUJOCO_USE_FILAMENT=ON \ + -DMUJOCO_BUILD_TESTS=OFF \ + -DMUJOCO_BUILD_EXAMPLES=OFF \ + -DMUJOCO_BUILD_SIMULATE=OFF + cmake --build build_host --target matc resgen cmgen mujoco_filament_assets -j$(nproc) + + echo "Building WASM app..." + emcmake cmake -S . -B build_wasm -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DMUJOCO_BUILD_STUDIO=ON \ + -DMUJOCO_USE_FILAMENT=ON \ + -DMUJOCO_BUILD_TESTS_WASM=OFF \ + -DMUJOCO_NATIVE_BUILD_DIR=$(pwd)/build_host + cmake --build build_wasm --target mujoco_live -j$(nproc) +} + + # Discover functions defined in this script by finding identifiers followed by # "()" and capturing the identifier as a valid function name. VALID_FUNCTIONS=() diff --git a/.github/workflows/live.yml b/.github/workflows/live.yml new file mode 100644 index 00000000..49cd5359 --- /dev/null +++ b/.github/workflows/live.yml @@ -0,0 +1,51 @@ +name: live + +on: + push: + branches: + - live + +permissions: + contents: read + pages: write + id-token: write + +jobs: + build-and-upload-artifacts: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - name: Prepare Linux + run: bash ./.github/workflows/build_steps.sh prepare_linux + + - name: Setup Emscripten + run: bash ./.github/workflows/build_steps.sh setup_emsdk + + - name: Build MuJoCo Live + env: + CC: clang-18 + CXX: clang++-18 + run: bash ./.github/workflows/build_steps.sh build_mujoco_live + + - name: Prepare files for GitHub Pages + run: | + mkdir -p dist/bin + cp -r build_wasm/bin/* dist/bin/ + cp src/experimental/studio/index.html dist/index.html + + - name: Upload GitHub Pages artifacts + uses: actions/upload-pages-artifact@v3 + with: + path: dist + + deploy-pages: + needs: build-and-upload-artifacts + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.readthedocs.yml b/.readthedocs.yml index 00c093bb..89ef662f 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -11,21 +11,37 @@ build: os: ubuntu-24.04 tools: python: "3.12" + apt_packages: + - libgl-dev jobs: create_environment: + # install uv - asdf plugin add uv - asdf install uv latest - asdf global uv latest - uv venv $READTHEDOCS_VIRTUALENV_PATH - - UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv pip install -r doc/requirements.txt - - UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv pip install mujoco mujoco-mjx - # replace mujoco.mjx.third_party.mujoco_warp import paths with mujoco_warp + # install doc requirements - | - find mjx/mujoco/mjx/third_party/mujoco_warp -type f -exec sed -i 's/mujoco\.mjx\.third_party\.mujoco_warp/mujoco_warp/g' {} \; + UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH \ + uv pip install \ + -r doc/requirements.txt \ + pip setuptools absl-py + # generate and install doc-only mujoco stubs (no C build required) + - python doc/make_mujoco_stubs.py python/mujoco_doc + - | + UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH \ + uv pip install --no-deps python/mujoco_doc + # install mjx and mujoco_warp (mujoco dep satisfied by stubs above) + - UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv pip install -e mjx + - | + find mjx/mujoco/mjx/third_party/mujoco_warp -type f -exec \ + sed -i 's/mujoco\.mjx\.third_party\.mujoco_warp/mujoco_warp/g' {} \; - python doc/mjwarp/update_types.py mjx/mujoco/mjx/third_party/mujoco_warp/_src/types.py - - UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv pip install mjx/mujoco/mjx/third_party/mujoco_warp + - | + UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH \ + uv pip install mjx/mujoco/mjx/third_party/mujoco_warp install: - - "true" # skip + - "true" # skip default install sphinx: builder: html diff --git a/CMakeLists.txt b/CMakeLists.txt index f79153c5..92254c2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ set(MSVC_INCREMENTAL_DEFAULT ON) project( mujoco - VERSION 3.7.0 + VERSION 3.9.0 DESCRIPTION "MuJoCo Physics Simulator" HOMEPAGE_URL "https://mujoco.org" ) @@ -53,8 +53,49 @@ endif() if(EMSCRIPTEN) option(MUJOCO_BUILD_TESTS_WASM "Build tests for WASM bindings" ON) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20 -O3 -pthread -fexceptions") + option(MUJOCO_BUILD_STUDIO "Build studio for MuJoCo (WASM)" OFF) + option(MUJOCO_USE_FILAMENT "Use filament rendering" OFF) + option(MUJOCO_WASM_THREADS "Build with multi-threading support" ON) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20 -O3 -fexceptions") + if(MUJOCO_WASM_THREADS) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") + endif() + + # Filament uses the WEBGL variable (not EMSCRIPTEN) to identify web builds. + # Without this, it falls into the LINUX path and tries to compile with + # futex, X11, Vulkan, etc. + if(MUJOCO_USE_FILAMENT) + set(WEBGL ON CACHE BOOL "Filament WebGL mode" FORCE) + endif() + + # Automatically generate host tool imports for Filament cross-compilation. + # When WEBGL is true, Filament hardcodes the path to: + # ${FILAMENT}/${IMPORT_EXECUTABLES_DIR}/ImportExecutables-Release.cmake + # So we write our file with that exact name and set IMPORT_EXECUTABLES_DIR + # to point at CMAKE_BINARY_DIR (which is ../../ relative to filament-src). + set(MUJOCO_NATIVE_BUILD_DIR "${PROJECT_SOURCE_DIR}/build-host" CACHE PATH "Path to native build directory containing host tools") + find_program(MATC_EXE matc PATHS "${MUJOCO_NATIVE_BUILD_DIR}/bin" NO_DEFAULT_PATH) + find_program(RESGEN_EXE resgen PATHS "${MUJOCO_NATIVE_BUILD_DIR}/bin" NO_DEFAULT_PATH) + find_program(CMGEN_EXE cmgen PATHS "${MUJOCO_NATIVE_BUILD_DIR}/bin" NO_DEFAULT_PATH) + + if(MATC_EXE AND RESGEN_EXE AND CMGEN_EXE) + message(STATUS "Found host tools in ${MUJOCO_NATIVE_BUILD_DIR}/bin") + set(IMPORT_EXECUTABLES_FILE "${CMAKE_BINARY_DIR}/ImportExecutables-Release.cmake") + file(WRITE "${IMPORT_EXECUTABLES_FILE}" + "add_executable(matc IMPORTED)\n" + "set_property(TARGET matc PROPERTY IMPORTED_LOCATION \"${MATC_EXE}\")\n" + "add_executable(resgen IMPORTED)\n" + "set_property(TARGET resgen PROPERTY IMPORTED_LOCATION \"${RESGEN_EXE}\")\n" + "add_executable(cmgen IMPORTED)\n" + "set_property(TARGET cmgen PROPERTY IMPORTED_LOCATION \"${CMGEN_EXE}\")\n" + ) + # Filament's WEBGL path resolves: ${FILAMENT}/${IMPORT_EXECUTABLES_DIR}/ImportExecutables-Release.cmake + # FILAMENT = _deps/filament-src, so ../../ resolves to CMAKE_BINARY_DIR. + set(IMPORT_EXECUTABLES_DIR "../../" CACHE PATH "" FORCE) + else() + message(WARNING "Host tools (matc, resgen, cmgen) not found in ${MUJOCO_NATIVE_BUILD_DIR}/bin. WASM build of Studio might fail.") + endif() endif() if(APPLE AND (MUJOCO_BUILD_EXAMPLES OR MUJOCO_BUILD_SIMULATE)) @@ -112,6 +153,7 @@ if(NOT EMSCRIPTEN) endif() add_subdirectory(plugin/obj_decoder) add_subdirectory(plugin/stl_decoder) + add_subdirectory(src/engine) add_subdirectory(src/user) add_subdirectory(src/xml) @@ -120,16 +162,14 @@ if(NOT EMSCRIPTEN AND NOT MUJOCO_USE_FILAMENT_MJR_COMPAT) add_subdirectory(src/render/classic) add_subdirectory(src/ui) endif() +add_subdirectory(src/render/noop) -if(MUJOCO_USE_FILAMENT AND NOT EMSCRIPTEN) +if(MUJOCO_USE_FILAMENT) add_subdirectory(src/experimental/filament) endif() if(EMSCRIPTEN) add_subdirectory(wasm) - if(MUJOCO_BUILD_TESTS_WASM) - add_subdirectory(wasm/tests) - endif() endif() @@ -216,7 +256,7 @@ if(MUJOCO_BUILD_SIMULATE) endif() if(MUJOCO_BUILD_STUDIO) - add_subdirectory(src/experimental/mjz) + add_subdirectory(src/xml/mjz) add_subdirectory(src/experimental/platform) add_subdirectory(src/experimental/studio) endif() diff --git a/README.md b/README.md index 98bee9e2..22a23e0e 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,8 @@ These packages give users of various languages access to MuJoCo functionality: DeepMind's related environment stack, includes [PyMJCF](https://github.com/google-deepmind/dm_control/blob/main/dm_control/mjcf/README.md), a module for procedural manipulation of MuJoCo models. -- [JavaScript bindings and WebAssembly support](/wasm/README.md) (inspired [stillonearth](https://github.com/stillonearth) and [zalo](https://github.com/zalo)'s community projects). +- [JavaScript bindings and WebAssembly support](/wasm/README.md) (inspired [stillonearth](https://github.com/stillonearth) and [zalo](https://github.com/zalo)'s community projects; [mjswan](https://github.com/ttktjmt/mjswan) extends these with real-time policy control, interactive force +application, and more). - [C# bindings and Unity plug-in](https://mujoco.readthedocs.io/en/stable/unity.html) #### Third-party bindings: diff --git a/cmake/MujocoDependencies.cmake b/cmake/MujocoDependencies.cmake index d2404bc1..a6a0a4ca 100644 --- a/cmake/MujocoDependencies.cmake +++ b/cmake/MujocoDependencies.cmake @@ -38,8 +38,12 @@ set(MUJOCO_DEP_VERSION_qhull 62ccc56af071eaa478bef6ed41fd7a55d3bb2d80 CACHE STRING "Version of `qhull` to be fetched." ) +set(MUJOCO_DEP_VERSION_miniz + 3.1.1 + CACHE STRING "Version of `miniz` to be fetched." +) set(MUJOCO_DEP_VERSION_Eigen3 - 75bcd155c40cb48e647c87c3f29052360255bc9e + ea13a98decd497a8c5588fb5de71b57bcf10d864 CACHE STRING "Version of `Eigen3` to be fetched." ) @@ -243,6 +247,27 @@ if(WIN32) endif() endif() +if(DEFINED BUILD_TESTS) + set(_OLD_BUILD_TESTS "${BUILD_TESTS}") + set(_BUILD_TESTS_WAS_DEFINED TRUE) +else() + set(_BUILD_TESTS_WAS_DEFINED FALSE) +endif() +set(BUILD_TESTS OFF) +fetchpackage( + PACKAGE_NAME miniz + GIT_REPO https://github.com/richgel999/miniz.git + GIT_TAG ${MUJOCO_DEP_VERSION_miniz} + TARGETS miniz +) +if(_BUILD_TESTS_WAS_DEFINED) + set(BUILD_TESTS "${_OLD_BUILD_TESTS}") +else() + unset(BUILD_TESTS) +endif() +unset(_BUILD_TESTS_WAS_DEFINED) + + if(MUJOCO_BUILD_TESTS OR MUJOCO_BUILD_STUDIO OR MUJOCO_USE_FILAMENT) set(ABSL_PROPAGATE_CXX_STD ON) diff --git a/cmake/MujocoOptions.cmake b/cmake/MujocoOptions.cmake index a606220c..74dc340f 100644 --- a/cmake/MujocoOptions.cmake +++ b/cmake/MujocoOptions.cmake @@ -18,7 +18,11 @@ set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_C_EXTENSIONS OFF) +if(EMSCRIPTEN) + set(CMAKE_C_EXTENSIONS ON) +else() + set(CMAKE_C_EXTENSIONS OFF) +endif() set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # For LLVM tooling if(NOT CMAKE_CONFIGURATION_TYPES) diff --git a/cmake/ShellTests.cmake b/cmake/ShellTests.cmake index d2480a25..b26b1658 100644 --- a/cmake/ShellTests.cmake +++ b/cmake/ShellTests.cmake @@ -38,7 +38,6 @@ function(add_mujoco_shell_test TEST_NAME TARGET_BINARY) "CMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR}" "TARGET_BINARY=$" "TEST_TMPDIR=${TEST_TMPDIR}" - "MUJOCO_PLUGIN_DIR=$" ) if(WIN32) # Define the directory containing the mujoco DLL library so that it can be added to the PATH. diff --git a/cmake/third_party_deps/filament.cmake b/cmake/third_party_deps/filament.cmake index 007bc23b..0c94d53f 100644 --- a/cmake/third_party_deps/filament.cmake +++ b/cmake/third_party_deps/filament.cmake @@ -13,7 +13,7 @@ # limitations under the License. set(MUJOCO_DEP_VERSION_filament - a4945939de514d049baeed654efbbdd06bc5bdbf + 06793c4a80dd467025b2db1b3b7ea63bf1a865bb CACHE STRING "Tag/version of `filament` to be fetched." ) mark_as_advanced(MUJOCO_DEP_VERSION_filament) @@ -23,6 +23,15 @@ include(FindOrFetch) set(BUILD_SHARED_LIBS_OLD ${BUILD_SHARED_LIBS}) set(BUILD_SHARED_LIBS OFF) +# Filament's ShaderMinifier.cpp uses strlen without including , and +# PostProcessManager.h uses std::optional without including . +set(CMAKE_CXX_FLAGS_OLD "${CMAKE_CXX_FLAGS}") +if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /FI cstring /FI optional") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -include cstring -include optional") +endif() + set(FILAMENT_ENABLE_EXPERIMENTAL_GCC_SUPPORT ON) set(FILAMENT_SKIP_SDL2 ON) set(FILAMENT_USE_EXTERNAL_ABSL ON) @@ -39,3 +48,4 @@ fetchpackage( ) set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_OLD}) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_OLD}") diff --git a/dist/mujoco.rc b/dist/mujoco.rc index 25f2e83e..b9f1eff7 100644 --- a/dist/mujoco.rc +++ b/dist/mujoco.rc @@ -1,6 +1,6 @@ 1 VERSIONINFO -FILEVERSION 3,7,0,0 -PRODUCTVERSION 3,7,0,0 +FILEVERSION 3,9,0,0 +PRODUCTVERSION 3,9,0,0 FILEOS 0x4 FILETYPE 0x1 { @@ -9,9 +9,9 @@ FILETYPE 0x1 BLOCK "040904b0" { VALUE "ProductName", "MuJoCo" - VALUE "ProductVersion", "3.7.0" + VALUE "ProductVersion", "3.9.0" VALUE "FileDescription", "MuJoCo" - VALUE "FileVersion", "3.7.0" + VALUE "FileVersion", "3.9.0" VALUE "InternalName", "mujoco.dll" VALUE "OriginalFilename", "mujoco.dll" VALUE "CompanyName", "Google DeepMind" diff --git a/dist/simulate.rc b/dist/simulate.rc index 0626bc62..dd3f0778 100644 --- a/dist/simulate.rc +++ b/dist/simulate.rc @@ -1,8 +1,8 @@ MUJOCO ICON "mujoco.ico" 1 VERSIONINFO -FILEVERSION 3,7,0,0 -PRODUCTVERSION 3,7,0,0 +FILEVERSION 3,9,0,0 +PRODUCTVERSION 3,9,0,0 FILEOS 0x4 FILETYPE 0x1 { @@ -11,9 +11,9 @@ FILETYPE 0x1 BLOCK "040904b0" { VALUE "ProductName", "MuJoCo" - VALUE "ProductVersion", "3.7.0" + VALUE "ProductVersion", "3.9.0" VALUE "FileDescription", "MuJoCo" - VALUE "FileVersion", "3.7.0" + VALUE "FileVersion", "3.9.0" VALUE "InternalName", "simulate.exe" VALUE "OriginalFilename", "simulate.exe" VALUE "CompanyName", "Google DeepMind" diff --git a/doc/APIreference/APIglobals.rst b/doc/APIreference/APIglobals.rst index 951d0b34..ba2d63ae 100644 --- a/doc/APIreference/APIglobals.rst +++ b/doc/APIreference/APIglobals.rst @@ -388,7 +388,7 @@ Defined in `mujoco.h ` for more details. +Register a plugin before `main()` is called. This macro takes a unique identifier `n` as an argument that is used to avoid +name collisions between different plugin initialization functions. See :ref:`plugin registration` for +more details. .. _tyXMacro: diff --git a/doc/APIreference/functions.rst b/doc/APIreference/functions.rst index df6381f5..fc8a07c4 100644 --- a/doc/APIreference/functions.rst +++ b/doc/APIreference/functions.rst @@ -1179,6 +1179,18 @@ It is also triggered for :ref:`user sensors` of :ref:`stage`__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. mujoco-include:: mj_maxContact + +Return the maximum number of contacts that can be generated between two geoms. + +If has_margin is -1, then the margin is pulled from the model, otherwise if has_margin > 0 +indicates that the geoms have a positive margin. + .. _mj_collision: `mj_collision <#mj_collision>`__ @@ -1507,6 +1519,24 @@ Add file to VFS from buffer; return 0: success, 2: repeated name, -1: failed to Delete file from VFS; return 0: success, -1: not found in VFS. +.. _mj_containsBufferVFS: + +`mj_containsBufferVFS <#mj_containsBufferVFS>`__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. mujoco-include:: mj_containsBufferVFS + +Check if buffer exists in VFS; return 1: exists, 0: not found. + +.. _mj_containsFileVFS: + +`mj_containsFileVFS <#mj_containsFileVFS>`__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. mujoco-include:: mj_containsFileVFS + +Check if file exists in VFS; return 1: exists, 0: not found. + .. _mj_deleteVFS: `mj_deleteVFS <#mj_deleteVFS>`__ @@ -3952,6 +3982,15 @@ Convert matrix from dense to sparse. Convert matrix from sparse to dense. +.. _mju_sym2dense: + +`mju_sym2dense <#mju_sym2dense>`__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. mujoco-include:: mju_sym2dense + +Convert lower-triangular symmetric CSR matrix to full dense matrix. + .. _Quaternions: Quaternions @@ -4658,6 +4697,17 @@ Set actuator to muscle; return error if any.a Set actuator to active adhesion; return error if any. +.. _mjs_setToDCMotor: + +`mjs_setToDCMotor <#mjs_setToDCMotor>`__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. mujoco-include:: mjs_setToDCMotor + +Set actuator to DC motor; return error if any. + +*Nullable:* ``motorconst``, ``nominal``, ``saturation``, ``inductance``, ``cogging``, ``controller``, ``thermal``, ``lugre`` + .. _AddAssets: Assets @@ -4733,6 +4783,16 @@ Find and get utilities Get spec from body. +.. _mjs_getOriginSpec: + +`mjs_getOriginSpec <#mjs_getOriginSpec>`__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. mujoco-include:: mjs_getOriginSpec + +get spec that originally defined an element +contrary to mjs_getSpec, this does not change after attachment + .. _mjs_getCompiler: `mjs_getCompiler <#mjs_getCompiler>`__ diff --git a/doc/XMLreference.rst b/doc/XMLreference.rst index 7e90fa14..d136291a 100644 --- a/doc/XMLreference.rst +++ b/doc/XMLreference.rst @@ -266,7 +266,7 @@ This element does not strictly belong to MJCF. Instead it is a meta-element, use files in a single document object model (DOM) before parsing. The included file must be a valid XML file with a unique top-level element. This top-level element is removed by the parser, and the elements below it are inserted at the location of the :el:`include` element. At least one element must be inserted as a result of this procedure. The -:el:`include` element can be used where ever an XML element is expected in the MJCF file. Nested includes are allowed, +:el:`include` element can be used wherever an XML element is expected in the MJCF file. Nested includes are allowed, however a given XML file can be included at most once in the entire model. After all the included XML files have been assembled into a single DOM, it must correspond to a valid MJCF model. Other than that, it is up to the user to decide how to use includes and how to modularize large files if desired. @@ -376,8 +376,8 @@ adjust it properly through the XML. :at:`o_margin`: :at-val:`real, "0"` This attribute replaces the margin parameter of all active contact pairs when :ref:`Contact override ` is enabled. Otherwise MuJoCo uses the element-specific margin attribute of :ref:`geom` or - :ref:`pair` depending on how the contact pair was generated. See also :ref:`Collision` in the - Computation chapter. The related gap parameter does not have a global override. + :ref:`pair` depending on how the contact pair was generated. See :ref:`margin and gap` in + the Computation chapter. The related gap parameter does not have a global override. .. _option-o_solref: .. _option-o_solimp: @@ -657,18 +657,27 @@ from its default. .. _option-flag-invdiscrete: :at:`invdiscrete`: :at-val:`[disable, enable], "disable"` - This flag enables discrete-time inverse dynamics with :ref:`mj_inverse` for all - :ref:`integrators` other than ``RK4``. Recall from the - :ref:`numerical integration` section that the one-step integrators (``Euler``, ``implicit`` and - ``implicitfast``), modify the mass matrix :math:`M \rightarrow M-hD`. This implies that finite-differenced - accelerations :math:`(v_{t+h} - v_t)/h` will not correspond to the continuous-time acceleration ``mjData.qacc``. - When this flag is enabled, :ref:`mj_inverse` will interpret ``qacc`` as having been computed from the difference of - two sequential velocities, and undo the above modification. + This dual-purpose flag enables discrete-time inverse dynamics and disables :ref:`midpoint integration`. + + Enable discrete-time inverse dynamics + This flag **enables** discrete-time inverse dynamics with :ref:`mj_inverse` for all + :ref:`integrators` other than ``RK4``. Recall from the :ref:`numerical + integration` section that the one-step integrators (``Euler``, ``implicit`` and ``implicitfast``), + modify the mass matrix :math:`M \rightarrow M-hD`. This implies that finite-differenced accelerations + :math:`(v_{t+h} - v_t)/h` will not correspond to the continuous-time acceleration ``mjData.qacc``. When this flag + is enabled, :ref:`mj_inverse` will interpret ``qacc`` as having been computed from the difference of two sequential + velocities, and undo the above modification. + + Disable midpoint integration + Additionally and relatedly, this flag **disables** :ref:`midpoint integration` for free bodies, which + would otherwise break the linear relationship between finite-differenced velocities and forces assumed by discrete + inverse dynamics. Note that disabling midpoint integration might be useful for debugging or for other reasons, + regardless or whether inverse dynamics are used. .. _option-flag-multiccd: -:at:`multiccd`: :at-val:`[disable, enable], "disable"` +:at:`multiccd`: :at-val:`[disable, enable], "enable"` This flag enables multiple-contact collision detection for geom pairs that use a general-purpose convex-convex collider e.g., mesh-mesh collisions. This can be useful when the contacting geoms have a flat surface and the single contact point generated by the convex-convex collider cannot accurately capture the surface contact, leading @@ -739,17 +748,15 @@ has any effect. The settings here are global and apply to the entire model. .. _compiler-strippath: -:at:`strippath`: :at-val:`[false, true], "false" for MJCF, "true" for URDF` +:at:`strippath`: :at-val:`[false, true], "false"` When this attribute is "true", the parser will remove any path information in file names specified in the model. This is useful for loading models created on a different system using a different directory structure. .. _compiler-coordinate: :at:`coordinate`: :at-val:`[local, global], "local"` - In previous versions, this attribute could be used to specify whether frame positions and orientations are expressed - in local or global coordinates, but the "global" option has since been removed, and will cause an error to be - generated. In order to convert older models which used the "global" option, load and save them in MuJoCo 2.3.3 or - older. + This attribute specifies whether frame positions and orientations are expressed in local coordinates. The "global" + option is no longer supported and will cause an error. .. _compiler-angle: @@ -826,8 +833,8 @@ has any effect. The settings here are global and apply to the entire model. .. _compiler-usethread: :at:`usethread`: :at-val:`[false, true], "true"` - If this attribute is "true", the model compiler will run in multi-threaded mode. Currently multi-threading is used - for computing the length ranges of actuators and for parallel loading and processing of meshes. + If this attribute is "true", the model compiler will run in multi-threaded mode. Multi-threading is used for + computing the length ranges of actuators and for parallel loading and processing of meshes. .. _compiler-fusestatic: @@ -995,25 +1002,24 @@ compilation. .. _size-njmax: :at:`njmax`: :at-val:`int, "-1"` |nbsp| |nbsp| |nbsp| (legacy) - This is a deprecated legacy attribute. In versions prior to 2.3.0, it determined the maximum allowed number - of constraints. Currently it means "allocate as much memory as would have previously been required for this number of + This is a deprecated legacy attribute. It previously determined the maximum allowed number of constraints. + Currently it means "allocate as much memory as would have previously been required for this number of constraints". Specifying both :at:`njmax` and :at:`memory` leads to an error. .. _size-nconmax: :at:`nconmax`: :at-val:`int, "-1"` |nbsp| |nbsp| |nbsp| (legacy) This attribute specifies the maximum number of contacts that will be generated at runtime. If the number of active - contacts is about to exceed this value, the extra contacts are discarded and a warning is generated. This is a - deprecated legacy attribute which prior to version 2.3.0 affected memory allocation. It is kept for backwards - compatibility and debugging purposes. + contacts is about to exceed this value, the extra contacts are discarded and a warning is generated. This is a + deprecated legacy attribute which previously affected memory allocation. It is kept for backwards compatibility + and debugging purposes. .. _size-nstack: :at:`nstack`: :at-val:`int, "-1"` |nbsp| |nbsp| |nbsp| (legacy) - This is a deprecated legacy attribute. In versions prior to 2.3.0, it determined the maximum size of the - :ref:`stack `. After version 2.3.0, if :at:`nstack` is specified, then the size of ``mjData.narena`` is - ``nstack * sizeof(mjtNum)`` bytes, plus an additional space for the constraint solver. Specifying both :at:`nstack` - and :at:`memory` leads to an error. + This is a deprecated legacy attribute. It previously determined the maximum size of the :ref:`stack `. + If :at:`nstack` is specified, then the size of ``mjData.narena`` is ``nstack * sizeof(mjtNum)`` bytes, plus an + additional space for the constraint solver. Specifying both :at:`nstack` and :at:`memory` leads to an error. .. _size-nuserdata: @@ -1290,8 +1296,8 @@ The full list of processing steps applied by the compiler to each mesh is as fol :at:`inertia`: :at-val:`[convex, exact, legacy, shell], "legacy"` This attribute controls how the mesh is used when mass and inertia are - :ref:`inferred from geometry`. The current default value :at-val:`legacy` will be changed - to :at-val:`convex` in a future release. + :ref:`inferred from geometry`. The default value is :at-val:`legacy` for backward + compatibility, but :at-val:`convex` is recommended. :at-val:`convex`: Use the mesh's convex hull to compute volume and inertia, assuming uniform density. @@ -1602,8 +1608,8 @@ also known as terrain map, is a 2D matrix of elevation data. The data can be spe .. _asset-skin-rgba: .. _asset-skin-group: -:ref:`Skins` have been moved under the new grouping element :ref:`deformable`. They can -still be specified here but this functionality is now deprecated and will be removed in the future. +:ref:`Skins` are grouped under the :ref:`deformable` element. Specifying them here is +deprecated. @@ -1618,7 +1624,7 @@ The texture data can be loaded from files or can be generated by the compiler as different texture types require different parameters, only a subset of the attributes below are used for any given texture. Provisions are provided for loading cube and skybox textures from individual image files. -Currently, three file formats are supported for loading textures: PNG, KTX, and a custom MuJoCo texture format. The +Three file formats are supported for loading textures: PNG, KTX, and a custom MuJoCo texture format. The loader will use the extension of the file name to determine which format to use, defaulting to the custom format if the extension is not recognized. Alternatively, the content_type attribute can be used to specify the format explicitly. Only ``image/png``, ``image/ktx``, or ``image/vnd.mujoco.texture`` are supported. @@ -1917,8 +1923,8 @@ properties are grouped together. This attribute should be in the range [0 1]. If the value is greater than 0, and the material is applied to a plane or a box geom, the renderer will simulate reflectance. The larger the value, the stronger the reflectance. For boxes, only the face in the direction of the local +Z axis is reflective. Simulating reflectance properly requires - ray-tracing which cannot (yet) be done in real-time. We are using the stencil buffer and suitable projections - instead. Only the first reflective geom in the model is rendered as such. This adds one extra rendering pass through + ray-tracing. This renderer uses the stencil buffer and suitable projections instead to approximate it. Only the + first reflective geom in the model is rendered as such. This adds one extra rendering pass through all geoms, in addition to the extra rendering pass added by each shadow-casting light. .. _asset-material-metallic: @@ -2183,7 +2189,7 @@ between the body where it is defined and the body's parent. If multiple joints a corresponding spatial transformations (of the body frame relative to the parent frame) are applied in order. If no joints are defined, the body is welded to its parent. Joints cannot be defined in the world body. At runtime the positions and orientations of all joints defined in the model are stored in the vector ``mjData.qpos``, in the order in -which the appear in the kinematic tree. The linear and angular velocities are stored in the vector ``mjData.qvel``. +which they appear in the kinematic tree. The linear and angular velocities are stored in the vector ``mjData.qvel``. These two vectors have different dimensionality when free or ball joints are used, because such joints represent rotations as unit quaternions. @@ -2479,7 +2485,7 @@ helps clarify the role of bodies and geoms in MuJoCo. .. _body-geom-type: :at:`type`: :at-val:`[plane, hfield, sphere, capsule, ellipsoid, cylinder, box, mesh, sdf], "sphere"` - Type of geometric shape. The keywords have the following meaning: The **plane** type defines a plane which is + Type of geometric shape. The keywords have the following meaning: The **plane** type defines a surface which is infinite for collision detection purposes. It can only be attached to the world body or static children of the world. The plane passes through a point specified via the pos attribute. It is normal to the Z axis of the geom's local frame. The +Z direction corresponds to empty space. Thus the position and orientation defaults of (0,0,0) and @@ -2696,18 +2702,20 @@ helps clarify the role of bodies and geoms in MuJoCo. .. _body-geom-margin: :at:`margin`: :at-val:`real, "0"` - Distance threshold below which contacts are detected and included in the global array mjData.contact. This however - does not mean that contact force will be generated. A contact is considered active only if the distance between the - two geom surfaces is below margin-gap. Recall that constraint impedance can be a function of distance, as explained - in :ref:`CSolver`. The quantity this function is applied to is the distance between - the two geoms minus the margin plus the gap. + Geometric inflation of the geom surface for the purpose of contact force generation. When the distance between two + geom surfaces is below ``margin``, the contact is considered active and contact forces are generated. The constraint + impedance can be a function of distance, as explained in :ref:`CSolver`. The quantity this function is applied to is + the distance between the two geoms minus the ``margin``. See :ref:`margin and gap`. .. _body-geom-gap: :at:`gap`: :at-val:`real, "0"` - This attribute is used to enable the generation of inactive contacts, i.e., contacts that are ignored by the - constraint solver but are included in mjData.contact for the purpose of custom computations. When this value is - positive, geom distances between margin and margin-gap correspond to such inactive contacts. + Additional contact detection buffer beyond ``margin``. When this value is positive, contacts are detected at + distance ``margin + gap`` but forces are only generated at distance ``margin``. Contacts with distance between + ``margin`` and ``margin + gap`` are included in ``mjData.contact`` as inactive contacts (with ``efc_address`` = -1). + These inactive contacts can be used for custom computations, for example by :ref:`adhesion` + actuators which use contacts in the gap zone to generate adhesive forces without producing contact forces. + See :ref:`margin and gap`. .. _body-geom-fromto: @@ -3218,9 +3226,9 @@ object. These elements are bodies (with their own joints and geoms) that become the macro. The macro expansion is done by the model compiler. If the resulting model is then saved, the macro will be replaced with the actual model elements. The defaults mechanism used in the rest of MJCF does not apply here, even if the parent body has a childclass attribute defined. Instead there are internal defaults adjusted automatically for each -composite object type. See :ref:`CComposite` in the modeling guide for more detailed explanation. Note that there used -to be several composite types, but they have incrementally replaced by :ref:`replicate` (for repeated -objects) and :ref:`flexcomp` (for soft objects). Therefore, the only supported composite type is now +composite object type. See :ref:`CComposite` in the modeling guide for more detailed explanation. Note that several +legacy composite types have been replaced by :ref:`replicate` (for repeated objects) and +:ref:`flexcomp` (for soft objects). Therefore, the only supported composite type is now cable, which produces an inextensible chain of bodies connected with ball joints. .. _body-composite-prefix: @@ -3237,8 +3245,8 @@ cable, which produces an inextensible chain of bodies connected with ball joints The **cable** type creates a 1D chain of bodies connected with ball joints, each having a geom with user-defined type (cylinder, capsule or box). The geometry can either be defined with an array of 3D vertex coordinates :at:`vertex` - or with prescribed functions with the option :at:`curve`. Currently, only linear and trigonometric functions are - supported. For example, an helix can be obtained with curve="cos(s) sin(s) s". The size is set with the option + or with prescribed functions with the option :at:`curve`. Only linear and trigonometric functions are supported. For + example, an helix can be obtained with curve="cos(s) sin(s) s". The size is set with the option :at:`size`, resulting in :math:`f(s)=\{\text{size}[1]\cdot\cos(2\pi\cdot\text{size}[2]),\; \text{size}[1]\cdot\sin(2\pi\cdot\text{size}[2]),\; \text{size}[0]\cdot s\}`. @@ -3360,7 +3368,7 @@ joints should be created, as well as to adjust the attributes of both automatic '''''''''''''''''''''''''''''''''''''''' This sub-element adjusts the attributes of the geoms in the composite object. The default attributes are the same as in -the rest of MJCF (except that user-defined defaults have no effect here). Note that the geom sub-element can appears +the rest of MJCF (except that user-defined defaults have no effect here). Note that the geom sub-element can appear only once, unlike joint and tendon sub-elements which can appear multiple times. This is because different kinds of joints and tendons have different sets of attributes, while all geoms in the composite object are identical. @@ -3500,8 +3508,8 @@ Associate this composite with an :ref:`engine plugin`. Either :at:`plu :el-prefix:`body/` |-| **flexcomp** |*| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Similar to :el:`composite`, this element (new in MuJoCo 3.0) is not a model element, but rather a macro which expands -into multiple model elements representing a deformable entity. In particular this macro creates one +Similar to :el:`composite`, this element is not a model element, but rather a macro which expands into multiple +model elements representing a deformable entity. In particular this macro creates one :ref:`flex` element, a number of bodies that are children of the body in which the :el:`flexcomp` is defined, and optionally one :ref:`flex equality` which constrains all flex edges to their initial length. A number of attributes are specified here and then passed through to the automatically-constructed flex. The primary @@ -3518,9 +3526,9 @@ flexcomp point is not pinned, a new child body is created at the coordinates of parent body), and then the coordinates of the flex vertex within that new body are (0,0,0). The mechanism for :ref:`pinning` flexcomp points is explained below. -Composite objects (available prior to MuJoCo 3.0) needed bodies with geoms for collisions, and sites for connecting -tendons which generated shape-preserving forces. In contrast, flexes generate their own collisions and shape-preserving -forces (as well as rendering), thus the bodies created here are much simpler: no geoms, sites or tendons are needed. +While :el:`composite` objects need bodies with geoms for collisions and sites for connecting tendons, flexes +generate their own collisions and shape-preserving forces. Thus the bodies created here are much simpler: no geoms, +sites or tendons are needed. Most of the bodies created here have 3 orthogonal slider joints, corresponding to freely moving point masses. In some cases we generate radial slider joints, allowing only expansion and contraction. Since no geoms are generated, the bodies need to have explicit inertial parameters. @@ -3587,7 +3595,7 @@ saving the XML: .. _body-flexcomp-dof: -:at:`dof`: :at-val:`[full, radial, trilinear, quadratic], "full"` +:at:`dof`: :at-val:`[full, radial, trilinear, quadratic, 2d], "full"` The parametrization of the flex's degrees of freedom (dofs). See the video on the right illustrating the different parametrizations with deformable spheres. The three models in the video are respectively `sphere_full `__, @@ -3602,6 +3610,10 @@ saving the XML: requires a free joint at the flex's parent in order for free body motion to be possible. This type of parametrization is appropriate for shapes that are relatively spherical. + **2d** + Two orthogonal translational dofs (X and Y) per vertex. This restricts the motion of the vertices to planes + parallel to the parent body's X-Y plane. + **trilinear** Three translational dofs at each corner of the bounding box of the flex, for a total of 24 dofs for the entire flex, independent of the number of vertices. The positions of the vertices are updated using trilinear @@ -3694,8 +3706,14 @@ saving the XML: .. _body-flexcomp-count: :at:`count`: :at-val:`int(3), "10 10 10"` - The number of automatically generated points in each dimension. This and the next attribute only apply to types grid, - box, cylinder, ellipsoid. + Specifies the number of automatically generated points in each dimension for types **grid**, **box**, **cylinder**, + and **ellipsoid**. + +.. _body-flexcomp-cellcount: + +:at:`cellcount`: :at-val:`int(3), "1 1 1"` + Specifies the number of cells in each dimension for the background interpolation grid when using **trilinear** or + **quadratic** dofs. .. _body-flexcomp-spacing: @@ -4094,14 +4112,15 @@ friction can only be created with this element. .. _contact-pair-margin: :at:`margin`: :at-val:`real, "0"` - Distance threshold below which contacts are detected and included in the global array mjData.contact. + Geometric inflation for the purpose of contact force generation. Contacts are detected at distance ``margin + gap`` + and forces are generated at distance ``margin``. .. _contact-pair-gap: :at:`gap`: :at-val:`real, "0"` - This attribute is used to enable the generation of inactive contacts, i.e., contacts that are ignored by the - constraint solver but are included in mjData.contact for the purpose of custom computations. When this value is - positive, geom distances between margin and margin-gap correspond to such inactive contacts. + Additional contact detection buffer beyond ``margin``. When this value is positive, contacts with distance between + ``margin`` and ``margin + gap`` are included in ``mjData.contact`` as inactive contacts but no contact forces are + generated. .. _contact-exclude: @@ -4142,8 +4161,8 @@ This is a grouping element and does not have any attributes. It groups elements :el-prefix:`deformable/` |-| **flex** |*| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Flexible objects (or flexes) were added in MuJoCo 3.0. These are collections of massless stretchable geometric elements -(capsules, triangles or tetrahedra) connecting vertices that are defined within different moving body frames. These +Flexible objects (or flexes) are collections of massless stretchable geometric elements (capsules, triangles or +tetrahedra) connecting vertices that are defined within different moving body frames. These stretchable elements support collisions and contact forces, which are then distributed to all the interconnected bodies. Flexes also generate passive and constraint forces as needed to simulate deformable entities with the desired material properties. The modeling of flexes is automated and simplified by the :ref:`flexcomp` element. In most @@ -4236,6 +4255,17 @@ cases, the user will specify a :el:`flexcomp` which will then automatically cons An array of MuJoCo body names (separated by white space) to which each node belongs. The number of body names should equal the number of nodes (nnode). See the flexcomp :ref:`dof` attribute for more details. +.. _deformable-flex-cellcount: + +:at:`cellcount`: :at-val:`int(3), optional` + When using **trilinear** or **quadratic** dofs, this specifies the number of cells in each dimension for the + background interpolation grid. + +.. _deformable-flex-dof: + +:at:`dof`: :at-val:`[trilinear, quadratic], optional` + Interpolation order for the flex. + .. _flex-edge: :el-prefix:`flex/` |-| **edge** |?| @@ -4301,7 +4331,8 @@ stress-strain relationship. See also :ref:`deformable ` objects and :at:`elastic2d`: :at-val:`[none, bend, stretch, both], "none"` Elastic contribution to passive forces of 2D flexes. "none": none, "bend": bending only, "stretch": stretching only, - "both": bending and stretching. + "both": bending and stretching. Bending is not yet supported by :ref:`dof` **trilinear** and + **quadratic**. .. _flex-contact: @@ -4321,9 +4352,8 @@ extensions specific to flexes. flex. The pre-defined vertex-element pairs are generated by the model compiler automatically. In 3D, internal collision checks are performed within each tetraheron: each vertex is collided with the plane corresponding to the opposing triangle face (again using the flex radius). The resulting contacts are always created with condim 1, gap 0, - margin 0. Note that internal contacts modify the behavior implied by the :ref:`elasticity - parameters` and is recommended only for flexes where element inversion cannot be prevented. The - default value of this attribute was changed from "true" to "false" in version 3.3.1. + margin 0. Note that internal contacts modify the behavior implied by the :ref:`elasticity parameters` + and is recommended only for flexes where element inversion cannot be prevented. .. _flex-contact-selfcollide: @@ -4369,7 +4399,7 @@ extensions specific to flexes. :at:`passive`: :at-val:`[true, false], "false"` When enabled, the contact is not added to the contact solver but it is instead used to compute passive (spring-damper) contact forces. All contacts, regardless of the specified condim, are frictionless (condim 1). This - is an experimental feature and might change in future releases. + is an experimental feature. .. _deformable-skin: @@ -4866,14 +4896,11 @@ constraint type is only supported for dimension 3 flexes with trilinear or quadr :at:`flex`: :at-val:`string, required` Name of the flex whose strain is being constrained. +.. _equality-flexstrain-cell: -.. _equality-distance: - -:el-prefix:`equality/` |-| **distance** |*| -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Distance equality constraints were removed in MuJoCo version 2.2.2. If you are using an earlier version, please switch -to the corresponding version of the documentation. +:at:`cell`: :at-val:`int(3), optional` + 3D grid index (i, j, k) identifying the cell in the flex object. The grid size is specified in the :ref:`cellcount + ` attribute. .. _tendon: @@ -5157,7 +5184,7 @@ illustrated the use of pulleys. This element creates an abstract tendon whose length is defined as a linear combination of joint positions. Recall that the tendon length and its gradient are the only quantities needed for simulation. Thus we could define any scalar -function of joint positions, call it "tendon", and plug it in MuJoCo. Presently the only such function is a fixed linear +function of joint positions, call it "tendon", and use it in MuJoCo. The only such function supported is a fixed linear combination. The attributes of fixed tendons are a subset of the attributes of spatial tendons and have the same meaning as above. @@ -5574,8 +5601,8 @@ specify them independently. :el-prefix:`actuator/` |-| **motor** |*| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -This and the next three elements are the :ref:`Actuator shortcuts ` discussed earlier. When a -such shortcut is encountered, the parser creates a :el:`general` actuator and sets its dynprm, gainprm and biasprm +This and the next three elements are the :ref:`Actuator shortcuts ` discussed earlier. When +such a shortcut is encountered, the parser creates a :el:`general` actuator and sets its dynprm, gainprm and biasprm attributes to the internal defaults shown above, regardless of any default settings. It then adjusts dyntype, gaintype and biastype depending on the shortcut, parses any custom attributes (beyond the common ones), and translates them into regular attributes (i.e., attributes of the :el:`general` actuator type) as explained here. @@ -5775,7 +5802,7 @@ This element has one custom attribute in addition to the common attributes: :el-prefix:`actuator/` |-| **velocity** |*| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -This element creates a velocity servo. Note that in order create a PD controller, one has to define two actuators: a +This element creates a velocity servo. Note that in order to create a PD controller, one has to define two actuators: a position servo and a velocity servo. This is because MuJoCo actuators are SISO while a PD controller takes two control inputs (reference position and reference velocity). When using this actuator, it is recommended to use the implicitfast or implicit :ref:`integrators`. @@ -6204,7 +6231,7 @@ This element has nine custom attributes in addition to the common attributes: :at:`tausmooth`: :at-val:`real, "0"` Width of smooth transition between activation and deactivation time constants. Units of ctrl, must be - nonegative. + nonnegative. .. _actuator-muscle-range: @@ -6262,16 +6289,16 @@ This element has nine custom attributes in addition to the common attributes: This element defines an active adhesion actuator which injects forces at contacts in the normal direction, see illustration video. The model shown in the video can be found `here -`_ and includes inline annotations. The transmission target -is a :el:`body`, and adhesive forces are injected into all contacts involving geoms which belong to this body. The force -is divided equally between multiple contacts. When the :at:`gap` attribute is not used, this actuator requires active -contacts and cannot apply a force at a distance, more like the active adhesion on the feet of geckos and insects rather -than an industrial vacuum gripper. In order to enable "suction at a distance", "inflate" the body's geoms by -:at:`margin` and add a corresponding :at:`gap` which activates contacts only after :at:`gap` penetration distance. This -will create a layer around the geom where contacts are detected but are inactive, and can be used for -applying the adhesive force. In the video above, such inactive contacts are blue, while active contacts are orange. -An adhesion actuator's length is always 0. :at:`ctrlrange` is required and must also be nonnegative (no repulsive forces -are allowed). The underlying :el:`general` attributes are set as follows: +`_ and includes inline annotations. The transmission +target is a :el:`body`, and adhesive forces are injected into all contacts involving geoms which belong to this body. +The force is divided equally between multiple contacts. When the :ref:`gap` attribute is not used, this +actuator requires active contacts and cannot apply a force at a distance, more like the active adhesion on the feet of +geckos and insects rather than an industrial vacuum gripper. In order to enable "suction at a distance", set the +:ref:`gap` attribute of the body's geoms to a positive value. This creates a layer around each geom where +contacts are detected but no contact forces are generated, and the adhesive force can act across this gap. In the video +above, such inactive contacts are blue, while active contacts are orange. An adhesion actuator's length is always 0. +:at:`ctrlrange` is required and must also be nonnegative (no repulsive forces are allowed). The underlying :el:`general` +attributes are set as follows: =========== ======= =========== ======== Attribute Setting Attribute Setting @@ -6323,10 +6350,179 @@ This element has a subset of the common attributes and two custom attributes. to the target body. +.. _actuator-dcmotor: + +:el-prefix:`actuator/` |-| **dcmotor** |*| +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +This element creates a DC motor actuator. See the `DC motor technical note <_static/dcmotor.pdf>`__ for complete +mathematical formulations and parameter semantics, but we include a few important notes below. Note that :el:`dcmotor` +does not conform to the affine gain / bias structure of the :ref:`general actuation model`, except for +the stateless case. + +- :ref:`resistance`, :ref:`motorconst` and + :ref:`nominal` are each optional, but some combination of them is required. + See Section 2.1 of the `technical note <_static/dcmotor.pdf>`__. +- The control :ref:`input` semantic is either the voltage applied to the motor terminals (the + default), or a position or velocity target for a :ref:`PID controller`. +- Optional features include electrical dynamics (:ref:`inductance`), + :ref:`cogging torque`, :ref:`thermal resistance variation`, and + :ref:`LuGre` friction. + +The underlying :el:`general` attributes are set to the :el:`dcmotor` type, and their associated parameter arrays are +computed internally: + +========= ======= ========= ======== +Attribute Setting Attribute Setting +========= ======= ========= ======== +dyntype dcmotor dynprm computed +gaintype dcmotor gainprm computed +biastype dcmotor biasprm computed +========= ======= ========= ======== + +This element has the following custom attributes in addition to the common attributes: + +.. _actuator-dcmotor-name: + +.. _actuator-dcmotor-class: + +.. _actuator-dcmotor-group: + +.. _actuator-dcmotor-delay: + +.. _actuator-dcmotor-nsample: + +.. _actuator-dcmotor-interp: + +.. _actuator-dcmotor-ctrllimited: + +.. _actuator-dcmotor-ctrlrange: + +.. _actuator-dcmotor-lengthrange: + +.. _actuator-dcmotor-gear: + +.. _actuator-dcmotor-damping: + +.. _actuator-dcmotor-armature: + +.. _actuator-dcmotor-cranklength: + +.. _actuator-dcmotor-joint: + +.. _actuator-dcmotor-jointinparent: + +.. _actuator-dcmotor-tendon: + +.. _actuator-dcmotor-cranksite: + +.. _actuator-dcmotor-slidersite: + +.. _actuator-dcmotor-site: + +.. _actuator-dcmotor-refsite: + +.. _actuator-dcmotor-user: + +.. |actuator/dcmotor attrib list| replace:: + :at:`name`, :at:`class`, :at:`group`, :at:`nsample`, :at:`interp`, :at:`delay`, :at:`ctrllimited`, :at:`ctrlrange`, + :at:`lengthrange`, :at:`gear`, :at:`damping`, :at:`armature`, :at:`cranklength`, :at:`joint`, :at:`jointinparent`, + :at:`tendon`, :at:`cranksite`, :at:`slidersite`, :at:`site`, :at:`refsite`, :at:`user` + +|actuator/dcmotor attrib list| + Same as in actuator/ :ref:`general `. + +.. _actuator-dcmotor-resistance: + +:at:`resistance`: :at-val:`real, optional` + Terminal resistance :math:`R` in Ohm. (see `tech note <_static/dcmotor.pdf>`__, Sections 1.1 and 2.1) + +.. _actuator-dcmotor-motorconst: + +:at:`motorconst`: :at-val:`real(2), optional` + Motor constants, defined as :at:`motorconst` = ":at-val:`Kt` :at-val:`Ke`" (N·m/A, equivalently V·s/rad). + :at-val:`Kt` is the torque constant and :at-val:`Ke` the back-EMF constant; they can differ when magnetic saturation + is present. If both are positive, the effective constant is :math:`K = \sqrt{K_t K_e}` (geometric mean). If only one + is positive, :math:`K` equals that value. If a datasheet specifies the speed constant :math:`K_v` in rad/(V·s), use + :math:`K_e = 1/K_v`. (see `tech note <_static/dcmotor.pdf>`__, Sections 1.1 and 2.1) + +.. _actuator-dcmotor-nominal: + +:at:`nominal`: :at-val:`real(3), optional` + Nominal operating point, defined as :at:`nominal` = ":at-val:`voltage` :at-val:`stall_torque` + :at-val:`no_load_speed`". The compiler derives :math:`K =` :at-val:`voltage` / :at-val:`no_load_speed` and :math:`R = + K` · :at-val:`voltage` / :at-val:`stall_torque`. (see `tech note <_static/dcmotor.pdf>`__, Sections 1.1 and 2.1) + +.. _actuator-dcmotor-inductance: + +:at:`inductance`: :at-val:`real(2), "0 0"` + Electrical dynamics, defined as :at:`inductance` = ":at-val:`L` :at-val:`timeconst`" (Henry, seconds). These are + alternative specifications: :at-val:`L` is the winding inductance and :at-val:`timeconst` :math:`= L/R` is the + electrical time constant. Specify one; if both are given, :at-val:`L` takes precedence. If both are 0 (the default), + no electrical dynamics are modeled and the current is computed algebraically. Adds one activation variable for + armature current. (see `tech note <_static/dcmotor.pdf>`__, Sections 1.1.1 and 2.2) + +.. _actuator-dcmotor-thermal: + +:at:`thermal`: :at-val:`real(6), "0 0 0 0 0 0"` + Thermal model, defined as :at:`thermal` = ":at-val:`resistance` :at-val:`capacitance` :at-val:`timeconst` + :at-val:`tempcoef` :at-val:`reftemp` :at-val:`ambient`" (K/W, J/K, s, 1/K, °C, °C). The first three sub-values + specify the thermal time constant: :at-val:`timeconst` = :at-val:`resistance` :math:`\times` :at-val:`capacitance`. + Specify either :at-val:`timeconst` directly, or :at-val:`resistance` and :at-val:`capacitance`; if all three are + given, :at-val:`timeconst` takes precedence. If all are 0 (the default), thermal modeling is disabled. Adds one + activation variable for winding temperature. (see `tech note <_static/dcmotor.pdf>`__, Sections 1.3 and 2.3) + +.. _actuator-dcmotor-saturation: + +:at:`saturation`: :at-val:`real(3), "0 0 0"` + Limits on the actuator, defined as :at:`saturation` = ":at-val:`torque` :at-val:`current` + :at-val:`current_rate`". :at-val:`torque` and :at-val:`current` are alternative specifications of the maximum + continuous torque: if :at-val:`current` is given, :at-val:`torque` :math:`= K \cdot` :at-val:`current`; if both are + given, :at-val:`torque` takes precedence. Sets :at:`forcerange` to [:math:`-\tau_{\max},\, \tau_{\max}`]. + :at-val:`current_rate` sets the maximum rate of change of current :math:`(di/dt)_{\max}` (requires + :ref:`inductance`). A value of 0 (the default) for any sub-value disables the respective + limit. (see `tech note <_static/dcmotor.pdf>`__, Section 2) + +.. _actuator-dcmotor-cogging: + +:at:`cogging`: :at-val:`real(3), "0 0 0"` + Cogging torque, defined as :at:`cogging` = ":at-val:`amplitude` :at-val:`poles` :at-val:`phase`" (N·m, integer, rad). + Adds a position-dependent torque :math:`= \textsf{amplitude} \cdot \sin(\textsf{poles} \cdot \theta + + \textsf{phase})`. Disabled when :at-val:`amplitude` = 0 (the default). + (see `tech note <_static/dcmotor.pdf>`__, Sections 1.2 and 2.1) + +.. _actuator-dcmotor-lugre: + +:at:`lugre`: :at-val:`real(5), "0 0 0 0 0"` + LuGre friction, defined as :at:`lugre` = ":at-val:`stiffness` :at-val:`damping` :at-val:`coulomb` + :at-val:`static` :at-val:`stribeck`" (N·m/rad, N·m·s/rad, N·m, N·m, rad/s). Disabled when + :at-val:`stiffness` = 0 (the default). Adds one activation variable for bristle deflection. Note that the + viscous damping coefficient :math:`\sigma_2` is not part of the :at:`lugre` attribute and should be + added to the standard actuator :ref:`damping` attribute. + (see `tech note <_static/dcmotor.pdf>`__, Sections 1.4 and 2.4) + +.. _actuator-dcmotor-input: + +:at:`input`: :at-val:`[voltage, position, velocity], "voltage"` + Specifies the input signal semantics. In "voltage" mode, the control directly sets applied motor voltage. In + "position" or "velocity" modes, the :ref:`PID controller` uses the control as a + reference setpoint relative to the joint trajectory. (see `tech note <_static/dcmotor.pdf>`__, Section 2.5) + +.. _actuator-dcmotor-controller: + +:at:`controller`: :at-val:`real(6), "0 0 0 0 0 0"` + PID controller parameters, defined as :at:`controller` = ":at-val:`kp` :at-val:`ki` :at-val:`kd` + :at-val:`slewmax` :at-val:`Imax` :at-val:`Vmax`". Depending on the :at:`input` mode, the controller stabilizes + either position or velocity. If the :at:`input` mode is voltage, :at-val:`kp`, :at-val:`ki`, :at-val:`kd` are + ignored. :at-val:`Vmax` sets the maximum drive voltage :math:`v_{\max}` (Volt); in position/velocity modes it clamps + the controller output, in voltage mode it clamps the control signal (if :at:`ctrlrange` is also set, the tighter + limit wins). A value of 0 (the default) disables the respective feature. When positive, :at-val:`slewmax` limits the + setpoint rate-of-change, :at-val:`Imax` clamps the integrator state (anti-windup), and :at-val:`Vmax` clamps the + drive voltage. (see `tech note <_static/dcmotor.pdf>`__, Section 2.5) + .. _actuator-plugin: :el-prefix:`actuator/` |-| **plugin** |?| -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Associate this actuator with an :ref:`engine plugin`. Either :at:`plugin` or :at:`instance` are required. @@ -6429,7 +6625,7 @@ computations. In addition to the sensors created with the elements below, the top-level function :ref:`mj_step` computes the quantities mjData.cacc, mjData.cfrc_int and mjData.crfc_ext corresponding to body accelerations and interaction forces. Some of these quantities are used to compute the output of -certain sensors (force, acceleration etc.) but even if no such sensors are defined in the model, these quantities +certain sensors (force, acceleration, etc.) but even if no such sensors are defined in the model, these quantities themselves are "features" that could be of interest to the user. @@ -6442,7 +6638,7 @@ This element creates a touch sensor. The active sensor zone is defined by a site site's volume, and involves a geom attached to the same body as the site, the corresponding contact force is included in the sensor reading. If a contact point falls outside the sensor zone, but the normal ray intersects the sensor zone, it is also included. This re-projection feature is needed because, without it, the contact point may leave the sensor zone -from the back (due to soft contacts) and cause an erroneous force reading. The output of this sensor is non-negative +from the back (due to soft contacts) and cause an erroneous force reading. The output of this sensor is a non-negative scalar. It is computed by adding up the (scalar) normal forces from all included contacts. .. _sensor-touch-name: @@ -6709,10 +6905,10 @@ defined as geoms whose rgba (or whose material rgba) has alpha=0, are also exclu invisible in the visualizer by disabling their geom group are not excluded; this is because sensor calculations are independent of the visualizer. -The image on the right (click to see the model being visualized) shows two rangefinder sensors attached to a perspective and -an orthographic camera, with frustums visualized. Both cameras have 4x4 resolution, for 16 rays each. The rangefinder -sensors report :at:`data` = :at-val:`"dist point normal"` (see below), so we can see the rays (lines), the intersection -points (spheres) and the surface normals (arrows). +The image on the right (click to see the model being visualized) shows two rangefinder sensors attached to a +perspective and an orthographic camera, with frustums visualized. Both cameras have 4x4 resolution, for 16 rays +each. The rangefinder sensors report :at:`data` = :at-val:`"dist point normal"` (see below), so we can see the rays +(lines), the intersection points (spheres) and the surface normals (arrows). .. _sensor-rangefinder-data: @@ -8159,7 +8355,7 @@ sensor reports information that was discovered during the collision and constrai from ``mjData.{contact, efc_force}``, ignoring contacts that were filtered out by the :ref:`standard` mechanism and produce no force. -Contact sensor output involves three stages: **matching**, **reduction** and **extraction**. +Contact sensor output involves three stages: **matching**, **reduction**, and **extraction**. Matching Selects a set of contacts from ``mjData.contact`` using criteria defined by :ref:`geom1`, @@ -8177,7 +8373,7 @@ Matching Reduction Reduces the number of matched contacts to exactly :ref:`num` sub-arrays, or "slots". If less than :at:`num` contacts match, the remaining slots are set to be identically zero. Note that the default, - "unsorted" reduction criterion is potentitally non-deterministic. See :ref:`reduce` below. + "unsorted" reduction criterion is potentially non-deterministic. See :ref:`reduce` below. Extraction Copies the set of fields specified by the user into each slot, see :ref:`data`. @@ -8231,7 +8427,7 @@ Extraction Importantly, the :at:`data` attribute can contain **multiple sequential data types**, as long as the relative order---as listed above---is maintained. For example, :at:`data` = :at-val:`"found force dist"` will return 5 numbers - per contact (the concateneated values of [found, force, dist]), while :at:`data` = :at-val:`"force found dist"` is an + per contact (the concatenated values of [found, force, dist]), while :at:`data` = :at-val:`"force found dist"` is an error because :at-val:`found` must come before :at-val:`force`. Missing contacts @@ -8430,8 +8626,8 @@ This element creates a user sensor. MuJoCo does not know how to compute the outp should install the callback :ref:`mjcb_sensor` which is expected to fill in the sensor data in ``mjData.sensordata``. The specification in the XML is used to allocate space for this sensor, and also determine which MuJoCo object it is attached to and what stage of computation it needs before the data can be computed. Note that the MuJoCo object -referenced here can be a tuple, which in turn can reference a custom collection of MuJoCo objects -- for example several -bodies whose center of mass is of interest. +referenced here can be a tuple, which in turn can reference a custom collection of MuJoCo objects -- for example +several bodies whose center of mass is of interest. If a user sensor is of :ref:`stage` "vel" or "acc", then :ref:`mj_subtreeVel` or :ref:`mj_rnePostConstraint` will be triggered, respectively. @@ -8708,7 +8904,7 @@ visualization should somehow be simplified. .. _visual-quality-shadowsize: :at:`shadowsize`: :at-val:`int, "4096"` - This attribute specifies the size of the square texture used for shadow mapping. Higher values result is smoother + This attribute specifies the size of the square texture used for shadow mapping. Higher values result in smoother shadows. The size of the area over which a :ref:`light ` can cast shadows also affects smoothness, so these settings should be adjusted jointly. The default here is somewhat conservative. Most modern GPUs are able to handle significantly larger textures without slowing down. @@ -9077,7 +9273,7 @@ disables the rendering of the corresponding object. .. _visual-rgba-contactgap: -:at:`contactgap`: :at-val:`real(4), "0.5, 0.8, 0.9, 1"` +:at:`contactgap`: :at-val:`real(4), "0.5 0.8 0.9 1"` Color of contacts that fall in the contact gap (and are thereby excluded from contact force computations). .. _visual-rgba-rangefinder: @@ -9146,7 +9342,7 @@ if omitted. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | This element sets the attributes of the dummy :ref:`mesh ` element of the defaults class. -| The available attributes are: :ref:`scale ` and :ref:`scale `. +| The available attributes are: :ref:`scale ` and :ref:`maxhullvert `. .. _default-material: @@ -9597,8 +9793,8 @@ if omitted. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This and the next three elements set the attributes of the :ref:`general ` element using -:ref:`Actuator shortcuts `. It does not make sense to use more than one such shortcut in the same defaults -class, because they set the same underlying attributes, replacing any previous settings. All +:ref:`Actuator shortcuts `. It does not make sense to use more than one such shortcut in the same +defaults class, because they set the same underlying attributes, replacing any previous settings. All :ref:`motor ` attributes are available here except: name, class, joint, jointinparent, site, refsite, tendon, slidersite, cranksite. @@ -9887,6 +10083,57 @@ refsite, tendon, slidersite, cranksite. All :ref:`adhesion ` attributes are available here except: name, class, body. +.. _default-dcmotor: + +.. _default-dcmotor-ctrllimited: + +.. _default-dcmotor-ctrlrange: + +.. _default-dcmotor-gear: + +.. _default-dcmotor-damping: + +.. _default-dcmotor-armature: + +.. _default-dcmotor-cranklength: + +.. _default-dcmotor-user: + +.. _default-dcmotor-group: + +.. _default-dcmotor-delay: + +.. _default-dcmotor-nsample: + +.. _default-dcmotor-interp: + +.. _default-dcmotor-motorconst: + +.. _default-dcmotor-resistance: + +.. _default-dcmotor-nominal: + +.. _default-dcmotor-saturation: + +.. _default-dcmotor-inductance: + +.. _default-dcmotor-cogging: + +.. _default-dcmotor-controller: + +.. _default-dcmotor-input: + +.. _default-dcmotor-thermal: + +.. _default-dcmotor-lugre: + +:el-prefix:`default/` |-| **dcmotor** |?| +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +All :ref:`dcmotor ` attributes are available here except: name, class, joint, jointinparent, site, +refsite, tendon, slidersite, cranksite. + + .. _custom: **custom** |*| @@ -10008,7 +10255,7 @@ See :ref:`exPlugin` for more details. :el-prefix:`plugin/` |-| **instance** |*| ''''''''''''''''''''''''''''''''''''''''' -Declares a plugin instance. Explicit instances declaration is required when multiple elements are backed by the same +Declares a plugin instance. Explicit instance declaration is required when multiple elements are backed by the same plugin, or when global plugin configuration is desired. See plugin :ref:`declaration` and :ref:`configuration` for more details. diff --git a/doc/XMLschema.rst b/doc/XMLschema.rst index 74f72561..f394f2ac 100755 --- a/doc/XMLschema.rst +++ b/doc/XMLschema.rst @@ -1417,6 +1417,9 @@ .. grid-item:: :ref:`count` + .. grid-item:: + :ref:`cellcount` + .. grid-item:: :ref:`spacing` @@ -1657,6 +1660,12 @@ .. grid-item:: :ref:`node` + .. grid-item:: + :ref:`cellcount` + + .. grid-item:: + :ref:`dof` + .. dropdown:: :ref:`contact` :octicon:`dot` @@ -2053,6 +2062,9 @@ .. grid-item:: :ref:`flex` + .. grid-item:: + :ref:`cell` + .. grid-item:: :ref:`active` @@ -2984,6 +2996,105 @@ :ref:`gain` + .. dropdown:: :ref:`dcmotor` |*| + + .. grid:: 2 3 4 4 + :gutter: 0 + + .. grid-item:: + :ref:`name` + + .. grid-item:: + :ref:`class` + + .. grid-item:: + :ref:`group` + + .. grid-item:: + :ref:`nsample` + + .. grid-item:: + :ref:`interp` + + .. grid-item:: + :ref:`delay` + + .. grid-item:: + :ref:`ctrllimited` + + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`lengthrange` + + .. grid-item:: + :ref:`gear` + + .. grid-item:: + :ref:`damping` + + .. grid-item:: + :ref:`armature` + + .. grid-item:: + :ref:`cranklength` + + .. grid-item:: + :ref:`user` + + .. grid-item:: + :ref:`joint` + + .. grid-item:: + :ref:`jointinparent` + + .. grid-item:: + :ref:`tendon` + + .. grid-item:: + :ref:`slidersite` + + .. grid-item:: + :ref:`cranksite` + + .. grid-item:: + :ref:`site` + + .. grid-item:: + :ref:`refsite` + + .. grid-item:: + :ref:`motorconst` + + .. grid-item:: + :ref:`resistance` + + .. grid-item:: + :ref:`nominal` + + .. grid-item:: + :ref:`saturation` + + .. grid-item:: + :ref:`inductance` + + .. grid-item:: + :ref:`cogging` + + .. grid-item:: + :ref:`controller` + + .. grid-item:: + :ref:`thermal` + + .. grid-item:: + :ref:`lugre` + + .. grid-item:: + :ref:`input` + + .. dropdown:: :ref:`plugin` |*| .. grid:: 2 3 4 4 @@ -6146,6 +6257,75 @@ :ref:`delay` + .. dropdown:: :ref:`dcmotor` :octicon:`dot` + + .. grid:: 2 3 4 4 + :gutter: 0 + + .. grid-item:: + :ref:`ctrllimited` + + .. grid-item:: + :ref:`ctrlrange` + + .. grid-item:: + :ref:`gear` + + .. grid-item:: + :ref:`damping` + + .. grid-item:: + :ref:`armature` + + .. grid-item:: + :ref:`cranklength` + + .. grid-item:: + :ref:`user` + + .. grid-item:: + :ref:`group` + + .. grid-item:: + :ref:`nsample` + + .. grid-item:: + :ref:`interp` + + .. grid-item:: + :ref:`delay` + + .. grid-item:: + :ref:`motorconst` + + .. grid-item:: + :ref:`resistance` + + .. grid-item:: + :ref:`nominal` + + .. grid-item:: + :ref:`saturation` + + .. grid-item:: + :ref:`inductance` + + .. grid-item:: + :ref:`cogging` + + .. grid-item:: + :ref:`controller` + + .. grid-item:: + :ref:`input` + + .. grid-item:: + :ref:`thermal` + + .. grid-item:: + :ref:`lugre` + + .. dropdown:: :ref:`custom` |*| diff --git a/doc/_static/dcmotor.pdf b/doc/_static/dcmotor.pdf new file mode 100644 index 00000000..be5c53de Binary files /dev/null and b/doc/_static/dcmotor.pdf differ diff --git a/doc/changelog.rst b/doc/changelog.rst index 39316130..5261a0b3 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -7,45 +7,217 @@ Upcoming version (not yet released) General ^^^^^^^ - -- Actuators with joint or tendon transmissions can now contribute - :ref:`damping` and :ref:`armature` to their transmission target. - These are applied during the passive force and inertia computations, respectively, and are scaled by gear\ :sup:`2` - ("reflected" damping/inertia). - -.. youtube:: aKa3ZlEF9_Y - :align: right - :width: 35% - -- Stiffness in :ref:`joints` and :ref:`tendons` and damping in - :ref:`joints` and :ref:`tendons` now support nonlinear polynomial - :ref:`force profiles`. New ``mjModel`` arrays (``jnt_stiffnesspoly``, ``tendon_stiffnesspoly``, - ``dof_dampingpoly``, ``tendon_dampingpoly``) hold higher-order coefficients. The existing scalar arrays - (``jnt_stiffness``, ``dof_damping``, etc.) continue to hold the linear coefficient and are unchanged. - The polynomial order is defined by the new constant :ref:`mjNPOLY`. A future breaking C-API change - may unify the linear and higher-order coefficients into a single array. - -- Introduced :ref:`mjpEncoder`, the counterpart to :ref:`mjpDecoder` for encoding of :ref:`mjSpec` and :ref:`mjModel` into :ref:`mjResource`. - - - Added :ref:`mj_encode`, :ref:`mjp_registerEncoder`, :ref:`mjp_defaultEncoder`, and :ref:`mjp_findEncoder`. +- The pseudo-random constraint visitation order in the :ref:`PGS solver`, introduced in the previous + release, now uses a fixed seed. The previous implementation seeded with ``mjData.time``, which introduced subtle yet + undesirable time dependence. .. admonition:: Breaking API changes :class: attention - - The ``mjs`` layer fields ``stiffness`` and ``damping`` in :ref:`mjsJoint` and :ref:`mjsTendon` have - been widened from ``mjtNum`` scalars to ``mjtNum[mjNPOLY+1]`` arrays. The first element is the linear coefficient - (previously the scalar), and subsequent elements are the higher-order :ref:`polynomial` coefficients. + - The semantics of the contact ``margin`` and ``gap`` parameters have been redesigned for conceptual clarity and + consistency with `NVIDIA Newton `__. See the new + :ref:`margin and gap` documentation section for details. - **Migration:** Replace assignments like ``joint.stiffness = val`` with ``joint.stiffness[0] = val``. + Previously, ``margin`` controlled the *detection threshold* (contacts exist when ``dist < margin``) and ``gap`` + was subtracted from it to produce the *force threshold* (forces generated when ``dist < margin - gap``). This was + unintuitive: users expected ``margin`` to mean geometric inflation and ``gap`` to mean a spatial gap. - - The ``vertcollide`` field in :ref:`mjsFlex` has been removed. It is no longer required since - :doc:`MuJoCo Warp ` supports native flex collisions. + Under the new semantics, ``margin`` is the geometric inflation of the geom surface and ``gap`` is an additional + detection buffer beyond the inflated surface: + + - **Detection**: contacts are created when ``dist < margin + gap``. + - **Force generation**: constraint forces are applied when ``dist < margin``. + - **Inactive contacts**: contacts with ``margin < dist ≤ margin + gap`` are included in ``mjData.contact`` but + generate no force (``efc_address = -1``). This is useful for :ref:`adhesion` actuators and + custom callbacks. + + With the default values ``margin = 0``, ``gap = 0``, the behavior is unchanged. + + .. image:: images/modeling/margin_gap_light.svg + :width: 80% + :align: center + :class: only-light + + .. image:: images/modeling/margin_gap_dark.svg + :width: 80% + :align: center + :class: only-dark + + | + + **Migration:** Models that use the default ``gap="0"`` (the vast majority) require no changes. For models with + ``gap > 0``, apply the following transformation to preserve identical behavior: + + .. code-block:: + + margin_new = margin_old - gap_old + gap_new = gap_old + + For example, a geom with the old attributes ``margin="0.1" gap="0.1"`` should be changed to + ``margin="0" gap="0.1"``. + + Negative ``margin`` values are now permitted (corresponding to ``gap > margin`` under the old semantics). The + constraint ``margin + gap >= 0`` should be maintained to ensure valid collision detection. + +Version 3.8.1 (May 11, 2026) +---------------------------- + +General +^^^^^^^ +1. Added island support for the :ref:`PGS solver`. +2. The :ref:`PGS solver` now iterates over constraints in pseudo-random order, improving performance by + ~20%. +3. Added support for :ref:`elastic2d` for trilinear and quadratic flex + :ref:`dofs`. +4. :ref:`Midpoint integration` is now restricted to the ``implicitfast`` + :ref:`integrator` and is disabled when fluid forces are active + (nonzero :ref:`density` or :ref:`viscosity`). + Midpoint integration treats external forces as zero-order-hold constants, which causes + energy gain in the presence of contacts and in fluid media. +5. Added :ref:`mjs_getOriginSpec`, returning the spec that originally defined an element, prior to attachment. This is + in contrast to :ref:`mjs_getSpec` which returns the spec currently owning the element. If the element is not the + result of an attach operation, the functions are identical. +6. Added :ref:`mju_sym2dense`, converting a lower-triangular, implicitly symmetric CSR matrix to a dense symmetric + matrix. The inertia matrix ``mjData.M`` is an example of such a matrix. + +.. admonition:: Future breaking API changes + :class: warning + + 7. The introduction of :ref:`mju_sym2dense` is a step towards the removal of the legacy-format ``mjData.qM`` in favor + of the CSR-format ``mjData.M``. This removal will involve a future breaking change to :ref:`mj_fullM` (which + currently accepts a ``qM``-like matrix as an argument). To prevent a future breakage, replace + ``mj_fullM(m, dst, d->qM)`` with + |br| ``mju_sym2dense(dst, d->M, m->nv, m->M_rownnz, m->M_rowadr, m->M_colind)``. Bug fixes ^^^^^^^^^ -- The compiler now correctly accounts for negative scaling when loading user specified mesh data. +8. Fixed default for multiccd in :doc:`mjcPhysics `. + +Python +^^^^^^ + +9. Added ``MjSpec.encode`` method, wrapping :ref:`mj_encode`. +10. Added ``mujoco.MjVfs`` Python binding to interact with the Virtual File System directly from Python. + See :ref:`Virtual File System ` for usage details. + + .. warning:: + The previous way of passing assets via a dictionary mapping asset names to bytes is **deprecated** and will be + removed in an upcoming release. You cannot specify both the ``assets`` dictionary and the ``vfs`` argument at the + same time. ``MjVfs`` should be used as a drop-in replacement. + + +Version 3.8.0 (April 24, 2026) +------------------------------ + +General +^^^^^^^ +1. Added support for Python 3.14. +2. Added :ref:`multi-cell support` for trilinear and quadratic flexes. Note that the implicit + integrator uses a dense solver for the flex degrees of freedom, which can be slow for multi-cell flexes. +3. Refactored ``strain`` flex :ref:`equality constraints` to be instantiated per cell instead of + per flex object, reducing the number of degrees of freedom per constraint row. The equality can be associated with a + specific cell with the new attribute :ref:`cell ` +4. Added new :ref:`mj_maxContact` function to get the maximum number of possible contacts returned by + colliding two geoms. +5. Added ``mj_containsBufferVFS`` and ``mj_containsFileVFS`` to check for existence of buffers and files in VFS. + +.. admonition:: Breaking API changes + :class: attention + + 6. The :ref:`multiccd` option (multiple contacts returned from the convex collision detection pipeline) + is now enabled by default. The new implementation (as opposed to the legacy pipeline) has little performance + overhead and improves stability. + + **Migration:** Disable :ref:`multiccd` to recover the previous behavior. + +Documentation +^^^^^^^^^^^^^ + +7. Added :ref:`documentation` for :ref:`mjpDecoder` plugins. + +Bug fixes +^^^^^^^^^ + +8. Asset paths in attached child specs are now resolved relative to the model file directory of the child spec, rather + than the parent spec. This prevents the origin of the parent spec to affect the resolution of asset paths in the + child spec. + +Version 3.7.0 (April 14, 2026) +------------------------------ + +General +^^^^^^^ + +1. Added the :ref:`dcmotor` actuator for modeling DC motors. Supports optional + electrical dynamics (inductance), cogging torque, thermal resistance variation, and LuGre friction. See the + `technical note <_static/dcmotor.pdf>`__ for more details. +2. Actuators with joint or tendon transmissions can now contribute + :ref:`damping` and :ref:`armature` to their transmission target. + These are applied during the passive force and inertia computations, respectively, and are scaled by gear\ :sup:`2` + ("reflected" damping/inertia). + +.. youtube:: aKa3ZlEF9_Y + :align: right + :width: 35% + +3. Stiffness in :ref:`joints` and :ref:`tendons` and damping in + :ref:`joints` and :ref:`tendons` now support nonlinear polynomial + :ref:`force profiles`. New ``mjModel`` arrays (``jnt_stiffnesspoly``, ``tendon_stiffnesspoly``, + ``dof_dampingpoly``, ``tendon_dampingpoly``) hold higher-order coefficients. The existing scalar arrays + (``jnt_stiffness``, ``dof_damping``, etc.) continue to hold the linear coefficient and are unchanged. + The polynomial order is defined by the new constant :ref:`mjNPOLY`. A future breaking C-API change + may unify the linear and higher-order coefficients into a single array. +4. Added :ref:`midpoint integration` for standalone free bodies in ``implicit`` and ``implicitfast`` + :ref:`integrators`. This applies the implicit midpoint rule to the rotational dynamics of free bodies + with no children, conserving kinetic energy to machine precision in the absence of external torques. The + :ref:`invdiscrete` flag now also disables midpoint integration, providing an opt-out + mechanism. +5. Added the centripetal/Coriolis acceleration term :math:`\dot{J}v` to the constraint solver bias for + :ref:`connect` and :ref:`weld` equality constaints. This significantly improves the + stability of constrained mechanisms like four-bar linkages. See :ref:`Dual problem` for details. + +6. Introduced :ref:`mjpEncoder`, the counterpart to :ref:`mjpDecoder` for encoding of :ref:`mjSpec` and :ref:`mjModel` + into :ref:`mjResource`. + +7. Added :ref:`mj_encode`, :ref:`mjp_registerEncoder`, :ref:`mjp_defaultEncoder`, and :ref:`mjp_findEncoder`. + +.. admonition:: Breaking API changes + :class: attention + + 8. The ``mjs`` layer fields ``stiffness`` and ``damping`` in :ref:`mjsJoint` and :ref:`mjsTendon` have + been widened from ``mjtNum`` scalars to ``mjtNum[mjNPOLY+1]`` arrays. The first element is the linear coefficient + (previously the scalar), and subsequent elements are the higher-order :ref:`polynomial` coefficients. + + **Migration:** Replace assignments like ``joint.stiffness = val`` with ``joint.stiffness[0] = val``. + 9. ``.obj`` and ``.stl`` decoders are now included as source when building MuJoCo with CMake. This fixes the + behaviour from the previous release where it required downstream code to load these plugins explicitly. + + 10. The ``vertcollide`` field in :ref:`mjsFlex` has been removed. It is no longer required since + :doc:`MuJoCo Warp ` supports native flex collisions. + + 11. :ref:`mjPLUGIN_LIB_INIT` macro now requires a name argument to avoid initialization function name collisions. + When building with MSVC, we now use the C runtime initialization section to initialize plugins instead of + ``DllMain``. See :ref:`plugin registration` for more details. + + 12. The :ref:`mjtWarning` enum value ``mjWARN_VGEOMFULL`` is removed. Exhaustion of visual geoms is now handled + internally by the :ref:`mjvScene`. + 13. URDF parsing no longer hardcodes :ref:`strippath` to "true". The setting is now respected and + the default is "false". Setting this is attribute is now the responsibility of the user. + + **Migration:** Set :ref:`strippath` to "true" in MJCF or programmatically using + + .. code-block:: python + + spec = mujoco.MjSpec.from_file("path/to/model.urdf") + spec.compiler.strippath = True + + +Bug fixes +^^^^^^^^^ + +14. The compiler now correctly accounts for negative scaling when loading user specified mesh data. Version 3.6.0 (March 10, 2026) ------------------------------ diff --git a/doc/computation/index.rst b/doc/computation/index.rst index b3122212..059558ee 100644 --- a/doc/computation/index.rst +++ b/doc/computation/index.rst @@ -202,7 +202,7 @@ earlier arm model :ref:`example ` the model has :math:`\nv = 13` degre for each of the 4 hinge joints, and 6 for the free-floating object. They appear in the same order in all system-level vectors and matrices whose dimensionality is :math:`\nv`. The data corresponding to a given model element can be recovered via indexing operations as illustrated in the :ref:`Clarifications` section in the Overview chapter. Vectors -and matrices with dimensionality :math:`\nq` are somewhat different because the active :ref:`constraints ` +and matrices with dimensionality :math:`\nc` are somewhat different because the active :ref:`constraints ` change at runtime. In that case there is still a fixed enumeration order (corresponding to the order in which the model elements appear in ``mjModel``) but any inactive constraints are omitted. @@ -524,13 +524,13 @@ the *new* velocity. *Implicit* Euler means: \end{aligned} Comparing :eq:`eq_semimplicit` and :eq:`eq_implicit`, we see that the acceleration :math:`a_{t+h}=\dot{v}_{t+h}` on the -right hand side of the velocity update is evaluated at the *next time step*. While evaluating the next acceleration +right-hand side of the velocity update is evaluated at the *next time step*. While evaluating the next acceleration is not possible without stepping, we can use a first-order Taylor expansion to approximate this quantity, and take a single step of Newton's method. When the expansion is only with respect to velocity (and not position), the integrator is known as *implicit-in-velocity* Euler. This approach is particularly effective in systems where instabilities are caused by velocity-dependent forces: multi-joint pendulums, bodies tumbling through space, systems with lift and drag forces, and systems with substantial damping in tendons and actuators. Writing the -acceleration as a function of velocity: :math:`a_t = a(v_t)`, the velocity update we aim to approximate is +acceleration as a function of velocity, :math:`a_t = a(v_t)`, the velocity update we aim to approximate is .. math:: v_{t+h} = v_t + h a(v_{t+h}) @@ -550,7 +550,7 @@ Thus we define the derivative D &\equiv {\partial \over \partial v} \Big(\tau(v) - c (v) + J^T f(v)\Big) \end{aligned} -The velocity update corresponding to Newton's method is as follows. First, we expand the right hand side to first order +The velocity update corresponding to Newton's method is as follows. First, we expand the right-hand side to first order .. math:: \begin{aligned} @@ -573,6 +573,51 @@ Solving for :math:`v_{t+h}`, we obtain the implicit-in-velocity update \widehat{M} &\equiv M-h D \end{aligned} +.. _geMidpoint: + +Midpoint integration for free bodies in vacuum + The implicit-in-velocity update :eq:`eq_implicit_update` treats the acceleration as a function of velocity and + linearizes. While effective for damping-like forces, it is sub-optimal for rotational dynamics, where + Coriolis and gyroscopic forces are *quadratic* in angular velocity. For this case, a better approach is to directly + discretize the rotational equations of motion using the *midpoint method*. + + Consider a rigid body rotating in its principal-axis frame with angular velocity + :math:`\omega \in \mathbb{R}^3` and diagonal inertia tensor :math:`I = \text{diag}(I_1, I_2, I_3)`. The rotational + dynamics are given by `Euler's rotation equation + `__: + + .. math:: + I \dot{\omega} + \omega \times I\omega = \tau + + where :math:`\tau` is the external torque in the principal-axis frame. + Evaluating the velocities at the midpoint, :math:`\omega_\text{mid} = (\omega_t + \omega_{t+h})/2`, gives: + + .. math:: + \frac{2}{h} I (\omega_\text{mid} - \omega_t) + \omega_\text{mid} \times I \omega_\text{mid} = \tau + + This is a system of 3 nonlinear equations in 3 unknowns :math:`\omega_\text{mid}`, solved at each timestep using + Newton's method with a backtracking line search. After solving, the new velocity is recovered as + :math:`\omega_{t+h} = 2\omega_\text{mid} - \omega_t`. + + **Properties.** The midpoint method preserves all `quadratic first integrals + `__ of the ODE. For Euler's equations, these are the + kinetic energy :math:`H = \frac{1}{2}\omega^T I\omega` and the squared angular momentum + :math:`C = \frac{1}{2}|I\omega|^2`, both conserved exactly in the absence of external torque. Since :math:`C` is the + Casimir function of the `Lie-Poisson `__ structure, the midpoint + method is a symmetric (time-reversible) and second-order accurate *Poisson integrator*. + + **Eligibility.** Midpoint integration is only applied when using the ``implicitfast`` integrator, to + free bodies with no child bodies, and only when the medium has zero :ref:`density` and + :ref:`viscosity`. + + **Performance.** While the midpoint method carries computational overhead, we've found it to be + negligible compared to the rest of the pipeline, on the order of 1% in the worst case. + + **Disabling.** Because midpoint integration solves a nonlinear equation for the next velocity, it breaks the linear + relationship between finite-differenced velocities and forces assumed by discrete inverse dynamics. Therefore, + setting the :ref:`invdiscrete` flag disables midpoint integration, and also provides a + general opt-out mechanism for this integrator. + .. _geIntegrators: Integrators @@ -585,7 +630,7 @@ Semi-implicit with implicit joint damping (``Euler``) For this method, :math:`D` only includes derivatives of joint damping. Note that in this case :math:`D` is diagonal and :math:`\widehat{M}` is symmetric, so :math:`L^TL` decomposition (a variant of Cholesky) can be used. This factorization is stored in ``mjData.qH``. If the model has no joint damping or the - :ref:`eulerdamp` disable-flag is set, implicit damping is disabled and the semi-implicit + :ref:`eulerdamp` disable flag is set, implicit damping is disabled and the semi-implicit update :eq:`eq_semimplicit` is used, rather than :eq:`eq_implicit_update`, avoiding the additional factorization of :math:`\widehat{M}` (*additional* because :math:`M` is already factorized for the acceleration update :eq:`eq_forward`). @@ -609,15 +654,17 @@ Fast implicit-in-velocity (``implicitfast``) scenarios which are not common and already well-handled by the Runge-Kutta integrator (see below). Because the RNE derivatives are also the main source of asymmetry of :math:`D`, by dropping them and symmetrizing, we can use the faster :math:`L^TL` rather than :math:`LU` decomposition. + The ``implicitfast`` integrator applies :ref:`midpoint integration` to eligible free bodies in vacuum, + providing exact energy conservation for spinning objects at negligible additional cost. 4th-order Runge-Kutta (``RK4``) One advantage of our continuous-time formulation is that we can use higher order integrators such as Runge-Kutta or - multistep methods. The only such integrator currently implemented is the fixed-step `4th-order Runge-Kutta method + multistep methods. MuJoCo implements the fixed-step `4th-order Runge-Kutta method `__, though users can easily implement other integrators by calling :ref:`mj_forward` and integrating accelerations themselves. We have observed that for energy-conserving systems (`example <../_static/pendulum.xml>`__), RK4 is qualitatively better than the single-step methods, both in terms of stability and accuracy, even when the timestep is decreased by - a factor of 4 (so the computational effort is identical). In the presence of large velocity- dependent forces, if the + a factor of 4 (so the computational effort is identical). In the presence of large velocity-dependent forces, if the chosen single-step method integrates those forces implicitly, single-step methods can be significantly more stable than RK4. @@ -641,11 +688,12 @@ Fast implicit-in-velocity (``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. **implicit**: - The benefit over ``implicitfast`` is the implicit integration of Coriolis and centripetal forces, including - gyroscopic forces. The most common case where integrating such forces implicitly leads to noticeable improvement is - when free objects with asymmetric inertia are spinning quickly. `gyroscopic.xml <../_static/gyroscopic.xml>`__ - shows an ellipsoid rolling on an inclined plane which quickly diverges with ``implicitfast`` but is stable with - ``implicit``. + The benefit over ``implicitfast`` is the implicit integration of Coriolis and centripetal forces for *coupled* + rotational systems such as multi-link pendula. Note that ``implicit`` does not apply :ref:`midpoint + integration` (only ``implicitfast`` does), but its RNE derivatives provide comparable stability + for free-body rotation. For example, `gyroscopic.xml <../_static/gyroscopic.xml>`__ shows an ellipsoid rolling + on an inclined plane; both ``implicitfast`` and ``implicit`` handle this case well, while ``Euler`` quickly + diverges. **RK4**: This integrator is best for systems which are energy conserving, or almost energy-conserving. `pendulum.xml <../_static/pendulum.xml>`__ shows a complicated pendulum mechanism which diverges quickly using ``Euler`` or @@ -683,8 +731,8 @@ Constraint model MuJoCo has a very flexible constraint model, which is nevertheless handled in a uniform way by the :ref:`solver ` described later. Here we explain what the individual constraints are conceptually, and how they -are laid out in the system-level vector and matrices with dimensionality :math:`\nq`. Each conceptual constraint can -contribute one or more scalar constraints towards the total count :math:`\nq`, and each scalar constraint has a +are laid out in the system-level vector and matrices with dimensionality :math:`\nc`. Each conceptual constraint can +contribute one or more scalar constraints towards the total count :math:`\nc`, and each scalar constraint has a corresponding row in the constraint Jacobian :math:`J`. Active constraints are ordered by type in the order in which the types are described below, and then by model element within each type. The types are: equality, friction loss, limit, contact. Limits are handled as frictionless contacts by the solver and are not treated as a separate type internally. We @@ -698,7 +746,7 @@ Equality MuJoCo can model equality constraints in the general form :math:`r(q) = 0` where :math:`r` can be any differentiable scalar or vector function of the position vector :math:`q`. It has the semantics of a residual. The solver can actually work with non-holonomic constraints as well, but we do not yet have such constraint types defined. Each equality -constraint contributes :math:`\dim(r)` elements to the total constraint count :math:`\nq`. The corresponding block in +constraint contributes :math:`\dim(r)` elements to the total constraint count :math:`\nc`. The corresponding block in :math:`J` is simply the Jacobian of the residual, namely :math:`\partial r / \partial q`. Note that due to the properties of quaternions, differentiation with respect to :math:`q` produces vectors of size :math:`\nv` rather than :math:`\nq`. @@ -861,7 +909,7 @@ In addition to the above quantities which are computed online, each contact has model definition. .. list-table:: - :widths: 1 5 + :widths: 2 6 :header-rows: 1 * - Parameter @@ -872,15 +920,53 @@ model definition. - Vector of friction coefficients with dimensionality ``condim-1``. See below for semantics of the specific coefficients. * - ``margin`` - - The distance margin used to determine if the contact should be included in the global contact array - ``mjData.contact``. + - The geometric inflation of the geom surfaces. Contacts are detected when the distance is below + ``margin + gap``, and contact forces are generated when the distance is below ``margin``. * - ``gap`` - - For custom computations it is sometimes convenient to include contacts in ``mjData.contact`` but not generate - contact forces. This is what ``gap`` does: contact forces are generated only when the normal distance is below - (margin - gap). + - An additional detection buffer beyond ``margin``. Contacts with distance between ``margin`` and + ``margin + gap`` are included in ``mjData.contact`` as inactive contacts, but no contact forces are generated. + This is useful for action-at-a-distance effects, for example by :ref:`adhesion` actuators. * - ``solref`` and ``solimp`` - :ref:`Solver ` parameters, explained later. +.. _coMarginGap: + +margin and gap +^^^^^^^^^^^^^^ + +Each geom has a ``margin`` and a ``gap`` parameter, defined in the table above. The values for both parameters are +:ref:`summed` when considering contact between the two geoms. Together they define three regimes of contact +detection and force generation, illustrated in the figure below. + +.. image:: ../images/modeling/margin_gap_light.svg + :width: 90% + :align: center + :class: only-light + +.. image:: ../images/modeling/margin_gap_dark.svg + :width: 90% + :align: center + :class: only-dark + +The distance between two geom surfaces determines which regime applies: + +- **No contact** (distance > ``margin + gap``): The geom surfaces, including their gap buffers, are not overlapping. + No contact is generated. + +- **Inactive contact** (``margin`` < distance ≤ ``margin + gap``): A contact is detected and included in + ``mjData.contact``, but no contact force is generated (``efc_address = -1``). These contacts can be used for custom + computations, for example by :ref:`adhesion` actuators. + +- **Active contact** (distance ≤ ``margin``): The contact is active and constraint forces are generated. The constraint + impedance function is applied to the quantity ``distance - margin``, which is non-positive in this regime. + +Negative ``margin`` values, corresponding "shrinkgage" of the geometric shape, are permitted. In this case +``margin + gap >= 0`` must be maintained for collision detection to work correctly. + +.. _coCondim: + +condim +^^^^^^ The contact friction cone can be either elliptic or pyramidal. This is a global setting determined by the choice of constraint solver: the elliptic solvers work with elliptic cones, while the pyramidal solvers work with pyramidal cones, as defined later. The ``condim`` parameter determines the contact type, and has the following meaning: @@ -913,6 +999,11 @@ Note that condim cannot be 2 or 5. This is because the two tangential directions treated as pairs. The friction coefficients within a pair can be different though, which can be used to model skating for example. +.. _coCones: + +Friction cones +^^^^^^^^^^^^^^ + Now we describe the friction cones and the corresponding Jacobians more formally. In this section only, let :math:`f` denote the vector of constraint forces for a single contact (as opposed to the system-level vector of constraint forces), :math:`\mu` the vector of friction coefficients, and :math:`n` the contact dimensionality condim. For @@ -1002,34 +1093,34 @@ We will use the following notation beyond the notation introduced earlier: - Size - Description * - :math:`z` - - :math:`\nq` + - :math:`\nc` - constraint deformations * - :math:`\omega` - - :math:`\nq` + - :math:`\nc` - velocity of constraint deformations * - :math:`k` - - :math:`\nq` + - :math:`\nc` - virtual constraint stiffness * - :math:`b` - - :math:`\nq` + - :math:`\nc` - virtual constraint damping * - :math:`d` - - :math:`\nq` + - :math:`\nc` - constraint impedance * - :math:`A(q)` - - :math:`\nq \times \nq` + - :math:`\nc \times \nc` - inverse inertia in constraint space * - :math:`R(q)` - - :math:`\nq \times \nq` + - :math:`\nc \times \nc` - diagonal regularizer in constraint space * - :math:`\ar` - - :math:`\nq` + - :math:`\nc` - reference acceleration in constraint space * - :math:`\au(q, v, \tau)` - - :math:`\nq` + - :math:`\nc` - unconstrained acceleration in constraint space * - :math:`\ac(q, v, \dot{v})` - - :math:`\nq` + - :math:`\nc` - constrained acceleration in constraint space * - :math:`\mathcal{K}(q)` - @@ -1066,7 +1157,8 @@ explain what it means and why it makes sense. That problem is :label: eq:primal The new players here are the diagonal regularizer :math:`R > 0` which makes the constraints soft, and the reference -acceleration :math:`\ar` which stabilizes the constraints. The latter is similar in spirit to Baumgarte stabilization, +acceleration :math:`\ar` which stabilizes the constraints; the latter is a spring-damper defined in the +:ref:`Parameters ` section below. It is similar in spirit to Baumgarte stabilization, but instead of adding a constraint force directly, it modifies the optimization problem whose solution is the constraint force. Since this problem is itself constrained, the relation between :math:`\ar` and :math:`f` is generally non-linear. The quantities :math:`R` and :math:`\ar` are computed from the solver :ref:`parameters ` as described @@ -1249,18 +1341,23 @@ when This key identity is essentially Newton's second law projected in constraint space. It is derived by moving the term :math:`c` in the equations of motion :eq:`eq:motion` to the right hand side, multiplying by :math:`J M^{-1}` from the -left, adding :math:`\dot{J} v` to both sides, and substituting the above definitions of :math:`A, \au, \ac`. In terms of -implementation, we do not actually compute the acceleration term :math:`\dot{J} v`. This is because our optimization -problems depend on differences of constraint-space accelerations, and so this term would cancel out even if we were to -compute it. +left, adding :math:`\dot{J} v` to both sides, and substituting the above definitions of :math:`A, \au, \ac`. Computing +:math:`\dot{J} v` requires differentiating the constraint Jacobian with respect to time, which is nontrivial. +Although this term cancels in the identity :eq:`eq:identity` and so does not affect the forward-inverse comparison, its +omission in the forward dynamics introduces a velocity-dependent bias for any constraint whose Jacobian varies with +configuration. We compute this term for equality constraints (connect and weld) where Jacobian differentiation +is tractable. For contacts, the term remains omitted due to the complexity of differentiating the contact frame through +the collision pipeline. -Note that the quadratic term in the inverse problem is weighted by :math:`R` instead of :math:`A+R`. This tells us two -things. First, in the limit :math:`R \to 0` corresponding to hard constraints the inverse is no longer defined, as one -would expect. Second and more useful, the inverse problem is diagonal, i.e., it decouples into independent optimization -problems over the individual constraint forces. The only remaining coupling is due to the constraint set :math:`\Omega`, -but that set is also decoupled over the conceptual constraints discussed earlier. It turns out that all these -independent optimization problems can be solved analytically. The only non-trivial case is the elliptic friction cone -model; we have shown how it can be handled in the above-referenced +Note that the quadratic term in the inverse problem is weighted by :math:`R` instead of :math:`A+R`. This is the key +structural insight: the :math:`A` matrix cancels entirely, leaving only :math:`R` in the quadratic term. Two +consequences follow. First, in the limit :math:`R \to 0` corresponding to hard constraints the inverse is no longer +defined, as one would expect. Second, the inverse problem is diagonal, i.e., it decouples into independent optimization +problems over the individual constraint forces. Since :math:`R` is diagonal, no matrix inversion or factorization is +needed -- the inverse dynamics require no optimization at all, only analytical formulas. The only remaining coupling is +due to the constraint set :math:`\Omega`, but that set is also decoupled over the conceptual constraints discussed +earlier. It turns out that all these independent optimization problems can be solved analytically. The only non-trivial +case is the elliptic friction cone model; we have shown how it can be handled in the above-referenced `paper `__. It requires a certain coupling of the diagonal values of :math:`R`, which is automatically enforced by MuJoCo so as to enable an exact analytical inverse for every model. @@ -1287,12 +1384,15 @@ Each solver algorithm can be used with both pyramidal and elliptic friction cone representations of the constraint Jacobian and related matrices. **CG** : conjugate gradient method - This algorithm uses the non-linear conjugate gradient method with the Polak-Ribiere-Plus formula. Line-search is - exact, using Newton's method in one dimension, with analytical second derivatives. + This algorithm uses the non-linear conjugate gradient method with the Polak-Ribiere-Plus formula (non-negative + :math:`\beta`). Line-search is exact, using Newton's method in one dimension with analytical second derivatives on + the piecewise-quadratic cost. CG has no setup cost. **Newton** : Newton's method This algorithm implements the exact Newton method, with analytical second-order derivatives and Cholesky - factorization of the Hessian. The line-search is the same as in the CG method. It is the default solver. + factorization of the Hessian. The line-search is the same as in the CG method. When constraint states change between + iterations (e.g., a constraint transitions from quadratic to linear), the Hessian factorization is updated + incrementally via rank-1 Cholesky updates, avoiding full refactorization. It is the default solver. **PGS** : Projected Gauss-Seidel method This is the most common algorithm used in physics simulators, and used to be the default in MuJoCo, until we @@ -1327,6 +1427,21 @@ representations of the constraint Jacobian and related matrices. handle elliptic cones without approximating them. It does more work per contact, however the contact dimensionality is smaller, and these two factors roughly balance each other. +**NoSlip** : post-processing pass + This is not a standalone solver but a post-processing step, enabled by setting ``noslip_iterations`` to a positive + value in :ref:`option