1. 程式人生 > >視覺和imu(慣性感測器)

視覺和imu(慣性感測器)

由於轉載的地方沒有標明出處,這裡也沒提供出處。

目前單目slam存在初始化的尺度問題和追蹤的尺度漂移問題,而雙目也存在精度不高和魯棒性不好的問題。針對這些問題,提出了融合imu的想法。

那麼imu的作用是什麼呢?

單目

(1)解決初始化尺度問題

(2)追蹤中提供較好的初始位姿。

(3)提供重力方向

(4)提供一個時間誤差項以供優化

雙目

(1)追蹤中提供較好的初始位姿。

(2)提供重力方向

(3)提供一個時間誤差項以供優化

目前做這方面融合論文很多,但開源的比較少,這裡給出幾個比較好的開源code和論文

開源code:

(1)imu和單目的資料融合開原始碼(EKF)

https://github.com/ethz-asl/rovio

(2)imu和單目的資料融合開原始碼

https://github.com/ethz-asl/okvis_ros(非線性優化)

(3)orbslam+imu(立體相機)

https://github.com/JzHuai0108/ORB_SLAM

論文:

(1)Keyframe-based visual–inertial odometry(okvis的論文)

(2) IMU Preintegration on Manifold for Efficient Visual-Inertial Maximum-a-Posteriori Estimation(預積分)

(3)Visual-Inertial Monocular SLAM with Map Reuse (orb+imu)

(4)Robust Visual Inertial Odometry Using a Direct EKF-Based Approach(eth的rovio)

(5)On-Manifold Preintegration for Real-Time Visual-Inertial Odometry(gtsam)

由於是初學比較詳細看得就是以上5篇,而且自認為還不錯的論文。

本人研究的是基於非線性優化的視覺和imu融合的演算法研究,那麼這裡先引出融合的方式:

濾波方法:

(1)緊耦合

(2)鬆耦合

非線性優化:

(1)緊耦合(本人研究方向)

(2)鬆耦合

imu'和視覺是怎樣融合的呢?

僅僅視覺的時候我們優化的只是重投影誤差項:

以上的公式我就不解釋了。

而imu+視覺優化的是重投影誤差項+imu的時間誤差項:

其中imu時間誤差項:

其中為:

這裡:imu時間誤差項要求的主要有5個變數:eR,ev,ep,eb,W。即求(R ,v,p,b,W)

這裡先給出一張非線性優化視覺+imu融合的圖:

下面我們就開始用與積分的方式求以上的6個變數,下面給出預積分的code

 在CODE上檢視程式碼片派生到我的程式碼片

  1. Eigen::Matrix4d Tracking::propagate(const double time_frame)  
  2. {  
  3.     bool is_meas_good=getObservation(time_frame);  
  4.     assert(is_meas_good);  
  5.     time_pair[0]=time_pair[1];  
  6.     time_pair[1]=time_frame;  
  7.     Eigen::Vector3d tempVs0inw;  
  8.     Eigen::Matrix<double, 15,15>* holder=NULL;  
  9.     if(bPredictCov)  
  10.         holder= &P_;  
  11.     predictStates(T_s1_to_w, speed_bias_1, time_pair,  
  12.                                  measurement, imu_.gwomegaw, imu_.q_n_aw_babw,  
  13.                                  &pred_T_s2_to_w, &tempVs0inw);  
  14.     pred_speed_bias_2.head<3>()=tempVs0inw;//速度偏差  
  15.     pred_speed_bias_2.tail<6>()=speed_bias_1.tail<6>();     //biases do not change in propagation  
  16.    Eigen::Matrix4d pred_Tr_delta=pred_T_s2_to_w*imu_.T_imu_from_cam;//camera-imu-world(矩陣的乘法從左開始)  
  17.    cam_to_w=pred_Tr_delta;  
  18.    pred_Tr_delta=pred_Tr_delta.inverse()*(T_s1_to_w*imu_.T_imu_from_cam);//由imu計算(預測)上一幀-》當前幀的變換關  
  19.   // T_s1_to_w=pred_T_s2_to_w;  
  20.    speed_bias_1=pred_speed_bias_2;  
  21.    return pred_Tr_delta;  
  22. }  

 在CODE上檢視程式碼片派生到我的程式碼片

  1. void Tracking::predictStates(const Eigen::Matrix4d  &T_sk_to_w, const Eigen::Matrix<double, 9,1>& speed_bias_k,  
  2.                    const double * time_pair,  
  3.                    std::vector<Eigen::Matrix<double, 7,1> >& measurements, const Eigen::Matrix<double, 6,1> & gwomegaw,  
  4.                    const Eigen::Matrix<double, 12, 1>& q_n_aw_babw,  
  5.                    Eigen::Matrix4d  * pred_T_skp1_to_w, Eigen::Matrix<double, 3,1>* pred_speed_kp1,  
  6.                    Eigen::Matrix<double, 15,15> *covariance,  
  7.                    Eigen::Matrix<double, 15,15>  *jacobian)  
  8. {  
  9.     double time=time_pair[0],end = time_pair[1];  
  10.     // the eventual covariance has little to do with this param as long as it remains small  
  11.     Eigen::Matrix<double, 3,1>  r_0(T_sk_to_w.topRightCorner<3, 1>());  
  12.     Eigen::Matrix<double,3,3> C_WS_0(T_sk_to_w.topLeftCorner<3, 3>());  
  13.     Eigen::Quaternion<double>  q_WS_0(C_WS_0);  
  14.     Eigen::Quaterniond Delta_q(1,0,0,0);  
  15.     Eigen::Matrix3d C_integral = Eigen::Matrix3d::Zero();  
  16.     Eigen::Matrix3d C_doubleintegral = Eigen::Matrix3d::Zero();  
  17.     Eigen::Vector3d acc_integral = Eigen::Vector3d::Zero();  
  18.     Eigen::Vector3d acc_doubleintegral = Eigen::Vector3d::Zero();  
  19.     Eigen::Matrix3d cross = Eigen::Matrix3d::Zero();  
  20.     // sub-Jacobians  
  21.     Eigen::Matrix3d dalpha_db_g = Eigen::Matrix3d::Zero();  
  22.     Eigen::Matrix3d dv_db_g = Eigen::Matrix3d::Zero();  
  23.     Eigen::Matrix3d dp_db_g = Eigen::Matrix3d::Zero();  
  24.     // the Jacobian of the increment (w/o biases)  
  25.     Eigen::Matrix<double,15,15> P_delta = Eigen::Matrix<double,15,15>::Zero();  
  26.     double Delta_t = 0;  
  27.     bool hasStarted = false;  
  28.     int i = 0;  
  29.     for (int it=0;it<measurements.size();it++)  
  30.     {  
  31.         Eigen::Vector3d omega_S_0 =measurements[it].block<3,1>(4,0);//角速度  
  32.         Eigen::Vector3d acc_S_0 = measurements[it].block<3,1>(1,0);//線加速度  
  33.         Eigen::Vector3d omega_S_1 = measurements[it+1].block<3,1>(4,0);  
  34.         Eigen::Vector3d acc_S_1 = measurements[it+1].block<3,1>(1,0);  
  35.         ave_omega_S=ave_omega_S+omega_S_0;  
  36.         ave_omega_S=ave_omega_S/(it+1);  
  37.         // time delta  
  38.         double nexttime;  
  39.        if ((it + 1) == (measurements.size()-1)) {  
  40.           nexttime = end;  
  41.         }  
  42.         else  
  43.           nexttime =measurements [it + 1][0];  
  44.         double dt = (nexttime - time);  
  45.         if ( end < nexttime) {  
  46.           double interval = (nexttime - measurements[it][0]);  
  47.           nexttime = end;  
  48.           dt = (nexttime - time);  
  49.           const double r = dt / interval;  
  50.           omega_S_1 = ((1.0 - r) * omega_S_0 + r * omega_S_1).eval();  
  51.           acc_S_1 = ((1.0 - r) * acc_S_0 + r * acc_S_1).eval();  
  52.         }  
  53.       /* if ( it+1==measurements.size()) { 
  54.           double interval = last_dt; 
  55.           nexttime = end; 
  56.           double dt = (nexttime - time); 
  57.           const double r = dt / interval; 
  58.           omega_S_1 = ((1.0 - r) * omega_S_0 + r * omega_S_1).eval(); 
  59.           acc_S_1 = ((1.0 - r) * acc_S_0 + r * acc_S_1).eval(); 
  60.         } 
  61.         else 
  62.         nexttime =measurements [it + 1][0]; 
  63.           double dt = (nexttime - time);*/  
  64.       if (dt <= 0.0) {  
  65.           continue;  
  66.         }  
  67.         Delta_t += dt;  
  68.     if (!hasStarted) {  
  69.       hasStarted = true;  
  70.       const double r = dt / (nexttime -measurements[it][0]);  
  71.       omega_S_0 = (r * omega_S_0 + (1.0 - r) * omega_S_1).eval();//求開始是加權的角速度和線加速度  
  72.       acc_S_0 = (r * acc_S_0 + (1.0 - r) * acc_S_1).eval();  
  73.     }  
  74.     // ensure integrity  
  75.     double sigma_g_c = q_n_aw_babw(3);//Gyroscope noise density.  
  76.     double sigma_a_c = q_n_aw_babw(1);  
  77.     // actual propagation  
  78.     // orientation:  
  79.     Eigen::Quaterniond dq;  
  80.     const Eigen::Vector3d omega_S_true = (0.5*(omega_S_0+omega_S_1) - speed_bias_k.segment<3>(3));//w  
  81.     const double theta_half = omega_S_true.norm() * 0.5 * dt;  
  82.     const double sinc_theta_half = ode(theta_half);  
  83.     const double cos_theta_half = cos(theta_half);  
  84.     dq.vec() = sinc_theta_half * omega_S_true * 0.5 * dt;  
  85.     dq.w() = cos_theta_half;  
  86.     Eigen::Quaterniond Delta_q_1 = Delta_q * dq;  
  87.     // rotation matrix integral:  
  88.     const Eigen::Matrix3d C = Delta_q.toRotationMatrix();  
  89.     const Eigen::Matrix3d C_1 = Delta_q_1.toRotationMatrix();  
  90.     const Eigen::Vector3d acc_S_true = (0.5*(acc_S_0+acc_S_1) - speed_bias_k.segment<3>(6));  
  91.     const Eigen::Matrix3d C_integral_1 = C_integral + 0.5*(C + C_1)*dt;  
  92.     const Eigen::Vector3d acc_integral_1 = acc_integral + 0.5*(C + C_1)*acc_S_true*dt;  
  93.     // rotation matrix double integral:  
  94.     C_doubleintegral += C_integral*dt + 0.25*(C + C_1)*dt*dt;  
  95.     acc_doubleintegral += acc_integral*dt + 0.25*(C + C_1)*acc_S_true*dt*dt;  
  96.     // Jacobian parts  
  97.     dalpha_db_g += dt*C_1;  
  98.     const Eigen::Matrix3d cross_1 = dq.inverse().toRotationMatrix()*cross +  
  99.     okvis::kinematics::rightJacobian(omega_S_true*dt)*dt;  
  100.     const Eigen::Matrix3d acc_S_x = crossMx(acc_S_true);  
  101.     Eigen::Matrix3d dv_db_g_1 = dv_db_g + 0.5*dt*(C*acc_S_x*cross + C_1*acc_S_x*cross_1);  
  102.     dp_db_g += dt*dv_db_g + 0.25*dt*dt*(C*acc_S_x*cross + C_1*acc_S_x*cross_1);  
  103.     // covariance propagation  
  104.     if (covariance) {  
  105.       Eigen::Matrix<double,15,15> F_delta = Eigen::Matrix<double,15,15>::Identity();  
  106.       // transform  
  107.       F_delta.block<3,3>(0,3) = -crossMx(acc_integral*dt + 0.25*(C + C_1)*acc_S_true*dt*dt);  
  108.       F_delta.block<3,3>(0,6) = Eigen::Matrix3d::Identity()*dt;  
  109.       F_delta.block<3,3>(0,9) = dt*dv_db_g + 0.25*dt*dt*(C*acc_S_x*cross + C_1*acc_S_x*cross_1);  
  110.       F_delta.block<3,3>(0,12) = -C_integral*dt + 0.25*(C + C_1)*dt*dt;  
  111.       F_delta.block<3,3>(3,9) = -dt*C_1;  
  112.       F_delta.block<3,3>(6,3) = -crossMx(0.5*(C + C_1)*acc_S_true*dt);  
  113.       F_delta.block<3,3>(6,9) = 0.5*dt*(C*acc_S_x*cross + C_1*acc_S_x*cross_1);  
  114.       F_delta.block<3,3>(6,12) = -0.5*(C + C_1)*dt;  
  115.       P_delta = F_delta*P_delta*F_delta.transpose();  
  116.       // add noise. Note that transformations with rotation matrices can be ignored, since the noise is isotropic.  
  117.       //F_tot = F_delta*F_tot;  
  118.       const double sigma2_dalpha = dt * sigma_g_c * sigma_g_c;  
  119.       P_delta(3,3) += sigma2_dalpha;  
  120.       P_delta(4,4) += sigma2_dalpha;  
  121.       P_delta(5,5) += sigma2_dalpha;  
  122.       const double sigma2_v = dt * sigma_a_c * q_n_aw_babw(1);  
  123.       P_delta(6,6) += sigma2_v;  
  124.       P_delta(7,7) += sigma2_v;  
  125.       P_delta(8,8) += sigma2_v;  
  126.       const double sigma2_p = 0.5*dt*dt*sigma2_v;  
  127.       P_delta(0,0) += sigma2_p;  
  128.       P_delta(1,1) += sigma2_p;  
  129.       P_delta(2,2) += sigma2_p;  
  130.       const double sigma2_b_g = dt * q_n_aw_babw(9) * q_n_aw_babw(9);  
  131.       P_delta(9,9)   += sigma2_b_g;  
  132.       P_delta(10,10) += sigma2_b_g;  
  133.       P_delta(11,11) += sigma2_b_g;  
  134.       const double sigma2_b_a = dt * q_n_aw_babw(6) * q_n_aw_babw(6);  
  135.       P_delta(12,12) += sigma2_b_a;  
  136.       P_delta(13,13) += sigma2_b_a;  
  137.       P_delta(14,14) += sigma2_b_a;  
  138.     }  
  139.     // memory shift  
  140.     Delta_q = Delta_q_1;  
  141.     C_integral = C_integral_1;  
  142.     acc_integral = acc_integral_1;  
  143.     cross = cross_1;  
  144.     dv_db_g = dv_db_g_1;  
  145.     time = nexttime;  
  146.     interval_time=Delta_t;  
  147.      last_dt=dt;  
  148.     ++i;  
  149.     if (nexttime == end)  
  150.       break;  
  151.   }  
  152. // actual propagation output:  
  153. const Eigen::Vector3d g_W = gwomegaw.head<3>();  
  154. const Eigen::Vector3d  t=r_0+speed_bias_k.head<3>()*Delta_t+ C_WS_0*(acc_doubleintegral)+0.5*g_W*Delta_t*Delta_t;  
  155. const  Eigen::Quaterniond q=q_WS_0*Delta_q;  
  156. (*pred_T_skp1_to_w)=rt_to_T(t,q.toRotationMatrix());  
  157. (*pred_speed_kp1)=speed_bias_k.head<3>() + C_WS_0*(acc_integral)+g_W*Delta_t;//???語法曾有錯誤  
  158. if (jacobian) {  
  159.   Eigen::Matrix<double,15,15> & F = *jacobian;  
  160.   F.setIdentity(); // holds for all states, including d/dalpha, d/db_g, d/db_a  
  161.   F.block<3,3>(0,3) = -okvis::kinematics::crossMx(C_WS_0*acc_doubleintegral);  
  162.   F.block<3,3>(0,6) = Eigen::Matrix3d::Identity()*Delta_t;  
  163.   F.block<3,3>(0,9) = C_WS_0*dp_db_g;  
  164.   F.block<3,3>(0,12) = -C_WS_0*C_doubleintegral;  
  165.   F.block<3,3>(3,9) = -C_WS_0*dalpha_db_g;  
  166.   F.block<3,3>(6,3) = -okvis::kinematics::crossMx(C_WS_0*acc_integral);  
  167.   F.block<3,3>(6,9) = C_WS_0*dv_db_g;  
  168.   F.block<3,3>(6,12) = -C_WS_0*C_integral;  
  169. }  
  170. // overall covariance, if requested  
  171. if (covariance) {  
  172.   Eigen::Matrix<double,15,15> & P = *covariance;  
  173.   // transform from local increments to actual states  
  174.   Eigen::Matrix<double,15,15> T = Eigen::Matrix<double,15,15>::Identity();  
  175.   T.topLeftCorner<3,3>() = C_WS_0;  
  176.   T.block<3,3>(3,3) = C_WS_0;  
  177.   T.block<3,3>(6,6) = C_WS_0;  
  178.   P = T * P_delta * T.transpose();  
  179. }  
  180. }  

以上code來自以下公式:

其中認為角速度w和加速度a在連續兩次imu測量之間是勻速的,因此上式可寫成:

其中上式的角速度和加速度:

因此最終公式:

上面公式給出5個變數(R,V,P,b,W)中的3個最重要的變數:R,V,P。

而偏差變數b我們可以初始化的時候可以設為0(其實最好是要求出來的,這裡就不給出推倒公式了)。

下面的們就是有關W(權重)的公式了。

其中

是有關R,P,V,b的協方差矩陣

到此為止已經把imu時間誤差項求完。

下一篇將是怎樣把時間誤差項融合到目標函式裡(主要是區域性地圖的優化)

--------------------- 本文來自 學之之博未若之之要-知之之要未若行之之實 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/datase/article/details/78586880?utm_source=copy