【ROS1】09-ROS通信机制——参数服务器
目录
一、参数服务器概念
二、参数操作
2.1 C++实现
2.1.1 新增参数
2.1.2 修改参数
2.1.3 查询参数
2.1.4 删除参数
2.2 python实现
2.2.1 新增参数
2.2.2 修改参数
2.2.3 查询参数
2.2.4 删除参数
一、参数服务器概念
假设正在开发一个复杂的机器人应用,里面有很多需要配置的数值,比如:
-
机器人的物理尺寸(轮子直径、轮距)
-
PID 控制器的增益参数(Kp, Ki, Kd)
-
传感器的配置(相机分辨率、激光雷达扫描频率)
-
导航算法的参数(避障距离、目标容忍度)
你当然可以把这些数值硬编码(hard-code)在你的 C++ 或 Python 代码里。但这样做有几个巨大的缺点:
-
修改困难:每次想调整一个参数,都必须重新修改代码、重新编译、重新部署。
-
复用性差:同一个算法用在不同机器人上,参数不同,就需要维护多个版本的代码。
-
管理混乱:参数散落在各个节点的代码中,难以集中查看和管理。
参数服务器就是为了解决这些问题而生的。它是一个全局的、集中式的、运行在 ROS Master 内部的字典(dictionary),能够存储一些多节点共享的数据,类似于全局变量。
这个“字典”可以存储各种基本数据类型的键值对(Key-Value pairs),任何 ROS 节点都可以在运行时存入 (set)、查询 (get) 和 删除 (delete) 这些参数。
核心特点:
-
集中存储: 所有参数都存储在一个地方(ROS Master),方便管理和调试。
-
全局可访问: 任何连接到同一个 ROS Master 的节点都可以访问这些参数。
-
动态配置: 可以在节点运行时动态地修改参数,而无需重启节点(需要节点代码支持动态重配置)。
-
与代码解耦: 将配置参数从业务逻辑代码中分离出来,提高了代码的通用性和可维护性。
-
支持多种数据类型: 支持字符串、整数、浮点数、布尔值、列表(数组)和字典(结构体)。
注意:参数服务器不是为高性能而设计的,因此最好用于存储静态的非二进制的简单数据。
二、参数操作
2.1 C++实现
2.1.1 新增参数
进入到工作空间的src目录下,输入如下指令来创建一个名为“plumbing_param_server”的功能包
在功能包的src目录下新建一个cpp文件,这里命名为“demo01_param_set.cpp”
在“demo01_param_set.cpp”中添加如下代码来实现参数的新增
#include "ros/ros.h"/*
需求:实现参数的新增
实现:ros::NodeHandle.setParam()ros::param.set()
*/int main(int argc, char *argv[])
{// 初始化ROS节点ros::init(argc, argv, "set_param_c");// 创建ROS节点句柄ros::NodeHandle nh;// 参数增加// 方式1nh.setParam("type", "type1");nh.setParam("radius", 0.15);// // 方式2// ros::param::set("type", "type1");// ros::param::set("radius", 0.15);return 0;
}
打开功能包下的“CMakeLists.txt”,添加如下部分
Ctrl+Shift+B编译一下,然后开启3个终端窗口分别用于启动ROS核心、启动ROS节点、查看参数
roscore // 启动ROS核心source ./devel/setup.bash
rosrun plumbing_param_server demo01_param_set //启动ROS节点rosparam list //列出参数
如果想查询参数的值,可以使用如下命令
rosparam get 参数名
2.1.2 修改参数
如果再次设置相同参数名,就会覆盖之前参数名对应的参数值
2.1.3 查询参数
在功能包的src目录中新创建一个cpp文件,这里命名为“demo02_param_get.cpp”
在“demo02_param_get.cpp” 添加如下代码,用于展示如何执行参数的相关查询操作
#include "ros/ros.h"/*
需求:实现参数的查询
实现:ros::NodeHandle.param(键,默认值) 存在这个键方法返回存储的值,否则返回默认值.getParam(键,变量) 存在这个键方法返回true并将存储的值赋值给变量,否则返回false,且不为变量赋值.getparamCached(键,变量) 和.getParam基本一样.getParamNames(td::vector<std::string>) 获取所有的键并存储在vector中.hasParam(键) 判断是否存在某个键,存在返回true,否则返回false.searchParam(键,变量) 能够搜索到就将“/”+键名赋值给变量,否则将空字符串赋给变量ros::param
*/int main(int argc, char *argv[])
{setlocale(LC_ALL,"");// 初始化ROS节点ros::init(argc, argv, "get_param_c");// 创建ROS节点句柄ros::NodeHandle nh;// ros::NodeHandle// 1. paramdouble radius = nh.param("radius", 0.5); //查询参数名为“radius”对应的值,如果“radius”不存在返回0.5ROS_INFO("radius = %.2f", radius);// 2. getParamdouble radius2 = 0.0;bool result = nh.getParam("radius", radius2);if (result){ROS_INFO("radius = %.2f", radius2);}// 3.getparamCached// 4.getParamNamesstd::vector<std::string> names;nh.getParamNames(names);for (auto &&name : names){ROS_INFO("遍历的元素:%s", name.c_str());}// 5.hasParambool flag = nh.hasParam("radius");// 6.searchParamstd::string key;nh.searchParam("radius", key);ROS_INFO("搜索结果:%s", key.c_str());return 0;
}
打开功能包中的“CMakeLists.txt”,添加如下部分
编译一下,该节点执行效果如下:
2.1.4 删除参数
删除参数主要通过如下两种方式实现
#include "ros/ros.h"/*
删除参数:实现:ros::NodeHandle.delParam()ros::param.del()*/int main(int argc, char *argv[])
{setlocale(LC_ALL,"");ros::init(argc, argv, "param_del_c");ros::NodeHandle nh;bool flag = nh.deleteParam("radius");if (flag){ROS_INFO("删除成功!");}else{ROS_INFO("删除失败!");}// ros::param::del("radius");return 0;
}
运行效果如下,可以看到成功删除了“radius”参数
2.2 python实现
2.2.1 新增参数
在功能包中添加一个“scripts”目录
在“scripts”目录添加一个python文件,用于新增参数
#! /usr/bin/env python
# -*- coding: utf-8 -*-import rospyif __name__ == "__main__":rospy.init_node("param_set_py")rospy.set_param("name", "czc")rospy.set_param("age", 18)
在“CMakeLists.txt”中添加如下部分
为python文件添加可执行权限
chmod +x *.py
可以看到成功添加了两个参数
2.2.2 修改参数
只需重新设置一下相同键名的参数,那么参数值就会被重新覆盖
2.2.3 查询参数
参数查询可通过如下方法实现
1. get_param
2. get_param_cached
3. get_param names
4. has_param
5. search param
示例:
import rospyif __name__ == "__main__":rospy.init_node('param_example_node')# 1. get_param - 获取参数值,支持默认值name1 = rospy.get_param('name', 'default_name')print(f"Name1: {name1}")# 2. get_param_cached - 缓存参数值,减少RPC调用name2 = rospy.get_param_cached('name', 'default_name')print(f"Name2: {name2}")# 3. get_param_names - 获取所有参数名称all_params = rospy.get_param_names()for param in all_params:print(f"param: - {param}")# 4. has_param - 检查参数是否存在has_name = rospy.has_param('name')print(f"Has Param: {has_name}")# 5. search_param key = rospy.search_param('name')rospy.loginfo("key = %s", key)rospy.spin()
执行效果如下:
2.2.4 删除参数
rospy.delete_param("Key")