Initial open sourcing of MuJoCo.
PiperOrigin-RevId: 450374687 Change-Id: Ie3225a46ce095fc28ae8e63c326a640261f562bb
This commit is contained in:
committed by
Copybara-Service
parent
0e5d062302
commit
1913a02b40
+183
-160
@@ -2,6 +2,8 @@
|
||||
Programming
|
||||
===========
|
||||
|
||||
.. _inIntro:
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
@@ -10,32 +12,16 @@ is a dynamic library compatible with Windows, Linux and macOS, which requires a
|
||||
library exposes the full functionality of the simulator through a compiler-independent shared-memory C API. It can also
|
||||
be used in C++ programs.
|
||||
|
||||
MuJoCo is a free product currently distributed as a pre-built dynamic library and will soon be made available as an
|
||||
open-source project. The software distribution contains a compiled version of GLFW which is used in the code samples to
|
||||
create an OpenGL window and direct user input to it. The distribution for each platform contains the following dynamic
|
||||
library:
|
||||
|
||||
.. code-block:: Text
|
||||
|
||||
Windows: mujoco.dll (stub library: mujoco.lib)
|
||||
|
||||
Linux: mujoco.so.2.1.5
|
||||
|
||||
macOS: mujoco.2.1.5.dylib
|
||||
|
||||
Even though MuJoCo is a single dynamic library with unified C API, it contains several modules, some of which are
|
||||
implemented in C++. We have taken advantage of the convenience of C++ for functionality that is used before the
|
||||
simulation starts (namely the parser and compiler), and have gone to the trouble of writing carefully-tuned C code for
|
||||
all runtime functionality. The modules are:
|
||||
The MuJoCo codebase is organized into subdirectories corresponding to different major areas of functionality:
|
||||
|
||||
Engine
|
||||
The simulator (or physics engine) is written in C. It is responsible for all runtime computations.
|
||||
Parser
|
||||
The XML parser is written in C++. It can parse MJCF models and URDF models, converting them into an internal mjCModel
|
||||
C++ object which is not directly exposed to the user.
|
||||
Compiler
|
||||
The compiler is written in C++. It takes an mjCModel C++ object constructed by the parser, and converts it into an
|
||||
mjModel C structure used at runtime.
|
||||
Simulator
|
||||
The simulator (or physics engine) is written in C. It is responsible for all runtime computations.
|
||||
Abstract visualizer
|
||||
The abstract visualizer is written in C. It generates a list of abstract geometric entities representing the
|
||||
simulation state, with all information needed for actual rendering. It also provides abstract mouse hooks for camera
|
||||
@@ -54,43 +40,83 @@ UI framework
|
||||
Getting started
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
The software distribution is a single .zip (Windows) or .tar.gz (Mac and Linux) archive whose name contains the platform
|
||||
and software version, e.g. mujoco210_windows.zip. There is no installer. Simply unzip this archive in a directory of
|
||||
your choice (where you have write access). You may need to use chmod to set execute permissions or otherwise give
|
||||
permissions to run the libraries. From the bin subdirectory, you can now run the precompiled code samples, for example:
|
||||
MuJoCo is an open source project. Pre-built dynamic libraries are available for x86_64 and arm64 machines running
|
||||
Windows, Linux, and macOS. These can be downloaded from the `GitHub Releases page <https://github.com/deepmind/mujoco/releases>`_.
|
||||
Users who do not intend to develop or modify core MuJoCo code are encouraged to use our pre-built libraries, as these
|
||||
come bundled with the same versions of dependencies those that we regularly test against, and benefit from build flags
|
||||
that have been tuned for performance. Our pre-built libraries are almost entirely self-contained and do not require
|
||||
other any library to be present, other than the standard C runtime. We also hide all symbols corresponding apart from
|
||||
those that form MuJoCo's public API, thus ensuring that it can coexist with any other libraries that may be loaded into
|
||||
the process (including other versions of libraries that MuJoCo depends on).
|
||||
|
||||
The pre-built distribution is a single .zip on Windows, .dmg on macOS, and .tar.gz on Linux. There is no installer.
|
||||
On Windows and Linux, simply extract the archive in a directory of your choice. From the ``bin`` subdirectory, you can
|
||||
now run the precompiled code samples, for example:
|
||||
|
||||
.. code-block:: Text
|
||||
|
||||
Windows: simulate ..\model\humanoid.xml
|
||||
Linux and macOS: ./simulate ../model/humanoid.xml
|
||||
|
||||
Prior to MuJoCo 2.0, running the code samples needed LD_LIBRARY_PATH on Linux. As of MuJoCo 2.0, they are compiled with
|
||||
"rpath $ORIGIN" so the library is found in the executable directory (if it is not in the path).
|
||||
|
||||
The directory structure is shown below. Users can re-organize it if needed, as well as install the dynamic libraries in
|
||||
other directories and set the path accordingly. The only file created automatically is MUJOCO_LOG.TXT in the executable
|
||||
directory; it contains error and warning messages, and can be deleted at any time.
|
||||
|
||||
.. code-block:: Text
|
||||
|
||||
mujoco210
|
||||
bin - dynamic libraries, executables, MUJOCO_LOG.TXT
|
||||
doc - README.txt and REFERENCE.txt
|
||||
include - header files needed to develop with MuJoCo
|
||||
model - model collection (extra models available on the Forum)
|
||||
sample - code samples and makefile need to build them
|
||||
bin - dynamic libraries, executables, MUJOCO_LOG.TXT
|
||||
doc - README.txt and REFERENCE.txt
|
||||
include - header files needed to develop with MuJoCo
|
||||
model - model collection
|
||||
sample - code samples and makefile need to build them
|
||||
|
||||
After verifying that the simulator works, the next step is to re-compile the code samples so as to ensure that the
|
||||
development environment is properly installed. The distribution includes a platform-specific makefile in the sample
|
||||
subdirectory, which assumes Visual Studio on Windows, GCC on Linux and Clang on macOS. On Windows, remember to open a
|
||||
Visual Studio command prompt with native x64 tools. Assuming the compilation succeeded and the resulting executables in
|
||||
the bin subdirectory work, you are ready to start developing with MuJoCo.
|
||||
After verifying that the simulator works, you may also want to re-compile the code samples to ensure that you have a
|
||||
working development environment. We provide Makefiles for `Windows <https://github.com/deepmind/mujoco/blob/main/sample/Makefile.windows>`_,
|
||||
`macOS <https://github.com/deepmind/mujoco/blob/main/sample/Makefile.macos>`_, and
|
||||
`Linux <https://github.com/deepmind/mujoco/blob/main/sample/Makefile>`_, and also a cross-platform
|
||||
`CMake <https://github.com/deepmind/mujoco/blob/main/sample/CMakeLists.txt>`_ setup that can be used to build sample
|
||||
applications independently of the MuJoCo library itself. If you are using the vanilla Makefile, we assume that you are
|
||||
using Visual Studio on Windows and LLVM/Clang on Linux. On Windows, you also need to either open a Visual Studio command
|
||||
prompt with native x64 tools or call the ``vcvarsall.bat`` script that comes with your MSVC installation to set up the
|
||||
appropriate environment variables.
|
||||
|
||||
As already mentioned, MuJoCo is a compiler-independent library. In theory the user should be able to switch to any
|
||||
compiler of their choice. In practice we are using C++11 features as well as std:: functionality internally, and despite
|
||||
our efforts to statically link all necessary runtime libraries, this is not always possible - especially on Linux where
|
||||
licensing restrictions prevent static linking. If MuJoCo fails to start because of missing or incompatible dynamic
|
||||
libraries, please install the necessary libraries.
|
||||
On macOS, the DMG disk image contains ``MuJoCo.app``, which you can double-click to launch the ``simulate`` GUI.
|
||||
You can also drag ``MuJoCo.app`` into the ``/Application`` on your system, as you would to install any other app.
|
||||
While ``MuJoCo.app`` may look like a file, it is in fact an `Application Bundle <https://developer.apple.com/go/?id=bundle-structure>`_,
|
||||
which is a directory that contains executable binaries for all of MuJoCo's sample applications, along with an embedded
|
||||
`framework <https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WhatAreFrameworks.html>`_,
|
||||
which is a subdirectory containing the MuJoCo dynamic library and all of its public headers. In other words,
|
||||
``MuJoCo.app`` contains all the same files that are shipped in the archive on Windows and Linux. To see this, right
|
||||
click (or control-click) on ``MuJoCo.app`` and click "Show Package Contents".
|
||||
|
||||
As mentioned above, ``mujoco.framework`` contains the library and headers that are necessary to build any application
|
||||
that depends on MuJoCo. If you are using Xcode, you can import it as a framework dependency on your project. (This also
|
||||
works for Swift projects without any modification). If you are building manually, you can use ``-F`` and
|
||||
``-framework mujoco`` to specify the header search path and the library search path respectively. The macOS Makefile
|
||||
provides an example for this.
|
||||
|
||||
.. _inBuild:
|
||||
|
||||
Building MuJoCo from source
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To build MuJoCo from source, you will need CMake and a working C++17 compiler installed. The steps are:
|
||||
|
||||
#. Clone the ``mujoco`` repository from GitHub.
|
||||
#. Create a new build directory somewhere, and ``cd`` into it.
|
||||
#. Run ``cmake $PATH_TO_CLONED_REPO`` to configure the build.
|
||||
#. Run ``cmake --build .`` to build.
|
||||
|
||||
MuJoCo's build system automatically fetches dependencies from upstream repositories over the Internet using CMake's
|
||||
`FetchContent <https://cmake.org/cmake/help/latest/module/FetchContent.html>`_ module.
|
||||
|
||||
The main CMake setup will build the MuJoCo library itself along with all sample applications, but the Python
|
||||
bindings are not built. Those come with their own build instructions, which can be found in the :doc:`python`
|
||||
section of the documentation.
|
||||
|
||||
Additionally, the CMake setup also implements an installation phase which will copy and organize the output files to a
|
||||
target directory. Specify the directory using ``cmake $PATH_TO_CLONED_REPO -DCMAKE_INSTALL_PREFIX=<my_install_dir>``.
|
||||
After successfully building MuJoCo following the instructions above, you can install it using ``cmake --install .``.
|
||||
|
||||
.. _inHeader:
|
||||
|
||||
@@ -100,29 +126,29 @@ Header files
|
||||
The distribution contains several header files which are identical on all platforms. They are also available from the
|
||||
links below, to make this documentation self-contained.
|
||||
|
||||
mujoco.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mujoco.h>`__
|
||||
mujoco.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mujoco/mujoco.h>`__
|
||||
This is the main header file and must be included in all programs using MuJoCo. It defines all API functions and
|
||||
global variables, and includes the next 5 files which provide the necessary type definitions.
|
||||
mjmodel.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mjmodel.h>`__
|
||||
mjmodel.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mujoco/mjmodel.h>`__
|
||||
This file defines the C structure :ref:`mjModel` which is the runtime representation of the
|
||||
model being simulated. It also defines a number of primitive types and other structures needed to define mjModel.
|
||||
mjdata.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mjdata.h>`__
|
||||
mjdata.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mujoco/mjdata.h>`__
|
||||
This file defines the C structure :ref:`mjData` which is the workspace where all computations
|
||||
read their inputs and write their outputs. It also defines primitive types and other structures needed to define
|
||||
mjData.
|
||||
mjvisualize.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mjvisualize.h>`__
|
||||
mjvisualize.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mujoco/mjvisualize.h>`__
|
||||
This file defines the primitive types and structures needed by the abstract visualizer.
|
||||
mjrender.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mjrender.h>`__
|
||||
mjrender.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mujoco/mjrender.h>`__
|
||||
This file defines the primitive types and structures needed by the OpenGL renderer.
|
||||
mjui.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mjui.h>`__
|
||||
mjui.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mujoco/mjui.h>`__
|
||||
This file defines the primitive types and structures needed by the UI framework.
|
||||
mjtnum.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mjtnum.h>`__
|
||||
mjtnum.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mujoco/mjtnum.h>`__
|
||||
Defines MuJoCo's ``mjtNum`` floating-point type to be either ``double`` or ``float``. See :ref:`mjtNum`.
|
||||
mjxmacro.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mjxmacro.h>`__
|
||||
mjxmacro.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mujoco/mjxmacro.h>`__
|
||||
This file is optional and is not included by mujoco.h. It defines :ref:`X Macros <tyXMacro>` that can
|
||||
automate the mapping of mjModel and mjData into scripting languages, as well as other operations that require
|
||||
accessing all fields of mjModel and mjData. See code sample :ref:`testxml.cc <saTestXML>`.
|
||||
mjexport.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mjexport.h>`__
|
||||
mjexport.h `(source) <https://github.com/deepmind/mujoco/blob/main/include/mujoco/mjexport.h>`__
|
||||
Macros used for exporting public symbols from the MuJoCo library. This header should not be used directly by client
|
||||
code.
|
||||
glfw3.h
|
||||
@@ -152,7 +178,7 @@ the symbol :ref:`mjVERSION_HEADER <glNumeric>` and the library provides the func
|
||||
|
||||
// recommended version check
|
||||
if( mjVERSION_HEADER!=mj_version() )
|
||||
complain();
|
||||
complain();
|
||||
|
||||
Note that only the main header defines this symbol. We assume that the collection of headers released with each software
|
||||
version will stay together and will not be mixed between versions. To avoid complications with floating-point
|
||||
@@ -309,7 +335,10 @@ This code sample is a full-featured interactive simulator. It opens an OpenGL wi
|
||||
GLFW library, and renders the simulation state in it. There is built-in help, simulation statistics, profiler, sensor
|
||||
data plots. The model file can be specified as a command-line argument, or loaded at runtime using drag-and-drop
|
||||
functionality. As of MuJoCo 2.0, this code sample uses the native UI to render various controls, and provides an
|
||||
illustration of how the new UI framework is intended to be used.
|
||||
illustration of how the new UI framework is intended to be used. Below is a screen-capture of ``simulate`` in action:
|
||||
|
||||
.. youtube:: 0ORsj_E17B0
|
||||
:align: center
|
||||
|
||||
Interaction is done with the mouse; see the built-in help for summary of available commands. Briefly, an object is
|
||||
selected by left-double-click. The user can then apply forces and torques on the selected object by holding Ctrl and
|
||||
@@ -556,7 +585,7 @@ function :ref:`mj_step` in a loop such as
|
||||
|
||||
// simulate until t = 10 seconds
|
||||
while( d->time<10 )
|
||||
mj_step(m, d);
|
||||
mj_step(m, d);
|
||||
|
||||
This by itself will simulate the passive dynamics, because we have not provided any control signals or applied forces.
|
||||
The default (and recommended) way to control the system is to implement a control callback, for example
|
||||
@@ -566,8 +595,8 @@ The default (and recommended) way to control the system is to implement a contro
|
||||
// simple controller applying damping to each dof
|
||||
void mycontroller(const mjModel* m, mjData* d)
|
||||
{
|
||||
if( m->nu==m->nv )
|
||||
mju_scl(d->ctrl, d->qvel, -0.1, m->nv);
|
||||
if( m->nu==m->nv )
|
||||
mju_scl(d->ctrl, d->qvel, -0.1, m->nv);
|
||||
}
|
||||
|
||||
This illustrates two concepts. First, we are checking if the number of controls ``mjModel.nu`` equals the number of
|
||||
@@ -595,10 +624,9 @@ control callback) would become
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
while( d->time<10 )
|
||||
{
|
||||
// set d->ctrl or d->qfrc_applied or d->xfrc_applied
|
||||
mj_step(m, d);
|
||||
while( d->time<10 ) {
|
||||
// set d->ctrl or d->qfrc_applied or d->xfrc_applied
|
||||
mj_step(m, d);
|
||||
}
|
||||
|
||||
Why would we not be able to compute the controls before ``mj_step`` is called? After all, isn't this what causality means?
|
||||
@@ -619,11 +647,10 @@ before the control is needed, and after the control is needed. The simulation lo
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
while( d->time<10 )
|
||||
{
|
||||
mj_step1(m, d);
|
||||
// set d->ctrl or d->qfrc_applied or d->xfrc_applied
|
||||
mj_step2(m, d);
|
||||
while( d->time<10 ) {
|
||||
mj_step1(m, d);
|
||||
// set d->ctrl or d->qfrc_applied or d->xfrc_applied
|
||||
mj_step2(m, d);
|
||||
}
|
||||
|
||||
There is one complication however: this only works with Euler integration. The Runge-Kutta integrator (as well as other
|
||||
@@ -637,23 +664,22 @@ omitting some code that computes timing diagnostics. The main simulation functio
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void mj_step(const mjModel* m, mjData* d)
|
||||
{
|
||||
// common to all integrators
|
||||
mj_checkPos(m, d);
|
||||
mj_checkVel(m, d);
|
||||
mj_forward(m, d);
|
||||
mj_checkAcc(m, d);
|
||||
void mj_step(const mjModel* m, mjData* d) {
|
||||
// common to all integrators
|
||||
mj_checkPos(m, d);
|
||||
mj_checkVel(m, d);
|
||||
mj_forward(m, d);
|
||||
mj_checkAcc(m, d);
|
||||
|
||||
// compare forward and inverse solutions if enabled
|
||||
if( mjENABLED(mjENBL_FWDINV) )
|
||||
mj_compareFwdInv(m, d);
|
||||
// compare forward and inverse solutions if enabled
|
||||
if( mjENABLED(mjENBL_FWDINV) )
|
||||
mj_compareFwdInv(m, d);
|
||||
|
||||
// use selected integrator
|
||||
if( m->opt.integrator==mjINT_RK4 )
|
||||
mj_RungeKutta(m, d, 4);
|
||||
else
|
||||
mj_Euler(m, d);
|
||||
// use selected integrator
|
||||
if( m->opt.integrator==mjINT_RK4 )
|
||||
mj_RungeKutta(m, d, 4);
|
||||
else
|
||||
mj_Euler(m, d);
|
||||
}
|
||||
|
||||
The checking functions reset the simulation automatically if any numerical values have become invalid or too large.
|
||||
@@ -668,34 +694,34 @@ mj_step2 regardless of the setting of ``mjModel.opt.integrator``.
|
||||
|
||||
void mj_step1(const mjModel* m, mjData* d)
|
||||
{
|
||||
mj_checkPos(m, d);
|
||||
mj_checkVel(m, d);
|
||||
mj_fwdPosition(m, d);
|
||||
mj_sensorPos(m, d);
|
||||
mj_energyPos(m, d);
|
||||
mj_fwdVelocity(m, d);
|
||||
mj_sensorVel(m, d);
|
||||
mj_energyVel(m, d);
|
||||
mj_checkPos(m, d);
|
||||
mj_checkVel(m, d);
|
||||
mj_fwdPosition(m, d);
|
||||
mj_sensorPos(m, d);
|
||||
mj_energyPos(m, d);
|
||||
mj_fwdVelocity(m, d);
|
||||
mj_sensorVel(m, d);
|
||||
mj_energyVel(m, d);
|
||||
|
||||
// if we had a callback we would be using mj_step, but call it anyway
|
||||
if( mjcb_control )
|
||||
mjcb_control(m, d);
|
||||
// if we had a callback we would be using mj_step, but call it anyway
|
||||
if( mjcb_control )
|
||||
mjcb_control(m, d);
|
||||
}
|
||||
|
||||
void mj_step2(const mjModel* m, mjData* d)
|
||||
{
|
||||
mj_fwdActuation(m, d);
|
||||
mj_fwdAcceleration(m, d);
|
||||
mj_fwdConstraint(m, d);
|
||||
mj_sensorAcc(m, d);
|
||||
mj_checkAcc(m, d);
|
||||
mj_fwdActuation(m, d);
|
||||
mj_fwdAcceleration(m, d);
|
||||
mj_fwdConstraint(m, d);
|
||||
mj_sensorAcc(m, d);
|
||||
mj_checkAcc(m, d);
|
||||
|
||||
// compare forward and inverse solutions if enabled
|
||||
if( mjENABLED(mjENBL_FWDINV) )
|
||||
mj_compareFwdInv(m, d);
|
||||
// compare forward and inverse solutions if enabled
|
||||
if( mjENABLED(mjENBL_FWDINV) )
|
||||
mj_compareFwdInv(m, d);
|
||||
|
||||
// integrate with Euler; ignore integrator option
|
||||
mj_Euler(m, d);
|
||||
// integrate with Euler; ignore integrator option
|
||||
mj_Euler(m, d);
|
||||
}
|
||||
|
||||
.. _siStateControl:
|
||||
@@ -830,37 +856,35 @@ skip arguments (mjSTAGE_NONE, 0), where the latter function is implemented as
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void mj_forwardSkip(const mjModel* m, mjData* d,
|
||||
int skipstage, int skipsensor)
|
||||
{
|
||||
// position-dependent
|
||||
if( skipstage<mjSTAGE_POS )
|
||||
{
|
||||
mj_fwdPosition(m, d);
|
||||
if( !skipsensor )
|
||||
mj_sensorPos(m, d);
|
||||
if( mjENABLED(mjENBL_ENERGY) )
|
||||
mj_energyPos(m, d);
|
||||
}
|
||||
|
||||
// velocity-dependent
|
||||
if( skipstage<mjSTAGE_VEL )
|
||||
{
|
||||
mj_fwdVelocity(m, d);
|
||||
if( !skipsensor )
|
||||
mj_sensorVel(m, d);
|
||||
if( mjENABLED(mjENBL_ENERGY) )
|
||||
mj_energyVel(m, d);
|
||||
}
|
||||
|
||||
// acceleration-dependent
|
||||
if( mjcb_control )
|
||||
mjcb_control(m, d);
|
||||
mj_fwdActuation(m, d);
|
||||
mj_fwdAcceleration(m, d);
|
||||
mj_fwdConstraint(m, d);
|
||||
void mj_forwardSkip(const mjModel* m, mjData* d, int skipstage, int skipsensor) {
|
||||
// position-dependent
|
||||
if( skipstage<mjSTAGE_POS )
|
||||
{
|
||||
mj_fwdPosition(m, d);
|
||||
if( !skipsensor )
|
||||
mj_sensorAcc(m, d);
|
||||
mj_sensorPos(m, d);
|
||||
if( mjENABLED(mjENBL_ENERGY) )
|
||||
mj_energyPos(m, d);
|
||||
}
|
||||
|
||||
// velocity-dependent
|
||||
if( skipstage<mjSTAGE_VEL )
|
||||
{
|
||||
mj_fwdVelocity(m, d);
|
||||
if( !skipsensor )
|
||||
mj_sensorVel(m, d);
|
||||
if( mjENABLED(mjENBL_ENERGY) )
|
||||
mj_energyVel(m, d);
|
||||
}
|
||||
|
||||
// acceleration-dependent
|
||||
if( mjcb_control )
|
||||
mjcb_control(m, d);
|
||||
mj_fwdActuation(m, d);
|
||||
mj_fwdAcceleration(m, d);
|
||||
mj_fwdConstraint(m, d);
|
||||
if( !skipsensor )
|
||||
mj_sensorAcc(m, d);
|
||||
}
|
||||
|
||||
Note that this is the same sequence of calls as in mj_step1 and mj_step2 above, except that checking of real values
|
||||
@@ -985,17 +1009,17 @@ management.
|
||||
// parallel section
|
||||
#pragma omp parallel
|
||||
{
|
||||
int n = omp_get_thread_num(); // thread-private variable with thread id (0 to nthread-1)
|
||||
int n = omp_get_thread_num(); // thread-private variable with thread id (0 to nthread-1)
|
||||
|
||||
// ... initialize d[n] from results in serial code
|
||||
// ... initialize d[n] from results in serial code
|
||||
|
||||
// thread function
|
||||
worker(m, d[n]); // shared mjModel (read-only), per-thread mjData (read-write)
|
||||
// thread function
|
||||
worker(m, d[n]); // shared mjModel (read-only), per-thread mjData (read-write)
|
||||
}
|
||||
|
||||
// delete per-thread mjData
|
||||
for( int n=0; n<nthread; n++ )
|
||||
mj_deleteData(d[n]);
|
||||
mj_deleteData(d[n]);
|
||||
|
||||
Since all top-level API functions threat mjModel as ``const``, this multi-threading scheme is safe. Each thread only
|
||||
writes to its own mjData. Therefore no further synchronization among threads is needed.
|
||||
@@ -1310,11 +1334,11 @@ the total energy indicate inaccuracies in numerical integration. For such system
|
||||
better performance than the default semi-implicit Euler integrator.
|
||||
|
||||
Finally, the user can implement additional diagnostics as needed. Two examples were provided in the code samples
|
||||
``testxml.cc`` and ``derivative.cc``, where we computed model mismatches after save and load, and assessed the accuracy of the
|
||||
numerical derivatives respectively. Key to such diagnostics is to implement two different algorithms or simulation
|
||||
paths that compute the same quantity, and compare the results numerically. This type of sanity check is essential when
|
||||
dealing with complex dynamical systems where we do not really know what the numerical output should be; if we knew
|
||||
that, we would not be using a simulator in the first place.
|
||||
``testxml.cc`` and ``derivative.cc``, where we computed model mismatches after save and load, and assessed the accuracy
|
||||
of the numerical derivatives respectively. Key to such diagnostics is to implement two different algorithms or
|
||||
simulation paths that compute the same quantity, and compare the results numerically. This type of sanity check is
|
||||
essential when dealing with complex dynamical systems where we do not really know what the numerical output should be;
|
||||
if we knew that, we would not be using a simulator in the first place.
|
||||
|
||||
.. _siJacobian:
|
||||
|
||||
@@ -1529,29 +1553,28 @@ one of its derivatives.
|
||||
// ... install GLFW keyboard and mouse callbacks
|
||||
|
||||
// run main loop, target real-time simulation and 60 fps rendering
|
||||
while( !glfwWindowShouldClose(window) )
|
||||
{
|
||||
// advance interactive simulation for 1/60 sec
|
||||
// Assuming MuJoCo can simulate faster than real-time, which it usually can,
|
||||
// this loop will finish on time for the next frame to be rendered at 60 fps.
|
||||
// Otherwise add a cpu timer and exit this loop when it is time to render.
|
||||
mjtNum simstart = d->time;
|
||||
while( d->time - simstart < 1.0/60.0 )
|
||||
mj_step(m, d);
|
||||
while( !glfwWindowShouldClose(window) ) {
|
||||
// advance interactive simulation for 1/60 sec
|
||||
// Assuming MuJoCo can simulate faster than real-time, which it usually can,
|
||||
// this loop will finish on time for the next frame to be rendered at 60 fps.
|
||||
// Otherwise add a cpu timer and exit this loop when it is time to render.
|
||||
mjtNum simstart = d->time;
|
||||
while( d->time - simstart < 1.0/60.0 )
|
||||
mj_step(m, d);
|
||||
|
||||
// get framebuffer viewport
|
||||
mjrRect viewport = {0, 0, 0, 0};
|
||||
glfwGetFramebufferSize(window, &viewport.width, &viewport.height);
|
||||
// get framebuffer viewport
|
||||
mjrRect viewport = {0, 0, 0, 0};
|
||||
glfwGetFramebufferSize(window, &viewport.width, &viewport.height);
|
||||
|
||||
// update scene and render
|
||||
mjv_updateScene(m, d, &opt, NULL, &cam, mjCAT_ALL, &scn);
|
||||
mjr_render(viewport, &scn, &con);
|
||||
// update scene and render
|
||||
mjv_updateScene(m, d, &opt, NULL, &cam, mjCAT_ALL, &scn);
|
||||
mjr_render(viewport, &scn, &con);
|
||||
|
||||
// swap OpenGL buffers (blocking call due to v-sync)
|
||||
glfwSwapBuffers(window);
|
||||
// swap OpenGL buffers (blocking call due to v-sync)
|
||||
glfwSwapBuffers(window);
|
||||
|
||||
// process pending GUI events, call GLFW callbacks
|
||||
glfwPollEvents();
|
||||
// process pending GUI events, call GLFW callbacks
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
// close GLFW, free visualization storage
|
||||
|
||||
Reference in New Issue
Block a user