ROS探索总结(五十六)—— launch文件

13952
27
2018年10月29日 12时23分

每当我们需要运行一个ROS节点或工具时,都需要打开一个新的终端运行一个命令。当系统中的节点数量不断增加时,每个节点一个终端的模式会变得非常麻烦。那么有没有一种方式可以一次性启动所有节点呢?答案当然是肯定的。

启动文件(Launch File)便是ROS中一种同时启动多个节点的途径,还可以自动启动ROSMaster节点管理器,而且可以实现每个节点的各种配置,为多个节点的操作提供了很大便利。

一、基本元素

首先来看一个简单的launch文件:

<launch>
   <nodepkg="turtlesim"name="sim1" type="turtlesim_node"/>
   <nodepkg="turtlesim"name="sim2" type="turtlesim_node"/>
</launch>

这是一个简单而完整的launch文件,采用XML的形式进行描述,包含一个根元素<launch>和两个节点元素<node>。

1.<launch>

XML文件必须要包含一个根元素,launch文件中的根元素采用<launch>标签定义,文件中的其他内容都必须包含在这个标签之中:

<launch>
    ......
</launch>

2. <node>

启动文件的核心是启动ROS节点,采用<node>标签定义,语法如下:

<node pkg="package-name"type="executable-name" name="node-name" />

从上边的定义规则可以看出,在启动文件中启动一个节点需要三个属性:pkg、type和name。其中pkg定义节点所在的功能包名称,type定义节点的可执行文件名称,这两个属性等同于在终端中使用rosrun命令执行节点时的输入参数。name属性用来定义节点运行的名称,将覆盖节点中init()赋予节点的名称。这是三个最常用的属性,在某些情况下,我们还有可能用到以下属性:

·  output = “screen”:将节点的标准输出打印到终端屏幕,默认输出为日志文档;

·  respawn = “true”:复位属性,该节点停止时,会自动重启,默认为false;

·  required = “true”:必要节点,当该节点终止时,launch文件中的其他节点也被终止;

·  ns = “namespace”:命名空间,为节点内的相对名称添加命名空间前缀;

·  args = “arguments”:节点需要的输入参数。

实际应用中的launch文件往往会更加复杂,使用的标签也会更多,例如一个启动机器人的launch文件如下:

<launch>

   <node pkg="mrobot_bringup" type="mrobot_bringup" name="mrobot_bringup" output="screen" />

   <arg name="urdf_file" default="$(find xacro)/xacro --inorder '$(find mrobot_description)/urdf/mrobot_with_rplidar.urdf.xacro'" />
   <param name="robot_description" command="$(arg urdf_file)" />

   <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />  

   <node pkg="robot_state_publisher" type="robot_state_publisher" name="state_publisher">
       <param name="publish_frequency" type="double" value="5.0" />
   </node>
   <node name="base2laser" pkg="tf" type="static_transform_publisher" args="0 0 0 0 0 0 1 /base_link /laser 50"/>

   <node pkg="robot_pose_ekf" type="robot_pose_ekf" name="robot_pose_ekf">
       <remap from="robot_pose_ekf/odom_combined" to="odom_combined"/>
       <param name="freq" value="10.0"/>
       <param name="sensor_timeout" value="1.0"/>
       <param name="publish_tf" value="true"/>
       <param name="odom_used" value="true"/>
       <param name="imu_used" value="false"/>
       <param name="vo_used" value="false"/>
       <param name="output_frame" value="odom"/>
   </node>

   <include file="$(find mrobot_bringup)/launch/rplidar.launch" />

</launch>

目前,我们只关注其中的标签元素,除了上边介绍的<launch>和<node>,这里还出现了<arg>、<param>、<remap>,这些都是常用的标签元素。

二、参数设置

为了方便设置和修改,launch文件支持参数设置的功能,类似于编程语言中的变量声明。关于参数设置的标签元素有两个:<param>、<arg>,一个代表parameter,另一个代表argument。这两个标签元素翻译成中文都是“参数”的意思,但是这两个“参数”的意义是完全不同的。

1. <param>

parameter是ROS系统运行中的参数,存储在参数服务器中。在launch文件中通过<param>元素加载parameter;launch文件执行后,parameter就加载到ROS的参数服务器上了。每个活跃的节点都可以通过 ros::param::get()接口来获取parameter的值,用户也可以在终端中通过rosparam命令获得parameter的值。

<param>的使用方法如下:

<param name="output_frame" value="odom"/>

运行launch文件后,output_frame这个parameter的值就设置为odom,并且加载到ROS参数服务器上了。但是在很多复杂的系统中,参数的数量很多,如果这样一个一个的设置会非常麻烦,ROS也为我们提供了另外一种类似的参数加载方式——<rosparam>:

<rosparamfile="$(find 2dnav_pr2)/config/costmap_common_params.yaml" command="load" ns="local_costmap" />

<rosparam>可以帮助我们将一个yaml格式文件中的参数全部加载到ROS参数服务器中,需要设置command属性为“load”,还可以选择设置命名空间“ns”。

 

2. <arg>

argument是另外一个概念,类似于launch文件内部的局部变量,仅限于launch文件使用,便于launch文件的重构,和ROS节点内部的实现没有关系。

设置argument使用<arg>标签元素,语法如下:

<arg name=”arg-name” default=”arg-value”/>

launch文件中需要使用到argument时,可以使用如下方式调用:

<paramname="foo" value="$(argarg-name)" />
<node name="node" pkg="package" type="type "args="$(arg arg-name)" />

三、重映射机制

ROS的设计目标是提高代码的复用率,所以ROS社区中的很多功能包我们都可以拿来直接使用,而不需要关注功能包的内部实现。那么问题就来了,别人功能包的接口不一定和我们的系统兼容呀?

ROS提供一种重映射的机制,简单来说就是取别名,类似于C++中的别名机制,我们不需要修改别人功能包的接口,只需要将接口名称重映射一下,取个别名,我们的系统就认识了(接口的数据类型必须相同)。launch文件中的<remap>标签可以帮我们实现这个重映射的功能。

比如turtlebot的键盘控制节点,发布的速度控制指令话题可能是/turtlebot/cmd_vel,但是我们自己的机器人订阅的速度控制话题是/cmd_vel,这个时候使用<remap>就可以轻松解决问题,将/turtlebot /cmd_vel重映射为/cmd_vel,我们的机器人就可以接收到速度控制指令了:

<remap from="/turtlebot/cmd_vel"to="/cmd_vel"/>

重映射机制在ROS中的使用非常广泛,也非常重要,方法不止这一种,也可以在终端rosrun命令中实现重映射,大家一定要理解好这种机制。

四、嵌套复用

在复杂的系统当中,launch文件往往有很多,这些launch文件之间也会存在依赖关系。如果需要直接复用一个已有launch文件中的内容,可以使用<include>标签包含其他launch文件,这和C语言中的include几乎是一样的。

<include file="$(dirname)/other.launch" />

总而言之,launch是ROS框架中非常实用、灵活的功能,它类似于一种高级编程语言,可以帮助我们管理启动系统时的方方面面。在使用ROS的过程中,很多情况下我们并不需要编写大量代码,仅需要使用已有的功能包,编辑一下launch文件,就可以完成很多机器人功能。

 

这里仅介绍了launch中最为常用的一些标签元素,还有更多高级的标签元素可以访问wiki学习:

http://wiki.ros.org/roslaunch/XML。

 

发表评论

后才能评论

评论列表(27条)

  • 张无忌 2020年4月14日 下午11:19

    您好老师,我在键盘控制节点之后进行了的重映射,希望能使键盘控制ns=”uav0″下的飞机,但是发现rostopic当中还是有/mavros/state,并且rqt_graph查看依然不能通信,希望老师能够提供一下解决问题的思路。谢谢老师!

  • zhou 2019年5月11日 下午5:42

    古月老师您好,想请教一下,之前都是利用笔记本通过局域网连入机器人端,输入命令并控制关机,现在我把机器人多点自主导航的那个launch文件设置为开机自启动,想问一下在不用外部笔记本接入的情况下,怎么能让命令自动退出,并自动关机呢?在网上没找到相关的资料,有没有什么好的办法呀,谢谢!

  • 林夕 2019年4月23日 上午9:23

    古月大神,请问运行launch文件时,cmakelist需要设置哪些地方呀。

    • 古月 回复 林夕 2019年4月25日 下午7:41

      launch文件不需要在cmaklist里配置

    • 林夕 回复 古月 2019年4月26日 上午9:48

      好的。蟹蟹❤

  • 田月平 2019年3月11日 下午5:06

    古月博主你好,最近在做ROS仿真这块,通过roslaunch将URDF在RVIZ中显示出来,现在有个问题想请教,如果我想临时在RVIZ中添加一个新的模型,在不重启roslaunch的情况下,有什么方法将模型导入RVIZ 中去呢

    • 古月 回复 田月平 2019年3月16日 下午9:45

      rviz是通过robotmodel显示机器人模型的,其中会通过robot_description参数获取模型路径,应该可以再加一个robot_description2,配置第二个模型的路径,我没试过,也许可以

  • Lixin 2019年1月18日 下午11:06

    Hi, thx for the tipps! 古月博主你好
    But when i launched my robot, i got the warning: Controller Spawner couldn’t find the expected controller_manager ROS interface.
    i’m stuck with this error.. and i have already added the gazebo_ros_control plugin in my urdf file.
    Besides i have also installed both ros-kinetic-gazebo-ros and ros-kinetic-gazebo-ros-control.
    do you have any idea?
    many thanks!!!

    • 古月 回复 Lixin 2019年1月19日 下午6:31

      还要安装ros-kinetic-gazebo-ros-controllers

  • 彭风 2019年1月10日 上午10:19

    古月老师您好,我最近在调试gazebo和SUMO联合仿真,在启动launch文件时,出现了如下的错误,请老师指点一下:
    … logging to /home/weifengpeng/.ros/log/9312f14e-147a-11e9-bf66-40e230b1bf9d/roslaunch-weifengpeng-8122.log
    Checking log directory for disk usage. This may take awhile.
    Press Ctrl-C to interrupt
    Done checking log file disk usage. Usage is <1GB.

    Invalid tag: prius_description
    ROS path [0]=/opt/ros/kinetic/share/ros
    ROS path [1]=/home/weifengpeng/catkin_ws/src
    ROS path [2]=/opt/ros/kinetic/share.

    Arg xml is
    The traceback for the exception was written to the log file

    • 古月 回复 彭风 2019年1月10日 上午11:18

      prius_description没找到

    • 菜菜 回复 彭风 2019年4月13日 上午8:50

      hi,你好,能交流下gazebo 和sumo的联合仿真吗

  • terminal 2019年1月8日 上午10:10

    老师,您好!这是我按照您课程里面提供的mbot_bringup.launch文件改的启动文件,但是里面的回调函数都进不去,不知道为什么?麻烦老师帮忙看一下,谢谢老师!
    #include “xbot_bringup/xbot.h”
    double RobotV_ = 0;
    double YawRate_ = 0;
    sensor_msgs::Imu imu_;

    // 速度控制消息的回调函数
    void cmdCallback(const geometry_msgs::Twist& msg)
    {
    // 在回调函数中将接收到的cmd_vel速度消息转换为自定义的结构体(或者union)类型的数据
    // RobotV_ = msg.linear.x * 10000; //机器人的速度
    // YawRate_ = msg.angular.z; //机器人的旋转角度

    RobotV_ = 1000; //机器人的速度
    YawRate_ =80; //机器人的旋转角度
    }
    //IMU回调函数
    void imuCallback(const sensor_msgs::Imu &imu_msg)
    {
    //imu_ = imu_msg;
    imu_.orientation.x=99;
    imu_.orientation.x=88;
    imu_.orientation.x=66;
    imu_.orientation.x=21;
    }
    int main(int argc, char** argv)
    {
    //初始化ROS节点
    ros::init(argc,argv,”xbot_bringup”);
    ros::NodeHandle n;
    //初始化xbot
    xbot::xbot robot;
    if(!robot.init())
    ROS_ERROR(“xbot initialized failed.”);
    ROS_INFO(“xbot initialized successful.”);
    ros::Publisher odom_pub = n.advertise(“odom”, 10);
    ros::Subscriber sub = n.subscribe(“cmd_vel”, 10, cmdCallback);
    ros::Subscriber imu_sub = n.subscribe(“imu”, 10, imuCallback);
    //循环运行
    ros::Rate loop_rate(1);
    while (ros::ok())
    {
    ros::spinOnce();
    // 机器人控制
    robot.spinOnce(RobotV_, YawRate_, imu_);
    loop_rate.sleep();
    }
    return 0;
    }

    • terminal 回复 terminal 2019年1月10日 上午10:57

      问题已经解决了,是一个子程序陷入了死循环导致的,谢谢老师!

  • terminal 2019年1月2日 上午11:23

    古老师,我在launch文件中加了robot_pose_ekf的相关信息,然后,启动launch提示下面这个错误:
    [ERROR] [1546398778.050686709]: filter time older than odom message buffer
    [ERROR] [1546398778.062998175]: Covariance specified for measurement on topic wheelodom is zero
    请问是什么原因?怎么解决这个问题?

    • 古月 回复 terminal 2019年1月4日 上午11:47

      参考:http://wiki.ros.org/robot_pose_ekf/Troubleshooting
      可能是没设置协方差

  • 小白 2018年12月25日 下午5:16

    老师,我想问一下,用robot_pose_ekf这个功能包的话,imu、里程计和激光雷达发送的数据需要做什么改动吗?他的odom_combined数据如何被move_base利用?

  • 胡运 2018年11月21日 下午4:36

    你好,在使用argument时,调用方式为什么是
    而不是

    • 胡运 回复 胡运 2018年11月21日 下午4:38

      为什么在尖括号里的东西看不到……好尴尬……

    • 古月 回复 胡运 2018年11月21日 下午9:11

      这个好像是回复功能中的bug,这里用的都是xml表示的方法,通过$()调用具体值

    • 胡运 回复 古月 2018年11月22日 上午8:17

      就是在使用argument时 ,写的是param name=”foo” value=”$(arg arg-name)”,这里为什么是param而不是arg

    • 古月 回复 胡运 2018年11月24日 下午12:47

      param是设置到ros master中的,在节点里使用,arg只用在launch文件,相当于是launch文件内部的变量

  • 余徽阳 2018年11月16日 下午2:36

    古月博主你好,最近我们在做多个机器人的通信,我们现在需要一个在一个master上管理多个turtlebot3来发送位置信息,这个位置信息是基于slam.alunch得到的。我们按照turtlebot教程启动roslaunch turtlebot3_bringup turtlebot3_robot.launch,但是启动第二个时就会使第一次启动的robot.launch自动关闭,我们很疑惑.
    请问博主,能不能做到两个turtlebot3在一个master上同时运行各自的robot.launch?如果可以,博主能不能指点一下呢?如果不可以,那我们应该怎么才能做到呢?
    希望能得到博主的帮助,感谢!

    • 古月 回复 余徽阳 2018年11月20日 下午1:37

      这是因为在同一个网络下存在同名的节点了,需要通过命名空间来做区分,每个机器人用不同的命名空间,这样才不会冲突,google搜下ros namespace,有具体说明

    • 余徽阳 回复 古月 2018年11月28日 上午12:17

      恩恩,好的,谢谢古月君