imufilter.hpp
Go to the documentation of this file.
00001 
00037 #ifndef __IMUFILTER_H__
00038 #define __IMUFILTER_H__
00039 
00040 #include <Eigen/Core>
00041 #include <Eigen/Dense>
00042 #include <sensor_msgs/Imu.h>
00043 #include <vector>
00044 
00045 // Convenient constants
00046 #define RAD2DEG(X) ( (X) * 57.2957795131)
00047 #define DEG2RAD(X) ( (X) * 0.01745329251)
00048 #define LIN2GRAV(X) ( (X) * 0.10197162)
00049 
00054 class ImuFilter
00055 {
00056 public:
00057         
00063     ImuFilter(double T, std::string imuTopic, double calibTime = 5.0)
00064         {
00065         init_ = false;
00066         T_ = T;
00067         T2_ = T*T;
00068         calibTime_ = calibTime;
00069 
00070                 // IMU EKF parameters
00071         accDev_ = 0.006;//0.001
00072         gyrDev_ = 0.005;//0.01;
00073         magDev_ = 0;
00074         magXs_ = 1.0;
00075         magYs_ = 1.0;
00076         magZs_ = 1.0;
00077         magXo_ = 0.0;
00078         magYo_ = 0.0;
00079         magZo_ = 0.0;
00080         biaDev_ = 0.00001;//0.000001;
00081         biaTh_ = 0.005; //0.001;
00082                 
00083         // Setup IMU data subscriber
00084         sub_ = nh_.subscribe(imuTopic, 10, &ImuFilter::imuDataCallback, this);
00085         }
00086 
00087         
00092         bool initialize(void)
00093         {
00094                 double gx_m, gy_m, gz_m, gx_m2, gy_m2, gz_m2, gx_d, gy_d, gz_d; 
00095                 
00096                 // Compute mean value and mean square
00097                 gx_m = gy_m = gz_m = gx_m2 = gy_m2 = gz_m2 = 0.0;
00098         for(int i = 0; i < (int)calibData_.size(); i++)
00099                 {
00100             gx_m += calibData_[i].angular_velocity.x;
00101             gy_m += calibData_[i].angular_velocity.y;
00102             gz_m += calibData_[i].angular_velocity.z;
00103             gx_m2 += calibData_[i].angular_velocity.x*calibData_[i].angular_velocity.x;
00104             gy_m2 += calibData_[i].angular_velocity.y*calibData_[i].angular_velocity.y;
00105             gz_m2 += calibData_[i].angular_velocity.z*calibData_[i].angular_velocity.z;
00106                 }
00107         gx_m = gx_m/(double)calibData_.size();
00108         gy_m = gy_m/(double)calibData_.size();
00109         gz_m = gz_m/(double)calibData_.size();
00110         gx_m2 = gx_m2/(double)calibData_.size();
00111         gy_m2 = gy_m2/(double)calibData_.size();
00112         gz_m2 = gz_m2/(double)calibData_.size();
00113                 //std::cout << "gxM: " << gx_m << ", gyM: " << gy_m << ", gzM: " << gz_m << std::endl;
00114                 
00115                 // Compute standar deviation of gyros
00116                 gx_d = sqrt(gx_m2-gx_m*gx_m);
00117                 gy_d = sqrt(gy_m2-gy_m*gy_m);
00118                 gz_d = sqrt(gz_m2-gz_m*gz_m);
00119                 //std::cout << "gxDev: " << gx_d << ", gyDev: " << gy_d << ", gzDev: " << gz_d << std::endl;
00120                 
00121                 // Initalize compass calibration
00122         magCal_[0] = magXs_; magCal_[1] = magYs_; magCal_[2] = magZs_;
00123         magCal_[3] = magXo_; magCal_[4] = magYo_; magCal_[5] = magZo_;
00124                 
00125                 // Initialize sensor variances
00126         accVar_[0] = accDev_*accDev_;   accVar_[1] = accDev_*accDev_;   accVar_[2] = accDev_*accDev_;           // Variance in g
00127         gyrVar_[0] = gyrDev_*gyrDev_; gyrVar_[1] = gyrDev_*gyrDev_; gyrVar_[2] = gyrDev_*gyrDev_;       // Variance in rad/s
00128         magVar_[0] = magDev_*magDev_;   magVar_[1] = magDev_*magDev_;   magVar_[2] = magDev_*magDev_;   // Variance in mGaus wth data normalized to 1
00129         biaVar_[0] = biaDev_*biaDev_; biaVar_[1] = biaDev_*biaDev_; biaVar_[2] = biaDev_*biaDev_;       // Variance in rad/s
00130                 
00131                 // Initialize accelerometer threshold
00132         accTh_ = sqrt(accVar_[0]+accVar_[1]+accVar_[2]);
00133                 
00134                 // Initialize state vector x = [rx, ry, rz, gbx, gby, gbz]
00135         rx_ = ry_ = rz_ = 0.0;
00136         gbx_ = gx_m;
00137         gby_ = gy_m;
00138         gbz_ = gz_m;
00139                 
00140                 // Initialize covariance matrix
00141         P_.setIdentity(6, 6);
00142         P_(0,0) = M_PI_2;
00143         P_(1,1) = M_PI_2;
00144         P_(2,2) = M_PI_2;
00145         P_(3,3) = 0.01*0.01;
00146         P_(4,4) = 0.01*0.01;
00147         P_(5,5) = 0.01*0.01;
00148         /*P_(3,3) = biaVar_[0];
00149         P_(4,4) = biaVar_[1];
00150         P_(5,5) = biaVar_[2];*/
00151                 
00152         if(gx_d < biaTh_ && gy_d < biaTh_ && gz_d < biaTh_)
00153                 {
00154             init_ = true;
00155             ROS_INFO("IMU filter initialized");
00156                 
00157                         return true;
00158                 }
00159                 else
00160                         return false;
00161         }       
00162         
00168         bool predict(double gx, double gy, double gz)
00169         {
00170                 // Check initialization 
00171         if(!init_)
00172                         return false;
00173                 
00174                 // Compute matrix F 
00175                 Eigen::Matrix<double, 6, 6> F;
00176         F(0,0) = 1, F(0,1) = 0, F(0,2) = 0, F(0,3) = -T_, F(0,4) = 0,   F(0,5) = 0;
00177         F(1,0) = 0, F(1,1) = 1, F(1,2) = 0, F(1,3) = 0,  F(1,4) = -T_,  F(1,5) = 0;
00178         F(2,0) = 0, F(2,1) = 0, F(2,2) = 1, F(2,3) = 0,  F(2,4) = 0,   F(2,5) = -T_;
00179                 F(3,0) = 0, F(3,1) = 0, F(3,2) = 0, F(3,3) = 1,  F(3,4) = 0,   F(3,5) = 0;
00180                 F(4,0) = 0, F(4,1) = 0, F(4,2) = 0, F(4,3) = 0,  F(4,4) = 1,   F(4,5) = 0;
00181                 F(5,0) = 0, F(5,1) = 0, F(5,2) = 0, F(5,3) = 0,  F(5,4) = 0,   F(5,5) = 1;
00182 
00183                 // Update covariance matrix
00184         P_ = F*P_*F.transpose();
00185         P_(0,0) += gyrVar_[0]*T2_;
00186         P_(1,1) += gyrVar_[1]*T2_;
00187         P_(2,2) += gyrVar_[2]*T2_;
00188         P_(3,3) += biaVar_[0]*T_;
00189         P_(4,4) += biaVar_[1]*T_;
00190         P_(5,5) += biaVar_[2]*T_;
00191                 
00192                 // Update state vector
00193         rx_ += T_*(gx - gbx_);
00194         ry_ += T_*(gy - gby_);
00195         rz_ += T_*(gz - gbz_);
00196                                                                                                                 
00197                 return true; 
00198         }
00199         
00205         bool update(double ax, double ay, double az)
00206         {
00207                 double crx, srx, cry, sry, mod, y[3];
00208                 
00209                 // Check initialization 
00210         if(!init_)
00211                         return false;
00212                 
00213                 // Pre-compute constants
00214         crx = cos(rx_);
00215         cry = cos(ry_);
00216         srx = sin(rx_);
00217         sry = sin(ry_);
00218                 
00219                 // Create measurement jacobian H
00220                 Eigen::Matrix<double, 3, 6> H;
00221                 H(0,0) = 0;                     H(0,1) = cry;           H(0,2) = 0; H(0,3) = 0; H(0,4) = 0; H(0,5) = 0;
00222                 H(1,0) = -crx*cry;      H(1,1) = srx*sry;       H(1,2) = 0; H(1,3) = 0; H(1,4) = 0; H(1,5) = 0;
00223                 H(2,0) = cry*srx;       H(2,1) = crx*sry;       H(2,2) = 0; H(2,3) = 0; H(2,4) = 0; H(2,5) = 0;
00224                 
00225                 // Compute measurement noise jacoban R
00226                 Eigen::Matrix<double, 3, 3> R;
00227                 mod = fabs(sqrt(ax*ax + ay*ay + az*az)-1);
00228                 R.setZero(3, 3);
00229         R(0,0) = accVar_[0];
00230         R(1,1) = accVar_[1];
00231         R(2,2) = accVar_[2];
00232                 /*if(mod > accTh)
00233                 {
00234                         R(0,0) += 1.5*mod*mod;
00235                         R(1,1) += 1.5*mod*mod;
00236                         R(2,2) += 1.5*mod*mod;
00237                 }*/
00238                 
00239                 // Compute innovation matrix
00240                 Eigen::Matrix<double, 3, 3> S;
00241         S = H*P_*H.transpose()+R;
00242                 
00243                 // Compute kalman gain
00244                 Eigen::Matrix<double, 6, 3> K;
00245         K = P_*H.transpose()*S.inverse();
00246                 
00247                 // Compute mean error
00248                 y[0] = ax-sry;
00249                 y[1] = ay+cry*srx;
00250                 y[2] = az+crx*cry;
00251                 
00252                 // Compute new state vector
00253         rx_ += K(0,0)*y[0]+K(0,1)*y[1]+K(0,2)*y[2];
00254         ry_ += K(1,0)*y[0]+K(1,1)*y[1]+K(1,2)*y[2];
00255         rz_ += K(2,0)*y[0]+K(2,1)*y[1]+K(2,2)*y[2];
00256         gbx_ += K(3,0)*y[0]+K(3,1)*y[1]+K(3,2)*y[2];
00257         gby_ += K(4,0)*y[0]+K(4,1)*y[1]+K(4,2)*y[2];
00258         gbz_ += K(5,0)*y[0]+K(5,1)*y[1]+K(5,2)*y[2];
00259                 
00260                 // Compute new covariance matrix
00261                 Eigen::Matrix<double, 6, 6> I;
00262                 I.setIdentity(6, 6);
00263         P_ = (I-K*H)*P_;
00264                 
00265                 return true;
00266         }
00267 
00276         bool update(double ax, double ay, double az, double mx, double my, double mz)
00277         {
00278                 double crx, srx, cry, sry, crz, srz, mod, y[5], hx, hy;
00279                 
00280                 // Check initialization 
00281         if(!init_)
00282                         return false;
00283                 
00284                 // Remove distortion and normalize magnetometer
00285         mx = (mx - magCal_[3])/magCal_[0];
00286         my = (my - magCal_[4])/magCal_[1];
00287         mz = (mz - magCal_[5])/magCal_[2];
00288                 mod = sqrt(mx*mx + my*my + mz*mz);
00289                 mx /= mod;
00290                 my /= mod;
00291                 mz /= mod;
00292                 
00293                 // Pre-compute constants
00294         crx = cos(rx_);
00295         cry = cos(ry_);
00296         crz = cos(rz_);
00297         srx = sin(rx_);
00298         sry = sin(ry_);
00299         srz = sin(rz_);
00300                 
00301                 // Create measurement jacobian H
00302                 Eigen::Matrix<double, 5, 6> H;
00303                 H(0,0) = 0;                     H(0,1) = cry;           H(0,2) = 0;     H(0,3) = 0; H(0,4) = 0; H(0,5) = 0;
00304                 H(1,0) = -crx*cry;      H(1,1) = srx*sry;       H(1,2) = 0;     H(1,3) = 0; H(1,4) = 0; H(1,5) = 0;
00305                 H(2,0) = cry*srx;       H(2,1) = crx*sry;       H(2,2) = 0;     H(2,3) = 0; H(2,4) = 0; H(2,5) = 0;
00306                 H(3,0) = 0;                     H(3,1) = 0;                     H(3,2) = -srz;  H(3,3) = 0; H(3,4) = 0; H(3,5) = 0;
00307                 H(4,0) = 0;                     H(4,1) = 0;                     H(4,2) = -crz;  H(4,3) = 0; H(4,4) = 0; H(4,5) = 0;
00308                 
00309         // Compute measurement noise jacobian R
00310                 Eigen::Matrix<double, 5, 5> R;
00311                 mod = fabs(sqrt(ax*ax + ay*ay + az*az)-1);
00312                 R.setZero(5, 5);
00313         R(0,0) = accVar_[0];
00314         R(1,1) = accVar_[1];
00315         R(2,2) = accVar_[2];
00316         R(3,3) = magVar_[0];
00317         R(4,4) = magVar_[1];
00318         if(mod > accTh_)
00319                 {
00320                         R(0,0) += 1.5*mod*mod;
00321                         R(1,1) += 1.5*mod*mod;
00322                         R(2,2) += 1.5*mod*mod;
00323                 }
00324                 
00325                 // Compute innovation matrix
00326                 Eigen::Matrix<double, 5, 5> S;
00327         S = H*P_*H.transpose()+R;
00328                 
00329         // Compute Kalman gain
00330                 Eigen::Matrix<double, 6, 5> K; 
00331         K = P_*H.transpose()*S.inverse();
00332                 
00333                 // Compute mean error
00334                 hx = mx*cry + mz*crx*sry + my*srx*sry;
00335                 hy = my*crx - mz*srx;
00336                 mod = sqrt(hx*hx+hy*hy);
00337                 y[0] = ax-sry;
00338                 y[1] = ay+cry*srx;
00339                 y[2] = az+crx*cry;
00340                 y[3] = hx/mod-crz;
00341                 y[4] = hy/mod+srz;
00342                 
00343                 // Compute new state vector
00344         rx_ += K(0,0)*y[0]+K(0,1)*y[1]+K(0,2)*y[2]+K(0,3)*y[3]+K(0,4)*y[4];
00345         ry_ += K(1,0)*y[0]+K(1,1)*y[1]+K(1,2)*y[2]+K(1,3)*y[3]+K(1,4)*y[4];
00346         rz_ += K(2,0)*y[0]+K(2,1)*y[1]+K(2,2)*y[2]+K(2,3)*y[3]+K(2,4)*y[4];
00347         gbx_ += K(3,0)*y[0]+K(3,1)*y[1]+K(3,2)*y[2]+K(3,3)*y[3]+K(3,4)*y[4];
00348         gby_ += K(4,0)*y[0]+K(4,1)*y[1]+K(4,2)*y[2]+K(4,3)*y[3]+K(4,4)*y[4];
00349         gbz_ += K(5,0)*y[0]+K(5,1)*y[1]+K(5,2)*y[2]+K(5,3)*y[3]+K(5,4)*y[4];
00350                 
00351                 // Compute new covariance matrix
00352                 Eigen::Matrix<double, 6, 6> I;
00353                 I.setIdentity(6, 6);
00354         P_ = (I-K*H)*P_;
00355                 
00356                 return true;
00357         }
00358         
00364     bool getAngles(double &rx, double &ry, double &rz)
00365         {
00366         rx = Pi2PiRange(rx_);
00367         ry = Pi2PiRange(ry_);
00368         rz = Pi2PiRange(rz_);
00369                 return true;
00370         }
00371 
00377     bool getAngleIntegration(double &irx, double &iry, double &irz)
00378     {
00379         irx = irx_;
00380         iry = iry_;
00381         irz = irz_;
00382         return true;
00383     }
00384 
00387     bool resetAngleIntegration(void)
00388     {
00389         irx_ = iry_ = irz_ = 0.0;
00390         return true;
00391     }
00392 
00398     bool getBIAS(double &gbx, double &gby, double &gbz)
00399         {
00400         gbx = gbx_;
00401         gby = gby_;
00402         gbz = gbz_;
00403                 
00404                 return true;
00405         }
00406         
00410         bool isInit(void)
00411         {
00412         return init_;
00413         }
00414 
00418         void imuDataCallback(const sensor_msgs::Imu::ConstPtr& msg)
00419         {
00420                 // Check for IMU initialization
00421         if(!init_)
00422                 {
00423             calibData_.push_back(*msg);
00424             if(calibData_.size() > calibTime_/T_)
00425                                 initialize();
00426                         
00427                         return;
00428                 }       
00429                 
00430                 // Process sensor data
00431                 predict(msg->angular_velocity.z, msg->angular_velocity.x, msg->angular_velocity.y);
00432                 update(LIN2GRAV(msg->linear_acceleration.z), LIN2GRAV(msg->linear_acceleration.x), LIN2GRAV(msg->linear_acceleration.y));
00433 
00434         // Integrate angle rates
00435         irx_ += (msg->angular_velocity.z-gbx_)*T_;
00436         iry_ += (msg->angular_velocity.x-gby_)*T_;
00437         irz_ += (msg->angular_velocity.y-gbz_)*T_;
00438     }
00439         
00440 protected:
00441 
00446     double floorAbsolute( double value )
00447         {
00448           if (value < 0.0)
00449                 return ceil( value );
00450           else
00451                 return floor( value );
00452         }
00453 
00458     double Pi2PiRange(double contAngle)
00459         {
00460         double boundAngle = 0.0;
00461         if(fabs(contAngle)<=M_PI)
00462             boundAngle= contAngle;
00463                 else
00464                 {
00465             if(contAngle > M_PI)
00466                 boundAngle = (contAngle-2*M_PI) - 2*M_PI*floorAbsolute((contAngle-M_PI)/(2*M_PI));
00467                         
00468             if(contAngle < - M_PI)
00469                 boundAngle = (contAngle+2*M_PI) - 2*M_PI*floorAbsolute((contAngle+M_PI)/(2*M_PI));
00470                 }
00471                 
00472         return boundAngle;
00473         }
00474         
00475 
00476     double calibTime_;      
00478     double T_;                                  
00479     double T2_;                                 
00480     double rx_, ry_, rz_, gbx_, gby_, gbz_;     
00481     Eigen::MatrixXd P_;                         
00483     double magCal_[6];      
00485     double accVar_[3];      
00486     double magVar_[3];      
00487     double gyrVar_[3];      
00488     double biaVar_[3];      
00490     double accTh_;          
00492     bool init_;             
00494         // EKF Parameters
00495     double accDev_;
00496     double gyrDev_;
00497     double magDev_;
00498     double biaDev_;
00499     double biaTh_;
00500     double magXs_;
00501     double magYs_;
00502     double magZs_;
00503     double magXo_;
00504     double magYo_;
00505     double magZo_;
00506         
00507     std::vector<sensor_msgs::Imu> calibData_;   
00509     ros::NodeHandle nh_;        
00510     ros::Subscriber sub_;       
00512     double irx_, iry_, irz_;    
00513 };
00514 
00515 #endif
00516 
00517 
00518 
00519 
00520 
00521 
00522 
00523 


viodom
Author(s): Fernando Caballero , Francisco J. Perez Grau
autogenerated on Thu Jun 6 2019 20:17:02