ORBSLAM的LocalMapping模块和Tracking模块的接口讲解
Track线程 和 LocalMapping 线程的交互(很多人在读代码的时候发现这个疑问,它们是怎么交互的?)。下面给出它们的关系,供大家理解整体系统的。
在ORBSLAM系统中,主流的是Track线程,它能够跟踪每一帧的图像(里面有点和线段等等特征)。在完成一个图像匹配后,如果这一帧是KeyFrame的时候,会调用InsertKeyFrame()。它自动调用LocalMapping线程,这个线程在LocalMapping.h中,可以看到它所有的实现
下图给出具体的流程:
Tracking 线程|| 1. InsertKeyFrame(pKF)v
LocalMapping::InsertKeyFrame()|| 2. push 到队列 mvpNewKeyFrames| 设置 mbAbortBA=true(打断优化)|| 3. 唤醒 LocalMapping 线程v
LocalMapping::Run()|| 4. 等待队列非空 → ProcessNewKeyFrame()|| 5. MapPointCulling()|| 6. CreateNewMapPoints()|| 7. Local BA (OptimizeLocalMap)
LocalMapping这个类,维持一个基本的地图,它用于后续的Tracking.
对于LocalMapping具体实现如下:
Step 1 — Tracking 决定插入关键帧(Track.cc):
当 Tracking 判断需要新增关键帧(insertKF = true)
if (NeedNewKeyFrame())
{CreateNewKeyFrame();
}
关键帧创建后:
mpLocalMapper->InsertKeyFrame(pKF);
Step 2 — LocalMapping::InsertKeyFrame()(LocalMapping.cc)
这是“唤醒 LocalMapping 的入口”:
void LocalMapping::InsertKeyFrame(KeyFrame *pKF)
{unique_lock<mutex> lock(mMutexNewKFs);mvpNewKeyFrames.push_back(pKF);// 这句非常关键:打断当前 Local BAmbAbortBA = true;// 唤醒 LocalMapping::Run()
}
注意:没有显式的 notify() 或 condition_variable
LocalMapping 线程是通过“检查队列是否为空”来间接唤醒的
Step 3 — LocalMapping线程的主循环等待新关键帧(LocalMapping.cc)
void LocalMapping::Run()
{while (1){// 如果有新 KeyFrame,处理它if (CheckNewKeyFrames()){ProcessNewKeyFrame();MapPointCulling();CreateNewMapPoints();if (!CheckNewKeyFrames())OptimizeLocalMap();MapPointCulling();}else if (StopRequested()){// 等待 Tracking 或 LoopClosing 解除暂停while (isStopped() && !CheckFinish()) usleep(3000);}// small sleep 避免死循环占 CPUusleep(3000);}
}
LocalMapping 其实是一个 忙等 + sleep 的线程,没有 wait/notify
Step 4 — CheckNewKeyFrames() 负责“检查是否被唤醒”
bool LocalMapping::CheckNewKeyFrames()
{unique_lock<mutex> lock(mMutexNewKFs);return(!mvpNewKeyFrames.empty());
}
只要 Tracking 推入了一个 KeyFrame,LocalMapping 下次循环就会醒来.
Step 5 — ProcessNewKeyFrame()(正式处理关键帧)
void LocalMapping::ProcessNewKeyFrame()
{// 取出队列中的第一个 KeyFrame{unique_lock<mutex> lock(mMutexNewKFs);mpCurrentKeyFrame = mvpNewKeyFrames.front();mvpNewKeyFrames.pop_front();}// 更新共视图、生成BoW、添加到地图等
}
Step 6 — MapPointCulling()
剔除短生命周期点。
Step 7 — CreateNewMapPoints()(真正的三角化步骤)
这里可以插入你自己的点生成逻辑
Step 8 — OptimizeLocalMap()(Local BA)
本地优化完成后再进行一次点剔除
最终完整顺序
Tracking::Track()└─> NeedNewKeyFrame()└─> CreateNewKeyFrame()└─> LocalMapping::InsertKeyFrame(pKF)LocalMapping::Run()└─> CheckNewKeyFrames()└─> ProcessNewKeyFrame()└─> MapPointCulling()└─> CreateNewMapPoints()└─> OptimizeLocalMap()└─> MapPointCulling()
LocalMapping 是如何“被唤醒”的?(非常重要)
不是用条件变量,而是:
✔ Tracking 写队列
✔ LocalMapping 读队列
✔ LocalMapping 每 3ms 唤醒检查一次
这是个典型的 producer-consumer 模式,但使用了忙等+sleep,而不是 wait/notify。具体伪代码如下
Tracking thread:InsertKeyFrame => push 到队列LocalMapping thread:while(true):if (queue 非空):处理 KeyFramesleep(3ms)
具体的实现如下:
Tracking.cc└─> mpLocalMapper->InsertKeyFrame(pKF)LocalMapping.cc├─> InsertKeyFrame() ← producer: push into mvpNewKeyFrames├─> CheckNewKeyFrames() ← consumer: queue non-empty?└─> Run() ← consumer thread loop (busy wait)while(1) {if(CheckNewKeyFrames()) { ... }usleep(3000);}
