在前面的文章,我们已经介绍了话题题、服务、动作三种通信机制,接下来呢我们再来介绍一种ROS系统中常用的数据传输方式——参数。
类似C++编程中的全局变量,可以便于在多个程序中共享某些数据,参数是ROS机器人系统中的全局字典,可以运行多个节点中共享数据。
一、通信模型
在机器视觉识别的时候,有很多参数都会影响视觉识别的效果;
在Node A相机驱动节点中,就需要考虑很多问题,相机连接到哪个USB端口,使用的图像分辨率是多少,曝光度和编码格式分别是什么,这些都可以通过参数设置,我们可以通过配置文件或者程序进行设置。
Node B节点中也是一样,图像识别使用的阈值是多少,整个图像面积很大,那个部分是我们关注的核心区域,识别过程是否需要美颜等等,就像我们使用美颜相机一样,我们可以通过滑动条或者输入框设置很多参数,不同参数设置后,都会改变执行功能的一些效果。
这就是参数的作用。
1.1 全局字典
在ROS系统中,参数是以全局字典的形态存在的,什么叫字典?
就像真实的字典一样,由名称和数值组成,也叫做键和值,合成键值。或者我们也可以理解为,就像编程中的参数一样,有一个参数名 ,然后跟一个等号,后边就是参数值了,在使用的时候,访问这个参数名即可。
1.2 可动态监控
在ROS2中,参数的特性非常丰富,比如某一个节点共享了一个参数,其它节点都可以访问,如果某一个节点对参数进行了修改,其它节点也有办法立刻知道,从而获取最新的数值。这在参数的高级编程中,我们都可能会用到。
二、参数案例
2.1 小海龟的参数
在小海龟的例程中,仿真器也提供了不少参数,我们一起来通过这个例程,熟悉下参数的含义和命令行的使用方法。
进入桌面系统,启动第一个终端,运行小海龟仿真器;- pi@NanoPC-T6:~/dev_ws$ ros2 run turtlesim turtlesim_node
复制代码 该指令将启动一个蓝色背景的海龟仿真器;
启动第二个终端,运行如下指令:- pi@NanoPC-T6:~/dev_ws$ ros2 run turtlesim turtle_teleop_key
复制代码 该指令将启动一个键盘控制节点,在该终端中点击键盘上的“上下左右”按键,就可以控制小海龟运动啦。
2.1.1 查看参数列表
当前系统中有哪些参数呢?我们可以启动一个终端,并使用如下命令查询:- pi@NanoPC-T6:~/dev_ws$ ros2 param list
- /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
复制代码 可以看到系统中有两个正在运行的节点:
- /teleop_turtle:键盘控制节点;
- scale_linear:控制线性速度缩放比例;
- scale_angular:控制角速度缩放比例;
- use_sim_time:是否使用仿真时间;
- /turtlesim: 海龟仿真节点;
- background_b:背景颜色的蓝色分量 (0-255);
- background_g:背景颜色的绿色分量 (0-255);
- background_r:背景颜色的红色分量 (0-255);
- use_sim_time:是否使用仿真时间。
两个节点都有针对参数事件发布器的QoS覆盖参数:
- qos_overrides./parameter_events.publisher.depth;
- qos_overrides./parameter_events.publisher.durability;
- qos_overrides./parameter_events.publisher.history;
- qos_overrides./parameter_events.publisher.reliability。
2.1.2 参数查询与修改
2.1.2.1 获取参数值
如果想要查询或者修改某个参数的值,可以在param命令后边跟get或者set子命令。
获取键盘控制的速度参数:- pi@NanoPC-T6:~/dev_ws$ ros2 param get /teleop_turtle scale_linear
- Double value is: 2.0
- pi@NanoPC-T6:~/dev_ws$ ros2 param get /teleop_turtle scale_angular
- Double value is: 2.0
复制代码 获取小海龟仿真的背景颜色:- pi@NanoPC-T6:~/dev_ws$ ros2 param get /turtlesim background_r
- Integer value is: 69
复制代码 2.1.2.2 查看参数描述信息
查看某个参数的描述信息:- pi@NanoPC-T6:~/dev_ws$ ros2 param describe /turtlesim background_b
- Parameter name: background_b
- Type: integer
- Description: Blue channel of the background color
- Constraints:
- Min value: 0
- Max value: 255
- Step: 1
复制代码 2.1.2.3 设置参数值
让小海龟移动更快:- pi@NanoPC-T6:~/dev_ws$ ros2 param set /teleop_turtle scale_linear 3.0
- Set parameter successful
- pi@NanoPC-T6:~/dev_ws$ ros2 param set /teleop_turtle scale_angular 3.0
- Set parameter successful
复制代码 改变小海龟仿真背景颜色:- pi@NanoPC-T6:~/dev_ws$ ros2 param set /turtlesim background_r 100
- Set parameter successful
- pi@NanoPC-T6:~/dev_ws$ ros2 param set /turtlesim background_g 50
- Set parameter successful
- pi@NanoPC-T6:~/dev_ws$ ros2 param set /turtlesim background_b 150
- Set parameter successful
复制代码 2.1.3 参数文件保存与加载
一个一个查询/修改参数太麻烦了,不如试一试参数文件,ROS中的参数文件使用yaml格式,可以在param命令后边跟dump子命令,将某个节点的参数都保存到文件中,或者通过load命令一次性加载某个参数文件中的所有内容。
将某个节点的参数保存到参数文件中:- pi@NanoPC-T6:~/dev_ws$ ros2 param dump /turtlesim >> turtlesim.yaml
- pi@NanoPC-T6:~/dev_ws$ cat turtlesim.yaml
- /turtlesim:
- ros__parameters:
- background_b: 150
- background_g: 50
- background_r: 100
- qos_overrides:
- /parameter_events:
- publisher:
- depth: 1000
- durability: volatile
- history: keep_last
- reliability: reliable
- use_sim_time: false
复制代码 一次性加载某一个文件中的所有参数:- pi@NanoPC-T6:~/dev_ws$ ros2 param load /turtlesim turtlesim.yaml
复制代码 2.2 简单参数示例
接下来就要开始写程序了,在程序中设置参数和读取参数都比较简单,一两句函数就可以实现,我们先来体验一下这几个函数的使用方法。
我们首先创建my_learning_parameter的Python版本的功能包;- pi@NanoPC-T6:~/dev_ws$ cd src
- pi@NanoPC-T6:~/dev_ws/src$ ros2 pkg create --build-type ament_python my_learning_parameter
复制代码 2.2.1 代码实现
打开my_learning_parameter功能包,在my_learning_parameter文件夹下创建param_declare.py;- """
- ROS2参数示例-创建、读取、修改参数
- @author: zy
- @since : 2025/12/15
- """
- import rclpy # ROS2 Python接口库
- from rclpy.node import Node # ROS2 节点类
- class ParameterNode(Node):
- def __init__(self, name):
- super().__init__(name) # ROS2节点父类初始化
- self.timer = self.create_timer(2, self.timer_callback) # 创建一个定时器(单位为秒的周期,定时执行的回调函数)
- self.declare_parameter('robot_name', 'mbot') # 创建一个参数,并设置参数的默认值
- def timer_callback(self): # 创建定时器周期执行的回调函数
- robot_name_param = self.get_parameter('robot_name').get_parameter_value().string_value # 从ROS2系统中读取参数的值
- self.get_logger().info('Hello %s!' % robot_name_param) # 输出日志信息,打印读取到的参数值
- new_name_param = rclpy.parameter.Parameter( # 创建一个新的 Parameter 对象
- 'robot_name', # 参数名称
- rclpy.Parameter.Type.STRING, # 参数类型(字符串类型)
- 'mbot' # 参数值
- )
- all_new_parameters = [new_name_param]
- self.set_parameters(all_new_parameters) # 将重新创建的参数列表发送给ROS2系统
- def main(args=None): # ROS2节点主入口main函数
- rclpy.init(args=args) # ROS2 Python接口初始化
- node = ParameterNode("param_declare") # 创建ROS2节点对象并进行初始化
- rclpy.spin(node) # 循环等待ROS2退出
- node.destroy_node() # 销毁节点对象
- rclpy.shutdown() # 关闭ROS2 Python接口
复制代码 完成代码的编写后需要设置功能包的编译选项,让系统知道Python程序的入口,打开功能包的setup.py文件,加入如下入口点的配置:- entry_points={
- 'console_scripts': [
- 'param_declare = my_learning_parameter.param_declare:main',
- ],
- },
复制代码 2.2.2 编译运行
编译程序:- pi@NanoPC-T6:~/dev_ws$ colcon build --paths src/my_learning_parameter
复制代码 启动第一个终端,运行节点;- pi@NanoPC-T6:~/dev_ws$ ros2 run my_learning_parameter param_declare
- [INFO] [1765804528.869092474] [param_declare]: Hello mbot!
- [INFO] [1765804530.840071999] [param_declare]: Hello mbot!
- [INFO] [1765804532.840587253] [param_declare]: Hello mbot!
- ......
- INFO] [1765804620.837805446] [param_declare]: Hello mbot!
- [INFO] [1765804622.839387783] [param_declare]: Hello turtle!
- .....
复制代码 再启动一个中断修改参数robot_name的值;- pi@NanoPC-T6:~/dev_ws$ ros2 param set param_declare robot_name turtle
- Set parameter successful
复制代码 2.2.3 流程分析
总结一下,想要实现一个参数设置,代码的实现流程是这样做;
- 编程接口初始化;
- 创建节点并初始化;
- 声明参数,并在定时器读取、设置自己的参数;
- 销毁节点并关闭接口。
2.3 机器视觉应用
我们已经初步学会了参数的使用,如何在机器人中应用呢?
继续优化机器视觉的示例,物体识别对光线比较敏感,不同的环境大家使用的阈值也是不同的,每次在代码中修改阈值还挺麻烦,不如我们就把阈值提炼成参数,运行过程中就可以动态设置,不是大大提高了程序的易用性么?
说干就干,我们先来看下效果如何,这里我们使用两个节点;
- 机驱动节点:将驱动相机并发布图像话题,此时的话题数据使用的是ROS中标准定义的Image图像消息;
- 视觉识别节点:订阅图像数据,并运行视觉识别功能,识别目标的位置;
2.3.1 代码实现
在my_learning_parameter文件夹下创建param_object_detect.py;- """
- ROS2参数示例-设置目标识别的颜色阈值参数
- @author: zy
- @since : 2025/12/15
- """
- import rclpy # ROS2 Python接口库
- from rclpy.node import Node # ROS2 节点类
- from sensor_msgs.msg import Image # 图像消息类型
- from cv_bridge import CvBridge # ROS与OpenCV图像转换类
- import cv2 # Opencv图像处理库
- import numpy as np # Python数值计算库
- lower_red = np.array([0, 90, 128]) # 红色的HSV阈值下限
- upper_red = np.array([180, 255, 255]) # 红色的HSV阈值上限
- """
- 创建一个订阅者节点
- """
- class ImageSubscriber(Node):
- def __init__(self, name):
- super().__init__(name) # ROS2节点父类初始化
- self.sub = self.create_subscription(Image, # 创建订阅者对象(消息类型、话题名、订阅者回调函数、队列长度)
- 'image_raw', self.listener_callback, 10)
- self.cv_bridge = CvBridge() # 创建一个图像转换对象,用于OpenCV图像与ROS的图像消息的互相转换
- self.declare_parameter('red_h_upper', 0) # 创建一个参数,表示阈值上限
- self.declare_parameter('red_h_lower', 0) # 创建一个参数,表示阈值下限
- def object_detect(self, image):
- upper_red[0] = self.get_parameter('red_h_upper').get_parameter_value().integer_value # 读取阈值上限的参数值
- lower_red[0] = self.get_parameter('red_h_lower').get_parameter_value().integer_value # 读取阈值下限的参数值
- self.get_logger().info('Get Red H Upper: %d, Lower: %d' % (upper_red[0], lower_red[0])) # 通过日志打印读取到的参数值
- hsv_img = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 图像从BGR颜色模型转换为HSV模型
- mask_red = cv2.inRange(hsv_img, lower_red, upper_red) # 图像二值化
- contours, hierarchy = cv2.findContours(mask_red, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) # 图像中轮廓检测
- for cnt in contours: # 去除一些轮廓面积太小的噪声
- if cnt.shape[0] < 150:
- continue
- (x, y, w, h) = cv2.boundingRect(cnt) # 得到苹果所在轮廓的左上角xy像素坐标及轮廓范围的宽和高
- cv2.drawContours(image, [cnt], -1, (0, 255, 0), 2) # 将苹果的轮廓勾勒出来
- cv2.circle(image, (int(x+w/2), int(y+h/2)), 5, (0, 255, 0), -1) # 将苹果的图像中心点画出来
- cv2.imshow("object", image) # 使用OpenCV显示处理后的图像效果
- cv2.waitKey(50)
- def listener_callback(self, data):
- self.get_logger().info('Receiving video frame') # 输出日志信息,提示已进入回调函数
- image = self.cv_bridge.imgmsg_to_cv2(data, "bgr8") # 将ROS的图像消息转化成OpenCV图像
- self.object_detect(image) # 苹果检测
- def main(args=None): # ROS2节点主入口main函数
- rclpy.init(args=args) # ROS2 Python接口初始化
- node = ImageSubscriber("param_object_detect") # 创建ROS2节点对象并进行初始化
- rclpy.spin(node) # 循环等待ROS2退出
- node.destroy_node() # 销毁节点对象
- rclpy.shutdown() # 关闭ROS2 Python接口
复制代码 完成代码的编写后需要设置功能包的编译选项,让系统知道Python程序的入口,打开功能包的setup.py文件,加入如下入口点的配置:- entry_points={
- 'console_scripts': [
- 'param_declare = my_learning_parameter.param_declare:main',
- 'param_object_detect = my_learning_parameter.param_object_detect:main',
- ],
- },
复制代码 2.3.2 编译运行
编译程序:- pi@NanoPC-T6:~/dev_ws$ colcon build --paths src/my_learning_parameter
复制代码 启动第一个终端,第一个节点是相机驱动节点,发布图像数据;- pi@NanoPC-T6:~/dev_ws$ ros2 run usb_cam usb_cam_node_exe --ros-args -p video_device:="/dev/video21"
复制代码 启动第二个终端,订阅图像数据,并运行视觉识别功能,识别目标的位置;- pi@NanoPC-T6:~/dev_ws$ ros2 run my_learning_parameter param_object_detect
复制代码 在视觉识别节点中,我们故意将视觉识别中红色阈值的上限设置为0;- lower_red = np.array([0, 90, 128]) # 红色的HSV阈值下限
- upper_red = np.array([180, 255, 255]) # 红色的HSV阈值上限
- ......
- self.declare_parameter('red_h_upper', 0) # 创建一个参数,表示阈值上限
- self.declare_parameter('red_h_lower', 0) # 创建一个参数,表示阈值下限
- ......
- upper_red[0] = self.get_parameter('red_h_upper').get_parameter_value().integer_value # 读取阈值上限的参数值
- lower_red[0] = self.get_parameter('red_h_lower').get_parameter_value().integer_value
复制代码 HSV是一种将RGB颜色表示为三个分量的颜色模型:
- H (Hue):色相/色调 (0-180°);
- S (Saturation): 饱和度 (0-255);
- V (Value):明度/亮度 (0-255);
如果不修改参数,将无法实现目标识别。为了便于调整阈值,我们在节点中将红色阈值的限位修改为了ROS参数,通过命令行修改该参数的值,就可以实现视觉识别啦;- pi@NanoPC-T6:~/dev_ws$ ros2 param set param_object_detect red_h_upper 180
复制代码 2.4 参数命令行操作
参数相关命令:- pi@NanoPC-T6:~/dev_ws$ ros2 param
- usage: ros2 param [-h] Call `ros2 param <command> -h` for more detailed usage. ...
- Various param related sub-commands
- options:
- -h, --help show this help message and exit
- Commands:
- delete Delete parameter
- describe Show descriptive information about declared parameters
- dump Show all of the parameters of a node in a YAML file format
- get Get parameter
- list Output a list of available parameters
- load Load parameter file for a node
- set Set parameter
- Call `ros2 param <command> -h` for more detailed usage.
复制代码 2.4.1 查看参数列表
- pi@NanoPC-T6:~/dev_ws$ ros2 param list
- /param_object_detect:
- red_h_lower
- red_h_upper
- use_sim_time
- /usb_cam:
- auto_white_balance
- autoexposure
- autofocus
- ......
复制代码 可以看到我们实现的/param_object_detect节点有三个参数,其中:
- red_h_lower: 红色识别的最小色相阈值 (Hue lower);
- red_h_upper:红色识别的最大色相阈值 (Hue upper);
- use_sim_time :是否使用仿真时间。
red_h_lower和red_h_upper我们在代码里有定义,而use_sim_time 是ROS 2节点的一个内置默认参数,所有节点都会自动拥有这个参数,即使没有在代码中声明它。
2.4.2 获取参数值
- pi@NanoPC-T6:~/dev_ws$ ros2 param get /param_object_detect red_h_upper
- Integer value is: 180
复制代码 2.4.3 查询参数信息
- pi@NanoPC-T6:~/dev_ws$ ros2 param describe /param_object_detect red_h_lower
- Parameter name: red_h_lower
- Type: integer
- Constraints:
- pi@NanoPC-T6:~/dev_ws$ ros2 param describe /param_object_detect red_h_upper
- Parameter name: red_h_upper
- Type: integer
- Constraints:
复制代码 2.4.4 设置参数值
- pi@NanoPC-T6:~/dev_ws$ ros2 param set param_object_detect red_h_upper 180
复制代码 参考文章
[1] 古月居ROS2入门教程学习笔记
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |