0%

SLAM导航实战(一):编程基础

前言

本系列主要基于《机器人SLAM导航——核心技术与实战》一书进行学习总结,根据作者对本书的章节规划,预计共分为四个部分:

  1. 编程基础篇
  2. 硬件基础篇
  3. SLAM篇
  4. 自主导航篇

本系列笔记也将基于上述四个部分进行归纳总结

简介

当前SLAM系统主要是在Linux系统进行开发的,其中应用最广的当属Ubuntu,掌握Linux系统的基本操作是进行SLAM开发的前提条件。除了操作系统外,进行SLAM学习还需要掌握一些其他的必要的基础技能,也是本章的主要内容——ROS操作系统、C++编程基础、OpenCV基础。本章将依次对其内容进行简要的总结梳理(主要是采集里面对于自己有用的知识点)。

(注:笔者本人粗略查看了书籍第一部分内容,认为对无基础小白并不友好,需要有一定基础才能更好地学习此书,为此每个部分笔者也简单梳理自己的学习资料)

ROS操作系统

相关学习资料

详细清晰,对小白友好:中科院ROS操作系统学习教程

版本较新,含实战内容:Autolabor Ros教程

经典教程(个人入门教程,但没太学明白)古月居ROS 21讲

ROS简介

ROS是分布式的通信框架,帮助各个进程之间更方便地进行通信,其开发初衷就是避免重复造轮子

常用官方学习网站:

  • 官网:www.ros.org
  • Wiki:www.wiki.ros.org
  • 问答:www.answers.ros.org

ROS开发环境

文件组织方式:系统空间(/opt/ros)、工作空间

网络通信配置:分布式开发过程中需要配置MASTER、HOST(实战部分再做解释)

ROS框架

计算图角度:节点、话题、服务、动作等

文件系统角度:源文件空间、编译空间、开发空间

消息机制:话题、服务、动作

个人理解:系统各个工作单元在ROS框架下为节点,他们通过各种消息机制获取、发送各类数据、信息,从而使各个部分正常工作形成完整的系统。

ROS节点通信

话题:单向异步

服务:双向同步

动作:双向异步

服务、动作均不用构建节点之间的连接。

话题通信

发布者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "ros/ros.h" 
#include "std_msgs/String.h"

#include <sstream>

int main(int argc, char **argv)
{
ros::init(argc, argv, "publish_node");
ros::NodeHandle nh;

ros::Publisher chatter_pub = nh.advertise<std_msgs::String>("chatter", 1000);
ros::Rate loop_rate(10);//自循环的频率需要配合27行的sleep()方法使用
int count = 0;

while (ros::ok())
{
std_msgs::String msg;

std::stringstream ss;
ss << "hello " << count;
msg.data = ss.str();
ROS_INFO("%s", msg.data.c_str());

chatter_pub.publish(msg);

ros::spinOnce();//让回调函数有机会被执行的声明
loop_rate.sleep();
++count;
}

return 0;
}

订阅者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "ros/ros.h" 
#include "std_msgs/String.h"

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]",msg->data.c_str());
}

int main(int argc, char **argv)
{
ros::init(argc, argv, "subscribe_node");
ros::NodeHandle nh;

ros::Subscriber chatter_sub = nh.subscribe("chatter", 1000,chatterCallback);

ros::spin();//让程序进入自循环的挂起状态

return 0;
}

服务通信

自定义服务基本步骤:

  1. 创建srv文件夹,创建 .srv 格式文件,编写消息类型
  2. 功能包CMakeLists.txt文件中find_package中添加std_msgs、message_generation依赖项
  3. 解注释add_service_files 添加第一步编写的srv文件
  4. 解注释generate_messages 添加std_msgs,其作用是自动创建消息类型的.h头文件
  5. package.xml中添加message_generation、message_runtime依赖

编译运行注意:由于自定义了服务消息类型,需在add_dependencies中配置自定义功能包命_gencpp,若为python则_genpy

动作通信

基本步骤: find_package中需添加Boost库,其余参照服务通信配置方法

ROS其他重要概念

parameter: getParam()、setParam()

tf: 右手坐标系;由广播tf变换和监听tf变换组成节点

nodelet:该节点可以在单个进程下以多个线程形式运行


C++编程规范

相关学习资料

书籍:CMake Practice

编译方式及规范

编译方式:

  1. g++
  2. Make
  3. CMake

编程规范:

谷歌C++编程风格指南


OpenCV图像处理

相关学习资料

入门书籍:OpenCV3编程入门

经典书籍(中文翻译版也可以):Learning Opencv: Computer Vision with the Opencv Library

图像数据

Mat类组成:矩阵头——存放矩阵尺寸、存储方式、存储地址等信息;矩阵指针——指向内存区域

默认图片存储顺序:BGR

图像滤波

线性滤波

  • 均值滤波(blur)
  • 高斯滤波(GaussianBlur)

非线性滤波

  • 中值滤波(medianBlur)
  • 双边滤波(bilateralFilter):与空间位置、像素值相似度有关,能保留细节信息

形态学滤波

  • 膨胀(dilate)
  • 腐蚀(erode)

不同组合形成新的滤波算法

  • 开运算(open)
  • 闭运算(close)
  • 形态学梯度(morphgrad)
  • 顶帽运算(tophat)
  • 黑帽运算(blackhat)

图像变换

射影变换

  • 欧氏变换
  • 相似变换
  • 仿射变换
  • 射影变换(上述三种变换均为射影变换的特例)

霍夫变换

检测直线的一种常用方法

基本原理:过某一点存在直线簇,其对应参数$r、\theta$ 可以绘制一条正弦曲线,若多个点绘制的正弦曲线为同一条曲线,则三点位于同一条直线上

封装函数:HoughLines、HoughLinesP(累计概率霍夫变换,具有更高的执行效率)

边缘检测

sobel算法: x、y方向的卷积核对图像卷积,得到两个方向的梯度后合成为某点的近似梯度

canny算法: 在sobel基础上先用高斯滤波去除噪声,然后sobel算法,最后采用滞后阈值讲边缘提取出来

直方图均衡

图像直方图:横坐标为亮度值,纵坐标为每个亮度值对应的像素总数量

图像特征点提取

SIFT特征点

尺度空间:模拟人眼远近观察的成像特点,可图区图像中尺度不变性的特征

  • 图像金字塔
  • 高斯金字塔
  • 高斯差分金字塔(由于尺度归一化高斯拉普拉斯函数高斯差分函数非常近似,且差分计算量少)

特征点定位:高斯差分金字塔中完成,DoG空间进行

  • 极值点检测
  • 特征点定位
  • 特征点筛选

特征点方向提取:高斯金字塔中完成

  • 特征点主方向
  • 特征点邻域方向
  • 特征点描述子(4 x 4 x 8 = 128维向量描述)

SURF特征点

尺度空间:在SIFT基础上讲高斯滤波用Hessian矩阵的盒式滤波代替,大幅降低运算耗时;尺度不同问题由盒式滤波窗口尺寸解决

特征点定位: Hessian矩阵的决定值中进行

特征点方向提取: Haar小波特征得到,最终(4 x 4 x 4 = 64维向量描述)

ORB特征点

尺度空间:直接图像金字塔拼接成大图

特征点提取: FAST特征提取,结合灰度质心得到特征点方向的oFAST特征

特征点描述: 先对图像进行高斯滤波后,采用BRIEF描述计算,最后将BRIEF中按照高斯分布对特征点方向进行旋转,得到rBRIEF