From 24a555062d2e167f81e0e25693690d5b084bd44e Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Tue, 30 Jul 2024 08:40:55 -0700 Subject: [PATCH] Rename mjDSBL_AUTORESETNAN to mjDSBL_AUTORESET. - Expose in MJCF. - Add documentation. - Improve handling in simulate. PiperOrigin-RevId: 657606140 Change-Id: I6a27c2f4842d7d4ae32642f2a6255e5f8f1f605a --- doc/XMLreference.rst | 5 +++++ doc/XMLschema.rst | 6 +++--- doc/changelog.rst | 3 ++- doc/includes/references.h | 2 +- include/mujoco/mjmodel.h | 2 +- introspect/enums.py | 2 +- simulate/main.cc | 26 ++++++++++++++++++++++++-- simulate/simulate.cc | 7 +------ src/engine/engine_forward.c | 8 ++++---- src/engine/engine_support.c | 2 +- src/xml/xml_native_reader.cc | 5 +++-- src/xml/xml_native_writer.cc | 1 + unity/Runtime/Bindings/MjBindings.cs | 2 +- 13 files changed, 48 insertions(+), 23 deletions(-) diff --git a/doc/XMLreference.rst b/doc/XMLreference.rst index ec0fea5c..56c026a4 100644 --- a/doc/XMLreference.rst +++ b/doc/XMLreference.rst @@ -577,6 +577,11 @@ from its default. This flag disables implicit integration with respect to joint damping in the Euler integrator. See the :ref:`Numerical Integration` section for more details. +.. _option-flag-autoreset: + +:at:`autoreset`: :at-val:`[disable, enable], "enable"` + This flag disables the automatic reseting of the simulation state when numerical issues are detected. + .. _option-flag-override: :at:`override`: :at-val:`[disable, enable], "disable"` diff --git a/doc/XMLschema.rst b/doc/XMLschema.rst index 9fdd9dcd..ae9f43c7 100644 --- a/doc/XMLschema.rst +++ b/doc/XMLschema.rst @@ -35,11 +35,11 @@ | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | | | | | :ref:`warmstart` | :ref:`filterparent` | :ref:`actuation` | :ref:`refsafe` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`sensor` | :ref:`midphase` | :ref:`eulerdamp` | :ref:`override` | | +| | | | :ref:`sensor` | :ref:`midphase` | :ref:`eulerdamp` | :ref:`autoreset` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`energy` | :ref:`fwdinv` | :ref:`invdiscrete` | :ref:`multiccd` | | +| | | | :ref:`override` | :ref:`energy` | :ref:`fwdinv` | :ref:`invdiscrete` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`island` | | | | | +| | | | :ref:`multiccd` | :ref:`island` | | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | mujoco |br| |L| | | .. table:: | diff --git a/doc/changelog.rst b/doc/changelog.rst index d22ccc3b..a574c451 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -8,7 +8,8 @@ Upcoming version (not yet released) General ^^^^^^^ 1. Renamed ``mjModel.tex_rbg`` to ``mjModel.tex_data``. -2. Added a new disable flag ``mjDSBL_AUTORESETNAN`` to disable automatic reset when NaNs or infinities are produced. +2. Added a new :ref:`autoreset` flag to disable automatic reset when NaNs or infinities are + detected. 3. Added sub-elements to the MJCF :ref:`material` element, to allow specification of multiple textures for rendering (e.g., :ref:`occlusion-roughness-metallic`). Note that the MuJoCo renderer doesn't support these new features, and they are made available for use with external renderers. diff --git a/doc/includes/references.h b/doc/includes/references.h index 871069f2..d301a2c2 100644 --- a/doc/includes/references.h +++ b/doc/includes/references.h @@ -418,7 +418,7 @@ typedef enum mjtDisableBit_ { // disable default feature bitflags mjDSBL_SENSOR = 1<<12, // sensors mjDSBL_MIDPHASE = 1<<13, // mid-phase collision filtering mjDSBL_EULERDAMP = 1<<14, // implicit integration of joint damping in Euler integrator - mjDSBL_AUTORESETNAN = 1<<15, // automatic reset when numerical issues are detected + mjDSBL_AUTORESET = 1<<15, // automatic reset when numerical issues are detected mjNDISABLE = 16 // number of disable flags } mjtDisableBit; diff --git a/include/mujoco/mjmodel.h b/include/mujoco/mjmodel.h index 73697a66..5f3fe4bd 100644 --- a/include/mujoco/mjmodel.h +++ b/include/mujoco/mjmodel.h @@ -61,7 +61,7 @@ typedef enum mjtDisableBit_ { // disable default feature bitflags mjDSBL_SENSOR = 1<<12, // sensors mjDSBL_MIDPHASE = 1<<13, // mid-phase collision filtering mjDSBL_EULERDAMP = 1<<14, // implicit integration of joint damping in Euler integrator - mjDSBL_AUTORESETNAN = 1<<15, // automatic reset when numerical issues are detected + mjDSBL_AUTORESET = 1<<15, // automatic reset when numerical issues are detected mjNDISABLE = 16 // number of disable flags } mjtDisableBit; diff --git a/introspect/enums.py b/introspect/enums.py index 52bf4c6a..f040505c 100644 --- a/introspect/enums.py +++ b/introspect/enums.py @@ -42,7 +42,7 @@ ENUMS: Mapping[str, EnumDecl] = dict([ ('mjDSBL_SENSOR', 4096), ('mjDSBL_MIDPHASE', 8192), ('mjDSBL_EULERDAMP', 16384), - ('mjDSBL_AUTORESETNAN', 32768), + ('mjDSBL_AUTORESET', 32768), ('mjNDISABLE', 16), ]), )), diff --git a/simulate/main.cc b/simulate/main.cc index 17c3ff5e..15316383 100644 --- a/simulate/main.cc +++ b/simulate/main.cc @@ -199,6 +199,16 @@ void scanPluginLibraries() { //------------------------------------------- simulation ------------------------------------------- +const char* Diverged(int disableflags, const mjData* d) { + if (disableflags & mjDSBL_AUTORESET) { + for (mjtWarning w : {mjWARN_BADQACC, mjWARN_BADQVEL, mjWARN_BADQPOS}) { + if (d->warning[w].number > 0) { + return mju_warningText(w, d->warning[w].lastinfo); + } + } + } + return nullptr; +} mjModel* LoadModel(const char* file, mj::Simulate& sim) { // this copy is needed so that the mju::strlen call below compiles @@ -356,7 +366,13 @@ void PhysicsLoop(mj::Simulate& sim) { // run single step, let next iteration deal with timing mj_step(m, d); - stepped = true; + const char* message = Diverged(m->opt.disableflags, d); + if (message) { + sim.run = 0; + mju::strcpy_arr(sim.load_error, message); + } else { + stepped = true; + } } // in-sync: step until ahead of cpu @@ -381,7 +397,13 @@ void PhysicsLoop(mj::Simulate& sim) { // call mj_step mj_step(m, d); - stepped = true; + const char* message = Diverged(m->opt.disableflags, d); + if (message) { + sim.run = 0; + mju::strcpy_arr(sim.load_error, message); + } else { + stepped = true; + } // break if reset if (d->time < prevSim) { diff --git a/simulate/simulate.cc b/simulate/simulate.cc index 9fe5ae7c..d676129b 100644 --- a/simulate/simulate.cc +++ b/simulate/simulate.cc @@ -739,18 +739,12 @@ void MakePhysicsSection(mj::Simulate* sim) { for (int i=0; idisable + i; - if ((1 << i) == mjDSBL_AUTORESETNAN) { - defFlag[0].state = 0; - } else { - defFlag[0].state = 2; - } mjui_add(&sim->ui0, defFlag); } mjui_add(&sim->ui0, defEnableFlags); for (int i=0; ienable + i; - defFlag[0].state = 2; mjui_add(&sim->ui0, defFlag); } // add contact override @@ -1956,6 +1950,7 @@ void Simulate::Sync() { if (pending_.reset) { mj_resetData(m_, d_); mj_forward(m_, d_); + load_error[0] = '\0'; update_profiler = true; update_sensor = true; scrub_index = 0; diff --git a/src/engine/engine_forward.c b/src/engine/engine_forward.c index 6c78663e..cb326594 100644 --- a/src/engine/engine_forward.c +++ b/src/engine/engine_forward.c @@ -52,7 +52,7 @@ void mj_checkPos(const mjModel* m, mjData* d) { for (int i=0; i < m->nq; i++) { if (mju_isBad(d->qpos[i])) { mj_warning(d, mjWARN_BADQPOS, i); - if (!(m->opt.disableflags & mjDSBL_AUTORESETNAN)) { + if (!mjDISABLED(mjDSBL_AUTORESET)) { mj_resetData(m, d); } d->warning[mjWARN_BADQPOS].number++; @@ -69,7 +69,7 @@ void mj_checkVel(const mjModel* m, mjData* d) { for (int i=0; i < m->nv; i++) { if (mju_isBad(d->qvel[i])) { mj_warning(d, mjWARN_BADQVEL, i); - if (!(m->opt.disableflags & mjDSBL_AUTORESETNAN)) { + if (!mjDISABLED(mjDSBL_AUTORESET)) { mj_resetData(m, d); } d->warning[mjWARN_BADQVEL].number++; @@ -86,12 +86,12 @@ void mj_checkAcc(const mjModel* m, mjData* d) { for (int i=0; i < m->nv; i++) { if (mju_isBad(d->qacc[i])) { mj_warning(d, mjWARN_BADQACC, i); - if (!(m->opt.disableflags & mjDSBL_AUTORESETNAN)) { + if (!mjDISABLED(mjDSBL_AUTORESET)) { mj_resetData(m, d); } d->warning[mjWARN_BADQACC].number++; d->warning[mjWARN_BADQACC].lastinfo = i; - if (!(m->opt.disableflags & mjDSBL_AUTORESETNAN)) { + if (!mjDISABLED(mjDSBL_AUTORESET)) { mj_forward(m, d); } return; diff --git a/src/engine/engine_support.c b/src/engine/engine_support.c index b0e86887..a3f269c0 100644 --- a/src/engine/engine_support.c +++ b/src/engine/engine_support.c @@ -58,7 +58,7 @@ const char* mjDISABLESTRING[mjNDISABLE] = { "Sensor", "Midphase", "Eulerdamp", - "AutoResetNaN" + "AutoReset" }; diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index 4e16d79b..46b13c4f 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -115,9 +115,9 @@ const char* MJCF[nMJCF][mjXATTRNUM] = { "solver", "iterations", "ls_iterations", "noslip_iterations", "mpr_iterations", "sdf_iterations", "sdf_initpoints", "actuatorgroupdisable"}, {"<"}, - {"flag", "?", "21", "constraint", "equality", "frictionloss", "limit", "contact", + {"flag", "?", "22", "constraint", "equality", "frictionloss", "limit", "contact", "passive", "gravity", "clampctrl", "warmstart", - "filterparent", "actuation", "refsafe", "sensor", "midphase", "eulerdamp", + "filterparent", "actuation", "refsafe", "sensor", "midphase", "eulerdamp", "autoreset", "override", "energy", "fwdinv", "invdiscrete", "multiccd", "island"}, {">"}, @@ -1122,6 +1122,7 @@ void mjXReader::Option(XMLElement* section, mjOption* opt) { READDSBL("sensor", mjDSBL_SENSOR) READDSBL("midphase", mjDSBL_MIDPHASE) READDSBL("eulerdamp", mjDSBL_EULERDAMP) + READDSBL("autoreset", mjDSBL_AUTORESET) #undef READDSBL #define READENBL(NAME, MASK) \ diff --git a/src/xml/xml_native_writer.cc b/src/xml/xml_native_writer.cc index 5798ef7e..ceb5d836 100644 --- a/src/xml/xml_native_writer.cc +++ b/src/xml/xml_native_writer.cc @@ -1001,6 +1001,7 @@ void mjXWriter::Option(XMLElement* root) { WRITEDSBL("sensor", mjDSBL_SENSOR) WRITEDSBL("midphase", mjDSBL_MIDPHASE) WRITEDSBL("eulerdamp", mjDSBL_EULERDAMP) + WRITEDSBL("autoreset", mjDSBL_AUTORESET) #undef WRITEDSBL #define WRITEENBL(NAME, MASK) \ diff --git a/unity/Runtime/Bindings/MjBindings.cs b/unity/Runtime/Bindings/MjBindings.cs index 46f89ab6..b5563b2e 100644 --- a/unity/Runtime/Bindings/MjBindings.cs +++ b/unity/Runtime/Bindings/MjBindings.cs @@ -157,7 +157,7 @@ public enum mjtDisableBit : int{ mjDSBL_SENSOR = 4096, mjDSBL_MIDPHASE = 8192, mjDSBL_EULERDAMP = 16384, - mjDSBL_AUTORESETNAN = 32768, + mjDSBL_AUTORESET = 32768, mjNDISABLE = 16, } public enum mjtEnableBit : int{