Ros2_学习整理_7_Launch文件编写(赵虚左老师)

Ros2_Launch文件编写

简化节点的配置与启动,提高程序的启动效率。
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"

你可能感兴趣的:(Ros2理论与实践,机器人,c++,python,人工智能,学习方法,ros2)