Add kv damping attribute to position and intvelocity actuator shortcuts.

PiperOrigin-RevId: 588377097
Change-Id: I8ded2ff982e52ed8673019979e29b706ef65c743
This commit is contained in:
Yuval Tassa
2023-12-06 04:27:34 -08:00
committed by Copybara-Service
parent b3ccf67ebf
commit 762371c3e4
8 changed files with 250 additions and 142 deletions
+28 -11
View File
@@ -5317,13 +5317,13 @@ This element does not have custom attributes. It only has common attributes, whi
This element creates a position servo. The underlying :el:`general` attributes are set as follows:
========= ======= ========= =======
========= ======= ========= =========
Attribute Setting Attribute Setting
========= ======= ========= =======
========= ======= ========= =========
dyntype none dynprm 1 0 0
gaintype fixed gainprm kp 0 0
biastype affine biasprm 0 -kp 0
========= ======= ========= =======
biastype affine biasprm 0 -kp -kv
========= ======= ========= =========
This element has one custom attribute in addition to the common attributes:
@@ -5377,6 +5377,11 @@ This element has one custom attribute in addition to the common attributes:
:at:`kp`: :at-val:`real, "1"`
Position feedback gain.
.. _actuator-position-kv:
:at:`kv`: :at-val:`real, "0"`
Damping applied by the actuator.
When using this attribute, it is recommended to use the implicitfast or implicit :ref:`integrators<geIntegration>`.
.. _actuator-velocity:
@@ -5385,7 +5390,9 @@ This element has one custom attribute in addition to the common attributes:
This element creates a velocity servo. Note that in order create a PD controller, one has to define two actuators: a
position servo and a velocity servo. This is because MuJoCo actuators are SISO while a PD controller takes two control
inputs (reference position and reference velocity). The underlying :el:`general` attributes are set as follows:
inputs (reference position and reference velocity).
When using this actuator, it is recommended to use the implicitfast or implicit :ref:`integrators<geIntegration>`.
The underlying :el:`general` attributes are set as follows:
========= ======= ========= =======
Attribute Setting Attribute Setting
@@ -5456,14 +5463,14 @@ This element creates an integrated-velocity servo. For more information, see the
:ref:`Activation clamping <CActRange>` section of the Modeling chapter. The underlying
:el:`general` attributes are set as follows:
========== =========== ========= =======
========== =========== ========= =========
Attribute Setting Attribute Setting
========== =========== ========= =======
========== =========== ========= =========
dyntype integrator dynprm 1 0 0
gaintype fixed gainprm kp 0 0
biastype affine biasprm 0 -kp 0
biastype affine biasprm 0 -kp -kv
actlimited true
========== =========== ========= =======
========== =========== ========= =========
This element has one custom attribute in addition to the common attributes:
@@ -5518,6 +5525,11 @@ This element has one custom attribute in addition to the common attributes:
:at:`kp`: :at-val:`real, "1"`
Position feedback gain.
.. _actuator-intvelocity-kv:
:at:`kv`: :at-val:`real, "0"`
Damping applied by the actuator.
When using this attribute, it is recommended to use the implicitfast or implicit :ref:`integrators<geIntegration>`.
.. _actuator-damper:
@@ -5525,8 +5537,9 @@ This element has one custom attribute in addition to the common attributes:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This element is an active damper which produces a force proportional to both velocity and control: ``F = - kv * velocity
* control``, where ``kv`` must be nonnegative. :at:`ctrlrange` is required and must also be nonnegative. The underlying
:el:`general` attributes are set as follows:
* control``, where ``kv`` must be nonnegative. :at:`ctrlrange` is required and must also be nonnegative.
When using this actuator, it is recommended to use the implicitfast or implicit :ref:`integrators<geIntegration>`.
The underlying :el:`general` attributes are set as follows:
=========== ======= ========= =======
Attribute Setting Attribute Setting
@@ -7680,6 +7693,8 @@ slidersite, cranksite.
.. _default-position-kp:
.. _default-position-kv:
:el-prefix:`default/` |-| **position** (?)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7736,6 +7751,8 @@ tendon, slidersite, cranksite.
.. _default-intvelocity-kp:
.. _default-intvelocity-kv:
:el-prefix:`default/` |-| **intvelocity** (?)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+5 -3
View File
@@ -778,7 +778,7 @@
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`jointinparent<actuator-position-jointinparent>` | :ref:`tendon<actuator-position-tendon>` | :ref:`slidersite<actuator-position-slidersite>` | :ref:`cranksite<actuator-position-cranksite>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`site<actuator-position-site>` | :ref:`refsite<actuator-position-refsite>` | :ref:`kp<actuator-position-kp>` | | |
| | | | :ref:`site<actuator-position-site>` | :ref:`refsite<actuator-position-refsite>` | :ref:`kp<actuator-position-kp>` | :ref:`kv<actuator-position-kv>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| actuator |br| |_| |L| | | .. table:: |
@@ -810,6 +810,8 @@
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`cranksite<actuator-intvelocity-cranksite>` | :ref:`site<actuator-intvelocity-site>` | :ref:`refsite<actuator-intvelocity-refsite>` | :ref:`kp<actuator-intvelocity-kp>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`kv<actuator-intvelocity-kv>` | | | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| actuator |br| |_| |L| | | .. table:: |
| :ref:`damper | \* | :class: mjcf-attributes |
@@ -1440,7 +1442,7 @@
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`gear<default-position-gear>` | :ref:`cranklength<default-position-cranklength>` | :ref:`user<default-position-user>` | :ref:`group<default-position-group>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`kp<default-position-kp>` | | | | |
| | | | :ref:`kp<default-position-kp>` | :ref:`kv<default-position-kv>` | | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| default |br| |_| |L| | | .. table:: |
@@ -1462,7 +1464,7 @@
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`actrange<default-intvelocity-actrange>` | :ref:`gear<default-intvelocity-gear>` | :ref:`cranklength<default-intvelocity-cranklength>` | :ref:`user<default-intvelocity-user>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`group<default-intvelocity-group>` | :ref:`kp<default-intvelocity-kp>` | | | |
| | | | :ref:`group<default-intvelocity-group>` | :ref:`kp<default-intvelocity-kp>` | :ref:`kv<default-intvelocity-kv>` | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| default |br| |_| |L| | | .. table:: |
+4
View File
@@ -12,6 +12,10 @@ General
robust for very small or large geom sizes.
- Added :ref:`frame<frame>` to MJCF, a :ref:`meta-element<meta-element>` which defines a pure coordinate transformation
on its direct children, without requiring a :ref:`body<body>`.
- Added the :at:`kv` attribute to the :ref:`position<actuator-position>` and :ref:`intvelocity<actuator-intvelocity>`
actuators, for specifying actuator-applied damping. This can be used to implement a PD controller with 0 reference
velocity. When using this attribute, it is recommended to use the implicitfast or implicit
:ref:`integrators<geIntegration>`.
Plugins
^^^^^^^
+1 -1
View File
@@ -3876,7 +3876,7 @@ void mjCActuator::Compile(void) {
throw mjCError(this, "invalid control range for actuator '%s' (id = %d)", name.c_str(), id);
}
if (actrange[0]>=actrange[1] && actlimited) {
throw mjCError(this, "invalid activation range for actuator '%s' (id = %d)", name.c_str(), id);
throw mjCError(this, "invalid actrange for actuator '%s' (id = %d)", name.c_str(), id);
}
if (actlimited && dyntype == mjDYN_NONE) {
throw mjCError(this, "actrange specified but dyntype is 'none' in actuator '%s' (id = %d)",
+21 -30
View File
@@ -166,16 +166,16 @@ static const char* MJCF[nMJCF][mjXATTRNUM] = {
"dyntype", "gaintype", "biastype", "dynprm", "gainprm", "biasprm", "actearly"},
{"motor", "?", "8", "ctrllimited", "forcelimited", "ctrlrange", "forcerange",
"gear", "cranklength", "user", "group"},
{"position", "?", "9", "ctrllimited", "forcelimited", "ctrlrange", "forcerange",
{"position", "?", "10", "ctrllimited", "forcelimited", "ctrlrange", "forcerange",
"gear", "cranklength", "user", "group",
"kp"},
"kp", "kv"},
{"velocity", "?", "9", "ctrllimited", "forcelimited", "ctrlrange", "forcerange",
"gear", "cranklength", "user", "group",
"kv"},
{"intvelocity", "?", "10", "ctrllimited", "forcelimited",
{"intvelocity", "?", "11", "ctrllimited", "forcelimited",
"ctrlrange", "forcerange", "actrange",
"gear", "cranklength", "user", "group",
"kp"},
"kp", "kv"},
{"damper", "?", "8", "forcelimited", "ctrlrange", "forcerange",
"gear", "cranklength", "user", "group",
"kv"},
@@ -379,22 +379,22 @@ static const char* MJCF[nMJCF][mjXATTRNUM] = {
"ctrllimited", "forcelimited", "ctrlrange", "forcerange",
"lengthrange", "gear", "cranklength", "user",
"joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite"},
{"position", "*", "19", "name", "class", "group",
{"position", "*", "20", "name", "class", "group",
"ctrllimited", "forcelimited", "ctrlrange", "forcerange",
"lengthrange", "gear", "cranklength", "user",
"joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite",
"kp"},
"kp", "kv"},
{"velocity", "*", "19", "name", "class", "group",
"ctrllimited", "forcelimited", "ctrlrange", "forcerange",
"lengthrange", "gear", "cranklength", "user",
"joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite",
"kv"},
{"intvelocity", "*", "20", "name", "class", "group",
{"intvelocity", "*", "21", "name", "class", "group",
"ctrllimited", "forcelimited",
"ctrlrange", "forcerange", "actrange", "lengthrange",
"gear", "cranklength", "user",
"joint", "jointinparent", "tendon", "slidersite", "cranksite", "site", "refsite",
"kp"},
"kp", "kv"},
{"damper", "*", "18", "name", "class", "group",
"forcelimited", "ctrlrange", "forcerange",
"lengthrange", "gear", "cranklength", "user",
@@ -1895,19 +1895,26 @@ void mjXReader::OneActuator(XMLElement* elem, mjCActuator* pact) {
pact->biastype = mjBIAS_NONE;
}
// position servo
else if (type=="position") {
// clear bias
mjuu_zerovec(pact->biasprm, mjNBIAS);
// position or integrated velocity servo
else if (type=="position" || type=="intvelocity") {
// explicit attributes
ReadAttr(elem, "kp", 1, pact->gainprm, text);
pact->biasprm[1] = -pact->gainprm[0];
if (ReadAttr(elem, "kv", 1, pact->biasprm + 2, text)) {
if (pact->biasprm[2] < 0)
throw mjXError(elem, "kv cannot be negative");
pact->biasprm[2] *= -1;
}
// implied parameters
pact->dyntype = mjDYN_NONE;
pact->gaintype = mjGAIN_FIXED;
pact->biastype = mjBIAS_AFFINE;
if (type=="intvelocity") {
pact->dyntype = mjDYN_INTEGRATOR;
pact->actlimited = 1;
}
}
// velocity servo
@@ -1925,22 +1932,6 @@ void mjXReader::OneActuator(XMLElement* elem, mjCActuator* pact) {
pact->biastype = mjBIAS_AFFINE;
}
// integrated velocity
else if (type=="intvelocity") {
// clear bias
mjuu_zerovec(pact->biasprm, mjNBIAS);
// explicit attributes
ReadAttr(elem, "kp", 1, pact->gainprm, text);
// implied parameters
pact->dyntype = mjDYN_INTEGRATOR;
pact->gaintype = mjGAIN_FIXED;
pact->biastype = mjBIAS_AFFINE;
pact->actlimited = 1;
pact->biasprm[1] = -pact->gainprm[0];
}
// damper
else if (type=="damper") {
// clear gain
+8 -8
View File
@@ -13,7 +13,7 @@
<default>
<default class="translation">
<general gainprm="100" biasprm="0 -100 -10" biastype="affine" ctrlrange="-.25 .25"/>
<position kp="100" kv="10" ctrlrange="-.25 .25"/>
</default>
<default class="rotation">
<!--
@@ -22,7 +22,7 @@
Increase this range to pi or bigger in order to see the instabillity.
See here for more details https://mujoco.readthedocs.io/en/latest/XMLreference.html#actuator
-->
<general gainprm=".5" biasprm="0 -.5 -.05" biastype="affine" ctrlrange="-1.571 1.571"/>
<position kp=".5" kv=".05" ctrlrange="-1.571 1.571"/>
</default>
<!--
Clamping the total actuator torque at the joints means that the motion produced by the Cartesian
@@ -62,11 +62,11 @@
</worldbody>
<actuator>
<general name="x" site="end_effector" refsite="reference" gear="1 0 0 0 0 0" class="translation"/>
<general name="y" site="end_effector" refsite="reference" gear="0 1 0 0 0 0" class="translation"/>
<general name="z" site="end_effector" refsite="reference" gear="0 0 1 0 0 0" class="translation"/>
<general name="rx" site="end_effector" refsite="reference" gear="0 0 0 1 0 0" class="rotation"/>
<general name="ry" site="end_effector" refsite="reference" gear="0 0 0 0 1 0" class="rotation"/>
<general name="rz" site="end_effector" refsite="reference" gear="0 0 0 0 0 1" class="rotation"/>
<position name="x" site="end_effector" refsite="reference" gear="1 0 0 0 0 0" class="translation"/>
<position name="y" site="end_effector" refsite="reference" gear="0 1 0 0 0 0" class="translation"/>
<position name="z" site="end_effector" refsite="reference" gear="0 0 1 0 0 0" class="translation"/>
<position name="rx" site="end_effector" refsite="reference" gear="0 0 0 1 0 0" class="rotation"/>
<position name="ry" site="end_effector" refsite="reference" gear="0 0 0 0 1 0" class="rotation"/>
<position name="rz" site="end_effector" refsite="reference" gear="0 0 0 0 0 1" class="rotation"/>
</actuator>
</mujoco>
+2 -2
View File
@@ -940,7 +940,7 @@ TEST_F(ActRangeTest, ActRangeBad) {
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid activation range"));
EXPECT_THAT(error.data(), HasSubstr("invalid actrange"));
}
TEST_F(ActRangeTest, ActRangeUndefined) {
@@ -960,7 +960,7 @@ TEST_F(ActRangeTest, ActRangeUndefined) {
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid activation range"));
EXPECT_THAT(error.data(), HasSubstr("invalid actrange"));
}
TEST_F(ActRangeTest, ActRangeNoDyntype) {
+181 -87
View File
@@ -531,92 +531,6 @@ TEST_F(XMLReaderTest, ReadShellParameter) {
mj_deleteModel(model);
}
TEST_F(XMLReaderTest, ReadsDamper) {
static constexpr char xml[] = R"(
<mujoco>
<compiler autolimits="true"/>
<worldbody>
<body>
<geom size="1"/>
<joint name="jnt" type="slide" axis="1 0 0" range="-10 10"/>
</body>
</worldbody>
<actuator>
<damper joint="jnt" ctrlrange="0 1"/>
<general joint="jnt" ctrllimited="true" ctrlrange="0 1" gaintype="affine" biastype="none"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, NotNull());
EXPECT_THAT(model->actuator_gaintype[0], Eq(mjGAIN_AFFINE));
EXPECT_THAT(model->actuator_gaintype[1], Eq(mjGAIN_AFFINE));
EXPECT_THAT(model->actuator_biastype[0], Eq(mjBIAS_NONE));
EXPECT_THAT(model->actuator_biastype[1], Eq(mjBIAS_NONE));
mj_deleteModel(model);
}
TEST_F(XMLReaderTest, RequiresPoisitiveDamping) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1"/>
<joint name="jnt" type="slide" axis="1 0 0" range="-10 10"/>
</body>
</worldbody>
<actuator>
<damper joint="jnt" kv="-1"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(),
HasSubstr("damping coefficient cannot be negative"));
}
TEST_F(XMLReaderTest, RequiresControlRange) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1"/>
<joint name="jnt" type="slide" axis="1 0 0" range="-10 10" limited="true"/>
</body>
</worldbody>
<actuator>
<damper joint="jnt" kv="1"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid control range"));
}
TEST_F(XMLReaderTest, PositiveControlRange) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1"/>
<joint name="jnt" type="slide" axis="1 0 0" range="-10 10"/>
</body>
</worldbody>
<actuator>
<damper joint="jnt" kv="1" ctrlrange="-1 0"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("control range cannot be negative"));
}
TEST_F(XMLReaderTest, ReadsSkinGroups) {
static constexpr char xml[] = R"(
@@ -779,6 +693,186 @@ TEST_F(ActuatorTest, ReadsByte) {
using ActuatorParseTest = MujocoTest;
TEST_F(ActuatorParseTest, ReadsDamper) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1"/>
<joint name="jnt" type="slide" axis="1 0 0" range="-10 10"/>
</body>
</worldbody>
<actuator>
<damper joint="jnt" ctrlrange="0 1"/>
<general joint="jnt" ctrllimited="true" ctrlrange="0 1" gaintype="affine" biastype="none"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, NotNull());
EXPECT_THAT(model->actuator_gaintype[0], Eq(mjGAIN_AFFINE));
EXPECT_THAT(model->actuator_gaintype[1], Eq(mjGAIN_AFFINE));
EXPECT_THAT(model->actuator_biastype[0], Eq(mjBIAS_NONE));
EXPECT_THAT(model->actuator_biastype[1], Eq(mjBIAS_NONE));
mj_deleteModel(model);
}
TEST_F(ActuatorParseTest, DamperRequiresPositiveDamping) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1"/>
<joint name="jnt" type="slide" axis="1 0 0" range="-10 10"/>
</body>
</worldbody>
<actuator>
<damper joint="jnt" kv="-1"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(),
HasSubstr("damping coefficient cannot be negative"));
}
TEST_F(ActuatorParseTest, DamperRequiresControlRange) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1"/>
<joint name="jnt" type="slide" axis="1 0 0" range="-10 10" limited="true"/>
</body>
</worldbody>
<actuator>
<damper joint="jnt" kv="1"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid control range"));
}
TEST_F(ActuatorParseTest, DamperPositiveControlRange) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1"/>
<joint name="jnt" type="slide" axis="1 0 0" range="-10 10"/>
</body>
</worldbody>
<actuator>
<damper joint="jnt" kv="1" ctrlrange="-1 0"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("control range cannot be negative"));
}
TEST_F(ActuatorParseTest, ReadsPositionIntvelKv) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1"/>
<joint name="jnt" type="slide" axis="1 0 0"/>
</body>
</worldbody>
<actuator>
<position joint="jnt" kv="2"/>
<intvelocity joint="jnt" actrange="-1 1" kv="3"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, NotNull());
EXPECT_THAT(model->actuator_biasprm[0*mjNBIAS + 2], Eq(-2.0));
EXPECT_THAT(model->actuator_biasprm[1*mjNBIAS + 2], Eq(-3.0));
mj_deleteModel(model);
}
TEST_F(ActuatorParseTest, RequirePositiveKv) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1"/>
<joint name="jnt" type="slide" axis="1 0 0"/>
</body>
</worldbody>
<actuator>
<position joint="jnt" kv="-2"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("kv cannot be negative"));
}
TEST_F(ActuatorParseTest, PositionIntvelocityVelocityDefaultsPropagate) {
static constexpr char xml[] = R"(
<mujoco>
<default>
<default class="position">
<position kp="3" kv="4"/>
</default>
<default class="intvelocity">
<intvelocity kp="5" kv="6" actrange="-1 1"/>
</default>
<default class="velocity">
<velocity kv="7"/>
</default>
</default>
<worldbody>
<body>
<geom size="1"/>
<joint name="jnt" type="slide" axis="1 0 0"/>
</body>
</worldbody>
<actuator>
<position joint="jnt" class="position"/>
<intvelocity joint="jnt" class="intvelocity"/>
<velocity joint="jnt" class="velocity"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, NotNull()) << error.data();
EXPECT_EQ(model->actuator_gainprm[0*mjNGAIN + 0], 3.0);
EXPECT_EQ(model->actuator_biasprm[0*mjNBIAS + 1], -3.0);
EXPECT_EQ(model->actuator_biasprm[0*mjNBIAS + 2], -4.0);
EXPECT_EQ(model->actuator_gainprm[1*mjNGAIN + 0], 5.0);
EXPECT_EQ(model->actuator_biasprm[1*mjNBIAS + 1], -5.0);
EXPECT_EQ(model->actuator_biasprm[1*mjNBIAS + 2], -6.0);
EXPECT_EQ(model->actuator_gainprm[2*mjNGAIN + 0], 7.0);
EXPECT_EQ(model->actuator_biasprm[2*mjNBIAS + 1], 0.0);
EXPECT_EQ(model->actuator_biasprm[2*mjNBIAS + 2], -7.0);
for (int i = 0; i < model->nu; i++) {
for (int j = 3; j < mjNBIAS; j++) {
EXPECT_EQ(model->actuator_biasprm[i*mjNBIAS + j], 0.0);
}
for (int j = 3; j < mjNGAIN; j++) {
EXPECT_EQ(model->actuator_gainprm[i*mjNGAIN + j], 0.0);
}
}
mj_deleteModel(model);
}
TEST_F(ActuatorParseTest, IntvelocityCheckEquivalence) {
static constexpr char xml[] = R"(
<mujoco>
@@ -871,7 +965,7 @@ TEST_F(ActuatorParseTest, IntvelocityNoActrangeThrowsError) {
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid activation range for actuator"));
EXPECT_THAT(error.data(), HasSubstr("invalid actrange for actuator"));
}
TEST_F(ActuatorParseTest, IntvelocityDefaultsPropagate) {