diff --git a/doc/XMLreference.rst b/doc/XMLreference.rst index c901e7e9..bc3168d9 100644 --- a/doc/XMLreference.rst +++ b/doc/XMLreference.rst @@ -3943,7 +3943,7 @@ bodies whose center of mass is of interest. The type of output generated by this sensor. "axis" means a unit-length 3D vector. "quat" means a unit quaternion. These need to be declared because when MuJoCo adds noise, it must respect the vector normalization. "real" means a generic array (or scalar) of real values to which noise can be added independently. -:at:`needstage`: :at-val:`[pos, vel, acc], required` +:at:`needstage`: :at-val:`[pos, vel, acc], "acc"` The MuJoCo computation stage that must be completed before the user callback mjcb_sensor() is able to evaluate the output of this sensor. :at:`dim`: :at-val:`int, required` diff --git a/doc/changelog.rst b/doc/changelog.rst index 1fe612a6..9977024e 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -69,8 +69,9 @@ General register one or more MuJoCo plugins on load. - Add an optional ``visualize`` callback to plugins, which is called during ``mjv_updateScene``. This callback allows custom plugin visualizations. Enable stree visualization for the Cable plugin as an example. -- Sensors of type :ref:`user` no longer require :at:`objtype` and :at:`objname`. If unspecified, the - objtype will be :ref:`mjOBJ_UNKNOWN`. ``user`` sensors :at:`datatype` default is now :at-val:`"real"`. +- Sensors of type :ref:`user` no longer require :at:`objtype`, :at:`objname` and :at:`needstage`. If + unspecified, the objtype is now :ref:`mjOBJ_UNKNOWN`. ``user`` sensors :at:`datatype` default is now + :at-val:`"real"`, :at:`needstage` default is now :at-val:`"acc"`. - Add support for capsules in URDF import. - On macOS, issue an informative error message when run under `Rosetta 2 `_ translation on an Apple Silicon machine. Pre-built MuJoCo binaries make use of diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index 3576856e..120fbda7 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -3159,8 +3159,9 @@ void mjXReader::Sensor(XMLElement* section) { ReadAttrInt(elem, "dim", &psen->dim, true); // keywords - MapValue(elem, "needstage", &n, stage_map, stage_sz, true); - psen->needstage = (mjtStage)n; + if (MapValue(elem, "needstage", &n, stage_map, stage_sz)) { + psen->needstage = (mjtStage)n; + } if (MapValue(elem, "datatype", &n, datatype_map, datatype_sz)) { psen->datatype = (mjtDataType)n; } diff --git a/test/xml/xml_native_reader_test.cc b/test/xml/xml_native_reader_test.cc index 1365bd35..e4a9397c 100644 --- a/test/xml/xml_native_reader_test.cc +++ b/test/xml/xml_native_reader_test.cc @@ -967,6 +967,25 @@ TEST_F(SensorParseTest, UserObjNameNoType) { EXPECT_THAT(error.data(), HasSubstr("objname 'kevin' given but")); } +TEST_F(SensorParseTest, UserNeedstageAcc) { + static constexpr char xml[] = R"( + + + + + + + + )"; + std::array error; + mjModel* model = LoadModelFromString(xml, error.data(), error.size()); + ASSERT_THAT(model, NotNull()) << error.data(); + EXPECT_EQ(model->sensor_needstage[0], mjSTAGE_VEL); + EXPECT_EQ(model->sensor_needstage[1], mjSTAGE_ACC); + EXPECT_EQ(model->sensor_needstage[2], mjSTAGE_POS); + mj_deleteModel(model); +} + // ------------- test general parsing ------------------------------------------ TEST_F(XMLReaderTest, ZnearZeroNotAllowed) {