Note
.xml
文件在 ROS1 下无法被roslaunch
识别而补全
🔧 用例 1: namespace
<!-- ROS1 -->
<group ns="map">
<include file="$(find map_loader)/launch/lanelet2_map_loader.launch">
<arg name="file_name" default="$(arg lanelet2_map_path)"/>
</include>
</group>
<!-- ROS2 -->
<group>
<push-ros-namespace namespace="map"/>
<include file="$(find-pkg-share map_loader)/launch/lanelet2_map_loader.launch.xml">
<arg name="lanelet2_map_path" value="$(var lanelet2_map_path)"/>
</include>
</group>
🔧 用例 1: substitution
ROS1 | ROS2 | 备注 |
---|---|---|
$(arg 变量名) | $(var 变量名) | —— |
$(find-pkg-share 包名) | $(find 包名) | substitutions(ROS2 的需要安装到 install) |
具体参考 ROS1
🔧 用例 1: arg 标签
ROS1 | ROS2 |
---|---|
type | exec |
ns | namespace |
doc | description |
machine, respawn_delay, clear_params | — |
在 ROS2 中对某个变量进行赋值,将使用 let 标签
<arg name="foo" value="foo"/> <!-- ROS1 -->
<let name="foo" value="foo"/> <!--ROS2-->
🔧 用例 3: group 标签
1)scope:相关作用类似于作用域,表示其中的配置参数在 group 外是否还能被使用,默认值为 true,表示该变量的作用域只局限于 group 内部
<group scoped="false">
<!-- TODO -->
</group>
2)条件判断
<arg name="mode" default="..."/>
<group if="$(eval mode=='...')">TODO</group>
🔧 用例 4: rosparam 和 param
ROS1 | ROS2 | 备注 |
---|---|---|
rosparam tag | param tag | —— |
<!-- ROS1 -->
<node pkg="my_package" exec="my_executable" name="my_node" ns="/an_absolute_ns">
<rosparam command="load" file="/path/to/file"/>
</node>
<!-- ROS2 -->
<node pkg="my_package" exec="my_executable" name="my_node" ns="/an_absoulute_ns">
<param from="/path/to/file"/>
</node>
[!note]
ROS2 没有全局参数的概念,param 标签只能嵌套放在 node 等标签中,同时该标签也没有 type 等属性
🔧 用例 1: 启动一个节点
import launch
import launch_ros.actions
from launch import LaunchDescription
# 方案一:
def generate_launch_description():
return launch.LaunchDescription([
launch.actions.DeclareArgument(name='log_level', default_value='info'),
launch_ros.actions.Node(
package='包名',
executable='可执行文件名',
name='节点名',
remappings=[
("input/initialpose", "/initialpose3d"),
("input/ackermann_control_command", "/control/command/control_cmd")
],
parameters=[{
参数名: 参数值
}],
arguments=['--ros-args', '--log-level', LaunchConfiguration('log_level')], output="screen"
)
])
# 方案二:
def generate_launch_description():
ld = LaunchDescription()
node = Node(package="包名",
executable="static_transform_publisher",
arguments=["0", "0", "0", "0", "0", "0", "odom", "laser"])
ld.add_action(node)
return ld
🔧 用例 2: 基于命令设置 param 参数
set_prarm = ExecuteProcess(
cmd=[['ros2 param set ', 节点名, '参数名 参数值']], shell=True)
🔧 用例 3: 导入参数文件
import yaml
behavior_velocity_planner_param_path = os.path.join(
# .perform(context) 相当于$(find <包名>)
LaunchConfiguration("tier4_planning_launch_param_path").perform(context),
"scenario_planning",
"lane_driving",
"behavior_planning",
"behavior_velocity_planner",
"behavior_velocity_planner.param.yaml",
)
with open(behavior_velocity_planner_param_path, "r") as f:
behavior_velocity_planner_param = yaml.safe_load(f)["/**"]["ros__parameters"]
# 导入参数:
parameters = [
behavior_velocity_planner_param,
...]
🔧 用例 4: 设置定时器对象
from launch.actions import ExecuteProcess, TimerAction
TimerAction(
period=2.0,
actions=[ExecuteProcess(...)],
)
Note
roslaunch
在启动节点前,会提前解析 substitution args
和导入参数 param
到参数服务器
🔧 用例 1: 使某些 launch 文件不被 roslaunch 识别(hide the launch files only intended to be included from the tab completion)
将 .launch 文件的后缀名改为 .launch.xml
- VSCode 插件:ROS snippets(代码块)
- VSCode 插件:Xml Formatter(格式化 XML 文件)
- ROS2 Launch File Migrator:将 ROS1 的 launch.xml 文件转换为 ROS2 的 launch.py 文件
- XML Format for ROS2
- Migration tutorials