Attitude estimation using IMU (3-DoF ver.)
Fork of ATTITUDE_ESTIMATION by
ATTITUDE_ESTIMATION.cpp
- Committer:
- benson516
- Date:
- 2016-12-24
- Revision:
- 6:c362ed165c39
- Parent:
- 5:01e322f4158f
- Child:
- 7:6fc812e342e6
File content as of revision 6:c362ed165c39:
#include "ATTITUDE_ESTIMATION.h" //=====================LPF ====================// LPF_vector::LPF_vector(size_t dimension, float samplingTime, float cutOff_freq_Hz_in) { n = dimension; Ts = samplingTime; cutOff_freq_Hz = cutOff_freq_Hz_in; alpha_Ts = (2*3.1415926)*cutOff_freq_Hz*Ts; One_alpha_Ts = 1.0 - alpha_Ts; zeros.assign(n, 0.0); output = zeros; // Flag_Init = false; } vector<float> LPF_vector::filter(const vector<float> &input) { // Initialization if (!Flag_Init){ reset(input); Flag_Init = true; return output; } for (size_t i = 0; i < n; ++i){ // output = One_alpha_Ts*output + alpha_Ts*input; output[i] += alpha_Ts*(input[i] - output[i]); } return output; } void LPF_vector::reset(const vector<float> &input) { // output = (1.0 - alpha_Ts)*output + alpha_Ts*input; output = input; return; } //-------------------------------------------------------// ATTITUDE::ATTITUDE(float alpha_in, float one_over_gamma_in, float Ts_in): 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 { // Dimension n = 3; // init_flag = 0; // Uninitialized // Default: close the gyro-bias estimation enable_biasEst = false; // Unit transformation pi = 3.1415926; deg2rad = pi/180.0; rad2deg = 180.0/pi; // The map from "real" coordinate to "here" coordinate // eg. accMap_real2here = [3,-1,-2]; // means: real -> here // 1 x z 3 // 2 y -x -1 // 3 z -y -2 // int accmap_temp[] = {3,-1,-2}; 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 gyroMap_temp[] = {3,-1,-2}; accMap_real2here.assign(accmap_temp, accmap_temp+n); gyroMap_real2here.assign(gyroMap_temp, gyroMap_temp+n); // zeros zeros.assign(n,0.0); // unit_nz unit_nx = zeros; unit_ny = zeros; unit_nz = zeros; unit_nx[0] = -1; // negative x unit_ny[1] = -1; // negative y unit_nz[2] = -1; // negative z // States x_est = unit_nx; // x is pointing downward gyroBias_est = zeros; omega = zeros; ys = zeros; w_cross_ys = zeros; // omega X ys ys_cross_x_ys = zeros; // ys X (x_est - ys) // Eular angles, in rad/s pitch = 0.0; roll = 0.0; yaw = 0.0; // Gain matrix Set_L1_diag(alpha); } // real -> here void ATTITUDE::InputMapping(vector<float> &v_hereDef, const vector<float> &v_realDef, const vector<int> &map_real2here){ // The map from "real" coordinate to "here" coordinate // eg. accMap_real2here = [3,-1,-2]; // means: real -> here // 1 x z 3 // 2 y -x -1 // 3 z -y -2 // vector<int> accMap_real2here = {3,-1,-2}; // vector<int> gyroMap_real2here = {3,-1,-2}; // Iterate through "real" coordinates int idx_here = 1; for (size_t i = 0; i < n; ++i){ idx_here = map_real2here[i]; if (idx_here > 0){ v_hereDef[idx_here-1] = v_realDef[i]; }else{ v_hereDef[-idx_here-1] = -1*v_realDef[i]; } } } // here -> real void ATTITUDE::OutputMapping(vector<float> &v_realDef, const vector<float> &v_hereDef, const vector<int> &map_real2here){ // This is the inverse mapping of the InputMapping // The map from "real" coordinate to "here" coordinate // eg. accMap_real2here = [3,-1,-2]; // means: real -> here // 1 x z 3 // 2 y -x -1 // 3 z -y -2 // vector<int> accMap_real2here = {3,-1,-2}; // vector<int> gyroMap_real2here = {3,-1,-2}; // Iterate through "real" coordinates int idx_here = 1; for (size_t i = 0; i < n; ++i){ idx_here = map_real2here[i]; if (idx_here > 0){ v_realDef[i] = v_hereDef[idx_here-1]; }else{ v_realDef[i] = -1*v_hereDef[-idx_here-1]; } } } // Public methods void ATTITUDE::gVector_to_EulerAngle(const vector<float> &v_in) { // // This function should be customized according to the definition of coordinate system // /* // 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 */ // Eular angle: 1-3-2, zs is pointing forwasd yaw = 0.0; // phi, yaw pitch = atan2(-v_in[2],-v_in[0]); // psi, pitch if (abs(pitch) < 0.7854){ // pi/4 roll = atan2(cos(pitch)*v_in[1],-v_in[0]); // theta, roll }else{ if (pitch >= 0.0) roll = atan2(sin(pitch)*v_in[1],-v_in[2]); // theta, roll else roll = atan2(-sin(pitch)*v_in[1],v_in[2]); // theta, roll } } void ATTITUDE::Get_CrossProduct3(vector<float> &v_c, const vector<float> &v_a, const vector<float> &v_b) // v_a X v_b { v_c[0] = (-v_a[2]*v_b[1]) + v_a[1]*v_b[2]; v_c[1] = v_a[2]*v_b[0] - v_a[0]*v_b[2]; v_c[2] = (-v_a[1]*v_b[0]) + v_a[0]*v_b[1]; } vector<float> ATTITUDE::Get_VectorPlus(const vector<float> &v_a, const vector<float> &v_b, bool is_minus) // v_a + (or -) v_b { static vector<float> v_c(n); for (size_t i = 0; i < n; ++i){ if (is_minus){ v_c[i] = v_a[i] - v_b[i]; }else{ v_c[i] = v_a[i] + v_b[i]; } } return v_c; } vector<float> ATTITUDE::Get_VectorScalarMultiply(const vector<float> &v_a, float scale) // scale*v_a { static vector<float> v_c(n); for (size_t i = 0; i < n; ++i){ v_c[i] = scale*v_a[i]; } return v_c; } float ATTITUDE::Get_Vector3Norm(const vector<float> &v_in) { float temp = 0.0; for (size_t i = 0; i < n; ++i) temp += v_in[i]*v_in[i]; return sqrt(temp); // <- Should check if this function is available (?) } void ATTITUDE::Normolization(vector<float> &V_out, const vector<float> &V_in){ float norm = Get_Vector3Norm(V_in); for (size_t i = 0; i < n; ++i){ V_out[i] = V_in[i]/norm; } } void ATTITUDE::Init(const vector<float> &y_in) // Let _x_est = y_in { // ys = y_in; // Normolization(x_est,y_in); // x_est be set as normalized y_in x_est = y_in; ++init_flag; } void ATTITUDE::iterateOnce(const vector<float> &y_in, const vector<float> &omega_in) // Main alogorithm { InputMapping(ys, y_in, accMap_real2here); InputMapping(omega, omega_in, gyroMap_real2here); // Input filter ys = lpfv_ys.filter(ys); // omega = lpfv_w.filter(omega); // gyro-bias estimation if (enable_biasEst){ omega = Get_VectorPlus(omega,gyroBias_est, true); // omega - gyroBias_est } // if(init_flag < 3){ Init(ys); } 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]); } // gyro-bias estimation if (enable_biasEst){ updateGyroBiasEst(); } } // gVector_to_EulerAngle(x_est); } void ATTITUDE::updateGyroBiasEst(void){ // Update the gyro bias estimation if (one_over_gamma == 0.0){ return; } // Get_CrossProduct3(ys_cross_x_ys, ys, Get_VectorPlus(x_est,ys,true)); // gyroBias_est = Get_VectorPlus(gyroBias_est, Get_VectorScalarMultiply(ys_cross_x_ys, (one_over_gamma)), true); } // transform the x_est into "real" coordinate void ATTITUDE::getEstimation_realCoordinate(vector<float> &V_out){ OutputMapping(V_out,x_est,accMap_real2here); } // Get Eular angles float ATTITUDE::pitch_deg(void){ return (rad2deg*pitch); } float ATTITUDE::roll_deg(void){ return (rad2deg*roll); } float ATTITUDE::yaw_deg(void){ return (rad2deg*yaw); } // Private methods void ATTITUDE::Set_L1_diag(float alpha_in) // set diagnal element of gain matrix { alpha = alpha_in; L1_diag.assign(n,alpha_in); }