Skip to content
Snippets Groups Projects
IMU_tools.h 24.24 KiB
/*
 * imu_tools.h
 *
 *  Created on: Jul 29, 2017
 *      Author: jsola
 */

#ifndef IMU_TOOLS_H_
#define IMU_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 imu {
using namespace Eigen;

template<typename D1, typename D2, typename D3>
inline void identity(MatrixBase<D1>& p, QuaternionBase<D2>& q, MatrixBase<D3>& v)
{
    p = MatrixBase<D1>::Zero(3,1);
    q = QuaternionBase<D2>::Identity();
    v = MatrixBase<D3>::Zero(3,1);
}

template<typename D1, typename D2, typename D3>
inline void identity(MatrixBase<D1>& p, MatrixBase<D2>& q, MatrixBase<D3>& v)
{
    typedef typename D1::Scalar T1;
    typedef typename D2::Scalar T2;
    typedef typename D3::Scalar T3;
    p << T1(0), T1(0), T1(0);
    q << T2(0), T2(0), T2(0), T2(1);
    v << T3(0), T3(0), T3(0);
}

template<typename T = wolf::Scalar>
inline Matrix<T, 10, 1> identity()
{
    Matrix<T, 10, 1> ret;
    ret<< T(0), T(0), T(0),
          T(0), T(0), T(0), T(1),
          T(0), T(0), T(0);
    return ret;
}

template<typename D1, typename D2, typename D3, typename D4, typename D5, typename D6, class T>
inline void inverse(const MatrixBase<D1>& dp, const QuaternionBase<D2>& dq, const MatrixBase<D3>& dv,
                    const T dt,
                    MatrixBase<D4>& idp, QuaternionBase<D5>& idq, MatrixBase<D6>& idv )
{
    MatrixSizeCheck<3, 1>::check(dp);
    MatrixSizeCheck<3, 1>::check(dv);
    MatrixSizeCheck<3, 1>::check(idp);
    MatrixSizeCheck<3, 1>::check(idv);

    idp = - ( dq.conjugate() * (dp - dv * typename D3::Scalar(dt) ) );
    idq =     dq.conjugate();
    idv = - ( dq.conjugate() * dv );
}

template<typename D1, typename D2, class T>
inline void inverse(const MatrixBase<D1>& d,
                    T dt,
                    MatrixBase<D2>& id)
{
    MatrixSizeCheck<10, 1>::check(d);
    MatrixSizeCheck<10, 1>::check(id);

    Map<const Matrix<typename D1::Scalar, 3, 1> >   dp   ( & d( 0 ) );
    Map<const Quaternion<typename D1::Scalar> >     dq   ( & d( 3 ) );
    Map<const Matrix<typename D1::Scalar, 3, 1> >   dv   ( & d( 7 ) );
    Map<Matrix<typename D2::Scalar, 3, 1> >         idp  ( & id( 0 ) );
    Map<Quaternion<typename D2::Scalar> >           idq  ( & id( 3 ) );
    Map<Matrix<typename D2::Scalar, 3, 1> >         idv  ( & id( 7 ) );

    inverse(dp, dq, dv, dt, idp, idq, idv);
}


template<typename D, class T>
inline Matrix<typename D::Scalar, 10, 1> inverse(const MatrixBase<D>& d,
                                                 T dt)
{
    Matrix<typename D::Scalar, 10, 1> id;
    inverse(d, dt, id);
    return id;
}

template<typename D1, typename D2, typename D3, typename D4, typename D5, typename D6, typename D7, typename D8, typename D9, class T>
inline void compose(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, const MatrixBase<D3>& dv1,
                    const MatrixBase<D4>& dp2, const QuaternionBase<D5>& dq2, const MatrixBase<D6>& dv2,
                    const T dt,
                    MatrixBase<D7>& sum_p, QuaternionBase<D8>& sum_q, MatrixBase<D9>& sum_v )
{
        MatrixSizeCheck<3, 1>::check(dp1);
        MatrixSizeCheck<3, 1>::check(dv1);
        MatrixSizeCheck<3, 1>::check(dp2);
        MatrixSizeCheck<3, 1>::check(dv2);
        MatrixSizeCheck<3, 1>::check(sum_p);
        MatrixSizeCheck<3, 1>::check(sum_v);

        sum_p = dp1 + dv1*dt + dq1*dp2;
        sum_v = dv1 +          dq1*dv2;
        sum_q =                dq1*dq2; // dq here to avoid possible aliasing between d1 and sum
}
template<typename D1, typename D2, typename D3, class T>
inline void compose(const MatrixBase<D1>& d1,
                    const MatrixBase<D2>& d2,
                    T dt,
                    MatrixBase<D3>& sum)
{
    MatrixSizeCheck<10, 1>::check(d1);
    MatrixSizeCheck<10, 1>::check(d2);
    MatrixSizeCheck<10, 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 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> >         sum_p  ( & sum( 0 ) );
    Map<Quaternion<typename D3::Scalar> >           sum_q  ( & sum( 3 ) );
    Map<Matrix<typename D3::Scalar, 3, 1> >         sum_v  ( & sum( 7 ) );

    compose(dp1, dq1, dv1, dp2, dq2, dv2, dt, sum_p, sum_q, sum_v);
}

template<typename D1, typename D2, class T>
inline Matrix<typename D1::Scalar, 10, 1> compose(const MatrixBase<D1>& d1,
                                                  const MatrixBase<D2>& d2,
                                                  T dt)
{
    Matrix<typename D1::Scalar, 10, 1>  ret;
    compose(d1, d2, dt, ret);
    return ret;
}

template<typename D1, typename D2, typename D3, typename D4, typename D5, class T>
inline void compose(const MatrixBase<D1>& d1,
                    const MatrixBase<D2>& d2,
                    T dt,
                    MatrixBase<D3>& sum,
                    MatrixBase<D4>& J_sum_d1,
                    MatrixBase<D5>& J_sum_d2)
{
    MatrixSizeCheck<10, 1>::check(d1);
    MatrixSizeCheck<10, 1>::check(d2);
    MatrixSizeCheck<10, 1>::check(sum);
    MatrixSizeCheck< 9, 9>::check(J_sum_d1);
    MatrixSizeCheck< 9, 9>::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(0,6,3,3) = Matrix3s::Identity() * dt;        // dDp'/dDv = I*dt
    J_sum_d1.block(3,3,3,3) = dR2.transpose();                  // dDo'/dDo
    J_sum_d1.block(6,3,3,3).noalias() = - dR1 * skew(d2.tail(3)) ;     // dDv'/dDo

    // Jac wrt second delta
    J_sum_d2.setIdentity();                                     //
    J_sum_d2.block(0,0,3,3) = dR1;                              // dDp'/ddp
    J_sum_d2.block(6,6,3,3) = dR1;                              // dDv'/ddv
    // 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, dt, sum);
}

template<typename D1, typename D2, typename D3, typename D4, typename D5, typename D6, typename D7, typename D8, typename D9, class T>
inline void between(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, const MatrixBase<D3>& dv1,
                    const MatrixBase<D4>& dp2, const QuaternionBase<D5>& dq2, const MatrixBase<D6>& dv2,
                    const T dt,
                    MatrixBase<D7>& diff_p, QuaternionBase<D8>& diff_q, MatrixBase<D9>& diff_v )
{
        MatrixSizeCheck<3, 1>::check(dp1);
        MatrixSizeCheck<3, 1>::check(dv1);
        MatrixSizeCheck<3, 1>::check(dp2);
        MatrixSizeCheck<3, 1>::check(dv2);
        MatrixSizeCheck<3, 1>::check(diff_p);
        MatrixSizeCheck<3, 1>::check(diff_v);

        diff_p = dq1.conjugate() * ( dp2 - dp1 - dv1*dt );
        diff_v = dq1.conjugate() * ( dv2 - dv1 );
        diff_q = dq1.conjugate() *   dq2;
}

template<typename D1, typename D2, typename D3, class T>
inline void between(const MatrixBase<D1>& d1,
                    const MatrixBase<D2>& d2,
                    T dt,
                    MatrixBase<D3>& d2_minus_d1)
{
    MatrixSizeCheck<10, 1>::check(d1);
    MatrixSizeCheck<10, 1>::check(d2);
    MatrixSizeCheck<10, 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 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 ( & d2_minus_d1(0) );
    Map<Quaternion<typename D3::Scalar> >           diff_q ( & d2_minus_d1(3) );
    Map<Matrix<typename D3::Scalar, 3, 1> >         diff_v ( & d2_minus_d1(7) );

    between(dp1, dq1, dv1, dp2, dq2, dv2, dt, diff_p, diff_q, diff_v);
}


template<typename D1, typename D2, class T>
inline Matrix<typename D1::Scalar, 10, 1> between(const MatrixBase<D1>& d1,
                                                  const MatrixBase<D2>& d2,
                                                  T dt)
{
    Matrix<typename D1::Scalar, 10, 1> diff;
    between(d1, d2, dt, diff);
    return diff;
}

template<typename D1, typename D2, typename D3, class T>
inline void composeOverState(const MatrixBase<D1>& x,
                             const MatrixBase<D2>& d,
                             T dt,
                             MatrixBase<D3>& x_plus_d)
{
    MatrixSizeCheck<10, 1>::check(x);
    MatrixSizeCheck<10, 1>::check(d);
    MatrixSizeCheck<10, 1>::check(x_plus_d);

    Map<const Matrix<typename D1::Scalar, 3, 1> >   p         ( & x( 0 ) );
    Map<const Quaternion<typename D1::Scalar> >     q         ( & x( 3 ) );
    Map<const Matrix<typename D1::Scalar, 3, 1> >   v         ( & x( 7 ) );
    Map<const Matrix<typename D2::Scalar, 3, 1> >   dp        ( & d( 0 ) );
    Map<const Quaternion<typename D2::Scalar> >     dq        ( & d( 3 ) );
    Map<const Matrix<typename D2::Scalar, 3, 1> >   dv        ( & d( 7 ) );
    Map<Matrix<typename D3::Scalar, 3, 1> >         p_plus_d  ( & x_plus_d( 0 ) );
    Map<Quaternion<typename D3::Scalar> >           q_plus_d  ( & x_plus_d( 3 ) );
    Map<Matrix<typename D3::Scalar, 3, 1> >         v_plus_d  ( & x_plus_d( 7 ) );
    p_plus_d = p + v*dt + 0.5*gravity()*dt*dt + q*dp;
    v_plus_d = v +            gravity()*dt    + q*dv;
    q_plus_d =                                  q*dq; // dq here to avoid possible aliasing between x and x_plus_d
}

template<typename D1, typename D2, class T>
inline Matrix<typename D1::Scalar, 10, 1> composeOverState(const MatrixBase<D1>& x,
                                                           const MatrixBase<D2>& d,
                                                           T dt)
{
    Matrix<typename D1::Scalar, 10, 1>  ret;
    composeOverState(x, d, dt, ret);
    return ret;
}

template<typename D1, typename D2, typename D3, typename D4, typename D5, typename D6, typename D7, typename D8, typename D9, class T>
inline void betweenStates(const MatrixBase<D1>& p1, const QuaternionBase<D2>& q1, const MatrixBase<D3>& v1,
                          const MatrixBase<D4>& p2, const QuaternionBase<D5>& q2, const MatrixBase<D6>& v2,
                          const T dt,
                          MatrixBase<D7>& dp, QuaternionBase<D8>& dq, MatrixBase<D9>& dv )
{
        MatrixSizeCheck<3, 1>::check(p1);
        MatrixSizeCheck<3, 1>::check(v1);
        MatrixSizeCheck<3, 1>::check(p2);
        MatrixSizeCheck<3, 1>::check(v2);
        MatrixSizeCheck<3, 1>::check(dp);
        MatrixSizeCheck<3, 1>::check(dv);

        dp = q1.conjugate() * ( p2 - p1 - v1*dt - (T)0.5*gravity().cast<T>()*(T)dt*(T)dt );
        dv = q1.conjugate() * ( v2 - v1         -     gravity().cast<T>()*(T)dt );
        dq = q1.conjugate() *   q2;
}

template<typename D1, typename D2, typename D3, class T>
inline void betweenStates(const MatrixBase<D1>& x1,
                          const MatrixBase<D2>& x2,
                          T dt,
                          MatrixBase<D3>& x2_minus_x1)
{
    MatrixSizeCheck<10, 1>::check(x1);
    MatrixSizeCheck<10, 1>::check(x2);
    MatrixSizeCheck<10, 1>::check(x2_minus_x1);

    Map<const Matrix<typename D1::Scalar, 3, 1> >   p1  ( & x1(0) );
    Map<const Quaternion<typename D1::Scalar> >     q1  ( & x1(3) );
    Map<const Matrix<typename D1::Scalar, 3, 1> >   v1  ( & x1(7) );
    Map<const Matrix<typename D2::Scalar, 3, 1> >   p2  ( & x2(0) );
    Map<const Quaternion<typename D2::Scalar> >     q2  ( & x2(3) );
    Map<const Matrix<typename D2::Scalar, 3, 1> >   v2  ( & x2(7) );
    Map<Matrix<typename D3::Scalar, 3, 1> >         dp  ( & x2_minus_x1(0) );
    Map<Quaternion<typename D3::Scalar> >           dq  ( & x2_minus_x1(3) );
    Map<Matrix<typename D3::Scalar, 3, 1> >         dv  ( & x2_minus_x1(7) );

    betweenStates(p1, q1, v1, p2, q2, v2, dt, dp, dq, dv);
}

template<typename D1, typename D2, class T>
inline Matrix<typename D1::Scalar, 10, 1> betweenStates(const MatrixBase<D1>& x1,
                                                        const MatrixBase<D2>& x2,
                                                        T dt)
{
    Matrix<typename D1::Scalar, 10, 1> ret;
    betweenStates(x1, x2, dt, ret);
    return ret;
}

template<typename Derived>
Matrix<typename Derived::Scalar, 9, 1> lift(const MatrixBase<Derived>& delta_in)
{
    MatrixSizeCheck<10, 1>::check(delta_in);

    Matrix<typename Derived::Scalar, 9, 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<const Matrix<typename Derived::Scalar, 3, 1> >   dv_in  ( & delta_in(7) );
    Map<Matrix<typename Derived::Scalar, 3, 1> >         dp_ret ( & ret(0) );
    Map<Matrix<typename Derived::Scalar, 3, 1> >         do_ret ( & ret(3) );
    Map<Matrix<typename Derived::Scalar, 3, 1> >         dv_ret ( & ret(6) );

    dp_ret = dp_in;
    dv_ret = dv_in;
    do_ret = log_q(dq_in);

    return ret;
}

template<typename Derived>
Matrix<typename Derived::Scalar, 10, 1> retract(const MatrixBase<Derived>& d_in)
{
    MatrixSizeCheck<9, 1>::check(d_in);

    Matrix<typename Derived::Scalar, 10, 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<const Matrix<typename Derived::Scalar, 3, 1> >   dv_in  ( & d_in(6) );
    Map<Matrix<typename Derived::Scalar, 3, 1> >         dp     ( &  ret(0) );
    Map<Quaternion<typename Derived::Scalar> >           dq     ( &  ret(3) );
    Map<Matrix<typename Derived::Scalar, 3, 1> >         dv     ( &  ret(7) );

    dp = dp_in;
    dv = dv_in;
    dq = exp_q(do_in);

    return ret;
}

template<typename D1, typename D2, typename D3, typename D4, typename D5, typename D6, typename D7, typename D8, typename D9>
inline void plus(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, const MatrixBase<D3>& dv1,
                 const MatrixBase<D4>& dp2, const MatrixBase<D5>& do2, const MatrixBase<D6>& dv2,
                 MatrixBase<D7>& plus_p, QuaternionBase<D8>& plus_q, MatrixBase<D9>& plus_v )
{
        plus_p = dp1 + dp2;
        plus_v = dv1 + dv2;
        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 D1::Scalar, 3, 1> >   dv1    ( & d1(7) );
    Map<const Matrix<typename D2::Scalar, 3, 1> >   dp2    ( & d2(0) );
    Map<const Matrix<typename D2::Scalar, 3, 1> >   do2    ( & d2(3) );
    Map<const Matrix<typename D2::Scalar, 3, 1> >   dv2    ( & d2(6) );
    Map<Matrix<typename D3::Scalar, 3, 1> >         dp_p ( & d_pert(0) );
    Map<Quaternion<typename D3::Scalar> >           dq_p ( & d_pert(3) );
    Map<Matrix<typename D3::Scalar, 3, 1> >         dv_p ( & d_pert(7) );

    plus(dp1, dq1, dv1, dp2, do2, dv2, dp_p, dq_p, dv_p);
}

template<typename D1, typename D2>
inline Matrix<typename D1::Scalar, 10, 1> plus(const MatrixBase<D1>& d1,
                                               const MatrixBase<D2>& d2)
{
    Matrix<typename D1::Scalar, 10, 1> ret;
    plus(d1, d2, ret);
    return ret;
}

template<typename D1, typename D2, typename D3, 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<D3>& dv1,
                 const MatrixBase<D4>& dp2, const QuaternionBase<D5>& dq2, const MatrixBase<D6>& dv2,
                 MatrixBase<D7>& diff_p, MatrixBase<D8>& diff_o, MatrixBase<D9>& diff_v )
{
        diff_p = dp2 - dp1;
        diff_v = dv2 - dv1;
        diff_o = log_q(dq1.conjugate() * dq2);
}

template<typename D1, typename D2, typename D3, typename D4, typename D5, typename D6, typename D7, typename D8, typename D9, typename D10, typename D11>
inline void diff(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, const MatrixBase<D3>& dv1,
                 const MatrixBase<D4>& dp2, const QuaternionBase<D5>& dq2, const MatrixBase<D6>& dv2,
                 MatrixBase<D7>& diff_p, MatrixBase<D8>& diff_o, MatrixBase<D9>& diff_v ,
                 MatrixBase<D10>& J_do_dq1, MatrixBase<D11>& J_do_dq2)
{
    diff(dp1, dq1, dv1, dp2, dq2, dv2, diff_p, diff_o, diff_v);

    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 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 ( & err(0) );
    Map<Matrix<typename D3::Scalar, 3, 1> >         diff_o ( & err(3) );
    Map<Matrix<typename D3::Scalar, 3, 1> >         diff_v ( & err(6) );

    diff(dp1, dq1, dv1, dp2, dq2, dv2, diff_p, diff_o, diff_v);
}

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, 9, 9>::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, 9, 1> diff(const MatrixBase<D1>& d1,
                                              const MatrixBase<D2>& d2)
{
    Matrix<typename D1::Scalar, 9, 1> ret;
    diff(d1, d2, ret);
    return ret;
}


template<typename D1, typename D2, typename D3, typename D4, typename D5>
inline void body2delta(const MatrixBase<D1>& a,
                       const MatrixBase<D2>& w,
                       const typename D1::Scalar& dt,
                       MatrixBase<D3>& dp,
                       QuaternionBase<D4>& dq,
                       MatrixBase<D5>& dv)
{
    MatrixSizeCheck<3,1>::check(a);
    MatrixSizeCheck<3,1>::check(w);
    MatrixSizeCheck<3,1>::check(dp);
    MatrixSizeCheck<3,1>::check(dv);

    dp = 0.5 * a * dt * dt;
    dv =       a * dt;
    dq = exp_q(w * dt);
}

template<typename D1>
inline Matrix<typename D1::Scalar, 10, 1> body2delta(const MatrixBase<D1>& body,
                                                     const typename D1::Scalar& dt)
{
    MatrixSizeCheck<6,1>::check(body);

    typedef typename D1::Scalar T;

    Matrix<T, 10, 1> delta;

    Map< Matrix<T, 3, 1>> dp ( & delta(0) );
    Map< Quaternion<T>>   dq ( & delta(3) );
    Map< Matrix<T, 3, 1>> dv ( & delta(7) );

    body2delta(body.block(0,0,3,1), body.block(3,0,3,1), dt, dp, dq, dv);

    return delta;
}

template<typename D1, typename D2, typename D3>
inline void body2delta(const MatrixBase<D1>& body,
                       const typename D1::Scalar& dt,
                       MatrixBase<D2>& delta,
                       MatrixBase<D3>& jac_body)
{
    MatrixSizeCheck<6,1>::check(body);
    MatrixSizeCheck<9,6>::check(jac_body);
    typedef typename D1::Scalar T;

    delta = body2delta(body, dt);

    Matrix<T, 3, 1> w = body.block(3,0,3,1);

    jac_body.setZero();
    jac_body.block(0,0,3,3) = 0.5 * dt * dt * Matrix<T, 3, 3>::Identity();
    jac_body.block(3,3,3,3) =            dt * jac_SO3_right(w * dt);
    jac_body.block(6,0,3,3) =            dt * Matrix<T, 3, 3>::Identity();
}

template<typename D1, typename D2, typename D3, typename D4, typename D5, typename D6, typename D7>
void motion2data(const MatrixBase<D1>& a, const MatrixBase<D2>& w, const QuaternionBase<D3>& q, const MatrixBase<D4>& a_b, const MatrixBase<D5>& w_b, MatrixBase<D6>& a_m, MatrixBase<D7>& w_m)
{
    MatrixSizeCheck<3,1>::check(a);
    MatrixSizeCheck<3,1>::check(w);
    MatrixSizeCheck<3,1>::check(a_b);
    MatrixSizeCheck<3,1>::check(w_b);
    MatrixSizeCheck<3,1>::check(a_m);
    MatrixSizeCheck<3,1>::check(w_m);

    // Note: data = (a_m , w_m)
    a_m = a + a_b - q.conjugate()*gravity();
    w_m = w + w_b;
}

/* Create IMU data from body motion
 * Input:
 *   motion : [ax, ay, az, wx, wy, wz] the motion in body frame
 *   q      : the current orientation wrt horizontal
 *   bias   : the bias of the IMU
 * Output:
 *   return : the data vector as created by the IMU (with motion, gravity, and bias)
 */
template<typename D1, typename D2, typename D3>
Matrix<typename D1::Scalar, 6, 1> motion2data(const MatrixBase<D1>& motion, const QuaternionBase<D2>& q, const MatrixBase<D3>& bias)
{
    Matrix<typename D1::Scalar, 6, 1>      data;
    Map<Matrix<typename D1::Scalar, 3, 1>> a_m (data.data()    );
    Map<Matrix<typename D1::Scalar, 3, 1>> w_m (data.data() + 3);

    motion2data(motion.block(0,0,3,1),
                motion.block(3,0,3,1),
                q,
                bias.block(0,0,3,1),
                bias.block(3,0,3,1),
                a_m,
                w_m   );

    return  data;
}



} // namespace imu
} // namespace wolf

#endif /* IMU_TOOLS_H_ */