15.在ROS中,使用launch文件一次启动多个节点

Contenu vidéo originalAgrandir la vidéo
  • 在前面的课程中,我们学习了肉式节点的实现方法。
  • 为了将这些节点运行起来,我们打开了四个中端来运行指令,这是非常繁琐的。
  • 使用肉式的launch文件可以批量启动节点,简化操作。
  • XML语法用于描述多层嵌套的数据结构。
  • 在调试中,可以为节点添加属性以方便查看输出信息。

在前面的课程中,我们学习了肉式节点的实现方法。作为练习,编写了两个发布者节点和一个订阅者节点。为了将这些节点运行起来,我们打开了四个中端来运行指令,这非常繁琐。这还只是运行了三个节点,要是后面运行几十个节点,岂不是光输入指令就得敲个半天?有没有简单快捷的方法,一次就能将所有的节点运行起来呢?这就要用到肉式的launch文件了。

launch文件是一种遵循XML语法的描述文件,批量启动肉式节点,只是它的功能之一。既然是功能之一,说明不会用到太复杂的语法。在这一节里,我们只需要这一条一句就够了。咱们先不解释指令的具体内容,先来看一个例子。

假设现在有这么一个指合,应该怎么用XML去描述它呢?先把它的名称写出来,加个尖括号,这就是它标记名称的开头。有了开头,自然需要接尾,复制一个一样的标记,加上一个斜杠,这就是标记名称的接尾。一个开头,一个接尾,这就完成了一个指合的最基本的描述。

假设有个小指合掉到了这个大指合里面,那么可以在大指合的闭合标记中间插入一组小指合的闭合标记,这就完成了大指合套小指合的描述。其中闭合标记之间的这一部分称为这个标记的内容。为了便于阅读,通常会将包含内容的闭合标记分为上下两行,内容部分罗列在中间,就像C语言的函数体一样。

如果要对标记对象进行更详细的描述怎么办?一般是在标记名称的开头增加相应的属性值,比如这里,为小指合增加一个颜色描述,这样小指合的描述就更加丰富了。除了闭合标记,还有内容和属性。虽然现在内容还是空的,这是不是就和开头咱们提到的那一句XML的语法一样了?

描述一组多层嵌套的数据结构就是XML语言的主要作用之一。如果小指合里还有小小指合的话就可以这样无限的嵌套下去。但是现在咱们这个小指合内容是空的,有时候为了简单一点会把没有内容的闭合标记省略,将闭合的斜杠移动到头部标记后一个尖括号的前面,作为整个标记的闭合,这样写也是可以的。

好,假设又出现了一个小指合也掉到了这个大指合里,那我们就可以在这个大指合的内容部分再增加一行,加入这个新指合的描述。后面如果还有其他的小指合还可以继续这样增加内容,从而实现一个大容器包含多个小容器的描述。

这个有什么用呢? 来,我们来看一看下一个例子。比如有这么一个比赛阵容,该怎么用XML来描述呢?首先,这个阵容可以看作一个大指合,标记名称为阵容。先看第一个小指合,因为这是一个比赛,所以小指合的标签为选手,然后是它的属性值:第一个,选手的名字,诺言;所选的英雄,花木兰;英雄的职业,战士。那第一个小指合就描述完了。

第二个小指合,同样的选择:选手名字,花海;英雄,孙上乡;职业,射手。然后第三个小指合,选手名字,Cat;英雄,安琪拉;职业,法师。接下来,第四个小指合,选手名字,阿兰;英雄,蓝铃王;职业,刺客。最后一个小指合,选手名字,无鸣;英雄,忠诽;职业,法师。

好了,这就完成了对整个阵容的描述。有没有发现,其实咱们上一节的例子也是这样一个英雄阵容,只不过英雄的数量只有三个。下面我们一一对这三个英雄的阵容也进行相应的描述。首先我们来看看启动这三个节点所需要运行的指令。

第一条是启动弱势的核心;第二条是运行瑶的节点;第三条是超哥的节点;最后一条是小马哥的节点。好,我们开始了!首先是大盒子名称为阵容,第一个小盒子弱势核心,这个因为不是独立节点所以可以不用描述。第二个小盒子,标记名称为节点包名SSRpackage,节点为youtnote。

最后一个节点名字,这个节点名字是什么意思这里我们先不深究,后面涉及到多个同门节点的运行时就能体会到它的妙用了。然后第三个小盒子,包名SSRpackage,节点名字都是超note。最后一个小盒子,包名atrpackage,节点和名字都是马note。

好,这就完成了!最后我们再将里面的中文标签换成英文的:阵容换成launch,节点换成note,包名换成pkg,标签换成type,名字换成name,这样就构成了一个基本的launch文件的内容。

通过这个launch文件就可以一次将这三个节点全部启动。注意,这里的roscore还没有进行描述,还需要补充吗?不需要了,因为launch文件的机制就是只要包含了节点的描述,哪怕只有一个节点都会自动启动roscore,所以没有描述也没有关系。

现在文件内容都已经有了,下面我们看看如何把它写到一个包里吧。首先我们看看这个launch文件要放在哪里。其实只要随便放在某个软件包的文件夹里就行了。当我们使用指定启动launch文件时,会自动对指定软件包的目录进行逐层的便利搜索,所以只要launch文件放在软件包的文件夹里,哪怕是某个子目录里都可以被找到并执行。

不过为了优雅一点,我们还是创建一个新的子目录吧,目录名叫做launch,这样既直观又便于管理。至于这个launch子目录放在哪个软件包下,这个就很随意了,不一定非要放在节点所在的软件包,任何软件包都行

好,我们打开VSCode,在工作空间里随便找一个软件包,就第一个吧hgrpackage,右键点击软件包弹出菜单,选择新建文件夹,名字为launch,然后继续右键点击这个文件夹,新建文件,文件名为开黑.launch。文件内容就是刚才对三个节点的XML描述,先是首位的launch标记,然后是第一个瑶节点,后面的节点描述方式都一样,我们就直接复制两条,第二条修改节点名,第三条修改包名和节点名。

好,这就完成了!下面我们试着来运行这个launch文件。按下Ctrl + T,弹出终端窗口,输入roslaunch hgrpackage 开黑.launch,回车。怎么只有姚妹妹的消息?不急不急,Ctrl + C打断,回到VSCode的订阅者节点的属性中将output指定为screen(屏幕)。保存回到终端,再执行一下刚才的launch文件,看所有接收到的消息包都显示出来了。

我们来看看订阅者代码,超哥的消息用的是rosinfo显示的白色信息,姚妹妹的消息显示的是黄色信息。可见,刚才加的output属性只对rosinfo显示产生了影响,ros1无视这个属性,直接暴力输出。

好,这时候我们看看当前运行的节点网络。输入rqt_graph,回车,放大一下看看是不是和规划的节点网络一样。到这里我们就实现了用一个launch文件启动多个节点的功能。

最后还有个问题,就是所有的节点都在一个终端里输出,假设我们要调试其中的某个节点,会希望这个节点能够在一个独立的窗口里输出调试信息,否则所有的节点混在一起根本看不出哪条是哪个节点的信息。那应该怎么做呢?来,我们回到launch文件。

比如我们想让这个超note单独运行在一个终端窗口,只需要在它的属性里添加launch_prefix="xterm"这个参数为e,这个xterm就是Ubuntu自带的终端程序。这条属性的意思是使用一个新的终端程序去运行这个节点。保存,再到终端窗口再次运行这个launch文件,看弹出的这个新窗口输出了超哥的登场台词,说明这个终端中运行的就是刚才修改的超node节点。

此时,超哥的节点可以看到,订阅者节点中已经收不到超哥发出来的消息了。这时候我们再看一下节点网络,那是不是超哥的节点不见了?好,我们最后来小节一下:

  1. 使用launch文件可以通过launch指令一次启动多个节点。
  2. 在launch文件中为节点添加output="screen"属性可以让节点信息输出在终端中,注意launch_one不受该属性的控制。
  3. 在launch文件中为节点添加launch_prefix="xterm"属性可以让节点单独运行在一个独立终端中。

从这一节的内容可以看出,利用好launch文件可以大大方便我们对多个节点进行启动和调试。同时,launch文件也是一个软件包的重要入口,当我们拿到一个陌生的软件包不知道它的用途时,就可以从launch文件入手,通过文件名猜测它的功能,然后打开文件查看这个功能需要启动哪些节点,最后在选择这些线索逐个击破,很快就可以搞清楚其内部的实现机制。

当然launch文件的用途还不止这些,后面我们还会对它进行更多的扩展。好,这一期就到这,咱们下期再见