diff --git a/doc/changelog.rst b/doc/changelog.rst index 65a668ef..c2361990 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -2,6 +2,14 @@ Changelog ========= +Upcoming version (not yet released) +----------------------------------- + +Bug fixes +^^^^^^^^^ +- :ref:`mj_jacDot` was missing a term that accounts for the motion of the point with respect to + which the Jacobian is computed, now fixed. + Version 3.3.0 (Feb 26, 2025) ---------------------------- diff --git a/src/engine/engine_core_smooth.c b/src/engine/engine_core_smooth.c index 2e8cf8bb..9b453c3e 100644 --- a/src/engine/engine_core_smooth.c +++ b/src/engine/engine_core_smooth.c @@ -1893,7 +1893,7 @@ void mj_comVel(const mjModel* m, mjData* d) { // assign cvel, cdofdot mju_copy(d->cvel+6*i, cvel, 6); - mju_copy(d->cdof_dot+6*bda, cdofdot, 6*m->body_dofnum[i]); + mju_copy(d->cdof_dot+6*bda, cdofdot, 6*dofnum); } } diff --git a/src/engine/engine_support.c b/src/engine/engine_support.c index 60e05973..4f5d06af 100644 --- a/src/engine/engine_support.c +++ b/src/engine/engine_support.c @@ -811,11 +811,14 @@ void mj_jacDot(const mjModel* m, const mjData* d, mjtNum* jacp, mjtNum* jacr, const mjtNum point[3], int body) { int nv = m->nv; mjtNum offset[3]; + mjtNum pvel[6]; // point velocity (rot:lin order) - // clear jacobians, compute offset if required + // clear jacobians, compute offset and pvel if required if (jacp) { mju_zero(jacp, 3*nv); - mju_sub3(offset, point, d->subtree_com+3*m->body_rootid[body]); + const mjtNum* com = d->subtree_com+3*m->body_rootid[body]; + mju_sub3(offset, point, com); + mju_transformSpatial(pvel, d->cvel+6*body, 0, point, com, 0); } if (jacr) { mju_zero(jacr, 3*nv); @@ -838,6 +841,7 @@ void mj_jacDot(const mjModel* m, const mjData* d, while (i >= 0) { mjtNum cdof_dot[6]; mju_copy(cdof_dot, d->cdof_dot+6*i, 6); + mjtNum* cdof = d->cdof+6*i; // check for quaternion mjtJoint type = m->jnt_type[m->dof_jntid[i]]; @@ -846,7 +850,7 @@ void mj_jacDot(const mjModel* m, const mjData* d, // compute cdof_dot for quaternion (use current body cvel) if (is_quat) { - mju_crossMotion(cdof_dot, d->cvel+6*m->dof_bodyid[i], d->cdof+6*i); + mju_crossMotion(cdof_dot, d->cvel+6*m->dof_bodyid[i], cdof); } // construct rotation jacobian @@ -858,11 +862,17 @@ void mj_jacDot(const mjModel* m, const mjData* d, // construct translation jacobian (correct for rotation) if (jacp) { - mjtNum tmp[3] = {0}; - mju_cross(tmp, cdof_dot, offset); - jacp[i+0*nv] += cdof_dot[3] + tmp[0]; - jacp[i+1*nv] += cdof_dot[4] + tmp[1]; - jacp[i+2*nv] += cdof_dot[5] + tmp[2]; + // first correction term, account for varying cdof + mjtNum tmp1[3]; + mju_cross(tmp1, cdof_dot, offset); + + // second correction term, account for point translational velocity + mjtNum tmp2[3]; + mju_cross(tmp2, cdof, pvel + 3); + + jacp[i+0*nv] += cdof_dot[3] + tmp1[0] + tmp2[0]; + jacp[i+1*nv] += cdof_dot[4] + tmp1[1] + tmp2[1]; + jacp[i+2*nv] += cdof_dot[5] + tmp1[2] + tmp2[2]; } // advance to parent dof diff --git a/test/engine/engine_support_test.cc b/test/engine/engine_support_test.cc index 20dbfa29..c7d4f018 100644 --- a/test/engine/engine_support_test.cc +++ b/test/engine/engine_support_test.cc @@ -288,6 +288,7 @@ static constexpr char kQuat[] = R"(