diff --git a/src/three_D_tools.h b/src/three_D_tools.h new file mode 100644 index 0000000000000000000000000000000000000000..eaec7185ce9b8ad68767cbbde204538794a23c48 --- /dev/null +++ b/src/three_D_tools.h @@ -0,0 +1,383 @@ +/* + * three_D_tools.h + * + * Created on: Mar 15, 2018 + * Author: jsola + */ + +#ifndef THREE_D_TOOLS_H_ +#define THREE_D_TOOLS_H_ + + +#include "wolf.h" +#include "rotations.h" + +/* + * Most functions in this file are explained in the document: + * + * Joan Sola, "IMU pre-integration", 2015-2017 IRI-CSIC + * + * They relate manipulations of Delta motion magnitudes used for IMU pre-integration. + * + * The Delta is defined as + * Delta = [Dp, Dq, Dv] + * with + * Dp : position delta + * Dq : quaternion delta + * Dv : velocity delta + * + * They are listed below: + * + * - identity: I = Delta at the origin, with Dp = [0,0,0]; Dq = [0,0,0,1], Dv = [0,0,0] + * - inverse: so that D (+) D.inv = I + * - compose: Dc = D1 (+) D2 + * - between: Db = D2 (-) D1, so that D2 = D1 (+) Db + * - composeOverState: x2 = x1 (+) D + * - betweenStates: D = x2 (-) x1, so that x2 = x1 (+) D + * - lift: got from Delta manifold to tangent space (equivalent to log() in rotations) + * - retract: go from tangent space to delta manifold (equivalent to exp() in rotations) + * - plus: D2 = D1 (+) retract(d) + * - diff: d = lift( D2 (-) D1 ) + * - body2delta: construct a delta from body magnitudes of linAcc and angVel + */ + + + +namespace wolf +{ +namespace three_D { +using namespace Eigen; + +template<typename D1, typename D2> +inline void identity(MatrixBase<D1>& p, QuaternionBase<D2>& q) +{ + p = MatrixBase<D1>::Zero(3,1); + q = QuaternionBase<D2>::Identity(); +} + +template<typename D1, typename D2> +inline void identity(MatrixBase<D1>& p, MatrixBase<D2>& q) +{ + typedef typename D1::Scalar T1; + typedef typename D2::Scalar T2; + p << T1(0), T1(0), T1(0); + q << T2(0), T2(0), T2(0), T2(1); +} + +template<typename T = wolf::Scalar> +inline Matrix<T, 7, 1> identity() +{ + Matrix<T, 7, 1> ret; + ret<< T(0), T(0), T(0), + T(0), T(0), T(0), T(1); + return ret; +} + +template<typename D1, typename D2, typename D4, typename D5> +inline void inverse(const MatrixBase<D1>& dp, const QuaternionBase<D2>& dq, + MatrixBase<D4>& idp, QuaternionBase<D5>& idq) +{ + MatrixSizeCheck<3, 1>::check(dp); + MatrixSizeCheck<3, 1>::check(idp); + + idp = - ( dq.conjugate() * dp ); + idq = dq.conjugate(); +} + +template<typename D1, typename D2> +inline void inverse(const MatrixBase<D1>& d, + MatrixBase<D2>& id) +{ + MatrixSizeCheck<7, 1>::check(d); + MatrixSizeCheck<7, 1>::check(id); + + Map<const Matrix<typename D1::Scalar, 3, 1> > dp ( & d( 0 ) ); + Map<const Quaternion<typename D1::Scalar> > dq ( & d( 3 ) ); + Map<Matrix<typename D2::Scalar, 3, 1> > idp ( & id( 0 ) ); + Map<Quaternion<typename D2::Scalar> > idq ( & id( 3 ) ); + + inverse(dp, dq, idp, idq); +} + + +template<typename D> +inline Matrix<typename D::Scalar, 7, 1> inverse(const MatrixBase<D>& d) +{ + Matrix<typename D::Scalar, 7, 1> id; + inverse(d, id); + return id; +} + +template<typename D1, typename D2, typename D4, typename D5, typename D7, typename D8, typename D6> +inline void compose(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, + const MatrixBase<D4>& dp2, const QuaternionBase<D5>& dq2, + MatrixBase<D7>& sum_p, QuaternionBase<D8>& sum_q ) +{ + MatrixSizeCheck<3, 1>::check(dp1); + MatrixSizeCheck<3, 1>::check(dp2); + MatrixSizeCheck<3, 1>::check(sum_p); + + sum_p = dp1 + dq1*dp2; + sum_q = dq1*dq2; // dq here to avoid possible aliasing between d1 and sum +} + +template<typename D1, typename D2, typename D3> +inline void compose(const MatrixBase<D1>& d1, + const MatrixBase<D2>& d2, + MatrixBase<D3>& sum) +{ + MatrixSizeCheck<7, 1>::check(d1); + MatrixSizeCheck<7, 1>::check(d2); + MatrixSizeCheck<7, 1>::check(sum); + + Map<const Matrix<typename D1::Scalar, 3, 1> > dp1 ( & d1( 0 ) ); + Map<const Quaternion<typename D1::Scalar> > dq1 ( & d1( 3 ) ); + Map<const Matrix<typename D2::Scalar, 3, 1> > dp2 ( & d2( 0 ) ); + Map<const Quaternion<typename D2::Scalar> > dq2 ( & d2( 3 ) ); + Map<Matrix<typename D3::Scalar, 3, 1> > sum_p ( & sum( 0 ) ); + Map<Quaternion<typename D3::Scalar> > sum_q ( & sum( 3 ) ); + + compose(dp1, dq1, dp2, dq2, sum_p, sum_q); +} + +template<typename D1, typename D2> +inline Matrix<typename D1::Scalar, 7, 1> compose(const MatrixBase<D1>& d1, + const MatrixBase<D2>& d2 ) +{ + Matrix<typename D1::Scalar, 7, 1> ret; + compose(d1, d2, ret); + return ret; +} + +template<typename D1, typename D2, typename D3, typename D4, typename D5> +inline void compose(const MatrixBase<D1>& d1, + const MatrixBase<D2>& d2, + MatrixBase<D3>& sum, + MatrixBase<D4>& J_sum_d1, + MatrixBase<D5>& J_sum_d2) +{ + MatrixSizeCheck<7, 1>::check(d1); + MatrixSizeCheck<7, 1>::check(d2); + MatrixSizeCheck<7, 1>::check(sum); + MatrixSizeCheck< 6, 6>::check(J_sum_d1); + MatrixSizeCheck< 6, 6>::check(J_sum_d2); + + // Some useful temporaries + Matrix<typename D1::Scalar, 3, 3> dR1 = q2R(d1.segment(3,4)); //dq1.matrix(); // First Delta, DR + Matrix<typename D2::Scalar, 3, 3> dR2 = q2R(d2.segment(3,4)); //dq2.matrix(); // Second delta, dR + + // Jac wrt first delta + J_sum_d1.setIdentity(); // dDp'/dDp = dDv'/dDv = I + J_sum_d1.block(0,3,3,3).noalias() = - dR1 * skew(d2.head(3)) ; // dDp'/dDo + J_sum_d1.block(3,3,3,3) = dR2.transpose(); // dDo'/dDo + + // Jac wrt second delta + J_sum_d2.setIdentity(); // + J_sum_d2.block(0,0,3,3) = dR1; // dDp'/ddp + // J_sum_d2.block(3,3,3,3) = Matrix3s::Identity(); // dDo'/ddo = I + + // compose deltas -- done here to avoid aliasing when calling with input `d1` and result `sum` referencing the same variable + compose(d1, d2, sum); +} + +template<typename D1, typename D2, typename D4, typename D5, typename D7, typename D8, typename D6> +inline void between(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, + const MatrixBase<D4>& dp2, const QuaternionBase<D5>& dq2, + MatrixBase<D7>& diff_p, QuaternionBase<D8>& diff_q) +{ + MatrixSizeCheck<3, 1>::check(dp1); + MatrixSizeCheck<3, 1>::check(dp2); + MatrixSizeCheck<3, 1>::check(diff_p); + + diff_p = dq1.conjugate() * ( dp2 - dp1 ); + diff_q = dq1.conjugate() * dq2; +} + +template<typename D1, typename D2, typename D3> +inline void between(const MatrixBase<D1>& d1, + const MatrixBase<D2>& d2, + MatrixBase<D3>& d2_minus_d1) +{ + MatrixSizeCheck<7, 1>::check(d1); + MatrixSizeCheck<7, 1>::check(d2); + MatrixSizeCheck<7, 1>::check(d2_minus_d1); + + Map<const Matrix<typename D1::Scalar, 3, 1> > dp1 ( & d1(0) ); + Map<const Quaternion<typename D1::Scalar> > dq1 ( & d1(3) ); + Map<const Matrix<typename D2::Scalar, 3, 1> > dp2 ( & d2(0) ); + Map<const Quaternion<typename D2::Scalar> > dq2 ( & d2(3) ); + Map<Matrix<typename D3::Scalar, 3, 1> > diff_p ( & d2_minus_d1(0) ); + Map<Quaternion<typename D3::Scalar> > diff_q ( & d2_minus_d1(3) ); + + between(dp1, dq1, dp2, dq2, diff_p, diff_q); +} + + +template<typename D1, typename D2> +inline Matrix<typename D1::Scalar, 7, 1> between(const MatrixBase<D1>& d1, + const MatrixBase<D2>& d2 ) +{ + Matrix<typename D1::Scalar, 7, 1> diff; + between(d1, d2, diff); + return diff; +} + +template<typename Derived> +Matrix<typename Derived::Scalar, 6, 1> lift(const MatrixBase<Derived>& delta_in) +{ + MatrixSizeCheck<7, 1>::check(delta_in); + + Matrix<typename Derived::Scalar, 6, 1> ret; + + Map<const Matrix<typename Derived::Scalar, 3, 1> > dp_in ( & delta_in(0) ); + Map<const Quaternion<typename Derived::Scalar> > dq_in ( & delta_in(3) ); + Map<Matrix<typename Derived::Scalar, 3, 1> > dp_ret ( & ret(0) ); + Map<Matrix<typename Derived::Scalar, 3, 1> > do_ret ( & ret(3) ); + + dp_ret = dp_in; + do_ret = log_q(dq_in); + + return ret; +} + +template<typename Derived> +Matrix<typename Derived::Scalar, 7, 1> retract(const MatrixBase<Derived>& d_in) +{ + MatrixSizeCheck<6, 1>::check(d_in); + + Matrix<typename Derived::Scalar, 7, 1> ret; + + Map<const Matrix<typename Derived::Scalar, 3, 1> > dp_in ( & d_in(0) ); + Map<const Matrix<typename Derived::Scalar, 3, 1> > do_in ( & d_in(3) ); + Map<Matrix<typename Derived::Scalar, 3, 1> > dp ( & ret(0) ); + Map<Quaternion<typename Derived::Scalar> > dq ( & ret(3) ); + + dp = dp_in; + dq = exp_q(do_in); + + return ret; +} + +template<typename D1, typename D2, typename D4, typename D5, typename D7, typename D8, typename D6> +inline void plus(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, + const MatrixBase<D4>& dp2, const MatrixBase<D5>& do2, + MatrixBase<D7>& plus_p, QuaternionBase<D8>& plus_q) +{ + plus_p = dp1 + dp2; + plus_q = dq1 * exp_q(do2); +} + +template<typename D1, typename D2, typename D3> +inline void plus(const MatrixBase<D1>& d1, + const MatrixBase<D2>& d2, + MatrixBase<D3>& d_pert) +{ + Map<const Matrix<typename D1::Scalar, 3, 1> > dp1 ( & d1(0) ); + Map<const Quaternion<typename D1::Scalar> > dq1 ( & d1(3) ); + Map<const Matrix<typename D2::Scalar, 3, 1> > dp2 ( & d2(0) ); + Map<const Matrix<typename D2::Scalar, 3, 1> > do2 ( & d2(3) ); + Map<Matrix<typename D3::Scalar, 3, 1> > dp_p ( & d_pert(0) ); + Map<Quaternion<typename D3::Scalar> > dq_p ( & d_pert(3) ); + + plus(dp1, dq1, dp2, do2, dp_p, dq_p); +} + +template<typename D1, typename D2> +inline Matrix<typename D1::Scalar, 7, 1> plus(const MatrixBase<D1>& d1, + const MatrixBase<D2>& d2) +{ + Matrix<typename D1::Scalar, 7, 1> ret; + plus(d1, d2, ret); + return ret; +} + +template<typename D1, typename D2, typename D4, typename D5, typename D7, typename D8> +inline void diff(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, + const MatrixBase<D4>& dp2, const QuaternionBase<D5>& dq2, + MatrixBase<D7>& diff_p, MatrixBase<D8>& diff_o ) +{ + diff_p = dp2 - dp1; + diff_o = log_q(dq1.conjugate() * dq2); +} + +template<typename D1, typename D2, typename D4, typename D5, typename D6, typename D7, typename D8, typename D9> +inline void diff(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, + const MatrixBase<D4>& dp2, const QuaternionBase<D5>& dq2, + MatrixBase<D6>& diff_p, MatrixBase<D7>& diff_o, + MatrixBase<D8>& J_do_dq1, MatrixBase<D9>& J_do_dq2) +{ + diff(dp1, dq1, dp2, dq2, diff_p, diff_o); + + J_do_dq1 = - jac_SO3_left_inv(diff_o); + J_do_dq2 = jac_SO3_right_inv(diff_o); +} + + +template<typename D1, typename D2, typename D3> +inline void diff(const MatrixBase<D1>& d1, + const MatrixBase<D2>& d2, + MatrixBase<D3>& err) +{ + Map<const Matrix<typename D1::Scalar, 3, 1> > dp1 ( & d1(0) ); + Map<const Quaternion<typename D1::Scalar> > dq1 ( & d1(3) ); + Map<const Matrix<typename D2::Scalar, 3, 1> > dp2 ( & d2(0) ); + Map<const Quaternion<typename D2::Scalar> > dq2 ( & d2(3) ); + Map<Matrix<typename D3::Scalar, 3, 1> > diff_p ( & err(0) ); + Map<Matrix<typename D3::Scalar, 3, 1> > diff_o ( & err(3) ); + + diff(dp1, dq1, dp2, dq2, diff_p, diff_o); +} + +template<typename D1, typename D2, typename D3, typename D4, typename D5> +inline void diff(const MatrixBase<D1>& d1, + const MatrixBase<D2>& d2, + MatrixBase<D3>& dif, + MatrixBase<D4>& J_diff_d1, + MatrixBase<D5>& J_diff_d2) +{ + Map<const Matrix<typename D1::Scalar, 3, 1> > dp1 ( & d1(0) ); + Map<const Quaternion<typename D1::Scalar> > dq1 ( & d1(3) ); + Map<const Matrix<typename D1::Scalar, 3, 1> > dv1 ( & d1(7) ); + Map<const Matrix<typename D2::Scalar, 3, 1> > dp2 ( & d2(0) ); + Map<const Quaternion<typename D2::Scalar> > dq2 ( & d2(3) ); + Map<const Matrix<typename D2::Scalar, 3, 1> > dv2 ( & d2(7) ); + Map<Matrix<typename D3::Scalar, 3, 1> > diff_p ( & dif(0) ); + Map<Matrix<typename D3::Scalar, 3, 1> > diff_o ( & dif(3) ); + Map<Matrix<typename D3::Scalar, 3, 1> > diff_v ( & dif(6) ); + + Matrix<typename D4::Scalar, 3, 3> J_do_dq1, J_do_dq2; + + diff(dp1, dq1, dv1, dp2, dq2, dv2, diff_p, diff_o, diff_v, J_do_dq1, J_do_dq2); + + /* d = diff(d1, d2) is + * dp = dp2 - dp1 + * do = Log(dq1.conj * dq2) + * dv = dv2 - dv1 + * + * With trivial Jacobians for dp and dv, and: + * J_do_dq1 = - J_l_inv(theta) + * J_do_dq2 = J_r_inv(theta) + */ + + J_diff_d1 = - Matrix<typename D4::Scalar, 6, 6>::Identity();// d(p2 - p1) / d(p1) = - Identity + J_diff_d1.block(3,3,3,3) = J_do_dq1; // d(R1.tr*R2) / d(R1) = - J_l_inv(theta) + + J_diff_d2.setIdentity(); // d(R1.tr*R2) / d(R2) = Identity + J_diff_d2.block(3,3,3,3) = J_do_dq2; // d(R1.tr*R2) / d(R1) = J_r_inv(theta) +} + +template<typename D1, typename D2> +inline Matrix<typename D1::Scalar, 6, 1> diff(const MatrixBase<D1>& d1, + const MatrixBase<D2>& d2) +{ + Matrix<typename D1::Scalar, 6, 1> ret; + diff(d1, d2, ret); + return ret; +} + + +} // namespace three_d +} // namespace wolf + + +#endif /* THREE_D_TOOLS_H_ */