简化节点的配置与启动,提高程序的启动效率。
1、Launch的基本使用流程
1-1.C++实现
1.编写Launch文件
python格式launch文件 XML格式Launch文件 YAML格式Launch文件
2.编辑配置文件
在CMakeList.txt中添加语句: intall(DIRECTORY launch DESTINATION share/${PROJECT_NAME})
3.编译
编译功能包: colcon builid --packages-select 功能包
4.执行
. install/setup.bash ros2 run 功能包 Launch文件
2.Python实现
1.编写Launch文件
python格式launch文件 XML格式Launch文件 YAML格式Launch文件
2.编辑配置文件
编辑setup.py文件,在data_files属性中添加Launch文件的路径
from setuptools import setup from glob import glob package_name = 'py01_launch' setup( name=package_name, version='0.0.0', packages=[package_name], data_files=[ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), # launch 文件相关配置 ('share/' + package_name, glob("launch/py/*.launch.py")), ('share/' + package_name, glob("launch/xml/*.launch.xml")), ('share/' + package_name, glob("launch/yaml/*.launch.yaml")) ], install_requires=['setuptools'], zip_safe=True, maintainer='ros2', maintainer_email='[email protected]', description='TODO: Package description', license='TODO: License declaration', tests_require=['pytest'], entry_points={ 'console_scripts': [ ], }, )
3.编译
编译功能包: colcon builid --packages-select 功能包
4.执行
. install/setup.bash ros2 run 功能包 Launch文件
注意:
对于带有启动文件的功能包,最好在功能包的package.xml中添加对包,这有助于确保在构建功能包后ros2 launch命令可用。它还确保可以识别不同格式的 launch 文件。<exec_depend>ros2launch</exec_depend>
2、Launch文件的Python实现
{
// Place your snippets for python here. Each snippet is defined under a snippet name and has a prefix, body and
// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the
// same ids are connected.
// Example:
// "Print to console": {
// "prefix": "log",
// "body": [
// "console.log('$1');",
// "$2"
// ],
// "description": "Log output to console"
// }
"ros2 node": {
"prefix": "ros2_node_py",
"body": [
"\"\"\" ",
" 需求:",
" 流程:",
" 1.导包;",
" 2.初始化ROS2客户端;",
" 3.自定义节点类;",
" ",
" 4.调用spain函数,并传入节点对象;",
" 5.资源释放。",
"",
"",
"\"\"\"",
"# 1.导包;",
"import rclpy",
"from rclpy.node import Node",
"",
"# 3.自定义节点类;",
"class MyNode(Node):",
" def __init__(self):",
" super().__init__(\"mynode_node_py\")",
"",
"def main():",
" # 2.初始化ROS2客户端;",
" rclpy.init()",
" # 4.调用spain函数,并传入节点对象;",
" rclpy.spin(MyNode())",
" # 5.资源释放。",
" rclpy.shutdown()",
"",
"if __name__ == '__main__':",
" main()",
],
"description": "ros2 node"
},
"ros2 launch py": {
"prefix": "ros2_launch_py",
"body": [
"from launch import LaunchDescription",
"from launch_ros.actions import Node",
"# 封装终端指令相关类--------------",
"# from launch.actions import ExecuteProcess",
"# from launch.substitutions import FindExecutable",
"# 参数声明与获取-----------------",
"# from launch.actions import DeclareLaunchArgument",
"# from launch.substitutions import LaunchConfiguration",
"# 文件包含相关-------------------",
"# from launch.actions import IncludeLaunchDescription",
"# from launch.launch_description_sources import PythonLaunchDescriptionSource",
"# 分组相关----------------------",
"# from launch_ros.actions import PushRosNamespace",
"# from launch.actions import GroupAction",
"# 事件相关----------------------",
"# from launch.event_handlers import OnProcessStart, OnProcessExit",
"# from launch.actions import ExecuteProcess, RegisterEventHandler,LogInfo",
"# 获取功能包下share目录路径-------",
"# from ament_index_python.packages import get_package_share_directory",
"",
"def generate_launch_description():",
" ",
" return LaunchDescription([])"
],
"description": "ros2 launch"
}
}
2-1.节点设置
from launch import LaunchDescription from launch_ros.actions import Node import os from ament_index_python.packages import get_package_share_directory def generate_launch_description(): turtle1 = Node(package="turtlesim", executable="turtlesim_node", namespace="ns_1", name="t1", exec_name="turtle_label", # 表示流程的标签 respawn=True)#设置为True时,关闭节点后,可以自动重启 turtle2 = Node(package="turtlesim", executable="turtlesim_node", name="t2", # 参数设置方式1 # parameters=[{"background_r": 0,"background_g": 0,"background_b": 0}], # 参数设置方式2: 从 yaml 文件加载参数,yaml 文件所属目录需要在配>置文件中安装。 parameters=[os.path.join(get_package_share_directory("cpp01_launch"),"config","t2.yaml")]>, ) turtle3 = Node(package="turtlesim", executable="turtlesim_node", name="t3", remappings=[("/turtle1/cmd_vel","/cmd_vel")] #话题重映射 ) rviz = Node(package="rviz2", executable="rviz2", # 节点启动时传参 arguments=["-d", os.path.join(get_package_share_directory("cpp01_launch"),"config","my.rviz")] ) turtle4 = Node(package="turtlesim", executable="turtlesim_node", # 节点启动时传参,相当于 arguments 传参时添加前缀 --ros-args ros_arguments=["--remap", "__ns:=/t4_ns", "--remap", >"__node:=t4"] ) return LaunchDescription([turtle1, turtle2, turtle3, rviz, turtle4])
2-2.执行指令
from launch import LaunchDescription from launch_ros.actions import Node from launch.actions import ExecuteProcess from launch.substitutions import FindExecutable def generate_launch_description(): turtle = Node(package="turtlesim", executable="turtlesim_node") spawn = ExecuteProcess( # cmd=["ros2 service call /spawn turtlesim/srv/Spawn \"{x: 8.0, y: 9.0,theta: 0.0, name: 'turtle2'}\""], # 或 cmd = [ FindExecutable(name = "ros2"), # 不可以有空格 " service call", " /spawn turtlesim/srv/Spawn", " \"{x: 8.0, y: 9.0,theta: 1.0, name: 'turtle2'}\"" ], output="both", shell=True) return LaunchDescription([turtle,spawn]) /* cmd:被执行的命令 output:设置为"both"时,日志会被输出到日志文件和终端,默认为log,日志只输出到日志文件。 shell:如果为True,就以shell的方式执行命令。 */
2-3.参数设置
from pkg_resources import declare_namespace from launch import LaunchDescription from launch_ros.actions import Node from launch.actions import DeclareLaunchArgument#参数声明 from launch.substitutions import LaunchConfiguration#参数调用 def generate_launch_description(): #DeclareLaunchArgument对象会声明三个参数,每个参数都有默认值 #name 参数名称 #default_value 默认值 decl_bg_r = DeclareLaunchArgument(name="background_r",default_value="255") decl_bg_g = DeclareLaunchArgument(name="background_g",default_value="255") decl_bg_b = DeclareLaunchArgument(name="background_b",default_value="255") #LaunchConfiguration对象获取参数值 #variable_name 被解析的参数名称 turtle = Node(package="turtlesim", executable="turtlesim_node", parameters=[{"background_r": LaunchConfiguration("background_r"), "background_g": LaunchConfiguration("background_g"), "background_b": LaunchConfiguration("background_b")}] ) return LaunchDescription([decl_bg_r,decl_bg_g,decl_bg_b,turtle])
动态传入参数:
ros2 launch cpp01_launch py03_args.launch.py background_r:=200 background_g:=200 background_b:=200
2-4.文件包含
from launch import LaunchDescription from launch.actions import IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource import os from ament_index_python import get_package_share_directory def generate_launch_description(): #IncludeLaunchDescription对象包含两个参数: #1、launch_description_source:用于被设置的Launch文件 #PythonLaunchDescription对象中设置被包含的Launch文件的路径 #2、Launch_arguments:设置参数,包括参数的键和值。 include_launch = IncludeLaunchDescription( launch_description_source= PythonLaunchDescriptionSource( launch_file_path=os.path.join( get_package_share_directory("cpp01_launch"), "launch/py", "py03_args.launch.py" ) ), launch_arguments={ "background_r": "200", "background_g": "100", "background_b": "70", }.items() ) return LaunchDescription([include_launch])
2-5.分组设置
from launch import LaunchDescription from launch_ros.actions import Node from launch_ros.actions import PushRosNamespace from launch.actions import GroupAction #1、GroupAction对象中: #1、action列表:被包含到组内的命名空间、节点等 #1、PushRosNamespace对象中: #1、namespace:当前组使用的命名空间 def generate_launch_description(): turtle1 = Node(package="turtlesim",executable="turtlesim_node",name="t1") turtle2 = Node(package="turtlesim",executable="turtlesim_node",name="t2") turtle3 = Node(package="turtlesim",executable="turtlesim_node",name="t3") g1 = GroupAction(actions=[PushRosNamespace(namespace="g1"),turtle1, turtle2]) g2 = GroupAction(actions=[PushRosNamespace(namespace="g2"),turtle3]) return LaunchDescription([g1,g2])
2-6.添加事件
from launch import LaunchDescription from launch_ros.actions import Node from launch.actions import ExecuteProcess, RegisterEventHandler,LogInfo from launch.substitutions import FindExecutable from launch.event_handlers import OnProcessStart, OnProcessExit def generate_launch_description(): turtle = Node(package="turtlesim", executable="turtlesim_node") spawn = ExecuteProcess( cmd = [ FindExecutable(name = "ros2"), # 不可以有空格 " service call", " /spawn turtlesim/srv/Spawn", " \"{x: 8.0, y: 1.0,theta: 1.0, name: 'turtle2'}\"" ], output="both", shell=True) #RegisterEventHandler负责注册事件:参数为 event_handler 注册的事件对象 #OnProcessStart是启动对象:参数为 1、target_action 被注册的目标对象 2、on_start 事件触发时的执行逻辑 #OnProcessExit是退出事件对象: 参数为 1、target_action 被注册时的目标对象 2、on_exit 事件触发时的执行逻辑 #Loginfo是日志输出对象 参数为 msg 被输出的日志信息 start_event = RegisterEventHandler( event_handler=OnProcessStart( target_action = turtle, on_start = spawn ) ) exit_event = RegisterEventHandler( event_handler=OnProcessExit( target_action = turtle, on_exit = [LogInfo(msg = "turtlesim_node退出!")] ) ) return LaunchDescription([turtle,start_event,exit_event])
3、Launch文件的xml、yaml实现
3-1.节点设置
3-1-1.XML实现
<launch> <node pkg="turtlesim" exec="turtlesim_node" name="t1" namespace="t1_ns" exec_name="t1_label" respawn="true"/> <node pkg="turtlesim" exec="turtlesim_node" name="t2"> <param from="$(find-pkg-share cpp01_launch)/config/t2.yaml" /> node> <node pkg="turtlesim" exec="turtlesim_node" name="t3"> <remap from="/turtle1/cmd_vel" to="/cmd_vel" /> node> <node pkg="turtlesim" exec="turtlesim_node" ros_args="--remap __name:=t4 --remap __ns:=/group_2" /> <node pkg="rviz2" exec="rviz2" args="-d $(find-pkg-share cpp01_launch)/config/my.rviz" /> launch> pkg:功能包 exec:可执行文件 name:节点名称 namespace:命名空间 exec_name:流程标签 respwan:节点关闭后是否重启 args:调用指令时的参数列表 ros_args:相当于args前加上--ros-args node标签的子级标签包含: param: from:参数文件路径 remap: from 旧话题名称 to 新话题名称
3-1-2.YAML实现
launch: - node: pkg: "turtlesim" exec: "turtlesim_node" name: "t1" namespace: "t1_ns" exec_name: "t1_label" respawn: "false" - node: pkg: "turtlesim" exec: "turtlesim_node" name: "t2" param: # - # name: "background_r" # value: 255 # - # name: "background_b" # value: 255 - from: "$(find-pkg-share cpp01_launch)/config/t2.yaml" - node: pkg: "turtlesim" exec: "turtlesim_node" remap: - from: "/turtle1/cmd_vel" to: "/cmd_vel" - node: pkg: "turtlesim" exec: "turtlesim_node" ros_args: "--ros-args --remap __name:=t4 --remap __ns:=/t4" - node: pkg: "rviz2" exec: "rviz2" args: "-d $(find-pkg-share cpp01_launch)/config/my.rviz"
3-2.执行指令
3-2-1.XML实现
<launch> <node pkg="turtlesim" exec="turtlesim_node" /> <executable cmd="ros2 run turtlesim turtlesim_node" output="both" /> launch> exeutable:cmd 被执行的命令 output 日志输出目的地设置
3-2-2.YAML实现
launch: - executable: cmd: "ros2 run turtlesim turtlesim_node" output: "both"
3-3.参数设置
3-3-1.XML实现
<launch> <arg name="bg_r" default="255"/> <arg name="bg_g" default="255"/> <arg name="bg_b" default="255"/> <node pkg="turtlesim" exec="turtlesim_node"> <param name="background_r" value="$(var bg_r)" /> <param name="background_g" value="$(var bg_g)" /> <param name="background_b" value="$(var bg_b)" /> node> launch> 声明参数:arg标签 name 参数名称 default 参数默认值 调用参数:$(var 参数名称)
3-3-2.YAML实现
launch: - arg: name: "bgr" default: "255" - node: pkg: "turtlesim" exec: "turtlesim_node" param: - name: "background_r" value: $(var bgr)
3-4.文件包含
3-4-1.XML实现
<launch> <let name="bg_r" value="0" /> <include file="$(find-pkg-share cpp01_launch)/launch/xml/xml03_args.launch.xml"/> launch> 标签:include 用于实现文件包含 属性:file:被包含的Launch文件路径 标签:let 用于向被包含的Launch文件导入参数 属性:name:参数名称 value:参数值
3-4-2.YAML实现
launch: - let: name: "bgr" value: "255" - include: file: "$(find-pkg-share cpp01_launch)/launch/yaml/yaml03_arg.launch.yaml"
3-5.分组设置
3-5-1.XML实现
<launch> <group> <push_ros_namespace namespace="g1" /> <node pkg="turtlesim" exec="turtlesim_node" name="t1"/> <node pkg="turtlesim" exec="turtlesim_node" name="t2"/> group> <group> <push_ros_namespace namespace="g2" /> <node pkg="turtlesim" exec="turtlesim_node" name="t3"/> group> launch> 标签:group 用于分组 标签:push_ros_namespace 通过namespace属性设置组内节点使用的命名空间
3-5-2.YAML实现
launch: - group: - push_ros_namespace: namespace: "g1" - node: pkg: "turtlesim" exec: "turtlesim_node" name: "t1" - node: pkg: "turtlesim" exec: "turtlesim_node" name: "t2" - group: - push_ros_namespace: namespace: "g2" - node: pkg: "turtlesim" exec: "turtlesim_node" name: "t3"