【ROS2学习笔记】参数
前言
本系列博文是本人的学习笔记,自用为主,不是教程,学习请移步其他大佬的相关教程。前几篇学习资源来自鱼香ROS大佬的详细教程,适合深入学习,但对本人这样的初学者不算友好,后续笔记将以@古月居的ROS2入门21讲为主,侵权即删。
一、学习目标
- 理解 ROS 参数的核心概念 ——“全局共享的数据字典”,能用生活例子快速联想
- 掌握参数的 5 个核心命令行操作(查看、读取、修改、保存、加载)
- 学会在代码中实现 “参数声明→读取→修改” 的完整流程
- 理解参数在实际场景中的作用(如动态调整视觉阈值),能独立用参数优化节点
二、ROS 参数是什么?
2.1 一句话说清:ROS 中的 “全局共享变量”
参数是 ROS 系统中跨节点共享的数据容器,相当于 “全局字典”—— 所有节点都能访问、读取甚至修改这些数据,不用通过话题 / 服务通信。比如:相机节点的 “分辨率”、视觉节点的 “颜色阈值”、机器人的 “最大速度”,都可以用参数存储,方便所有节点共用。
2.2 用生活 / 编程例子类比(秒懂)
类比场景 | 对应 ROS 参数的逻辑 | 例子 |
---|---|---|
手机设置 | 手机的 “亮度”“音量” 是全局参数,所有 APP 都能响应 | 调亮屏幕后,微信、抖音的显示都变亮 |
编程全局变量 | 多个函数共享一个变量,不用反复传参 | C++ 中global int speed=5 ,多个函数都能调用speed |
字典(工具书) | 参数是 “键值对”(名字 = 值),按 “名字” 查 “值” | 键 =“robot_name”,值 =“mbot”;键 =“resolution”,值 =“1920x1080” |
2.3 ROS 参数的 3 个核心特性(为什么好用?)
- 全局共享:一个参数可以被多个节点访问(比如 “相机分辨率” 参数,相机节点、视觉节点都能读)
- 动态可改:运行中能随时修改参数值,修改后其他节点能立刻获取最新值(不用重启节点)
- 类型丰富:支持常见数据类型(字符串、整数、浮点数、布尔值),满足大部分场景需求
三、参数的命令行操作(最常用,小白优先掌握)
ROS 参数的命令行工具非常直观,所有操作都以ros2 param
开头,搭配小海龟案例实战,边练边记。
3.1 准备工作:启动小海龟节点
先打开 2 个终端,启动小海龟仿真器和键盘控制(后续所有命令都基于这个环境):
# 终端1:启动小海龟仿真器(会创建很多参数,比如背景色、海龟速度)
ros2 run turtlesim turtlesim_node
# 终端2:启动键盘控制(可选,不影响参数操作)
ros2 run turtlesim turtle_teleop_key
3.2 5 个核心命令(语法 + 示例 + 预期效果)
整理成表格,小白照着练就能会:
命令语法 | 功能说明 | 小海龟案例示例 | 预期输出 / 效果 |
---|---|---|---|
ros2 param list | 查看系统中所有参数(按 “节点名→参数名” 分类) | ros2 param list | 输出turtlesim.background_b (背景蓝通道)、turtlesim.background_g (背景绿通道)等 |
ros2 param describe <节点名> <参数名> | 查看某个参数的详细信息(类型、描述) | ros2 param describe turtlesim background_b | 输出 “Type: integer”(整数类型)、“Description: Blue channel of the background color”(背景色蓝通道) |
ros2 param get <节点名> <参数名> | 读取某个参数的当前值 | ros2 param get turtlesim background_b | 输出255 (默认背景蓝通道是 255,对应蓝色背景) |
ros2 param set <节点名> <参数名> <新值> | 修改某个参数的值(立即生效) | ros2 param set turtlesim background_b 10 | 小海龟窗口背景从 “蓝色” 变成 “深青色”(蓝通道从 255 降到 10) |
ros2 param dump <节点名> >> <文件名>.yaml | 将某个节点的所有参数保存到 YAML 文件(方便备份) | ros2 param dump turtlesim >> turtlesim_params.yaml | 在当前目录生成 turtlesim_params.yaml 文件,包含所有背景色、海龟参数 |
ros2 param load <节点名> <文件名>.yaml | 从 YAML 文件加载参数(一次性恢复所有参数) | 1. 先改背景绿通道:ros2 param set turtlesim background_g 10 2. 加载文件:ros2 param load turtlesim turtlesim_params.yaml | 背景绿通道恢复为默认值 255,窗口背景变回原来的蓝色 |
3.3 补充:YAML 文件是什么?(小白不用深究,会用就行)
YAML 是一种 “易读的配置文件格式”,专门用来存储键值对数据,ROS 参数保存后默认用这种格式。比如刚才保存的 turtlesim_params.yaml
文件内容(部分):
turtlesim:ros__parameters:background_b: 255background_g: 255background_r: 255use_sim_time: false
- 结构:
节点名→ros__parameters→参数名: 值
,清晰易懂,手动修改也很方便(比如把background_b
改成 100,再加载就生效)。
四、代码实战:参数的 “声明→读取→修改”
命令行适合手动操作,而代码能让参数 “自动化”(比如节点启动时自动声明参数,定时读取参数)。下面通过 2 个案例,从简单到复杂掌握代码逻辑。
案例 1:基础参数操作(声明 + 定时读取 + 自动重置)
场景说明
创建一个节点:
- 启动时声明参数
robot_name
,默认值是mbot
; - 每 2 秒读取一次
robot_name
的值,打印日志; - 读取后自动把参数重置为
mbot
(防止被手动修改后一直生效)。
步骤 1:创建功能包
先创建存放参数节点的功能包learning_parameter
:
cd dev_ws/src # 进入ROS工作空间的src目录
# 创建功能包,依赖rclpy(ROS2 Python核心库)和sensor_msgs(后续视觉案例用)
ros2 pkg create learning_parameter --build-type ament_python --dependencies rclpy sensor_msgs cv_bridge opencv-python numpy
步骤 2:代码实现(带逐行注释)
文件名:learning_parameter/param_declare.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
ROS2参数基础案例:
1. 声明参数robot_name(默认值mbot)
2. 每2秒读取参数并打印
3. 读取后自动重置参数为mbot
"""# 1. 导入需要的库
import rclpy # ROS2 Python核心库(初始化、节点操作等)
from rclpy.node import Node # ROS2节点类(所有自定义节点必须继承)# 2. 定义参数节点类(继承Node)
class ParameterNode(Node):def __init__(self, name):"""构造函数:初始化节点、定时器、参数"""# 调用父类Node的构造函数,给节点起名字:"param_declare"super().__init__(name) # 2.1 创建定时器:每2秒执行一次timer_callback函数(周期=2秒,回调函数=定时器处理逻辑)# 作用:定时读取参数,避免节点启动后只读一次self.timer = self.create_timer(2, self.timer_callback) # 2.2 声明参数:参数名=robot_name,默认值=mbot(如果没手动设置,就用这个默认值)# 声明后,这个参数会被注册到ROS系统的全局参数列表中self.declare_parameter('robot_name', 'mbot') def timer_callback(self):"""定时器回调函数:每2秒执行一次,读取参数→打印→重置参数"""# 3.1 读取参数值:从ROS系统中获取robot_name的当前值# 步骤:get_parameter(参数名) → 获取参数对象 → get_parameter_value() → 获取参数值 → .string_value(转成字符串类型)robot_name_param = self.get_parameter('robot_name').get_parameter_value().string_value # 3.2 打印日志:输出读取到的参数值(用info级别,绿色显示,清晰)self.get_logger().info(f'Hello {robot_name_param}!') # 格式:Hello mbot! / Hello turtle!# 3.3 重置参数:将robot_name改回默认值mbot(防止手动修改后一直生效)# ① 创建新的参数对象:参数名=robot_name,类型=字符串,值=mbotnew_name_param = rclpy.parameter.Parameter('robot_name', # 参数名rclpy.Parameter.Type.STRING, # 参数类型(字符串)'mbot' # 参数值)# ② 打包参数列表(set_parameters需要传入列表,支持一次改多个参数)all_new_parameters = [new_name_param]# ③ 发送参数修改请求,让ROS系统更新参数值self.set_parameters(all_new_parameters) # 3. 主入口函数:启动节点
def main(args=None): rclpy.init(args=args) # 初始化ROS2 Python接口(必须第一步)node = ParameterNode("param_declare") # 创建参数节点对象(节点名=param_declare)rclpy.spin(node) # 启动节点循环(让节点一直运行,处理定时器)node.destroy_node() # 关闭节点(程序退出时释放资源)rclpy.shutdown() # 关闭ROS2 Python接口
步骤 3:配置节点入口(让 ROS 找到程序)
打开learning_parameter/setup.py
,在entry_points
的console_scripts
中添加节点入口(告诉 ROS “运行哪个命令对应哪个代码”):
entry_points={'console_scripts': [# 格式:"命令名 = 包名.文件名:main函数"'param_declare = learning_parameter.param_declare:main',],
},
步骤 4:编译与运行(验证效果)
编译功能包:
cd dev_ws # 回到工作空间根目录 colcon build --packages-select learning_parameter # 只编译当前功能包(速度快) source install/setup.bash # 加载环境变量(每次编译后必须执行)
运行节点:
ros2 run learning_parameter param_declare # 预期输出:每2秒打印一次 "Hello mbot!"
手动修改参数(验证动态效果):打开新终端,执行修改命令:
source install/setup.bash # 先加载环境变量 ros2 param set param_declare robot_name turtle # 把robot_name改成turtle
- 预期效果:原终端会先打印一次 "Hello turtle!",下一次(2 秒后)恢复为 "Hello mbot!"(因为代码里有重置逻辑)。
案例 2:实战应用 —— 机器视觉阈值参数
场景说明
视觉识别中,“颜色阈值”(比如识别红色的 HSV 范围)对光线非常敏感:
- 白天可能需要
red_h_upper=180
,晚上可能需要red_h_upper=150
; - 每次改代码太麻烦,用参数动态调整,不用重启节点就能生效。
本案例实现:
- 视觉节点声明 2 个参数:
red_h_upper
(红色 HSV 上限,默认 0)、red_h_lower
(红色 HSV 下限,默认 0); - 每次接收图像时,读取最新的阈值参数,用新阈值识别红色目标;
- 手动修改参数后,立刻能看到识别效果变化。
步骤 1:代码实现(带逐行注释)
文件名:learning_parameter/param_object_detect.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
ROS2参数实战案例:用参数动态调整视觉识别的红色阈值
功能:1. 订阅相机图像 2. 读取阈值参数 3. 用参数值识别红色目标 4. 显示识别结果
"""# 1. 导入需要的库
import rclpy # ROS2 Python核心库
from rclpy.node import Node # ROS2节点类
from sensor_msgs.msg import Image # ROS标准图像消息类型(相机节点发布的图像)
from cv_bridge import CvBridge # ROS图像与OpenCV图像的转换工具
import cv2 # OpenCV库(图像处理、目标识别)
import numpy as np # 数值计算库(处理图像数组)# 2. 初始化红色HSV阈值(初始值会被参数覆盖,这里只是占位)
lower_red = np.array([0, 90, 128]) # 红色HSV下限(H:色调,S:饱和度,V:亮度)
upper_red = np.array([180, 255, 255]) # 红色HSV上限# 3. 定义视觉识别节点类(继承Node)
class ImageSubscriber(Node):def __init__(self, name):"""构造函数:初始化节点、订阅者、参数"""super().__init__(name) # 初始化节点,节点名=param_object_detect# 3.1 创建图像订阅者:订阅相机发布的"image_raw"话题self.sub = self.create_subscription(Image, # 消息类型(ROS标准图像)'image_raw', # 话题名(相机节点发布的图像话题)self.listener_callback, # 收到图像后的回调函数10 # 消息队列长度(缓存10张图,避免卡顿))# 3.2 创建CvBridge对象:将ROS图像(msg)转成OpenCV图像(array)self.cv_bridge = CvBridge() # 3.3 声明阈值参数:红色HSV的上下限(默认0,故意设为无效值,强迫手动修改)self.declare_parameter('red_h_upper', 0) # 红色H通道上限(参数名=red_h_upper,默认0)self.declare_parameter('red_h_lower', 0) # 红色H通道下限(参数名=red_h_lower,默认0)def object_detect(self, image):"""目标识别函数:读取参数→更新阈值→识别红色目标→显示结果"""# 4.1 读取阈值参数:从ROS系统获取最新的red_h_upper和red_h_lower# 注意:阈值是整数,所以用.integer_value转成int类型upper_red[0] = self.get_parameter('red_h_upper').get_parameter_value().integer_value # 更新H通道上限lower_red[0] = self.get_parameter('red_h_lower').get_parameter_value().integer_value # 更新H通道下限# 4.2 打印当前阈值:方便调试,确认参数是否生效self.get_logger().info(f'Get Red H Upper: {upper_red[0]}, Lower: {lower_red[0]}')# 4.3 图像处理:用最新阈值识别红色目标(OpenCV标准流程)hsv_img = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # BGR(OpenCV默认)→ HSV(便于颜色分割)mask_red = cv2.inRange(hsv_img, lower_red, upper_red) # 颜色分割:只保留红色区域(白色是目标,黑色是背景)# 轮廓检测:找到红色目标的边界(contours是轮廓列表)contours, hierarchy = cv2.findContours(mask_red, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)# 4.4 过滤小噪声,绘制目标轮廓和中心for cnt in contours: if cnt.shape[0] < 150: # 过滤面积太小的轮廓(避免把噪声当成目标)continue# 计算轮廓的外接矩形(x=左上角X,y=左上角Y,w=宽度,h=高度)(x, y, w, h) = cv2.boundingRect(cnt) cv2.drawContours(image, [cnt], -1, (0, 255, 0), 2) # 绘制轮廓(绿色,线宽2)# 绘制目标中心(绿色圆点,半径5,填充)cv2.circle(image, (int(x+w/2), int(y+h/2)), 5, (0, 255, 0), -1)# 4.5 显示识别结果(窗口名=object,每50ms刷新一次)cv2.imshow("object", image) cv2.waitKey(50)def listener_callback(self, data):"""图像订阅回调函数:收到相机图像→转成OpenCV格式→调用识别函数"""self.get_logger().info('Receiving video frame') # 打印日志,提示已收到图像# 将ROS图像消息(data)转成OpenCV图像(格式=bgr8,对应OpenCV的BGR)image = self.cv_bridge.imgmsg_to_cv2(data, "bgr8") self.object_detect(image) # 调用目标识别函数# 4. 主入口函数:启动节点
def main(args=None): rclpy.init(args=args) # 初始化ROS2 Python接口node = ImageSubscriber("param_object_detect") # 创建视觉节点对象(节点名=param_object_detect)rclpy.spin(node) # 启动节点循环(处理图像订阅)node.destroy_node() # 关闭节点cv2.destroyAllWindows() # 关闭OpenCV窗口(防止程序退出后窗口残留)rclpy.shutdown() # 关闭ROS2 Python接口
步骤 2:更新节点入口(添加新节点)
打开learning_parameter/setup.py
,在console_scripts
中添加视觉节点的入口:
entry_points={'console_scripts': ['param_declare = learning_parameter.param_declare:main','param_object_detect = learning_parameter.param_object_detect:main', # 新增视觉节点],
},
步骤 3:编译与运行(验证实战效果)
安装相机驱动(如果没有):本案例用 USB 相机,需要先安装
usb_cam
包:sudo apt install ros-humble-usb-cam # Humble是ROS2版本,其他版本替换成对应名称(如Iron)
编译功能包:
cd dev_ws colcon build --packages-select learning_parameter source install/setup.bash
运行 3 个终端(分步骤验证):
终端序号 命令 功能 / 预期效果 1 ros2 run usb_cam usb_cam_node_exe
启动 USB 相机,发布 image_raw
图像话题(相机正常工作时,会显示相机参数)2 ros2 run learning_parameter param_object_detect
启动视觉识别节点→打开 object
窗口→因阈值为 0,无法识别红色目标(窗口无绿色轮廓)3 ros2 param set param_object_detect red_h_upper 180
修改红色 H 通道上限为 180→终端 2 日志显示 “Upper: 180”→ object
窗口能识别红色目标(出现绿色轮廓)进阶操作(优化阈值):如果识别效果不好,可继续修改参数:
# 调整红色H通道下限为0,上限为180(适合大部分红色目标) ros2 param set param_object_detect red_h_lower 0 ros2 param set param_object_detect red_h_upper 180
五、参数命令行总结(复习必备)
将最常用的命令整理成 “速查表”,小白不用记语法,复习时看一眼就能用:
需求 | 命令 | 关键说明 |
---|---|---|
看所有参数 | ros2 param list | 按节点分组,清晰查看 |
查某个参数的类型 / 描述 | ros2 param describe <节点> <参数> | 知道参数能不能改、是什么类型 |
读参数当前值 | ros2 param get <节点> <参数> | 验证参数是否正确 |
改参数值(立即生效) | ros2 param set <节点> <参数> <值> | 动态调整,不用重启节点 |
备份节点的所有参数 | ros2 param dump <节点> >> <文件>.yaml | 换环境时直接加载,不用重新设置 |
恢复参数(从备份文件) | ros2 param load <节点> <文件>.yaml | 快速恢复配置,适合多节点部署 |
六、复习要点(小白必背)
- 参数本质:ROS 的 “全局共享字典”,跨节点共用数据,不用通信。
- 核心命令:
list
(看)、get
(读)、set
(改)、dump
(存)、load
(载)。 - 代码三步骤:
- 声明参数:
self.declare_parameter(参数名, 默认值)
- 读取参数:
self.get_parameter(参数名).get_parameter_value().类型
- 修改参数:
self.set_parameters([参数对象列表])
- 声明参数:
- 实战场景:动态调整阈值、分辨率、速度等(避免反复改代码)。
通过 “基础参数案例” 掌握语法,通过 “视觉阈值案例” 理解用途,小白就能轻松用参数优化 ROS 节点啦!