@@ -493,9 +493,16 @@ inline void predict(fuse_core::Vector3d const& position1, Eigen::Quaterniond con
493493 vel_linear2.y (), vel_linear2.z (), vel_angular2.x (), vel_angular2.y (), vel_angular2.z (), acc_linear2.x (),
494494 acc_linear2.y (), acc_linear2.z (), jacobians.data (), jacobian_quat2rpy);
495495
496- // TODO(henrygerardmoore): figure out how to fix this
497- // see https://github.com/locusrobotics/fuse/pull/354#discussion_r1884288806
498- jacobian << J[0 ], J[1 ], J[2 ], J[3 ], J[4 ].block <15 , 2 >(0 , 0 );
496+ // Convert J[1] from quaternion space (15x4) to RPY space (15x3) using the
497+ // pseudo-inverse of the quaternion-to-RPY Jacobian.
498+ // Chain rule: J[1] = d(state2)/d(quat1) = d(state2)/d(rpy1) * d(rpy)/d(quat)
499+ // So: d(state2)/d(rpy1) = J[1] * pinv(d(rpy)/d(quat))
500+ Eigen::Map<fuse_core::Matrix<double , 3 , 4 >> j_quat2rpy_map (jacobian_quat2rpy);
501+ fuse_core::Matrix<double , 4 , 3 > j_quat2rpy_pinv =
502+ j_quat2rpy_map.transpose () * (j_quat2rpy_map * j_quat2rpy_map.transpose ()).inverse ();
503+ fuse_core::Matrix<double , 15 , 3 > J1_rpy = J[1 ] * j_quat2rpy_pinv;
504+
505+ jacobian << J[0 ], J1_rpy, J[2 ], J[3 ], J[4 ];
499506
500507 // Convert back to quaternion
501508 orientation2 = Eigen::AngleAxisd (rpy[2 ], Eigen::Vector3d::UnitZ ()) *
0 commit comments