Fix frame accumulation order for <frame> meta-element.
PiperOrigin-RevId: 588803425 Change-Id: Id0289c34d1a6cfb6007540a29cc1f32d879e43ed
This commit is contained in:
committed by
Copybara-Service
parent
d12fe594d9
commit
1db0a9946f
@@ -993,7 +993,7 @@ void mjCBody::Compile(void) {
|
||||
|
||||
// frame
|
||||
if (frame) {
|
||||
mjuu_frameaccum(pos, quat, frame->pos, frame->quat);
|
||||
mjuu_frameaccumChild(frame->pos, frame->quat, pos, quat);
|
||||
}
|
||||
|
||||
// accumulate rbound, contype, conaffinity over geoms
|
||||
@@ -1101,7 +1101,7 @@ void mjCFrame::Compile() {
|
||||
// compile parents and accumulate result
|
||||
if (frame) {
|
||||
frame->Compile();
|
||||
mjuu_frameaccum(pos, quat, frame->pos, frame->quat);
|
||||
mjuu_frameaccumChild(frame->pos, frame->quat, pos, quat);
|
||||
}
|
||||
|
||||
mjuu_normvec(quat, 4);
|
||||
@@ -1263,7 +1263,7 @@ int mjCJoint::Compile(void) {
|
||||
mjuu_zerovec(pos, 3);
|
||||
} else if (frame) {
|
||||
double qunit[4] = {1, 0, 0, 0};
|
||||
mjuu_frameaccum(pos, qunit, frame->pos, frame->quat);
|
||||
mjuu_frameaccumChild(frame->pos, frame->quat, pos, qunit);
|
||||
}
|
||||
|
||||
// convert reference angles to radians for hinge joints
|
||||
@@ -1878,7 +1878,7 @@ void mjCGeom::Compile(void) {
|
||||
|
||||
// frame
|
||||
if (frame) {
|
||||
mjuu_frameaccum(pos, quat, frame->pos, frame->quat);
|
||||
mjuu_frameaccumChild(frame->pos, frame->quat, pos, quat);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1990,7 +1990,7 @@ void mjCSite::Compile(void) {
|
||||
|
||||
// frame
|
||||
if (frame) {
|
||||
mjuu_frameaccum(pos, quat, frame->pos, frame->quat);
|
||||
mjuu_frameaccumChild(frame->pos, frame->quat, pos, quat);
|
||||
}
|
||||
|
||||
// normalize quaternion
|
||||
@@ -2055,7 +2055,7 @@ void mjCCamera::Compile(void) {
|
||||
|
||||
// frame
|
||||
if (frame) {
|
||||
mjuu_frameaccum(pos, quat, frame->pos, frame->quat);
|
||||
mjuu_frameaccumChild(frame->pos, frame->quat, pos, quat);
|
||||
}
|
||||
|
||||
// normalize quaternion
|
||||
@@ -2159,7 +2159,7 @@ void mjCLight::Compile(void) {
|
||||
|
||||
// frame
|
||||
if (frame) {
|
||||
mjuu_frameaccum(pos, quat, frame->pos, frame->quat);
|
||||
mjuu_frameaccumChild(frame->pos, frame->quat, pos, quat);
|
||||
}
|
||||
|
||||
// normalize direction, make sure it is not zero
|
||||
|
||||
+21
-10
@@ -367,8 +367,8 @@ void mjuu_frame2quat(double* quat, const double* x, const double* y, const doubl
|
||||
|
||||
|
||||
// invert frame transformation
|
||||
void mjuu_frameinvert(double* newpos, double* newquat,
|
||||
const double* oldpos, const double* oldquat) {
|
||||
void mjuu_frameinvert(double newpos[3], double newquat[4],
|
||||
const double oldpos[3], const double oldquat[4]) {
|
||||
// position
|
||||
mjuu_localaxis(newpos, oldpos, oldquat);
|
||||
newpos[0] = -newpos[0];
|
||||
@@ -384,28 +384,39 @@ void mjuu_frameinvert(double* newpos, double* newquat,
|
||||
|
||||
|
||||
// accumulate frame transformations (forward kinematics)
|
||||
void mjuu_frameaccum(double* pos, double* quat,
|
||||
const double* addpos, const double* addquat) {
|
||||
void mjuu_frameaccum(double pos[3], double quat[4],
|
||||
const double childpos[3], const double childquat[4]) {
|
||||
double mat[9], vec[3], qtmp[4];
|
||||
mjuu_quat2mat(mat, quat);
|
||||
mjuu_mulvecmat(vec, addpos, mat);
|
||||
mjuu_mulvecmat(vec, childpos, mat);
|
||||
pos[0] += vec[0];
|
||||
pos[1] += vec[1];
|
||||
pos[2] += vec[2];
|
||||
mjuu_mulquat(qtmp, quat, addquat);
|
||||
mjuu_mulquat(qtmp, quat, childquat);
|
||||
mjuu_copyvec(quat, qtmp, 4);
|
||||
}
|
||||
|
||||
|
||||
// accumulate frame transformation in second frame
|
||||
void mjuu_frameaccumChild(const double pos[3], const double quat[4],
|
||||
double childpos[3], double childquat[4]) {
|
||||
double p[] = {pos[0], pos[1], pos[2]};
|
||||
double q[] = {quat[0], quat[1], quat[2], quat[3]};
|
||||
mjuu_frameaccum(p, q, childpos, childquat);
|
||||
mjuu_copyvec(childpos, p, 3);
|
||||
mjuu_copyvec(childquat, q, 4);
|
||||
}
|
||||
|
||||
|
||||
// invert frame accumulation
|
||||
void mjuu_frameaccuminv(double* pos, double* quat,
|
||||
const double* addpos, const double* addquat) {
|
||||
void mjuu_frameaccuminv(double pos[3], double quat[4],
|
||||
const double childpos[3], const double childquat[4]) {
|
||||
double mat[9], vec[3], qtmp[4];
|
||||
double qneg[4] = {addquat[0], -addquat[1], -addquat[2], -addquat[3]};
|
||||
double qneg[4] = {childquat[0], -childquat[1], -childquat[2], -childquat[3]};
|
||||
mjuu_mulquat(qtmp, quat, qneg);
|
||||
mjuu_copyvec(quat, qtmp, 4);
|
||||
mjuu_quat2mat(mat, quat);
|
||||
mjuu_mulvecmat(vec, addpos, mat);
|
||||
mjuu_mulvecmat(vec, childpos, mat);
|
||||
pos[0] -= vec[0];
|
||||
pos[1] -= vec[1];
|
||||
pos[2] -= vec[2];
|
||||
|
||||
+11
-7
@@ -104,16 +104,20 @@ void mjuu_z2quat(double* quat, const double* vec);
|
||||
void mjuu_frame2quat(double* quat, const double* x, const double* y, const double* z);
|
||||
|
||||
// invert frame transformation
|
||||
void mjuu_frameinvert(double* newpos, double* newquat,
|
||||
const double* oldpos, const double* oldquat);
|
||||
void mjuu_frameinvert(double newpos[3], double newquat[4],
|
||||
const double oldpos[3], const double oldquat[4]);
|
||||
|
||||
// accumulate frame transformations
|
||||
void mjuu_frameaccum(double* pos, double* quat,
|
||||
const double* addpos, const double* addquat);
|
||||
// accumulate frame transformation into parent frame
|
||||
void mjuu_frameaccum(double pos[3], double quat[4],
|
||||
const double childpos[3], const double childquat[4]);
|
||||
|
||||
// accumulate frame transformation into child frame
|
||||
void mjuu_frameaccumChild(const double pos[3], const double quat[4],
|
||||
double childpos[3], double childquat[4]);
|
||||
|
||||
// invert frame accumulation
|
||||
void mjuu_frameaccuminv(double* pos, double* quat,
|
||||
const double* addpos, const double* addquat);
|
||||
void mjuu_frameaccuminv(double pos[3], double quat[4],
|
||||
const double childpos[3], const double childquat[4]);
|
||||
|
||||
// convert local_inertia[3] to global_inertia[6]
|
||||
void mjuu_globalinertia(double* global, const double* local, const double* quat);
|
||||
|
||||
@@ -1404,38 +1404,47 @@ TEST_F(MujocoTest, Frame) {
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<frame euler="0 0 30">
|
||||
<geom size=".1" euler="0 0 20"/>
|
||||
<geom name="0" size=".1" euler="0 0 20"/>
|
||||
</frame>
|
||||
|
||||
<frame axisangle="0 0 1 90">
|
||||
<frame axisangle="0 1 0 90">
|
||||
<geom size=".1"/>
|
||||
<frame axisangle="0 1 0 90">
|
||||
<frame axisangle="0 0 1 90">
|
||||
<geom name="1" size=".1"/>
|
||||
</frame>
|
||||
</frame>
|
||||
|
||||
<body>
|
||||
<frame pos="0 1 0">
|
||||
<geom size=".1" pos="0 1 0"/>
|
||||
<geom name="3" size=".1" pos="0 1 0"/>
|
||||
<body pos="1 0 0">
|
||||
<geom size=".1" pos="0 0 1"/>
|
||||
<geom name="4" size=".1" pos="0 0 1"/>
|
||||
</body>
|
||||
</frame>
|
||||
</body>
|
||||
|
||||
<body>
|
||||
<geom size=".1"/>
|
||||
<geom name="5" size=".1"/>
|
||||
<frame euler="90 0 0">
|
||||
<joint type="hinge" axis="0 0 1"/>
|
||||
</frame>
|
||||
</body>
|
||||
|
||||
<body pos="0 1 0" euler="0 20 0">
|
||||
<geom name="6" pos=".5 .6 .7" size=".1" euler="30 0 0"/>
|
||||
</body>
|
||||
|
||||
<frame pos="0 1 0" euler="0 20 0">
|
||||
<geom name="2" pos=".5 .6 .7" size=".1" euler="30 0 0"/>
|
||||
</frame>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
|
||||
)";
|
||||
constexpr mjtNum eps = 1e-14;
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, testing::NotNull()) << error.data();
|
||||
EXPECT_EQ(m->nbody, 4);
|
||||
EXPECT_EQ(m->nbody, 5);
|
||||
|
||||
// geom quat transformed to euler = 0 0 50
|
||||
EXPECT_NEAR(m->geom_quat[0], mju_cos(25. * mjPI / 180.), 1e-3);
|
||||
@@ -1444,15 +1453,15 @@ TEST_F(MujocoTest, Frame) {
|
||||
EXPECT_NEAR(m->geom_quat[3], mju_sin(25. * mjPI / 180.), 1e-3);
|
||||
|
||||
// geom transformed to frame 0 1 0, 0 0 1, 1 0 0
|
||||
EXPECT_NEAR(m->geom_quat[4], .5, 1e-6);
|
||||
EXPECT_NEAR(m->geom_quat[5], .5, 1e-6);
|
||||
EXPECT_NEAR(m->geom_quat[6], .5, 1e-6);
|
||||
EXPECT_NEAR(m->geom_quat[7], .5, 1e-6);
|
||||
EXPECT_NEAR(m->geom_quat[4], .5, eps);
|
||||
EXPECT_NEAR(m->geom_quat[5], .5, eps);
|
||||
EXPECT_NEAR(m->geom_quat[6], .5, eps);
|
||||
EXPECT_NEAR(m->geom_quat[7], .5, eps);
|
||||
|
||||
// geom pos transformed from 0 1 0 to 0 2 0
|
||||
EXPECT_EQ(m->geom_pos[6], 0);
|
||||
EXPECT_EQ(m->geom_pos[7], 2);
|
||||
EXPECT_EQ(m->geom_pos[8], 0);
|
||||
EXPECT_EQ(m->geom_pos[ 9], 0);
|
||||
EXPECT_EQ(m->geom_pos[10], 2);
|
||||
EXPECT_EQ(m->geom_pos[11], 0);
|
||||
|
||||
// body pos transformed from 1 0 0 to 1 1 0
|
||||
EXPECT_EQ(m->body_pos[6], 1);
|
||||
@@ -1460,16 +1469,29 @@ TEST_F(MujocoTest, Frame) {
|
||||
EXPECT_EQ(m->body_pos[8], 0);
|
||||
|
||||
// nested geom pos not transformed
|
||||
EXPECT_EQ(m->geom_pos[ 9], 0);
|
||||
EXPECT_EQ(m->geom_pos[10], 0);
|
||||
EXPECT_EQ(m->geom_pos[11], 1);
|
||||
EXPECT_EQ(m->geom_pos[12], 0);
|
||||
EXPECT_EQ(m->geom_pos[13], 0);
|
||||
EXPECT_EQ(m->geom_pos[14], 1);
|
||||
|
||||
// joint axis transformed to 0 -1 0
|
||||
EXPECT_NEAR(m->jnt_axis[0], 0, 1e-6);
|
||||
EXPECT_NEAR(m->jnt_axis[1], -1, 1e-6);
|
||||
EXPECT_NEAR(m->jnt_axis[2], 0, 1e-6);
|
||||
EXPECT_NEAR(m->jnt_axis[0], 0, eps);
|
||||
EXPECT_NEAR(m->jnt_axis[1], -1, eps);
|
||||
EXPECT_NEAR(m->jnt_axis[2], 0, eps);
|
||||
|
||||
mjData* d = mj_makeData(m);
|
||||
mj_kinematics(m, d);
|
||||
|
||||
// body and frame equivalence geom 2 vs 6
|
||||
EXPECT_NEAR(d->geom_xpos[6], d->geom_xpos[18], eps);
|
||||
EXPECT_NEAR(d->geom_xpos[7], d->geom_xpos[19], eps);
|
||||
EXPECT_NEAR(d->geom_xpos[8], d->geom_xpos[20], eps);
|
||||
EXPECT_NEAR(d->geom_xmat[18], d->geom_xmat[54], eps);
|
||||
EXPECT_NEAR(d->geom_xmat[19], d->geom_xmat[55], eps);
|
||||
EXPECT_NEAR(d->geom_xmat[20], d->geom_xmat[56], eps);
|
||||
EXPECT_NEAR(d->geom_xmat[21], d->geom_xmat[57], eps);
|
||||
|
||||
mj_deleteModel(m);
|
||||
mj_deleteData(d);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user