美文网首页
ROS 中的 launch 文件

ROS 中的 launch 文件

作者: OurNote | 来源:发表于2019-02-01 15:15 被阅读0次

    launch 文件简介

    从 ROS 角度来看,机器人系统就是一堆 node 和 topic (再添加一些 parameter, service 等)构成的网络(rosgraph),其中每个 node 都可以完成一定的功能。通常一个机器人运行时要开启很多 node,如果一个 node 一个 node 的启动,比较麻烦。通过 launch文件以及 roslaunch 命令可以一次性启动多个 node,并且可以设置丰富的参数。

    目前来看,官方 ros package 大部分都包含名为 launch 的文件夹,里面存放了 launch 文件。我们自己编写的 package 也应该尽量使用这种结构,方便“一键启动”。

    运行 launch 文件

    用 roslaunch 命令启动 launch 文件至少有两种方式:

    1. 借助 ros package 路径启动

    格式如下:

    roslaunch  pkg_name  launchfile_name.launch 
    
    1. 直接给出 launch 文件的绝对路径

    格式如下:

    roslaunch path_to_launchfile
    

    不论用上述哪种方式启动 launch 文件,都可以在后边添加参数,比较常见的参数有

    • --screen: 令 ros node 的信息(如果有的话)输出到屏幕上,而不是保存在某个 log 文件中,这样比较方便调试
    • arg:=value: 如果 launch 文件中有待赋值的变量,可以通过这种方式赋值,例如:
    roslaunch   pkg_name  launchfile_name  model:=urdf/myfile.urdf  # launch file 中有参数 “model” 需要赋值
    

    roslaunch  pkg_name  launchfile_name  model:='$(find urdf_pkg)/urdf/myfile.urdf' # 用 find 命令提供路径
    

    roslaunch 命令运行时首先会检测系统的rosmaster是否运行,如果已经启动,就用现有的 rosmaster;如果没有启动,会先启动rosmaster,然后再执行 launch 文件中的设置,一次性把多个节点按照我们预先的配置启动起来。

    需要注意的是, launch 文件不需要编译,设置好之后可以直接用上述方式运行。

    launch 文件的格式

    launch 文件本质上是一种 xml 文件,可以在头部添加

    <?xml version="1.0"?>
    

    在某些编辑器中可以高亮显示关键字,方便阅读。

    与其他 xml 格式的文件类似,launch 文件也是通过标签 (tag) 的方式书写。
    主要的 tag 如下:

    <launch>                <!--根标签-->
    <node>                  <!--需要启动的node及其参数-->
    <include>               <!--包含其他launch-->
    <machine>               <!--指定运行的机器-->
    <env-loader>            <!--设置环境变量-->
    <param>                 <!--定义参数到参数服务器-->
    <rosparam>              <!--加载yaml文件中的参数到参数服务器-->
    <arg>                   <!--定义变量-->
    <remap>                 <!--设定 topic 映射-->
    <group>                 <!--设定分组-->
    </launch>               <!--根标签-->
    

    <launch>, <node>

    这两个 tag 是 launch 文件的核心部分。基本格式如下:

    <launch>
        <node pkg="package_name" type="executable_file" name="node_name1"/>
        <node pkg="another_package" type="another_executable" name="another_node"></node>
        ...
    </launch>
    

    其中

    • pkg 是节点所在的 package 名称
    • type是 package 中的可执行文件,如果是 python 或者 Julia 编写的,就可能是 .py 或者 .jl 文件,如果是 c++ 编写的,就是源文件编译之后的可执行文件的名字。
    • name是节点启动之后的名字, 每一个节点都要有自己独一无二的名字。

    注意: roslaunch 不能保证 node 的启动顺序,因此 launch 文件中所有的 node 都应该对启动顺序有鲁棒性。

    实际上 <node> 中除了 pkg, type, name 之外还可以设置更多参数,如下:

    <launch>
        <node
            pkg=""
            type=""
            name=""  
            respawn="true" 
            required="true"
            launch-prefix="xterm -e"
            output="screen"
            ns="some_namespace"
        />
    </launch>
    

    上述命令中,

    • respawn:若该节点关闭,是否自动重新启动
    • required:若该节点关闭,是否关闭其他所有节点
    • launch-prefix: 是否新开一个窗口执行。例如,需要通过窗口进行机器人移动控制的时候,应该为控制 node 新开一个窗口;或者当 node 有些信息输出,不希望与其他 node 信息混杂在一起的时候。
    • output:默认情况下,launch 启动 node 的信息会存入下面的 log 文件中
      /.ros/log/run_id/node_name-number-stdout.log
      
      可以通过此处参数设置,令信息显示在屏幕上
    • ns:将 node 归入不同的 namespace,即在 node name 前边加 ns 指定的前缀。为了实现这类操作,在 node 源文件中定义 node name 和 topic name 时要采用 relative name, 即不加slash符号 /.

    <remap>

    经常作为 node tag 的子 tag 出现,可以用来修改 topic。 在很多 rosnode 源文件中,可能并没有指定接收的或者发送的 topic,而仅仅是用 input_topicoutput_topic 代替,这样在使用中需要将抽象的 topic 名字替换成具体场景中的 topic 名字。

    简单地说, remap 的作用就是方便同一个 node 文件被应用到不同的环境中,用 remap 从外部修改一下 topic 即可,不需要改变源文件。

    remap 常见的使用格式如下:

    <node pkg="some" type="some" name="some">
        <remap from="origin" to="new" />
    </node>
    

    <include>

    这个标签的作用是将另外一个 launch 文件添加到本 launch 文件中,类似 launch 文件的嵌套。

    基本格式:

    <include file="path-to-launch-file" />
    

    上边的文件路径可以给具体路径,但是一般来说为了程序的可移植性,最好借助 find 命令给出文件路径:

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

    上述命令中,$(find package-name) 等价于本机中相应 package 的路径。这样即使换了其他机子,只要安装了同样的 package,就可以找到对应的路径。

    有时,另一个 launch 引入的 node 可能需要统一命名,或者具有类似特征的 node 名字,比如 /vehicle1/gps, /vehicle1/lidar, /vehicle1/imu,即 node 具有统一的前缀,方便查找。这可以通过设置 ns (namespace)属性来实现,命令如下:

    <include file="$(find package-name)/launch-file-name " ns="namespace_name" />
    

    <arg>

    通过 <arg> tag 可以使参数重复使用,也便于多处同时修改。
    <arg> 三种常用方法:

    • <arg name="foo">: 声明一个 arg,但不赋值。稍后可以通过命令行赋值,或者通过 <include> tag 赋值。
    • <arg name="foo" default="1">: 赋默认值。这个值可以被命令行和<include> tag 重写。
    • <arg name="foo" value="1">: 赋固定值,这个值不可以被改写.

    从 command-line 赋值

    roslaunch package_name file_name.launch  arg1:=value1  arg2:=value2
    

    变量替换 $(find *)$(arg *)

    在 launch 文件中常用的变量替换形式有两个

    • $(find pkg): 例如$(find rospy)/manifest.xml. 如果可能,强烈推荐这种基于 package 的路径设置

    • $(arg arg_name): 将此处替换成 <arg> tag 指定的 arg value.

    例如:

    <arg name="gui" default="true" />  
    # 先设置默认值,如果没有额外的赋值,就用这个默认值了
    
    <param name="use_gui" value="$(arg gui)"/>
    

    另一个例子:

    <node name="add_two_ints_client" pkg="beginner_tutorials" type="add_two_ints_client" args="$(arg a) $(arg b)" />
    

    这样设置之后,在启动 roslaunch 时,可以为 args 赋值

    roslaunch beginner_tutorials launch_file.launch a:=1 b:=5
    

    <param> 与 <rosparam>

    提到 param 首先要知道 parameter server, 它由 ROS Master 管理,提供了一个共享的字典 (dict) 类型数据。节点通过这个 server 存储、获取运行时所需的参数。

    param server 设计时就不是针对高速存取的,因此一般只适合存放静态数据,例如配置参数.

    由于是全局可获取, 我们可以很容易的查看其中的 param 并且修改。

    param 的命名与 topic 和 node 相同,都是有 namespace hierarchy 结构的,这可以防止不同来源的名字冲突。它的存取也是体现了结构性,例如下边的 params

    /camera/left/name: leftcamera
    /camera/left/exposure: 1
    /camera/right/name: rightcamera
    /camera/right/exposure: 1.1
    

    对于上述数据,

    • 如果读取参数 /camare/left/name 可以得到 leftcamera
    • 如果读取 param /camera/left可以得到 dict 为
      {name: leftcamera, exposure: 1}
      
    • 如果读取 param /camera,则得到 dict 为
      {left: {name: leftcamera, exposure: 1}, 
       right: {name: rightcamera, exposure: 1.1}} 
      

    <param>

    与 arg 不同,param 是共享的,并且它的取值不仅限于 value,还可以是文件,甚至是一行命令。

    • 格式
      <param name="param_name" type="type1" value="val"/>     # type可以省略,系统自动判断
      <param name="param_name" textfile="$(find pkg)/path/file"/>     # 读取 file 存成 string
      <param name="param_name" command="$(find pkg)/exe '$(find pkg)/arg.txt'"/>
      实例:
      <param name="param" type="yaml" command="cat '$(find pkg)/*.yaml'"/> # command 的结果存在 param 中
      

    param 可以是在 global scope 中,它的 name 就是原本的 name,也可以在某个更小的 scope 中,比如 node,那么它在全局的名字就是 node/param 形式.

    例如在 global scope 中定义如下 param

    <param name="publish_frequency" type="double" value="10.0" />
    

    再在 node scope 中定义如下 param

     <node name="node1" pkg="pkg1" type="exe1">
        <param name="param1" value="False"/>
      </node>
    

    如果用 rosparam list列出server 中的 param,则有

    /publish_frequency
    /node1/param1   # 自动加上了 namespace 前缀
    

    注意:虽然 param 名字前加了 namespace,但是依然 global viewable

    <rosparam>

    <param> 只能对单个 param 操作,而且只有三种:value, textfile, command 形式,返回的是单个 param 的内容。
    <rosparam> 则可以批量操作,还包括一些对参数设置的命令,如 dump, delete 等

    • load : 从 YAML 文件中加载一批 param,格式如下:

      <rosparam command="load" file="$(find rosparam)/example.yaml" />
      
    • delete: 删除某个 param

      <rosparam command="delete" param="my_param" />
      
    • 类似 <param> 的赋值操作

      <rosparam param="my_param">[1,2,3,4]</rosparam>
      

      或者

      <rosparam>
      a: 1
      b: 2
      </rosparam>
      

    <rosparam> tag 也可以放在 <node> tag 中, 此时 param 名字前边都加上 node namespace.

    <group>

    如果要对多个 node 进行同样的设置,比如都在同一个特定的 namespace,remap 相同的topic 等,可以用 <group> tag。在 group 中可以使用所有常见的 tag 进行设置,例如

    <group ns="wg2">
        <remap from="chatter" to="talker"/> # 对该 group 中后续所有 node 都有效
        <node ... />
        <node ... >
            <remap from="chatter" to="talker1"/> # 各个 node 中可以重新设置 remap
        </node>
    </group>
    

    Written by SH
    Revised by QP

    相关文章

      网友评论

          本文标题:ROS 中的 launch 文件

          本文链接:https://www.haomeiwen.com/subject/bfkdsqtx.html