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
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
00071 accDev_ = 0.006;
00072 gyrDev_ = 0.005;
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;
00081 biaTh_ = 0.005;
00082
00083
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
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
00114
00115
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
00120
00121
00122 magCal_[0] = magXs_; magCal_[1] = magYs_; magCal_[2] = magZs_;
00123 magCal_[3] = magXo_; magCal_[4] = magYo_; magCal_[5] = magZo_;
00124
00125
00126 accVar_[0] = accDev_*accDev_; accVar_[1] = accDev_*accDev_; accVar_[2] = accDev_*accDev_;
00127 gyrVar_[0] = gyrDev_*gyrDev_; gyrVar_[1] = gyrDev_*gyrDev_; gyrVar_[2] = gyrDev_*gyrDev_;
00128 magVar_[0] = magDev_*magDev_; magVar_[1] = magDev_*magDev_; magVar_[2] = magDev_*magDev_;
00129 biaVar_[0] = biaDev_*biaDev_; biaVar_[1] = biaDev_*biaDev_; biaVar_[2] = biaDev_*biaDev_;
00130
00131
00132 accTh_ = sqrt(accVar_[0]+accVar_[1]+accVar_[2]);
00133
00134
00135 rx_ = ry_ = rz_ = 0.0;
00136 gbx_ = gx_m;
00137 gby_ = gy_m;
00138 gbz_ = gz_m;
00139
00140
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
00149
00150
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
00171 if(!init_)
00172 return false;
00173
00174
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
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
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
00210 if(!init_)
00211 return false;
00212
00213
00214 crx = cos(rx_);
00215 cry = cos(ry_);
00216 srx = sin(rx_);
00217 sry = sin(ry_);
00218
00219
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
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
00233
00234
00235
00236
00237
00238
00239
00240 Eigen::Matrix<double, 3, 3> S;
00241 S = H*P_*H.transpose()+R;
00242
00243
00244 Eigen::Matrix<double, 6, 3> K;
00245 K = P_*H.transpose()*S.inverse();
00246
00247
00248 y[0] = ax-sry;
00249 y[1] = ay+cry*srx;
00250 y[2] = az+crx*cry;
00251
00252
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
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
00281 if(!init_)
00282 return false;
00283
00284
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
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
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
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
00326 Eigen::Matrix<double, 5, 5> S;
00327 S = H*P_*H.transpose()+R;
00328
00329
00330 Eigen::Matrix<double, 6, 5> K;
00331 K = P_*H.transpose()*S.inverse();
00332
00333
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
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
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
00421 if(!init_)
00422 {
00423 calibData_.push_back(*msg);
00424 if(calibData_.size() > calibTime_/T_)
00425 initialize();
00426
00427 return;
00428 }
00429
00430
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
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
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