SLAM

第一讲:预备知识

Simultaneous Localization and Mapping(同时定位与地图构建) 解决: 定位和建图

常见的库: Eigen:线性代数,Opencv:视觉处理,PCL:点云处理,g2o:slam框架,Ceres:非线性关系求解

slam系统: 视觉里程计,后端优化,建图,回环检测

第二讲:初始SLAM

slam解决的问题

(早期的slam一种状态估计问题) – 空间状态不确定性的估计 本质: 对运动主体自身和周围环境空间不确定性的估计 定位: 我在什么地方? 建图: 周围环境是什么样?

常见传感器:激光传感器,相机,轮式编码器,惯性测量单元(IMU)等

照片的本质是拍摄某个场景在相机的成像平面上留下的一个投影:它以二维的形式记录 三维的世界.(丢失深度(距离)) -> 可能是很近很小,也可能是很远很大

相机:

分为双目相机和深度相机

双目相机: 1.双目相机由两个单目相机组成,但这两个相机之间的距离(基线)是已知的,我们通过这个极限来估计每个像素的空间位置—这和人眼很相似 2.双目相机测量到的深度范围与基线相关.极限距离越大,能够测量到的物体越远,双目相机的距离是比较左右眼的图像获得的,并不依赖其他传感器设备.

3.视差的计算非常消耗计算资源,需要GPU和FPGA设备加速

深度相机:(RGB-D相机): 通过红外结构光或Time-of-Fliagh原理,通过主动向物体发射光接收返回的光测出物体与相机之间的距离

视觉slam的目标:是通过这样的一些图像,进行定位和地图构建

视觉slam框架

image.png

1.传感器信息读取:主要为相机图像信息的读取和预处理,码盘,惯性传感器等信息的读取和同步

2.前端视觉里程计:视觉里程计的任务是估算相邻图像间相机的运动,以及局部地图的样子.VO又称为前端(Font End)

3.后端(非线性)优化:后端接受不停时刻视觉里程计测量的相机位姿,以及回环检测的信息,对它们进行优化,得到全局一致的轨迹和地图,由于接在VO之后,又称为后端(Back End)

4.回环检测:回环检测判断机器人是否到达过先前的位置.如果检测到回环,它会把信息提供给后端进行处理

5.建图:它更具估计的轨迹,建立与任务要求对应的地图

视觉里程计: — 前端

视觉里程计: 视觉里程计能够通过相邻帧间的图像估计相机运动,并恢复尝尽的空间结构.称它为里程计就像一种只有短时记忆的物种

(图像地特征提取与匹配)

图像在计算机里知识一个数值矩阵

一方面:只要把相邻时刻的运动串起来,就构成了机器人的运动轨迹 另一方面:我们根据每个时刻的相机位置,计算出各像素对应的空间点位置,就得到了地图

仅通过视觉里程计来估计轨迹,将不可避免地出现累积漂移

累积漂移:

每次估计都带有一定地误差,而由于里程计地工作方式,先前时刻地误差将会传递到下一时刻,导致经过一段时间之后,估计地轨迹将不再准确 -> 导致我i们无法建立一致地地图

后端优化:

主要处理SLAM过程中地噪声问题 — 如何让从这些带有噪声地数据中估计整个系统地状态,以及这个状态估计地不确定有多大 —- 最大后验概率估计

(滤波与非线性优化算法)

回环检测

又称闭环检测,主要解决位置估计随时间漂移的问题

解决方法: 使用某种手段m让机器人知道回到了原点这件事,或者把原点识别出来,我们再把位置估计值拉过去,就可以消除漂移了,这就是所谓的回环检测

(可以通过判断图像间的相似性来完成回环检测) — 回环检测成功,则可以显著地减小累积误差

建图:

构建地图的过程
地图: 是对环境的描述,但这个描述并不是固定的,需要视SLAM的应用而定

(相机有6个自由度) -> XYZ轴平移,绕XYZ轴旋转

度量地图:

拓扑地图:

调试:

单步跳过: 执行当前行代码.如果该行包含函数调用,不进入函数内部,直接得到结果并跳到下一行 F10 单步进入: 执行当前行代码,如果该行包含函数调用,会进入该函数内部,并暂停在函数的第一行 F11 单步跳出: 立即执行完当前函数体内剩余的所有代码,并跳出到该函数的下一行语句暂停处 Shift + F11

1.配置编译任务 按ctrl+shift+p,输入"Tasks: Configure Task" , 选择"Create tasks.json file from templates",选择"Others"或"C/C++ g++ buikd active file" ,这回生成一个tasks.json,然后问ai生成一个调试文件

2.配置调试设置(launch.json) 按F5,选择(GDB/LDB),然后选择"g++ build and debug activate file"

3.开始断点调试 1).设置断点: 在代码行号左侧单击,出现红点即为断点 2).启动调试: 按F5 3).调试操作 4).查看状态

4.高级调试技巧 条件断点 日志断点 函数断点

第三讲 三维空间刚体运动

主要目标: 1.理解三维空间的刚体运动描述方式: 旋转矩阵,变换矩阵,四元数和欧拉角 2.掌握Eigen库的矩阵,集合模块的使用方法

如何描述刚体在三维空间中的运动 -> 由一次旋转加一次平移组成

旋转矩阵

点,向量和坐标系

点: 空间中的基本元素,没有长度和体积,用于表示位置 向量: 连接两个点的有向线段,表示为箭头,具有方向和大小(模长).向量本身是空间中的实体,独立于坐标表示 坐标系: 为描述点和向量的位置而定义的框架,由一组基向量(e1,e2,e3)构成.向量在坐标系下的坐标表示为线性组合系数

右手系​:常见于 OpenGL、3D Max 等库。坐标轴满足右手法则(x×y=z) 左手系​:常见于 Unity、Direct3D 等库。坐标轴满足左手法则(x×y=−z)

向量的运算: 基本运算: 数乘,加法,减法,内积(描述投影关系,结果与坐标系无关),外积(结果向量垂直于原向量构成的平面,模长等于两向量张成的平行四边形面积)

坐标系间的欧式变换

例子: 惯性坐标系(世界坐标系) -> 可以认为它是固定不动的 相机或机器人是一个移动坐标系

刚体运动: 两个坐标系之间的运动由一个旋转加上一个平移组成,这种运动称为刚体运动 ,同一个向量在各个坐标系下的长度和夹角都不会发生变化

欧式变换: (刚体变换) -> 描述三维空间中刚体运动的一种数学工具.他能保持物体内部任意两点间的距离和角度不变,只改变物体的位置和姿态想象一下你拿起手机移动或旋转:手机本身的形状、大小、各个面的夹角都没变,只是它在空间中的“位置”和“朝向”变了。 我们说手机坐标系到世界坐标之间,相差了一个欧式变换(Euclidean Transform)

欧式变换由旋转和平移组成

齐次坐标: 我们在一个三维向量的末尾添加1,将其变成了四维向量,称为齐次坐标,对于这个四维向量,我们可以把旋转和平移写在一个矩阵里,使得整个关系变成线性关系 -> 该矩阵T(Transform Matrix)称为变换矩阵 -> 数学技巧(统一的线性方式来处理旋转和平移) :

Eigen库

简介: 是一个C++开源线性代数库.它提供了快速的有关矩阵的线性代数运算,还包括解方程等功能.许多上层的软件库也使用Eigen进行矩阵运算,包括g20,Sophus等

安装:

sudo apt-get install libeigen3-dev 查找头文件安装位置: 默认位置: /usr/include/eigen3/

终端输入:

sudo updatedb locate eigen3

Eigen库是一个纯头文件库,这意味它的全部实现都包含在头文件中,而不是预先编译好的二进制文件(如Windows下的.lib,.dll或Linux下的.a,.so) 好处: 1.不需要担心操作系统或编译器的差异 2.更佳的优化潜力 3.避免API问题: 传统库升级时,如果二进制接口(API)发生变化,可能需要编译整个项目, 而Eigen作为头文件库,不存在这个问题

为了达到更高的效率,在Eigen中需要指定矩阵的大小和类型 -> 完全可以在编译时确定它们的大小和数据类型 Eigen矩阵不支持自动类型提升 -> 在C++程序中,我们可以把一个float数据和double数据相加,相乘,编译器会自动把数据类型转换为最合适的那种,而在Eigen中,出于性能的考虑,必须显式地对矩阵类型进行转换否则 -> YOU MIXED DIFFERENT NUMERIC TYPES(混合了不同地数值类型)

同理,在计算过程中也需要保证矩阵位数的正确性,否则 -> YOU MIXED MATRICES OF DIFFERENT SIZES(混合了不同尺寸的矩阵)

6自由度的三维刚体运动

描述一个物体在三维空间中完整运动能力的基石 物体可以进行3个方向的平移 x,y,z 和3个方向的旋转 roll,pitch,yaw

旋转向量

第四讲: 李群与李代数

第五讲: 相机与图像

第六讲 非线性优化

使用ceres进行曲线拟合

图片 1