Attitude estimation using IMU (3-DoF ver.)
Fork of ATTITUDE_ESTIMATION by
ATTITUDE_ESTIMATION.cpp
- Committer:
- benson516
- Date:
- 2017-01-20
- Revision:
- 13:16bc19155f54
- Parent:
- 12:058a9edb664e
File content as of revision 13:16bc19155f54:
#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 Ts_in): alpha(alpha_in), Ts(Ts_in), lpfv_y_acce(3, Ts_in, 200.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; // init_flag = 0; // Uninitialized // Default: close the gyro-bias estimation enable_biasEst = false; one_over_gamma = 0.0; // Default: close the estimation for magenetic field enable_magEst = false; // Unit transformation pi = 3.1415926; deg2rad = pi/180.0; rad2deg = 180.0/pi; gravity = 9.81; // m/s^2 // 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 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 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 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; // y_acce = zeros; // Accelerometer outputs y_mag = zeros; // Magnetometer outputs // Linear acceleration estimation acce_sensorFrame = 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; // pitchRate = 0.0; rollRate = 0.0; yawRate = 0.0; // Gain matrix Set_L1_diag(alpha); } // Public methods 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 // /* // Here we follow the definition in bicycle paper yaw = 0.0; // phi, yaw 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 forward // 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)*vg_in[1],-vg_in[0]); // theta, roll }else{ if (pitch >= 0.0) roll = atan2(sin(pitch)*vg_in[1],-vg_in[2]); // theta, roll else 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 } // Calculate the rate of each Eular angle if (abs(roll) > 1.2217 ){ // 75 deg, singular case yawRate = 0.0; // 0.0, approximation pitchRate = omega[1]; // w2, approximation }else{ // Normal case // yawRate = (w1*cos(psi) + w3*sin(psi))/cos(theta) yawRate = (omega[0]*cos(pitch) + omega[2]*sin(pitch))/cos(roll); // pitchRate = w2 + yawRate*sin(theta) pitchRate = omega[1] + yawRate*sin(roll); } // rollRate = w3*cos(psi) - w1*sin(psi) rollRate = (omega[2]*cos(pitch) - omega[0]*sin(pitch)); } // Setting parameters // Set L1, the diagonal matrix void ATTITUDE::Set_L1_diag(float alpha_in) // set diagnal element of gain matrix { alpha = alpha_in; L1_diag.assign(n,alpha_in); } void ATTITUDE::enable_gyroBiasEst(float gamma_in){ // Enable the gyro-bias estimation enable_biasEst = true; one_over_gamma = 1/gamma_in; } // void ATTITUDE::Init(void) // Let x_est = ys { // 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_acce_in, const vector<float> &omega_in) // Main alogorithm { 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 // 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(); } } // Calculate the linear acceleration acce_sensorFrame = Get_VectorPlus(y_acce, xg_est, true); // minus // 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(); } } // Calculate the linear acceleration acce_sensorFrame = Get_VectorPlus(y_acce, xg_est, true); // minus // 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,xg_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 //////////////////////////////////// // Input/output coordinate transformations within the different definitions between the "real" one and the "here" one // 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]; } } } // The kernel of the estimation process //////////////////////////////////////// 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(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]); } } void ATTITUDE::updateGyroBiasEst(void){ // Update the gyro bias estimation if (one_over_gamma == 0.0){ return; } // 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); } //////////////////////////////////////// end The kernal of the estimation process // Utilities // vector operation void ATTITUDE::Get_CrossProduct3(vector<float> &v_c, const vector<float> &v_a, const vector<float> &v_b) // v_a X v_b { // Check the size if (v_c.size() != n){ v_c.resize(n); } 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; } }