Don't infer limited attributes automatically by default.
This is an amendment to 4bfc2c0311.
Add an autolimits compiler option. When true, *limited will be inferred from the presence of the *range attributes.
When false, models where limited is not specified, and range is will fail to compile.
PiperOrigin-RevId: 472438650
Change-Id: I489098e879ee695030f44e0d8cd969787e75fb90
This commit is contained in:
committed by
Copybara-Service
parent
0784a46f62
commit
a693a2d981
+33
-12
@@ -47,6 +47,8 @@ in the second column of the table have the following meaning:
|
||||
| | | +-------------------------+-------------------------+-------------------------+ |
|
||||
| | | | :at:`inertiafromgeom` | :at:`inertiagrouprange` | :at:`exactmeshinertia` | |
|
||||
| | | +-------------------------+-------------------------+-------------------------+ |
|
||||
| | | | :at:`autolimits` | | | |
|
||||
| | | +-------------------------+-------------------------+-------------------------+ |
|
||||
+--------------------------+----+------------------------------------------------------------------------------------+
|
||||
| |_2|:el:`lengthrange` | ? | .. table:: |
|
||||
| | | :class: mjcf-attributes |
|
||||
@@ -1524,6 +1526,13 @@ The unique top-level element, identifying the XML file as an MJCF model file.
|
||||
This element is used to set options for the built-in parser and compiler. After parsing and compilation it no longer has
|
||||
any effect. The settings here are global and apply to the entire model.
|
||||
|
||||
:at:`autolimits`: :at-val:`[false, true], "false"`
|
||||
This attribute affects the behavior of attributes such as "limited" (on <joint> or <tendon>), "forcelimited",
|
||||
"ctrllimited", and "actlimited" (on <actuator>). If "true", these attributes are unnecessary and their value
|
||||
will be inferred from the presence of their corresponding "range" attribute.
|
||||
If "false", no such inference will happen: For a joint to be limited, both limited="true" and range="min max" must
|
||||
be specified. In this mode, it is an error to specify a range without a limit.
|
||||
|br| The default for this option will be set to "true" in an upcoming release.
|
||||
:at:`boundmass`: :at-val:`real, "0"`
|
||||
This attribute imposes a lower bound on the mass of each body except for the world body. Setting this attribute to
|
||||
a value greater than 0 can be used as a quick fix for poorly designed models that contain massless moving bodies,
|
||||
@@ -3162,7 +3171,8 @@ unit quaternions.
|
||||
:at:`limited`: :at-val:`[false, true, auto], "auto"`
|
||||
This attribute specifies if the joint has limits. It interacts with the range attribute below. If this attribute
|
||||
is "false", joint limits are disabled. If this attribute is "true", joint limits are enabled. If this
|
||||
attribute is "auto", joint limits will be enabled if range is defined and disabled otherwise.
|
||||
attribute is "auto", and :at:`autolimits` is set in :ref:`compiler <compiler>`, joint limits will be enabled
|
||||
if range is defined.
|
||||
:at:`solreflimit`, :at:`solimplimit`
|
||||
Constraint solver parameters for simulating joint limits. See :ref:`CSolver`.
|
||||
:at:`solreffriction`, :at:`solimpfriction`
|
||||
@@ -3176,6 +3186,8 @@ unit quaternions.
|
||||
joints, the limit is imposed on the angle of rotation (relative to the reference configuration) regardless of the
|
||||
axis of rotation. Only the second range parameter is used for ball joints; the first range parameter should be set to
|
||||
0. See the :ref:`Limit <coLimit>` section in the Computation chapter for more information.
|
||||
|br| Setting this attribute without specifying :at:`limited` is an error, unless :at:`autolimits` is set in
|
||||
:ref:`compiler <compiler>`.
|
||||
:at:`margin`: :at-val:`real, "0"`
|
||||
The distance threshold below which limits become active. Recall that the :ref:`Constraint solver <Solver>` normally
|
||||
generates forces as soon as a constraint becomes active, even if the margin parameter makes that happen at a
|
||||
@@ -4122,10 +4134,11 @@ the obstacle geom.
|
||||
visualizer to enable and disable the rendering of entire groups of tendons.
|
||||
:at:`limited`: :at-val:`[false, true, auto], "auto"`
|
||||
If this attribute is "true", the length limits defined by the range attribute below are imposed by the constraint
|
||||
solver. If this attribute is "auto", length limits will be enabled if range is defined and disabled otherwise.
|
||||
solver. If this attribute is "auto", and :at:`autolimits` is set in :ref:`compiler <compiler>`, length limits
|
||||
will be enabled if range is defined.
|
||||
:at:`range`: :at-val:`real(2), "0 0"`
|
||||
Range of allowed tendon lengths. To enable length limits, set the limited attribute to "true" in addition to defining
|
||||
the present value.
|
||||
Range of allowed tendon lengths. Setting this attribute without specifying :at:`limited` is an error, unless
|
||||
:at:`autolimits` is set in :ref:`compiler <compiler>`.
|
||||
:at:`solreflimit`, :at:`solimplimit`
|
||||
Constraint solver parameters for simulating tendon limits. See :ref:`CSolver`.
|
||||
:at:`solreffriction`, :at:`solimpfriction`
|
||||
@@ -4269,25 +4282,33 @@ specify them independently.
|
||||
visualizer to enable and disable the rendering of entire groups of actuators.
|
||||
:at:`ctrllimited`: :at-val:`[false, true, auto], "auto"`
|
||||
If true, the control input to this actuator is automatically clamped to :at:`ctrlrange` at runtime. If false, control
|
||||
input clamping is disabled. If auto, control clamping will automatically be set to true if :at:`ctrlrange` is
|
||||
defined without explicitly setting this attribute to "true". Note that control input clamping can also be globally
|
||||
disabled with the :at:`clampctrl` attribute of :ref:`option/flag <option-flag>`.
|
||||
input clamping is disabled. If "auto" and :at:`autolimits` is set in :ref:`compiler <compiler>`, control
|
||||
clamping will automatically be set to true if :at:`ctrlrange` is defined without explicitly setting this attribute
|
||||
to "true". Note that control input clamping can also be globally disabled with the :at:`clampctrl` attribute of
|
||||
:ref:`option/flag <option-flag>`.
|
||||
:at:`forcelimited`: :at-val:`[false, true, auto], "auto"`
|
||||
If true, the force output of this actuator is automatically clamped to :at:`forcerange` at runtime. If false, force
|
||||
clamping is disabled. If auto, force clamping will automatically be set to true if :at:`forcerange` is
|
||||
defined without explicitly setting this attribute to "true".
|
||||
clamping is disabled. If "auto" and :at:`autolimits` is set in :ref:`compiler <compiler>`, force clamping will
|
||||
automatically be set to true if :at:`forcerange` is defined without explicitly setting this attribute to "true".
|
||||
:at:`actlimited`: :at-val:`[false, true, auto], "auto"`
|
||||
If true, the internal state (activation) associated with this actuator is automatically clamped to :at:`actrange` at
|
||||
runtime. If false, activation clamping is disabled. If auto, activation clamping will automatically be set to true
|
||||
if :at:`actrange` is defined without explicitly setting this attribute to "true". See the :ref:`Activation clamping <CActRange>`
|
||||
section for more details.
|
||||
runtime. If false, activation clamping is disabled. If "auto" and :at:`autolimits` is set in
|
||||
:ref:`compiler <compiler>`, activation clamping will automatically be set to true if :at:`actrange` is defined
|
||||
without explicitly setting this attribute to "true". See the :ref:`Activation clamping <CActRange>` section for more
|
||||
details.
|
||||
:at:`ctrlrange`: :at-val:`real(2), "0 0"`
|
||||
Range for clamping the control input. The compiler expects the first value to be smaller than the second value.
|
||||
|br| Setting this attribute without specifying :at:`ctrllimited` is an error, unless :at:`autolimits` is set in
|
||||
:ref:`compiler <compiler>`.
|
||||
:at:`forcerange`: :at-val:`real(2), "0 0"`
|
||||
Range for clamping the force output. The compiler expects the first value to be no greater than the second value.
|
||||
|br| Setting this attribute without specifying :at:`forcelimited` is an error, unless :at:`autolimits` is set in
|
||||
:ref:`compiler <compiler>`.
|
||||
:at:`actrange`: :at-val:`real(2), "0 0"`
|
||||
Range for clamping the activation state. The compiler expects the first value to be no greater than the second value.
|
||||
See the :ref:`Activation clamping <CActRange>` section for more details.
|
||||
|br| Setting this attribute without specifying :at:`actlimited` is an error, unless :at:`autolimits` is set in
|
||||
:ref:`compiler <compiler>`.
|
||||
:at:`lengthrange`: :at-val:`real(2), "0 0"`
|
||||
Range of feasible lengths of the actuator's transmission. See :ref:`Length Range <CLengthRange>`.
|
||||
:at:`gear`: :at-val:`real(6), "1 0 0 0 0 0"`
|
||||
|
||||
+10
-5
@@ -31,13 +31,18 @@ General
|
||||
- Cartesian 6D end-effector control is now possible by adding a reference site to actuators with :at:`site`
|
||||
transmission. See description of new :at:`refsite` attribute in the :ref:`actuator<general>` documentation and
|
||||
`refsite.xml <https://github.com/deepmind/mujoco/tree/main/test/engine/testdata/refsite.xml>`_ example model.
|
||||
- Joint and tendon ``limited`` attribute and actuator ``ctrllimited``, ``forcelimited`` and ``actlimited`` attributes
|
||||
now default to ``auto`` rather than ``false``. Limits are automatically set to ``true`` if the corresponding range *is
|
||||
defined* and ``false`` otherwise.
|
||||
|
||||
- Added :at:`autolimits` compiler option. If ``true``, joint and tendon :at:`limited` attributes and actuator
|
||||
:at:`ctrllimited`, :at:`forcelimited` and :at:`actlimited` attributes will automatically be set to ``true`` if the
|
||||
corresponding range *is defined* and ``false`` otherwise.
|
||||
|
||||
If ``autolimits="false"`` (the default) models where a :at:`range` attribute is specified without the :at:`limited`
|
||||
attribute will fail to compile. A future release will change the default of :at:`autolimits` to ``true``, and this
|
||||
compilation error allows users to catch this future change of behavior.
|
||||
|
||||
.. attention::
|
||||
This is a minor breaking change. In models where a range was defined but :at:`limited` was unspecified, the target
|
||||
element will now be limited. Explicitly set limited to ``false`` to revert to the previous behavior.
|
||||
This is a breaking change. In models where a range was defined but :at:`limited` was unspecified, explicitly set
|
||||
limited to ``false`` or remove the range to maintain the current behavior of your model.
|
||||
|
||||
- Added moment of inertia computation for all well-formed meshes. This option is activated by setting the compiler
|
||||
flag :at:`exactmeshinertia` to ``true`` (defaults to ``false``). This default may change in the future.
|
||||
|
||||
@@ -79,6 +79,8 @@ mjCModel::mjCModel() {
|
||||
modelfiledir.clear();
|
||||
|
||||
//------------------------ compiler settings
|
||||
// TODO(b/245077553): Toggle to true by default.
|
||||
autolimits = false;
|
||||
boundmass = 0;
|
||||
boundinertia = 0;
|
||||
settotalmass = -1;
|
||||
|
||||
@@ -107,6 +107,7 @@ class mjCModel {
|
||||
std::vector<mjCDef*> defaults; // settings for each defaults class
|
||||
|
||||
//------------------------ compiler settings
|
||||
bool autolimits; // infer "limited" attribute based on range
|
||||
double boundmass; // enfore minimum body mass
|
||||
double boundinertia; // enfore minimum body diagonal inertia
|
||||
double settotalmass; // rescale masses and inertias; <=0: ignore
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -62,6 +63,18 @@ static void checksize(double* size, mjtGeom type, mjCBase* object, const char* n
|
||||
}
|
||||
}
|
||||
|
||||
// error message for missing "limited" attribute
|
||||
static void checklimited(
|
||||
const mjCBase* obj,
|
||||
bool autolimits, const char* entity, const char* attr, int limited, bool hasrange) {
|
||||
if (!autolimits && limited == 2 && hasrange) {
|
||||
std::stringstream ss;
|
||||
ss << entity << " has `" << attr << "range` but not `" << attr << "limited`. "
|
||||
<< "set the autolimits=\"true\" compiler option, specify `" << attr << "limited` "
|
||||
<< "explicitly (\"true\" or \"false\"), or remove the `" << attr << "range` attribute.";
|
||||
throw mjCError(obj, "%s", ss.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------- class mjCError implementation ------------------------------------------
|
||||
@@ -857,7 +870,9 @@ int mjCJoint::Compile(void) {
|
||||
}
|
||||
// otherwise if limited is auto, set according to whether range is specified
|
||||
else if (limited==2) {
|
||||
limited = (range[0]==0 && range[1]==0) ? 0 : 1;
|
||||
bool hasrange = !(range[0]==0 && range[1]==0);
|
||||
checklimited(this, model->autolimits, "joint", "", limited, hasrange);
|
||||
limited = hasrange ? 1 : 0;
|
||||
}
|
||||
|
||||
// resolve limits
|
||||
@@ -3222,7 +3237,9 @@ void mjCTendon::Compile(void) {
|
||||
|
||||
// if limited is auto, set to 1 if range is specified, otherwise unlimited
|
||||
if (limited==2) {
|
||||
limited = (range[0]==0 && range[1]==0) ? 0 : 1;
|
||||
bool hasrange = !(range[0]==0 && range[1]==0);
|
||||
checklimited(this, model->autolimits, "tendon", "", limited, hasrange);
|
||||
limited = hasrange ? 1 : 0;
|
||||
}
|
||||
|
||||
// check limits
|
||||
@@ -3389,13 +3406,19 @@ void mjCActuator::Compile(void) {
|
||||
|
||||
// if limited is auto, set to 1 if range is specified, otherwise unlimited
|
||||
if (forcelimited==2) {
|
||||
forcelimited = (forcerange[0]==0 && forcerange[1]==0) ? 0 : 1;
|
||||
bool hasrange = !(forcerange[0]==0 && forcerange[1]==0);
|
||||
checklimited(this, model->autolimits, "actuator", "force", forcelimited, hasrange);
|
||||
forcelimited = hasrange ? 1 : 0;
|
||||
}
|
||||
if (ctrllimited==2) {
|
||||
ctrllimited = (ctrlrange[0]==0 && ctrlrange[1]==0) ? 0 : 1;
|
||||
bool hasrange = !(ctrlrange[0]==0 && ctrlrange[1]==0);
|
||||
checklimited(this, model->autolimits, "actuator", "ctrl", ctrllimited, hasrange);
|
||||
ctrllimited = hasrange ? 1 : 0;
|
||||
}
|
||||
if (actlimited==2) {
|
||||
actlimited = (actrange[0]==0 && actrange[1]==0) ? 0 : 1;
|
||||
bool hasrange = !(actrange[0]==0 && actrange[1]==0);
|
||||
checklimited(this, model->autolimits, "actuator", "act", actlimited, hasrange);
|
||||
actlimited = hasrange ? 1 : 0;
|
||||
}
|
||||
|
||||
// check limits
|
||||
|
||||
@@ -46,8 +46,8 @@ static const int nMJCF = 165;
|
||||
static const char* MJCF[nMJCF][mjXATTRNUM] = {
|
||||
{"mujoco", "!", "1", "model"},
|
||||
{"<"},
|
||||
{"compiler", "*", "18", "boundmass", "boundinertia", "settotalmass", "balanceinertia",
|
||||
"strippath", "coordinate", "angle", "fitaabb", "eulerseq",
|
||||
{"compiler", "*", "19", "autolimits", "boundmass", "boundinertia", "settotalmass",
|
||||
"balanceinertia", "strippath", "coordinate", "angle", "fitaabb", "eulerseq",
|
||||
"meshdir", "texturedir", "discardvisual", "convexhull", "usethread",
|
||||
"fusestatic", "inertiafromgeom", "inertiagrouprange", "exactmeshinertia"},
|
||||
{"<"},
|
||||
@@ -765,6 +765,9 @@ void mjXReader::Compiler(XMLElement* section, mjCModel* mod) {
|
||||
int n;
|
||||
|
||||
// top-level attributes
|
||||
if (MapValue(section, "autolimits", &n, bool_map, 2)) {
|
||||
mod->autolimits = (n==1);
|
||||
}
|
||||
ReadAttr(section, "boundmass", 1, &mod->boundmass, text);
|
||||
ReadAttr(section, "boundinertia", 1, &mod->boundinertia, text);
|
||||
ReadAttr(section, "settotalmass", 1, &mod->settotalmass, text);
|
||||
|
||||
@@ -696,6 +696,9 @@ void mjXWriter::Compiler(XMLElement* root) {
|
||||
if (model->exactmeshinertia) {
|
||||
WriteAttrTxt(section, "exactmeshinertia", "true");
|
||||
}
|
||||
// always enable autolimits. limited attributes will be written appropriately
|
||||
// TODO(b/245077553): Remove this when the default is true.
|
||||
WriteAttrTxt(section, "autolimits", "true");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -206,6 +206,7 @@ TEST_F(CoreSmoothTest, RefsiteBringsToPose) {
|
||||
constexpr char kRefsitePath[] = "engine/testdata/refsite.xml";
|
||||
const std::string xml_path = GetTestDataFilePath(kRefsitePath);
|
||||
mjModel* model = mj_loadXML(xml_path.c_str(), nullptr, 0, 0);
|
||||
ASSERT_THAT(model, ::testing::NotNull());
|
||||
mjData* data = mj_makeData(model);
|
||||
|
||||
// set pose target in ctrl (3 positions, 3 rotations)
|
||||
|
||||
Vendored
+1
@@ -1,4 +1,5 @@
|
||||
<mujoco>
|
||||
<compiler autolimits="true"/>
|
||||
<option density="1000"/>
|
||||
|
||||
<worldbody>
|
||||
|
||||
Vendored
+1
@@ -1,4 +1,5 @@
|
||||
<mujoco>
|
||||
<compiler autolimits="true" />
|
||||
<worldbody>
|
||||
<geom type="plane" size="1 1 .01"/>
|
||||
<light pos="0 0 2"/>
|
||||
|
||||
Vendored
+1
@@ -1,4 +1,5 @@
|
||||
<mujoco>
|
||||
<compiler autolimits="true"/>
|
||||
<!--
|
||||
Adding a high fluid viscosity and using implicit integration for extra stabillity.
|
||||
Extra stabillity is required because the abstract "arm" model is not very realistic.
|
||||
|
||||
Vendored
+1
@@ -1,4 +1,5 @@
|
||||
<mujoco>
|
||||
<compiler autolimits="true" />
|
||||
<default>
|
||||
<default class="limited_false">
|
||||
<joint limited="false"/>
|
||||
|
||||
@@ -604,5 +604,97 @@ TEST_F(LimitedTest, JointLimited) {
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(LimitedTest, ErrorIfLimitedMissingOnJoint) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler autolimits="false"/>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint user="1" range="0 1"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model, IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("limited"));
|
||||
}
|
||||
|
||||
TEST_F(LimitedTest, ExplicitLimitedFalseIsOk) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler autolimits="false"/>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint user="1" limited="false" range="0 1"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model, NotNull()) << error.data();
|
||||
|
||||
EXPECT_EQ(model->jnt_limited[0], 0);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(LimitedTest, ErrorIfLimitedMissingOnTendon) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler autolimits="false"/>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint type="slide"/>
|
||||
<geom size="1"/>
|
||||
<site name="s1"/>
|
||||
</body>
|
||||
<site name="s2"/>
|
||||
</worldbody>
|
||||
<tendon>
|
||||
<spatial range="-1 1">
|
||||
<site site="s1"/>
|
||||
<site site="s2"/>
|
||||
</spatial>
|
||||
</tendon>
|
||||
</mujoco>
|
||||
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model, IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("limited"));
|
||||
EXPECT_THAT(error.data(), HasSubstr("tendon"));
|
||||
}
|
||||
|
||||
TEST_F(LimitedTest, ErrorIfForceLimitedMissingOnActuator) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler autolimits="false"/>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint type="slide" name="J1"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
<actuator>
|
||||
<position joint="J1" forcerange="0 100"/>
|
||||
</actuator>
|
||||
</mujoco>
|
||||
|
||||
)";
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||
ASSERT_THAT(model, IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("forcelimited"));
|
||||
EXPECT_THAT(error.data(), HasSubstr("forcerange"));
|
||||
EXPECT_THAT(error.data(), HasSubstr("actuator"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mujoco
|
||||
|
||||
@@ -316,6 +316,7 @@ TEST_F(UserDataTest, ReadShellParameter) {
|
||||
TEST_F(UserDataTest, ReadsDamper) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler autolimits="true"/>
|
||||
<worldbody>
|
||||
<body>
|
||||
<geom size="1"/>
|
||||
|
||||
@@ -144,7 +144,7 @@ TEST_F(XMLWriterTest, DropsInertialIfFromGeom) {
|
||||
TEST_F(XMLWriterTest, DoesNotKeepInferredJointLimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler angle="radian"/>
|
||||
<compiler angle="radian" autolimits="true" />
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge" range="-1 1"/>
|
||||
@@ -160,10 +160,10 @@ TEST_F(XMLWriterTest, DoesNotKeepInferredJointLimited) {
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, DoesNotKeepExplicitJointLimited) {
|
||||
TEST_F(XMLWriterTest, DoesNotKeepExplicitJointLimitedIfAutoLimits) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler angle="radian"/>
|
||||
<compiler angle="radian" autolimits="true" />
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge" limited="true" range="-1 1"/>
|
||||
@@ -174,15 +174,16 @@ TEST_F(XMLWriterTest, DoesNotKeepExplicitJointLimited) {
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("autolimits=\"true\""));
|
||||
EXPECT_THAT(saved_xml, HasSubstr("range=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("limited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, KeepsJointLimitedFalse) {
|
||||
TEST_F(XMLWriterTest, KeepsJointLimitedFalseIfAutoLimits) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler angle="radian"/>
|
||||
<compiler angle="radian" autolimits="true" />
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge" limited="false" range="-1 1"/>
|
||||
@@ -200,7 +201,7 @@ TEST_F(XMLWriterTest, KeepsJointLimitedFalse) {
|
||||
TEST_F(XMLWriterTest, DoesNotKeepInferredTendonLimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler angle="radian"/>
|
||||
<compiler angle="radian" autolimits="true" />
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint type="slide"/>
|
||||
@@ -219,15 +220,16 @@ TEST_F(XMLWriterTest, DoesNotKeepInferredTendonLimited) {
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("autolimits=\"true\""));
|
||||
EXPECT_THAT(saved_xml, HasSubstr("range=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("limited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, DoesNotKeepExplicitTendonLimited) {
|
||||
TEST_F(XMLWriterTest, DoesNotKeepExplicitTendonLimitedIfAutoLimits) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler angle="radian"/>
|
||||
<compiler angle="radian" autolimits="true" />
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint type="slide"/>
|
||||
@@ -246,15 +248,16 @@ TEST_F(XMLWriterTest, DoesNotKeepExplicitTendonLimited) {
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("autolimits=\"true\""));
|
||||
EXPECT_THAT(saved_xml, HasSubstr("range=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("limited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, KeepsTendonLimitedFalse) {
|
||||
TEST_F(XMLWriterTest, KeepsTendonLimitedFalseIfAutoLimits) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler angle="radian"/>
|
||||
<compiler angle="radian" autolimits="true" />
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint type="slide"/>
|
||||
@@ -280,6 +283,7 @@ TEST_F(XMLWriterTest, KeepsTendonLimitedFalse) {
|
||||
TEST_F(XMLWriterTest, DoesNotKeepInferredActlimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler autolimits="true" />
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
@@ -293,14 +297,16 @@ TEST_F(XMLWriterTest, DoesNotKeepInferredActlimited) {
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("autolimits=\"true\""));
|
||||
EXPECT_THAT(saved_xml, HasSubstr("actrange=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("actlimited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, DoesNotKeepExplicitActlimited) {
|
||||
TEST_F(XMLWriterTest, DoesNotKeepExplicitActlimitedIfAutoLimits) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler autolimits="true" />
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
@@ -314,6 +320,7 @@ TEST_F(XMLWriterTest, DoesNotKeepExplicitActlimited) {
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("autolimits=\"true\""));
|
||||
EXPECT_THAT(saved_xml, HasSubstr("actrange=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("actlimited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
@@ -322,6 +329,7 @@ TEST_F(XMLWriterTest, DoesNotKeepExplicitActlimited) {
|
||||
TEST_F(XMLWriterTest, KeepsActlimitedFalse) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler autolimits="true" />
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
@@ -342,6 +350,7 @@ TEST_F(XMLWriterTest, KeepsActlimitedFalse) {
|
||||
TEST_F(XMLWriterTest, DoesNotKeepInferredCtrllimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler autolimits="true" />
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
@@ -360,9 +369,10 @@ TEST_F(XMLWriterTest, DoesNotKeepInferredCtrllimited) {
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, DoesNotKeepExplicitCtrllimited) {
|
||||
TEST_F(XMLWriterTest, DoesNotKeepExplicitCtrllimitedIfAutoLimits) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler autolimits="true" />
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
@@ -404,6 +414,7 @@ TEST_F(XMLWriterTest, KeepsCtrllimitedFalse) {
|
||||
TEST_F(XMLWriterTest, DoesNotKeepInferredForcelimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler autolimits="true" />
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
@@ -417,6 +428,7 @@ TEST_F(XMLWriterTest, DoesNotKeepInferredForcelimited) {
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("autolimits=\"true\""));
|
||||
EXPECT_THAT(saved_xml, HasSubstr("forcerange=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("forcelimited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
@@ -438,6 +450,7 @@ TEST_F(XMLWriterTest, DoesNotKeepExplicitForcelimited) {
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("autolimits=\"true\""));
|
||||
EXPECT_THAT(saved_xml, HasSubstr("forcerange=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("forcelimited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
|
||||
Reference in New Issue
Block a user