Automatically infer *limited field from *range field for joints, tendons and actuators.
PiperOrigin-RevId: 467980594 Change-Id: If635c55a90cf949796b99a41395a6c2c4f7ea094
This commit is contained in:
committed by
Copybara-Service
parent
29535a8eca
commit
4bfc2c0311
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
<mujoco>
|
||||
<default>
|
||||
<default class="limited_false">
|
||||
<joint limited="false"/>
|
||||
</default>
|
||||
<default class="limited_true">
|
||||
<joint limited="true"/>
|
||||
<default class="limited_auto">
|
||||
<joint limited="auto"/>
|
||||
</default>
|
||||
</default>
|
||||
<default class="range_defined">
|
||||
<joint range="-1.57 1.57"/>
|
||||
</default>
|
||||
</default>
|
||||
<!--
|
||||
`user` attributes of the joints below indicate the expected state of the associated
|
||||
jnt_limited property in the compiled model.
|
||||
-->
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint user="0"/>
|
||||
<joint user="1" range="0 1"/>
|
||||
<joint user="0" range="0 1" limited="false"/>
|
||||
<joint user="1" range="0 1" limited="true"/>
|
||||
<joint user="0" range="0 1" class="limited_false"/>
|
||||
<joint user="1" range="0 1" class="limited_true"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
<!-- adding another body since bodies are allowed a maximum of 6 DoFs -->
|
||||
<body>
|
||||
<joint user="1" range="0 1" class="limited_false" limited="true"/>
|
||||
<joint user="0" range="0 1" class="limited_true" limited="false"/>
|
||||
<joint user="1" class="range_defined"/>
|
||||
<joint user="1" range="0 1" class="limited_auto"/>
|
||||
<joint user="1" range="0 1" limited="auto"/>
|
||||
<joint user="0" limited="auto"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
<body>
|
||||
<!-- free joints should remain unlimited even if a (meaningless) range is defined -->
|
||||
<joint user="0" type="free" class="range_defined"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
@@ -39,7 +39,7 @@ using ::testing::NotNull;
|
||||
|
||||
// ------------------------ test keyframes -------------------------------------
|
||||
|
||||
static const char* const kKeyframePath = "user/testdata/keyframe.xml";
|
||||
constexpr char kKeyframePath[] = "user/testdata/keyframe.xml";
|
||||
|
||||
TEST_F(MujocoTest, KeyFrameTest) {
|
||||
const std::string xml_path = GetTestDataFilePath(kKeyframePath);
|
||||
@@ -567,5 +567,25 @@ TEST_F(UserDataTest, NSensorTooSmall) {
|
||||
EXPECT_THAT(error.data(), HasSubstr("nuser_sensor"));
|
||||
}
|
||||
|
||||
// ------------- test for auto parsing of *limited fields -------------
|
||||
|
||||
using LimitedTest = MujocoTest;
|
||||
|
||||
constexpr char kKeyAutoLimits[] = "user/testdata/auto_limits.xml";
|
||||
|
||||
// check joint limit values when automatically inferred based on range
|
||||
TEST_F(LimitedTest, JointLimited) {
|
||||
const std::string xml_path = GetTestDataFilePath(kKeyAutoLimits);
|
||||
mjModel* model = mj_loadXML(xml_path.c_str(), nullptr, nullptr, 0);
|
||||
ASSERT_THAT(model, NotNull());
|
||||
|
||||
// see `user/testdata/auto_limits.xml` for expected values
|
||||
for (int i=0; i < model->njnt; i++) {
|
||||
EXPECT_EQ(model->jnt_limited[i], (mjtByte)model->jnt_user[i]);
|
||||
}
|
||||
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mujoco
|
||||
|
||||
@@ -127,7 +127,164 @@ TEST_F(XMLWriterTest, DropsInertialIfFromGeom) {
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, KeepsActlimited) {
|
||||
TEST_F(XMLWriterTest, DoesNotKeepInferredJointLimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler angle="radian"/>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge" range="-1 1"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("range=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("limited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, DoesNotKeepExplicitJointLimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler angle="radian"/>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge" limited="true" range="-1 1"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("range=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("limited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, KeepsJointLimitedFalse) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler angle="radian"/>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge" limited="false" range="-1 1"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("limited=\"false\" range=\"-1 1\""));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, DoesNotKeepInferredTendonLimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler angle="radian"/>
|
||||
<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>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("range=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("limited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, DoesNotKeepExplicitTendonLimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler angle="radian"/>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint type="slide"/>
|
||||
<geom size="1"/>
|
||||
<site name="s1"/>
|
||||
</body>
|
||||
<site name="s2"/>
|
||||
</worldbody>
|
||||
<tendon>
|
||||
<spatial limited="true" range="-1 1">
|
||||
<site site="s1"/>
|
||||
<site site="s2"/>
|
||||
</spatial>
|
||||
</tendon>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("range=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("limited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, KeepsTendonLimitedFalse) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler angle="radian"/>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint type="slide"/>
|
||||
<geom size="1"/>
|
||||
<site name="s1"/>
|
||||
</body>
|
||||
<site name="s2"/>
|
||||
</worldbody>
|
||||
<tendon>
|
||||
<spatial limited="false" range="-1 1">
|
||||
<site site="s1"/>
|
||||
<site site="s2"/>
|
||||
</spatial>
|
||||
</tendon>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("limited=\"false\" range=\"-1 1\""));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, DoesNotKeepInferredActlimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
<actuator>
|
||||
<general dyntype="filter" joint="hinge" actrange="-1 1"/>
|
||||
</actuator>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("actrange=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("actlimited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, DoesNotKeepExplicitActlimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
@@ -143,7 +300,152 @@ TEST_F(XMLWriterTest, KeepsActlimited) {
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("actlimited=\"true\" actrange=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, HasSubstr("actrange=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("actlimited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, KeepsActlimitedFalse) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
<actuator>
|
||||
<general dyntype="filter" joint="hinge" actlimited="false" actrange="-1 1"/>
|
||||
</actuator>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("actlimited=\"false\" actrange=\"-1 1\""));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, DoesNotKeepInferredCtrllimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
<actuator>
|
||||
<general joint="hinge" ctrlrange="-1 1"/>
|
||||
</actuator>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("ctrlrange=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("ctrllimited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, DoesNotKeepExplicitCtrllimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
<actuator>
|
||||
<general joint="hinge" ctrllimited="true" ctrlrange="-1 1"/>
|
||||
</actuator>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("ctrlrange=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("ctrllimited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, KeepsCtrllimitedFalse) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
<actuator>
|
||||
<general joint="hinge" ctrllimited="false" ctrlrange="-1 1"/>
|
||||
</actuator>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("ctrllimited=\"false\" ctrlrange=\"-1 1\""));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, DoesNotKeepInferredForcelimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
<actuator>
|
||||
<general joint="hinge" forcerange="-1 1"/>
|
||||
</actuator>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("forcerange=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("forcelimited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, DoesNotKeepExplicitForcelimited) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
<actuator>
|
||||
<general joint="hinge" forcelimited="true" forcerange="-1 1"/>
|
||||
</actuator>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("forcerange=\"-1 1\""));
|
||||
EXPECT_THAT(saved_xml, Not(HasSubstr("forcelimited=\"true\"")));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLWriterTest, KeepsForcelimitedFalse) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<body>
|
||||
<joint name="hinge"/>
|
||||
<geom size="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
<actuator>
|
||||
<general joint="hinge" forcelimited="false" forcerange="-1 1"/>
|
||||
</actuator>
|
||||
</mujoco>
|
||||
)";
|
||||
mjModel* model = LoadModelFromString(xml);
|
||||
std::string saved_xml = SaveAndReadXml(model);
|
||||
EXPECT_THAT(saved_xml, HasSubstr("forcelimited=\"false\" forcerange=\"-1 1\""));
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user