Skip to content

Commit fdf1412

Browse files
yuvaltassacopybara-github
authored andcommitted
Report gravity in accelerometer and framelinacc on static and mocap bodies
`mj_objectAcceleration` returned zero for dof-less (static and mocap) bodies, dropping the gravitational proper acceleration that `mj_rnePostConstraint` already stores in `cacc` for every body. Sensors on such bodies now read like a dynamic body at rest, matching MJX and MuJoCo Warp, which already did this. - `mj_objectAcceleration`: always transform `cacc`, only skip the Coriolis term for dof-less bodies (zero velocity). - Test accelerometer, framelinacc and frameangacc on world, static and mocap bodies, with the sleep filter active. - Changelog entry. PiperOrigin-RevId: 1012012486 Change-Id: I1b8b1574c5c53f45c7a7802439bfad24478470c9
1 parent 10ba77b commit fdf1412

3 files changed

Lines changed: 63 additions & 5 deletions

File tree

‎doc/changelog.rst‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,9 @@ Bug fixes
320320
- Legacy ``.msh`` meshes with mirrored :ref:`scale<asset-mesh-scale>` no longer double-flip face winding (which
321321
inverted faces), and ``.msh`` files without vertex normals no longer populate empty face normals or reject custom
322322
normals on recompilation.
323+
- :ref:`accelerometer<sensor-accelerometer>` and :ref:`framelinacc<sensor-framelinacc>` sensors and
324+
:ref:`mj_objectAcceleration` on static and mocap bodies now report the gravitational proper acceleration, like a
325+
dynamic body at rest. Previously they returned zero, a regression introduced in 3.3.7.
323326

324327
Documentation
325328
^^^^^^^^^^^^^

‎src/engine/engine_core_util.c‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,15 +1272,14 @@ void mj_objectAcceleration(const mjModel* m, const mjData* d,
12721272
mjERROR("invalid object type %d", objtype);
12731273
}
12741274

1275-
// dof-less body (static or mocap): quick return
1275+
// transform com-based acceleration to local frame
1276+
mju_transformSpatial(res, d->cacc+6*bodyid, 0, pos, d->subtree_com+3*m->body_rootid[bodyid], rot);
1277+
1278+
// dof-less body (static or mocap): zero velocity, quick return
12761279
if (m->body_dofnum[m->body_weldid[bodyid]] == 0) {
1277-
mju_zero(res, 6);
12781280
return;
12791281
}
12801282

1281-
// transform com-based acceleration to local frame
1282-
mju_transformSpatial(res, d->cacc+6*bodyid, 0, pos, d->subtree_com+3*m->body_rootid[bodyid], rot);
1283-
12841283
// transform com-based velocity to local frame
12851284
mjtNum vel[6];
12861285
mju_transformSpatial(vel, d->cvel+6*bodyid, 0, pos, d->subtree_com+3*m->body_rootid[bodyid], rot);

‎test/engine/engine_sensor_test.cc‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2046,6 +2046,62 @@ TEST_F(SensorTest, AccelerometerAfterStep1) {
20462046
EXPECT_NEAR(data->sensordata[2], 9.81, 1e-2);
20472047
}
20482048

2049+
// accelerometer and framelinacc on static and mocap bodies read gravity
2050+
TEST_F(SensorTest, AccelerometerStaticAndMocap) {
2051+
constexpr char xml[] = R"(
2052+
<mujoco>
2053+
<option>
2054+
<flag sleep="enable"/>
2055+
</option>
2056+
<worldbody>
2057+
<site name="world"/>
2058+
<body name="static" pos="1 2 3">
2059+
<geom size="0.1"/>
2060+
<site name="static" euler="90 0 0"/>
2061+
<camera name="static" euler="90 0 0"/>
2062+
</body>
2063+
<body name="mocap" mocap="true" pos="-1 0 2">
2064+
<geom size="0.1"/>
2065+
<site name="mocap"/>
2066+
</body>
2067+
<body pos="0 0 5" sleep="init">
2068+
<freejoint/>
2069+
<geom size="0.1"/>
2070+
</body>
2071+
</worldbody>
2072+
<sensor>
2073+
<accelerometer site="world"/>
2074+
<accelerometer site="static"/>
2075+
<accelerometer site="mocap"/>
2076+
<framelinacc objtype="body" objname="static"/>
2077+
<frameangacc objtype="body" objname="mocap"/>
2078+
</sensor>
2079+
</mujoco>
2080+
)";
2081+
MjModelPtr model = LoadModelFromString(xml);
2082+
ASSERT_THAT(model, NotNull());
2083+
MjDataPtr data = MakeData(model);
2084+
mj_forward(model.get(), data.get());
2085+
EXPECT_LT(data->nbody_awake, model->nbody);
2086+
2087+
std::vector<mjtNum> expected = {
2088+
0, 0, 9.81, // accelerometer: world
2089+
0, 9.81, 0, // accelerometer: static site rotated +90 deg about x
2090+
0, 0, 9.81, // accelerometer: mocap
2091+
0, 0, 9.81, // framelinacc: static
2092+
0, 0, 0, // frameangacc: mocap
2093+
};
2094+
EXPECT_THAT(AsVector(data->sensordata, 15),
2095+
Pointwise(MjNear(1e-12, 1e-5), expected));
2096+
2097+
mjtNum acc[6];
2098+
int cam_id = mj_name2id(model.get(), mjOBJ_CAMERA, "static");
2099+
mj_objectAcceleration(model.get(), data.get(), mjOBJ_CAMERA, cam_id, acc, 1);
2100+
EXPECT_THAT(
2101+
AsVector(acc, 6),
2102+
Pointwise(MjNear(1e-12, 1e-5), std::vector<mjtNum>{0, 0, 0, 0, 9.81, 0}));
2103+
}
2104+
20492105
// Test tactile sensor reads non-zero values when contacts occur
20502106
TEST_F(SensorTest, TactileSkipTangents) {
20512107
constexpr char xml[] = R"(

0 commit comments

Comments
 (0)