xxx.launch文件启动多个节点

当编写的程序中存在多个节点时,每次都使用“rosrun 功能包名 节点名”一个个开启节点是很麻烦的,因此开始学习如何采用xxx.launch文件启动多个节点,并记录下在编写的过程中踩过的雷。

1 一个简单的launch文件

1.1 将 launch文件放在哪里?

在“功能包名”(我用catkin_create_pkg创建的包名为package) 目录下,创建**.launch文件(我是为了启动imu的节点,因此将其称为imu.launch,可自行定义名称)。
此时,功能包下包括:include 、 src 、 cmakelist.txt 、 package.xml 、 imu.launch
另外, launch文件可以不被包含于package中。此时,只需指出该launch文件的绝对路径,即可运行。

1.2 launch文件最基本包括什么?

启动一个节点基本构成:

<launch>
    <node 
    name="imu_node"  
    pkg="package"  
    type="imu_node">
    </node>
</launch>
//更通用的定义方式,建议使用

或者可以写作:

<launch>
    <node 
    name="imu_node"  
    pkg="package"  
    type="imu_node"
    />   //斜杠/必不可少,表示结束,但是当node中有其他标签时,必须使用上一种定编译方式
</launch>

其中,你需要更改的只有三处:

    name="imu_node" //name=“××”是你在ros::init()中定义的节点名称,我的是ros::init(argc,argv,"imu_node")
    //如果此处node标签下的name属性与init()中的节点名不一致,那么node标签的name属性会覆盖init()中的节点名
    pkg="package" //pkg=“××”则为你的功能包名称,我的是package 
    type="imu_node"//type=“××”是你在cmakelist.txt中定义的可执行文件名称,我在编写时都将可执行文件的名称命名为节点的名称,如:add_executable(imu_node src/imu.cpp)

启动多个节点构成:

<launch>
    <node 
    name="imu_node"  
    pkg="package"  
    type="imu_node">
    </node>
    
    <node 
    name="imu_node2"  
    pkg="package"  
    type="imu_node2">
    </node>
    
    <node 
    name="imu_node3"  
    pkg="package"  
    type="imu_node3">
    </node>
    ... ...
</launch>

如上,launch文件可启动一个功能包中的多个节点,其中,对于每个节点,你需要更改的仍然只是节点名、功能包名、可执行文件名3处。

1.3 如何采用launch文件启动节点?

在终端的工作空间目录下,首先 catkin_make编译一下,然后 source devel/setup.bash 配置环境变量,最后 roslaunch 功能包名 **.launch 。

  • 使用roslaunch 启动.launch 文件,而不是rosrun 。

2 launch文件扩展

Part 1只是实现启动节点功能的launch文件的最基本构成,接下来将详细讲述launch文件及其下的node标签。

2.1 launch文件常用标签

(1) launch标签
每个launch文件都必须且只能包含一个根元素。根元素由一对launch标签定义,其他所有元素标签都应该包含在这两个标签之内,“/”表示结束,如下所示:

<launch> 
... 
</launch>

(2) node标签
node标签是launch文件中最常见的标签,最基本构成如Part1所示,包括name、pkg以及
type。其内部具体属性及标签将在2.2中详细介绍。

(3) param标签
设置parameter到参数服务器。
launch文件执行后,parameter就加载到ROS的参数服务器上了。每个活跃的节点都可以通过 ros::param::get()接口来获取parameter的值,用户也可以在终端中通过rosparam命令获得parameter的值。

语法:

<param name="output_frame" value="odom"/>
//其中,name表示向参数服务器中添加的参数名称,value表示其值。

应用:

//<param name="demo_param" type="int" value="666"/>
//表示向参数服务器中添加一个名为demo_param,值为666的参数。
//在.cpp文件中,使用nh.getParam("demo_param",demo_param)将.launch文件中的"demo_param"值传递给.cpp中的demo_param

(4) arg标签
可通过设置启动参数arg在launch文件中定义参数并赋值。
arg不储存在参数服务器中,不能提供给节点使用,只能在launch文件中使用。

语法:

//第一种赋值方式,在launch文件中:
<arg name="arg-name" default="arg-value" />
<arg name="arg-name" value="arg-value" /> 
//name为启动参数的名称,default为该参数的默认值(可更改),value为该参数的参数值(不可更改)。
//第二种赋值方式,在终端:
roslaunch 功能包名 launch文件名 arg-name:=”arg-value”
//获取参数值
$(arg arg-name) 
//arg-name中的值会赋值给arg

应用:

//在launch文件中:
<arg name="demo" value="666"/>
<arg name="demo1" default="666"/>
// 在launch文件中出现$(arg demo1)的地方

//在终端:
roslaunch 功能包名 launch文件名 demo1:=777//在运行时roslaunch会将它替换成参数值777。并且可以在include元素标签内使用arg来设置所包含的launch文件中的参数值。

//赋值方法及获取值方法使用待验证

但是,argument不能传递给 include 元素里包含的子launch文件使用。这个问题非常重要,因为这个 argument 就像是一个局部变量,它不能被包含的launch文件所 “继承” 。
解决这个问题的方法:在 include 元素中插入 arg 元素作为 include 元素的子类(children),如:

<include file="$(find package-name)/launch-file-name" /> 
<arg name="arg-name" value="arg-value"/>
...
</include>

这里的 arg 元素不同于我们已经知道的 arg 声明,在 include 标签内的arguments是给包含 (included) 的launch文件提供的arguments,不是为本launch文件提供的。
一种常见的情况是,被包含(included)的launch文件和本launch文件会有共同的参数。在这种情况下,我们希望这些值(values)永远不变。像这样的元素,在这两个地方使用相同的argument name (参数名),要这样做:

<arg name="arg-name" value="$(arg arg-name)" />

在这种情况下,第一个 arg-name 和往常一样。第二个 arg-name 是launch文件中提供的。结果是,这两个launch文件中给定的argument具有相同的值(value)。
需要进一步理解

(5) remap标签
重映射机制,相当于取一个别名。ROS支持topic的重映射,remap标签里包含一个original-name和一个new-name,即本名和别名。

语法:

<remap from="/turtlebot/cmd_vel"to="/cmd_vel"/>
//相当于把话题/turtlebot/cmd_vel重映射为/cmd_vel

应用:

现在有一个节点订阅了"/chatter"话题,然而你写的节点只能发布到话题"/demo/chatter",要想让两个节点通信,则可以在launch文件中写:

<remap from="chatter" to="demo/chatter"/>

可直接把话题/chatter 重映射到话题/demo/chatter,不用修改任何代码实现两个节点通讯。
此外,如果remap标签写在与 node标签的同一级,而且在launch标签内的最顶层, 那该重映射将会作用于launch文件中所有的节点。

(6) rosparam标签
加载程序的参数配置文件(yaml文件)到参数服务器,然后程序从参数服务器取得参数值,rosparam标签允许从YAML文件中一次性导入大量参数,在工程中需要设置的参数较多时可使用。
语法:

<rosparam command="load" file="$(find pkg-name)/path/name.yaml" ns="local_costmap"/>
//ns:命名空间

如何编辑yaml文件?
yaml文件内容的固定格式是

变量名: 变量值

例如:我们在功能包中创建一个叫config的文件夹,在该文件夹里面创建一个**.yaml的文件,输入:
noise: 10.0
string_var: abc
vector_var: [1,2,3]
注意在yaml文件中不需要指定变量类型什么的了,变量名: 变量值 是它的固定格式,变量值包含非数字的量它会自动认为这是string类型变量,纯数字的值,如果不包含小数则会认为是int类型的变量,包含小数则是double类型的变量。

(7)include标签
该标签可以导入另一个roslaunch文件到当前文件,使用导入的launch文件中的内容。

语法:

<include file ="$(find pkg-name)/path/filename.xml" ns="NAME_SPACE"/>
//或者
<include file ="$(find pkg-name)/path/filename.launch" ns="NAME_SPACE"/>
//指明我们想要包含进来的文件,并将其放入指定的namespace

** Q:pkg-name的路径是怎么样的?可不可以是其他工作空间?

应用:

<include file = "find learning_tutrols"/launch/start_demo.launch"/> 

(8) group标签
group标签可以将若干个节点同时划分进某个工作空间。

<group ns="demo_1">
    <node name="demo_1" pkg="demo_1" type="demo_pub_1" output="screen"/>
    <node name="demo_1" pkg="demo_1" type="demo_sub_1" output="screen"/>
</group>
<group ns="demo_2">
    <node name="demo_2" pkg="demo_2" type="demo_pub_2" output="screen"/>
    <node name="demo_2" pkg="demo_2" type="demo_sub_2" output="screen"/>
</group>

group标签还可以做到对node的批量管理,比如可以同时终止在同一个group中的节点。

<group if="1-or-0">
……
……
</group>

<group unless="1-or-0">
……
……
</group>

第一种情况,当if属性的值为0的时候将会忽略掉之间的标签。
第二种恰好相反,当if属性的值为1的时候将会忽略掉之间的标签。
但是通常不会直接用1或0来定义if标签,因为这样不够灵活,一般会与$(arg arg_name)来使用。
例如:
demo.launch文件

<launch>
    <include file="include.launch">
        <arg name="demo_arg" value="1"/>
    </include>
</launch>

include.launch文件

<launch>
    <arg name="demo_arg"/>
    <group if="$(demo_arg)">
        <node name="demo" pkg="demo" type="demo_pub" output="screen"/>
        <node name="demo" pkg="demo" type="demo_sub" output="screen"/>
    </group>
</launch>

2.2 node中的节点元素

node的结构如下所示:

<node 
    ...//属性及标签
</node>

接下来按照node的构成介绍:

<node>   //启动节点标志

    <node>常用属性tag:
    pkg:"pkg_name"    功能包名(必要属性)
    type:"exe_name"   编译生成的可执行文件名称(必要属性)
    name:"node_name"  节点名称,会覆盖init()中定义的节点名称(必要属性)
    args:"arg1 ..."   传递节点的参数列表(节点需要的输入参数),arg参数只在launch文件中合法(相当于局部变量),不直接传给节点,所以需要通过node中的args属性进行传递。
    respawn:"true"    如果节点退出自动重启 defaultfalse
    output:"screen"   标准输出/标准错误输出重定向屏幕,log重定向log文件,default:log
    required:"true"   如果节点退出,关闭全部launch进程
    launch-prefix:"prefix arguments" 前置的参数,可以使用其他工具如gdb,valgrind等

    //lannch机制不保证节点的启动顺序,虽然launch文件是顺序分析,但节点初始化的时间长度不一,启动时间不一
</node>    //结束标志

(1) 显示属性:output = “***”
要将节点的输出信息显示在终端上,只需在节点元素中写入:output=”screen”,默认输出为日志文档。
** 配置了该属性的节点会将输出显示在屏幕上而不被记录到日志文档。
** 上述方法仅可显示一个节点,若显示所有节点的输出,用–screen命令行。(待验证)
** $ roslaunch --screen package_name launch_file_name
** 如正在运行的文件没有显示想要对输出,可以查看该node属性中是否有output=”screen”.

(2) 复位属性: respawn=”true”
将某个节点的复位属性设置为真,这样当节点停止的时候,roslaunch会重新启动该节点,默认为false。
应用:比如在某个节点因为软件崩溃或硬件故障以及其他原因导致过早退出系统的时候会起到作用。

(3) 必要节点属性:required=”true”
当被配置为必要节点的节点终止时,launch文件中的其他节点也被终止,一个节点不能同事拥有respawn和required。
应用:比如在依赖控制台的机器人遥控导航中,关闭了该远程控制节点所在的窗口,roslaunch将会终止其他节点,然后退出。

(4)命名空间
ns=”namespace”,定义命名空间,同一命名空间下节点的话题才能通信。前提是节点的代码在创建 ros::Pbulisher 和 ros::Subccriber 对象时使用了像 turtle1/pose 这样的相对名称 (而不是/turtle1/pose 这样的全局名称)。同样,启动文件中的节点名称是相对名称。例如而不能是node name="/turtlesim_node".
动文件默认命名空间是全局命名空间“/”,因此,节点的默认命名空间就解析为/sim1,所以对应的全局名称即/sim1/turtlesim_node。

(5)名称重映射
每个重映射包含一个原始名称和一个新名称。每当节点使用重映射中的原始名称时,ROS客户端库就会将它替换成其对应的新名称。
例如,运行一个 turtlesime 的实例, 如果想要把海龟的姿态数据发布到话题/tim 而不是/turtle1/pose,就可以使用如下命令:
way1: rosrun 功能包名称 节点名称 turtle1/pose:=tim (是不同于launch文件中remap标签的另一种方法)
way2: 通过启动文件的方式,在启动文件内使用重映射(remap)元素即可:<remap from=”turtle1/pose” to ”tim”/>

(6)不同终端运行属性
运行roslaunch时,所有的节点共用一个终端,这对于那些需要从控制台输入的节点很不方便,因此可以在某个需要单独终端的节点中使用launch-prefix属性:launch-prefix=”command-prefix”
例如:launch-prefix=”xterm -e”
等价于:xterm -e rosrun 功能包名 节点名
其中,xterm 命令表示新建一个terminal; -e参数告诉xterm执行剩下的命令行。
** launch-prefix属性不仅仅限于xterm。它可用于调试(通过gdb或valgrind),或用于降低进程的执行顺序(通过nice)。

3 是否存在要启动的节点不在一个工作空间或者功能包下的情况,怎么实现?

待研究

参考自:
————————————————
版权声明:本文为CSDN博主「一把木剑」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/banzhuan133/article/details/77477029
————————————————
版权声明:本文为CSDN博主「沐棋」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_41995979/article/details/81784987
————————————————
版权声明:本文为CSDN博主「turtlebot」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/fengmengdan/article/details/42984429
————————————————
版权声明:本文为CSDN博主「Littlelsu」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_33444963/article/details/77893881
————————————————
作者:陈瓜瓜_ARPG
链接:https://www.jianshu.com/p/13efab3f67e0
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

原创文章 15 获赞 8 访问量 926

猜你喜欢

转载自blog.csdn.net/weixin_39652282/article/details/103682320
今日推荐