参数服务器是以共享方式实现不同节点间数据交互的通信方式。主要用于存储多节点共享的数据,类似于全局变量。ROS中的参数服务器主要包含三个角色,分别是ROS Master(节点管理者)、Talker(参数设置者)、Listener(参数使用者),其中Talker和Listener均通过RPC协议进行数据的交互,ROS Master根据Listener提供的请求,查询参数,并通过RPC协议将其发送给Listener,由于通信协议的限制,参数服务器适用于不是高性能的场景,一般用于存储一些非二进制的静态简单数据。
C++实现参数服务器
1 Talker(参数设置者)
#include "ros/ros.h"
/**
* @brief
* 实现参数服务器数据的增加和修改
* 即 设置一个参数,然后修改其值
* @param argc
* @param argv
* @return int
*/
int main(int argc,char *argv[]){
setlocale(LC_ALL,"");
//初始化ros节点
ros::init(argc,argv,"set_param_c");
//创建句柄
ros::NodeHandle nh;
//使用句柄创建参数服务器
nh.setParam("type","ceshi");
nh.setParam("radius",1.0);
//使用ros::param来设置参数
ros::param::set("type_param","ceshi_1");
ros::param::set("radius_param",1.2);
return 0;
}
1.1 CmakeLists.txt的配置,这个和普通节点的配置一样了
1.2 测试
打开终端,启动主节点 roscore
roscore
打开终端,启动配置好的C++节点
source ./devel/setup.bash
#该步骤会自动将参数发布至 rosparam list
rosrun plumbing_param_server ps_set_node
打开终端,使用rosparam list 查看话题
然后可以使用下面命令对参数进行操作
rosparam get /type# 得到参数ceshi
rosparam set /type 123#可以修改 /type的值
2 Listener(参数获取)
记录nodeHandler参数的获取方法,定义 param_server_get.cpp 文件,然后内容如下:
#include "ros/ros.h"
int main(int argc,char *argv[]){
setlocale(LC_ALL,"");
ros::init(argc,argv,"get_para");
ros::NodeHandle nh;
//nodehandler实现
//1 param(键,默认值),键值不存在,则返回默认值
double radius = nh.param("radius",0.01);
ROS_INFO("the radius param=%.2f",radius);
//2. getParam(键,存储的返回值变量)
//如果键存在,则返回true,且将返回值赋值给变量
double res = 0.0;
bool flag = nh.getParam("radius",res);
if(flag){
ROS_INFO("the res is :%.2f",res);
}else{
ROS_INFO("the res not exists..");
}
//3. getParamCached(键,存储的返回值变量) 从缓存中获取数据
//如果之前获取过,则返回true,一般速度较快 并将 值赋值给返回值变量
flag = nh.getParamCached("radius",res);
if(flag){
ROS_INFO("the cached res is :%.2f",res);
}else{
ROS_INFO("the cached res not exists..");
}
//4 getParamNames(std::vector<std::string>)
std::vector<std::string> names;
nh.getParamNames(names);
for(auto &&name : names){
ROS_INFO("the param name is: %s",name.c_str());
}
//5 hasParam(string) 有 true 无 false
bool flag1 = nh.hasParam("radius");
bool flag2 = nh.hasParam("tt");
ROS_INFO("the flag1 res: %d, the flag2 res: %d",flag1,flag2);
//searchParam("keyName",res)
// 如果 keyName存在,则将keyName 返回给res
std::string r;
nh.searchParam("radius",r);
ROS_INFO("the res %s",r.c_str());
return 0;
}
2.1 将上面的 param_server_get,cpp 配置到 CmakeLists.txt
2.2 打开终端,先启动 roscore
2.3 启动 Talker 节点,发布参数
source ./devel/setup.bash
rosrun plumbing_param_server ps_set_node
2.4 启动Listener节点,获取参数
source ./devel/setup.bash
rosrun plumbing_param_server ps_get_node
3. 使用ros::param获取参数
如果以上使用NodeHandler获取参数看懂了,下面使用ros::param进行获取其实是大差不差,可以看下图的 API
部分源代码:
#include "ros/ros.h"
int main(int argc,char *argv[]){
setlocale(LC_ALL,"");
ros::init(argc,argv,"get_para");
// ros::param下面的参数获取
double re = ros::param::param("radius",0.2);
ROS_INFO("rosParam res: %.2f",re);
//等价于std::vector<std::string> nameRes;
ros::V_string nameRes;
ros::param::getParamNames(nameRes);
for(auto &&name : nameRes){
ROS_INFO("the name :%s",name.c_str());
}
return 0;
}
执行过程和上面的一样,可以看到最终的执行结果
3 删除节点
创建 param_server_del.cpp 文件
#include "ros/ros.h"
int main(int argc,char *argv[]){
ros::init(argc,argv,"del_para");
ros::NodeHandle nh;
//nh.deleteParam
bool flag = nh.deleteParam("radius");
if(flag){
ROS_INFO("delete complete...");
}else{
ROS_INFO("Wrong...");
}
//ros:param::del
bool flag1 = ros::param::del("radius");
if(flag1){
ROS_INFO("delete success");
}else{
ROS_INFO("delete wrong");
}
return 0;
}
先运行 param_server_set.cpp 节点,然后再进行按照键值删除。注意不要忘了配置CMakeLists.txt,和上面的配置方法相同, 配置完全后,再进行运行即可。
Python实现参数服务器
1 设置参数
#! /usr/bin/env python
# -*- coding:utf-8 -*-
import rospy
if __name__=="__main__":
#初始化node
rospy.init_node("set_param_server_p")
#设置参数
rospy.set_param("type_p","set_server")
rospy.set_param("radius",1.0)
rospy.set_param("p_list",[1,2,3])
1.1 在 CMakeLists.txt 中设置 Python 脚本的执行
1.2 编译,随后切换到 scripts文件目录,使用以下命令:
chmod +x *.py #修改python 文件的可执行权限
1.3 打开终端 运行 roscore
1.4 运行新建立的节点
source ./devel/setup.bash
rosrun plumbing_param_s(你的项目名) param_server_set.py#即可设置参数
2 获取参数
#! /usr/bin/env python
# -*- coding:utf-8 -*-
import rospy
'''
get_param_cached
get_param_names
has_param
search_param
'''
if __name__=="__main__":
rospy.init_node("param_server_get")
type_p = rospy.get_param("type_p","aa")
rospy.loginfo("info : %s",type_p)
type_p = rospy.get_param_cached("type_p","aa")
rospy.loginfo("info : %s",type_p)
names = rospy.get_param_names()
for name in names:
rospy.loginfo("res: %s",name)
if rospy.has_param("type_p"):
rospy.loginfo("the type_p : %s",rospy.get_param("type_p"))
else:
rospy.loginfo("wrong ... ")
key = rospy.search_param("type_p")
rospy.loginfo(key)
执行过程和上面的 set.py 同
3 删除参数
#! /usr/bin/env python
# -*- coding:utf-8 -*-
import rospy
if __name__=="__main__":
rospy.init_node("del_p")
try:
rospy.delete_param("type_p")
except Exception as e:
rospy.loginfo("key is not exists")
执行过程和上面的 set.py 同