跳到主要内容

在 ROS2 中,参数(Parameters)是一种用于配置节点行为的机制,它允许用户在节点运行时设置或修改特定变量的值,而无需更改源代码。这种机制特别适合在不同应用场景下灵活调整节点的表现。

例如,当你编写一个用于控制小车速度的 ROS2 节点时,可以将 max_speed(最大速度)定义为一个参数。这样,用户只需修改参数值,就可以改变小车的最大速度,而无需重新编写或编译程序,从而大大提高了程序的可配置性与复用性。

参数的命令行工具

通过 ROS2 中现有的功能包 /turtlesim/teleop_turtle 学习参数的命令行工具,首先打开两个节点 turtlesim_node 和 turtle_teleop_key:

打开一个新的终端并运行:

ros2 run turtlesim turtlesim_node

打开另一个终端并运行:

ros2 run turtlesim turtle_teleop_key

1. 使用ros2 param list

要查看属于节点的参数,打开一个新的终端并输入命令:

ros2 param list

将看到节点命名空间/teleop_turtle/turtlesim,以及每个节点的参数:

/teleop_turtle:
qos_overrides./parameter_events.publisher.depth
qos_overrides./parameter_events.publisher.durability
qos_overrides./parameter_events.publisher.history
qos_overrides./parameter_events.publisher.reliability
scale_angular
scale_linear
use_sim_time
/turtlesim:
background_b
background_g
background_r
qos_overrides./parameter_events.publisher.depth
qos_overrides./parameter_events.publisher.durability
qos_overrides./parameter_events.publisher.history
qos_overrides./parameter_events.publisher.reliability
use_sim_time

每个节点都有 use_sim_time 参数;它不是 turtlesim 特有的。从参数名字可以看出 /turtlesim 的参数使用RGB颜色值确定 turtlesim 窗口的背景颜色。可以使用 ros2 param get 确定参数的类型。

2 使用 ros2 param get

要显示参数的类型和当前值,使用命令:

ros2 param get <node_name> <parameter_name>

使用如下命令查看 /turtlesim 的参数 background_g 的当前值:

ros2 param get /turtlesim background_g

这将返回值:

86

可以看出 background_g 包含一个整数值。如果对 background_rbackground_b 运行相同的命令,将分别得到值 69255

3 使用 ros2 param set

要在运行时更改参数的值,使用命令:

ros2 param set <node_name> <parameter_name> <value>

更改 /turtlesim 的背景颜色:

ros2 param set /turtlesim background_r 150

终端应该返回消息:

Set parameter background_r successful

并且 turtlesim 窗口的背景颜色会相应改变,set 命令只会在当前会话中更改背景颜色,而不是永久更改。 但是,我们可以保存设置并在下次启动节点时重新加载。

4 使用 ros2 param dump

通过使用命令查看节点的所有当前参数值:

ros2 param dump <node_name>

该命令默认打印到标准输出(stdout),但也可以将参数值保存到文件中以供以后加载使用。 要将 /turtlesim 的当前参数配置保存到文件 turtlesim.yaml 中,输入命令:

ros2 param dump /turtlesim > turtlesim.yaml

该命令将在当前工作目录中创建一个新的文件。 打开这个文件,将看到以下内容:

/turtlesim:
ros__parameters:
background_b: 255
background_g: 86
background_r: 150
qos_overrides:
/parameter_events:
publisher:
depth: 1000
durability: volatile
history: keep_last
reliability: reliable
use_sim_time: False

转储的参数可以在将来重新加载节点时使用。

5 使用 ros2 param load

使用 ros2 param load 命令从文件加载参数到当前运行的节点:

ros2 param load <node_name> <parameter_file>

要将使用 ros2 param dump 生成的 turtlesim.yaml 文件加载到 /turtlesim 节点的参数中,输入命令:

ros2 param load /turtlesim turtlesim.yaml

终端将返回消息:

Set parameter background_b successful
Set parameter background_g successful
Set parameter background_r successful
Set parameter qos_overrides./parameter_events.publisher.depth failed: parameter 'qos_overrides./parameter_events.publisher.depth' cannot be set because it is read-only
Set parameter qos_overrides./parameter_events.publisher.durability failed: parameter 'qos_overrides./parameter_events.publisher.durability' cannot be set because it is read-only

注意:只读参数只能在启动时修改,之后不能修改,这就是为什么“qos_overrides”参数有一些警告的原因。

6 在节点启动时加载参数文件

要使用保存的参数值启动相同的节点,使用:

ros2 run <package_name> <executable_name> --ros-args --params-file <file_name>

--ros-args--params-file 标志后跟想要加载的文件,这样可以在启动节点时加载之前保存的文件。

ros2 run turtlesim turtlesim_node --ros-args --params-file turtlesim.yaml

turtlesim 背景颜色是之前设置的紫色。

注意:当在节点启动时使用参数文件时,所有参数(包括只读参数)都将被更新。

编写自己的参数节点

编写Python参数节点

在工作空间 src 目录中,创建一个名为 python_parameters 的新功能包:

ros2 pkg create --build-type ament_python --license Apache-2.0 python_parameters --dependencies rclpy

终端将返回一条功能包 python_parameters 创建成功的消息。因为使用了 --dependencies 参数,因此不需要手动配置 package.xml

ros2_ws/src/python_parameters/python_parameters 目录中,创建一个名为 python_parameters_node.py 的新文件,并写入以下代码:

import rclpy
import rclpy.node

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)

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)

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

if __name__ == '__main__':
main()

代码解释

构造函数中的 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)

main函数运行节点内容。

添加ParameterDescriptor (可选)

还可以为参数设置一个描述符, 描述符允许用户对参数进行描述。 为了实现该目的,需要修改构造函数中的代码内容:

# ...
class MinimalParam(rclpy.node.Node):
def __init__(self):
super().__init__('minimal_param_node')
#导入 ParameterDescriptor 类型
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 来查看参数的类型和描述。

添加程序入口点

打开 setup.py 文件,添加如下入口

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

修改完成后要保存。

构建和运行

在构建之前,在工作空间的根目录(ros2_ws)中构建新功能包:

colcon build --packages-select python_parameters

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

source install/setup.bash

现在运行节点:

ros2 run python_parameters minimal_param_node

终端将每秒返回以下消息:

[INFO] [parameter_node]: Hello world!

现在可以看到参数的默认值,如果想要设置这个参数, 可以通过控制台更改,确保下面的节点正在运行:

ros2 run python_parameters minimal_param_node

打开另一个终端,再次从 ros2_ws 内部加载设置文件,并输入以下命令:

ros2 param list

将在终端显示自定义参数 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!

通过启动文件更改

节点通常和启动文件(launch)一起使用,用户可以在启动文件中设置参数,启动文件将在接下来的章节学习,这里做一个演示。首先,添加一个启动文件, 在 ros2_ws/src/python_parameters/ 目录中,创建一个名为 launch 的新目录。接着在该目录下创建一个名为 python_parameters_launch.py 的新文件,代码如下:

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
return LaunchDescription([
Node(
package='python_parameters',
executable='minimal_param_node',
name='custom_minimal_param_node',
output='screen',
emulate_tty=True,
parameters=[
{'my_parameter': 'earth'}
]
)
])

这段代码在启动节点 minimal_param_node 时将 my_parameter 设置为 earth。现在打开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]*')),
]
)

打开一个控制台,导航到工作空间的根目录 ros2_ws,并构建新功能包:

colcon build --packages-select python_parameters

然后在新的终端中添加设置文件:

source install/setup.bash

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

ros2 launch python_parameters python_parameters_launch.py

终端应该首次返回以下消息:

[INFO] [custom_minimal_param_node]: Hello earth!

后续输出应该每秒显示[INFO] [minimal_param_node]: Hello world!

总结

本节介绍了如何创建一个具有自定义参数的节点,该参数可以从启动文件或命令行设置。 将依赖项、可执行文件和启动文件添加到功能包配置文件中,以便我们可以构建和运行这些文件。