【ROS2】初级:客户端-在类中使用参数(Python)

目标:使用 Python 创建并运行一个带有 ROS 参数的类。

 教程级别:初学者

 时间:20 分钟

 目录

  •  背景

  •  先决条件

  •  任务

    • 1. 创建一个包

    • 2. 编写 Python 节点

    • 3. 建立并运行

  •  摘要

  •  下一步

 背景

在创建您自己的节点时,有时需要添加可以从启动文件设置的参数。

本教程将向您展示如何在 Python 类中创建这些参数,以及如何在启动文件中设置它们。

 先决条件

在之前的教程中,您学习了如何创建工作空间和创建软件包。您还了解了参数及其在 ROS 2 系统中的功能。

 任务

1. 创建一个包

打开一个新的终端并且初始化您的 ROS 2 安装,这样 ros2 命令就会生效。

按照这些指示创建一个名为 ros2_ws 的新工作区。

请记住,包应该在 src 目录中创建,而不是在工作区的根目录中。导航到 ros2_ws/src 并创建一个新包:

cxy@ubuntu2404-cxy:~/ros2_ws/src$ ros2 pkg create --build-type ament_python --license Apache-2.0 python_parameters --dependencies rclpy
going to create a new package
package name: python_parameters
destination directory: /home/cxy/ros2_ws/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['cxy <cxy@todo.todo>']
licenses: ['Apache-2.0']
build type: ament_python
dependencies: ['rclpy']
creating folder ./python_parameters
creating ./python_parameters/package.xml
creating source folder
creating folder ./python_parameters/python_parameters
creating ./python_parameters/setup.py
creating ./python_parameters/setup.cfg
creating folder ./python_parameters/resource
creating ./python_parameters/resource/python_parameters
creating ./python_parameters/python_parameters/__init__.py
creating folder ./python_parameters/test
creating ./python_parameters/test/test_copyright.py
creating ./python_parameters/test/test_flake8.py
creating ./python_parameters/test/test_pep257.py

您的终端将返回一条消息,确认您的包 python_parameters 及其所有必要的文件和文件夹已创建。

--dependencies `参数将自动向` package.xml `和` CMakeLists.txt `添加必要的依赖行。

 1.1 更新 package.xml 

因为在创建包时您使用了 --dependencies 选项,所以您无需手动添加依赖项到 package.xml 或 CMakeLists.txt 。

一如既往,不过,请确保将描述、维护者电子邮件和姓名以及许可信息添加到 package.xml 。

<description>Python parameter tutorial</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache-2.0</license>

2. 编写 Python 节点

在 ros2_ws/src/python_parameters/python_parameters 目录中,创建一个名为 python_parameters_node.py 的新文件,并将以下代码粘贴其中:

cxy@ubuntu2404-cxy:~/ros2_ws/src/python_parameters/python_parameters$ gedit python_parameters_node.py
# 导入rclpy模块,这是ROS2中Python客户端库的一部分
import rclpy
# 导入rclpy.node模块,这是ROS2中用于创建节点的模块
import rclpy.node


# 定义一个MinimalParam类,它继承自rclpy.node.Node类
class MinimalParam(rclpy.node.Node):
    # 类的初始化函数
    def __init__(self):
        # 调用父类的初始化函数,并设置节点名称为'minimal_param_node'
        super().__init__('minimal_param_node')


        # 声明一个参数'my_parameter',并设置默认值为'world'
        self.declare_parameter('my_parameter', 'world')


        # 创建一个定时器,每1秒调用一次timer_callback函数
        self.timer = self.create_timer(1, self.timer_callback)


    # 定时器回调函数
    def timer_callback(self):
        # 获取'my_parameter'参数的值
        my_param = self.get_parameter('my_parameter').get_parameter_value().string_value


        # 使用节点的日志功能打印信息
        self.get_logger().info('Hello %s!' % my_param)


        # 创建一个新的Parameter对象,用于更新'my_parameter'参数的值
        my_new_param = rclpy.parameter.Parameter(
            'my_parameter',
            rclpy.Parameter.Type.STRING,
            'world'
        )
        # 将新参数放入列表中
        all_new_parameters = [my_new_param]
        # 设置新的参数值
        self.set_parameters(all_new_parameters)


# main函数定义
def main():
    # 初始化rclpy库
    rclpy.init()
    # 创建MinimalParam类的实例
    node = MinimalParam()
    # 使节点保持运行,直到被外部事件(如Ctrl+C)中断
    rclpy.spin(node)


# Python脚本的入口点,当直接运行此脚本时执行main函数
if __name__ == '__main__':
    main()
2.1 检查代码 

顶部的 import 语句用于导入包依赖项。

下一段代码创建了类和构造函数。构造函数的第 self.declare_parameter('my_parameter', 'world') 行创建了一个名为 my_parameter 的参数,其默认值为 world 。参数类型是根据默认值推断出来的,所以在这种情况下它会被设置为字符串类型。接下来, timer 被初始化为 1,这导致 timer_callback 函数每秒执行一次。

class MinimalParam(rclpy.node.Node):
    def __init__(self):
        super().__init__('minimal_param_node')


        self.declare_parameter('my_parameter', 'world')


        self.timer = self.create_timer(1, self.timer_callback)

我们 timer_callback 函数的第一行从节点获取参数 my_parameter ,并将其存储在 my_param 中。接下来, get_logger 函数确保事件被记录。然后 set_parameters 函数将参数 my_parameter 重置为默认字符串值 world 。如果用户在外部更改了参数,这确保它总是被重置回原来的值。

def timer_callback(self):
    my_param = self.get_parameter('my_parameter').get_parameter_value().string_value


    self.get_logger().info('Hello %s!' % my_param)


    my_new_param = rclpy.parameter.Parameter(
        'my_parameter',
        rclpy.Parameter.Type.STRING,
        'world'
    )
    all_new_parameters = [my_new_param]
    self.set_parameters(all_new_parameters)

跟随 timer_callback 是我们的 main 。这里初始化了 ROS 2,构建了 MinimalParam 类的一个实例, rclpy.spin 开始处理来自节点的数据。

def main():
    rclpy.init()
    node = MinimalParam()
    rclpy.spin(node)


if __name__ == '__main__':
    main()
2.1.1(可选)添加参数描述符 

您可以选择为参数设置一个描述符。描述符允许您指定参数及其约束条件的文本描述,例如使其只读,指定范围等。为此, __init__ 代码必须更改为:

# ...


class MinimalParam(rclpy.node.Node):
    def __init__(self):
        super().__init__('minimal_param_node')


        from rcl_interfaces.msg import ParameterDescriptor
        my_parameter_descriptor = ParameterDescriptor(description='This parameter is mine!')


        self.declare_parameter('my_parameter', 'world', my_parameter_descriptor)


        self.timer = self.create_timer(1, self.timer_callback)

代码的其余部分保持不变。一旦运行了节点,你就可以运行 ros2 param describe /minimal_param_node my_parameter 来查看类型和描述。

2.2 添加一个入口点 

打开 setup.py 文件。再次,将 maintainer 、 maintainer_email 、 description 和 license 字段与您的 package.xml 匹配:

maintainer='YourName',
maintainer_email='you@email.com',
description='Python parameter tutorial',
license='Apache-2.0',

在 entry_points 字段的 console_scripts 括号内添加以下行:

entry_points={
    'console_scripts': [
        'minimal_param_node = python_parameters.python_parameters_node:main',
    ],
},

别忘了保存。

# 导入setuptools模块,用于配置、打包和安装Python包
from setuptools import find_packages, setup


# 设置包名为'python_parameters'
package_name = 'python_parameters'


# 调用setup函数来配置Python包
setup(
    # 包名
    name=package_name,
    # 版本号
    version='0.0.0',
    # 自动查找并包含所有find_packages()找到的包,排除名为'test'的包
    packages=find_packages(exclude=['test']),
    # 包含的数据文件
    data_files=[
        # 安装时需要复制的文件或文件夹列表
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    # 安装依赖项,这里只需要'setuptools'
    install_requires=['setuptools'],
    # 设置为zip安全,即可以安全地从zip压缩包运行
    zip_safe=True,
    # 维护者的名称
    maintainer='cxy',
    # 维护者的邮箱地址
    maintainer_email='cxy@126.com',
    # 包的简短描述
    description='Python parameter tutorial',
    # 许可证类型
    license='Apache-2.0',
    # 测试依赖项
    tests_require=['pytest'],
    # 入口点,定义了哪些脚本会被安装到系统路径中,以便直接在命令行中运行
    entry_points={
        'console_scripts': [
                # minimal_param_node是一个可执行命令,指向python_parameters.python_parameters_node模块中的main函数
                'minimal_param_node = python_parameters.python_parameters_node:main',
        ],
    },
)

3. 构建并运行

在工作区的根目录运行 rosdep ( ros2_ws )以检查构建前缺失的依赖项是一个好习惯:

rosdep install -i --from-path src --rosdistro jazzy -y

返回到您的工作区根目录, ros2_ws ,然后构建您的新包:

cxy@ubuntu2404-cxy:~/ros2_ws$ colcon build --packages-select python_parameters
Starting >>> python_parameters
Finished <<< python_parameters [2.56s]          


Summary: 1 package finished [2.82s]

打开一个新的终端,导航到 ros2_ws ,并且导入设置文件:

source install/setup.bash

现在运行节点:终端应该每秒返回以下消息:

cxy@ubuntu2404-cxy:~/ros2_ws$ ros2 run python_parameters minimal_param_node
[INFO] [1720325261.370823709] [minimal_param_node]: Hello world!
[INFO] [1720325262.346870169] [minimal_param_node]: Hello world!
[INFO] [1720325263.346835815] [minimal_param_node]: Hello world!

现在您可以看到参数的默认值,但您希望能够自己设置它。有两种方法可以做到这一点。

3.1 通过控制台进行更改 

这部分将使用你从教程中获得的关于参数的知识,并将其应用到你刚刚创建的节点上。

确保节点正在运行:

ros2 run python_parameters minimal_param_node

打开另一个终端,再次从 ros2_ws 内部获取设置文件,并输入以下行:

cxy@ubuntu2404-cxy:~/ros2_ws$ ros2 param list
/minimal_param_node:
  my_parameter
  start_type_description_service
  use_sim_time

在那里,您将看到自定义参数 my_parameter 。要更改它,只需在控制台中运行以下行:

ros2 param set /minimal_param_node my_parameter earth

你知道如果你得到输出 Set parameter successful ,那就进行得很顺利。如果你看看另一个终端,你应该会看到输出变成了 [INFO] [minimal_param_node]: Hello earth!

由于节点后来将参数重新设置为 world ,因此后续输出显示 [INFO] [minimal_param_node]: Hello world!

3.2 通过启动文件进行更改

您也可以在启动文件中设置参数,但首先您需要添加一个启动目录。在 ros2_ws/src/python_parameters/ 目录内,创建一个名为 launch 的新目录。在那里,创建一个名为 python_parameters_launch.py 的新文件。

# 从launch模块导入LaunchDescription类
from launch import LaunchDescription
# 从launch_ros模块的actions子模块导入Node类
from launch_ros.actions import Node


# 定义一个函数generate_launch_description,这个函数将会返回一个LaunchDescription对象
def generate_launch_description():
    # 返回一个LaunchDescription对象,它包含了一个Node列表
    return LaunchDescription([
        # 创建一个Node对象,用于启动一个ROS节点
        Node(
            # 指定节点所属的包名
            package='python_parameters',
            # 指定节点可执行文件的名称
            executable='minimal_param_node',
            # 为节点指定一个名称
            name='custom_minimal_param_node',
            # 设置节点的输出选项,这里是输出到屏幕
            output='screen',
            # 设置emulate_tty为True,以便在屏幕上模拟tty输出,使得输出更易读
            emulate_tty=True,
            # 设置节点的参数,这里定义了一个名为'my_parameter'的参数,其值为'earth'
            parameters=[
                {'my_parameter': 'earth'}
            ]
        )
    ])

在这里您可以看到,当我们启动节点 parameter_node 时,我们将 my_parameter 设置为 earth 。通过添加下面两行代码,我们确保输出打印在控制台上。

output="screen",
emulate_tty=True,

现在打开 setup.py 文件。将 import 语句添加到文件顶部,并将另一个新语句添加到 data_files 参数中,以包含所有启动文件:

import os
from glob import glob
# ...


setup(
  # ...
  data_files=[
      # ...
      (os.path.join('share', package_name), glob('launch/*launch.[pxy][yma]*')),
    ]
  )
# 从setuptools模块导入find_packages和setup函数
from setuptools import find_packages, setup
# 导入os模块,用于操作系统功能,如路径操作
import os
# 从glob模块导入glob函数,用于文件路径的模式匹配
from glob import glob


# 定义包名为'python_parameters'
package_name = 'python_parameters'


# 调用setup函数来配置包的设置
setup(
    # 设置包名
    name=package_name,
    # 设置包版本
    version='0.0.0',
    # 使用find_packages函数查找并包含所有子包,排除名为'test'的子包
    packages=find_packages(exclude=['test']),
    # 设置数据文件,这些文件将会被安装到系统中
    data_files=[
        # 安装ament索引资源到'share/ament_index/resource_index/packages'
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        # 安装package.xml到'share/' + package_name
        ('share/' + package_name, ['package.xml']),
        # 安装launch文件夹下所有的启动文件到'share/' + package_name
        (os.path.join('share', package_name), glob('launch/*launch.[pxy][yma]*')),
    ],
    # 设置包的依赖项,这里只需要'setuptools'
    install_requires=['setuptools'],
    # 设置zip_safe为True,表示可以安全地将此包作为zip文件运行
    zip_safe=True,
    # 设置维护者信息
    maintainer='cxy',
    maintainer_email='cxy@126.com',
    # 设置包描述
    description='Python parameter tutorial',
    # 设置许可证类型
    license='Apache-2.0',
    # 设置测试需要的依赖项
    tests_require=['pytest'],
    # 设置入口点,定义如何启动包中的程序
    entry_points={
        'console_scripts': [
                # 当运行'minimal_param_node'命令时,会调用python_parameters_node模块中的main函数
                'minimal_param_node = python_parameters.python_parameters_node:main',
        ],
    },
)

打开控制台并导航到您的工作区的根目录, ros2_ws ,然后构建您的新包:

cxy@ubuntu2404-cxy:~/ros2_ws$ colcon build --packages-select python_parameters
Starting >>> python_parameters
Finished <<< python_parameters [2.51s]          


Summary: 1 package finished [2.75s]

然后在新终端中导入设置文件:

source install/setup.bash

现在使用我们刚刚创建的启动文件运行节点:

cxy@ubuntu2404-cxy:~/ros2_ws$ source install/setup.bash
cxy@ubuntu2404-cxy:~/ros2_ws$ ros2 launch python_parameters python_parameters_launch.py
[INFO] [launch]: All log files can be found below /home/cxy/.ros/log/2024-07-07-12-15-25-235509-ubuntu2404-cxy-21329
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [minimal_param_node-1]: process started with pid [21332]
[minimal_param_node-1] [INFO] [1720325726.687588853] [custom_minimal_param_node]: Hello earth!
[minimal_param_node-1] [INFO] [1720325727.671121468] [custom_minimal_param_node]: Hello world!

进一步的输出应该每秒显示 [INFO] [minimal_param_node]: Hello world! 。

 摘要

您创建了一个带有自定义参数的节点,该参数可以从启动文件或命令行中设置。您将依赖项、可执行文件和启动文件添加到包配置文件中,以便您可以构建并运行它们,并看到参数在实际中的应用。

 下一步

现在您已经拥有了一些包和自己的 ROS 2 系统,下一个教程 https://docs.ros.org/en/jazzy/Tutorials/Beginner-Client-Libraries/Getting-Started-With-Ros2doctor.html 将向您展示如何在遇到问题时检查环境和系统中的问题。

ec338f859a3ceafc7385127f99de6a56.png

  • 19
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值