ros学习笔记(6)——参数服务器
- 一、参数服务器理论模型
- 二、参数服务器操作
- 2.1参数服务器新增(修改)参数
- 2.1.1 写cpp文件
- 2.1.2 修改CMake
- 2.1.3 实验效果
- 2.2 参数服务器获取参数
- 2.2.1 写cpp文件
- 2.2.1.1 问题排查
- 2.2.2 修改CMake
- 2.2.3 实验效果
- 2.3 参数服务器删除参数
- 2.3.1 写cpp文件
- 2.3.2 修改CMake
- 2.3.3 实验效果
一、参数服务器理论模型
参数服务器实现是最为简单的,该模型如下图所示,该模型中涉及到三个角色:
- ROS Master (管理者)
- Talker (参数设置者)
- Listener (参数调用者)
ROS Master 作为一个公共容器保存参数,Talker 可以向容器中设置参数,Listener 可以获取参数。
整个流程由以下步骤实现:
1.Talker 设置参数 Talker 通过 RPC 向参数服务器发送参数(包括参数名与参数值),ROS Master 将参数保存到参数列表中。
2.Listener 获取参数 Listener 通过 RPC 向参数服务器发送参数查找请求,请求中包含要查找的参数名。
3.ROS Master 向 Listener 发送参数值 ROS Master 根据步骤2请求提供的参数名查找参数值,并将查询结果通过 RPC 发送给 Listener。
参数可使用数据类型:
32-bit integers
booleans
strings
doubles
iso8601 dates
lists
base64-encoded binary data
字典
注意:参数服务器不是为高性能而设计的,因此最好用于存储静态的非二进制的简单数据
二、参数服务器操作
需求:实现参数服务器参数的增删改查操作。
在 C++ 中实现参数服务器数据的增删改查,可以通过两套 API 实现:
ros::NodeHandle
ros::param
下面为具体操作演示
2.1参数服务器新增(修改)参数
2.1.1 写cpp文件
在功能包下面的src添加cpp文件
#include"ros/ros.h"/* 需要实现参数的新增和修改 需求:首先设置机器人共享参数,类型,半径(0.15m) 再修改半径(0.2m) 实现: ros::NodeHandle setParam() ros::param set() 修改,只需要继续调用函数,保证键是已经存在的,那么值会覆盖 */intmain(intargc,char*argv[]){//初始化ros节点ros::init(argc,argv,"demo01_param_set");//创建ros节点句柄ros::NodeHandle nh;//参数增---------------//方案一:nhnh.setParam("car_type","xaiomisu7");nh.setParam("car_radius",0.15);//方案二:ros::paramros::param::set("type_param","xiaomisu8");ros::param::set("radius_param",0.15);//参数改---------------//方案一:nhnh.setParam("car_radius",0.2);//其实是参数的覆盖//方案二:ros::paramros::param::set("car_radius",0.25);return0;}2.1.2 修改CMake
添加add_executable和target_link_libraries函数。分别在136行和149-151行
add_executable(demo01_param_set src/demo01_param_set.cpp)target_link_libraries(demo01_param_set ${catkin_LIBRARIES} )2.1.3 实验效果
编译
启动ros
source一下然后rosrun
source./devel/setup.bash rosrun plumbing_permit_sever demo01_param_set
开一个新终端source一下,然后用rosparam list可以列出现在的参数列表rosparam get 参数名可以看到具体参数
source./devel/setup.bash rosparam list rosparam get car_radius2.2 参数服务器获取参数
2.2.1 写cpp文件
在功能包下的src目录下添加cpp文件
内容如下:
#include"ros/ros.h"/* 演示参数查询 实现: ros::NodeHandle param(键,默认值) 存在,返回对应结果,否则返回默认值 getParam(键,存储结果的变量) 存在,返回 true,且将值赋值给参数2 若果键不存在,那么返回值为 false,且不为参数2赋值 getParamCached键,存储结果的变量)--提高变量获取效率 存在,返回 true,且将值赋值给参数2 若果键不存在,那么返回值为 false,且不为参数2赋值 getParamNames(std::vector<std::string>) 获取所有的键,并存储在参数 vector 中 hasParam(键) 是否包含某个键,存在返回 true,否则返回 false searchParam(参数1,参数2) 搜索键,参数1是被搜索的键,参数2存储搜索结果的变量 ros::param ----- 与 NodeHandle 类似 */intmain(intargc,char*argv[]){//设置编码setlocale(LC_ALL,"");//初始化ros节点ros::init(argc,argv,"param_get");//创建节点句柄ros::NodeHandle nh;//ros::NodeHandle------------------------------//1.paramdoubleradius=nh.param("radius",10);ROS_INFO("半径是 = %.2f",radius);//2.getParamdoubleradius2=0.0;boolresult=nh.getParam("radius_param",radius2);if(result){ROS_INFO("getParam获取的半径是 = %.2f",radius2);}else{ROS_INFO("getParam获取失败");}//3.getParamCached//getParamCached 和 getParam一样,只是在性能上有提升,一般的测试性能提升肉眼不可见// double radius2 = 0.0;// bool result = nh.getParamCached("radius_param",radius2);if(result){ROS_INFO("getParamCached获取的半径是 = %.2f",radius2);}else{ROS_INFO("getParamCached获取失败");}//4.getParamNamesstd::vector<std::string>names;nh.getParamNames(names);for(auto&&name:names){ROS_INFO("遍历的元素:%s",name.c_str());}//5.hasParamboolflag1=nh.hasParam("radius_param");boolflag2=nh.hasParam("radius");ROS_INFO("radius_param是否存在:%d",flag1);ROS_INFO("radius是否存:%d",flag2);//6.searchParamstd::string key1;std::string key2;nh.searchParam("radius_param",key1);nh.searchParam("radius",key2);ROS_INFO("搜索的结果 = %s",key1.c_str());ROS_INFO("搜索的结果 = %s",key2.c_str());return0;}2.2.1.1 问题排查
在看着老师的视频跟练第二个的时候
//ros::NodeHandle------------------------------//1.paramdoubleradius=nh.param("radius",10);ROS_INFO("半径是 = %.2f",radius);//2.getParamdoubleradius2=0.0;boolresult=nh.getParam("radius",radius2);if(result){ROS_INFO("getParam获取的半径是 = %.2f",radius2);}else{ROS_INFO("getParam获取失败");}运行结果是
这是因为:
代码查找的是/radius,但参数服务器里实际存在的是/radius_param,它们不是同一个参数。
看一下参数列表
rosparam list
参数应该是:
/radius_param而代码是:
doubleradius2=0.0;boolresult=nh.getParam("radius",radius2);普通节点句柄:
ros::NodeHandle nh;会把"radius"解析成全局参数:
/radius由于参数服务器没有/radius,所以:
result==false于是程序输出:
获取失败为什么上一行还能显示 10?
doubleradius=nh.param("radius",10);param()和getParam()的行为不同:
nh.param("radius",10);意思是:
尝试获取
/radius,获取不到就使用默认值10。
所以输出10.00并不代表成功读取到了参数,而是使用了默认值。
而:
nh.getParam("radius",radius2);没有提供默认值,找不到就返回false。
2.2.2 修改CMake
添加add_executable和target_link_libraries函数。分别在136行和149-151行
add_executable(demo01_param_get src/demo01_param_get.cpp)target_link_libraries(demo01_param_get ${catkin_LIBRARIES} )2.2.3 实验效果
编译
启动ros
source一下然后rosrun
source./devel/setup.bash rosrun plumbing_permit_sever demo01_param_get2.3 参数服务器删除参数
2.3.1 写cpp文件
在功能包下的src目录下添加cpp文件
内容如下:
#include"ros/ros.h"/* 演示参数的删除: 实现: ros::NodeHandle deleteParam() ros::param del() */intmain(intargc,char*argv[]){setlocale(LC_ALL,"");ros::init(argc,argv,"param_del");ros::NodeHandle nh;//删除:ros::NodeHandle-----------------boolflag1=nh.deleteParam("radius_param");if(flag1){ROS_INFO("deleteParam删除radius_param成功");}else{ROS_INFO("deleteParam删除radius_param失败");}boolflag2=nh.deleteParam("radius");if(flag2){ROS_INFO("deleteParam删除radius成功");}else{ROS_INFO("deleteParam删除radius失败");}//删除:ros::param----------------------boolflag3=ros::param::del("car_type");if(flag3){ROS_INFO("ros::param::del删除car_type成功");}else{ROS_INFO("ros::param::del删除car_type失败");}boolflag4=ros::param::del("type");if(flag4){ROS_INFO("ros::param::del删除type成功");}else{ROS_INFO("ros::param::del删除type失败");}return0;}2.3.2 修改CMake
添加add_executable和target_link_libraries函数。分别在136行和149-151行
add_executable(demo01_param_del src/demo01_param_del.cpp)target_link_libraries(demo01_param_del ${catkin_LIBRARIES} )2.3.3 实验效果
编译
启动ros
source一下然后rosrun
source./devel/setup.bash rosrun plumbing_permit_sever demo01_param_del开一个新终端source一下,
再rosparam list一下,看到去试试被删除了
学习的为赵虚左老师的教程 1.老师的文档 2.老师的视频
在笔记上理论部分大量参考了老师的文档