AutoLabor-ROS-Python 学习记录

AutoLabor-ROS-Python 学习记录
Penry引言
该文档主要基于赵虚左老师的课程【Autolabor初级教程】ROS机器人入门
,撰写一些 ROS Python 相关的重要知识点或者配置内容。
- 课程视频链接:【Autolabor初级教程】ROS机器人入门
- 课程电子书:ROS机器人入门课程《ROS理论与实践》零基础教程
- ROS noetic 配置文档:ROS配置
第一章 ROS 概述与环境搭建
ROS 文件系统架构:
1 | WorkSpace --- 自定义的工作空间 |
1.0 ROS 演示
ROS 内置了一些小程序,可以通过运行这些小程序以检测 ROS 环境是否可以正常运行
- 首先启动三个命令行(ctrl + alt + T)
- 命令行1键入:
roscore
- 命令行2键入:
rosrun turtlesim turtlesim_node
(此时会弹出图形化界面) - 命令行3键入:
rosrun turtlesim turtle_teleop_key
(在3中可以通过上下左右控制2中乌龟的运动)
- 命令行1键入:
最终结果如下所示:
注意:光标必须聚焦在键盘控制窗口,否则无法控制乌龟运动。
1.1 集成开发环境_VsCode基本配置
1.1.1 settings.json
为了方便代码提示以及误抛异常,需要先配置 VsCode,将前面生成的 python 文件路径配置进 settings.json
:
1 | { |
我的填写示例:
1 | { |
1.1.2 tasks.json
1 | { |
1.2 集成开发环境_VsCode基本实现流程(为Python)
Python 文件:
1 | #! /usr/bin/env python |
由于一种编写 ROS-Python 习惯的沿袭,某些开源项目编写的 .py
文件没有经过 CMakeLists.txt
配置,导致编译时候出现如下报错:
1 | "python": 没有那个文件或目录 |
原因: 当前 noetic 版本中,python3 为默认 python 版本,而 python3 与 python2 不兼容
有三种解决方案:
- 直接声明解释器为 python3 (不建议)
/usr/bin/env python3
- 通过软连接将 python 连接到 python3 (建议)
- 备份现有链接:
sudo mv /usr/bin/python /usr/bin/python.bak
- 创建新链接:
sudo ln -s /usr/bin/python3 /usr/bin/python
- 验证链接:
ls -l /usr/bin/python
- 备份现有链接:
- 配置 CMakeLists.txt (推荐)
配置好软连接之后,即使不配置 CMakeLists.txt
,也可以按照以下步骤成功运行 .py
文件:
Ctrl+Shift+B
编译- 将
功能包/scripts
在终端打开 - 终端输入
chmod +x *.py
赋予所有.py
文件执行权限 - 终端输入
ll
查看可执行文件 - 新建两个终端:
- 第一个终端输入
roscore
启动 ROS 主进程 - 第二个终端输入先输入
source ./devel/setup.bash
配置 ROS 环境,再输入rosrun 包名 可执行文件名
运行节点.
- 第一个终端输入
第二章 ROS 通信机制
机器人是一种高度复杂的系统性实现,在机器人上可能集成各种传感器(雷达、摄像头、GPS…)以及运动控制实现,为了解耦合,在ROS中每一个功能点都是一个单独的进程,每一个进程都是独立运行的。更确切的讲,ROS是进程(也称为Nodes)的分布式框架。 因为这些进程甚至还可分布于不同主机,不同主机协同工作,从而分散计算压力。不过随之也有一个问题: 不同的进程是如何通信的?也即不同进程间如何实现数据交换的?在此我们就需要介绍一下ROS中的通信机制了。
ROS 中的基本通信机制主要有如下三种实现策略:
- 话题通信(发布订阅模式)
- 服务通信(请求响应模式)
- 参数服务器(参数共享模式)
本章的主要内容就是是介绍各个通信机制的应用场景、理论模型、代码实现以及相关操作命令。本章预期达成学习目标如下:
- 能够熟练介绍ROS中常用的通信机制
- 能够理解ROS中每种通信机制的理论模型
- 能够以代码的方式实现各种通信机制对应的案例
- 能够熟练使用ROS中的一些操作命令
- 能够独立完成相关实操案例
案例演示
- 话题通信演示:
控制小乌龟做圆周运动
获取乌龟位姿
- 服务通信演示:
在指定位置生成乌龟
- 参数服务器演示:
改变乌龟窗口的背景颜色
2.1 话题通信
话题通信基于发布/订阅模型,是一种异步通信模式。一个节点发布消息,另一个节点订阅该消息。这种方式将信息的产生和使用双方解耦,常用于不断更新的、含有较少逻辑处理的数据通信。例如,雷达数据、里程计数据等。
话题通信是ROS中使用频率最高的一种通信模式,话题通信是基于发布/订阅模式的,也即:一个节点发布消息,另一个节点订阅该消息。话题通信的应用场景也极其广泛,比如下面一个常见场景:
机器人在执行导航功能,使用的传感器是激光雷达,机器人会采集激光雷达感知到的信息并计算,然后生成运动控制信息驱动机器人底盘运动。
在上述场景中,就不止一次使用到了话题通信。
- 以激光雷达信息的采集处理为例,在 ROS 中有一个节点需要时时的发布当前雷达采集到的数据,导航模块中也有节点会订阅并解析雷达数据。
- 再以运动消息的发布为例,导航模块会根据传感器采集的数据时时的计算出运动控制信息并发布给底盘,底盘也可以有一个节点订阅运动信息并最终转换成控制电机的脉冲信号。
以此类推,像雷达、摄像头、GPS… 等等一些传感器数据的采集,也都是使用了话题通信,换言之,话题通信适用于不断更新的数据传输相关的应用场景。
概念:以发布订阅的方式实现不同节点之间数据交互的通信模式。
作用:用于不断更新的、少逻辑处理的数据传输场景。
2.1.1 理论模型
话题通信实现模型是比较复杂的,该模型如下图所示,该模型中涉及到三个角色:
- ROS Master
- Talker
- Listener
ROS Master 负责保管 Talker 和 Listener 注册的信息,并匹配话题相同的 Talker 与 Listener,帮助 Talker 与 Listener 建立连接,连接建立后,Talker 可以发布消息,且发布的消息会被 Listener 订阅。
- Talker 注册:
- Talker启动后,会通过RPC在 ROS Master 中注册自身信息,其中包含所发布消息的话题名称。ROS Master 会将节点的注册信息加入到注册表中。
- Listener 注册:
- Listener启动后,也会通过RPC在 ROS Master 中注册自身信息,包含需要订阅消息的话题名。ROS Master 会将节点的注册信息加入到注册表中。
- ROS Master 实现信息匹配:
- ROS Master 会根据注册表中的信息匹配Talker 和 Listener,并通过 RPC 向 Listener 发送 Talker 的 RPC 地址信息。
- Listener向Talker发送请求:
- Listener 根据接收到的 RPC 地址,通过 RPC 向 Talker 发送连接请求,传输订阅的话题名称、消息类型以及通信协议(TCP/UDP)。
- Talker确认请求:
- Talker 接收到 Listener 的请求后,也是通过 RPC 向 Listener 确认连接信息,并发送自身的 TCP 地址信息。
- Listener与Talker件里连接:
- Listener 根据步骤4 返回的消息使用 TCP 与 Talker 建立网络连接。
- Talker向Listener发送消息:
- 连接建立后,Talker 开始向 Listener 发布消息。
注意1: 上述实现流程中,前五步使用的 RPC协议,最后两步使用的是 TCP 协议
注意2: Talker 与 Listener 的启动无先后顺序要求
注意3: Talker 与 Listener 都可以有多个
注意4: Talker 与 Listener 连接建立后,不再需要 ROS Master。也即,即便关闭ROS Master,Talker 与 Listern 照常通信。
2.1.2 话题通信基本操作
需求:
编写发布订阅实现,要求发布方以10HZ(每秒10次)的频率发布文本消息,订阅方订阅消息并将消息内容打印输出。
分析:
在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:
- 发布方
- 订阅方
- 数据
流程:
- 编写发布方实现;
- 编写订阅方实现;
- Python 文件添加可执行权限;
- 编写配置文件;
- 编译并后自行。
2.1.2.1 发布方
1 | #! /usr/bin/env python |
验证:
2.1.2.2 订阅方
1 | #! /usr/bin/env python |
验证:
注意1:添加可执行权限,终端下进入 scripts 执行:
chmod +x *.py
;
注意2:配置CMakeLists.txt
文件
1 | catkin_install_python(PROGRAMS |
2.1.2.3 订阅费缺少消息的问题
如图所示,我将发布方发送频率设置为 ,明显发现接收方缺少了第一条消息:
原因解释:因为发布方首先要在 ROS Master 中注册,可能在注册过程中就已经发布了第一条消息,导致这个时候订阅方无法接收。
解决方案:确保发布方注册完毕后,再开始发送数据,在发布之前加一个休眠。
1 | #! /usr/bin/env python |
2.1.2.4 计算图查看Python发布订阅模型
Ctrl+Alt+T
快速创建四个终端:
- 第一个终端:
roscore
- 第二个终端:
rosrun 包名 demo01_sub.py
- 第三个终端:
rosrun 包名 demo01_pub.py
- 第四个终端:
rqt_graph
2.1.2.5 关键概念:解耦合
解耦是指系统中的组件或模块之间的依赖关系最小化,从而提高系统的灵活性、可维护性和可扩展性。在软件系统中,解耦通常通过引入中间件或消息队列等机制来实现。
解耦的实现方式:
- 发布/订阅模式:发布者将消息发布到主题(Topic),订阅者从主题订阅消息。发布者和订阅者之间没有直接依赖关系,它们通过消息队列进行通信。
- 服务/客户端模式:服务端提供服务,客户端请求服务。服务端和客户端之间也没有直接依赖关系,它们通过消息队列进行通信。
解耦合意味着即使我们的功能包中的两个源文件分别用 cpp
和 python
编写,也可以实现通信,这是因为它们通过消息队列进行解耦。
2.1.3 话题通信自定义msg
在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs
封装了一些原生的数据类型,比如:String
、Int32
、Int64
、Char
、Bool
、Empty
… 但是,这些数据一般只包含一个 data
字段,结构的单一意味着功能上的局限性,当传输一些复杂的数据,比如: 激光雷达的信息… std_msgs
由于描述性较差而显得力不从心,这种场景下可以使用自定义的消息类型。
msgs只是简单的文本文件,每行具有字段类型和字段名称,可以使用的字段类型有:
- int8, int16, int32, int64 (或者无符号类型: uint8, uint16, uint32, uint64)
- float32, float64
- string
- time
- duration
- other msg files
- variable-length array[] and fixed-length array[C]
ROS中还有一种特殊类型:Header
,标头包含时间戳和ROS中常用的坐标帧信息。会经常看到msg文件的第一行具有Header
标头。
需求:创建自定义消息,该消息包含人的信息:姓名、身高、年龄等。
流程:
- 按照固定格式创建 msg 文件
- 编辑配置文件
- 编译生成可以被 Python 调用的中间文件
2.1.3.1 定义 msg 文件
功能包下新建 msg
目录,添加文件 Person.msg
:
1 | string name |
2.1.3.2 编辑配置文件
- 在
package.xml
中添加编译依赖与执行依赖:
1 | <build_depend>message_generation</build_depend> |
- 在
CMakeLists.txt
编辑msg
相关配置:
1 | find_package(catkin REQUIRED COMPONENTS |
1 | ## 配置 msg 源文件 |
1 | # 生成消息时依赖于 std_msgs |
1 | #执行时依赖 |
2.1.3.3 编译并查看中间文件
Python 中间文件为:工作空间/devel/lib/python3/dist-packages/包名/msg/_Person.py
2.1.4 话题通信自定义msg调用
需求:
编写发布订阅实现,要求发布方以1HZ(每秒1次)的频率发布自定义消息,订阅方订阅自定义消息并将消息内容打印输出。
分析:
在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:
- 发布方
- 订阅方
- 自定义数据
流程:
- 编写发布方实现
- 编写订阅方实现
- 为 Python 文件赋予可执行权限
- 编辑配置文件
- 编译并执行
2.1.4.1 VsCode配置
为了方便代码提示以及误抛异常,需要先配置 VsCode,将前面生成的 python 文件路径配置进 settings.json
:
1 | { |
我的填写示例:
1 | { |
2.1.4.2 发布方
1 | #! /usr/bin/env python |
新建三个终端:
- 第一个终端:
roscore
- 第二个终端:
source ~/工作空间/devel/setup.bash
rosrun 包名 可执行文件
- 第三个终端:
source ~/工作空间/devel/setup.bash
rostopic echo 话题名
2.1.4.3 订阅方
1 | #! /usr/bin/env python |
新建四个终端:
- 第一个终端:
roscore
- 第二个终端发布方:
source ~/工作空间/devel/setup.bash
rosrun 包名 可执行文件
- 第三个终端订阅方:
source ~/工作空间/devel/setup.bash
rostopic echo 话题名
- 第四个终端:
rosnode list
计算图查看:rqt_graph
2.2 服务通信
服务通信基于请求/响应模型,是一种同步通信模式。一个节点A向另一个节点B发送请求,B接收处理请求并产生响应结果返回给A。这种方式常用于数据量较小但有强逻辑处理的数据交换,例如拍照、语音识别等,如以下场景:
机器人巡逻过程中,控制系统分析传感器数据发现可疑物体或人… 此时需要拍摄照片并留存。
在上述场景中,就使用到了服务通信:一个节点需要向相机节点发送拍照请求,相机节点处理请求,并返回处理结果。
与上述应用类似的,服务通信更适用于对时时性有要求、具有一定逻辑处理的应用场景。
概念:以请求响应的方式实现不同节点之间数据交互的通信模式。
作用:用于偶然的、对时时性有要求、有一定逻辑处理需求的数据传输场景。
案例:实现两个数字的求和,客户端节点,运行会向服务器发送两个数字,服务器端节点接收两个数字求和并将结果响应回客户端。
2.2.1 服务通信理论模型
服务通信较之于话题通信更简单些,理论模型如下图所示,该模型中涉及到三个角色:
- ROS master(管理者)
- Server(服务端)
- Client(客户端)
ROS Master 负责保管 Server 和 Client 注册的信息,并匹配话题相同的 Server 与 Client ,帮助 Server 与 Client 建立连接,连接建立后,Client 发送请求信息,Server 返回响应信息。
2.2.1.1 Server注册
Server 启动后,会通过RPC在 ROS Master 中注册自身信息,其中包含提供的服务的名称。ROS Master 会将节点的注册信息加入到注册表中。
2.2.1.2 Client注册
Client 启动后,也会通过RPC在 ROS Master 中注册自身信息,包含需要请求的服务的名称。ROS Master 会将节点的注册信息加入到注册表中。
2.2.1.3 ROS Master实现信息匹配
ROS Master 会根据注册表中的信息匹配Server和 Client,并通过 RPC 向 Client 发送 Server 的 TCP 地址信息。
2.2.1.4 Client发送请求
Client 根据步骤3 响应的信息,使用 TCP 与 Server 建立网络连接,并发送请求数据。
2.2.1.5 Server发送响应
Server 收到请求后,处理请求并将结果返回给 Client。
注意:
- 客户端请求被处理时,需要保证服务器已经启动,保证顺序;
- 服务端和客户端都可以存在多个。
2.2.2 服务通信自定义srv
需求:
服务通信中,客户端提交两个整数至服务端,服务端求和并响应结果到客户端,请创建服务器与客户端通信的数据载体。
流程:
srv 文件内的可用数据类型与 msg 文件一致,且定义 srv 实现流程与自定义 msg 实现流程类似:
- 按照固定格式创建 srv 文件
- 编辑配置文件
- 编译生成中间文件
2.2.2.1 定义 srv 文件
服务通信中,数据分成两部分,请求与响应,在 srv 文件中请求和响应使用---
分割,具体实现如下:
- 新建功能包:
atkin_create_pkg plumbing_server_client rospy roscpp std_msgs
- 在功能包下新建 srv 目录,添加
Addints.srv
文件,内容为:
1 | # 客户端请求时发送的两个数字 |
2.2.2.2 编辑配置文件
package.xml
中添加编译依赖于执行依赖:
1 | <build_depend>message_generation</build_depend> |
CMakeLists.txt
中编辑 srv 相关配置:
1 | find_package(catkin REQUIRED COMPONENTS |
1 | add_service_files( |
1 | generate_messages( |
1 | catkin_package( |
2.2.2.3 编译
- 使用快捷键
Ctrl+Alt+B
编译; - 在路径
/home/mpy/workspace_learn_ros/autolabor_python/devel/lib/python3/dist-packages/plumbing_server_client/srv/_Addints.py
下可以看到 Python 要调用的中间文件:
2.2.3 服务通信自定义 srv 调用
需求:
编写服务通信,客户端提交两个整数至服务端,服务端求和并响应结果到客户端。
分析:
在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:
- 服务端
- 客户端
- 数据
流程:
- 编写服务端实现;
- 编写客户端实现;
- 为 Python 文件添加可执行权限;
- 编辑配置文件;
- 编译并执行。
2.2.3.1 VsCode 配置
需要像之前自定义 msg 实现一样配置settings.json 文件,如果以前已经配置且没有变更工作空间,可以忽略,如果需要配置,配置方式与之前相同:
1 | { |
2.2.3.2 服务端实现
1 | #! usr/bin/env python |
注意给 Python 文件赋权限,以及在 CMakeLists.txt
中添加配置。
启动三个终端:
- 第一个终端:
roscore
- 第二个终端:
rosrun plumbing_server_client server.py
- 第三个终端:
rosservice call Addints "{num1: 10, num2: 20}"
2.2.3.3 客户端实现
1 | #! usr/bin/env python |
注意给 Python 文件赋权限,以及在 CMakeLists.txt
中添加配置。
2.2.3.4 客户端优化
1 | #! usr/bin/env python |
注意给 Python 文件赋权限,以及在 CMakeLists.txt
中添加配置。
2.2.3.5 设置权限
1 | chmod +x *.py |
2.2.3.5 要求先启动客户端再启动服务端
问题:客户端优先于服务端启动,会抛出异常;
需要:客户端优先于服务端启动,不要抛出异常,而是挂起,等待服务端启动后再发送请求。
实现:ROS 中内置了相关函数,这些函数可以判断相关服务器状态,如果服务没启动,就让客户端挂起。
函数:rospy.wait_for_service("服务名")
或client.wait_for_service()
,这里的client
是创建的客户端对象。
作用:等待服务启动,参数为服务名,返回值为 None。
1 | #! usr/bin/env python |
如下图,先启动客户端,发现客户端已经挂起,没有报错:
再启动服务端,发现成功实现通信:
2.3 参数通信
参数服务器在 ROS 中主要用于实现不同节点之间的数据共享。参数服务器相当于是独立于所有节点的一个公共容器,可以将数据存储在该容器中,被不同的节点调用,当然不同的节点也可以往其中存储数据,关于参数服务器的典型应用场景如下:
导航实现时,会进行路径规划,比如: 全局路径规划,设计一个从出发点到目标点的大致路径。本地路径规划,会根据当前路况生成时时的行进路径。
上述场景中,全局路径规划和本地路径规划时,就会使用到参数服务器:
- 路径规划时,需要参考小车的尺寸,我们可以将这些尺寸信息存储到参数服务器,全局路径规划节点与本地路径规划节点都可以从参数服务器中调用这些参数。
参数服务器,一般适用于存在数据共享的一些应用场景。
概念:以共享的方式实现不同节点之间数据交互的通信模式。
作用:存储一些多节点共享的数据,类似于全局变量。
案例:实现参数增删改查操作。
2.3.1 参数服务器理论模型
参数服务器实现是最为简单的,该模型如下图所示,该模型中涉及到三个角色:
- ROS Master(管理者)
- Talker(参数设置者)
- Listener(参数调用者)
ROS Master 作为一个公共容器保存参数,Talker 可以向容器中设置参数,Listener 可以获取参数。
2.3.1.1 Talker 设置参数
Talker 通过 RPC 向参数服务器发送参数(包括参数名与参数值),ROS Master 将参数保存到参数列表中。
2.3.1.2 Listener 获取参数
Listener 通过 RPC 向参数服务器发送参数查找请求,请求中包含要查找的参数名。
2.3.1.3 ROS Master 向 Listener 发送参数值
ROS Master 根据步骤2请求提供的参数名查找参数值,并将查询结果通过 RPC 发送给 Listener。
参数可使用数据类型:
- 32-bit integers
- booleans
- strings
- doubles
- iso8601 dates
- lists
- base64-encoded binary data
- 字典
注意:参数服务器不是为高性能而设计的,因此最好用于存储静态的非二进制的简单数据
2.3.2 参数操作
需求:实现参数服务器参数的增删改查操作。
2.3.2.1 参数服务器新增(修改)参数
- 新增参数:
1 | #! /usr/bin/env python |
新建四个终端:
- 第一个终端:
roscore
- 第二个终端:
rosrun plumbing_param_server demo01_param_set_p.py
- 第三个终端:
rosparam list
,查看参数列表 - 第四个终端:
rosparam get 参数名
,获取参数值
- 修改参数:
1 | #! /usr/bin/env python |
很明显观察到参数 radius
被修改为 1.11
:
2.3.2.2 参数服务器获取参数
这里提供了多个实现方式:
get_params(键,默认值)
:获取指定键的参数值,如果键不存在,返回默认值。get_param_cached(键,默认值)
:获取指定键的参数值,如果键不存在,返回默认值。与get_param
不同,该方法会缓存参数值,因此在循环中调用时效率更高。get_param_names()
:获取所有参数的键列表。has_param(键)
:检查参数服务器中是否存在指定键。search_param(参数名)
:搜索参数名,返回第一个匹配的参数名。
2.3.2.2.1 get_param
1 | #! /usr/bin/env python |
新建四个终端:
- 第一个终端:
roscore
- 第二个终端:
rosrun plumbing_param_server demo01_param_set_p.py
- 第三个终端:
rosrun plumbing_param_server demo02_param_get_p.py
- 第四个终端:
rosparam list
,获取参数列表
2.3.2.2.2 get_params_cached
1 | #! /usr/bin/env python |
2.3.2.2.3 get_param_names
1 | #! /usr/bin/env python |
2.3.2.2.4 has_param
1 | #! /usr/bin/env python |
2.3.2.2.5 search_param
1 | #! /usr/bin/env python |
2.3.2.3 参数服务器删除参数
使用 rospy.delete_param("键")
删除参数:
- 键不存在时,会抛出异常
- 键存在时,删除成功
1 | #! /usr/bin/env python |
这里如果要删除的参数不存在,是会抛异常的,这里我们使用try...except
结构打印出来异常,如下图所示:
2.4 常用命令
机器人系统中启动的节点少则几个,多则十几个、几十个,不同的节点名称各异,通信时使用话题、服务、消息、参数等等都各不相同,一个显而易见的问题是: 当需要自定义节点和其他某个已经存在的节点通信时,如何获取对方的话题、以及消息载体的格式呢?
在 ROS 同提供了一些实用的命令行工具,可以用于获取不同节点的各类信息,常用的命令如下:
rosnode
: 操作节点rostopic
: 操作话题rosservice
: 操作服务rosmsg
: 操作消息rossrv
: 操作 srv 消息rosparam
: 操作参数
作用:和之前介绍的文件系统操作命令比较,文件操作命令是静态的,操作的是磁盘上的文件,而上述命令是动态的,在ROS程序启动后,可以动态的获取运行中的节点或参数的相关信息。
案例:本节将借助于 2.1、2.2 和 2.3 的通信实现介绍相关命令的基本使用,并通过练习ROS内置的小海龟例程来强化命令的应用。
参考文档:CommandLineTools
2.4.1 rosnode
rosnode
是用于获取节点信息的命令:
- rosnode ping 测试到节点的连接状态
- rosnode list 列出活动节点
- rosnode info 打印节点信息
- rosnode machine 列出指定设备上节点
- rosnode kill 杀死某个节点
- rosnode cleanup 清除不可连接的节点
rosnode list
rosnode ping /Publisher_Person
rosnode info /Subscriber_Person
rosnode machine mpy-vpc
rosnode kill /Publisher_Person
能看到右下角的进程被杀死了:
rosnode cleanup
能看到虽然 /turtlesim
已经被 Ctrl+C
关掉了,但是 rosnode list
显示该节点还活着,这时候需要用 rosnode cleanup
清理干净
rosnode cleanup
清理僵尸节点:
2.4.2 rostopic
打开话题通信模型。
rostopic
包含rostopic
命令行工具,用于显示有关 ROS 主题的调试信息,包括发布者,订阅者,发布频率和 ROS 消息。它还包含一个实验性Python库,用于动态获取有关主题的信息并与之交互。
- rostopic bw 显示主题使用的带宽
- rostopic delay 显示带有 header 的主题延迟
- rostopic echo 打印消息到屏幕
- rostopic find 根据类型查找主题
- rostopic hz 显示主题的发布频率
- rostopic info 显示主题相关信息
- rostopic list 显示所有活动状态下的主题
- rostopic pub 将数据发布到主题
- rostopic type 打印主题类型
2.4.2.1 rostpoic list
2.4.2.2 rostopic echo 话题名
打开四个终端,在执行 rostopic echo Person
的终端中,我们要依次执行如下步骤:
cd ~/工作空间
,即进入到该功能包所在的工作空间;source ./devel/setup.bash
,即加载该功能包下的所有环境变量;rostopic echo 话题名
,即可打印发布的话题消息。
2.4.2.3 rostopic pub
在执行 rostopic pub 话题名 消息类型 "消息内容"
之前,我们要依次执行如下步骤:
cd ~/工作空间
,即进入到该功能包所在的工作空间;source ./devel/setup.bash
,即加载该功能包下的所有环境变量;rostopic pub 话题名 消息类型 "消息内容"
,即可发布消息。- 其中输入完消息类型后点击
Tab
可以自动补齐并产生“消息内容”。
- 其中输入完消息类型后点击
也可以按照某种频率发送消息:
rostopic pub -r 10 话题名 消息类型 "消息内容"
,即按照10hz的频率发布消息。
2.4.2.4 rostopic info
查看当前话题具体信息:
- 类型;
- 发布者;
- 订阅者;
2.4.2.5 rostopic hz
显示话题发布频率:
2.4.3 rosservice
打开服务通信模型。
rosservice
包含用于列出和查询ROSServices
的rosservice
命令行工具。
调用部分服务时,如果对相关工作空间没有配置 path,需要进入工作空间调用 source ./devel/setup.bash
.
常用的命令:
- rosservice args 打印服务参数
- rosservice call 使用提供的参数调用服务
- rosservice find 按照服务类型查找服务
- rosservice info 打印有关服务的信息
- rosservice list 列出所有活动的服务
- rosservice type 打印服务类型
- rosservice uri 打印服务的 ROSRPC uri
2.4.3.1 rosservice list
查看所有服务:
2.4.3.2 rosservice call
调用服务,扮演客户端的角色:
- 语法:
rosservice call 服务名 服务参数
; - 示例:
rosservice call Addints 服务参数
。- 服务参数可以直接使用
Tab
键补齐
- 服务参数可以直接使用
可以看到我们并没有启动客户端,仅仅通过该命令行也实现了客户端的功能。
2.4.3.3 rosservice info
查看服务具体信息:
Node
:服务所在的节点;URI
:服务的 ROSRPC uri;Type
:服务的类型;Args
:服务的参数;
2.4.3.4 rosservice type
查看服务类型:
- 语法:
rosservice type 服务名
; - 示例:
rosservice type Addints
。
2.4.4 rosmsg
打开话题通信模型。
rosmsg是用于显示有关 ROS 消息类型的信息的命令行工具。
常用的命令:
- rosmsg show 显示消息描述
- rosmsg info 显示消息信息
- rosmsg list 列出所有消息
- rosmsg md5 显示 md5 加密后的消息
- rosmsg package 显示某个功能包下的所有消息
- rosmsg packages 列出包含消息的功能包
2.4.4.1 rosmsg list
rosmsg list
会列出 ROS 支持的所有消息列表:
rosmsg list | grep -i 消息名
可以根据消息名进行搜索:
2.4.4.2 rosmsg info
和 rosmsg show
二者均是展示消息的详细信息,展示内容一致:
2.4.5 rossrv
rossrv
是用于显示有关 ROS 服务类型的信息的命令行工具,与 rosmsg
使用语法高度雷同。
常用语法:
- rossrv show 显示服务消息详情
- rossrv info 显示服务消息相关信息
- rossrv list 列出所有服务信息
- rossrv md5 显示 md5 加密后的服务消息
- rossrv package 显示某个包下所有服务消息
- rossrv packages 显示包含服务消息的所有包
2.4.5.1 rossrv list
显示 ROS 中所有的服务消息:
rossrv list | grep -i 服务名
可以根据服务名进行搜索:
2.4.5.2 rossrv info
使用用法是:rossrv info 消息名称
,而对应的消息名称我们已经使用rossrv list | grep -i 服务名
抓取到了。
2.4.5.3 rossrv show
整体用法与 rossrv info
一致,显示内容也一致:
2.4.6 rosparam
rosparam
包含 rosparam
命令行工具,用于使用 YAML
编码文件在参数服务器上获取和设置 ROS 参数。
常用命令:
- rosparam list 列出所有参数
- rosparam get 获取参数值
- rosparam set 设置参数值
- rosparam delete 删除参数
- rosparam dump 导出所有参数为 YAML 文件
- rosparam load 从 YAML 文件导入参数
2.4.6.1 rosparam list
列举出所有参数:
rosparam list
可以列出所有的参数;rosparam list | grep -i 参数名
可以根据参数名进行搜索。
2.4.6.2 rosparam set
& rosparam get
用法:
rosparam set 参数名 参数值
配合 rosparam list
以及 rosparam get 参数名
观察效果:
2.4.6.3 rosparam delete
- 首先使用
rosparam set
多设置几个参数和对应的值; - 演示
rosparam delete 参数名
效果。
2.4.6.4 rosparam dump
& rosparam load
描述:
- 执行
rosparam dump params.yaml
,将所有参数导出为 YAML 文件; - 执行
rosparam load params.yaml
,将 YAML 文件中的参数导入参数服务器。
这里我们演示将参数序列化,即导出为 YAML 文件:
接着我们将 roscore
重启,会发现之前自定义的参数已经被释放了,此时我们选择将 params.yaml
中的参数导入参数服务器,进行反序列化:
2.5 通信机制实操
内容:本节主要是通过ROS内置的 turtlesim
案例,结合已经介绍ROS命令获取节点、话题、话题消息、服务、服务消息与参数的信息,最终再以编码的方式实现乌龟运动的控制、乌龟位姿的订阅、乌龟生成与乌龟窗体背景颜色的修改。
目的:熟悉、强化通信模式应用。
2.5.1 实操01_话题发布
需求描述:编码实现乌龟运动控制,让小乌龟做圆周运动。
结果演示:
实现分析:
- 乌龟运动控制实现,关键节点有两个,一个是乌龟运动显示节点
turtlesim_node
,另外一个是控制节点,二者是订阅发布模式实现通信的,乌龟运动显示节点直接调用即可,运动控制节点之前是使用的turtle_teleop_key
通过键盘控制,现在需要自定义控制节点。 - 控制节点自实现时,首先需要了解控制节点与显示节点通信使用的话题与消息,可以使用ros命令结合计算图来获取。
- 了解了话题与消息之后,通过 C++ 或 Python 编写运动控制节点,通过指定的话题,按照一定的逻辑发布消息即可。
实现流程:
- 通过计算图结合ros命令获取话题与消息信息。
- 编码实现运动控制节点。
- 启动 roscore、turtlesim_node 以及自定义的控制节点,查看运行结果。
2.5.1.1 话题与消息获取
准备: 先启动键盘控制乌龟运动案例。
2.5.1.1.1 话题获取
获取话题:/turtle/cmd_vel
使用命令rostopic list
:
结合命令 rqt_graph
:
我们得知控制话题是 /turtle1/cmd_vel
。
2.5.1.1.2 消息获取
我们可以使用 rostopic info /tuetle1/cmd_vel
获取消息类型:
我们接着可以使用 rosmsg info geometry_msgs/Twist
获取消息的详细信息:
消息解释:
- linear:线速度,包含x、y、z三个坐标,单位是m/s;
- angular:角速度,包含x、y、z三个坐标,单位是rad/s。
详细请见补充资料。
对于乌龟案例而言,只需要控制其线速度的 x
参数,角速度的 z
参数即可实现圆周运动,以下我们先进行一个速度消息验证。
我们在终端中通过 rostopic echo /turtle1/cmd_vel
可以查看发布的速度消息:
可以通过打印数据观察到在整个运动过程中,只有线速度的 x
参数和角速度的 z
参数改变。
2.5.1.2 节点实现
- 其实有一种极简的方法实现,就是使用以下命令:
1 | rostopic pub 10 -r 1 /turtle1/cmd_vel geometry_msgs/Twist "linear: |
这条命令,其中
10
表示发布的频率,-r
表示重复发布,1
表示重复发布的次数,/turtle1/cmd_vel
表示发布的话题,geometry_msgs/Twist
表示发布的消息类型,后面的字符串是发布的消息内容。
- 使用 Python 实现自定义节点:
- 我们首先新建功能包:
catkin_create_pkg plumbing_test rospy roscpp std_msgs geometry_msgs
; - 我们在
plumbing_test/scripts
目录下新test01_pub_twist_p.py
文件,编写发布方代码; - 赋予可执行权限:
chmod +x *.py
; - 编辑
CMakeLists.txt
配置文件; - 运行:
rosrun plumbing_test test01_pub_twist_p.py
。
- 我们首先新建功能包:
1 | #! /usr/bin/env python |
2.5.1.3 运行
创建四个终端:
- 第一个终端
roscore
; - 第二个终端
rosrun turtlesim turtlesim_node
; - 第三个终端
rosrun plumbing_test test01_pub_twist_p.py
; - 第四个终端
rostopic echo /turtle1/cmd_vel
。
2.5.1.4 补充资料
这里整体均参考为右手坐标系。
- 弧度:单位弧度定义为圆弧长度等于半径时的圆心角。
- 圆周长计算公式:
- 偏航、翻滚与俯仰:
- 坐标系图解:
- 偏航:绕 z 轴旋转,单位是弧度;
- 俯仰:绕 y 轴旋转,单位是弧度;
- 翻滚:绕 x 轴旋转,单位是弧度。
2.5.2 实操02_话题订阅
需求描述: 已知turtlesim
中的乌龟显示节点,会发布当前乌龟的位姿(窗体中乌龟的坐标以及朝向),要求控制乌龟运动,并时时打印当前乌龟的位姿。
结果演示:
实现分析:
- 首先,启动乌龟显示以及运动控制节点并控制乌龟运动;
- 要通过 ROS 命令,来获取乌龟位姿发布的话题以及消息;
- 编写订阅节点,订阅并打印乌龟的位姿。
实现流程:
- 通过 ROS 命令获取话题与消息信息;
- 编码实现位姿获取节点;
- 启动
roscore
、turtlesim_node
、控制节点以及位姿订阅节点,控制乌龟运动并输出乌龟的位姿。
2.5.2.0 准备工作
准备工作:编写乌龟GUI界面和键盘控制的
launch
文件。
1 | <!-- 启动乌龟GUI与键盘控制节点 --> |
2.5.2.1 话题与消息获取
- 话题获取:
- 新建三个终端:
- 第一个:
roscore
- 第二个:
roslaunch plumbing_test start_turtle.launch
- 第三个:
rostopic list
/turtle1/pose
- 第一个:
- 新建三个终端:
- 消息类型获取:
- 首先使用
rostopic info /turtle1/pose
命令获取话题的消息类型;- 消息类型:
turtlesim/Pose
- 消息类型:
- 再使用
rosmsg info /turtle1/Pose
命令获取消息的具体结构;- 消息结构:
float32 x
float32 y
float32 theta
float32 linear_velocity
float32 angular_velocity
- 消息结构:
- 首先使用
2.5.2.2 实现订阅节点
最简单的方式,不需要通过自定义节点,只需要打印 /turtle1/pose
的信息即可:
1 | rostopic echo /turtle1/pose |
创建功能包需要依赖的功能包:roscpp rospy std_msgs turtlesim
,我们这里仍然在功能包 plumbing_test
中追加 turtlesim
依赖即可:
- 修改
package.xml
:
1 | <build_depend>turtlesim</build_depend> |
- 修改
CMakeLists.txt
:
1 | find_package(catkin REQUIRED COMPONENTS |
- 新建
test02_sub_pose_p.py
:
1 | #! /usr/bin/env python |
这里我们还需要配置 CMakeLists.txt
:
1 | catkin_install_python(PROGRAMS |
注意:为
Python
文件赋予执行权限。
2.5.3 实操03_服务调用
需求描述:编码实现向 turtlesim
发送请求,在乌龟显示节点的窗体指定位置生成一乌龟,这是一个服务请求操作。
结果演示:
实现分析:
- 首先,需要启动乌龟显示节点;
- 要通过ROS命令,来获取乌龟生成服务的服务名称以及服务消息类;
- 编写服务请求节点,生成新的乌龟。
实现流程:
- 通过ros命令获取服务与服务消息信息;
- 编码实现服务请求节点;
- 启动
roscore
、turtlesim_node
、乌龟生成节点,生成新的乌龟。
2.5.3.1 服务名称与服务消息获取
- 获取服务名称:
- 使用
rosservice list
:/spawn
- 使用
- 获取消息类型:
- 使用
rosservice info /spawn
turtlesim/Spawn
- 使用
- 获取消息结构:
- 使用
rossrv info turtlesim/Spawn
float32 x
float32 y
float32 theta
string name
- 使用
2.5.3.2 服务客户端实现
最简单的方式是使用 rosservice call
命令来调用服务,具体如下:
1 | rosservice call /spawn "x: 1.0 |
注意:
- 服务名称前需要添加
/
;- 服务消息的
x
、y
、theta
数据类型为float32
,name
数据类型为string
,需要使用''
包裹;- 多个数据之间使用空格隔开。
创建功能包需要依赖的功能包: roscpp rospy std_msgs turtlesim
- 创建
test03_srv_spawn_p.py
:
1 | #! /usr/bin/env python |
- 编辑
CMakeLists.txt
文件,赋予 Python 文件可执行权限,并编译。 - 运行,建立三个终端:
- 第一个:
roscore
- 第二个:
roslaunch plumbing_test start_turtle.launch
- 第三个:
rosrun plumbing_test test03_srv_spawn_p.py 3.0 3.0 0.5 "turtle3"
- 第一个:
2.5.4 实操04_参数设置
需求描述:修改 turtlesim
乌龟显示节点窗体的背景色,已知背景色是通过参数服务器的方式以 rgb
方式设置的。
结果演示:
实现分析:
- 首先,需要启动乌龟显示节点;
- 要通过ROS命令,来获取参数服务器中设置背景色的参数;
- 编写参数设置节点,修改参数服务器中的参数值。
实现流程:
- 通过ros命令获取参数;
- 编码实现服参数设置节点;
- 启动 roscore、turtlesim_node 与参数设置节点,查看运行结果。
2.5.4.1 参数名获取
- 获取参数列表:
/turtlesim/background_b
/turtlesim/background_g
/turtlesim/background_r
2.5.4.2 获取参数值
- 获取参数值:
rosparam get /turtlesim/background_r
rosparam get /turtlesim/background_g
rosparam get /turtlesim/background_b
2.5.4.2 参数修改
最简单的方式是直接使用命令的方式修改:
rosparam set /turtlesim/background_r 255
rosparam set /turtlesim/background_g 0
rosparam set /turtlesim/background_b 0
然后重新启动节点 rosrun turtlesim turtlesim_node
,会发现背景变为亮红色了:
接下来我们编写参数设置节点,修改背景颜色为亮红色。
新建 test04_par_back_p.py
文件,并配置 CMakeLists.txt
文件:
1 | #! /usr/bin/env python |
注意:赋予 Python 文件可执行权限,之后在终端运行
rosrun plumbing_test test04_par_back_p.py
,并重启 turtlesim_node 节点,查看运行结果。
2.5.4.3 补充其他设置方式
2.5.4.3.1 方式1:修改小乌龟节点的背景色(命令行实现)
1 | rosparam set /turtlesim/background_b 自定义数值 |
修改相关参数后,重启 turtlesim_node 节点,背景色就会发生改变了。
2.5.4.3.2 方式2:启动节点时,直接设置参数
1 | rosrun turtlesim turtlesim_node _background_r:=100 _background_g=0 _background_b=0 |
2.5.4.3.3 方式3:通过launch文件传参
1 | <launch> |
2.6 通信机制比较
三种通信机制中,参数服务器是一种数据共享机制,可以在不同的节点之间共享数据,话题通信与服务通信是在不同的节点之间传递数据的,三者是ROS中最基础也是应用最为广泛的通信机制。
这其中,话题通信和服务通信有一定的相似性也有本质上的差异,在此将二者做一下简单比较。
二者的实现流程是比较相似的,都是涉及到四个要素:
要素编号 | 要素内容 | 实现形式 |
---|---|---|
要素1 | 消息的发布方/客户端 | Publisher/Client |
要素2 | 消息的订阅方/服务端 | Subscriber/Server |
要素3 | 话题名称 | Topic/Service |
要素4 | 数据载体 | msg/srv |
可以概括为: 两个节点通过话题关联到一起,并使用某种类型的数据载体实现数据传输。
二者的实现也是有本质差异的,具体比较如下:
通信模式 | Topic(话题) | Service(服务) |
---|---|---|
同步性 | 异步 | 同步 |
底层协议 | ROSTCP/ROSUDP | ROSTCP/ROSUDP |
缓冲区 | 有 | 无 |
实时性 | 弱 | 强 |
节点关系 | 多对多 | 一对多(一个 Server) |
通信数据 | msg | srv |
使用场景 | 连续高频的数据发布与接收:雷达、里程计 | 偶尔调用或执行某一项特定功能: 拍照、语音识别 |
2.7 本章小节
本章主要介绍了ROS中最基本的也是最核心的通信机制实现: 话题通信、服务通信、参数服务器。每种通信机制,都介绍了如下内容:
- 伊始介绍了当前通信机制的应用场景;
- 介绍了当前通信机制的理论模型;
- 介绍了当前通信机制的 Python 实现。
除此之外,还介绍了:
- ROS中的常用命令方便操作、调试节点以及通信信息;
- 通过实操又将上述知识点加以整合;
- 最后又着重比较了话题通信与服务通信的相同点以及差异。
掌握本章内容后,基本上就可以从容应对ROS中大部分应用场景了。
第三章 ROS 通信机制进阶
本章主要内容如下:
- ROS常用API介绍;
- ROS中自定义头文件与源文件的使用。
3.1 常用 API
API
解释:API
的全称是 Application Programming Interface
,即应用程序编程接口。它是不同软件组件之间进行交互的一套规则和协议,就像两个程序之间沟通的 “桥梁”,比如在 Python 中调用的各种库函数,本质上就是在使用该库提供的 API
。
建议参考官方API文档或参考源码:
- ROS节点的初始化相关API;
- NodeHandle 的基本使用相关API;
- 话题的发布方,订阅方对象相关API;
- 服务的服务端,客户端对象相关API;
- 时间相关API;
- 日志输出相关API。
参考文档:
3.1.1 初始化
1 | #! /usr/bin/env python |
3.1.1.1 argv
的使用
我们在命令行中使用如下命令行,可以传入参数A,并赋值10000:
1 | rosrun plumbing_apis demo01_apis_pub_p.py _A:=10000 |
我们还可以查看并获取参数A的值:
1 | rosparam list /api_pub/A |
3.1.1.2 anoymous
的使用
如下图所示,我们能清楚发现,如果同一个 python 文件在两个终端运行,由于节点名称相同,会导致第一个启动的 python 文件被强制暂停:
这时候我们使用 anoymous
就可以很好的解决:
1 | rosnode list |
3.1.2 话题与服务相关对象
3.1.2.1 发布对象
参数解读:重点解读参数 latch
的使用,该参数作用是如果设置为 True,可以将发布的最后一条数据保存,且后续当新的订阅对象订阅时,会立即收到最后一条数据。
应用场景:
- 发布机器人的速度指令;
- 发布发布地图数据。
API 定义:
1 | class Publisher(Topic): |
示例代码:
1 | #! /usr/bin/env python |
如下图所示,我们先运行:
1 | rosrun plumbing_apis demo01_apis_pub_p.py |
接下来我们用终端调用一个新的节点来订阅:
1 | rostopic echo /api_pub_test |
3.1.2.2 订阅对象
对象获取:
1 | class Subscriber(Topic): |
3.1.2.3 服务对象
对象获取:
1 | class Service(ServiceImpl): |
3.1.2.4 客户端对象
对象获取:
1 | class ServiceProxy(_Service): |
请求发送函数:
1 | def call(self, *args, **kwds): |
等待服务函数:
1 | def wait_for_service(service, timeout=None): |
3.1.3 回旋函数
1 | def spin(): |
3.1.4 时间
ROS中时间相关的API是极其常用,比如:获取当前时刻、持续时间的设置、执行频率、休眠、定时器…都与时间相关。
1 | #! /usr/bin/env python |
3.1.4.1 时刻
3.1.4.2 持续时间
3.1.4.3 持续时间与时刻运算
注意:
Time
和Time
不可以相加减。
3.1.4.4 设置运行频率
这里设置为 0.5Hz
,即每隔2秒发送一次。
3.1.4.5 定时器
定时器解读:
1 | #定时器设置 |
根据该API定义,回调函数需要接收参数类型是rospy.TimerEvent
,如下展示其具有的作用:
1 | # 回调函数 |
3.1.5 其他函数
这里我们主要介绍两类 API:
- 一类是与节点生命周期有关:
- 节点接收到了关闭信息,比如常用的 ctrl + c 快捷键就是关闭节点的信号;
- 同名节点启动,导致现有节点退出;
- 程序中的其他部分调用了节点关闭相关的API(rospy.signal_shutdown())
- 一类是与日志相关:
- DEBUG(调试):只在调试时使用,此类消息不会输出到控制台;
- INFO(信息):标准消息,一般用于说明系统内正在执行的操作;
- WARN(警告):提醒一些异常情况,但程序仍然可以执行;
- ERROR(错误):提示错误信息,此类错误会影响程序运行;
- FATAL(严重错误):此类错误将阻止节点继续运行。
1 | #! /usr/bin/env python |
3.2 ROS中Python模块导入
需求:首先新建一个Python文件A,再创建Python文件UseA,在UseA中导入A并调用A的实现。
实现:
- 新建两个Python文件,使用 import 实现导入关系;
- 添加可执行权限、编辑配置文件并执行UseA。
3.2.1 创建 tools.py
1 | #! /usr/bin/env python |
3.2.2 创建 demo04_module_p.py
1 | #! /usr/bin/env python |
3.2.3 尝试运行并纠错
- 此时我们仅仅完成
CMakeLists.txt
中如下配置:
1 | catkin_install_python(PROGRAMS |
chmod +x *.py
赋予可执行权限后,尝试运行:
执行命令 | 运行结果 |
---|---|
rosrun plumbing_apis demo04_module_p.py |
|
python3 demo04_module_p.py |
解释:这主要是由于
rosrun
指令默认的执行路径是工作空间下,而并没有聚焦到具体功能包的scripts
文件夹下,就导致rosrun
找不到指定文件,会报错,我们可以通过以下代码验证。
1 | #! /usr/bin/env python |
执行指令 | 运行结果 |
---|---|
rosrun plumbing_apis demo04_module_p.py |
|
python3 demo04_module_p.py |
解决:我们可以声明 python 的环境变量,当依赖某个模块时,先去指定的环境变量中查找依赖。
问题:这样虽然解决了找不到 my_tools.py
模块的问题,但是这样将路径写死并不好,会导致其他人用这个代码的时候,还需要修改路径,因此接下来我们提供一个更优选择,我们可以动态获取路径:
1 | #! /usr/bin/env python |
第四章 ROS 运行管理
ROS是多进程(节点)的分布式框架,一个完整的ROS系统实现:
- 可能包含多台主机;
- 每台主机上又有多个工作空间(workspace);
- 每个的工作空间中又包含多个功能包(package);
- 每个功能包又包含多个节点(Node),不同的节点都有自己的节点名称;
- 每个节点可能还会设置一个或多个话题(topic)。
在多级层深的ROS系统中,其实现与维护可能会出现一些问题,比如,如何关联不同的功能包,繁多的ROS节点应该如何启动?功能包、节点、话题、参数重名时应该如何处理?不同主机上的节点如何通信?
本章主要内容介绍在ROS中上述问题的解决策略(见本章目录),预期达成学习目标也与上述问题对应:
- 掌握元功能包使用语法;
- 掌握launch文件的使用语法;
- 理解什么是ROS工作空间覆盖,以及存在什么安全隐患;
- 掌握节点名称重名时的处理方式;
- 掌握话题名称重名时的处理方式;
- 掌握参数名称重名时的处理方式;
- 能够实现ROS分布式通信。
4.1 ROS元功能包
场景:
- 完成ROS中一个系统性的功能,可能涉及到多个功能包,比如实现了机器人导航模块,该模块下有地图、定位、路径规划…等不同的子级功能包。那么调用者安装该模块时,需要逐一的安装每一个功能包吗?
- 显而易见的,逐一安装功能包的效率低下,在ROS中,提供了一种方式可以将不同的功能包打包成一个功能包,当安装某个功能模块时,直接调用打包后的功能包即可,该包又称之为元功能包(metapackage)。
概念:
- MetaPackage是Linux的一个文件管理系统的概念。是ROS中的一个虚包,里面没有实质性的内容,但是它依赖了其他的软件包,通过这种方法可以把其他包组合起来,我们可以认为它是一本书的目录索引,告诉我们这个包集合中有哪些子包,并且该去哪里下载。
- 例如
sudo apt install ros-noetic-desktop-full
命令安装ros时就使用了元功能包,该元功能包依赖于ROS中的其他一些功能包,安装该包时会一并安装依赖。 - 还有一些常见的MetaPackage:navigation moveit! turtlebot3 …
作用:
- 方便用户的安装,我们只需要这一个包就可以把其他相关的软件包组织到一起安装了。
实现:
- 基础描述:我目前已经有如图所示的五个功能包,我想要使用元功能包来管理这几个功能包。
- 创建一个功能包;
catkin_create_pkg plumbing_my
,不需要加依赖。
- 修改
package.xml
,内容如下,添加构建依赖:
1 | <exec_depend>plumbing_apis</exec_depend> |
- 修改
CMakeLists.txt
:
1 | cmake_minimum_required(VERSION 3.0.2) |
Ctrl+Shift+B
编译,编译通过。
CMakeLists.txt
中不可以有换行。
参考架构:ROS navigation
4.2 ROS 节点管理 launch 文件
一个程序中可能需要启动多个节点,比如:ROS 内置的小乌龟案例,如果要控制乌龟运动,要启动多个窗口,分别启动 roscore、乌龟界面节点、键盘控制节点。如果每次都调用 rosrun 逐一启动,显然效率低下,如何优化?
采用的优化策略便是使用 roslaunch 命令集合 launch 文件启动管理节点,并且在后续教程中,也多次使用到了 launch 文件。
概念:
- launch 文件是一个 XML 格式的文件,可以启动本地和远程的多个节点,还可以在参数服务器中设置参数。
作用:
- 简化节点的配置与启动,提高ROS程序的启动效率。
使用:
- 新建launch文件:
- 在功能包下添加 launch目录, 目录下新建
start_turtle.launch
文件,编辑 launch 文件。
- 在功能包下添加 launch目录, 目录下新建
1 | <launch> |
- 编译并新建一个终端窗口,输入
source ./devel/setup.bash
。
- 调用 launch 文件:
这里附上官方链接:ROS launch
4.2.1 launch文件标签——launch
<launch>
标签是所有 launch 文件的根标签,充当其他标签的容器。
属性:
deprecated = "弃用声明"
:如果该 launch 文件已经弃用,那么可以使用该属性进行说明。
1 | <launch deprecated = "此文件已过时,不建议使用!"> |
如下图所示,执行效果一样,只是会在终端输出日志:
1 | WARNING: [/home/mpy/workspace_learn_ros/autolabor_python/src/launch01_basic/launch/start_turtle.launch] DEPRECATED: 此文件已过时,不建议使用! |
4.2.2 launch文件标签——node
<node>
标签用于指定 ROS 节点,是最常见的标签,需要注意的是: roslaunch 命令不能保证按照 node 的声明顺序来启动节点(节点的启动是多进程的)
-
属性:
pkg="包名"
:节点所属的包type="nodeType"
:节点类型(与之相同名称的可执行文件)name="nodeName"
:节点名称(在 ROS 网络拓扑中节点的名称)args="xxx xxx xxx" (可选)
:将参数传递给节点machine="机器名"
:在指定机器上启动节点respawn="true | false" (可选)
:如果节点退出,是否自动重启respawn_delay=" N" (可选)
:如果 respawn 为 true, 那么延迟 N 秒后启动节点required="true | false" (可选)
:该节点是否必须,如果为 true,那么如果该节点退出,将杀死整个 roslaunchns="xxx" (可选)
:在指定命名空间 xxx 中启动节点clear_params="true | false" (可选)
:在启动前,删除节点的私有空间的所有参数output="log | screen" (可选)
:日志发送目标,可以设置为 log 日志文件,或 screen 屏幕,默认是 log
-
子级标签:
env
:环境变量设置remap
:重映射节点名称rosparam
:参数设置param
:参数设置
4.2.2.1 respawn
respawn
属性:如果节点退出,是否自动重启
respawn="true | false" (可选)
:如果节点退出,是否自动重启respawn_delay=" N" (可选)
:如果 respawn 为 true, 那么延迟 N 秒后启动节点
1 | <launch deprecated = "此文件已过时,不建议使用!"> |
如下演示所示,我们关闭窗口后会自动启动,那么如何彻底关闭节点呢?
- 在终端中使用
Ctrl+C
即可。
4.2.2.2 required
required="true | false" (可选)
:该节点是否必须,如果为 true,那么如果该节点退出,将杀死整个 roslaunch。
1 | <launch deprecated = "此文件已过时,不建议使用!"> |
如下演示过程:
如下可以观察到终端输出:REQUIRED process [my_turtle-2] has died!
4.2.2.3 ns
ns="xxx" (可选)
:在指定命名空间 xxx 中启动节点。
我们首先解释一下什么是命名空间,如下图所示,我们可以查看到节点列表名称:rosnode list
这时候如果我们想要在各个节点之前加前缀,我们可以在ns
属性中添加,如下:
1 | <launch deprecated = "此文件已过时,不建议使用!"> |
如下图所示:
ns
的使用可以很好的避免重名问题。
4.2.3 launch文件标签——include
include 标签用于将另一个 xml 格式的 launch 文件导入到当前文件。
-
属性:
file=$(find 包名)/xxx/xxx.launch
:要包含的文件路径;ns="xxx"(可选)
:在指定命名空间导入文件。
-
子级标签:
env
:环境变量设置;arg
:将参数传递给被包含的文件。
我们在launch01_basic
功能包下的launch
文件夹中新建start_turtle_use.launch
文件:
1 | <!-- 需要复用 start_turtle.launch 文件,使用 include 标签 --> |
注意:
launch
文件编写完毕后,不需要编译,可以直接执行。
1 | roslaunch launch01_basic start_turtle_use.launch |
4.2.4 launch文件标签——remap
remap
:用于话题重命名
- 属性:
from = "xxx"
:原始话题名称;to = "xxx"
:目标名称。
- 子级标签:无
这里我们首先补充下载一个控制功能包:
1 | sudo apt-get install ros-noetic-teleop-twist-keyboard |
然后我们就可以运行以下命令打开自带的键盘控制节点:
1 | rosrun teleop_twist_keyboard teleop_twist_keyboard.py |
从图中可以明显看出,自启动的键盘控制节点话题名称是/cmd_vel
,而乌龟仿真对应的节点话题名称是/turtle/cmd_vel
,如何使得两个话题名称一致从而可以正常通讯呢?就要使用我们的remap
标签了。
1 | <launch deprecated = "此文件已过时,不建议使用!"> |
4.2.5 launch文件标签——param
<param>
标签主要用于在参数服务器上设置参数,参数源可以在标签中通过 value 指定,也可以通过外部文件加载,在<node>
标签中时,相当于私有命名空间。
- 属性:
name="命名空间/参数名"
:- 参数名称,可以包含命名空间;
value="xxx"(可选)
:- 定义参数值,如果此处省略,必须指定外部文件作为参数源;
type="str | int | double | bool | yaml"(可选)
:- 指定参数类型,如果未指定,roslaunch 会尝试确定参数类型,规则如下:
- 如果包含
.
的数字解析为浮点型,否则为整型; - “true” 和 “false” 是 bool 值(不区分大小写);
- 其他是字符串。
- 如果包含
- 指定参数类型,如果未指定,roslaunch 会尝试确定参数类型,规则如下:
- 子级标签:无
- 格式:
launch
内,node
外;launch
内,node
内,此时会被视为私有。
1 | <launch deprecated = "此文件已过时,不建议使用!"> |
如下图如所示,使用rosparam list
可以观察到两个参数:
launch
内,node
外:/param_A
launch
内,node
内:/my_turtle/param_B
4.2.6 launch文件标签——rosparam
<rosparam>
标签可以从 YAML 文件导入参数,或将参数导出到 YAML 文件,也可以用来删除参数,<rosparam>
标签在<node>
标签中时被视为私有。
- 属性:
command = "load | dump | delete"
:load
:从 YAML 文件导入参数;dump
:将参数导出到 YAML 文件;delete
:删除参数。
file = "$(find xxx)/xxx/yyy/..."
:- 指定 YAML 文件路径。
param="参数名称"
ns="命名空间"(可选)
- 子级标签:无
- 格式:
launch
内,node
外;launch
内,node
内,此时会被视为私有。
4.2.6.1 参数导入
1 | <launch deprecated = "此文件已过时,不建议使用!"> |
4.2.6.2 参数导出
接下来我们也演示一下其他操作,如参数导出:
1 | <launch deprecated = "此文件已过时,不建议使用!"> |
此时我们发现,导出的params_dump.yaml
文件中,导出的只有少数几个参数,不符合我们的预期,如下图所示:
真正的操作顺序应该是,我们将rosparam
有关导出操作的标签写入一个新的launch
文件中,我们命名为dump.launch
:
1 | <launch> |
我们新建三个终端:
- 终端1:
roslaunch launch01_basic start_turtle.launch
- 终端2:
rosparam list
- 终端3:
roslaunch launch01_basic dump.launch
我们再打开生成的params_dump.yaml
文件,发现导出参数完整:
4.2.6.3 参数删除
1 | <launch> |
我们新建三个终端:
- 终端1:
roslaunch launch01_basic start_turtle.launch
- 终端2:
rosparam list
- 终端3:
roslaunch launch01_basic dump.launch
经过两次rosparam list
查询,明显可以发现参数/bg_B
已被删除。
4.2.7 launch文件标签——group
<group>
标签可以对节点分组,具有 ns 属性,可以让节点归属某个命名空间。
- 属性:
ns="命名空间"(可选)
clear_params="true|false"(可选)
:启动前,是否删除组名称空间的所有参数(慎用…此功能危险)。
- 子级标签:
- 除了
<launch>
标签外的其他标签。
- 除了
我们首先新建一个launch
文件为turtles.launch
:
1 | <launch> |
我们可以通过rosnode list
命令能查看到节点名称,如下:
使用
group
标签可以很好的避免节点重名问题,而且可以使launch
文件的层级结构更清晰。
4.2.8 launch文件标签——arg
<arg>
标签是用于动态传参,类似于函数的参数,可以增强launch文件的灵活性。
- 属性:
name="参数名"
:参数名。default="默认值"
:默认值。value="参数值"
:不可以与 default 并存doc="描述"
:参数说明。
- 子级标签:无
我们新建一个arg.launch
文件:
1 | <launch> |
我们新建三个终端:
- 第一个终端:
roscore
- 第二个终端:
roslaunch launch01_basic arg.launch
- 第三个终端:
rosparam list
我们也可以在终端直接动态传入car_length
的值:
1 | roslaunch launch01_basic arg.launch car_length:=0.6 |
4.3 ROS工作空间覆盖
所谓工作空间覆盖,是指不同工作空间中,存在重名的功能包的情形。
ROS 开发中,会自定义工作空间且自定义工作空间可以同时存在多个,可能会出现一种情况: 虽然特定工作空间内的功能包不能重名,但是自定义工作空间的功能包与内置的功能包可以重名或者不同的自定义的工作空间中也可以出现重名的功能包,那么调用该名称功能包时,会调用哪一个呢?比如:自定义工作空间A存在功能包 turtlesim,自定义工作空间B也存在功能包 turtlesim,当然系统内置空间也存在turtlesim,如果调用turtlesim包,会调用哪个工作空间中的呢?
4.3.1 实现
4.3.1.1 新建工作空间并配置
新建工作空间A和工作空间B,在两个工作空间中都创建功能包
turtlesim
;
- 首先我们需要配置
task.json
文件:
1 | { |
- 我们还需要配置
settings.json
文件:
1 | { |
- 接着,我们需要在每个工作空间下的
src
文件夹内执行
1 | catkin_create_pkg turtlesim roscpp rospy std_msgs |
- 我们需要分别在两个工作空间内添加
python
文件,并添加执行权限和修改CMakeLists.txt
文件:
/home/mpy/workspace_learn_ros/A/src/turtlesim/scripts/hello_ws01.py
1 | #! /usr/bin/env python |
/home/mpy/workspace_learn_ros/B/src/turtlesim/scripts/hello_ws02.py
1 | #! /usr/bin/env python |
4.3.1.2 配置环境变量
- 在
~/.bashrc
文件下追加当前工作空间的bash格式如下:
1 | source /home/用户/路径/工作空间A/devel/setup.bash |
- 新开命令行,
source .bashrc
加载环境变量; - 查看ROS环境环境变量
echo $ROS_PACKAGE_PATH
; - 调用命令
roscd turtlesim
会进入自定义工作空间B
。
4.3.2 原因
ROS 会解析 .bashrc
文件,并生成 ROS_PACKAGE_PATH
ROS包路径,该变量中按照 .bashrc
中配置设置工作空间优先级,在设置时需要遵循一定的原则:ROS_PACKAGE_PATH
中的值,和 .bashrc
的配置顺序相反—>后配置的优先级更高,如果更改自定义空间A与自定义空间B的source顺序,那么调用时,将进入工作空间B。
4.3.3 结论
功能包重名时,会按照 ROS_PACKAGE_PATH
查找,配置在前的会优先执行。
4.3.4 隐患
存在安全隐患,比如当前工作空间B优先级更高,意味着当程序调用 turtlesim
时,不会调用工作空间A也不会调用系统内置的 turtlesim
,如果工作空间A在实现时有其他功能包依赖于自身的 turtlesim
,而按照ROS工作空间覆盖的涉及原则,那么实际执行时将会调用工作空间B的turtlesim
,从而导致执行异常,出现安全隐患。
BUG说明:
当在.bashrc
文件中 source 多个工作空间后,可能出现的情况,在ROS PACKAGE PATH
中只包含两个工作空间,可以删除自定义工作空间的build
与devel
目录,重新catkin_make
,然后重新载入.bashrc
文件,问题解决。
4.4 ROS 节点名称重名
场景:ROS 中创建的节点是有名称的,
C++
初始化节点时通过API:ros::init(argc,argv,"xxxx")
;来定义节点名称,在Python中初始化节点则通过rospy.init_node("yyyy")
来定义节点名称。在ROS的网络拓扑中,是不可以出现重名的节点的,因为假设可以重名存在,那么调用时会产生混淆,这也就意味着,不可以启动重名节点或者同一个节点启动多次,的确,在ROS中如果启动重名节点的话,之前已经存在的节点会被直接关闭,但是如果有这种需求的话,怎么优化呢?
在ROS中给出的解决策略是使用命名空间或名称重映射。
命名空间就是为名称添加前缀,名称重映射是为名称起别名。这两种策略都可以解决节点重名问题,两种策略的实现途径有多种:
- rosrun 命令
- launch 文件
- 编码实现
以上三种途径都可以通过命名空间或名称重映射的方式,来避免节点重名,本节将对三者的使用逐一演示,三者要实现的需求类似。
启动两个 turtlesim
节点,当然如果直接打开两个终端,直接启动,那么第一次启动的节点会关闭,并给出提示:
4.4.1 rosrun 设置命名空间与名称重映射
4.4.1.1 rosrun 设置命名空间
- 语法:
rosrun 包名 节点名__ns:=新名称
1 | rosrun turtlesim turtlesim_node __ns:=/xxx |
1 | rosrun turtlesim turtlesim_node __ns:=/yyy |
4.4.1.2 rosrun 设置名称重映射
- 语法:
rosrun 包名 节点名 __name:=新名称
1 | rosrun turtlesim turtlesim_node __name:=t1 |
1 | rosrun turtlesim turtlesim_node __name:=t2 |
注意这里要使用
rosnode cleanup
清理一下僵尸节点。
4.4.1.3 rosrun 命名空间与名称重映射叠加
- 语法:
rosrun 包名 节点名 __ns:=新名称 __name:=新名称
1 | rosrun turtlesim turtlesim_node __ns:=/xxx __name:=t1 |
1 | rosrun turtlesim turtlesim_node __ns:=/yyy __name:=t2 |
使用环境变量也可以设置命名空间,启动节点前在终端键入如下命令:
export ROS_NAMESPACE=xxxx
4.4.2 launch 文件设置命名空间与名称重映射
介绍 launch 文件的使用语法时,在 node 标签中有两个属性: name 和 ns,二者分别是用于实现名称重映射与命名空间设置的。使用launch文件设置命名空间与名称重映射也比较简单。
4.4.2.1 launch 文件
1 | <!-- 需要启动多个乌龟 GUI 节点 --> |
4.4.3 编码设置命名空间与名称重映射
4.4.3.1 名称别名设置
核心代码:
rospy.init_node("t1", anoymous=True)
,会在节点名称后缀时间戳。
4.5 ROS 话题名称设置
在ROS中节点名称可能出现重名的情况,同理话题名称也可能重名。
在 ROS 中节点终端,不同的节点之间通信都依赖于话题,话题名称也可能出现重复的情况,这种情况下,系统虽然不会抛出异常,但是可能导致订阅的消息非预期的,从而导致节点运行异常。这种情况下需要将两个节点的话题名称由相同修改为不同。
又或者,两个节点是可以通信的,两个节点之间使用了相同的消息类型,但是由于,话题名称不同,导致通信失败。这种情况下需要将两个节点的话题名称由不同修改为相同。
在实际应用中,按照逻辑,有些时候可能需要将相同的话题名称设置为不同,也有可能将不同的话题名设置为相同。在ROS中给出的解决策略与节点名称重命类似,也是使用名称重映射或为名称添加前缀。根据前缀不同,有全局、相对、和私有三种类型之分。
- 全局(参数名称直接参考ROS系统,与节点命名空间平级);
- 相对(参数名称参考的是节点的命名空间,与节点名称平级);
- 私有(参数名称参考节点名称,是节点名称的子级)。
名称重映射是为名称起别名,为名称添加前缀,该实现比节点重名更复杂些,不单是使用命名空间作为前缀、还可以使用节点名称作为前缀。两种策略的实现途径有多种:
- rosrun 命令
- launch 文件
- 编码实现
案例描述:在ROS中提供了一个比较好用的键盘控制功能包:ros-noetic-teleop-twist-keyboard
,该功能包,可以控制机器人的运动,作用类似于乌龟的键盘控制节点,可以使用 sudo apt install ros-noetic-teleop-twist-keyboard
来安装该功能包,然后执行;rosrun teleop_twist_keyboard teleop_twist_keyboard.py
,在启动乌龟显示节点,不过此时前者不能控制乌龟运动,因为,二者使用的话题名称不同,前者使用的是 cmd_vel
话题,后者使用的是 /turtle1/cmd_vel
话题。需要将话题名称修改为一致,才能使用,如何实现?
4.5.1 rosrun 设置话题重映射
rosrun名称重映射语法:rorun 包名 节点名 话题名:=新话题名称
实现teleop_twist_keyboard
与乌龟显示节点通信方案由两种。
4.5.1.1 方案1
目的:将 teleop_twist_keyboard
节点的话题设置为/turtle1/cmd_vel
。
- 启动乌龟显示节点:
rosrun turtlesim turtlesim_node
- 启动键盘控制节点:
rosrun teleop_twist_keyboard teleop_twist_keyboard.py /cmd_vel:=/turtle1/cmd_vel
4.5.1.2 方案2
目的:将乌龟显示节点的话题设置为 /cmd_vel
。
- 启动乌龟显示节点:
rosrun turtlesim turtlesim_node /turtle1/cmd_vel:=/cmd_vel
- 启动键盘控制节点:
rosrun teleop_twist_keyboard teleop_twist_keyboard.py
注意使用
rosnode cleanup
清理僵尸节点。
4.5.2 launch 文件设置话题重映射
语法:
1 | <node pkg="xxx" type="xxx" name="xxx"> |
实现teleop_twist_keyboard与乌龟显示节点通信方案由两种,这里只演示将乌龟显示节点的话题设置为 /cmd_vel
。
1 | <!-- 键盘控制乌龟运动 --> |
注意使用
rosnode cleanup
清理僵尸节点。
4.5.3 编码设置话题名称
话题的名称与节点的命名空间、节点的名称是有一定关系的,话题名称大致可以分为三种类型:
- 全局(话题参考ROS系统,与节点命名空间平级)
- 相对(话题参考的是节点的命名空间,与节点名称平级)
- 私有(话题参考节点名称,是节点名称的子级)
4.5.3.1 演示准备
- 初始化节点设置一个节点名称:
rospy.init_node("hello")
- 设置不同类型的话题
- 启动节点时,传递一个
__ns:= xxx
- 节点启动后,使用 rostopic 查看话题信息
4.5.3.2 全局名称
格式:以/开头的名称,和节点名称无关
1 | #! /usr/bin/env python |
4.5.3.3 相对名称
格式:非/开头的名称,参考命名空间(与节点名称平级)来确定话题名称
1 | #! /usr/bin/env python |
4.5.3.4 私有名称
格式:以~开头的名称
1 | #! /usr/bin/env python |
4.6 ROS 参数名称设置
在ROS中节点名称话题名称可能出现重名的情况,同理参数名称也可能重名。
当参数名称重名时,那么就会产生覆盖,如何避免这种情况?
关于参数重名的处理,没有重映射实现,为了尽量的避免参数重名,都是使用为参数名添加前缀的方式,实现类似于话题名称,有全局、相对、和私有三种类型之分。
- 全局(参数名称直接参考ROS系统,与节点命名空间平级)
- 相对(参数名称参考的是节点的命名空间,与节点名称平级)
- 私有(参数名称参考节点名称,是节点名称的子级)
4.6.1 rosrun 设置参数
语法:rosrun 包名 节点名称 _参数名:=参数值
1 | rosrun turtlesim turtlesim_node _radius:=3.56 |
我们再使用rosparam list
能够查看到我们设置的参数:
这里我们设置的radius
是私有的。
4.6.2 launch 文件设置参数
通过 launch
文件设置参数的方式前面已经介绍过了,可以在 node
标签外,或 node
标签中通过 param
或 rosparam
来设置参数。在 node
标签外设置的参数是全局性质的,参考的是 /
,在 node
标签中设置的参数是私有性质的,参考的是 /命名空间/节点名称
。
1 | <!-- 设置参数 --> |
4.6.3 编码设置参数
编码的方式可以更方便的设置:全局、相对与私有参数。
调用的API时 rospy.set_param
,该函数中,参数1
传入参数名称,参数2
是传入参数值,参数1
中参数名称设置时,如果以 /
开头,那么就是全局参数,如果以 ~
开头,那么就是私有参数,既不以 / 也不以 ~ 开头,那么就是相对参数。代码示例:
1 | #! /usr/bin/env python |
4.7 ROS 分布式通信
ROS是一个分布式计算环境。一个运行中的ROS系统可以包含分布在多台计算机上多个节点。根据系统的配置方式,任何节点可能随时需要与任何其他节点进行通信。
因此,ROS对网络配置有某些要求:
- 所有端口上的所有机器之间必须有完整的双向连接。
- 每台计算机必须通过所有其他计算机都可以解析的名称来公告自己。
4.7.1 实现
- 准备:先要保证不同计算机处于同一网络中,最好分别设置固定IP,如果为虚拟机,需要将网络适配器改为桥接模式;
- 配置文件修改:
分别修改不同计算机的/etc/hosts
文件,在该文件中加入对方的IP地址和计算机名:
主机端:
1 | 从机的IP 从机计算机名 |
从机端:
1 | 主机的IP 主机计算机名 |
设置完毕,可以通过 ping
命令测试网络通信是否正常。
IP地址查看名: ifconfig
计算机名称查看: hostname
- 配置主机IP:
配置主机的 IP 地址,在~./.bashrc
追加:
1 | export ROS_MASTER_URI=http://主机IP:11311 |
- 配置从机IP:
配置从机的 IP 地址,从机可以有多台,每台都在~./.bashrc
追加:
1 | export ROS_MASTER_URI=http://主机IP:11311 |
4.7.2 测试
- 主机启动 roscore(必须);
- 主机启动订阅节点,从机启动发布节点,测试通信是否正常;
- 反向测试,主机启动发布节点,从机启动订阅节点,测试通信是否正常。
4.8 本章小结
本章主要介绍了ROS的运行管理机制,内容如下:
- 如何通过元功能包关联工作空间下的不同功能包
- 使用 launch 文件来管理维护 ROS 中的节点
- 重名是经常出现的,重名时会导致什么情况?以及怎么避免重名?
- 如何实现 ROS 分布式通信?
本章的重点是"重名"相关的内容:
- 包名重复,会导致覆盖。
- 节点名称重复,会导致先启动的节点关闭
- 话题名称重复,无语法异常,但是可能导致通信实现出现逻辑问题
- 参数名称重复,会导致参数设置的覆盖
解决重名问题的实现方案有两种:
- 重映射(重新起名字)
- 为命名添加前缀
本章介绍的内容还是偏向语法层面的实现,下一章将开始介绍ROS中内置的一些较为实用的组件。
第五章 ROS 常用组件
在ROS中内置一些比较实用的工具,通过这些工具可以方便快捷的实现某个功能或调试程序,从而提高开发效率,本章主要介绍ROS中内置的如下组件:
- TF坐标变换,实现不同类型的坐标系之间的转换;
- rosbag 用于录制ROS节点的执行过程并可以重放该过程;
- rqt 工具箱,集成了多款图形化的调试工具。
本章预期达成的学习目标:
- 了解 TF 坐标变换的概念以及应用场景;
- 能够独立完成TF案例:小乌龟跟随;
- 可以使用 rosbag 命令或编码的形式实现录制与回放;
- 能够熟练使用rqt中的图形化工具。
案例演示:小乌龟跟随实现,该案例是ros中内置案例,终端下键入启动命令。
1 | roslaunch turtle_tf2 turtle_tf2_demo.launch |
键盘可以控制一只乌龟运动,另一只跟随运动。
5.1 TF 坐标变换
机器人系统上,有多个传感器,如激光雷达、摄像头等,有的传感器是可以感知机器人周边的物体方位(或者称之为:坐标,横向、纵向、高度的距离信息)的,以协助机器人定位障碍物,可以直接将物体相对该传感器的方位信息,等价于物体相对于机器人系统或机器人其它组件的方位信息吗?显示是不行的,这中间需要一个转换过程。更具体描述如下:
场景1:雷达与小车
现有一移动式机器人底盘,在底盘上安装了一雷达,雷达相对于底盘的偏移量已知,现雷达检测到一障碍物信息,获取到坐标分别为(x,y,z),该坐标是以雷达为参考系的,如何将这个坐标转换成以小车为参考系的坐标呢?
场景2:机器人
现有一带机械臂的机器人(比如:PR2)需要夹取目标物,当前机器人头部摄像头可以探测到目标物的坐标(x,y,z),不过该坐标是以摄像头为参考系的,而实际操作目标物的是机械臂的夹具,当前我们需要将该坐标转换成相对于机械臂夹具的坐标,这个过程如何实现?
当然,根据我们高中学习的知识,在明确了不同坐标系之间的的相对关系,就可以实现任何坐标点在不同坐标系之间的转换,但是该计算实现是较为常用的,且算法也有点复杂,因此在 ROS 中直接封装了相关的模块: 坐标变换(TF)。
概念:
- tf:transform frame,坐标变换;
- 坐标系:ROS 中是通过坐标系标定物体的,确切地说是通过右手坐标系来标定的。
作用:
- 在 ROS 中用于实现不同坐标系之间的点或向量的转换。
案例:
- 小乌龟跟随案例:如本章引言部分演示。
说明:
- 在ROS中坐标变换最初对应的是tf,不过在 hydro 版本开始, tf 被弃用,迁移到 tf2,后者更为简洁高效,tf2 对应的常用功能包有:
tf2_geometry_msgs
:可以将ROS消息转换成tf2消息。tf2
: 封装了坐标变换的常用消息。tf2_ros
:为tf2提供了roscpp和rospy绑定,封装了坐标变换常用的API。
官方文档:
5.1.1 坐标 msg 消息
订阅发布模型中数据载体 msg 是一个重要实现,首先需要了解一下,在坐标转换实现中常用的msg:
geometry_msgs/TransformStamped
- 用于传输坐标系相关位置信息。
geometry_msgs/PointStamped
- 用于传输某个坐标系内坐标点的信息
在坐标变换中,频繁的需要使用到坐标系的相对关系以及坐标点信息。
geometry_msgs/TransformStamped
:- 命令行输入:
rosmsg info geometry_msgs/TransformStamped
- 命令行输入:
1 | std_msgs/Header header #头信息 |
geometry_msgs/PointStamped
:- 命令行输入:
rosmsg info geometry_msgs/PointStamped
- 命令行输入:
1 | std_msgs/Header header #头 |
官方文档:
四元数补充:
5.1.2 静态坐标变换
所谓静态坐标变换,是指两个坐标系之间的相对位置是固定的。
需求描述:
- 现有一机器人模型,核心构成包含主体与雷达,各对应一坐标系,坐标系的原点分别位于主体与雷达的物理中心,已知雷达原点相对于主体原点位移关系如下:。当前雷达检测到一障碍物,在雷达坐标系中障碍物的坐标为 ,请问,该障碍物相对于主体的坐标是多少?
实现分析:
- 坐标系相对关系,可以通过发布方发布;
- 订阅方,订阅到发布的坐标系相对关系,再传入坐标点信息(可以写死),然后借助于 tf 实现坐标变换,并将结果输出
实现流程:
- 新建功能包,添加依赖;
- 编写发布方实现;
- 编写订阅方实现;
- 执行并查看结果。
5.1.2.1 创建功能包
在终端输入:
1 | catkin_create_pkg tf01_static roscpp rospy std_msgs |
然后在该功能包目录下新建scripts
文件夹,用于存放脚本文件。
5.1.2.2 发布方实现
- 在
scripts
文件夹下新建demo01_static_pub.py
,并配置CMakeLists.txt
。 - 在终端输入
chmod +x *.py
赋予执行权限。
1 | #! /usr/bin/env python |
新建三个终端:
- 第一个终端:
roscore
- 第二个终端:
rosrun tf01_static demo01_static_pub.py
- 第三个终端:
rostopic echo /tf_static
也可以通过rviz
来查看:
- 终端输入
rviz
; Global Options
中Fixed Frame
选择为base_link
;- 点击
Add
,添加TF
。
5.1.2.3 订阅方实现
- 在
scripts
文件夹下新建demo02_static_sub.py
,并配置CMakeLists.txt
。 - 在终端输入
chmod +x *.py
赋予执行权限。
1 | #! /usr/bin/env python |
新建三个终端:
- 第一个终端:
roscore
- 第二个终端:
rosrun tf01_static demo01_static_pub.py
- 第三个终端:
rosrun tf01_static demo02_static_sub.py
5.1.2.4 补充1:代码复用
当坐标系之间的相对位置固定时,那么所需参数也是固定的:
- 父系坐标名称
- 子级坐标系名称
- x偏移量、y偏移量、z偏移量
- x 翻滚角度、y俯仰角度、z偏航角度
实现逻辑相同,参数不同,那么 ROS 系统就已经封装好了专门的节点,使用方式如下:
1 | rosrun tf2_ros static_transform_publisher x偏移量 y偏移量 z偏移量 z偏航角度 y俯仰角度 x翻滚角度 父级坐标系 子级坐标系 |
示例:
1 | rosrun tf2_ros static_transform_publisher 0.1 0 0.3 0 0 0 /baselink /camera |
也建议使用该种方式直接实现静态坐标系相对信息发布。
也可以使用rviz
查看:
我们也可以测试一下俯仰角:
1 | rosrun tf2_ros static_transform_publisher 0.1 0.0 0.3 0 0.5 0 /base_link /camera |
这里将y俯仰角设置为正值,意味着绕y轴逆时针旋转0.5弧度:
5.1.2.5 补充2:rviz
可以借助于rviz显示坐标系关系,具体操作:
- 新建窗口输入命令
rviz
; - 在启动的 rviz 中设置Fixed Frame 为 base_link;
- 点击左下的 add 按钮,在弹出的窗口中选择 TF 组件,即可显示坐标关系。
5.1.2.6 参考资料
- http://wiki.ros.org/tf2/Tutorials/Writing a tf2 static broadcaster (C%2B%2B)
- http://wiki.ros.org/tf2/Tutorials/Writing a tf2 static broadcaster (Python)
- http://wiki.ros.org/tf2/Tutorials/Writing a tf2 listener (C%2B%2B)
- http://wiki.ros.org/tf2/Tutorials/Writing a tf2 listener (Python)
5.1.3 动态坐标变换
所谓动态坐标变换,是指两个坐标系之间的相对位置是变化的。
需求描述:
- 启动
turtlesim_node
,该节点中窗体有一个世界坐标系(左下角为坐标系原点),乌龟是另一个坐标系,键盘控制乌龟运动,将两个坐标系的相对位置动态发布。
结果演示:
实现分析:
- 乌龟本身不但可以看作坐标系,也是世界坐标系中的一个坐标点;
- 订阅
turtle1/pose
,可以获取乌龟在世界坐标系的 x坐标、y坐标、偏移量以及线速度和角速度; - 转换 pose 信息,将其转换成 坐标系相对信息并发布。
实现流程:
- 新建功能包,添加依赖;
- 创建坐标相对关系发布方(同时需要订阅乌龟位姿信息);
- 创建坐标相对关系订阅方;
- 执行。
5.1.3.1 创建功能包
在终端输入:
1 | catkin_create_pkg tf02_dynamic tf2 tf2_ros tf2_geometry_msgs roscpp rospy std_msgs geometry_msgs turtlesim |
然后在该功能包目录下新建scripts
文件夹,用于存放脚本文件。
5.1.3.2 发布方实现
- 在
scripts
文件夹下新建demo01_dynamic_pub.py
,并配置CMakeLists.txt
。 - 在终端输入
chmod +x *.py
赋予执行权限。
1 | #! /usr/bin/env python |
新建五个终端:
- 第一个终端:
roscore
- 第二个终端:
rosrun turtlesim turtlesim_node
- 第三个终端:
rosrun tf02_dynamic demo01_dynamic_pub.py
- 第四个终端:
rostopic echo /tf
- 第五个终端:
rosrun turtlesim turtle_teleop_key
也可以通过rviz
来查看:
- 终端输入
rviz
; Global Options
中Fixed Frame
选择为base_link
;- 点击
Add
,添加TF
。
5.1.3.3 订阅方实现
- 在
scripts
文件夹下新建demo02_dynamic_sub.py
,并配置CMakeLists.txt
。 - 在终端输入
chmod +x *.py
赋予执行权限。
1 | #! /usr/bin/env python |
注意:这里修改了时间戳信息为
ps.header.stamp = rospy.Time()
,因为动态坐标变换。
在动态坐标变换的订阅方中使用 rospy.Time()
是为了:
- ✅ 获取最新的坐标变换数据
- ✅ 避免时间同步问题
- ✅ 简化时间管理
- ✅ 提高系统的鲁棒性
这是ROS TF系统的最佳实践,确保坐标变换查询的可靠性和实时性。
新建五个终端:
- 第一个终端:
roscore
- 第二个终端:
rosrun turtlesim turtlesim_node
- 第三个终端:
rosrun tf02_dynamic demo01_dynamic_pub.py
- 第四个终端:
rosrun turtlesim turtle_teleop_key
- 第五个终端:
rosrun tf02_dynamic demo02_dynamic_sub.py
5.1.3.4 参考资料
- http://wiki.ros.org/tf2/Tutorials/Writing a tf2 broadcaster (C%2B%2B)
- http://wiki.ros.org/tf2/Tutorials/Writing a tf2 broadcaster (Python)
5.1.4 多坐标变换
需求描述:
- 现有坐标系统,父级坐标系统 world,下有两子级系统 son1和son2,son1 相对于 world,以及 son2 相对于 world 的关系是已知的。
- 求 son1 原点在 son2中的坐标;
- 又已知在 son1 中一点的坐标,求该点在 son2 中的坐标。
实现分析:
- 首先,需要发布 son1 相对于 world,以及 son2 相对于 world 的坐标消息;
- 然后,需要订阅坐标发布消息,并取出订阅的消息,借助于 tf2 实现 son1 和 son2 的转换;
- 最后,还要实现坐标点的转换。
实现流程:
- 新建功能包,添加依赖;
- 创建坐标相对关系发布方(需要发布两个坐标相对关系);
- 创建坐标相对关系订阅方;
- 执行。
5.1.4.1 创建功能包
在终端输入:
1 | catkin_create_pkg tf03_tfs tf2 |
- 该功能包目录下新建
scripts
文件夹,用于存放脚本文件; - 该功能包目录下新建
launch
文件夹,用于存放launch
文件。
5.1.4.2 发布方实现
为了方便,我们这里撰写tfs.launch
文件,使用静态坐标变换发布。
1 | <launch> |
这里为了测试,我们新建三个终端:
- 第一个终端:
roscore
- 第二个终端:
roslaunch tf03_tfs tfs.launch
- 第三个终端:
rviz
5.1.4.3 订阅方实现
- 在
scripts
文件夹下新建my_python_script.py
,并配置CMakeLists.txt
。 - 在终端输入
chmod +x *.py
赋予执行权限。
1 | #! /usr/bin/env python |
新建四个终端:
- 第一个终端:
roscore
- 第二个终端:
roslaunch tf03_tfs tfs.launch
- 第三个终端:
rosrun tf03_tfs demo01_tfs_p.py
- 第四个终端:
rviz
5.1.5 坐标系关系查看
在机器人系统中,涉及的坐标系有多个,为了方便查看,ros 提供了专门的工具,可以用于生成显示坐标系关系的 pdf 文件,该文件包含树形结构的坐标系图谱。
5.1.5.1 准备
首先调用rospack find tf2_tools
查看是否包含该功能包:
如果没有,请使用如下命令安装:
1 | sudo apt install ros-noetic-tf2-tools |
5.1.5.2 使用
5.1.5.2.1 生成PDF文件
启动坐标系广播程序之后,运行如下命令:
1 | rosrun tf2_tools view_frames.py |
会产生如下日志:
1 | mpy@mpy-vpc:~$ rosrun tf2_tools view_frames.py |
查看当前目录会生成一个 frames.pdf 文件。
5.1.5.2.2 查看PDF
可以直接进入目录打开文件,或者调用命令查看文件:evince frames.pdf
5.1.5.3 参考资料
5.1.6 TF 坐标变换实操
需求分析:程序启动之初,产生两只乌龟,中间的乌龟(A) 和 左下乌龟(B), B 会自动运行至A的位置,并且键盘控制时,只是控制 A 的运动,但是 B 可以跟随 A 运行。
结果演示:
实现分析:
乌龟跟随实现的核心,是乌龟A和B都要发布相对世界坐标系的坐标信息,然后,订阅到该信息需要转换获取A相对于B坐标系的信息,最后,再生成速度信息,并控制B运动。
- 启动乌龟显示节点;
- 在乌龟显示窗体中生成一只新的乌龟(需要使用服务);
- 编写两只乌龟发布坐标信息的节点;
- 编写订阅节点订阅坐标信息并生成新的相对关系生成速度信息。
实现流程:
- 新建功能包,添加依赖;
- 编写服务客户端,用于生成一只新的乌龟;
- 编写发布方,发布两只乌龟的坐标信息;
- 编写订阅方,订阅两只乌龟信息,生成速度信息并发布;
- 运行。
5.1.6.1 准备工作
- 了解如何创建第二只乌龟,且不受键盘控制:
创建第二只乌龟需要使用 rosservice
,话题使用的是 spawn
。
1 | rosservice call /spawn "x: 1.0 |
键盘是无法控制第二只乌龟运动的,因为使用的话题: /第二只乌龟名称/cmd_vel
,对应的要控制乌龟运动必须发布对应的话题消息。
- 了解如何获取两只乌龟的坐标
是通过话题 /乌龟名称/pose 来获取的。
1 | x: 1.0 //x坐标 |
5.1.6.2 创建功能包
在终端输入:
1 | catkin_create_pkg tf04_test tf2 |
- 该功能包目录下新建
scripts
文件夹,用于存放脚本文件; - 该功能包目录下新建
launch
文件夹,用于存放launch
文件。
5.1.6.3 服务客户端(生成乌龟)
新建test01_new_turtle_p.py
:
1 | #! /usr/bin/env python |
此时为了方便我们测试,我们创建了test_p.launch
文件:
1 | <launch> |
我们在终端中执行该launch
文件:
1 | roslaunch tf04_test test_p.launch |
5.1.6.4 发布方(发布两只乌龟的坐标信息)
新建test02_pub_turtle_p.py
文件:
1 | #!/usr/bin/env python |
修改test_p.launch
文件:
1 | <launch> |
5.1.6.5 订阅方(解析坐标信息并生成速度信息)
新建test03_control_turtle_p.py
:
1 | #! /usr/bin/env python |
新建三个终端:
- 第一个终端:
roscore
- 第二个终端:
roslaunch tf04_test test_p.launch
- 第三个终端:
rviz
5.1.7 TF2与TF
5.1.7.1 简介
- TF2 已经替换了TF,TF2 是 TF 的超集,建议学习 TF2 而非 TF;
- TF2 功能包的增强了内聚性,TF 与 TF2 所依赖的功能包是不同的,TF 对应的是 tf 包,TF2 对应的是 tf2 和 tf2_ros 包,在 TF2 中不同类型的 API 实现做了分包处理。
- TF2 实现效率更高,比如在,TF2 的静态坐标实现、TF2 坐标变换监听器中的 Buffer 实现等。
5.1.7.2 静态坐标变换演示
接下来,我们通过静态坐标变换来演示TF2的实现效率。
5.1.7.2.1 启动 TF2 与 TF 两个版本的静态坐标变换
- TF2 版静态坐标变换:
1 | rosrun tf2_ros static_transform_publisher 0 0 0 0 0 0 /base_link /laser |
- TF 版静态坐标变换:
1 | rosrun tf static_transform_publisher 0 0 0 0 0 0 /base_link /laser |
会发现,TF 版本的启动中最后多一个参数,该参数是指定发布频率。
5.1.7.2.2 运行结果比对
使用 rostopic
查看话题,包含 /tf
与 /tf_static
,前者是 TF 发布的话题,后者是 TF2 发布的话题,分别调用命令打印二者的话题消息
rostopic echo /tf
: 当前会循环输出坐标系信息;rostopic echo /tf_static
: 坐标系信息只有一次。
5.1.7.3 结论
如果是静态坐标转换,那么不同坐标系之间的相对状态是固定的,既然是固定的,那么没有必要重复发布坐标系的转换消息,很显然的,tf2 实现较之于 tf 更为高效。
5.1.8 小结
坐标变换在机器人系统中是一个极其重要的组成模块,在 ROS 中 TF2 组件是专门用于实现坐标变换的,TF2 实现具体内容又主要介绍了如下几部分:
- 静态坐标变换广播器,可以编码方式或调用内置功能包来实现(建议后者),适用于相对固定的坐标系关系;
- 动态坐标变换广播器,以编码的方式广播坐标系之间的相对关系,适用于易变的坐标系关系;
- 坐标变换监听器,用于监听广播器广播的坐标系消息,可以实现不同坐标系之间或同一点在不同坐标系之间的变换;
- 机器人系统中的坐标系关系是较为复杂的,还可以通过 tf2_tools 工具包来生成 ros 中的坐标系关系图;
- 当前 TF2 已经替换了 TF,官网建议直接学习 TF2,并且 TF 与 TF2 的使用流程与实现 API 比较类似,只要有任意一方的使用经验,另一方也可以做到触类旁通。
5.2 rosbag
机器人传感器获取到的信息,有时我们可能需要时时处理,有时可能只是采集数据,事后分析,比如:
机器人导航实现中,可能需要绘制导航所需的全局地图,地图绘制实现,有两种方式:
方式1:可以控制机器人运动,将机器人传感器感知到的数据时时处理,生成地图信息。
方式2:同样是控制机器人运动,将机器人传感器感知到的数据留存,事后,再重新读取数据,生成地图信息。
两种方式比较,显然方式2使用上更为灵活方便。
概念:
- 是用于录制和回放 ROS 主题的一个工具集。
作用:
- 实现了数据的复用,方便调试、测试。
本质:
- rosbag 本质也是 ros 的节点:
- 当录制时,rosbag 是一个订阅节点,可以订阅话题消息并将订阅到的数据写入磁盘文件;
- 当重放时,rosbag是一个发布节点,可以读取磁盘文件,发布文件中的话题消息。
参考文档:http://wiki.ros.org/rosbag
5.2.1 rosbag使用——命令行
需求:ROS 内置的乌龟案例并操作,操作过程中使用 rosbag 录制,录制结束后,实现重放。
实现:
- 准备:创建目录保存录制的文件
1 | mkdir ~/rosbag |
- 开始录制:
- 我们这里新建四个终端:
- 第一个终端:
roscore
- 第二个终端:
rosrun turtlesim turtlesim_node
- 第三个终端:
rosrun turtlesim turtle_teleop_key
- 第四个终端:
rosbag record -a -o ~/rosbag/hello.bag
- 第一个终端:
- 我们这里新建四个终端:
操作小乌龟一段时间,结束录制使用 ctrl + c
,在创建的目录中会生成 bag 文件。
解释:
-a
表示all
,录制全部的意思;-o
表示output
,后面跟输出文件绝对路径。
生成bag
文件如下:
- 查看文件:
1 | rosbag info ~/rosbag/hello_2025-07-22-20-12-25.bag |
- 回放文件:
1 | rosbag play ~/rosbag/hello_2025-07-22-20-12-25.bag |
重启乌龟节点,会发现,乌龟按照录制时的轨迹运动。
参考文档:http://wiki.ros.org/rosbag/Commandline
5.2.2 rosbag使用——编码
命令实现不够灵活,可以使用编码的方式,增强录制与回放的灵活性,本节将通过简单的读写实现演示rosbag的编码实现。
5.2.2.1 准备工作
- 新建功能包:
1 | catkin_create_pkg rosbag_demo roscpp rospy std_msgs rosbag |
- 新建
srcipts
文件夹,放置python
文件。
5.2.2.2 写 bag
新建demo01_write_bag.py
,并配置CMakeLists.txt
,以及赋予执行权限。
1 | #! /usr/bin/env python |
打开终端并运行:
1 | rosrun rosbag_demo demo01_write_bag.py |
查看生成的bag
文件:
1 | rosbag info ~/rosbag/hello_p.bag |
5.2.2.3 读 bag
新建demo02_read_bag.py
,并配置CMakeLists.txt
,以及赋予执行权限。
1 | #! /usr/bin/env python |
打开终端并运行:
1 | rosrun rosbag_demo demo2_read_bag.py |
5.3 rqt 工具箱
之前,在 ROS 中使用了一些实用的工具,比如:ros_bag 用于录制与回放、tf2_tools 可以生成 TF 树;这些工具大大提高了开发的便利性,但是也存在一些问题:这些工具的启动和使用过程中涉及到一些命令操作,应用起来不够方便,在ROS中,提供了rqt工具箱,在调用工具时以图形化操作代替了命令操作,应用更便利,提高了操作效率,优化了用户体验。
概念:
- ROS基于 QT 框架,针对机器人开发提供了一系列可视化的工具,这些工具的集合就是 rqt。
作用:
- 可以方便的实现 ROS 可视化调试,并且在同一窗口中打开多个部件,提高开发效率,优化用户体验。
组成:
rqt
:核心实现,开发人员无需关注rqt_common_plugins
:rqt 中常用的工具套件rqt_robot_plugins
:运行中和机器人交互的插件(比如: rviz)
5.3.1 rqt 安装启动与基本使用
- 安装:
- 一般只要你安装的是desktop-full版本就会自带工具箱;
- 如果需要安装可以以如下方式安装:
1 | sudo apt-get install ros-noetic-rqt |
-
启动:
- 方式1:
rqt
- 方式2:
rosrun rqt_gui rqt_gui
- 方式1:
-
基本使用:
- 启动 rqt 之后,可以通过 plugins 添加所需的插件;
-
话题通信——乌龟控制演示:
- 服务通信——乌龟生成演示:
5.3.2 rqt 常用插件:rqt_graph
- 简介:可视化显示计算图
- 启动:可以在 rqt 的 plugins 中添加,或者使用rqt_graph启动
- 基本使用:
- 启动 rqt_graph 之后,会显示当前 ROS 系统中的所有话题、服务和参数;
- 可以通过点击不同的话题、服务或参数来查看其详细信息;
- 可以使用鼠标拖动节点来调整显示位置,方便查看不同的话题、服务或参数之间的关系;
- 可以使用鼠标右键点击节点来添加、删除或修改节点;
- 可以使用键盘快捷键来操作节点,比如:Ctrl+R 刷新显示,Ctrl+Q 退出程序。
5.3.3 rqt 常用插件:rqt_console
- 简介:rqt_console 是 ROS 中用于显示和过滤日志的图形化插件
- 准备:编写 Node 节点输出各个级别的日志信息
1 | #! /usr/bin/env python |
- 启动:
- 可以在 rqt 的
plugins
中添加,或者使用rqt_console
启动;
- 可以在 rqt 的
5.3.4 rqt 常用插件:rqt_plot
- 简介:图形绘制插件,可以以 2D 绘图的方式绘制发布在 topic 上的数据
- 准备:启动 turtlesim 乌龟节点与键盘控制节点,通过 rqt_plot 获取乌龟位姿
- 启动:可以在 rqt 的 plugins 中添加,或者使用rqt_plot启动
5.3.5 rqt 常用插件:rqt_bag
- 简介:录制和重放 bag 文件的图形化插件
- 准备:启动 turtlesim 乌龟节点与键盘控制节点
- 启动:可以在 rqt 的 plugins 中添加,或者使用rqt_bag启动
5.4 本章小结
本章主要介绍了ROS中的常用组件,内容如下:
- TF坐标变换(重点);
- rosbag 用于ros话题的录制与回放;
- rqt工具箱,图形化方式调用组件,提高操作效率以及易用性。
其中 TF坐标变换是重点,也是难点,需要大家熟练掌握坐标变换的应用场景以及代码实现。下一章开始将介绍机器人系统仿真,我们将在仿真环境下,创建机器人、控制机器人运动、搭建仿真环境,并以机器人的视角去感知世界。