Fix insidesite sensor for massless flex parent bodies.
mjSENS_INSIDESITE uses xipos to test containment, but for massless flex parent bodies xipos equals the static body frame origin and does not track the actual flex position. Fix: in the INSIDESITE sensor case, when the object is a massless body with positive subtree mass (i.e., a flex parent), use subtree_com instead of xipos. This correctly reflects the mass-weighted centroid of the flex child bodies without changing the global semantics of xipos. PiperOrigin-RevId: 908745144 Change-Id: I527f0efb7b419345188411c9da883505156ebeea
This commit is contained in:
committed by
Copybara-Service
parent
f7d31e06f0
commit
8287d9d152
@@ -795,6 +795,15 @@ static void mj_computeSensorPos(const mjModel* m, mjData* d, int i, mjtNum* sens
|
|||||||
|
|
||||||
case mjSENS_INSIDESITE: // 1 if object is inside site
|
case mjSENS_INSIDESITE: // 1 if object is inside site
|
||||||
get_xpos_xmat(d, objtype, objid, i, &xpos, &xmat);
|
get_xpos_xmat(d, objtype, objid, i, &xpos, &xmat);
|
||||||
|
|
||||||
|
// for massless bodies with positive subtree mass (e.g., flex parents),
|
||||||
|
// xipos is the static body frame origin; use subtree_com instead
|
||||||
|
if (objtype == mjOBJ_BODY && objid > 0 &&
|
||||||
|
m->body_mass[objid] < mjMINVAL &&
|
||||||
|
m->body_subtreemass[objid] >= mjMINVAL) {
|
||||||
|
xpos = d->subtree_com + 3*objid;
|
||||||
|
}
|
||||||
|
|
||||||
sensordata[0] = mju_insideGeom(d->site_xpos + 3*refid,
|
sensordata[0] = mju_insideGeom(d->site_xpos + 3*refid,
|
||||||
d->site_xmat + 9*refid,
|
d->site_xmat + 9*refid,
|
||||||
m->site_size + 3*refid,
|
m->site_size + 3*refid,
|
||||||
|
|||||||
@@ -1727,5 +1727,62 @@ TEST_F(SensorTest, TactileSkipTangents) {
|
|||||||
mj_deleteModel(model);
|
mj_deleteModel(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// insidesite uses subtree_com for massless flex parent bodies
|
||||||
|
TEST_F(SensorTest, InsideSiteFlexBody) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<option gravity="0 0 0"/>
|
||||||
|
<worldbody>
|
||||||
|
<body name="parent">
|
||||||
|
<flexcomp name="soft" type="grid" count="3 3 3"
|
||||||
|
radius="0.01" dim="3" mass="1">
|
||||||
|
<elasticity young="5e4" poisson="0.2"/>
|
||||||
|
</flexcomp>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<!-- large site centered at origin, should contain the flex -->
|
||||||
|
<site name="container" type="box" size="2 2 2"/>
|
||||||
|
</worldbody>
|
||||||
|
|
||||||
|
<sensor>
|
||||||
|
<insidesite name="inside" site="container"
|
||||||
|
objtype="body" objname="parent"/>
|
||||||
|
</sensor>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
|
||||||
|
char error[1024] = {0};
|
||||||
|
mjModel* m = LoadModelFromString(xml, error, sizeof(error));
|
||||||
|
ASSERT_THAT(m, NotNull()) << error;
|
||||||
|
mjData* d = mj_makeData(m);
|
||||||
|
|
||||||
|
// flex is at origin, site is a large box at origin — should be inside
|
||||||
|
mj_forward(m, d);
|
||||||
|
EXPECT_EQ(d->sensordata[0], 1)
|
||||||
|
<< "flex body should be inside the container site";
|
||||||
|
|
||||||
|
// shift all vertex/node bodies far outside the site via qpos
|
||||||
|
// each body has 3 slide joints (x, y, z); shift z by +10
|
||||||
|
int parent_id = mj_name2id(m, mjOBJ_BODY, "parent");
|
||||||
|
for (int b = parent_id + 1; b < m->nbody; b++) {
|
||||||
|
if (m->body_parentid[b] == parent_id) {
|
||||||
|
int jadr = m->body_jntadr[b];
|
||||||
|
if (jadr >= 0 && m->body_jntnum[b] == 3) {
|
||||||
|
// z-slide is the 3rd joint
|
||||||
|
d->qpos[m->jnt_qposadr[jadr + 2]] = 10.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mj_forward(m, d);
|
||||||
|
|
||||||
|
// subtree_com should now be far outside; sensor should read 0
|
||||||
|
EXPECT_EQ(d->sensordata[0], 0)
|
||||||
|
<< "flex body should be outside the container site after displacement";
|
||||||
|
|
||||||
|
mj_deleteData(d);
|
||||||
|
mj_deleteModel(m);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace mujoco
|
} // namespace mujoco
|
||||||
|
|||||||
Reference in New Issue
Block a user