购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.1 ROS框架

2.1.1 ROS简介

机器人操作系统的发展与电子计算机操作系统的发展十分类似。早期的计算机没有操作系统,开发人员需要直接面对硬件,并且各个硬件厂商的产品可能提供了不同的接口和使用方法,给开发人员带来了很多麻烦和重复性工作。而操作系统出现后,每一种操作系统都有自己的驱动程序模型,硬件厂商只需要按照驱动模型开发驱动程序,用户使用计算机时不必过于关心底层细节。

目前智能机器人研发领域也期望有类似的研发过程:如果每个设备厂商为某个“通用机器人平台”开发相应的支持软件,研发人员通过简单的配置和适配开发就能让它们协调工作,从而可以把更多的时间投入到应用设计与开发之中。同时,机器人软件研发也存在很多共性问题,比如易用性、开发效率、跨平台、多编程语言、分布式部署、代码可重用,等等。随着机器人领域的快速发展和复杂化,智能机器人的各项能力正在日趋完善,为智能机器人编写软件也变得越来越复杂繁重。

针对这些问题的解决需求,机器人操作系统应运而生。2010年Willow Garage公司发布了开源机器人操作系统ROS,很快就在机器人研究领域掀起了学习和使用ROS的热潮。

与Windows、Linux等传统意义上的计算机操作系统不同,机器人操作系统(ROS)并不具体负责计算机进程管理与调度。实际上它是一系列运行在上述计算机操作系统核心上,面向机器人特点的运行支撑软件和软件工具集。例如,ROS通过提供一种软件点对点通信机制,使得开发人员可以高效灵活地组织机器人软件模块。目前通过开发者的不断努力,ROS的功能包集合已经非常丰富,所支持的机器人种类也越来越多。

ROS是用于机器人的一种开源的“后操作系统”,或者说次级操作系统。它提供了类似于操作系统所提供的功能,包含硬件抽象描述、设备管理与控制、通用功能实现、程序间的消息传递、程序发行包管理等,它也提供了一些工具程序和函数库用于获取、建立、编写和运行机器人程序。

ROS的主要设计目标是便于机器人研发过程中的代码复用。因此ROS采用了一种分布式架构,各个软构件可以各自独立地设计,松散、即时地组合起来。并可以按照功能包和功能包集的方式分组,因而可以更容易地分享和发布。

ROS的运行架构是一种基于Socket网络连接的松耦合架构。在ROS的架构中,一切可执行的程序被抽象为节点(node),它可以是传感器数据采集程序、执行器控制程序、规划算法程序、视觉识别程序,等等。各个节点之间均使用ROS提供的消息传递机制进行通信。ROS支持多种类型的通信,包括基于服务的同步RPC通信、基于Topic的异步数据流通信及参数服务器上的数据存储等。

作为一个开放源代码软件系统,ROS的宗旨是构建一个能够整合不同研究成果,实现算法发布、代码重用的通用机器人软件平台。由于这些功能可满足广大开发者的需求,因此,ROS得到了广泛应用。不少智能机器人研发者在ROS的基础上开发了许多如运动规划、定位导航、仿真、感知等高层功能软件包,使得这一软件平台的功能更加丰富,发展更加迅速。目前,ROS1.0已经发行多个版本,同时ROS2.0也已经发行了。如今使用ROS进行软件开发的智能机器人已多达上百种,其范围涵盖机械手、类人机器人、平面移动机器人、无人驾驶汽车和无人飞行器等热点领域,而且大部分传感器在ROS上都得到了较好的支持。基于ROS开发的应用程序更是多达2000余种,涵盖了模拟仿真、硬件驱动、环境感知、运动控制等各个方面。ROS已经逐步成为智能机器人研发领域的通用性软件平台。

ROS具有如下主要特点。

1)分布式架构:ROS将每个工作进程都看作一个节点,使用节点管理器进行统一管理,并提供了一套消息传递机制。这种架构可以分散由计算机视觉和语音识别等CPU密集型任务带来的实时计算压力,也能够适应多机器人系统遇到的挑战。基于套接字通信的大量采用,ROS具备分布式计算的实现能力。在任何具备网络连接的主机上都可运行节点程序,这些主机可以是小型的ARM嵌入式系统,或者是具备强大运算能力的基站服务器,甚至是基于Android系统的移动手机或平板电脑。这些异构计算平台均可成为智能机器人系统的一部分。

2)多语言支持:由于所有节点的通信都是通过网络套接字来实现的,这意味着只要能够提供套接字接口,节点程序可以用任何编程语言来实现。ROS不依赖特定的编程语言,它目前已经支持多种现代编程语言,如C++、Python和Lisp已经在ROS中得到广泛应用,Java的测试性支持也已经实现。ROS采用了一种独立于编程语言的接口定义语言(IDL),并实现了多种编程语言对IDL的封装,使得各个不同编程语言编写的“节点”之间也能透明地进行消息传递。

3)良好的可伸缩性:使用ROS进行机器人研发,既可以简单地编写一两个节点单独运行,又可以通过rospack、roslaunch将很多个节点组织成一个更大的工程,指定它们之间的依赖关系及运行时的组织形式。

4)源码开放:ROS遵循BSD协议,实现源码开放,对个人、商业应用及修改完全免费,这也是使其具有更强生命力的主要原因之一。

2.1.2 ROS整体架构分析

ROS系统架构主要被设计划分为三个级别,如图2-1所示。

·文件系统级(Filesystem level),用于描述可以在硬盘上查到的代码及可执行程序。

·计算图级(Computation Graph level),体现的是进程与进程、进程与系统之间的通信。

·开源社区级(Community level),主要包括在开发人员之间如何共享知识、算法和代码。

图2-1 ROS系统架构

1. 文件系统级

ROS中有众多的抽象节点及消息、服务、工具和库文件,需要采用有效的结构管理这些代码。一个ROS程序的不同构件被放在不同的文件夹下,这些文件夹是根据功能的不同来对文件进行组织的。

ROS的软件是以Package(功能包)的方式进行组织的。ROS系统由众多的功能包组成,每个功能包中可能包含多个节点的可执行文件、消息接口定义文件、RPC服务接口定义文件及库文件等。此外还包含一个功能包清单,如图2-2所示。

功能包之间可以配置依赖关系。如果设定了功能包A依赖功能包B,那么ROS在构建系统时,B一定要早于A构建,并且在编译A时,自动配置环境,使得A可以使用B中的头文件和库文件。

(1)功能包集(Stack)

将一些具有某些相关功能的功能包组织在一起,就是一个功能包集。在ROS中存在大量的不同用途的功能包集,如导航功能包集navigation、机械臂运动控制功能包集MoveIt。

图2-2 ROS文件系统级

功能包集必须包含三个文件:CMakeList.txt、Makefile和stack.xml。如果在文件夹下见到stack.xml,那么可以确定这是一个功能包集。

(2)功能包(Package)

功能包是ROS中软件组织的基本形式。创建ROS程序时,功能包具有最小的结构和最少的内容,它可以包含ROS运行的进程(节点)、配置文件等。

当提到功能包时,一般指的是一种特定的文件结构和文件夹组合。这种结构具体如下所示。

·bin/:编译和链接程序后,用于存储可执行文件的文件夹。

·include/package_name/:此目录包含了所需库的头文件。请记住导出功能包清单,因为它们还会被其他功能包所使用。

·msg/:程序开发者开发的非标准消息类型。

·scripts/:包括bash、Python或任何其他脚本的可执行脚本文件。

·src/:程序源文件,可以为节点创建一个文件夹,或者按照希望的方式组织它。

·srv/:程序开发者开发的非标准服务。

·CMakeLists.txt:CMake的生成文件。

·manifest.xml/package.xml:功能包清单文件,其必须包含在功能包中,用来说明此功能包相关的各类信息。如果你发现某个文件夹内包含了此文件,那么这个文件夹很可能是一个功能包。

(3)功能包清单(Manifest)

功能包清单提供关于功能包、许可信息、依赖关系、编译标志等的信息。功能包清单是一个manifests.xml/package.xml文件,通过这个文件能够实现对功能包的管理。打开一个功能包清单文件,可以看到包的名称、依赖关系等信息。功能包清单的作用就是为了更容易地安装和分发这些功能包。

(4)消息类型(Message/msg type)

消息是ROS数据传递的基本元素,消息类型需要用ROS的消息定义语言进行描述。每个功能包的msg文件夹中,都定义了这个功能包需要的消息类型。此外,如果该功能包依赖另外一个功能包,则该功能包可以使用另一功能包的所有消息类型。

ROS使用了一种简化的消息类型描述语言来描述ROS节点发布的数据值。通过这样的描述语言,ROS能够使用多种编程语言生成不同消息类型的代码。

ROS提供了很多预定义的消息类型。如果你创建了一种新型消息类型,那么就要把消息类型的定义放到功能包的msg文件夹下。该文件夹中包含了用于定义各种消息的文件,这些文件都以.msg为扩展名。

(5)服务类型(Service/srv type)

ROS使用了一种简化的服务描述语言来描述ROS的服务类型。这直接借鉴了ROS消息的数据格式,以实现节点之间的请求/响应通信。服务的描述存储在功能包的srv子目录下扩展名为.srv的文件中。

若要调用服务,调用者需要使用该服务功能包的名称及服务名称。例如,对于sample_package1/srv/sample1.srv文件,可以将它称为sample_package1/sample1服务。

ROS中有查看某些功能包名称与服务的相关工具。例如,rossrv工具能输出服务说明.srv文件所在的功能包名称,并可以找到使用某一服务类型的源代码文件。如果要在ROS中创建一个服务,可以使用服务生成器。这些工具能够从基本的服务说明中生成代码,只需要在CMakeLists.txt文件中加一行gensrv()命令即可。

2. 计算图级

ROS能够创建一个连接所有进程的抽象“网络”,该网络是进程(节点)之间通过主题或服务的连接所形成的。系统中的任何节点都可以访问此网络,并通过该网络与其他节点进行交互,获取其他节点发布的消息,并将自身数据发布到网络上。

在这一层级中最基本的概念实体包括节点、节点管理器、参数服务器、消息、服务、主题和消息记录包,如图2-3所示,它们均以不同的方式向计算图级提供数据。

图2-3 ROS计算图级

(1)节点(Node)

节点是主要的计算执行进程。如果想要有一个可以与其他节点进行交互的进程,那么需要创建一个节点,并将此节点连接到ROS网络中。通常情况下,系统包含能够实现不同功能的多个节点。最好让每一个节点都具有特定的单一功能,而不是在系统中创建一个包罗万象的“大节点”。

节点都是各自独立的可执行文件,并能够通过主题、服务或参数服务器与其他节点进行通信。ROS通过使用节点概念将代码和功能解耦,提高了系统的容错能力和可维护性,使系统设计得以简化。同时,节点允许ROS能够布置在任意机器上并同时运行。

节点在系统中必须有唯一的名称,以便节点使用特定名称与其他节点进行通信而不产生歧义。节点可以使用不同的库进行编写,如roscpp和rospy,roscpp基于C++,rospy基于Python。

ROS是由很多节点组成的。在这里节点实际上是“软构件”。ROS使用节点使得基于ROS的系统在运行时更加形象化:当许多节点同时运行时,可以方便地使用rqt_graph工具将节点与节点之间的通信绘制成一个图表,其中进程就是图中的节点,节点间的消息连接关系就是其中的弧线连接,如图2-4所示。

图2-4 ROS节点示意

ROS提供了处理节点的工具,如rosnode是一个用于显示节点信息的命令行工具,支持的主要命令具体如下。

·rosnode info node:输出当前节点的信息。

·rosnode kill node:结束当前运行的节点进程。

·rosnode list:列出当前活动的节点。

·rosnode machine hostname:列出某一特定计算机上运行的节点或列出主机名称。

·rosnode ping node:测试节点间的连通性。

·rosnode cleanup:将无法访问节点的注册信息清除。

ROS节点的一个强大功能是在启动该节点时更改参数,此功能使我们能够改变节点、主题和参数的名称。我们无需重新编译代码就能重新配置节点,这样就可以在不同的场景中使用该节点。

以下为一个改变主题名称的示例:

$ rosrun book_tutorials tutorialX topic1:=/level1/topic1

此命令将主题名称从topic1改为/level1/topic1。也许你现在还不明白其作用,但在以后的应用中你会发现它的实用性。

更改节点中的参数与更改主题名称很类似。只需要在参数名称前添加一个下划线,例如:$rosrun book_tutorials tutorialX_param:=9.0。但需要注意的是,不能使用系统保留关键字的名称,具体如下。

·__name:为节点名称保留的一个特殊关键字。

·__log:为记录节点日志存储地址保留的一个关键字。

·__ip__hostname:表示ROS_IP和ROS_HOSTNAME的关键字。

·_master:表示ROS_MASTER_URI的关键字。

·_ns:表示ROS_NAMESPACE的关键字。

(2)节点管理器(Master)

节点管理器用于主题、服务名称的注册和查找等。如果在整个ROS中没有节点管理器,就不会有节点间的通信。需要注意的是,由于ROS本身就是一个分布式网络系统,可以在某一台计算机上运行节点管理器,在其他计算机上运行由该管理器管理的节点。节点管理器通常使用roscore命令运行,它会加载ROS节点管理器及其他ROS核心构件。同时,节点管理器还提供了参数服务器。

(3)参数服务器(Parameter Server)

参数服务器是可通过网络访问的共享的多变量字典,通过关键字存储在节点管理器上。节点使用此服务器存储和检索运行时的参数,还可以改变节点的工作任务。

参数服务器使用XMLRPC实现,并运行在ROS节点管理器上。这意味着其API可通过通用的XMLRPC库进行访问。

ROS中关于参数服务器的工具是rosparam,其支持的参数具体如下。

·rosparam list:列出参数服务器中的所有参数。

·rosparam get parameter:获取参数值。

·rosparam set parameter value:设置参数值。

·rosparam delete parameter:删除参数。

·rosparam dump file:将参数服务器保存到一个文件中。

·rosparam load file:加载参数文件到参数服务器。

(4)消息(Message)

节点可通过消息实现彼此的逻辑联系与数据交换。消息包含一个节点发送到其他节点的数据信息。消息具有多种标准类型,同时用户也可以基于标准消息开发自定义类型的消息。

ROS使用命令行工具rosmsg来获取有关消息的信息,主要参数具体如下。

·rosmsg show:显示一条消息的字段。

·rosmsg list:列出所有消息。

·rosmsg package:列出功能包中的所有消息。

·rosmsg packages:列出所有具有该消息的功能包。

·rosmsg users:搜索使用该消息类型的代码文件。

·rosmsg md5:显示一条消息的MD5检验值。

(5)主题(Topic)

主题是由ROS网络对消息进行路由和消息管理的“数据总线”。每一条消息都要发布到相应的主题上。当一个节点发送数据时,就说该节点正在向主题发布消息。节点可以通过订阅某个主题,接收来自其他节点的消息。节点可以订阅任何节点发布的主题,而不需要了解向该主题发送消息的节点。这就保证了消息的发布者和订阅者之间相互解耦,完全无需知晓对方的存在。主题的名称必须具有唯一性,否则在同名主题之间的消息路由就会发生错误。

每一个主题都是强类型的,发布到主题上的消息必须与主题的ROS消息类型相匹配,并且节点只能接收类型匹配的消息。一个节点要订阅一个主题,相关者必须具有相同的消息类型。

ROS的主题消息可以使用TCP/IP或UDP传输。基于TCP传输称为TCPROS,它使用TCP/IP长连接,这是ROS默认的传输方式。基于UDP传输称为UDPROS,它是一种低延迟、高效率的传输方式,但可能产生数据丢失,所以它适合于远程操控任务。

ROS提供了rostopic命令行工具用于主题操作,允许获取主题的相关信息或直接在网络上发布数据。此工具的参数具体如下。

·rostopic bw/topic:显示主题所使用的带宽。

·rostopic echo/topic:将主题对应的消息输出到屏幕。

·rostopic find message_type:按照类型查找主题。

·rostopic hz/topic:显示主题的发布频率。

·rostopic info/topic:输出关于该主题的信息。

·rostopic list:输出活动主题列表。

·rostopic pub/topic type args:将数据发布到主题。它允许我们直接从命令行中对任意主题创建和发布数据。

·rostopic type/topic:输出主题的类型,或者说主题中发布的消息类型。

(6)服务(Service)

服务用于请求应答模型,也必须有一个唯一的名称。当一个节点提供某个服务时,所有的节点都可以通过使用ROS客户端库所编写的代码与之通信。

ROS关于服务的两个命令行工具是rossrv和rosservice。可以通过rossrv看到有关服务数据结构的信息,并且与rosmsg具有完全一致的用法;通过rosservice可以列出服务列表和查询某个服务。其所支持的命令具体如下。

·rosservice call/service args:根据命令行参数调用服务。

·rosservice find msg-type:根据服务类型查询服务。

·rosservice info/service:输出服务信息。

·rosservice list:输出活动服务列表。

·rosservice type/service:输出服务类型。

·rosservice uri/service:输出服务的ROSRPCURI。

(7)消息记录包(Bag)

消息记录包是一种用于保存和回放ROS消息数据的文件格式,保存在.bag文件中。消息记录包是一种用于存储数据的重要机制,它能够获取并记录各种难以收集的传感器数据。程序可以通过消息记录包反复获取实验数据,以进行必要的开发和算法测试。在使用复杂机器人进行实验工作时,需要经常使用消息记录包。

消息记录包文件可以像实时会话一样在ROS中再现情景,在相同时间内向主题发送相同的数据。通常情况下,开发者可以使用此功能来调试算法。若要使用记录包文件,则可以使用以下ROS工具。

·rosbag:用来录制、播放和执行其他操作。

·rxbag:用于可视化图形环境中的数据。

·rostopic:用于查看节点发送的主题。

3. 开源社区级

ROS开源社区级的概念主要用于ROS资源管理,其能够通过独立的网络社区分享软件和知识。这些资源具体如下。

·发行版(Distribution):ROS发行版是可以独立安装、带有版本号的一系列功能包集。ROS发行版像Linux发行版一样可发挥类似的作用。这使得ROS软件安装更加容易,而且能够通过一个软件集合来维持一致的版本。

·软件源(Repositorie):ROS依赖于共享代码与软件源的网站或主机服务,在这里不同的机构都能够发布和分享各自的机器人软件和程序。

·ROS Wiki:ROS Wiki是用于记录有关ROS系统信息的主要论坛。任何人都可以注册账户和贡献自己的文件、提供更正或更新、编写教程及其他信息。

·邮件列表(Mailing list):ROS用户邮件列表是关于ROS的主要交流渠道,能够交流从ROS软件更新到ROS软件使用中的各种疑惑或信息。

2.1.3 名称系统

当构建一个规模较大且结构复杂的智能机器人系统时,ROS框架通过名称来处理和提取复杂的信息。因此名称在ROS中具有非常重要的作用:节点、主题、服务和参数均有各自的名称。每一个客户端库都支持名称的命令行再映射,这意味着一个编译过的程序可以在运行时被重新构建,以便于其能够在不同的图级拓扑结构中操作。

1. 计算图资源名称

计算图资源名称提供了分层命名结构,用于在ROS中计算图中的所有“资源”,如节点、参数、主题和服务。计算图资源名称的机制在ROS中非常有用,对于构建复杂的机器人系统有很大的帮助。

以下是一些计算图资源名称的具体实例。

·/foo

·/nwpu/robot/name

·/ur5/node1

计算图资源名称提供了封装作用。每一个资源被定义在一个命名空间内,该资源可以与其他资源共享。一般来说,资源可以在它们的命名空间内被创建,它们在自己的命名空间内或上一级命名空间内连接资源。连接可以在不同的命名空间的资源之间进行,不过这通常需要编写一段代码来实现。这种封装分离了系统的不同部分,从而避免了因为偶然的名称错误或全局的“名称劫持”而导致出现不期望的结果。

资源名称的解析可以是相对的,所以资源并不一定需要知道它们在哪个命名空间内。这样可以简化节点的编写,在编写每个节点时可以假设它们就在根命名空间内。当将这样编写的节点集成到更大的系统中时,它们可以被放到另一个指定的命名空间内。

例如,有两个开发者A和B,合作开发一个智能机器人的软件系统。A开发的数个节点与B开发的数个节点中有一个节点名字重复(如/Camera_node),如果要将A与B的成果部署到同一台智能机器人上,那么只需将A、B的节点放入不同的命名空间内,即可区分同名的节点。如:

/DeveloperA/Camera_node
/DeveloperB/Camera_node

此外,这种机制也在很大程度上增强了ROS的可复用性。例如,我们为一个双目摄像头开发了一个图像采集节点,该节点发布了两个主题:/Camera_Left与/Camera_Right。若智能机器人需要安装两台这种摄像头同时工作,这时可以在两个不同的命名空间(例如CamA、CamB)内分别运行相同的节点,这样该节点发布的主题也在不同的命名空间内,如:

摄像头A:/CamA/Camera_Left与/CamA/Camera_Right

摄像头B:/CamB/Camera_Left与/CamB/Camera_Right

2. 名称的有效性

在ROS中,一个有效的资源名称应该具有如下特征。

·第一个字符是字母、波浪号或斜线。

·后续字符可以是字母、数字、下划线或斜线。

“基本名称”中不能有波浪号或斜线。

3. 名称的解析

ROS包含了4类型的计算图资源名称:基本名称、相对名称、全局名称和私有名称,其语法分别如下。

·基本名称:base

·相对名称:relative/name

·全局名称:/global/name

·私有名称:~private/name

默认情况下,名称解析是相对命名空间进行的。如节点/ur5/node1的命名空间为/ur5,因此若该节点使用了“res”资源,那么该名称实际上被解析为/ur5/res。

没有命名空间修饰符的名称都是基本名称。基本名称实际上是一种特殊的相对名称,因此具有相同的解析规则。基本名称用得最多的场合是用来初始化节点名称。

以斜线(/)开头的名称是全局名称,全局名称是被完整解析的。全局名称在一定程度上限制了代码的可移植性,所以应当尽量避免使用。

以波浪号(~)开头的名称是私有名称。私有名称把节点名称转换为一个命名空间。例如,若节点/ur5/node1中使用了“~res”资源,那么该名称实际上是被解析为/ur5/node1/res。 I4HEQIR1BbjChlnKaUiIL0qXSKOPGrUqBHWIHp6KuG/nQzsyCeJtuKyugo6v6oTS

点击中间区域
呼出菜单
上一章
目录
下一章
×