本篇博客将主要记录用来实例化SLAM系统的System类的一些用法。
System.h
中包含了七个类,分别是Viewer,FrameDrawer,Map,Tracking,LocalMapping,LoopClosing的声明,和System类的定义,就像描述的一样,这些类组成了一个系统。
class Viewer;
class FrameDrawer;
class Map;
class Tracking;
class LocalMapping;
class LoopClosing;
class System;
System 类中的public成员包含一个sensor枚举和一些成员函数,主要有:
① sensor枚举
// Input sensor
enum eSensor{
MONOCULAR=0,
STEREO=1,
RGBD=2
};
0,1,2分别代表传感器的类型。
② System构造函数
System(const string &strVocFile, const string &strSettingsFile, const eSensor sensor, const bool bUseViewer = true);
读入词包路径,读入YAML配置文件,设置SLAM为mono状态,启用viewer的线程。
③ Tracking函数
cv::Mat TrackStereo(const cv::Mat &imLeft, const cv::Mat &imRight, const double ×tamp);
cv::Mat TrackRGBD(const cv::Mat &im, const cv::Mat &depthmap, const double ×tamp);
cv::Mat TrackMonocular(const cv::Mat &im, const double ×tamp);
针对不同传感器不同的Tracking。输入图像可以使rgb的也可以是grayscale的(最终读进去都会转化为grayscale的),函数返回值为camera的位姿pose。
④ 定位模式函数
void ActivateLocalizationMode();
void DeactivateLocalizationMode();
调用前者终止mapping线程,开启定位模式,调用后者重启mapping线程。
⑤ 重启与终止函数
void Reset();
void Shutdown();
前者可以清空map,后者可以终止所有线程,在 保存相机轨迹之前 需要调用此函数。
⑥ SaveTrajectory 函数
void SaveTrajectoryTUM(const string &filename);
void SaveKeyFrameTrajectoryTUM(const string &filename);
void SaveTrajectoryKITTI(const string &filename);
把相机轨迹存成相应数据集的格式,调用此函数时先shutdown SLAM系统,mono_kittti中save函数用的是SaveKeyFrameTrajectoryTUM
,这个函数看起来像是只能用于TUM数据集,但三种传感器均适合。
除上述这些外,private成员里还有一些其他的变量就不一一列举,之后学习后再记录,大致看了一下,基本是各个类的指针,在成员函数中作为其他类的接口使用,可能用于线程之间互相通信吧。
前面说到System构造函数用于实例化一个SLAM系统,开启局部建图(Local Mapping),回环检测(Loop Closing),和可视化界面(Viewer)的线程。
sensor → mSensor
static_cast(NULL) → mpViewer
mbReset 设置为 false
mbActivateLocalizationMode 设置为 false
mbDeactivateLocalizationMode 设置为 false
sensor是传进来的形参,是前面枚举体中三种传感器的一个,这里为MONOCULAR
,它传递给了mSensor,这是一个System类的隐含成员变量,两种变量类型一样。
mpViewer是System类的隐含成员变量,Viewer类指针,这里赋空。
mbReset,mbActivateLocalizationMode,mbDeactivateLocalizationMode均为bool型,赋false。
//Check settings file
cv::FileStorage fsSettings(strSettingsFile.c_str(), cv::FileStorage::READ);
if(!fsSettings.isOpened())
{
cerr << "Failed to open settings file at: " << strSettingsFile << endl;
exit(-1);
}
//Load ORB Vocabulary
cout << endl << "Loading ORB Vocabulary. This could take a while..." << endl;
mpVocabulary = new ORBVocabulary();
bool bVocLoad = mpVocabulary->loadFromTextFile(strVocFile);
if(!bVocLoad)
{
cerr << "Wrong path to vocabulary. " << endl;
cerr << "Falied to open at: " << strVocFile << endl;
exit(-1);
}
cout << "Vocabulary loaded!" << endl << endl;
从strSettingsFile
这个途径中读取文件,类型为只读,接下来创建一个新类ORBVocabulary
,用一个mpVocabulary指针指向它,调用类内的函数 loadFromTextFile() 将 strVocFile(字典路径)装载进去。(ORBVocabulary
类是 typedef 成的,来源于 DBoW2 的TemplatedVocabulary类,类参数为 FORB::TDescriptor 和 FORB,现在还不知道什么意思,之后学习后会记录)
初始化各种线程和数据库
①用词袋初始化关键帧数据库( 用于 重定位 和 回环检测 )
②初始化一个Map类,该类用于存储指向所有 关键帧 和 地图点 的指针
③初始化画图工具,用于可视化。
④初始化 Tracking线程 ,主线程 ,使用this指针(只初始化不启动,启动在 main 函数里 TrackMonocular() 启动)
⑤初始化 Local Mapping线程 并启动(这里mSensor传入MONOCULAR)
⑥初始化 Loop Closing线程 并启动(这里mSensor传入的不是MONOCULAR)
⑦初始化 Viewer线程 并启动,也使用了this指针;给 Tracking线程设置Viewer
⑧三个线程每两个线程之间设置指针
//Create KeyFrame Database
mpKeyFrameDatabase = new KeyFrameDatabase(*mpVocabulary);
//Create the Map
mpMap = new Map();
//Create Drawers. These are used by the Viewer
mpFrameDrawer = new FrameDrawer(mpMap);
mpMapDrawer = new MapDrawer(mpMap, strSettingsFile);
//Initialize the Tracking thread
//(it will live in the main thread of execution, the one that called this constructor)
mpTracker = new Tracking(this, mpVocabulary, mpFrameDrawer, mpMapDrawer,
mpMap, mpKeyFrameDatabase, strSettingsFile, mSensor);
//Initialize the Local Mapping thread and launch
mpLocalMapper = new LocalMapping(mpMap, mSensor==MONOCULAR);
mptLocalMapping = new thread(&ORB_SLAM2::LocalMapping::Run,mpLocalMapper);
//Initialize the Loop Closing thread and launch
mpLoopCloser = new LoopClosing(mpMap, mpKeyFrameDatabase, mpVocabulary, mSensor!=MONOCULAR);
mptLoopClosing = new thread(&ORB_SLAM2::LoopClosing::Run, mpLoopCloser);
//Initialize the Viewer thread and launch
if(bUseViewer)
{
mpViewer = new Viewer(this, mpFrameDrawer,mpMapDrawer,mpTracker,strSettingsFile);
mptViewer = new thread(&Viewer::Run, mpViewer);
mpTracker->SetViewer(mpViewer);
}
//Set pointers between threads
mpTracker->SetLocalMapper(mpLocalMapper);
mpTracker->SetLoopClosing(mpLoopCloser);
mpLocalMapper->SetTracker(mpTracker);
mpLocalMapper->SetLoopCloser(mpLoopCloser);
mpLoopCloser->SetTracker(mpTracker);
mpLoopCloser->SetLocalMapper(mpLocalMapper);
接下来就是这几个线程的工作过程了,感觉有必要看一下有关多线程方面的知识了,还要看一下词袋怎么用来回环检测的,然后看看每个线程如何工作的,互相之间又是通信的。