Fix mass/inertia checking for moving bodies with nested children.
Previously, we only checked immediate children of moving bodies. PiperOrigin-RevId: 726999705 Change-Id: I133a557daf86223b8751c6d46e25809781e168a1
This commit is contained in:
committed by
Copybara-Service
parent
37d7591ce0
commit
78a4d2f389
+45
-27
@@ -4319,33 +4319,11 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check body mass and inertia
|
// check mass and inertia of moving bodies
|
||||||
for (int i=1; i<bodies_.size(); i++) {
|
if (bodies_.size() > 1) {
|
||||||
mjCBody* b = bodies_[i];
|
// we ignore the first body as it is the world body
|
||||||
|
if (!CheckBodiesMassInertia(std::vector<mjCBody*>(bodies_.begin()+1, bodies_.end()))) {
|
||||||
// find moving body with small mass or inertia
|
throw mjCError(0, "mass and inertia of moving bodies must be larger than mjMINVAL");
|
||||||
if (!b->joints.empty() &&
|
|
||||||
(b->mass<mjMINVAL ||
|
|
||||||
b->inertia[0]<mjMINVAL ||
|
|
||||||
b->inertia[1]<mjMINVAL ||
|
|
||||||
b->inertia[2]<mjMINVAL)) {
|
|
||||||
// does it have static children with mass and inertia
|
|
||||||
bool ok = false;
|
|
||||||
for (size_t j=0; j<b->bodies.size(); j++) {
|
|
||||||
if (b->bodies[j]->joints.empty() &&
|
|
||||||
b->bodies[j]->mass>=mjMINVAL &&
|
|
||||||
b->bodies[j]->inertia[0]>=mjMINVAL &&
|
|
||||||
b->bodies[j]->inertia[1]>=mjMINVAL &&
|
|
||||||
b->bodies[j]->inertia[2]>=mjMINVAL) {
|
|
||||||
ok = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// error
|
|
||||||
if (!ok) {
|
|
||||||
throw mjCError(b, "mass and inertia of moving bodies must be larger than mjMINVAL");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4497,6 +4475,46 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool mjCModel::CheckBodiesMassInertia(std::vector<mjCBody*> bodies) {
|
||||||
|
// check mass and inertia of moving bodies
|
||||||
|
for (int i=0; i<bodies.size(); i++) {
|
||||||
|
if (!bodies[i]->joints.empty()) {
|
||||||
|
if (!CheckBodyMassInertia(bodies[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool mjCModel::CheckBodyMassInertia(mjCBody* body) {
|
||||||
|
// check if body has valid mass and inertia
|
||||||
|
if (body->mass>=mjMINVAL &&
|
||||||
|
body->inertia[0]>=mjMINVAL &&
|
||||||
|
body->inertia[1]>=mjMINVAL &&
|
||||||
|
body->inertia[2]>=mjMINVAL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// body is valid if we find a single static child with valid mass and inertia
|
||||||
|
for (int i=0; i<body->Bodies().size(); i++) {
|
||||||
|
// if we find a child with a joint, time to move on to the next moving body
|
||||||
|
if (!body->Bodies()[i]->joints.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (CheckBodyMassInertia(body->Bodies()[i])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we did not find a child with valid mass and inertia
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------- DECOMPILER -------------------------------------------------------
|
//------------------------------- DECOMPILER -------------------------------------------------------
|
||||||
|
|
||||||
// get numeric data back from mjModel
|
// get numeric data back from mjModel
|
||||||
|
|||||||
@@ -414,6 +414,13 @@ class mjCModel : public mjCModel_, private mjSpec {
|
|||||||
// compute qpos0
|
// compute qpos0
|
||||||
void ComputeReference();
|
void ComputeReference();
|
||||||
|
|
||||||
|
// return true if all bodies have valid mass and inertia
|
||||||
|
bool CheckBodiesMassInertia(std::vector<mjCBody*> bodies);
|
||||||
|
|
||||||
|
// return true if body has valid mass and inertia
|
||||||
|
bool CheckBodyMassInertia(mjCBody* body);
|
||||||
|
|
||||||
|
|
||||||
mjListKeyMap ids; // map from object names to ids
|
mjListKeyMap ids; // map from object names to ids
|
||||||
mjCError errInfo; // last error info
|
mjCError errInfo; // last error info
|
||||||
std::vector<mjKeyInfo> key_pending_; // attached keyframes
|
std::vector<mjKeyInfo> key_pending_; // attached keyframes
|
||||||
|
|||||||
@@ -140,6 +140,82 @@ TEST_F(UserCModelTest, ActuatorSparsity) {
|
|||||||
mj_deleteModel(m);
|
mj_deleteModel(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(UserCModelTest, NestedZeroMassBodiesOK) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<worldbody>
|
||||||
|
<body>
|
||||||
|
<freejoint/>
|
||||||
|
<body>
|
||||||
|
<body>
|
||||||
|
<body>
|
||||||
|
<geom size="1"/>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
char error[1024];
|
||||||
|
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||||
|
ASSERT_THAT(model, NotNull()) << error;
|
||||||
|
mj_deleteModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UserCModelTest, NestedZeroMassBodiesWithJointOK) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<worldbody>
|
||||||
|
<body>
|
||||||
|
<freejoint/>
|
||||||
|
<body>
|
||||||
|
<body>
|
||||||
|
<body>
|
||||||
|
<joint/>
|
||||||
|
<geom size="1"/>
|
||||||
|
</body>
|
||||||
|
<body>
|
||||||
|
<geom size="1"/>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
char error[1024];
|
||||||
|
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||||
|
ASSERT_THAT(model, NotNull()) << error;
|
||||||
|
mj_deleteModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UserCModelTest, NestedZeroMassBodiesFail) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<worldbody>
|
||||||
|
<body>
|
||||||
|
<geom size="1"/>
|
||||||
|
<body>
|
||||||
|
<freejoint/>
|
||||||
|
<body>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
char error[1024];
|
||||||
|
mjModel* model = LoadModelFromString(xml, error, sizeof(error));
|
||||||
|
ASSERT_THAT(model, IsNull());
|
||||||
|
EXPECT_THAT(
|
||||||
|
error,
|
||||||
|
HasSubstr(
|
||||||
|
"mass and inertia of moving bodies must be larger than mjMINVAL"));
|
||||||
|
mj_deleteModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
// ------------- test automatic inference of nuser_xxx -------------------------
|
// ------------- test automatic inference of nuser_xxx -------------------------
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user