From 9c2efbdbe16b237dab31e4b9a2dce52cf2921173 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Joan=20Sol=C3=A0?= <jsola@iri.upc.edu>
Date: Sun, 12 Nov 2017 23:44:33 +0100
Subject: [PATCH] [WIP] New test for IMU integration

---
 src/test/gtest_constraint_imu.cpp | 207 +++++++++++++++++++++++++-----
 1 file changed, 176 insertions(+), 31 deletions(-)

diff --git a/src/test/gtest_constraint_imu.cpp b/src/test/gtest_constraint_imu.cpp
index 3b4fa894d..325d9b19c 100644
--- a/src/test/gtest_constraint_imu.cpp
+++ b/src/test/gtest_constraint_imu.cpp
@@ -1339,17 +1339,29 @@ class ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRotXY : public testing::Test
     virtual void TearDown(){}
 };
 
-class ConstraintIMU_biasTest_Move_NonNullBias2 : public testing::Test
+class ConstraintIMU_biasTest : public testing::Test
 {
     public:
         ProblemPtr problem;
         SensorIMUPtr sensor_imu;
         ProcessorIMUPtr processor_imu;
-        CaptureIMUPtr capture_imu;
         FrameBasePtr KF_0, KF_1;
+        CaptureBasePtr   C_0;
         CaptureMotionPtr CM_0, CM_1;
+        CaptureIMUPtr capture_imu;
         CeresManagerPtr ceres_manager;
 
+        TimeStamp t0, t;
+        Scalar dt, DT;
+        int num_integrations;
+
+        VectorXs x0;
+        Vector3s p0, v0;
+        Quaternions q0, q;
+        Vector6s motion, data, bias_real, bias_preint, bias_null;
+        Vector3s a, w, am, wm;
+
+
     virtual void SetUp( )
     {
         using std::shared_ptr;
@@ -1374,52 +1386,185 @@ class ConstraintIMU_biasTest_Move_NonNullBias2 : public testing::Test
         sensor_imu    = std::static_pointer_cast<SensorIMU>   (sensor);
         processor_imu = std::static_pointer_cast<ProcessorIMU>(processor);
 
-        // ==================================== INITIAL CONDITIONS
-        TimeStamp t0(0);
-        VectorXs x0(10); x0 << 0,0,0, 0,0,0,1, 0,0,0;
-        MatrixXs P0(9,9); P0.setIdentity() * 0.01;
+        bias_null.setZero();
+
+        x0.resize(10);
 
+    }
+
+    virtual void TearDown( ) { }
+
+    /* 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)
+     */
+    VectorXs motion2data(const VectorXs& body, const Quaternions& q, const VectorXs& bias)
+    {
+        VectorXs data(6);
+        data = body;                                // start with body motion
+        data.head(3) -= q.conjugate()*gravity();    // add -g
+        data = data + bias;                         // add bias
+        return data;
+    }
+
+
+
+    /* Integrate acc and angVel motion, obtain Delta_preintegrated
+     * Input:
+     *   N: number of steps
+     *   q0: initial orientaiton
+     *   motion: [ax, ay, az, wx, wy, wz] as the true magnitudes in body brame
+     *   bias_real: the real bias of the IMU
+     *   bias_preint: the bias used for Delta pre-integration
+     * Output:
+     *   return: the preintegrated delta
+     */
+    VectorXs integrateDelta(int N, const Quaternions& q0, const VectorXs& motion, const VectorXs& bias_real, const VectorXs& bias_preint, Scalar dt)
+    {
+        VectorXs data(6);
+        VectorXs body(6);
+        VectorXs delta(10);
+        VectorXs Delta(10), Delta_plus(10);
+        Delta = imu::identity();
+        Quaternions q(q0);
+        for (int n = 0; n<N; n++)
+        {
+            data        = motion2data(motion, q, bias_real);
+            q           = q*exp_q(motion.tail(3)*dt);
+            body        = data - bias_preint;
+            delta       = imu::body2delta(body, dt);
+            Delta_plus  = imu::compose(Delta, delta, dt);
+            Delta       = Delta_plus;
+        }
+        return Delta;
+    }
+
+    /* Integrate acc and angVel motion, obtain Delta_preintegrated
+     * Input:
+     *   N: number of steps
+     *   q0: initial orientaiton
+     *   motion: [ax, ay, az, wx, wy, wz] as the true magnitudes in body brame
+     *   bias_real: the real bias of the IMU
+     *   bias_preint: the bias used for Delta pre-integration
+     * Output:
+     *   J_D_b: the Jacobian of the preintegrated delta wrt the bias
+     *   return: the preintegrated delta
+     */
+    VectorXs integrateDelta(int N, const Quaternions& q0, const VectorXs& motion, const VectorXs& bias_real, const VectorXs& bias_preint, Scalar dt, Matrix<Scalar, 9, 6>& J_D_b)
+    {
+        VectorXs data(6);
+        VectorXs body(6);
+        VectorXs delta(10);
+        Matrix<Scalar, 9, 6> J_d_d, J_d_b;
+        Matrix<Scalar, 9, 9> J_D_D, J_D_d;
+        VectorXs Delta(10), Delta_plus(10);
+        Quaternions q;
+
+        Delta = imu::identity();
+        J_D_b.setZero();
+        q = q0;
+        for (int n = 0; n<N; n++)
+        {
+            // Simulate data
+            data = motion2data(motion, q, bias_real);
+            q    = q*exp_q(motion.tail(3)*dt);
+            // Motion::integrateOneStep()
+            {   // IMU::computeCurrentDelta
+                body  = data - bias_preint;
+                imu::body2delta(body, dt, delta, J_d_d);
+                J_d_b = - J_d_d;
+            }
+            {   // IMU::deltaPlusDelta
+                imu::compose(Delta, delta, dt, Delta_plus, J_D_D, J_D_d);
+            }
+            // Motion:: jac calib
+            J_D_b = J_D_D*J_D_b + J_D_d*J_d_b;
+            // Motion:: buffer
+            Delta = Delta_plus;
+        }
+        return Delta;
+    }
+
+};
+
+TEST_F(ConstraintIMU_biasTest, VarB1B2_InvarP1Q1V1P2Q2V2_initOK)
+{
+
+         // ==================================== INITIAL CONDITIONS
+        t0 = 0;
+        dt = 0.1;
+        num_integrations = 10;
+        DT = num_integrations * dt;
+
+        p0 << 0,0,0;
+        q0.setIdentity();
+        v0 << 0,0,0;
+        MatrixXs  P0(9,9); P0.setIdentity() * 0.01;
+
+        x0 << p0, q0.coeffs(), v0;
         KF_0 = problem->setPrior(x0, P0, t0);
+        C_0  = processor_imu->getOriginPtr();
 
-        Scalar dt = 0.01;
+        // bias
+        bias_real   << .001, .002, .003, -.001, -.002, -.003;
+        bias_preint = bias_null;
 
-        Vector6s data; data << 0,0,0, 0,0,0;
-        Vector3s a, am, w, wm;
-        a << 0,0,0;
-        w << 0,0,0; w *= 0.1;
+        processor_imu->getLastPtr()->setCalibrationPreint(bias_preint);
 
-        Quaternions q; q.setIdentity();
-        Vector6s bias; bias << 0,0,0, 0,0,0;
-        Vector6s bias_preint; bias_preint << 0,0,0, 0,0,0;
+        // ===================================== MOTION params
+        a << 0,0,0;
+        w << 0,1,0; w *= 0.1;
 
-        CaptureIMUPtr capture_imu = std::make_shared<CaptureIMU>(t0, sensor_imu, data, sensor_imu->getNoiseCov());
+        motion << a, w;
 
-        VectorXs D_current(10), D_preint(10), D_corrected(10);
+        // ===================================== INTEGRATE USING PROCESSOR
 
-        for (TimeStamp t = t0; t < t0 + 1.0; t += dt)
+        capture_imu = std::make_shared<CaptureIMU>(t0, sensor_imu, data, sensor_imu->getNoiseCov());
+        VectorXs D_preint(10), D_corrected(10);
+        q = q0;
+        for ( t = t0 + dt; t < t0 + num_integrations * dt; t += dt )
         {
-            q *= exp_q(wm*dt);
-            am = a - q*gravity();
-            wm = w;
-            data << am, wm;
-            data += bias;
+            data = motion2data(motion, q, bias_real);
+            q    = q * exp_q(wm*dt);
 
             capture_imu->setTimeStamp(t);
             capture_imu->setData(data);
 
             sensor_imu->process(capture_imu);
 
-            D_current = processor_imu->getLastPtr()->getDeltaCorrected(bias);
-            D_preint = processor_imu->getLastPtr()->getDeltaCorrected(bias_preint);
+            D_preint    = processor_imu->getLastPtr()->getDeltaPreint();
+            D_corrected = processor_imu->getLastPtr()->getDeltaCorrected(bias_real);
 
-            WOLF_TRACE("X_current(t): ", imu::composeOverState(x0, D_current, t - t0 ) );
-            WOLF_TRACE("X_preint(t) : ", imu::composeOverState(x0, D_preint , t - t0 ) );
         }
 
-    }
+        // INTEGRATE USING IMU_TOOLS
+        VectorXs D_preint_imu, D_corrected_imu;
+        Matrix<Scalar, 9, 6> J_b;
+        D_preint_imu = integrateDelta(num_integrations, q0, motion, bias_real, bias_preint, dt, J_b);
 
-    virtual void TearDown( ) { }
-};
+        // correct perturbated
+        Vector9s step = J_b*(bias_real-bias_preint);
+        D_corrected_imu = imu::plus(D_preint_imu, step);
+
+        WOLF_TRACE("D_preint     : ", D_preint       .transpose() );
+        WOLF_TRACE("D_preint_imu : ", D_preint_imu   .transpose() );
+//        ASSERT_MATRIX_APPROX(D_preint, D_preint_imu, 1e-8);
+
+        WOLF_TRACE("D_correct    : ", D_corrected    .transpose() );
+        WOLF_TRACE("D_correct_imu: ", D_corrected_imu.transpose() );
+//        ASSERT_MATRIX_APPROX(D_corrected, D_corrected_imu, 1e-8);
+
+        WOLF_TRACE("X_preint     : ", imu::composeOverState(x0, D_preint       , DT ).transpose() );
+        WOLF_TRACE("X_preint_imu : ", imu::composeOverState(x0, D_preint_imu   , DT ).transpose() );
+
+        WOLF_TRACE("X_correct    : ", imu::composeOverState(x0, D_corrected    , DT ).transpose() );
+        WOLF_TRACE("X_correct_imu: ", imu::composeOverState(x0, D_corrected_imu, DT ).transpose() );
+
+}
 
 // tests with following conditions :
 //  var(b1,b2),        invar(p1,q1,v1,p2,q2,v2),    factor : imu(p,q,v)
@@ -2922,11 +3067,11 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRot, VarB1B2P2Q2V2_InvarP1Q1V
 int main(int argc, char **argv)
 {
   testing::InitGoogleTest(&argc, argv);
-  ::testing::GTEST_FLAG(filter) = "ConstraintIMU_biasTest_Move_NonNullBiasRot.*:ConstraintIMU_biasTest_Static_NullBias.*:ConstraintIMU_biasTest_Static_NonNullAccBias.*:ConstraintIMU_biasTest_Static_NonNullGyroBias.*";
+//  ::testing::GTEST_FLAG(filter) = "ConstraintIMU_biasTest_Move_NonNullBiasRot.*:ConstraintIMU_biasTest_Static_NullBias.*:ConstraintIMU_biasTest_Static_NonNullAccBias.*:ConstraintIMU_biasTest_Static_NonNullGyroBias.*";
 //  ::testing::GTEST_FLAG(filter) = "ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRotY.VarB1B2V1V2_InvarP1Q1P2Q2_initOK";
 //    ::testing::GTEST_FLAG(filter) = "ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRot.VarB1B2_InvarP1Q1V1P2Q2V2_initOK";
 //    ::testing::GTEST_FLAG(filter) = "ConstraintIMU_biasTest_Move_NonNullBiasRot.VarB1B2V1P2V2_InvarP1Q1Q2_initOK";
-
+  ::testing::GTEST_FLAG(filter) = "ConstraintIMU_biasTest.*";
 
 
   return RUN_ALL_TESTS();
-- 
GitLab