添加IMU注释内容
							parent
							
								
									62da5259f8
								
							
						
					
					
						commit
						b9823b7892
					
				|  | @ -4,16 +4,16 @@ project(ORB_SLAM3) | |||
| IF(NOT CMAKE_BUILD_TYPE) | ||||
|   SET(CMAKE_BUILD_TYPE Release) | ||||
| ENDIF() | ||||
| 
 | ||||
| # set(CMAKE_BUILD_TYPE "Debug") | ||||
| MESSAGE("Build type: " ${CMAKE_BUILD_TYPE}) | ||||
| 
 | ||||
| set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}  -Wall   -O3") | ||||
| set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall   -O3") | ||||
| set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -march=native") | ||||
| set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -march=native") | ||||
| # set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -march=native") | ||||
| # set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -march=native") | ||||
| 
 | ||||
| # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-deprecated -O3 -march=native ") | ||||
| # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-deprecated -O3 -march=native") | ||||
| set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-deprecated -O3 -march=native ") | ||||
| set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-deprecated -O3 -march=native") | ||||
| 
 | ||||
| # Check C++11 or C++0x support | ||||
| include(CheckCXXCompilerFlag) | ||||
|  |  | |||
|  | @ -103,8 +103,10 @@ int main(int argc, char **argv) | |||
| 
 | ||||
|         // Find first imu to be considered, supposing imu measurements start first
 | ||||
|         // Step 3 默认IMU数据早于图像数据记录,找到和第一帧图像时间戳最接近的imu时间戳索引,记录在first_imu[seq]中
 | ||||
|         while(vTimestampsImu[seq][first_imu[seq]]<=vTimestampsCam[seq][0]) | ||||
|         while(vTimestampsImu[seq][first_imu[seq]]<=vTimestampsCam[seq][0]){ | ||||
|             first_imu[seq]++; | ||||
|             cout << "first_imu[seq] = "  << first_imu[seq] << endl; | ||||
|         } | ||||
|         // 因为上面退出while循环时IMU时间戳刚刚超过图像时间戳,所以这里需要再减一个索引    
 | ||||
|         first_imu[seq]--; // first imu measurement to be considered
 | ||||
| 
 | ||||
|  | @ -125,22 +127,26 @@ int main(int argc, char **argv) | |||
|     // Step 4 SLAM系统的初始化,包括读取配置文件、字典,创建跟踪、局部建图、闭环、显示线程
 | ||||
|     ORB_SLAM3::System SLAM(argv[1],argv[2],ORB_SLAM3::System::IMU_MONOCULAR, true, 0, file_name); | ||||
| 
 | ||||
|     //遍历所有数据
 | ||||
|     int proccIm = 0; | ||||
|     for (seq = 0; seq<num_seq; seq++) | ||||
|     { | ||||
|         // Main loop
 | ||||
|         cv::Mat im; | ||||
|         //存放imu数据容器,包含该加速度,角速度,时间戳
 | ||||
|         vector<ORB_SLAM3::IMU::Point> vImuMeas; | ||||
|         proccIm = 0; | ||||
|         //直方图均衡化,直方图均衡化的思想就是这样的:
 | ||||
|         //假设我有灰度级255的图像,但是都是属于[100,110]的灰度,图像对比度就很低,我应该尽可能拉到整个[0,255]
 | ||||
|         cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(3.0, cv::Size(8, 8)); | ||||
|         for(int ni=0; ni<nImages[seq]; ni++, proccIm++) | ||||
|         { | ||||
|             // Read image from file
 | ||||
|             // Step 5 读取每一帧图像并转换为灰度图存储在im
 | ||||
|             // Step 5 读取每一帧图像并转换为灰度图存储在im,seq表示第几个数据集,ni表示这个数据集的第几个数据
 | ||||
|             im = cv::imread(vstrImageFilenames[seq][ni],cv::IMREAD_GRAYSCALE); | ||||
| 
 | ||||
|             // clahe
 | ||||
|             // ?这里是什么作用?
 | ||||
|             //直方图均衡化
 | ||||
|             clahe->apply(im,im); | ||||
| 
 | ||||
| 
 | ||||
|  | @ -163,7 +169,7 @@ int main(int argc, char **argv) | |||
|             { | ||||
|                 // cout << "t_cam " << tframe << endl;
 | ||||
|                 // Step 6 把上一图像帧和当前图像帧之间的imu信息存储在vImuMeas里
 | ||||
|                 // 注意第一个图像帧没有对应的imu数据
 | ||||
|                 // 注意第一个图像帧没有对应的imu数据 //?是否存在一帧,因为之前是从最接近图像第一帧的imu算起,可能无效
 | ||||
|                 while(vTimestampsImu[seq][first_imu[seq]]<=vTimestampsCam[seq][ni]) | ||||
|                 { | ||||
|                     vImuMeas.push_back(ORB_SLAM3::IMU::Point(vAcc[seq][first_imu[seq]].x,vAcc[seq][first_imu[seq]].y,vAcc[seq][first_imu[seq]].z, | ||||
|  |  | |||
							
								
								
									
										4
									
								
								build.sh
								
								
								
								
							
							
						
						
									
										4
									
								
								build.sh
								
								
								
								
							|  | @ -27,5 +27,5 @@ echo "Configuring and building ORB_SLAM3 ..." | |||
| 
 | ||||
| mkdir build | ||||
| cd build | ||||
| cmake .. -DCMAKE_BUILD_TYPE=Release | ||||
| make -j | ||||
| cmake .. -DCMAKE_BUILD_TYPE=Debug | ||||
| make | ||||
|  |  | |||
|  | @ -193,7 +193,7 @@ protected: | |||
|     bool mHasTumbnail; | ||||
|     bool mbBad = false; | ||||
| 
 | ||||
|     bool mbIsInertial; | ||||
|     bool mbIsInertial;             //标记是否有imu
 | ||||
|     bool mbIMU_BA1; | ||||
|     bool mbIMU_BA2; | ||||
| 
 | ||||
|  |  | |||
|  | @ -99,6 +99,17 @@ public: | |||
| public: | ||||
| 
 | ||||
|     // Initialize the SLAM system. It launches the Local Mapping, Loop Closing and Viewer threads.
 | ||||
|     /**
 | ||||
|      * @brief Construct a new System object | ||||
|      *  | ||||
|      * @param[in] strVocFile               //词袋文件所在路径
 | ||||
|      * @param[in] strSettingsFile          //配置文件所在路径 
 | ||||
|      * @param[in] sensor                   //传感器类型 
 | ||||
|      * @param[in] bUseViewer               //指定是否使用可视化界面
 | ||||
|      * @param[in] initFr                   //initFr表示初始化帧的id,开始设置为0 
 | ||||
|      * @param[out] strSequence             //序列名,在跟踪线程和局部建图线程用得到 
 | ||||
|      * @param[in] strLoadingFile           //看起来作者貌似想加地图重载功能的一个参数
 | ||||
|      */ | ||||
|     System(const string &strVocFile, const string &strSettingsFile, const eSensor sensor, const bool bUseViewer = true, const int initFr = 0, const string &strSequence = std::string(), const string &strLoadingFile = std::string()); | ||||
| 
 | ||||
|     // Proccess the given stereo frame. Images must be synchronized and rectified.
 | ||||
|  |  | |||
|  | @ -244,6 +244,7 @@ bool Atlas::isInertial() | |||
| void Atlas::SetInertialSensor() | ||||
| { | ||||
|     unique_lock<mutex> lock(mMutexAtlas); | ||||
|     //接着又调用Map类的SetInertialSensor成员函数,将其设置为imu属性,以后的跟踪和预积分将和这个标志有关
 | ||||
|     mpCurrentMap->SetInertialSensor(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -149,30 +149,44 @@ cv::Mat InverseRightJacobianSO3(const cv::Mat &v) | |||
|     return InverseRightJacobianSO3(v.at<float>(0),v.at<float>(1),v.at<float>(2)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief                  计算旋转角度积分量 | ||||
|  *  | ||||
|  * @param[in] angVel       陀螺仪数据 | ||||
|  * @param[in] imuBias      陀螺仪偏置 | ||||
|  * @param[in] time         两帧间的时间差 | ||||
|  */ | ||||
| IntegratedRotation::IntegratedRotation(const cv::Point3f &angVel, const Bias &imuBias, const float &time): | ||||
|     deltaT(time) | ||||
| { | ||||
|     //得到考虑偏置后的角度旋转
 | ||||
|     const float x = (angVel.x-imuBias.bwx)*time; | ||||
|     const float y = (angVel.y-imuBias.bwy)*time; | ||||
|     const float z = (angVel.z-imuBias.bwz)*time; | ||||
| 
 | ||||
|     cv::Mat I = cv::Mat::eye(3,3,CV_32F); | ||||
| 
 | ||||
|     //计算旋转矩阵的模值,后面用罗德里格公式计算旋转矩阵时会用到
 | ||||
|     const float d2 = x*x+y*y+z*z; | ||||
|     const float d = sqrt(d2); | ||||
| 
 | ||||
|     //角度转成叉积的矩阵形式
 | ||||
|     cv::Mat W = (cv::Mat_<float>(3,3) << 0, -z, y, | ||||
|                  z, 0, -x, | ||||
|                  -y,  x, 0); | ||||
|     // eps = 1e-4 是一个小量,根据罗德里格斯公式求极限,后面的高阶小量忽略掉得到此式
 | ||||
|     if(d<eps) | ||||
|     { | ||||
|         //forster 经典预积分论文公式(4)
 | ||||
|         deltaR = I + W; | ||||
|         //小量时,右扰动 Jr = I
 | ||||
|         rightJ = cv::Mat::eye(3,3,CV_32F); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         //forster 经典预积分论文公式(3)
 | ||||
|         deltaR = I + W*sin(d)/d + W*W*(1.0f-cos(d))/d2; | ||||
|         //forster 经典预积分论文公式(8)
 | ||||
|         rightJ = I - W*(1.0f-cos(d))/d2 + W*W*(d-sin(d))/(d2*d); | ||||
|     } | ||||
| } | ||||
|  | @ -252,8 +266,16 @@ void Preintegrated::Reintegrate() | |||
|         IntegrateNewMeasurement(aux[i].a,aux[i].w,aux[i].t); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief 预积分计算,更新noise | ||||
|  *  | ||||
|  * @param[in] acceleration  加速度计数据 | ||||
|  * @param[in] angVel        陀螺仪数据 | ||||
|  * @param[in] dt            两帧之间时间差 | ||||
|  */ | ||||
| void Preintegrated::IntegrateNewMeasurement(const cv::Point3f &acceleration, const cv::Point3f &angVel, const float &dt) | ||||
| { | ||||
|     // 保存imu数据,利用中值积分的结果构造一个预积分类保存在mvMeasurements中
 | ||||
|     mvMeasurements.push_back(integrable(acceleration,angVel,dt)); | ||||
| 
 | ||||
|     // Position is updated firstly, as it depends on previously computed velocity and rotation.
 | ||||
|  | @ -261,20 +283,28 @@ void Preintegrated::IntegrateNewMeasurement(const cv::Point3f &acceleration, con | |||
|     // Rotation is the last to be updated.
 | ||||
| 
 | ||||
|     //Matrices to compute covariance
 | ||||
|     // Step 1.构造协方差矩阵 参考Forster论文公式(62),邱笑晨的《预积分总结与公式推导》的P12页也有详细推导:η_ij = A * η_i,j-1 + B_j-1 * η_j-1
 | ||||
|     // ? 位姿第一个被更新,速度第二(因为这两个只依赖前一帧计算的旋转矩阵和速度),后面再更新旋转角度
 | ||||
|     // 噪声矩阵的传递矩阵,这部分用于计算i到j-1历史噪声或者协方差
 | ||||
|     cv::Mat A = cv::Mat::eye(9,9,CV_32F); | ||||
|     // 噪声矩阵的传递矩阵,这部分用于计算j-1新的噪声或协方差,这两个矩阵里面的数都是当前时刻的,计算主要是为了下一时刻使用
 | ||||
|     cv::Mat B = cv::Mat::zeros(9,6,CV_32F); | ||||
| 
 | ||||
|      | ||||
|     // 考虑偏置后的加速度、角速度
 | ||||
|     cv::Mat acc = (cv::Mat_<float>(3,1) << acceleration.x-b.bax,acceleration.y-b.bay, acceleration.z-b.baz); | ||||
|     cv::Mat accW = (cv::Mat_<float>(3,1) << angVel.x-b.bwx, angVel.y-b.bwy, angVel.z-b.bwz); | ||||
| 
 | ||||
|     // 记录平均加速度和角速度
 | ||||
|     avgA = (dT*avgA + dR*acc*dt)/(dT+dt); | ||||
|     avgW = (dT*avgW + accW*dt)/(dT+dt); | ||||
| 
 | ||||
|      | ||||
|     // Update delta position dP and velocity dV (rely on no-updated delta rotation)
 | ||||
|     // 根据没有更新的dR来更新dP与dV  eq.(38)
 | ||||
|     dP = dP + dV*dt + 0.5f*dR*acc*dt*dt; | ||||
|     dV = dV + dR*acc*dt; | ||||
| 
 | ||||
|     // Compute velocity and position parts of matrices A and B (rely on non-updated delta rotation)
 | ||||
|     // 根据η_ij = A * η_i,j-1 + B_j-1 * η_j-1中的A矩阵和B矩阵对速度和位移进行更新
 | ||||
|     cv::Mat Wacc = (cv::Mat_<float>(3,3) << 0, -acc.at<float>(2), acc.at<float>(1), | ||||
|                                                    acc.at<float>(2), 0, -acc.at<float>(0), | ||||
|                                                    -acc.at<float>(1), acc.at<float>(0), 0); | ||||
|  | @ -285,27 +315,36 @@ void Preintegrated::IntegrateNewMeasurement(const cv::Point3f &acceleration, con | |||
|     B.rowRange(6,9).colRange(3,6) = 0.5f*dR*dt*dt; | ||||
| 
 | ||||
|     // Update position and velocity jacobians wrt bias correction
 | ||||
|     // ? 更新bias雅克比,计算偏置的雅克比矩阵,pv 分别对ba与bg的偏导数,论文中没推这个值,邱笑晨那边有推导
 | ||||
|     // 因为随着时间推移,不可能每次都重新计算雅克比矩阵,所以需要做J(k+1) = j(k) + (~)这类事,分解方式与AB矩阵相同
 | ||||
|     JPa = JPa + JVa*dt -0.5f*dR*dt*dt; | ||||
|     JPg = JPg + JVg*dt -0.5f*dR*dt*dt*Wacc*JRg; | ||||
|     JVa = JVa - dR*dt; | ||||
|     JVg = JVg - dR*dt*Wacc*JRg; | ||||
| 
 | ||||
|     // Update delta rotation
 | ||||
|     // Step 2. 构造函数,会根据更新后的bias进行角度积分
 | ||||
|     IntegratedRotation dRi(angVel,b,dt); | ||||
|     // 强行归一化使其符合旋转矩阵的格式
 | ||||
|     dR = NormalizeRotation(dR*dRi.deltaR); | ||||
| 
 | ||||
|     // Compute rotation parts of matrices A and B
 | ||||
|     // 补充AB矩阵
 | ||||
|     A.rowRange(0,3).colRange(0,3) = dRi.deltaR.t(); | ||||
|     B.rowRange(0,3).colRange(0,3) = dRi.rightJ*dt; | ||||
| 
 | ||||
|     // 小量delta初始为0,更新后通常也为0,故省略了小量的更新
 | ||||
|     // Update covariance
 | ||||
|     // Step 3.更新协方差,frost经典预积分论文的第63个公式,推导了噪声(ηa, ηg)对dR dV dP 的影响
 | ||||
|     C.rowRange(0,9).colRange(0,9) = A*C.rowRange(0,9).colRange(0,9)*A.t() + B*Nga*B.t(); | ||||
|     // 这一部分最开始是0矩阵,随着积分次数增加,每次都加上随机游走,偏置的信息矩阵
 | ||||
|     C.rowRange(9,15).colRange(9,15) = C.rowRange(9,15).colRange(9,15) + NgaWalk; | ||||
| 
 | ||||
|     // Update rotation jacobian wrt bias correction
 | ||||
|     // 计算偏置的雅克比矩阵,r对bg的导数,∂ΔRij/∂bg = (ΔRjj-1) * ∂ΔRij-1/∂bg - Jr(j-1)*t
 | ||||
|     JRg = dRi.deltaR.t()*JRg - dRi.rightJ*dt; | ||||
| 
 | ||||
|     // Total integrated time
 | ||||
|     // 更新总时间
 | ||||
|     dT += dt; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -342,6 +342,7 @@ void Map::ApplyScaledRotation(const cv::Mat &R, const float s, const bool bScale | |||
| void Map::SetInertialSensor() | ||||
| { | ||||
|     unique_lock<mutex> lock(mMutexMap); | ||||
|     //将mbIsInertial设置为true,将其设置为imu属性,以后的跟踪和预积分将和这个标志有关
 | ||||
|     mbIsInertial = true; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -37,11 +37,20 @@ namespace ORB_SLAM3 | |||
| { | ||||
| 
 | ||||
| Verbose::eLevel Verbose::th = Verbose::VERBOSITY_NORMAL; | ||||
| 
 | ||||
| System::System(const string &strVocFile, const string &strSettingsFile, const eSensor sensor, | ||||
|                const bool bUseViewer, const int initFr, const string &strSequence, const string &strLoadingFile): | ||||
|     mSensor(sensor), mpViewer(static_cast<Viewer*>(NULL)), mbReset(false), mbResetActiveMap(false), | ||||
|     mbActivateLocalizationMode(false), mbDeactivateLocalizationMode(false) | ||||
| // 系统的构造函数,将会启动其他的线程
 | ||||
| System::System(const string &strVocFile,                //词袋文件所在路径
 | ||||
|                const string &strSettingsFile,           //配置文件所在路径 
 | ||||
|                const eSensor sensor,                    //传感器类型 
 | ||||
|                const bool bUseViewer,                   //是否使用可视化界面 
 | ||||
|                const int initFr,                        //initFr表示初始化帧的id,开始设置为0
 | ||||
|                const string &strSequence,               //序列名,在跟踪线程和局部建图线程用得到
 | ||||
|                const string &strLoadingFile             //看起来作者貌似想加地图重载功能的一个参数
 | ||||
|                ): | ||||
|                 mSensor(sensor),                        //初始化传感器类型
 | ||||
|                 mpViewer(static_cast<Viewer*>(NULL)),   // ?空。。。对象指针?  TODO 
 | ||||
|                 mbReset(false), mbResetActiveMap(false),// ?重新设置ActiveMap  
 | ||||
|                 mbActivateLocalizationMode(false),      // ?是否开启局部定位功能开关
 | ||||
|                 mbDeactivateLocalizationMode(false)     // ?没有这个模式转换标志
 | ||||
| { | ||||
|     // Output welcome message
 | ||||
|     cout << endl << | ||||
|  | @ -54,15 +63,15 @@ System::System(const string &strVocFile, const string &strSettingsFile, const eS | |||
|     cout << "Input sensor was set to: "; | ||||
|     // Step 1 输出当前传感器类型
 | ||||
|     if(mSensor==MONOCULAR) | ||||
|         cout << "Monocular" << endl; | ||||
|         cout << "Monocular" << endl;             //单目
 | ||||
|     else if(mSensor==STEREO) | ||||
|         cout << "Stereo" << endl; | ||||
|         cout << "Stereo" << endl;                //双目
 | ||||
|     else if(mSensor==RGBD) | ||||
|         cout << "RGB-D" << endl; | ||||
|         cout << "RGB-D" << endl;                 //RGBD相机   
 | ||||
|     else if(mSensor==IMU_MONOCULAR) | ||||
|         cout << "Monocular-Inertial" << endl; | ||||
|         cout << "Monocular-Inertial" << endl;    //单目 + imu
 | ||||
|     else if(mSensor==IMU_STEREO) | ||||
|         cout << "Stereo-Inertial" << endl; | ||||
|         cout << "Stereo-Inertial" << endl;       //双目 + imu
 | ||||
| 
 | ||||
|     //Check settings file
 | ||||
|     // Step 2 读取配置文件
 | ||||
|  | @ -75,6 +84,7 @@ System::System(const string &strVocFile, const string &strSettingsFile, const eS | |||
|        exit(-1); | ||||
|     } | ||||
| 
 | ||||
|     // ?ORBSLAM3新加的多地图管理功能,这里好像是加载Atlas标识符
 | ||||
|     bool loadedAtlas = false; | ||||
| 
 | ||||
|     //----
 | ||||
|  | @ -172,6 +182,7 @@ System::System(const string &strVocFile, const string &strSettingsFile, const eS | |||
| 
 | ||||
|     // 设置Atlas中的传感器类型
 | ||||
|     if (mSensor==IMU_STEREO || mSensor==IMU_MONOCULAR) | ||||
|         // ? 如果是有imu的传感器类型,将mbIsInertial设置为imu属性,以后的跟踪和预积分将和这个标志有关
 | ||||
|         mpAtlas->SetInertialSensor(); | ||||
| 
 | ||||
|     // Step 6 依次创建跟踪、局部建图、闭环、显示线程
 | ||||
|  | @ -182,7 +193,7 @@ System::System(const string &strVocFile, const string &strSettingsFile, const eS | |||
| 
 | ||||
|     //Initialize the Tracking thread
 | ||||
|     //(it will live in the main thread of execution, the one that called this constructor)
 | ||||
|     // 创建跟踪线程(主线程)
 | ||||
|     // 创建跟踪线程(主线程),不会立刻开启,会在对图像和imu预处理后在main主线程种执行
 | ||||
|     cout << "Seq. Name: " << strSequence << endl; | ||||
|     mpTracker = new Tracking(this, mpVocabulary, mpFrameDrawer, mpMapDrawer, | ||||
|                              mpAtlas, mpKeyFrameDatabase, strSettingsFile, mSensor, strSequence); | ||||
|  | @ -196,6 +207,7 @@ System::System(const string &strVocFile, const string &strSettingsFile, const eS | |||
|     mpLocalMapper->mInitFr = initFr; | ||||
|     //设置最远3D地图点的深度值,如果超过阈值,说明可能三角化不太准确,丢弃
 | ||||
|     mpLocalMapper->mThFarPoints = fsSettings["thFarPoints"]; | ||||
|     // ? 这里有个疑问,C++中浮点型跟0比较是否用精确?
 | ||||
|     if(mpLocalMapper->mThFarPoints!=0) | ||||
|     { | ||||
|         cout << "Discard points further than " << mpLocalMapper->mThFarPoints << " m from current camera" << endl; | ||||
|  | @ -381,6 +393,7 @@ cv::Mat System::TrackMonocular(const cv::Mat &im, const double ×tamp, const | |||
| 
 | ||||
|     // Check mode change
 | ||||
|     { | ||||
|         // 独占锁,主要是为了mbActivateLocalizationMode和mbDeactivateLocalizationMode不会发生混乱
 | ||||
|         unique_lock<mutex> lock(mMutexMode); | ||||
|         // mbActivateLocalizationMode为true会关闭局部地图线程,仅跟踪模式
 | ||||
|         if(mbActivateLocalizationMode) | ||||
|  | @ -394,6 +407,7 @@ cv::Mat System::TrackMonocular(const cv::Mat &im, const double ×tamp, const | |||
|             } | ||||
|             // 局部地图关闭以后,只进行追踪的线程,只计算相机的位姿,没有对局部地图进行更新
 | ||||
|             mpTracker->InformOnlyTracking(true); | ||||
|             // 关闭线程可以使得别的线程得到更多的资源
 | ||||
|             mbActivateLocalizationMode = false; | ||||
|         } | ||||
|         if(mbDeactivateLocalizationMode) | ||||
|  | @ -413,6 +427,7 @@ cv::Mat System::TrackMonocular(const cv::Mat &im, const double ×tamp, const | |||
|             mbReset = false; | ||||
|             mbResetActiveMap = false; | ||||
|         } | ||||
|         //如果检测到重置活动地图,讲重置地图设置
 | ||||
|         else if(mbResetActiveMap) | ||||
|         { | ||||
|             cout << "SYSTEM-> Reseting active map in monocular case" << endl; | ||||
|  |  | |||
|  | @ -1073,7 +1073,8 @@ cv::Mat Tracking::GrabImageMonocular(const cv::Mat &im, const double ×tamp, | |||
|     } | ||||
|     else if(mSensor == System::IMU_MONOCULAR) | ||||
|     { | ||||
|         if(mState==NOT_INITIALIZED || mState==NO_IMAGES_YET) | ||||
|         //判断该帧是不是初始化
 | ||||
|         if(mState==NOT_INITIALIZED || mState==NO_IMAGES_YET)  //没有成功初始化的前一个状态就是NO_IMAGES_YET
 | ||||
|         { | ||||
|             mCurrentFrame = Frame(mImGray,timestamp,mpIniORBextractor,mpORBVocabulary,mpCamera,mDistCoef,mbf,mThDepth,&mLastFrame,*mpImuCalib); | ||||
|         } | ||||
|  | @ -1104,6 +1105,7 @@ cv::Mat Tracking::GrabImageMonocular(const cv::Mat &im, const double ×tamp, | |||
|     f_track_stats << mvpLocalMapPoints.size() << ","; | ||||
|     f_track_stats << setprecision(6) << t_track << endl;*/ | ||||
| 
 | ||||
| //开启保存数据模式
 | ||||
| #ifdef SAVE_TIMES | ||||
|     f_track_times << mCurrentFrame.mTimeORB_Ext << ","; | ||||
|     f_track_times << mCurrentFrame.mTimeStereoMatch << ","; | ||||
|  | @ -1118,7 +1120,7 @@ cv::Mat Tracking::GrabImageMonocular(const cv::Mat &im, const double ×tamp, | |||
|     return mCurrentFrame.mTcw.clone(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //将imu数据存放在mlQueueImuData的list链表里
 | ||||
| void Tracking::GrabImuData(const IMU::Point &imuMeasurement) | ||||
| { | ||||
|     unique_lock<mutex> lock(mMutexImuQueue); | ||||
|  | @ -1127,11 +1129,13 @@ void Tracking::GrabImuData(const IMU::Point &imuMeasurement) | |||
| 
 | ||||
| void Tracking::PreintegrateIMU() | ||||
| { | ||||
|     //cout << "start preintegration" << endl;
 | ||||
| 
 | ||||
|     // Step 1.拿到两两帧之间待处理的预积分数据,组成一个集合 
 | ||||
|     // cout << "start preintegration" << endl;
 | ||||
|     // 上一帧不存在,说明两帧之间没有imu数据,不进行预积分
 | ||||
|     if(!mCurrentFrame.mpPrevFrame) | ||||
|     { | ||||
|         Verbose::PrintMess("non prev frame ", Verbose::VERBOSITY_NORMAL); | ||||
|         // ? 当前帧是否进行预积分标志
 | ||||
|         mCurrentFrame.setIntegrated(); | ||||
|         return; | ||||
|     } | ||||
|  | @ -1140,6 +1144,7 @@ void Tracking::PreintegrateIMU() | |||
| 
 | ||||
|     mvImuFromLastFrame.clear(); | ||||
|     mvImuFromLastFrame.reserve(mlQueueImuData.size()); | ||||
|     // 没有imu数据,不进行预积分
 | ||||
|     if(mlQueueImuData.size() == 0) | ||||
|     { | ||||
|         Verbose::PrintMess("Not IMU data in mlQueueImuData!!", Verbose::VERBOSITY_NORMAL); | ||||
|  | @ -1149,17 +1154,22 @@ void Tracking::PreintegrateIMU() | |||
| 
 | ||||
|     while(true) | ||||
|     { | ||||
|         // 数据还没有时,会等待一段时间,直到mlQueueImuData中有imu数据.一开始不需要等待
 | ||||
|         bool bSleep = false; | ||||
|         { | ||||
|             unique_lock<mutex> lock(mMutexImuQueue); | ||||
|             if(!mlQueueImuData.empty()) | ||||
|             { | ||||
|                 // 拿到第一个imu数据作为起始数据
 | ||||
|                 IMU::Point* m = &mlQueueImuData.front(); | ||||
|                 cout.precision(17); | ||||
|                 // imu起始数据会比当前帧的前一帧时间戳早,如果相差0.001则舍弃这个imu数据
 | ||||
|                 if(m->t<mCurrentFrame.mpPrevFrame->mTimeStamp-0.001l) | ||||
|                 { | ||||
|                     mlQueueImuData.pop_front(); | ||||
|                 } | ||||
|                 // 同样最后一个的imu数据时间戳也不能理当前帧时间间隔多余0.001 
 | ||||
|                 // ? (时间戳本身的差值,单位是s秒,tum数据集里面是19位时间戳,单位为ns,这里可能只保留了10位整数和9位小数)
 | ||||
|                 else if(m->t<mCurrentFrame.mTimeStamp-0.001l) | ||||
|                 { | ||||
|                     mvImuFromLastFrame.push_back(*m); | ||||
|  | @ -1167,6 +1177,7 @@ void Tracking::PreintegrateIMU() | |||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // 得到两帧间的imu数据放入mvImuFromLastFrame中,得到后面预积分的处理数据
 | ||||
|                     mvImuFromLastFrame.push_back(*m); | ||||
|                     break; | ||||
|                 } | ||||
|  | @ -1181,32 +1192,55 @@ void Tracking::PreintegrateIMU() | |||
|             usleep(500); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     // Step 2.对两帧之间进行中值积分处理
 | ||||
|     // m个imu组数据会有m-1个预积分量
 | ||||
|     const int n = mvImuFromLastFrame.size()-1; | ||||
|     // 构造imu预处理器,并初始化标定数据
 | ||||
|     IMU::Preintegrated* pImuPreintegratedFromLastFrame = new IMU::Preintegrated(mLastFrame.mImuBias,mCurrentFrame.mImuCalib); | ||||
| 
 | ||||
|     // 针对预积分位置的不同做不同中值积分的处理
 | ||||
|     /**
 | ||||
|      *  根据上面imu帧的筛选,IMU与图像帧的时序如下: | ||||
|      *  Frame---IMU0---IMU1---IMU2---IMU3---IMU4---------------IMUx---Frame---IMUx+1 | ||||
|      *  T_------T0-----T1-----T2-----T3-----T4-----------------Tx-----_T------Tx+1 | ||||
|      *  A_------A0-----A1-----A2-----A3-----A4-----------------Ax-----_T------Ax+1 | ||||
|      *  W_------W0-----W1-----W2-----W3-----W4-----------------Wx-----_T------Wx+1 | ||||
|      *  T_和_T分别表示上一图像帧和当前图像帧的时间戳,A(加速度数据),W(陀螺仪数据),同理 | ||||
|      */ | ||||
|     for(int i=0; i<n; i++) | ||||
|     { | ||||
|         float tstep; | ||||
|         cv::Point3f acc, angVel; | ||||
|         // 第一帧数据但不是最后两帧,imu总帧数大于2
 | ||||
|         if((i==0) && (i<(n-1))) | ||||
|         { | ||||
|             // 时间差作为积分量
 | ||||
|             float tab = mvImuFromLastFrame[i+1].t-mvImuFromLastFrame[i].t; | ||||
|             // 根据上面分析的IMU与图像帧的时序分析,获取当前imu到上一帧的时间间隔
 | ||||
|             // 在加加速度不变的假设上算出第一帧图像到第二个imu数据的中值积分
 | ||||
|             float tini = mvImuFromLastFrame[i].t-mCurrentFrame.mpPrevFrame->mTimeStamp; | ||||
|             // ? 这里采用离散中值积分进行预积分,获取当前imu到上一帧的时间间隔
 | ||||
|             // 设当前时刻imu的加速度a0,下一时刻加速度a1,时间间隔tab 为t10,tini t0p
 | ||||
|             // 正常情况下时为了求上一帧到当前时刻imu的一个平均加速度,但是imu时间不会正好落在上一帧图像的时刻,需要做补偿,要求得a0时刻到上一帧这段时间加速度的改变量
 | ||||
|             // 有了这个改变量将其加到a0上之后就可以表示上一帧时的加速度了。其中a0 - (a1-a0)*(tini/tab) 为上一帧时刻的加速度再加上a1 之后除以2就为这段时间的加速度平均值
 | ||||
|             // 其中tstep表示a1到上一帧的时间间隔,a0 - (a1-a0)*(tini/tab)这个式子中tini可以是正也可以是负表示时间上的先后,(a1-a0)也是一样,多种情况下这个式子依然成立
 | ||||
|             acc = (mvImuFromLastFrame[i].a+mvImuFromLastFrame[i+1].a- | ||||
|                     (mvImuFromLastFrame[i+1].a-mvImuFromLastFrame[i].a)*(tini/tab))*0.5f; | ||||
|             angVel = (mvImuFromLastFrame[i].w+mvImuFromLastFrame[i+1].w- | ||||
|                     (mvImuFromLastFrame[i+1].w-mvImuFromLastFrame[i].w)*(tini/tab))*0.5f; | ||||
|             // 上一帧图像到下一帧imu(也就是第二个imu数据)的时间差
 | ||||
|             tstep = mvImuFromLastFrame[i+1].t-mCurrentFrame.mpPrevFrame->mTimeStamp; | ||||
|         } | ||||
|         //中间帧直接求中值
 | ||||
|         else if(i<(n-1)) | ||||
|         { | ||||
|             acc = (mvImuFromLastFrame[i].a+mvImuFromLastFrame[i+1].a)*0.5f; | ||||
|             angVel = (mvImuFromLastFrame[i].w+mvImuFromLastFrame[i+1].w)*0.5f; | ||||
|             tstep = mvImuFromLastFrame[i+1].t-mvImuFromLastFrame[i].t; | ||||
|         } | ||||
|         //最后一帧,但不是第一帧
 | ||||
|         else if((i>0) && (i==(n-1))) | ||||
|         { | ||||
|             // 直到倒数第二个imu时刻时,计算过程跟第一时刻类似,都需要考虑帧与imu时刻的关系
 | ||||
|             float tab = mvImuFromLastFrame[i+1].t-mvImuFromLastFrame[i].t; | ||||
|             float tend = mvImuFromLastFrame[i+1].t-mCurrentFrame.mTimeStamp; | ||||
|             acc = (mvImuFromLastFrame[i].a+mvImuFromLastFrame[i+1].a- | ||||
|  | @ -1215,23 +1249,28 @@ void Tracking::PreintegrateIMU() | |||
|                     (mvImuFromLastFrame[i+1].w-mvImuFromLastFrame[i].w)*(tend/tab))*0.5f; | ||||
|             tstep = mCurrentFrame.mTimeStamp-mvImuFromLastFrame[i].t; | ||||
|         } | ||||
|         //只有两帧的情况
 | ||||
|         else if((i==0) && (i==(n-1))) | ||||
|         { | ||||
|             // ? 就两个数据时使用第一个时刻的,之前size减一了,最后一帧imu好像没遍历,这时候应该还有一帧在后面,但这里直接没有算中值积分?
 | ||||
|             acc = mvImuFromLastFrame[i].a; | ||||
|             angVel = mvImuFromLastFrame[i].w; | ||||
|             tstep = mCurrentFrame.mTimeStamp-mCurrentFrame.mpPrevFrame->mTimeStamp; | ||||
|         } | ||||
| 
 | ||||
|         // Step 3.依次进行预积分计算
 | ||||
|         // 应该是必存在的吧,一个是相对上一关键帧,一个是相对上一帧
 | ||||
|         if (!mpImuPreintegratedFromLastKF) | ||||
|             cout << "mpImuPreintegratedFromLastKF does not exist" << endl; | ||||
|         mpImuPreintegratedFromLastKF->IntegrateNewMeasurement(acc,angVel,tstep); | ||||
|         pImuPreintegratedFromLastFrame->IntegrateNewMeasurement(acc,angVel,tstep); | ||||
|     } | ||||
| 
 | ||||
|     // 记录当前预积分的图像帧
 | ||||
|     mCurrentFrame.mpImuPreintegratedFrame = pImuPreintegratedFromLastFrame; | ||||
|     mCurrentFrame.mpImuPreintegrated = mpImuPreintegratedFromLastKF; | ||||
|     mCurrentFrame.mpLastKeyFrame = mpLastKeyFrame; | ||||
| 
 | ||||
|     // ? 设置为已预积分状态
 | ||||
|     mCurrentFrame.setIntegrated(); | ||||
| 
 | ||||
|     Verbose::PrintMess("Preintegration is finished!! ", Verbose::VERBOSITY_DEBUG); | ||||
|  | @ -1399,7 +1438,11 @@ void Tracking::ResetFrameIMU() | |||
| 
 | ||||
| /**
 | ||||
|  * @brief 跟踪过程,包括恒速模型跟踪、参考关键帧跟踪、局部地图跟踪 | ||||
|  * track包含两部分:估计运动、跟踪局部地图 | ||||
|  *  | ||||
|  * Step 1:初始化 | ||||
|  * Step 2:跟踪 | ||||
|  * Step 3:记录位姿信息,用于轨迹复现 | ||||
|  */ | ||||
| void Tracking::Track() | ||||
| { | ||||
|  | @ -1409,7 +1452,7 @@ void Tracking::Track() | |||
|     mTime_LocalMapTrack = 0; | ||||
|     mTime_NewKF_Dec = 0; | ||||
| #endif | ||||
| 
 | ||||
|     // ? 还不清楚这个标识符,跟绘图相关?
 | ||||
|     if (bStepByStep) | ||||
|     { | ||||
|         while(!mbStep) | ||||
|  | @ -1445,12 +1488,14 @@ void Tracking::Track() | |||
|         { | ||||
|             // 如果当前图像时间戳和前一帧图像时间戳大于1s,说明时间戳明显跳变了,重置地图后直接返回
 | ||||
|             cout << "id last: " << mLastFrame.mnId << "    id curr: " << mCurrentFrame.mnId << endl; | ||||
|             //根据是否是imu模式,进行imu的补偿
 | ||||
|             if(mpAtlas->isInertial()) | ||||
|             { | ||||
|                 // 如果当前地图imu成功初始化
 | ||||
|                 if(mpAtlas->isImuInitialized()) | ||||
|                 { | ||||
|                     cout << "Timestamp jump detected. State set to LOST. Reseting IMU integration..." << endl; | ||||
|                     // ? BA2标志代表什么?,BA优化成功?
 | ||||
|                     if(!pCurrentMap->GetIniertialBA2()) | ||||
|                     { | ||||
|                         // 如果当前子图中imu没有经过BA2,重置active地图
 | ||||
|  | @ -1474,8 +1519,9 @@ void Tracking::Track() | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Step 3 IMU模式下设置IMU的Bias参数
 | ||||
|     // Step 3 IMU模式下设置IMU的Bias参数,还要保证上一帧存在非空
 | ||||
|     if ((mSensor == System::IMU_MONOCULAR || mSensor == System::IMU_STEREO) && mpLastKeyFrame) | ||||
|         //认为bias在两帧间不变
 | ||||
|         mCurrentFrame.SetNewBias(mpLastKeyFrame->GetImuBias()); | ||||
| 
 | ||||
|     if(mState==NO_IMAGES_YET) | ||||
|  | @ -1484,7 +1530,7 @@ void Tracking::Track() | |||
|     } | ||||
| 
 | ||||
|     mLastProcessedState=mState; | ||||
|     // Step 4 IMU模式下对IMU数据进行预积分
 | ||||
|     // Step 4 IMU模式下对IMU数据进行预积分 -> // ? 没有创建地图的情况下
 | ||||
|     if ((mSensor == System::IMU_MONOCULAR || mSensor == System::IMU_STEREO) && !mbCreatedMap) | ||||
|     { | ||||
| #ifdef SAVE_TIMES | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue