第120篇 ROS2 Launch进阶——参数传递、条件启动和节点编排
上篇讲了launch文件的基础用法。这篇讲几个进阶技巧都是实际项目中经常用到的。面试的时候如果你能说出这些细节面试官会觉得你真的做过项目不是只看了教程。事件系统节点启动顺序控制launch文件里的节点默认是同时启动的。但有些场景需要控制顺序比如地图服务器必须先启动并加载完地图导航节点才能启动。ROS2的launch事件系统可以处理这种依赖关系from launch import LaunchDescription from launch.actions import EmitEvent, RegisterEventHandler from launch.events import EventHandler from launch_ros.event_handlers import OnProcessExit def generate_launch_description(): map_server Node( packagenav2_map_server, executablemap_server, parameters[{yaml_filename: map.yaml}] ) # 地图服务器退出后启动导航 nav_lifecycle RegisterEventHandler( OnProcessExit( target_actionmap_server, on_exit[ Node( packagenav2_lifecycle_manager, executablelifecycle_manager, parameters[{node_names: [map_server, navigator]}] ) ] ) ) return LaunchDescription([ map_server, nav_lifecycle ])OnProcessExit监听某个进程的退出事件退出后执行后续动作。这在需要先初始化再启动的场景中很有用。TimerAction延迟启动有时候不是等某个节点退出而是单纯想延迟几秒再启动某个节点。比如等所有传感器驱动都初始化完成后再启动融合节点from launch.actions import TimerAction fusion_delayed TimerAction( period5.0, actions[ Node( packagemy_robot, executablesensor_fusion, outputscreen ) ] )period是延迟秒数。这个方案虽然简单粗暴但在很多场景下够用了。比在代码里写time.sleep(5)优雅得多因为延迟逻辑集中在launch文件里一目了然。ExecuteProcess运行非ROS命令launch文件不只是启动ROS节点。你可以通过ExecuteProcess运行任何系统命令from launch.actions import ExecuteProcess # 启动Gazebo gazebo ExecuteProcess( cmd[gazebo, --verbose, -s, libgazebo_ros_init.so, world/my_world.world], outputscreen ) # 设置环境变量 set_env ExecuteProcess( cmd[bash, -c, export ROS_DOMAIN_ID42], outputscreen )这在需要启动第三方工具或者设置环境的时候很有用。比如启动Gazebo仿真、运行数据录制脚本、设置网络配置等。OpaqueFunction动态生成Launch描述如果你需要根据运行时的条件动态决定启动哪些节点用OpaqueFunctionfrom launch.actions import OpaqueFunction def load_config(context, *args, **kwargs): config_file LaunchConfiguration(config_file).perform(context) # 从YAML文件读取节点列表动态创建Node对象 nodes create_nodes_from_yaml(config_file) return nodes这个例子从YAML配置文件动态读取要启动的节点列表。不同的配置文件可以启动完全不同的节点组合不需要写多个launch文件。GroupAction分组管理节点多的时候可以用GroupAction把相关节点分组from launch.actions import GroupAction sensor_group GroupAction([ Node(packagemy_robot, executablelidar_driver), Node(packagemy_robot, executablecamera_driver), Node(packagemy_robot, executableimu_driver), ]) nav_group GroupAction([ Node(packagenav2, executableplanner), Node(packagenav2, executablecontroller), ])分组之后可以对整组做操作比如统一设置命名空间或者条件启动sensor_group GroupAction( actions[...], conditionIfCondition(LaunchConfiguration(use_real_sensors)) )实际项目的Launch结构在我们项目中launch文件分三层第一层是system.launch.py总入口。它根据参数use_sim、robot_type决定加载哪些子系统。第二层是子系统launch文件sensors.launch.py、navigation.launch.py、manipulation.launch.py。每个子系统内部自己管理节点启动顺序和参数。第三层是具体节点的launch文件通常不直接使用被第二层包含。配置文件放在config/目录下按机器人型号分config/robot_a/、config/robot_b/。不同机器人加载不同的配置。面试中怎么聊面试官问launch进阶你可以说ROS2 launch支持事件系统控制节点启动顺序TimerAction延迟启动ExecuteProcess运行系统命令OpaqueFunction动态生成节点配置。实际项目中launch文件分三层管理配合YAML配置文件实现不同机器人型号的快速切换。Launch高级功能实战Launch文件中有一些高级但很实用的功能。ExecuteProcess可以运行非ROS的命令比如启动Gazebo仿真器TimerAction可以延迟启动某些节点等底层服务准备好GroupAction可以把一组节点放在同一个命名空间下。还有条件启动可以根据参数决定是否启动某个组件。这些功能在构建复杂的机器人系统时非常有用。补充一个实战技巧在复杂的Launch系统中用OpaqueFunction可以执行任意Python代码适合需要根据运行时条件动态决定启动逻辑的场景。比如根据环境变量或参数文件的内容来决定启动哪些节点。给你的建议把你项目的launch文件按三层结构重新组织。把硬编码的参数提取到配置文件里。加上use_sim参数支持仿真和实机切换。这些改进做一次就行但会让后续的开发和调试效率提升很多。多花时间在launch文件的组织上回报是非常可观的。上一篇第119篇 ROS2 Launch系统入门——一键启动你的机器人下一篇预告第121篇 ROS2消息类型——std_msgs/sensor_msgs/geometry_msgs详解

相关新闻