【ROS2】☆ launch之Python

devtools/2025/1/8 19:38:30/

 

☆重点 

        ROS1和ROS2其中一个很大区别之一就是launch的编写方式。在ROS1中采用xml格式编写launch,而ROS2保留了XML 格式launch,还另外引入了Python和YAML 编写方式。选择哪种编写取决于每位开发人员的爱好,但是ROS2官方推荐使用Python方式编写,理由如下:Python 是一种脚本语言,使用灵活,Python库强大,可以直接引入:ROS2launch框架本身是用Python编写,由于亲和力高Python可以直接调用一些高级特性 ,而XML 和 YAML 可能无法调用。

        当然用 Python 编写的启动文件可能比 XML 或 YAML 编写的启动文件更复杂、更冗长。

        不过建议能使用Python编写尽量使用Python,不要问为什么,问就是官方推荐!

在使用Python版的launch文件时,涉及的API众多,为了提高编码效率,可以在VScode中设置launch文件的代码模板,将VScode的配置文件python.json修改为为如下内容:

python">    "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"}

一、节点设置

launch 中需要执行的节点被封装为了 launch_ros.actions.Node 对象。

示例:新建 py01_node.launch.py 文件,输入如下内容:

python">from launch import LaunchDescription
from launch_ros.actions import Node
import os
from ament_index_python.packages import get_package_share_directorydef generate_launch_description():turtle1 = Node(package="turtlesim", executable="turtlesim_node", namespace="ns_1",name="t1", exec_name="turtle_label", # 表示流程的标签respawn=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])

代码解释

1.1 Node使用语法1
python">turtle1 = Node(package="turtlesim", executable="turtlesim_node", namespace="group_1", name="t1", exec_name="turtle_label", # 表示流程的标签respawn=True)

上述代码会创建一个 turtlesim_node 节点,设置了若干节点属性,并且节点关闭后会自动重启。

  • package:功能包;
  • executable:可执行文件;
  • namespace:命名空间;
  • name:节点名称;
  • exe_name:流程标签;
  • respawn:设置为True时,关闭节点后,可以自动重启。
1.2 Node使用语法2
python">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")],)

上述代码会创建一个 turtlesim_node 节点,并导入背景色相关参数。

  • parameters:导入参数。

parameter 用于设置被导入的参数,如果是从 yaml 文件加载参数,那么需要先准备 yaml 文件,在功能包下新建 config 目录,config目录下新建 t2.yaml 文件,并输入如下内容:

python">/t2:ros__parameters:background_b: 0background_g: 0background_r: 50qos_overrides:/parameter_events:publisher:depth: 1000durability: volatilehistory: keep_lastreliability: reliableuse_sim_time: false

注意,还需要在 CMakeLists.txt 中安装 config:

install(DIRECTORY launchconfigDESTINATION share/${PROJECT_NAME})
1.3 Node使用语法3
python">turtle3 = Node(package="turtlesim", executable="turtlesim_node", name="t3", remappings=[("/turtle1/cmd_vel","/cmd_vel")] #话题重映射)

上述代码会创建一个 turtlesim_node 节点,并将话题名称从 /turtle1/cmd_vel 重映射到 /cmd_vel。

  • remappings:话题重映射。
1.4 Node使用语法4
python">rviz = Node(package="rviz2",executable="rviz2",# 节点启动时传参arguments=["-d", os.path.join(get_package_share_directory("cpp01_launch"),"config","my.rviz")])

上述代码会创建一个 rviz2 节点,并加载了 rviz2 相关的配置文件。

该配置文件可以先启动 rviz2 ,配置完毕后,保存到 config 目录并命名为 my.rviz。

  • arguments:调用指令时的参数列表。
1.5 Node使用语法5
python">turtle4 = Node(package="turtlesim", executable="turtlesim_node",# 节点启动时传参,相当于 arguments 传参时添加前缀 --ros-args ros_arguments=["--remap", "__ns:=/t4_ns", "--remap", "__node:=t4"])

上述代码会创建一个 turtlesim_node 节点,并在指令调用时传入参数列表。

  • ros_arguments:相当于 arguments 前缀 --ros-args。

二、执行指令

launch 中需要执行的命令被封装为了 launch.actions.ExecuteProcess 对象。

示例:新建 py02_cmd.launch.py 文件,输入如下内容:

python">from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import ExecuteProcess
from launch.substitutions import FindExecutabledef 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])

代码解释

python">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)

上述代码用于执行 cmd 参数中的命令,该命令会在 turtlesim_node 中生成一只新的小乌龟。

  • cmd:被执行的命令;
  • output:设置为 both 时,日志会被输出到日志文件和终端,默认为 log,日志只输出到日志文件。
  • shell:如果为 True,则以 shell 的方式执行命令。

三、参数设置

参数设置主要涉及到参数的声明与调用两部分,其中声明被封装为 launch.actions.DeclareLaunchArgument,调用则被封装为 launch.substitutions import LaunchConfiguration。

需求:启动turtlesim_node节点时,可以动态设置背景色。

示例:新建 py03_args.launch.py 文件,输入如下内容:

python">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 LaunchConfigurationdef generate_launch_description():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")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])

代码解释

python">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")

上述代码会使用DeclareLaunchArgument对象声明三个参数,且每个参数都有参数名称以及默认值。

  • name:参数名称;
  • default_value:默认值。
parameters=[{"background_r": LaunchConfiguration(variable_name="background_r"), "background_g": LaunchConfiguration("background_g"), "background_b": LaunchConfiguration("background_b")}]

上述代码会使用LaunchConfiguration对象获取参数值。

  • variable_name:被解析的参数名称。

launch文件执行时,可以动态传入参数,示例如下:

ros2 launch cpp01_launch py03_args.launch.py background_r:=200 background_g:=80 background_b:=30

如果执行launch文件时不手动传入参数,那么解析到的参数值是声明时设置的默认值。

四、文件包含

在 launch 文件中可以包含其他launch文件,需要使用的API为:launch.actions.IncludeLaunchDescription 和 launch.launch_description_sources.PythonLaunchDescriptionSource。

需求:新建 launch 文件,包含 4.2.3 中的 launch 文件并为之传入设置背景色相关的参数。

示例:新建 py04_include.launch.py 文件,输入如下内容:

python">from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSourceimport os
from ament_index_python import get_package_share_directorydef generate_launch_description():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])

代码解释

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())

上述代码将包含一个launch文件并为launch文件传参。

在 IncludeLaunchDescription 对象中:

  • launch_description_source:用于设置被包含的 launch 文件;
  • launch_arguments:元组列表,每个元组中都包含参数的键和值。

在 PythonLaunchDescriptionSource 对象中:

  • launch_file_path:被包含的 launch 文件路径。

五、分组设置

在 launch 文件中,为了方便管理可以对节点分组,分组相关API为:launch.actions.GroupAction和launch_ros.actions.PushRosNamespace。

需求:对 launch 文件中的多个 Node 进行分组。

示例:新建 py05_group.launch.py 文件,输入如下内容:

python">from launch import LaunchDescription
from launch_ros.actions import Node
from launch_ros.actions import PushRosNamespace
from launch.actions import GroupActiondef 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])

代码解释

g1 = GroupAction(actions=[PushRosNamespace(namespace="g1"),turtle1, turtle2])
g2 = GroupAction(actions=[PushRosNamespace(namespace="g2"),turtle3])

上述代码将创建两个组,两个组使用了不同的命名空间,每个组下包含了不同的节点。

在 GroupAction 对象中,使用的参数为:

  • actions:action列表,比如被包含到组内的命名空间、节点等。

在 PushRosNamespace 对象中,使用的参数为:

  • namespace:当前组使用的命名空间。

六、添加事件

节点在运行过程中会触发不同的事件,当事件触发时可以为之注册一定的处理逻辑。事件使用相关的 API 为:launch.actions.RegisterEventHandler、launch.event_handlers.OnProcessStart、launch.event_handlers.OnProcessExit。

需求:为 turtlesim_node 节点添加事件,事件1:节点启动时调用spawn服务生成新乌龟;事件2:节点关闭时,输出日志信息。

示例:新建 py06_event.launch.py 文件,输入如下内容:

python">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)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])

代码解释

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退出!")]))

上述代码为 turtle 节点注册启动事件和退出事件,当 turtle 节点启动后会执行 spwn 节点,当 turtle 节点退出时,会输出日志文本:“turtlesim_node退出!”。

对象 RegisterEventHandler 负责注册事件,其参数为:

  • event_handler:注册的事件对象。

OnProcessStart 是启动事件对象,其参数为:

  • target_action:被注册事件的目标对象;
  • on_start:事件触发时的执行逻辑。

OnProcessExit 是退出事件对象,其参数为:

  • target_action:被注册事件的目标对象;
  • on_exit:事件触发时的执行逻辑。

LogInfo 是日志输出对象,其参数为:

  • msg:被输出的日志信息。

http://www.ppmy.cn/devtools/148975.html

相关文章

单片机实物成品-010 智能宠物喂食系统(代码+硬件+论文)

项目介绍 版本1:oled显示定时投喂(舵机模拟)声光报警显示实时时间 ---演示视频: 智能宠物喂食001_哔哩哔哩_bilibili 1. STM32F103C8T6 单片机进行数据处理 2. OLED 液晶显示 3,按键1 在数据显示界面时按下按键1切…

python_excel列表单元格字符合并、填充、复制操作

读取指定sheet页,根据规则合并指定列,填充特定字符,删除多余的列,每行复制四次,最后写入新的文件中。 import pandas as pd""" 读取指定sheet页,根据规则合并指定列,填充特定字…

30、论文阅读:基于小波的傅里叶信息交互与频率扩散调整的水下图像恢复

Wavelet-based Fourier Information Interaction with Frequency Diffusion Adjustment for Underwater Image Restoration 摘要介绍相关工作水下图像增强扩散模型 论文方法整体架构离散小波变换与傅里叶变换频率初步增强Wide Transformer BlockSpatial-Frequency Fusion Block…

从零手写线性回归模型:PyTorch 实现深度学习入门教程

系列文章目录 01-PyTorch新手必看:张量是什么?5 分钟教你快速创建张量! 02-张量运算真简单!PyTorch 数值计算操作完全指南 03-Numpy 还是 PyTorch?张量与 Numpy 的神奇转换技巧 04-揭秘数据处理神器:PyTor…

go怎么终止协程的运行

在Go语言中,**协程(goroutine)**是由Go的运行时(runtime)管理的轻量级线程。一旦启动,协程会持续运行直到它执行完毕或发生异常。Go语言本身没有显式的“停止”或“关闭”协程的机制,协程的生命…

C 实现植物大战僵尸(三)

C 实现植物大战僵尸(三) 十 实现豌豆子弹 原设计 这里的设计思路和原 UP 主思路差异比较大,罗列如下 原作中只要僵尸在出现在某条道路上,且存在豌豆射手,豌豆射手就会发射子弹,(这里是网页在…

人工智能AI学习路径

一、打好基础 1. 数学基础 - 线性代数:这是 AI 的基石之一。矩阵和向量的运算在神经网络等许多 AI 算法中无处不在。例如,在深度学习中,图像可以被表示为一个矩阵,通过矩阵乘法等操作进行特征提取。你需要理解矩阵的基本运算&…

(安卓无线调试)ADB 无法连接及 Scrcpy 问题排查指南

问题描述 在使用 ADB 和 Scrcpy 时遇到以下问题&#xff1a; 无法连接到 ADB 服务。 即使连接成功&#xff0c;Scrcpy 显示以下错误&#xff1a; INFO: scrcpy 1.10 <https://github.com/Genymobile/scrcpy> D:\.....\scrcpy\scrcpy-server.jar: 1 file pushed. 0.2 …