一、ROS简介与环境搭建
1.1 准备工作
1.1.1 ROS安装
ubuntu安装常用方式有两种:
-
实体机安装 ubuntu (较为常用的是使用双系统,windows 与 ubuntu 并存);
-
虚拟机安装 ubuntu。
两种方式比较,各有优缺点:
- 方案1可以保证性能,且不需要考虑硬件兼容性问题,但是和windows系统交互不便;
- 方案2可以方便的实现 windows 与 ubuntu 交互,不过性能稍差,且与硬件交互不便。
我选择方案2 虚拟机安装 ubuntu.
采用虚拟机安装 ubuntu,再安装 ROS 的话,大致流程如下:
- 安装虚拟机软件(比如:virtualbox 或 VMware);
- 使用虚拟机软件虚拟一台主机;
- 在虚拟主机上安装 ubuntu 20.04;
- 在 ubuntu 上安装 ROS;
- 测试 ROS 环境是否可以正常运行。
1.1.2 ROS集成开发环境搭建
- 安装终端Terminator;
- 安装VScode及vscode集成ROS插件。
1.2 vscode使用基本流程
1.创建ROS工作空间
mkdir -p xxx_ws/src
cd xxx_ws
catkin_make
2.启动vscode
cd xxx_ws
code .
3.vscode中编译ROS
“ctrl+shift+B”调用编译
选择 catkin_make :build 小齿轮配置一下
修改 .vscode/tasks.json 文件
实现按“ctrl+shift+B"自动编译
4.创建ROS功能包
选定src右击 create catkin package
设置包名-----xxxxxx
添加依赖----- roscpp rospy std_msgs
5.c++实现
在下一级src创建新建文件 xxxx.cpp
Notes:
1.写代码不能自动补齐的话到.vscode/c.cpp_propeties.json里修改成”c++17";
2.常用快捷键
"ctrl+~ "在vscode中打开命令行 "ctrl+alt+t" 启动命令行
"ctrl+/" 加注释“// ” "ctrl+shift+a" 加注释“/* */"
“ctrl+s" 保存 “alt+↑/↓” 这一行代码向上或向下移动
“ctrl+c/v"复制 粘贴
“ctrl+c" 终止命令 “↑/↓”翻找之前的命令 “clear"清空终端页面
简单helloworld程序实现:
6.修改配置文件
下一级里的src的cmakelists.txt
7.运行
使用vscode内置终端/ctrl+shift+t调用终端都可
新建一个终端 roscore
再新建一个终端 ---刷新环境变量 source ./devel/setup.bash
---运行 rosrun 包名 映射的名 (eg:haha,通常和.cpp文件名保持一致)
补充:
※ 解决中文乱码问题
setlocale(LC_ALL,"");
1.3 launch文件演示
功能:使用launch文件,可以一次性启动多个ROS节点。
实现:
- 选定功能包右击 添加launch文件夹;
- 选定launch文件夹右击,添加launch文件;
- 编辑launch文件内容;
- 运行launch文件 命令格式:roslaunch 包名 launch文件名
Note: 节点中有日志输出的话,想要显示在控制台,需要再设置一个属性output,代表将输出显示在屏幕上
二、ROS通信机制
2.1 话题通信
概念: 以发布订阅的方式实现不同节点之间数据交互的通信模式。
作用:适用于不断更新的、少逻辑处理的数据传输场景。
话题通信应用时的关注点:
- 话题设置;
- 关注发布者实现;
- 关注订阅者实现;
- 关注消息载体(二者通信时使用的数据)
2.1.1 话题通信基本操作
案例:编写发布订阅实现 要求发布方以10Hz的频率发布文本消息,订阅方订阅消息并将消息内容打印输出。
分析:需要关注的关键点有三个:
1.发布方 2.接收方 3.数据(此处为普通文本)
流程:
- 编写发布方实现;
- 编写订阅方实现;
- 编辑配置文件;
- 编译并执行。
发布方实现:
订阅方实现:
编辑配置文件
编译并执行
补充:
问题:订阅时第一条或前几条数据丢失 或者先启动订阅方再启动发布方
解决:加入休眠 ros::Duration(3.0).sleep();
可以使用rqt_graph查看节点间的关系
2.1.3 话题通信自定义msg
需求:创建自定义消息,该消息包含人的信息:姓名、身高、年龄
流程:
1.按照固定格式创建msg文件
功能包下创建msg文件夹,添加文件Person.msg
2.编辑配置文件
package.xml 中添加编译依赖与执行依赖
※ CMakeLists.txt 中编辑 msg 相关配置
3.编译后生成中间文件
2.1.4 话题通信自定义msg调用
流程:
0. vscode配置
为了方便代码提示以及避免误抛异常,需要先配置 vscode,将前面生成的 head 文件路径配置进 c_cpp_properties.json 的 includepath属性
方法:选定中间文件右击在集成终端中打开,然后输入命令 pwd 打印路径 复制粘贴到 includepath 属性中,按照格式将include/后面也改成“**”。
1.编写发布方实现
编写配置文件
特别注意:自定义msg需比之前多修改一条
将150行代码释放,目的是为了先编译msg,再编译.cpp源文件
2.编写订阅方实现
编写配置文件
还是注意多添加的那条 add_dependencies----------
3.编译并执行
2.2 服务通信
概念:以请求响应的方式实现不同节点之间数据交互的通信模式。
作用:用于偶然的、对实时性有要求、有一定逻辑处理需求的数据传输场景。
Note: 也是Master匹配相同的话题的Server和Client,但是这两者有先后顺序问题,必须先启动服务端,再启动客户端;如果多个进程可能启动节点时在启动顺序问题上出现问题,后面在优化中有解决办法。
2.2.1 服务通信自定义srv
案例:实现两个数字的求和,客户端节点运行时会向服务器发送两个数字,服务端节点接受两个数字求和并将结果响应回客户端。
流程:
srv 文件内的可用数据类型与 msg 文件一致,且定义 srv 实现流程与自定义 msg 实现流程类似:
-
按照固定格式创建srv文件
-
编辑配置文件
- 编译生成中间文件
1.定义srv文件
服务通信中,数据分成两部分,请求与响应,即:自定义srv= 请求部分+响应部分
具体实现如下:
功能包下新建 srv 目录,添加 xxx.srv 文件
在 srv 文件中请求和响应使用“---”
分割
2.编写配置文件
package.xml 中添加编译依赖与执行依赖
CMakeLists.txt 中编辑 srv 相关配置
3.编译生成中间文件
2.2.2 服务通信自定义srv调用
流程:
- 编写服务端实现;
- 编写客户端实现;
- 编辑配置文件;
- 编译并执行。
0. vscode配置
需要像之前自定义 msg 实现一样配置 c_cpp_properies.json 文件;
如果需要配置(在新的工作空间下),配置方式与之前相同;
如果以前已经配置且没有变更工作空间,可以忽略此步骤。
1. 服务端实现
※ 编写配置文件,和之前自定义msg一样,多释放一行代码,但是比之前对这行代码多改动一个地方_gencpp 保证srv文件和cpp源文件编译顺序
编译并执行 检验一下服务端代码有没有问题
2.客户端实现
编写配置文件
同服务端操作一样
编译并执行
优化处理:
1.实现参数的动态提交
上面参数是在客户端写死的,正常应该能在命令行中动态提交
eg: 命令行格式:rosrun xxxx xxxx 12 34
2.先启动客户端的问题
问题:先启动了客户端
解决:函数1 client.waitForExistence();
函数2 ros::service::waitForService("服务话题");
2.3 参数服务器
概念:以共享的方式实现不同节点之间的数据交互的通信模式。
作用: 存储一些多节点共享的数据,类似于全局变量。
在 C++ 中实现参数服务器数据的增删改查,可以通过两套 API 实现:
-
ros::NodeHandle
-
ros::param
2.3.1 参数服务器新增或修改参数
增:
改:
2.3.2 参数服务器获取参数
ros::NodeHandle--------------------------
1. param(键,默认值)
存在,返回对应结果;否则,返回默认值
eg: 键 存在的情况,返回对应值0.2
ros::param----------------------与NodeHandle 类似
eg: 键 不存在的情况(如:radius拼错),返回默认值0.5
2. getParam(键,存储结果的变量)
存在,返回 true,且将值赋值给参数2;
如果键不存在,那么返回值为 false,且不为参数2赋值。
3. getParamCached(键,存储结果的变量)---------提高变量获取效率
存在,返回 true,且将值赋值给参数2;
如果键不存在,那么返回值为 false,且不为参数2赋值。
4. getParamNames(std::vector<std::string>)
获取所有的键,并存储在参数 vector 中
5. hasParam(键)
是否包含某个键,存在返回 true,否则返回 false
6. searchParam(参数1,参数2)
搜索键,参数1是被搜索的键,参数2存储搜索结果的变量
2.3.3 参数服务器删除参数
参数服务器操作之删除_C++实现:
ros::NodeHandle----------------
1. deleteParam("键")
根据键删除参数,删除成功,返回 true,否则(参数不存在),返回 false
ros::param-----------------
1. del("键")
根据键删除参数,删除成功,返回 true,否则(参数不存在),返回 false