目錄
一、參數服務器概念
二、參數操作
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")