- ROS主要包含包括功能包、节点、话题、消息类型和服务;
ROS功能包/软件包(Packages)
- ROS软件包是一组用于实现特定功能的相关文件的集合,包括可执行文件和其他支持文件。
- 所有的 ROS 软件都是一个软件包或其他软件包的一部分。
- 每个程序包由一个清单文件(文件名为 package.xml)定义。
- 该文件定义关于包的一些细节,包括其名称、版本、维护者和依赖关系。
- 包含 package.xml 文件的目录被称为软件包目录。
- 使用catkin编译构建系统的功能包, 编译产生的可执行文件存放在一个单独的标准化目录层次结构中。
- 功能包集(stack): 功能包集是紧密相关的功能包的集合,从groovy开始慢慢地被淘汰, 取而代之的是元功能包(metapackages)。
节点管理器(The Master)
- 接单(node)是几乎相对独立的小程序,这些节点必须能够通信, 通信的关键部分是ROS节点管理器。
- 启动节点管理器的命令 -- roscore。
- 大多数 ROS 节点在启动时连接到节点管理器上,如果运行中连接中断,则不会尝试重新连接。
- 因此,如果 roscore被终止,当前运行的其他节点将无法建立新的连接,即使稍后重启 roscore 也无济于事。
- roslaunch 的工具,其目的是一次性启动多个节点。
节点(Nodes)
- 一旦启动roscore后,便可以运行ROS程序了, ROS程序的运行实例被称为节点(node)。
- “运行实例”(running instance)很重要。
- 如果我们同时执行相同程序的多个副本——注意确保每个副本使用不同的节点名——则每个副本都被当做一个单独的节点。
- 启动节点:
- 利用命令rosrun: rosrun package-name executable-name;
- rosrun 没有什么“神奇”的:它只不过是一个 shell 脚本,能够理解 ROS 的文件组织结构,知道到哪里能找到与给定包名称对应的可执行文件。
- 通过节点管理器注册成为 ROS 节点发生在程序的内部,而不是通过 rosrun 命令。
- 查看节点列表:
- 利用命令: rosnode list;
- rosout 节点是一个特殊的节点,通过 roscore 自动启动,其作用类似于标准输出(即std::cout)。
- 节点名不一定与对应可执行文件名称相同。
- 获得特定节点的信息: rosmode info node-name;
- 终止节点: rosnode kill node-name;
- 终止和重启节点通常不会对其他节点有较大影响。
- 即使节点间正在相互交换消息(message),这些连接也会在节点终止时断开,在节点重启时重新连接。
- 将节点从列表中删除: rosnode cleanup。
话题和消息
- ROS节点之间进行通信所利用的最重要的机制就是消息传递。
- 在ROS中,消息有组织地存放在话题里。
- 消息传递的理念:
- 当一个节点想要分享信息时,它就会发布(publish)消息到对应的一个或者多个话题;
- 当一个节点想要接收信息时, 它就会订阅(subscribe)它所需要的一个或多个话题;
- ROS节点管理器负责确保发布节点和订阅节点能找到对方;
- 消息是直接地从发布节点传递到订阅节点,中间并不经过节点管理器转交;
- 查看节点构成的计算图:
- 查看节点之间的发布-订阅关系的最简单方式就是在终端输入rqt_graph命令。
- r代表ROS, qt指的是Qt图形界面(GUI)工具包;
- 在默认情况下,rqt_graph 隐藏了其认为只在调试过程中使用的节点。
- 的名称/rosout 既指节点又指话题。但 ROS 并不会因这种重复的名字而混淆,因为 ROS 会根据上下文来推测我们讨论的是/rosout 节点还是/rosout 话题。
- ROS 节点通常设计成了只管发布它们有用的信息,而不需要担心是否有其他节点来订阅这些消息。这样有助于减少各个节点之间的耦合度。
- ,/teleop_turtle 节点会以消息的形式将这些运动控制命令发布到 话 题 /turtle1/cmd_vel; 与此同时,因为turtlesim_node 订阅了该话题,因此它会接收到这个些消息,控制海龟按照该预定的速度移动。
话题列表
- 通过rostopic list获取当前活跃的话题;
- 打印消息内容rostopic echo topic-name;
- 测试发布频率rostopic hz topic-name(每秒发布消息的数量) 和 rostopic bw topic-name(每秒发布消息所占的带宽);
- Type在文本输出中表示数据类型;
- 查看消息类型: rosmsg show message-type-name。
- 一个复合域是由简单的一个或者多个子域组合而成,其中的每一个子域可能是另一个复合域或者独立的域,而且它们一般也都由基本数据类型组成。
用命令行发布消息
- 利用rostopic命令工具: rostopic pub -r rate-in-hz topic-name message-type message-content(按照指定的频率给指定的话题发布指定的消息);
- 该命令最后的参数 message-content 应该按顺序提供消息类型中所有域的参数值。
- rostopic pub -r 1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 3]'命令中利用了-r来指定话题以频率模式发布消息;
- 锁存模式只是发布一条消息,但锁存模式是默认的模式。
- -f是从文件中读取,输入应该 符合rostopic echo的输出格式。
- 编写一种脚本将 rostopic echo 和 rostopic pub 结合起来作为“记录”和“回放”消息的方式;rosbag工具。
理解消息类型的命名
- 每条消息类型都属于一个特定的包,消息类型名总会包含一个斜杆,斜杆钱面的名字是包含它的包: package-name/type-name;
- turtlesim/Color中的turtlesim是功能包名, Color是类型名称;
- ROS 节点管理器不允许多个节点拥有相同的名称。
话题通信的多对多机制
- 基于话题和消息的通信机制是多对多的,即多个发布者和多个订阅者可以共享同一个话题。
- 节点之间的松耦合关系:
- 每个节点都不需要显式知道其他节点的存在与否;它们的唯一交互方式是间接地发生在基于话题和消息的通信层。
- 节点之间的独立性,以及其支持的任务可分解特性(即复杂任务分解成可重用的小模块),是 ROS 最关键的设计特性之一。
- “生产”消息的程序(例如 turtle_teleop_key)只管发布该消息,而不用关心该消息是如何被“消费”的。
- “消费”消息的程序(例如 turtlesim_node)只管订阅该话题或者它所需要消息的所有话题,而不用关心这些消息数据是如何“生产”的。
- ROS为更加直接的一对一通信提供了一种称为服务(services)的机制。
- ROS 利用roswtf进行问题的查找。
- roswtf 将会检测在安装过程中 rosdep 初始化是否完成,任何节点是否出现了意外的挂起或者终止,以及活跃的节点是否正确地和其他节点相连接等。
- roswtf 检测的完整列表只能在 Python 源码中才能找到。
编写ROS程序
创建工作区和功能包
- 创建工作区,我们创建的包,应该全部放到一个叫做工作区的目录中。
- ROS的catkin编译系统试图一次性编译同一个工作区中的所有功能包,如果设计到几个相互独立的项目,则应该维护数个独立的工作区。
- 每个工作区必须创建一个src的子目录,这个子目录讲用于存放功能包的源码。
- catkin_create_pkg package-name是创建一个功能包。
- 一个配置文件 -- package.xml这是一个清单文件。
- CMakeLists.txt是一个Cmake的脚本文件, 其实catkin在内部使用了Cmake。
- ROS 包的命名遵循一个命名规范,只允许使用小写字母、数字和下划线,而且首字符必须是一个小写字母。一些 ROS工具,包括 catkin,不支持那些不遵循此命名规范的包。
- 本着保持文档与实际功能同步的精神,至少在package.xml中填写description 和 maintainer 两部分可能是比较合理的
- 包含消息的声明: 每一个话题都与一个消息类型相关联,每一个消息类型都有一个相对应C++头文件。
#include <package_name/type_name.h>头文件, 像#include <geometry_msgs/Twist.h>表示名为 geometry_msgs 的包所拥有的类型为 Twist 的消息。
编写回调函数
- 发布和订阅消息的一个重要的区别是订阅者节点无法知道消息什么时候才能到达, 为了对应这一事实, 我们必须把响应收到消息事件的代码放到回调函数里, ROS每接收到一个新的消息将调用一次这个函数。
日志消息
- 学习如何生成和查看日志消息。
- ROS中分为5个不同的严重级别,按严重性程度递增为: DEBUG、INFO、WARN、ERROR、FATAL。