ROS不仅仅是一个开发框架。我们可以将ROS称为元操作系统,因为它不仅提供工具和库,还提供类似操作系统的功能(如硬件抽象、包管理)和开发人员工具链。与真实的操作系统一样,ROS文件以特定的方式组织在硬盘上,如图1.1所示。
以下是对文件系统中每个板块的解释:
● 功能包 :ROS功能包(也叫软件包,或者简称包)是ROS软件的核心元素,包含一个或多个ROS程序(节点)、库、配置文件等,它们作为一个单元组织在一起。包是ROS软件中的原子构建和发布项。
● 功能包清单 :功能包清单文件位于包内,包含有关包、作者、许可证、依赖项、编译标志等的信息。ROS包中的package.xml文件就是清单文件。
图1.1 ROS文件系统级别
● 元功能包 :元功能包(简称元包)指的是一个或多个可以松散分组的相关包。原则上,元包是不包含任何源代码或通常可以在包中找到的典型文件的虚拟包。
● 元功能包清单 :元功能包清单与功能包清单类似,区别在于它可以将包作为运行时的依赖项包含在其中,并声明一个导出(export)标记。
● 消息( .msg ) :我们可以在包内的msg文件夹中自定义消息(my_package/msg/MyMessageType.msg)。消息文件的扩展名是.msg。
● 服务( .srv ): 回复和请求数据类型可以在包内的srv文件夹中定义(my_package/srv/MyServiceType.srv)。
● 存储库 :大多数ROS包都是使用 版本控制系统 (VCS)维护的,比如Git、 Subversion ( SVN )或 Mercurial ( hg )。放在VCS上的一组文件称为存储库。
图1.2所示是我们将要创建的功能包的文件和文件夹。
接下来将讨论ROS包的所有文件和目录的目标。
图1.2 示例包中的文件列表
ROS功能包的典型结构如图1.3所示。
图1.3 一个典型C++ROS功能包的结构
让我们讨论一下每个文件夹的使用方法。
●config:ROS包中使用的所有配置文件都保存在这个文件夹中。此文件夹由用户创建,通常将文件夹命名为config,表示这是保存配置文件的位置。
●include/package_name:这个文件夹里面包含我们需要在包中使用的头文件和库。
●script:此文件夹包含可执行的Python脚本。
●src:此文件夹存储C++源代码。
●launch:此文件夹包含用于启动一个或多个ROS节点的启动文件。
●msg:此文件夹包含自定义的消息定义。
●srv:此文件夹包含服务定义。
●action:此文件夹包含动作文件。我们将在第2章中了解更多关于此类文件的知识。
●package.xml:这是此包的功能包清单文件。
●CMakeLists.txt:此文件包含编译包的指令。
我们需要了解一些用于创建、修改和使用ROS包的命令,如下是一些常用的。
●catkin_create_pkg:此命令用于创建新包。
●rospack:此命令用于获取文件系统中包的相关信息。
●catkin_make:此命令用于在工作区中构建包。
●rosdep:此命令将安装此软件包所需的系统依赖项。
为了使用功能包,ROS提供了一个类似bash的命令,叫作rosbash(http://wiki.ros.org/rosbash),可用于导航和操作ROS包。以下是一些rosbash命令。
●roscd:此命令用于使用包名、栈名或特殊位置信息更改当前目录。如果我们以一个包名作为参数,它将切换到该包的文件夹。
●roscp:此命令用于从包中复制文件。
●rosed:此命令用于使用vim编辑器编辑文件。
●rosrun:此命令用于在包内运行可执行文件。
在一个典型的包中,package.xml的定义如图1.4所示。
图1.4 package.xml的定义
package.xml也包含有关编译的信息。<build_depend></build_depend>标签包括构建包的源代码所需的包。<run_depend></run_depend>标签内的包是在运行时运行包节点所必需的。
元包是一种特殊的包,只需要一个文件,即package.xml。
元包只是将多个包组合为一个逻辑包。在元包的package.xml文件中包含一个导出标记,如下所示:
此外,在元包中,catkin没有<buildtool_depend>依赖项,只有<run_depend>依赖项,它们就是在元包中被组合到一起的那些包。
ROS导航栈是包含元包的地方的一个良好示例。如果安装了ROS及导航包,我们可以尝试使用以下命令来切换到navigation元包文件夹:
使用喜欢的文本编辑器(在下面的例子中是gedit)打开package.xml文件:
这是一个冗长的文件,图1.5所示是它的精简版本。
图1.5 package.xml元包的结构
此文件包含有关包的几条信息,例如简要说明、依赖项和包版本。
ROS节点可以写入或读取各种类型的数据。这些不同类型的数据使用简化的消息描述语言(也称为ROS消息)进行描述。这些数据类型描述可用于以不同的目标语言为适当的消息类型生成源代码。
尽管ROS框架提供了大量已经实现的机器人专用消息,开发人员仍然可以在节点内定义自己的消息类型。
消息定义可以由两种类型组成:字段和常量。字段分为字段类型和字段名称,前者是传输消息的数据类型,而后者是它的名称。
以下是消息定义的一个示例:
这里,左边是字段类型,右边是字段名。字段类型就是数据类型,字段名可用于访问消息中的值。例如,我们可以使用msg.number从消息中访问数字值。
表1.1显示了读者可以在消息中使用的一些内置字段类型。
表1.1 内置字段类型
ROS提供了一组复杂且更结构化的消息文件,旨在满足特定应用程序的需求,例如交换常见几何信息(geometry_msgs)或传感器信息(sensor_msgs)。这些消息由不同的基本类型组成。一种特殊类型的ROS消息称为消息头。消息头可以携带时间、参考系(frame_id)以及序列号等信息。使用消息头,我们将得到编号的消息和哪个组件正在发送当前消息的清晰信息。消息头信息主要用于发送机器人关节变换等数据。以下是消息头的定义:
rosmsg命令工具可用于检查消息头和字段类型。以下命令有助于查看特定消息的消息头:
这将为读者提供与前面示例的消息头类似的输出。我们将在本章后面介绍rosmsg命令以及如何使用自定义消息。
ROS服务是ROS节点之间的一种请求/响应通信。一个节点会发送一个请求,并等待另一个节点的响应。
与使用.msg文件时的消息定义类似,我们必须在另一个名为.srv的文件中定义服务,.srv文件必须保存在包的srv子目录中。
服务描述格式示例如下:
上面部分是请求的消息类型,下面部分包含响应的消息类型,上下由---分隔。在示例中,请求和响应都是字符串类型的。
接下来我们将了解如何使用ROS服务。