视觉SLAM的框架以及各个模块的作用
1.传感器信息读取 在视觉SLAM中主要为相机图像信息的读取和预处理。如果在机器人中,还可能有码盘,惯性传感器等信息的读取和同步。
2.视觉里程计 (visual odometry,VO) 视觉里程计的任务是估算相邻图像间相机运动,以及局部地图的样子。vo又称为前端。
3. 后端优化(optimization)。后端接受不同时刻视觉里程计测量的相机位姿,以及回环检测的信息,对他们进行优化,得到全局一致的轨迹和地图。由于在VO之后,又称为后端。
4. 回环检测(loop closing)。 回环检测判断机器人是否到达过去先前的位置,如果检测到回环,它会把信息提供给后端进行检测。
5. 建图(mapping)。它根据估计的轨迹,建立与任务要求对应的地图。
slam前端后端怎么连接在一起,数据流怎么传递的
前端实时的做帧间匹配,然后帧间匹配会得到一个位姿,这个位姿传给后端再做一次优化,后端优化过的位姿才是我们最后得到的位姿,然后用最后这个比较准确的位姿把点云投影到地图上。这个就是我们最后形成的点云地图。数据流通过ROS通信机制进行传输,前端publish里程计,后端subscriber。
当前帧和局部地图的数据关联是如何做的?
仅使用帧与帧之间运动估计运动,一般精度还不够。一般会维护局部地图来提高跟踪精度和鲁棒性。为了权衡精度和实时性,为了保证实时性,只能使用当前帧跟踪一部分帧,一般使用固定滑动窗口或ORB-SLAM2中使用的共视帧窗口,它们与当前帧共视点相对其他帧多很多。前端主要用于跟踪(得到当前帧位姿),据此选择关键帧交给后端,后端再进行三角化新的路标点、删错冗余和错误的路标点和帧、优化各帧位姿和路标点位姿(一般在世界坐标系表示)。
SLAM的回环检测方法
激光: Scan Context
首先使用Scan Context进行回环帧检测,确定历史帧中的回环帧后,将回环帧与当前点云帧进行点云配准,获取回环精确位姿。也就是说回环检测的本质是利用当前点云和历史点云做相似度检测,如果历史中有对应的点云相似度较高,我们就把这个历史帧确定为回环帧,用当前点云和历史帧去做配准得到精确位姿;由于累计误差的存在,激光里程计连续下来求得本时刻与那个历史时刻的位姿存在一定的偏差,而回环检测没有累计误差;因此构建了一条G2O的回环边。
传统的领域距离搜索+ICP匹配
基于scan context系列的粗匹配+ICP精准匹配的回环检测
基于scan context的回环检测
视觉的话,回环检测目前多采用词袋模型(Bag-of-Word)
重载、隐藏、重写(覆盖)三者的区别?
重载的参数不同,函数体不同(同一个类中,同一作用域);
隐藏的参数可以不同,函数体不同;
重写或者覆盖仅仅函数体不同(花括号内)不同的范围(分别位于派生类与基类)。
智能指针
虚函数与纯虚函数
能用纯虚函数的类声明对象么
KD树工作原理:
Kd-Tree是从BST(Binary search tree)发展而来,是一种高维索引树形数据结构,常用于大规模高维数据密集的查找比对的使用场景中,主要是最近邻查找(Nearest Neighbor)以及近似最近邻查找(Approximate Nearest Neighbor)
原文链接:https://blog.csdn.net/u012423865/article/details/77488920
map与unordered_map
多线程
public static native void sleep(long millis) throws InterruptedException
线程休眠会交出CPU(变回阻塞状态),让CPU去执行其他的任务,睡眠结束后返回就绪状态。但是有一点要非常注意,sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象。休眠时间使用毫秒作为单位。
注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。
join()方法
等待该线程终止。意思就是如果在主线程中调用该方法时就会让主线程休眠,让调用该方法的线程run方法先执行完毕之后在开始执行主线程。
join()方法只是对Object提供的wait()做的的一层包装而已。
join()方法变回阻塞状态,结束后返回就绪状态,会释放锁
多线程中有三种方式可以停止线程。
设置标记位,可以是线程正常退出。
使用stop方法强制使线程退出,但是该方法不太安全所以已经被废弃了。
使用Thread类中的一个interrupt() 可以中断线程。
对于优先级设置的内容可以通过Thread类的几个常量来决定
高优先级:public final static int MAX_PRIORITY = 10;
中等优先级:public final static int NORM_PRIORITY = 5;
低优先级:public final static int MIN_PRIORITY = 1;
主方法只是一个中等优先级,为5
线程间的同步与互斥:
举例:假如程序中有一个静态变量,static int a;线程1负责往里写入数据,线程2需要读取其中的数据,那么线程2在读数据之前必须是线程1写入了数据,如果不是,那么线程2必须停下来等待线程1的操作结束。这就是线程之间在某些地方上的合作关系,协同工作嘛!
举例:还是假如程序中有一个静态变量,static int b;线程1想要往里写入数据,线程2也想要往里写入数据,那么此时静态变量b就是一个临界资源(互斥资源),即一次只能被一个线程访问。想一想,如果线程1和线程2同时往b中写入数据,那怎么能行,计算机是不允许的!所以,要么是线程1占用b,此时线程2要等待;要么是线程2占用b,此时线程1等待。这就是所谓的线程间的互斥,这里可以通过加锁的方式来实现。
join()和detach()
thread first(GetSumT,largeArrays.begin(),largeArrays.begin()+20000000,std::ref(result1));
first.join();
原文链接:https://blog.csdn.net/lizun7852/article/details/88753218
简单工厂模式
//简单工厂模式
#include
using namespace std;
//产品的基类
class Product{
public:
//基类中的纯虚函数
virtual int operation(int a, int b) = 0;
};
//产品的子类Add
class Product_Add : public Product{
public:
int operation(int a, int b){
return a + b;
}
};
//产品的子类Mul
class Product_Mul : public Product{
public:
int operation(int a, int b){
return a * b;
}
};
//工厂
class Factory{
public:
Product* Create(int i){
switch (i){
case 1:
return new Product_Add;
break;
case 2:
return new Product_Mul;
break;
default:
break;
}
}
};
int main()
{
Factory *factory = new Factory();
int add_result = factory->Create(1)->operation(1, 2);
int mul_result = factory->Create(2)->operation(1, 2);
cout <<"op_add:" <<add_result << endl;
cout <<"op_multiply:" << mul_result << endl;
getchar();
return 0;
}
一些好的博客:
视觉SLAM的前段后端最详细的梳理(硕士入门知识框架更新)
C++笔记——多线程编程(1)
SLAM从0到1——13.SLAM中的多线程编程(2)
一些面试问题
视觉SLAM总结——视觉SLAM面试题汇总