Attitude estimation using IMU (3-DoF ver.)

Fork of ATTITUDE_ESTIMATION by LDSC_Robotics_TAs

Revision:
8:3882cb4be9d3
Parent:
7:6fc812e342e6
Child:
9:84fad91d3587
--- a/ATTITUDE_ESTIMATION.cpp	Tue Dec 27 07:43:25 2016 +0000
+++ b/ATTITUDE_ESTIMATION.cpp	Tue Dec 27 11:28:49 2016 +0000
@@ -45,8 +45,9 @@
                         alpha(alpha_in),
                         one_over_gamma(one_over_gamma_in),
                         Ts(Ts_in),
-                        lpfv_ys(3, Ts_in, 10.0), // Input filter
-                        lpfv_w(3, Ts_in, 200.0) // Input filter
+                        lpfv_y_acce(3, Ts_in, 10.0), // Input filter for accelerometers
+                        lpfv_y_mag(3, Ts_in, 200.0), // Input filter for magenetometers
+                        lpfv_w(3, Ts_in, 200.0) // Input filter for gyroscope
 {
     // Dimension
     n = 3;
@@ -55,6 +56,7 @@
 
     // Default: close the gyro-bias estimation
     enable_biasEst = false;
+    enable_magEst = false;
 
     // Unit transformation
     pi = 3.1415926;
@@ -72,8 +74,10 @@
     int accmap_temp[] = {-3,1,2}; // Reverse: The direction of accelerometer is defined based on the direction of the acceleration of the sensor, not the g-direction
     // int accmap_temp[] = {1, 2, 3};
     //
+    int magMap_temp[] = {3,-1, 2}; // real z-axis is in the reverse direction
     int gyroMap_temp[] = {3,-1,-2};
     accMap_real2here.assign(accmap_temp, accmap_temp+n);
+    magMap_real2here.assign(magMap_temp, magMap_temp+n);
     gyroMap_real2here.assign(gyroMap_temp, gyroMap_temp+n);
 
     // zeros
@@ -87,11 +91,15 @@
     unit_nz[2] = -1; // negative z
 
     // States
-    x_est = unit_nx; // x is pointing downward
+    xg_est = unit_nx; // g is pointing downward
+    xm_est = Get_VectorScalarMultiply(unit_nz, -1.0); // m is pointing forward
     gyroBias_est = zeros;
     omega = zeros;
-    ys = zeros;
-    w_cross_ys = zeros; // omega X ys
+    //
+    y_acce = zeros; // Accelerometer outputs
+    y_mag = zeros; // Magnetometer outputs
+    //
+    // w_cross_ys = zeros; // omega X ys
     ys_cross_x_ys = zeros; // ys X (x_est - ys)
 
     // Eular angles, in rad/s
@@ -105,8 +113,7 @@
 
 }
 // Public methods
-void ATTITUDE::gVector_to_EulerAngle(const vector<float> &v_in)
-{
+void ATTITUDE::Vectors_to_EulerAngle(const vector<float> &vg_in, const vector<float> &vm_in){
     //
     // This function should be customized according to the definition of coordinate system
     //
@@ -114,23 +121,30 @@
     /*
     // Here we follow the definition in bicycle paper
     yaw = 0.0; // phi, yaw
-    roll = atan2(-v_in[1],v_in[0]); // theta, roll
-    pitch = atan2(cos(roll)*v_in[2],v_in[0]); // psi, pitch
+    roll = atan2(-vg_in[1],vg_in[0]); // theta, roll
+    pitch = atan2(cos(roll)*vg_in[2],vg_in[0]); // psi, pitch
     */
 
     // Eular angle: 1-3-2, zs is pointing forwasd
-    yaw = 0.0; // phi, yaw
-    pitch = atan2(-v_in[2],-v_in[0]); // psi, pitch
+    // yaw = 0.0; // phi, yaw
+    pitch = atan2(-vg_in[2],-vg_in[0]); // psi, pitch
     if (abs(pitch) <  0.7854){ // pi/4
-        roll = atan2(cos(pitch)*v_in[1],-v_in[0]); // theta, roll
+        roll = atan2(cos(pitch)*vg_in[1],-vg_in[0]); // theta, roll
     }else{
         if (pitch >= 0.0)
-            roll = atan2(sin(pitch)*v_in[1],-v_in[2]); // theta, roll
+            roll = atan2(sin(pitch)*vg_in[1],-vg_in[2]); // theta, roll
         else
-            roll = atan2(-sin(pitch)*v_in[1],v_in[2]); // theta, roll
+            roll = atan2(-sin(pitch)*vg_in[1],vg_in[2]); // theta, roll
     }
 
-
+    // Calculate the yaw angle
+    if (enable_magEst){
+        float num = vm_in[1]*cos(pitch);
+        float den = (vm_in[2]*cos(roll) - vm_in[1]*sin(pitch)*sin(roll));
+        yaw = atan2(num, den);
+    }else{
+        yaw = 0.0; // phi, yaw
+    }
 
 }
 // Setting parameters
@@ -141,42 +155,40 @@
     L1_diag.assign(n,alpha_in);
 }
 //
-void ATTITUDE::Init(const vector<float> &y_in) // Let _x_est = y_in
+void ATTITUDE::Init(void) // Let x_est = ys
 {
-    // ys = y_in;
-    // Normolization(x_est,y_in); // x_est be set as normalized y_in
-    x_est = y_in;
+    // y_acce = y_in;
+    // Normolization(xg_est,y_in); // xg_est be set as normalized y_in
+    xg_est = y_acce;
+    xm_est = y_mag;
     ++init_flag;
 }
-void ATTITUDE::iterateOnce(const vector<float> &y_in, const vector<float> &omega_in) // Main alogorithm
+void ATTITUDE::iterateOnce(const vector<float> &y_acce_in, const vector<float> &omega_in) // Main alogorithm
 {
-    InputMapping(ys, y_in, accMap_real2here);
+    enable_magEst = false; // no magenetometers input
+    // Input mapping
+    InputMapping(y_acce, y_acce_in, accMap_real2here);
+    // InputMapping(y_mag, y_mag_in, magMap_real2here);
     InputMapping(omega, omega_in, gyroMap_real2here);
 
     // Input filter
-    ys = lpfv_ys.filter(ys);
+    y_acce = lpfv_y_acce.filter(y_acce);
+    // y_mag = lpfv_y_mag.filter(y_mag);
     // omega = lpfv_w.filter(omega);
 
     // gyro-bias estimation
     if (enable_biasEst){
-        omega = Get_VectorPlus(omega,gyroBias_est, true); // omega - gyroBias_est
+        omega = Get_VectorPlus(omega, gyroBias_est, true); // minus, omega - gyroBias_est
     }
 
     //
     if(init_flag < 3){
-        Init(ys);
+        Init();
     }
     else{
-        //
-        /*
-        Get_CrossProduct3(w_cross_ys,omega,ys);
-        for(int i=0; i<3; i++){
-            // x_est_plus[i] = x_est[i] + Ts*( L1_diag[i]*(ys[i] - x_est[i]) - w_cross_ys[i]);
-            x_est[i] += Ts*( L1_diag[i]*(ys[i] - x_est[i]) - w_cross_ys[i]);
-        }
-        */
-        // Estimation process
-        EstimationKernel(x_est, ys, omega);
+        // Estimation kernel process
+        EstimationKernel(xg_est, y_acce, omega);
+        // EstimationKernel(xm_est, y_mag, omega);
 
         // gyro-bias estimation
         if (enable_biasEst){
@@ -184,11 +196,46 @@
         }
     }
     //
-    gVector_to_EulerAngle(x_est);
+    Vectors_to_EulerAngle(xg_est,xm_est);
+}
+void ATTITUDE::iterateOnce(const vector<float> &y_acce_in, const vector<float> &y_mag_in, const vector<float> &omega_in) // Main alogorithm
+{
+    enable_magEst = true; // with magenetometers input
+    // Input mapping
+    InputMapping(y_acce, y_acce_in, accMap_real2here);
+    InputMapping(y_mag, y_mag_in, magMap_real2here);
+    InputMapping(omega, omega_in, gyroMap_real2here);
+
+    // Input filter
+    y_acce = lpfv_y_acce.filter(y_acce);
+    // y_mag = lpfv_y_mag.filter(y_mag);
+    // omega = lpfv_w.filter(omega);
+
+    // gyro-bias estimation
+    if (enable_biasEst){
+        omega = Get_VectorPlus(omega, gyroBias_est, true); // minus, omega - gyroBias_est
+    }
+
+    //
+    if(init_flag < 3){
+        Init();
+    }
+    else{
+        // Estimation kernel process
+        EstimationKernel(xg_est, y_acce, omega);
+        EstimationKernel(xm_est, y_mag, omega);
+
+        // gyro-bias estimation
+        if (enable_biasEst){
+            updateGyroBiasEst();
+        }
+    }
+    //
+    Vectors_to_EulerAngle(xg_est,xm_est);
 }
 // transform the x_est into "real" coordinate
 void ATTITUDE::getEstimation_realCoordinate(vector<float> &V_out){
-    OutputMapping(V_out,x_est,accMap_real2here);
+    OutputMapping(V_out,xg_est,accMap_real2here);
 }
 // Get Eular angles
 float ATTITUDE::pitch_deg(void){
@@ -255,7 +302,7 @@
 void ATTITUDE::EstimationKernel(vector<float> &_x_est_, const vector<float> &_ys_, const vector<float> &_omega_){
     static vector<float> _w_cross_ys_;
     Get_CrossProduct3(_w_cross_ys_, _omega_, _ys_);
-    for(int i=0; i<3; i++){
+    for(size_t i = 0; i < n; ++i){
         // x_est_plus[i] = x_est[i] + Ts*( L1_diag[i]*(ys[i] - x_est[i]) - w_cross_ys[i]);
         _x_est_[i] += Ts*( L1_diag[i]*(_ys_[i] - _x_est_[i]) - _w_cross_ys_[i]);
     }
@@ -266,7 +313,7 @@
         return;
     }
     //
-    Get_CrossProduct3(ys_cross_x_ys, ys, Get_VectorPlus(x_est,ys,true));
+    Get_CrossProduct3(ys_cross_x_ys, y_acce, Get_VectorPlus(xg_est,y_acce,true));
     //
     gyroBias_est = Get_VectorPlus(gyroBias_est, Get_VectorScalarMultiply(ys_cross_x_ys, (one_over_gamma)), true);
 }