一.ROS简介
1.1 简介
1.2 ROS的总体设计
1.3 ROS安装
1.4 ROS的系统实现
二.ROS的文件系统级
2.1 文件系统级的基本概念
2.2 文件系统级中的src目录详解
2.3 创建工作空间和功能包
三.ROS的计算图
计算图级体现的是进程与系统之间的通信,描述程序是如何运行的。
3.1 基本概念
3.2 详解Topic通信机制(适用数据传输,使用最为频繁)
3.3 详解Service通信机制(适用逻辑处理)
3.4 详解Parameter server通信机制
3.5 Action通信机制
四.开源社区
ROS(Robot Operating System)--- 机器人操作系统,它是一个用于编写机器人软件的灵活框架,它提供了类似操作系统所提供的功能,包括硬件抽象,底层设备控制,常用函数的实现,进程间消息传递,以及包管理,同时也提供用于获取、编译、编写、和跨计算机运行代码所需的工具和库函数。可以极大简化繁杂多样的机器人平台下的复杂任务创建与稳定行为控制。
ROS的前身是斯坦福大学人工智能实验室为了支持斯坦福智能机器人STAIR而建立的一个switchyard项目。ROS的正式诞生是在该实验室与机器人技术公司柳树车库(Willow Garage)合作的个人机器人项目中(Personal Robots Program),在2008年后全权由Willow Garage维护,2013年后移交给开源机器人基金会(OSFR)管理维护。在2010年,Willow Garage正式以开放源码的形式发布了ROS框架,并很快在机器人研究领域掀起了ROS开发与应用的热潮。在短短几年的时间里,ROS得到了广泛的应用,各大机器人平台几乎都支持ROS框架。
ROS的迅猛发展已经使它成为机器人领域的事实标准。
ROS的设计目标是提高机器人研发中的软件复用率,可以避免在机器人技术研发中重复“造轮子”,以达到简化、高效、直接的效果。从机器人的角度来看,那些人类微不足道的行为常常基于复杂的任务需求和环境影响,对于这些问题的处理具有极大的复杂度,单一的开发者、实验室或者研究机构都无法独立完成。ROS的出现就是为了鼓励更多的开发者、实验室或者研究机构共同协作来开发机器人软件。例如,一个拥有室内地图建模领域专家的实验室可能会开发并发布一个先进的地图建模系统;一个拥有导航方面专家的实验室可以使用建模完成的地图进行机器人导航;另一个专注于机器人视觉的组织可能开发出了一种物体识别的有效方法。ROS为这些组织提供了一种相互合作的高效方式,可以在已有成果的基础上继续自己工作的构建。所以ROS被设计为一种分布式结构,使得框架中的每个功能模块都可以被单独设计、编译,并且在运行时以松散耦合的方式结合在一起。而且ROS中的功能模块都封装于独立的功能包(package)或者元功能包(meta package)中,便于在社区中共享和分发。
ROS的核心---分布式网络,使用了基于TCP/IP的通信方式,实现了模块间点对点的松耦合链接,可以执行若干种类型的通信。总体来讲,ROS主要有五种特点:
(1)点对点设计
在ROS中,每个进程都以一个节点的形式运行,可以分布于多个不同的主机。节点间的通信消息通过一个带有发布和订 阅功能的RPC传输系统,从发布节点传输到接收节点。
(2)多语言支持
为了支持更多应用的移植和开发,ROS被设计为一种语言弱相关的框架结构。ROS使用简洁、中立的定义语言描述模块间的消息接口,在编译过程中再生成所使用语言的目标文件,为消息交互提供支持,同时也允许消息接口的嵌套使用。
(3)架构精简、集成度高
ROS框架具有的模块化特点使得每个功能节点可以进行单独编译,并且使用统一的消息接口让模块的移植、复用更加便捷。同时,ROS开源社区中移植、集成了大量已有开源项目中的代码,开发者可以使用丰富的资源实现机器人应用的快速开发。
(4)组件化工具包丰富
机器人开发往往需要一些友好的可视化工具和仿真软件,ROS采用组件化的方式将这些工具和软件集成到系统中并可以作为一个组件直接使用。例如,3D可视化工具Rviz(Robot Visualizer)和3D物理仿真平台Gazebo,前者强调把已有的数据可视化显示,后者强调的是创建一个虚拟的仿真环境。
Rviz
Gazebo:
(5)免费且开源
ROS遵循BSD许可
参考官网http://wiki.ros.org/cn/ROS/Installation
从系统实现的角度来看,ROS可以分为三个层次:文件系统、计算图和开源社区。
Package(功能包):
是ros中软件组织的基本形式,是构成ROS的基本单元,也是catkin编译的基本单元。一个package可以包含多个可执行文件(节点)。ROS应用程序是以功能包为单位开发的,功能包包括至少一个以上的节点或拥有用于运行其他功能包的节点的配置文件,还包含功能包所需的所有文件,如依赖库、数据集和配置文件等。
如何判断是一个package:在package文件下一定有CMakeList.txt和package.xml这两个文件。
CMakeList.txt规定了catkin编译的规则,即告诉编译系统如何编译在这个包下的代码,需要编译那些文件,需要那些依赖,生成那些目标文件等信息。具体的写法如下,系统会帮我们生成这个模板,我们只需更改就行。
package.xml文件定义了包的属性,如包名、版本号、作者、依赖等等(包的自我描述)。创建包的时候会提供一个写好的模板(如下)。通常我们需要修改的是build_depengd(会显示当前功能包安装之前必须先安装那些功能包)和run_depend(显示运行功能包代码所需的包)两个标记。
关于catkin编译系统,package.xml和CMakeList.txt文件可以看https://blog.csdn.net/weixin_41070687/article/details/82079308
Package manifest(功能包清单):
记录功能包的基本信息,包含作者信息、许可信息、依赖选项和编译标志等信息。包的清单由一个名为package.xml的文件管理。
Meta package(元功能包):
用于同一目的的功能包的集合。如导航功能包包含AMCL、DWA、EKF和map_server等10余个功能包。该功能包本身是一个“虚包”,只是依赖了若干个功能包,其txt文件中只是声明了其为元功能包,编译过程不会生成任何东西。只是一个功能包的集合。
Meta package manifest(元功能包清单):
类似于功能包清单,不同之处在于元功能包清单中可能会包含运行时所需要依赖的功能包或者声明一些引用的标签。
.msg(消息类型,对消息的描述):
消息是ROS节点之间发布/订阅的通信消息,可以使用ROS系统提供的消息类型,也可以使用.msg文件在功能包的msg文件夹下自定义需要的消息类型。
.srv(服务类型,对服务的描述):
服务类型定义了ROS服务器/客户端通信模型下的请求与应答数据类型,可以使用ROS系统提供的服务类型,也可以使用.srv文件在功能包的srv文件夹下自定义需要的服务类型.
src是我们真正编写代码的地方,在我们写完代码后catkin_make进行编译,build和devel会自动生成。
在这个src目录中放置了各类功能包。在前面提过package是catkin编译的基本单元,catkin的编译对象就是一个又一个的package。catkin编译系统在编译的时候会在src目录下递归的查找每一个package,因此可以将几个package放在同一个文件夹下(集合成元功能包)。
针对开头的示意图中的package4下面的各文件进行详细讨论:
CMakeList.txt和package.xml上面已经说明过。
scripts:防止可执行脚本文件,如python和shell等。
include/package_name:包含了我们所需要在包内使用的头文件和库。
src:存储C++源代码。
msg:包含自定义消息类型格式
srv:包含自定义服务类型格式
launch:存放launch文件(.launch或者.xml)。launch文件可帮助一次运行多个可执行文件。
config:这个是ROS包中保存的所有需要使用的配置文件。
创建工作空间:
工作空间就是一个包含功能包、可编辑源文件或编译包的文件夹
本人使用的是zsh终端,zsh是bash的增强版,它相比于bash更加的强大而且好用,尤其是命令补全。
具体配置可参考https://blog.csdn.net/weixin_41070687/article/details/83215785
ros常用命令https://blog.csdn.net/weixin_41070687/article/details/82014667
注:catkin_ws是工作空间名称(自行任意取名),使用mkdir命令创建工作空间时必须要同时在catkin_ws下创建一个src目录
下面是对catkin_make的一个解释:
在catkin_make之前必须要回到工作空间路径下。catkin_make是帮助我们初始化工作空间。在没有catkin之前,工作空间中只有src文件(源文件空间(source space),这是我们编写代码的地方,放置了各类功能包、程序源文件等)。在catkin之后,就会自动生成devel和build文件。
build文件夹是编译空间(build space),在build中,CMake和catkin为功能包和项目保存缓存信息、配置和其他中间文件。
devel文件夹是开发空间(development space),保存一些生成的目标文件、环境变量,如头文件、动态链接库、静态链接库和可执行文件等,这些都是编译后的程序,无需安装就能用来测试的程序。
但catkin_make的最主要功能其实不是初始化工作空间,而是编译。一般写完代码需要catkin_make一下,这样系统会帮助我们自动构建,生成我们需要的目标文件。
编译完成后,在devel文件夹中已经产生几个setup.*sh形式的环境变量设置脚本。使用source命令运行这些脚本文件,工作空间中的环境变量才可以生效。所以每次编译完之后必须刷新一下工作空间的环境,否则系统可能找不到工作空间,只有source之后系统才知道ROS可执行文件放在何处,之后才能运行。最好再使用echo命令直接追加到~/.zshrc文件之中,这样的话每次打开新的终端系统就会刷新工作空间环境,可以简化操作。
$source ~/catkin_ws/devel/setup.zsh #环境变量只能在当前终端中生效
$echo "source ~/catkin_ws/devel/setup.zsh" >> ~/.zshrc #环境变量在所有终端中有效
为了确保环境变量已经生效,可以使用如下命令进行检查:
$echo $ROS_PACKAGE_PATH
如果打印的路径中已经包含当前工作空间的路径,则说明环境变量设置成功。每个路径之间用冒号分隔开来
创建功能包:
一个package必须包含1个package.xml和1个CMakeList.txt文件
首先进入之前创建的工作空间的src目录下,使用catkin_create_pkg命令创建功能包
创建完成后,在代码空间src中会生成一个名为beginner_tutorials的包,这个包的依赖是std_msgs、roscpp和rospy。在创建这个包的同时还在这个包里面生成了package.xml和CMakeList.txt两个文件,这两个文件都已经自动包含了部分我们在执行catkin_create_pkg命令时提供的信息。
然后回到工作空间的根目录下进行编译,并且设置环境变量:
1.节点(Node):
执行运算任务的进程。在ROS系统中,节点是最小的进程单元。一个软件包里面可以有多个可执行文件,可执行文件在运行之后就成了一个进程(这个进程便是一个节点)。因此,从程序的角度来讲,节点是一个可执行文件(使用roscpp和rospy等ROS客户端库编写,能通过主题、服务或参数服务器与其他节点进行通信);从功能的角度来讲,通常一个节点负责某一个单独的功能。整个ROS系统就是由很多个节点组成的,也可称节点为“软件模块”。
节点概念的引入使得基于ROS的系统在运行时更加形象:当许多个节点同时运行时,可以很方便的将端对端的通信绘制成节点关系图(开头的"一个简单的ROS计算图"), 在这个图中进程就是图中的节点,而端对端的连接关系就是节点之间的连线。
2.节点管理器(Node Master):
控制中心,是“管家”身份。节点管理器通过远程过程调用(RPC)提供登记列表和对其他计算图表的查找功能,帮助ROS节点之间互相查找、建立连接,同时还为系统提供参数服务器,管理全局参数。
3.消息(Message):
节点之间最重要的通信机制就是基于发布/订阅模型的消息通信。每一个消息都是严格的数据结构,支持标准数据类型(整型、浮点型、布尔型等),也支持嵌套结构和数组(类似C语言中的结构体),还可以根据需求由开发者自主定义。消息包含一个节点发送到其他节点的数据信息,节点是通过消息实现彼此的逻辑联系与数据交换。
4.话题(Topic):
单向异步通信机制,传输消息(Message)。在这种机制中,Message以一种发布/订阅的方式进行传递(Publish-Subscribe)。因为每个Topic的消息类型都是强类型,发布到其上的Message都必须与Topic的ROS消息类型匹配,而且节点只能接收类型匹配的消息。 “单向”:数据只能从发布者传输到订阅者,如果订阅者需要传输数据则需要另外开辟一个Topic进行数据传输。“异步”:对接收者来讲,其订阅Topic,只要Message从Topic过来就接收并进行处理,不管是谁发布的。对于发布者而言,只管发布Message到Topic,不管有没有接收者接收Message,也不需要等待接收者的处理反馈。
ROS中的每条消息都使用名为话题的命名总线进行传输。当节点通过话题发布消息时,我们可以说节点正在发布一个话题。当节点通过话题接收消息时,我们可以说节点订阅一个话题。发布节点和订阅节点不知道彼此的存在,甚至还可以订阅一个没有任何发布者的话题。简而言之,信息的生产和消费是分离的。每个话题都有一个唯一的名称,任何节点都可以访问这个话题并通过它发送数据,只要他们有正确的消息类型。系统中可能同时有多个节点发布或者订阅同一个话题的消息。
5.服务(Service):
双向同步通信机制,ROS中称其为“服务”,传输请求/应答数据,是一个request-reply模型。“双向”:这种机制不仅可以发送消息,还存在反馈。“同步”:在Client发送请求后,它会在原地等待反馈,只有当Server接收处理完请求并完成response反馈,Client才会继续执行。Client等待过程是处于阻塞状态的通信。与话题不同的是,ROS中只允许有一个节点提供指定命名的服务。
在一些应用中,如果需要一个请求/响应交互,仅有发布/订阅模型是无法实现的。发布/订阅模型是一种单向传输系统,当我们使用分布式系统时,我们可能需要一个请求/响应类型的交互,这种情况下我们可以使用ROS服务(双向传输系统)。可以定义包含两个部分的服务定义:一个是请求,另一个是响应。使用ROS服务,我们可以编写服务器节点和客户端节点。服务器节点以名称提供服务,当客户端节点向该服务器发送请求消息时,它将响应并将结果发送给客户端,客户端在此过程需要等待服务器响应。
6.参数服务器(Parameter Server):
参数服务器能够是数据通过通过关键词存储在一个系统的核心位置(节点管理器)。通过使用参数就能够在运行时配置节点或改变节点的工作任务。
7.消息记录包(Bag)
用于记录和回放ROS消息数据的文件格式,保存在.bag文件中。Bag是一种用于存储数据的重要机制,它可以获取并且记录各种难以收集的传感器数据,程序可以通过Bag反复获取实验数据。常用于调试算法。
Topic通信机制是一种单向的异步通信机制,此机制中Message以一种发布/订阅(Publish-Subscribe)的方式进行传递。
*每个Topic都是强类型,发布到其上的Message必须与Topic的ROS消息类型相匹配且节点只接收类型匹配的消息
*一个节点可在一个给定的主题中发布消息,一个节点针可对某Topic关注与订阅特定类型的数据,也可多个节点同时发布或订阅同一个话题的消息。
*Publisher和Subscriber之间无需知晓对方的存在
“异步”:
对于接受者而言(订阅Topic),只要有Message从订阅的Topic过来就接收并进行处理,不管Message是谁发的。
对于发布者而言(发布Message到Topic),不论有没有接收者订阅该Topic来接收Message,也不需等待接收者的处理反馈,只管发布发布Message到Topic。
(一)Talker注册。启动Talker,在启动时,Talker通过端口将其信息注册到Master端,其中包括Talker所发布消息的话题名、节点地址信息等。Master将这些信息加入到一个注册列表中。
(二)Listener注册。启动Listener,Listener向Master端注册,注册其所需订阅的话题以及Listener自己的地址信息。
(三)ROS Master进行信息匹配。Master根据Listener的订阅信息从注册列表中进行查找,如果没有找到匹配的发布者,则等待发布者的加入。如果找到匹配的发布者信息,则把Talker的地址发送给Listener。
(四)Listener发送连接请求。Listener接收到Master发送的Talker地址后,向Talker发送连接请求,同时将Listener要订阅的话题名、消息类型和通信协议(TCP/UDP)全发给Talker。
(五)Talker发送连接请求。Talker接收到Listener请求后,返还一个确认连接的信息,包括其自身的TCP地址。
(六)Listener尝试与Talker建立网络连接。Listener接收到Talker的TCP地址后,通过TCP与Talker建立网络连接。
(七)Talker向Listener发布数据。Talker通过建立的TCP网络连接将话题消息数据发送给Listener。
1-5是使用RPC通信协议,6-7是TCP通信协议,通过4、5、6三步建立起Publish-Subscribe的网络连接。
远程过程调用(Remote Procedure Call ,RPC),可以简单通俗的理解为在一个进程里调用另一个进程的函数。
Service通信机制是一种双向的同步通信机制,此机制中节点间通过request-reply的方式进行通信。
“双向”:不仅可以发送消息,同时还会有反馈。
“异步”:Node A在发布请求后会在原地等待reply,直到Node B处理完了请求并且完成了reply,Node A才会继续执行。Node A等待过程中是处于阻塞状态的通信。(这种通信模型没有频繁的消息传递,没有冲突与高系统资源的占用,只有接受请求才执行服务)
Service包含两个部分:请求方(Client)和应答方(Server)。Node B是server(应答方),提供一个服务的接口,叫做/service,我们一般都会用string类型来指定service的名称,类似于Topic。请求方Node A发送一个request,请求调用服务,然后等待Node B接收并进行处理,Node B处理完之后反馈回一个reply。
(一)Talker注册。启动Talker,通过1234端口使用RPC向ROS Master注册发布者的信息,包括所提供的服务名。ROS Master会将节点的注册信息加入注册列表中。
(二)Listener注册。启动Listener,同样使用RPC向ROS Master注册订阅者的信息,包括所需要查找的服务名。
(三)ROS Master进行信息匹配。Master根据Listener的订阅信息从注册列表中进行查找,如果没有找到匹配的服务提供者,则等待该服务的提供者加入;如果找到匹配的服务提供者信息,则通过RPC向Listener发送Talker的TCP地址信息。
(四)Listener与Talker建立网络连接。Listener接收到确认信息后,使用TCP尝试与Talker建立网络连接,并且发送服务的请求数据。
(五)Talker向Listener发布服务应答数据。Talker接收到服务请求和参数后,开始执行服务功能,执行完后,向Listener发送应答数据。
话题与服务的区别:
参数服务器通信方式与上述两种不同,它是一种特殊的通信方式。特殊点在于参数服务器是节点存储参数的地方、用于配置参数,全局共享参数。参数服务器是通过互联网传输(不涉及TCP/UDP),在节点管理器中运行,实现整个通信过程。
参数服务器维护着一个数据字典,字典里面存储着各种参数和配置。
字典就是一个一个的键值对,每一个键值Key不重复且每一个Key对应着一个值value。也可以说字典是一种映射关系。在实际项目的应用中,由于字典的这种静态的映射特点,我们往往将一些不常用到的参数和配置放入到参数服务器里面的字典中,这样对这些数据进行读写都将高效方便。
(一)Talker设置变量。Talker使用RPC向ROS Master发送参数设置数据,包含参数名和参数值;ROS Master会将参数名和参数值保存到参数值列表中。
(二)Listener查询参数值。Listener通过RPC向ROS Master发送参数查找请求,包含所要查找的参数名。
(三)ROS Master 向Listener发送参数值。Master根据Listener的查找请求从参数列表中进行查找,查找到参数后,使用RPC将参数值发送给Listener。
注:如果Talker向Master更新参数值,Listener在不重新查询参数值的情况下是无法知晓参数值已经被更新的。因此在许多应用场景中,需要一种动态参数更新的机制(可使用参数动态配置工具---rqt_reconfigure)
维护方式:
1.命令行维护
主要是使用rosparam语句进行操作各种命令。
2.launch文件内读写
launch文件内有很多标签(遵循XML格式),与参数服务器相关的标签只有两个,一个是,另一个是
3.node源码
修改ROS源码,即利用API来对参数服务器进行操作。
Actionlib是ROS很重要的一个库,类似于Service通信机制,actionlib也是一种请求响应机制的通信方式。actionlib主要弥补了service通信的一个不足,就是当执行一个长时间的任务时,假如利用service通信方式,那么publisher会很长时间接收不到反馈的reply,致使通信受阻。当service通信不能很好的完成任务时候,actionlib则可以比较合适实现长时间的通信过程,actionlib通信过程可以随时被查看过程进度,也可终止请求。
Action的工作原理是client-server模式,也是一个双向的通信模式。通信双方在ROS Action Protocol下通过消息进行数据的交流通信。client和server为用户提供一个简单的API来请求目标(在客户端)或通过函数调用和回调来执行目标(在服务器端)。
客户端会向服务器发送目标指令和取消动作指令,而服务器则可以给客户端发送实时的状态信息,结果信息,反馈信息等等,从而完成了service无法做到的部分。