机器人操作系统ROS(21):launch文件

0 – Summary

Roslaunch is a tool for easily launching multiple ROS nodes locally or remotely via SSH, as well as setting parameters on the Parameter Server.
It includes options to automatically respawn processes that have already died.
Roslaunch takes in one or more XML configuration files with the .launch extension that specify the parameters to set and nodes to launch, as well as the machines that they should be run on.

1 – Roslaunch Architecture

roslaunch was designed to fit the ROS architecture of complexity via composition: write a simple system first, then combine it with other simple systems to make more complex systems.

In roslaunch, this is expressed through several mechanisms:
1. include : you can easily include other .launch files and also assign them a namespace so that their names do not confict with yours.
2. group : you can group together a collection of nodes to give them the same name remappings. All resource names can be remapped. You can also provide assignment for private node parameters. Remapping arguments can be passed to any node and use the syntax name:=new_name. For example, to configure the talker node to publish to /wg/chatter instead of chatter:
$ rosrun rospy_tutorials talker chatter:=/wg/chatter. You can assign private parameters for a node directly from the command-line using a single underscore _ as a prefix. For example, $rosrun rospy_tutorials talker _param:=1.0, this will sets ~param to 1.0. ROS uses YAML syntax to determine the parameter typing. Note there are some Special keys(double _): __name, __ip and __hostname, __master, __ns.
3. aliased : you can separate machine definitions and node definitions into separate .launch files and use aliases to define which machines get used at runtime. This allows you to reuse the same node definitions for multiple robots. For example, instead of saying that a laser_assembler runs on ‘foo.willowgarage.com’, you can say that it runs on the ’tilt-laser’ machine. The machine definitions then take care of which host is the ’tilt-laser’ machine.

You can use the tag to specify environment variables that need to be set for a particular machine or node. The $(find pkg) syntax let you specify file paths relative to a ROS package, instead of specifying their location on a particular machine. You can also use the $(env ENVIRONMENT_VARIABLE) syntax within include tags to load in .launch files based on environment variables (e.g. MACHINE_NAME).

Roslaunch launches local processes using popen and kills them using POSIX signals. NOTE roslaunch does not guarantee any particular order to the startup of nodes — although this is a frequently requested feature, it is not one that has any particular meaning in the ROS architecture as there is no way to tell when a node is initialized.

2 – Commandline Tools

roslaunch is an important tool that manages the start and stop of ROS nodes. It takes one or more .launch files as arguments.
Most roslaunch command require the name of a launch file. You can either specify the file path of the launch file, or you can specify a package name and launch file in that package:
$ roslaunch [args]
Launch located in , e.g.:
$ roslaunch rospy_tutorials talker_listener.launch
or,
$ roscd package_name
$ roslaunch example.launch
or,Launch the file(s) specified by relative or absolute paths
$ roslaunch pr2_robot/pr2_bringup/pr2.launch

And [args] New in Indigo:
-p port, If you launched roscore on a different port using the -p option.
–wait, Delay the launch until a roscore is detected.
–local, Launch of the local nodes only. Nodes on remote machines will not be run.
–screen, Force all node output to screen. Useful for node debugging.
–dump-params, Print parameters in launch file in YAML format.

If the file you are launching specifies args that require setting, you can do so using an identical syntax to ROS remapping arguments, e.g.:
$ roslaunch my_file.launch arg:=value

2 – roslaunch XML

ROS 的 launch 文档中经常被使用到的三个与参数设置有关的标签 <arg>、<param>、rosparam。arg和param的区别是,param是在node或py等执行文件里面定义的,而arg则是在launch或xml等配置文件里定义的 。

变量标签 arg

<arg>标签给launch文件内部设置参数,通过<arg>标签设置的参数仅在launch文件内有效。

<arg>标签有三种设置参数的方式:

1、直接用此标签设置

2、用此标签声明,用roslaunch命令确定其值

3、用此标签声明,在include 这个launch文件的 父launch文件中确定其值

0、如何声明一个 argument :
<arg name=”arg-name” …/>

1、 如何在声明 argument 时赋值
<arg name=”arg-name” default=”arg-value” />
<arg name=”arg-name” value=”arg-value” />
default 和 value 的区别在于,在命令行中赋值的参数可以覆盖 default,但是不能重写 value 的值。

获取变量值的方式是:
$(arg arg-name)
我们可以通过 $arg$ 来使用该变量,roslaunch 会用给定的参数 $arg-name$ 的值替换整个表达式的值。

2、如何在命令行赋值指定 argument 的值
$ roslaunch package-name launch-file-name arg-name:=arg-value

3、将 argument 值传递给 included launch 文档
<include file=”path-to-file”>
<arg name=”arg-name”  value=”arg-value” />
</include>

注意:若 launch 文档及其 include 的 launch 文档出现相同的 argument,通过如下方式传递给 include launch 文档 :
<arg name=”arg-name” value=”$(arg arg-name)” />
第一个”arg-name”表示 include的launch 文档中的变量;第二个”arg-name”则表示当前 launch 文档中的变量 “arg-name” 指定的变量在当前 launch 文档以及 included launch 文档中都有相同的值。

参数标签 rosparam

尽管 argument(变量)和 parameter(参数)优势可互换,但二者在 ROS 中的意义完全不同:parameters 是 ROS 系统使用的数值,存在 parameter server 上,nodes 可通过ros::param::get函数编程得到,用户可通过rosparam命令获取;与之不同,arguments 仅在 launch 文档内部有意义,nodes 不能直接获取它们的值

前面介绍的<arg>用于设置变量;接下来介绍的两个<param>和<rosparam>标签用于设置参数。

参数访问有三种方式
1、命令行:
rosparam set、rosparam get

2、launch 文档:
<param>、<rosparam>

3、API方式
roscpp: ros::param::set、ros::param::get
rospy: set_param、set_param

<rosparam>  通过配置文档*.yaml文档加载参数
<rosparam file=”$(find navigation_launch)/config/costmap_common_params.yaml” command=”load” ns=”global_costmap” />

<rosparam> 其他常见方式
<rosparam command=”delete” param=”my/param” />
<rosparam param=”a_list”>[1, 2, 3, 4]</rosparam>
<rosparam>
a: 1
b: 2
</rosparam>

参数标签 param

<param>更像是 define 宏,必须在本地 launch 文档中赋值,无法用于在 launch 文档中获取命令中的参数(但可以通过下面介绍 rosrun 方式接收和传递)。定义的参数均会保留在 ROS 参数服务器(PARAMETERS)中,该参数会被节点(NODES)使用进行节点配置。
<launch>
<param name=”param-name-1″ value=”false” />
<node ….>
<param name=”param-name-2″ value=”…”>
</node>
</launch>
注意区别:第一个参数 param-name-1 ,是整个 launch 全局(global)有效;第二个参数 param-name-2 ,只相对(relative)节点局部(private)有效。

rosrun 本身的设计是可以让使用者直接修改节点内的参数,通过以下的方式:
$ rosrun package-name node-name _param-name:=param-value

rosparam可以使用command属性 :

<arg name=”urdf_file” default=”$(find xacro)/xacro.py ‘$(find turtlebot_description)/robots/$(arg base)_$(arg stacks)_$(arg 3d_sensor).urdf.xacro'” />

<param name=”robot_description” command=”$(arg urdf_file)” />

The output of the command will be read and stored as a string. It is strongly recommended that you use the package-relative $(find)/file.txt syntax to specify file arguments. You should also quote file arguments using single quotes due to XML escaping requirements.

env和optenv 标签

These two are using to modify the environment variables that one or more nodes are executed with.

Using env will force the user to have this variable set (roslaunch would fail if the variable is missing) . If you used the optenv expansion arg to set the value of the argument, then, you’d be able to decide the value of the argument simply by setting an environment variable.

The roslaunch evaluates the XML file in a single pass. Includes are processed in depth-first traversal order. Tags are evaluated serially and the last setting wins. Thus, if there are multiple settings of a parameter, the last value specified for the parameter will be used.
Relying on the override behavior can be brittle. There is no guarantee that an override is specified correctly (e.g. if a parameter name is changed in an included file). Instead, it is recommended that override behavior be done using $(arg)/ settings.

substitution args
Roslaunch tag attributes can make use of substitution args, which roslaunch will resolve prior to launching nodes. The currently supported substitution args are:

1. $(env ENVIRONMENT_VARIABLE)
Substitute the value of a variable from the current environment. The launch will fail if environment variable is not set. This value cannot be overridden by tags.

2. $(optenv ENVIRONMENT_VARIABLE)  $(optenv ENVIRONMENT_VARIABLE default_value)
Substitute the value of an environment variable if it is set. If default_value is provided, it will be used if the environment variable is not set. If default_value is not provided, an empty string will be used. default_value can be multiple words separated by spaces.

Examples:3. $(find pkg)
e.g. $(find rospy)/manifest.xml. Specifies a package-relative path. The filesystem path to the package directory will be substituted inline. Use of package-relative paths is highly encouraged as hard-coded paths inhibit the portability of the launch configuration. Forward and backwards slashes will be resolved to the local filesystem convention.

4. $(anon name)
e.g. $(anon rviz-1). Generates an anonymous id based on name. name itself is a unique identifier: multiple uses of $(anon foo) will create the same “anonymized” name. This is used for name attributes in order to create nodes with anonymous names, as ROS requires nodes to have unique names. For example:

5. $(arg foo)
$(arg foo) evaluates to the value specified by an tag. There must be a corresponding tag in the same launch file that declares the arg.
For example:
Will assign the my_foo argument to the foo parameter.
Another example:Will assign the my_foo argument to the foo parameter.
Another example:

Will launch both the server and client from the example, passing as parameters the value a and b. The resulting launch project can be called as follows:
The resulting launch project can be called as follows:
$ roslaunch beginner_tutorials launch_file.launch a:=1 b:=5

All tags support if and unless attributes, which include or exclude a tag based on the evaluation of a value. “1” and “true” are considered true values. “0” and “false” are considered false values. Other values will error.

TAGs:
1. tag
The tag is the root element of any roslaunch file. Its sole purpose is to act as a container for the other elements.
2. tag
The tag specifies a ROS node that you wish to have launched.
Examples

Launches the “listener1″ node using the listener.py executable from the rospy_tutorials package with the command-line argument –test. If the node dies, it will automatically be respawned.

Launches the bar node from the foo_pkg package. This example uses substitution arguments to pass in a portable reference to baz_pkg/resources/map.pgm.
Attributes includes: pkg=”mypackage”, Package of node. type=”nodetype”, Node type. There must be a corresponding executable with the same name. name=”nodename”, Node name. NOTE: name cannot contain a namespace. Use the ns attribute instead. machine=”machine-name”(optional, see ), Launch node on designated machine. ns=”foo”(optional) ,Start the node in the ‘foo’ namespace. output=”log|screen”(optional), If ‘screen’, stdout/stderr from the node will be sent to the screen. If ‘log’, the stdout/stderr output will be sent to a log file in $ROS_HOME/log, and stderr will continue to be sent to screen. The default is ‘log’.
3. tag
The tag declares a machine that you can run ROS nodes on. You do not need this tag if you are launching all the nodes locally. It is mainly used to declare SSH and ROS environment variable settings for remote machines, though you can also use it to declare information about the local machine.
4. tag
The tag allows you to pass in name remapping arguments to the ROS node that you are launching in a more structured manner than setting the args attribute of a directly.
Example, For example, you are given a node that says it subscribes to the “chatter” topic, but you only have a node that publishes the “hello” topic. They are the same type, and you want to pipe your “hello” topic into the new node which wants “chatter” by simply:
5.tag
Thetag defines a parameter to be set on the Parameter Server.
Examples,
6. tag
The tag enables the use of rosparam YAML files for loading and dumping parameters from the ROS Parameter Server. It can also be used to remove parameters. The tag can be put inside of a tag, in which case the parameter is treated like a private name. The delete and dump commands run before the load command as well as before any other parameters are uploaded to the Parameter Server. delete and dump commands run in the declared order.
Examples
7. The tag
The tag makes it easier to apply settings to a group of nodes. I
8. tag
The tag allows you to create more re-usable and configurable launch files by specifying values that are passed via the command-line, passing in via an , or declared for higher-level files. Args are not global. An arg declaration is specific to a single launch file, much like a local parameter in a method. You must explicitly pass arg values to an included file, much like you would in a method call.
can be used in one of three ways:
, Declares the existence of foo. foo must be passed in either as a command-line argument (if top-level) or via passing (if included).
, Declares foo with a default value. foo can be overriden by command-line argument (if top-level) or via passing (if included).
, Declares foo with constant value. The value for foo cannot be overridden. This usage enables internal parameterization of a launch file without exposing that parameterization at higher levels.
Examples:
my.launch: ## declare var hoge, and assign value, productor

included.launch: ## get value , store t paramserver, consumer

Passing an argument via the command-line:

$ $ roslaunch %YOUR_ROS_PKG% my.launch hoge:=my_new_value

Minimal Example
The following example shows a minimal launch configuration script. It launches a single ‘talker’ node, which is part of the ‘rospy_tutorials’ package. This node will launch on the local machine using the currently configured ROS environment (i.e. ROS_ROOT, etc…).

A Complicated Example

Setting parameters
You can also set parameters on the Parameter Server. These parameters will be stored on the Parameter Server before any nodes are launched.

5 – TIPS FOR LARGE PROJECTS

1. Introduction
Large applications on a robot typically involve several interconnected nodes, each of which have many parameters.
The 2d navigation is a good example. The 2dnav_pr2 application consists of the move_base node itself, localization, ground plane filtering, the base controller, and the map server. Collectively, there are also a few hundred ROS parameters that affect the behavior of these nodes. Finally, there are constraints such as the fact that ground plane filtering should run on the same machine as the tilt laser for efficiency.
A roslaunch file allows us to say all this. Given a running robot, launching the file 2dnav_pr2.launch in the 2dnav_pr2 package will bring up everything required for the robot to navigate. In this tutorial, we’ll go over this launch file and the various features used.
We’d also like roslaunch files to be as reusable as possible. In this case, moving between physically identical robots can be done without changing the launch files at all. Even a change such as moving from the robot to a simulator can be done with only a few changes. We’ll go over how the launch file is structured to make this possible.

2. Top-level organization
Here is the top-level launch file (in “rospack find 2dnav_pr2/move_base/2dnav_pr2.launch”).

This file includes a set of other files. Each of these included files contains nodes and parameters (and possibly nested includes) pertaining to one part of the system, such as localization, sensor processing, and path planning.
Design tip: Top-level launch files should be short, and consist of include’s to other files corresponding to subcomponents of the application, and commonly changed ROS parameters.
This makes it easy to swap out one piece of the system, as we’ll see later.

To run this on the PR2 robot requires bringing up a core, then bringing up a robot-specific launch file such as pre.launch in the pr2_alpha package, and then launching 2dnav_pr2.launch. We could have included a robot launch file here rather than requiring it to be launched separately. That would bring the following tradeoffs:
PRO: We’d have to do one fewer “open new terminal, roslaunch” step.
CON: Launching the robot launch file initiates a calibration phase lasting about a minute long. If the 2dnav_pr2 launch file included the robot launch file, every time we killed the roslaunch (with control-c) and brought it back up, the calibration would happen again.
CON: Some of the 2d navigation nodes require that the calibration already have finished before they start. Roslaunch intentionally does not provide any control on the order or timing of node start up. The ideal solution would be to make nodes work gracefully by waiting till calibration is done, but pending that, putting things in two launch files allows us to launch the robot, wait until calibration is complete, then launch 2dnav.

There is therefore no universal answer on whether or not to split things into multiple launch files. Here, it has been decided to use two different launch files.
Design tip: Be aware of the tradeoffs when deciding how many top-level launch files your application requires.

3. Machine tags and Environment Variables
We would like control over which nodes run on which machines, for load-balancing and bandwidth management. For example, we’d like the amcl node to run on the same machine as the base laser. At the same time, for reusability, we don’t want to hardcode machine names into $ roslaunch files. Roslaunch handles this with ****machine*** tags.

The first include is

The first thing to note about this file is the use of the env substitution argument to use the value of the environment variable ROBOT. For example, doing “$ export ROBOT=pre”
prior to the roslaunch would cause the file pre.machine to be included.
*** Design tip: Use the env substitution argument to allow parts of a launch file to depend on environment variables.

Next, let’s look at an example machine file: pre.machine in the pr2_alpha package.

This file sets up a mapping between logical machine names, “c1” and “c2” in this case, and actual host names, such as “pre2”. It even allows controlling the user you log in as (assuming you have the appropriate ssh credentials).
Once the mapping has been defined, it can be used when launching nodes. For example, the included file config/new_amcl_node.xml in the 2dnav_pr2 package contains the line:

This causes the amcl node to run on machine with logical name c1 (looking at the other launch files, you’ll see that most of the laser sensor processing has been put on this machine).
When running on a new robot, say one known as prf, we just have to change the ROBOT environment variable. The corresponding machine file (prf.machine in the pr2_alpha package) will then be loaded. We can even use this for running on a simulator, by setting ROBOT to sim. Looking at the file sim.machine in the pr2_alpha package, we see that it just maps all logical machine names to localhost.
*** Design tip: Use machine tags to balance load and control which nodes run on the same machine, and consider having the machine file name depend on an environment variable for reusability.

4. Parameters, namespaces, and yaml files
Let’s look at the included file move_base.xml. Here is a portion of this file:

The first included element is a remapping. Move_base is designed to receive odometry on the topic “odom”. In the case of the pr2, odometry is published on the pr2_base_odometry topic, so we remap it.
*** Design tip: Use topic remapping when a given type of information is published on different topics in different situations.
Then is followed by a bunch oftags. Note that these parameters are inside the node element (since they’re before the at the end), so they will be private parameters. For example, the first one sets move_base/controller_frequency to 10.0.
After theelements, there are some elements. These read parameter data in yaml, a format which is human readable and allows complex data structures.
Here’s a portion of the costmap_common_params.yaml file loaded by the first element:
raytrace_range: 3.0
footprint: [[-0.325, -0.325], [-0.325, 0.325], [0.325, 0.325], [0.46, 0.0], [0.325, -0.325]]
inflation_radius: 0.55
We see that yaml allows things like vectors (for the footprint parameter). It also allows putting some parameters into a nested namespace. For example, base_scan_marking/sensor_frame is set to base_laser. Note that these namespaces are relative to the yaml file’s own namespace, which was declared as global_costmap by the ns attribute of the including rosparam element. In turn, since that rosparam was included by the node element, the fully qualified name of the parameter is /move_base/global_costmap/base_scan_marking/sensor_frame.
# BEGIN VOXEL STUFF
observation_sources: base_scan_marking base_scan tilt_scan ground_object_cloud
base_scan_marking: {sensor_frame: base_laser, topic: /base_scan_marking, data_type: PointCloud, expected_update_rate: 0.2,
observation_persistence: 0.0, marking: true, clearing: false, min_obstacle_height: 0.08, max_obstacle_height: 2.0}
We see that yaml allows things like vectors (for the footprint parameter). It also allows putting some parameters into a nested namespace. For example, base_scan_marking/sensor_frame is set to base_laser. Note that these namespaces are relative to the yaml file’s own namespace, which was declared as global_costmap by the ns attribute of the including rosparam element. In turn, since that rosparam was included by the node element, the fully qualified name of the parameter is /move_base/global_costmap/base_scan_marking/sensor_frame.

The next line in move_base.xml is:

This actually includes the exact same yaml file as the line before it. It’s just in a different namespace (the local_costmap namespace is for the trajectory controller, while the global_costmap namespace affects the global navigation planner). This is much nicer than having to retype all the values.

The next line is:

Unlike the previous ones, this element doesn’t have an ns attribute. Thus the yaml file’s namespace is the parent namespace, /move_base.
But take a look at the first few lines of the yaml file itself:
local_costmap:
#Independent settings for the local costmap
publish_voxel_map: true
global_frame: odom_combined
robot_base_frame: base_link
Thus we see that the parameters are in the /move_base/local_costmap namespace after all.
*** Design tip: Yaml files allow parameters with complex types, nested namespaces of parameters, and reusing the same parameter values in multiple places.

5. Reusing launch files
The motivation for many of the tips above was to make reusing launch files in different situations easier. We’ve already seen one example, where the use of the env substitution arg can allow modifying behavior without changing any launch files. There are some situations, though, where that’s inconvenient or impossible. Let’s take a look at the pr2_2dnav_gazebo package. This contains a version of the 2d navigation app, but for use in the Gazebo simulator. For navigation, the only thing that changes is actually that the Gazebo environment we use is based on a different static map, so the map_server node must be loaded with a different argument. We could have used another env substitution here. But that would require the user to set a bunch of environment variables just to be able to roslaunch. Instead, 2dnav gazebo contains its own top level launch file called ‘2dnav-stack-amcl.launch’, shown here (modified slightly for clarity):

The first difference is that, since we know we’re on the simulator, we just use the sim.machine file rather than using a substitution argument.
Second, the line

has been replaced by

The included file in the first case just contained a node declaration as in the second case, but with a different map file.
*** Design tip: To modify a “top-level” aspect of an application, copy the top level launch file and change the portions you need.

6. Parameter overrides
The technique above sometimes becomes inconvenient. Suppose we want to use 2dnav_pr2, but just change the resolution parameter of the local costmap to 0.5. We could just locally change local_costmap_params.yaml. This is the simplest for temporary modifications, but it means we can’t check the modified file back in. We could instead make a copy of local_costmap_params.yaml and modify it. We would then have to change move_base.xml to include the modified yaml file. And then we would have to change 2dnav_pr2.launch to include the modified move_base.xml. This can be time-consuming, and if using version control, we would no longer see changes to the original files. An alternative is to restructure the launch files so that the move_base/local_costmap/resolution parameter is defined in the top-level file 2dnav_pr2.launch, and make a modified version of just that file. This is a good option if we know in advance which parameters are likely to be changed.
Another option is to use roslaunch’s overriding behavior: parameters are set in order (after includes are processed). Thus, we could make a further top-level file that overrides the original resolution:

The main drawback is that this method can make things harder to understand: knowing the actual value that roslaunch sets for a parameter requires tracing through the including roslaunch files. But it does avoid having to make copies of multiple files.
*** Design tip: To modify a deeply nested parameter in a tree of launch files which you cannot change, use roslaunch’s parameter overriding semantics.

7. Roslaunch arguments
As of CTurtle, roslaunch has an argument substitution feature together with tags that allow conditioning parts of the launch file on the value of arguments. This can be a more general and clear way to structure things than the parameter override mechanism or launch file reuse techniques above, at the cost of having to modify the original launch file to specify what the changeable arguments are. See the roslaunch XML documentation.

Design tip: If you can modify the original launch file, it’s often preferable to use roslaunch arguments rather than parameter overriding or copying roslaunch files.

0 回复

发表评论

Want to join the discussion?
Feel free to contribute!

发表评论