一、Master和Node

ROS的应用场景是很复杂的机器人,机器人中不仅部件复杂,而且各个部件之间的沟通也是十分重要的一部分,因此ROS引入了Master作为总管家。

首先前面提到过,ROS中每个进程都称之为一个节点,节点之间的通信、节点的注册管理都需要经过Master这个管家来管理,所有的节点通信都是由Master管理的,在ROS程序启动的时候,第一步就是先启动Master,之后由节点管理器处理依次启动节点。
启动Master需要使用roscore指令,该指令除了启动Master,还会一并启动rosout和parameter server,前者主要负责日志输出,后者则是参数服务器。

启动Master之后,就可以根据需要启动不同的节点Node,节点是ROS中的进程,也是package里面可执行文件运行的示例,也就是说package里面的可执行文件是静态的,而node是动态的概念,这一点很像程序和进程之间的关系。有了Node之后,ROS中各个节点就可以各司其职,只负责自己的任务,而沟通之类的任务完全就丢给了Master。

这里关于Master的职责其实和一开始理解的有所偏差,查看ROS官方的文档,文档中写的是:“The role of the Master is to enable individual ROS nodes to locate one another”,也就是说Master主要负责的是让节点能够找到彼此,而不是万事通,结合课本上的Topic和Service的工作流程,Master主要还是对节点的管理,节点启动时的注册、加入Topic、Service时提供想要加入的对象的地址从而让其建立连接,仅此而已,而对于具体的数据传输,Master并不参与,连接建立后即使关掉也不影响节点的通信,只不过没法再建立新的连接。

启动Node主要是使用rosrun指令,利用rosrun+包名+节点名来启动一个节点。对Node的管理则使用rosnode指令,可以利用rosnode list指令列出当前运行的node信息,可以利用rosnode info 节点名显示某个node的详细信息,利用rosnode kill 节点名结束某个node。

ros2 节点启动时如何带上namespace_异步通信


当需要一次性启动多个node的时候,显然可以使用rosrun来一个一个启动,但更加节省时间的方式是用roslaunch+包名+launch文件名,利用launch文件,直接启动多个Master和node。这里其实隐含了一点,ROS程序启动时,并不一定必须先使用roscore指令,也可以先使用roslaunch指令,在roslaunch指令内部启动Master。

launch文件的一些基本写法如下:

ros2 节点启动时如何带上namespace_数据_02

二、Topic和Msg

Topic是ROS中的异步通信方式,节点之间通过订阅发布话题的机制实现通信,是ROS中最常用的一种通信方式。Topic要经历下面几步的初始化过程:首先,publisher节点和subscriber节点都要到节点管理器进行注册,注册的部分在节点运行的时候就汇报给Master了,然后publisher会发布topic,subscriber在Master的指挥下会订阅该topic,从而建立起sub-pub之间的通信。也就是说topic的订阅管理是交给Master的,在Master的指导下topic双方建立连接,之后Master就放心离开,直到有新的节点想要加入topic。

整个过程的灵魂在于这种订阅机制,注册过的节点并不是向其余节点进行订阅或者发布topic的请求,而是交给Master统一管理,节点的连接建立之后,即使关掉Master也不会影响数据的传输,但是其它的节点也无法再加入topic。这种Topic机制本身是一种异步通信,发送时调用publish方法,发送完成后不等待直接返回,也就是说发布者不关心收没收到。一个Topic可以被多个节点同时发布,也可以同时被多个节点接收。同一个Topic可以同时有多个subscribers,也可以同时有多个publishers。

可以使用下面的指令对Topic进行管理:

ros2 节点启动时如何带上namespace_数据_03


Topic内容的数据类型就是Message,也可以说是topic内容的格式标准。严格扣定义的话,收发的内容并不是Message,收发内容的格式才是Message,基本的msg包括bool、int8、int16、int32、int64(以及uint)、float、float64、string、time、duration、header、可变长数组array[]、固定长度数组array[C]。

这里可以借鉴类和对象的关系,可以将msg理解为一个类,这个类规定了一条信息内部的格式,而发送的内容是对象,就是这个类的一个实例化。从下面的代码就可以看出,本身msg的格式就像是结构体,定义了一条信息的格式。

std_msg/Header header
    uint32    seq
    time    stamp
    string    frame_id
uint32    height
uint32    width
string    encoding
uint8    is_bigendian
uint32    step
uint8[]    data

对topic的操作命令就少很多了,只有下面两个:

ros2 节点启动时如何带上namespace_数据_04

三、Service和srv

前面的Topic专门对付的是异步通信,而这里的Service则主要负责痛不痛信。并不是所有的问题都可以使用异步通信机制来完成,比如说一些周期性的操作,过一段时间才会需要一定的数据,如果让这部分数据一直用topic发送,势必会造成资源浪费,所以引入了Service这种同步通信机制,通过请求-查询的通信模型来实现数据的交换。

与Topic不同的是,Service的通信是双向的,不仅可以发送消息,同时还会有反馈。请求方在发送请求之后会一直等待,直到收到service的响应,其关系如下图所示:

ros2 节点启动时如何带上namespace_异步通信_05


采用service的通信时,就是两个节点之间的通信了,虽然这个过程中也会用到Master去完成节点的注册和信息的匹配,作为应答方的节点需要留一个服务接口,请求方在发出请求之后就原地等待服务方的响应,收到响应之后才会继续原来的任务,这正好对应同步通信中的同步二字。

对比Topic和Service,Topic采用的是异步通信,利用发布订阅机制实现的是多对多的交流,适用于连续、高频的数据发布;而Service采用的是同步通信,利用请求响应机制实现节点之间一对一的交流,适用于偶尔使用的功能。

常用的service操作指令如下:

ros2 节点启动时如何带上namespace_自动驾驶_06


就好比Topic的内容的数据类型是msg,Service的内容的数据类型利用srv文件描述,它声明了一个服务,包括请求(request)和响应(reply)两部分。srv文件格式很固定,第一行是请求的格式,中间用—隔开,第三行是应答的格式。

ros2 节点启动时如何带上namespace_Server_07


图里是一个msg文件的示例,请求为一个布尔值,表示是否开始检测,应答是一个数组,数组的内容是msg,所以msg可以嵌套到srv中,而srv不能嵌套到srv中。

对srv的操作指令如下:

ros2 节点启动时如何带上namespace_异步通信_08


如果要自定义Service,不仅要定义msg文件和srv文件,还需要修改package.xml和CMakeList.txt,添加一些必要的依赖。

四、Parameter Server

Parameter Server是一种特殊的静态通信方式,前面提到在使用roscore指令启动Master的时候,系统会顺便启动rosout和Parameter Server,这里的Parameter Server也就是参数服务器就是一种特殊的静态通信。
参数服务器是节点存储参数的地方,可以看作一个参数的仓库,相比与topic,参数管理器更加静态,它维护一个数据字典,在字典中利用键值对存储各种参数和配置。

读取这个参数服务器的方式十分灵活,可以用命令行、launch文件或者在Node内部进行维护。命令行的维护指令如下:

ros2 节点启动时如何带上namespace_异步通信_09

五、Action

Action是一种特殊的Service,可以看作一般Service的增强版,增强的地方在于对长时间等待的处理。
前面提到过在Service中,请求方发出请求后就会一直等待响应,如果这个请求的时间特别长,整个通信就会受阻,此时再使用Service就会很麻烦。在此基础上ROS引入了Action机制。actionlib则可以比较适合实现长时间的通信过程,actionlib通信过程可以随时被查看过程进度,也可以终止请求,这样的一个特性,使得它在一些特别的机制中拥有很高的效率。

六、小总结

ros2 节点启动时如何带上namespace_异步通信_10

七、演示

ros2 节点启动时如何带上namespace_Server_11


这里演示了对Node的操作,启动roscore之后,查看当前节点,只有一个负责日志的rosout,启动一下之前的小乌龟程序,再次查看节点列表,发现新增了启动的小乌龟节点。之后使用info指令查看节点的信息:

ros2 节点启动时如何带上namespace_自动驾驶_12


从这里可以看出节点的许多信息,publications对应的是查询的节点发布的topic,subscriptions对应的是节点订阅的topic,services是节点使用的服务,最后是节点目前的一些连接信息,因为节点本身也是一个进程,所以还带着进程的PID。

利用ping查看ros节点的连通情况,利用kill清除节点:

ros2 节点启动时如何带上namespace_数据_13


还是一样的方法,启动roscore之后启动小海龟程序,这次换成查看topic的信息,启动后多了三个topic:

ros2 节点启动时如何带上namespace_数据_14


可以用echo查看实时的topic信息,这里如果要使用这条指令的话,必须要让topic里面有信息,否则一直什么都不显示,我这里是又开了一个控制方向移动的节点,让这个节点和小海龟节点通信,这样就显示出来了topic的信息。

ros2 节点启动时如何带上namespace_数据_15


使用rosmsg查看这些topic信息的格式,刚刚好与msg文件内的格式相对应:

ros2 节点启动时如何带上namespace_数据_16


对Service和srv的操作与对Topic和msg的操作基本一致,就不再重复了。对parameter的操作就比较简单了,和对数据库的操作基本一样。

ros2 节点启动时如何带上namespace_异步通信_17