Mocap bodies are the weld root of their own kinematic subtree.
PiperOrigin-RevId: 960212286 Change-Id: Ibeff129c3110576c8846c76ba6ab756f23c0fa2e
This commit is contained in:
committed by
Copybara-Service
parent
0accc5b3c7
commit
ed13bf5647
@@ -790,5 +790,146 @@ TEST_F(SleepTest, FlexMocapContact) {
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
|
||||
// mocap bodies are their own weld root: dragging into a sleeping tree wakes it
|
||||
TEST_F(SleepTest, MocapWakes) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<option>
|
||||
<flag sleep="enable"/>
|
||||
</option>
|
||||
<worldbody>
|
||||
<geom type="plane" size="5 5 .1"/>
|
||||
<body name="hand" mocap="true" pos="2 0 .1">
|
||||
<geom type="sphere" size=".1"/>
|
||||
<body name="finger">
|
||||
<geom type="sphere" size=".05" pos=".1 0 0"/>
|
||||
</body>
|
||||
</body>
|
||||
<body name="box" pos="0 0 .1">
|
||||
<freejoint/>
|
||||
<geom type="box" size=".1 .1 .1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
MjModelPtr m = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(m.get(), NotNull()) << error;
|
||||
|
||||
// mocap body is its own weld root, static child inherits it,
|
||||
// box is its own (jointed)
|
||||
int hand = mj_name2id(m.get(), mjOBJ_BODY, "hand");
|
||||
int finger = mj_name2id(m.get(), mjOBJ_BODY, "finger");
|
||||
EXPECT_EQ(m->body_weldid[hand], hand);
|
||||
EXPECT_EQ(m->body_weldid[finger], hand);
|
||||
|
||||
// let the box fall asleep
|
||||
MjDataPtr d = MakeData(m);
|
||||
int steps = 0;
|
||||
while (d->ntree_awake > 0 && steps++ < 10000) {
|
||||
mj_step(m.get(), d.get());
|
||||
}
|
||||
ASSERT_EQ(d->ntree_awake, 0);
|
||||
|
||||
// drag the mocap hand into the sleeping box: box wakes
|
||||
d->mocap_pos[0] = 0;
|
||||
mj_step(m.get(), d.get());
|
||||
EXPECT_EQ(d->ntree_awake, 1);
|
||||
}
|
||||
|
||||
// mocap bodies do not generate contacts with static bodies or each other
|
||||
TEST_F(SleepTest, MocapNoStaticContacts) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<geom type="plane" size="5 5 .1"/>
|
||||
<body mocap="true" pos="0 0 .05">
|
||||
<geom type="sphere" size=".1"/>
|
||||
</body>
|
||||
<body mocap="true" pos=".05 0 .05">
|
||||
<geom type="sphere" size=".1"/>
|
||||
</body>
|
||||
<geom type="box" size=".1 .1 .1" pos="-.05 0 .05"/>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
MjModelPtr m = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(m.get(), NotNull()) << error;
|
||||
MjDataPtr d = MakeData(m);
|
||||
|
||||
// everything interpenetrates, nothing can move: no contacts
|
||||
mj_forward(m.get(), d.get());
|
||||
EXPECT_EQ(d->ncon, 0);
|
||||
}
|
||||
|
||||
// a plane on a mocap body collides like a plane on a static body
|
||||
TEST_F(SleepTest, MocapPlane) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<body mocap="true">
|
||||
<geom type="plane" size="5 5 .1"/>
|
||||
</body>
|
||||
<body pos="0 0 .5">
|
||||
<freejoint/>
|
||||
<geom type="box" size=".1 .1 .1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
MjModelPtr m = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(m.get(), NotNull()) << error;
|
||||
MjDataPtr d = MakeData(m);
|
||||
|
||||
// box falls onto the mocap plane and rests on it
|
||||
while (d->time < 2) {
|
||||
mj_step(m.get(), d.get());
|
||||
}
|
||||
EXPECT_GT(d->ncon, 0);
|
||||
EXPECT_NEAR(d->qpos[2], 0.1, 1e-3);
|
||||
}
|
||||
|
||||
// a tree welded by equality to a mocap body is woken when asleep
|
||||
TEST_F(SleepTest, MocapWeldEqualityWakes) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<option>
|
||||
<flag sleep="enable"/>
|
||||
</option>
|
||||
<worldbody>
|
||||
<geom type="plane" size="5 5 .1"/>
|
||||
<body name="target" mocap="true" pos="2 0 .5">
|
||||
<geom type="sphere" size=".05" contype="0" conaffinity="0"/>
|
||||
</body>
|
||||
<body name="box" pos="0 0 .1">
|
||||
<freejoint/>
|
||||
<geom type="box" size=".1 .1 .1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
<equality>
|
||||
<weld name="grab" body1="target" body2="box" active="false"/>
|
||||
</equality>
|
||||
</mujoco>
|
||||
)";
|
||||
char error[1024];
|
||||
MjModelPtr m = LoadModelFromString(xml, error, sizeof(error));
|
||||
ASSERT_THAT(m.get(), NotNull()) << error;
|
||||
MjDataPtr d = MakeData(m);
|
||||
|
||||
// equality inactive: box falls asleep on the floor
|
||||
int steps = 0;
|
||||
while (d->ntree_awake > 0 && steps++ < 10000) {
|
||||
mj_step(m.get(), d.get());
|
||||
}
|
||||
ASSERT_EQ(d->ntree_awake, 0);
|
||||
|
||||
// activate the weld to the mocap body: box wakes
|
||||
d->eq_active[mj_name2id(m.get(), mjOBJ_EQUALITY, "grab")] = 1;
|
||||
mj_step(m.get(), d.get());
|
||||
EXPECT_EQ(d->ntree_awake, 1);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mujoco
|
||||
|
||||
@@ -100,8 +100,9 @@ TEST_F(UserModelTest, WeldRootID) {
|
||||
|
||||
EXPECT_THAT(AsVector(model->body_rootid, model->nbody),
|
||||
ElementsAre(0, 1, 1, 3, 3, 5, 5, 7, 7, 9, 9));
|
||||
// mocap bodies (7, 9) are their own weld roots, inherited by static children (8)
|
||||
EXPECT_THAT(AsVector(model->body_weldid, model->nbody),
|
||||
ElementsAre(0, 1, 2, 3, 3, 0, 0, 0, 0, 0, 10));
|
||||
ElementsAre(0, 1, 2, 3, 3, 0, 0, 7, 7, 9, 10));
|
||||
}
|
||||
|
||||
TEST_F(UserModelTest, RepeatedNames) {
|
||||
|
||||
Reference in New Issue
Block a user