ROS6

参数服务器

理论模型

参数服务器实现是最为简单的,该模型如下图所示,该模型中涉及到三个角色:

  • master -> 管理者
  • talker -> 参数设置者
  • listener -> 参数调用者

ROS Master 作为一个公共容器保存参数,Talker 可以向容器中设置参数,Listener 可以获取参数。

img

整个流程由以下步骤实现:

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++ 实现

在 C++ 中实现参数服务器数据的增删改查,可以通过两套 API 实现:

  • ros::NodeHandle
  • ros::param

下面为具体操作演示

1.参数服务器新增(修改)参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/*
参数服务器操作之新增与修改(二者API一样)_C++实现:
在 roscpp 中提供了两套 API 实现参数操作
ros::NodeHandle
setParam("键",值)
ros::param
set("键","值")

示例:分别设置整形、浮点、字符串、bool、列表、字典等类型参数
修改(相同的键,不同的值)

*/
#include "ros/ros.h"

int main(int argc, char *argv[])
{
ros::init(argc,argv,"set_update_param");

std::vector<std::string> stus;
stus.push_back("zhangsan");
stus.push_back("李四");
stus.push_back("王五");
stus.push_back("孙大脑袋");

std::map<std::string,std::string> friends;
friends["guo"] = "huang";
friends["yuang"] = "xiao";

//NodeHandle--------------------------------------------------------
ros::NodeHandle nh;
nh.setParam("nh_int",10); //整型
nh.setParam("nh_double",3.14); //浮点型
nh.setParam("nh_bool",true); //bool
nh.setParam("nh_string","hello NodeHandle"); //字符串
nh.setParam("nh_vector",stus); // vector
nh.setParam("nh_map",friends); // map

//修改演示(相同的键,不同的值)
nh.setParam("nh_int",10000);

//param--------------------------------------------------------
ros::param::set("param_int",20);
ros::param::set("param_double",3.14);
ros::param::set("param_string","Hello Param");
ros::param::set("param_bool",false);
ros::param::set("param_vector",stus);
ros::param::set("param_map",friends);

//修改演示(相同的键,不同的值)
ros::param::set("param_int",20000);

return 0;
}
Copy

2.参数服务器获取参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
参数服务器操作之查询_C++实现:
在 roscpp 中提供了两套 API 实现参数操作
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 类似

*/

#include "ros/ros.h"

int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
ros::init(argc,argv,"get_param");

//NodeHandle--------------------------------------------------------
/*
ros::NodeHandle nh;
// param 函数
int res1 = nh.param("nh_int",100); // 键存在
int res2 = nh.param("nh_int2",100); // 键不存在
ROS_INFO("param获取结果:%d,%d",res1,res2);

// getParam 函数
int nh_int_value;
double nh_double_value;
bool nh_bool_value;
std::string nh_string_value;
std::vector<std::string> stus;
std::map<std::string, std::string> friends;

nh.getParam("nh_int",nh_int_value);
nh.getParam("nh_double",nh_double_value);
nh.getParam("nh_bool",nh_bool_value);
nh.getParam("nh_string",nh_string_value);
nh.getParam("nh_vector",stus);
nh.getParam("nh_map",friends);

ROS_INFO("getParam获取的结果:%d,%.2f,%s,%d",
nh_int_value,
nh_double_value,
nh_string_value.c_str(),
nh_bool_value
);
for (auto &&stu : stus)
{
ROS_INFO("stus 元素:%s",stu.c_str());
}

for (auto &&f : friends)
{
ROS_INFO("map 元素:%s = %s",f.first.c_str(), f.second.c_str());
}

// getParamCached()
nh.getParamCached("nh_int",nh_int_value);
ROS_INFO("通过缓存获取数据:%d",nh_int_value);

//getParamNames()
std::vector<std::string> param_names1;
nh.getParamNames(param_names1);
for (auto &&name : param_names1)
{
ROS_INFO("名称解析name = %s",name.c_str());
}
ROS_INFO("----------------------------");

ROS_INFO("存在 nh_int 吗? %d",nh.hasParam("nh_int"));
ROS_INFO("存在 nh_intttt 吗? %d",nh.hasParam("nh_intttt"));

std::string key;
nh.searchParam("nh_int",key);
ROS_INFO("搜索键:%s",key.c_str());
*/
//param--------------------------------------------------------
ROS_INFO("++++++++++++++++++++++++++++++++++++++++");
int res3 = ros::param::param("param_int",20); //存在
int res4 = ros::param::param("param_int2",20); // 不存在返回默认
ROS_INFO("param获取结果:%d,%d",res3,res4);

// getParam 函数
int param_int_value;
double param_double_value;
bool param_bool_value;
std::string param_string_value;
std::vector<std::string> param_stus;
std::map<std::string, std::string> param_friends;

ros::param::get("param_int",param_int_value);
ros::param::get("param_double",param_double_value);
ros::param::get("param_bool",param_bool_value);
ros::param::get("param_string",param_string_value);
ros::param::get("param_vector",param_stus);
ros::param::get("param_map",param_friends);

ROS_INFO("getParam获取的结果:%d,%.2f,%s,%d",
param_int_value,
param_double_value,
param_string_value.c_str(),
param_bool_value
);
for (auto &&stu : param_stus)
{
ROS_INFO("stus 元素:%s",stu.c_str());
}

for (auto &&f : param_friends)
{
ROS_INFO("map 元素:%s = %s",f.first.c_str(), f.second.c_str());
}

// getParamCached()
ros::param::getCached("param_int",param_int_value);
ROS_INFO("通过缓存获取数据:%d",param_int_value);

//getParamNames()
std::vector<std::string> param_names2;
ros::param::getParamNames(param_names2);
for (auto &&name : param_names2)
{
ROS_INFO("名称解析name = %s",name.c_str());
}
ROS_INFO("----------------------------");

ROS_INFO("存在 param_int 吗? %d",ros::param::has("param_int"));
ROS_INFO("存在 param_intttt 吗? %d",ros::param::has("param_intttt"));

std::string key;
ros::param::search("param_int",key);
ROS_INFO("搜索键:%s",key.c_str());

return 0;
}
Copy

3.参数服务器删除参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/* 
参数服务器操作之删除_C++实现:

ros::NodeHandle
deleteParam("键")
根据键删除参数,删除成功,返回 true,否则(参数不存在),返回 false

ros::param
del("键")
根据键删除参数,删除成功,返回 true,否则(参数不存在),返回 false


*/
#include "ros/ros.h"


int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
ros::init(argc,argv,"delete_param");

ros::NodeHandle nh;
bool r1 = nh.deleteParam("nh_int");
ROS_INFO("nh 删除结果:%d",r1);

bool r2 = ros::param::del("param_int");
ROS_INFO("param 删除结果:%d",r2);

return 0;
}

Python实现

1.参数服务器新增(修改)参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#! /usr/bin/env python
"""
参数服务器操作之新增与修改(二者API一样)_Python实现:
"""

import rospy

if __name__ == "__main__":
rospy.init_node("set_update_paramter_p")

# 设置各种类型参数
rospy.set_param("p_int",10)
rospy.set_param("p_double",3.14)
rospy.set_param("p_bool",True)
rospy.set_param("p_string","hello python")
rospy.set_param("p_list",["hello","haha","xixi"])
rospy.set_param("p_dict",{"name":"hulu","age":8})

# 修改
rospy.set_param("p_int",100)
Copy

2.参数服务器获取参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#! /usr/bin/env python

"""
参数服务器操作之查询_Python实现:
get_param(键,默认值)
当键存在时,返回对应的值,如果不存在返回默认值
get_param_cached
get_param_names
has_param
search_param
"""

import rospy

if __name__ == "__main__":
rospy.init_node("get_param_p")

#获取参数
int_value = rospy.get_param("p_int",10000)
double_value = rospy.get_param("p_double")
bool_value = rospy.get_param("p_bool")
string_value = rospy.get_param("p_string")
p_list = rospy.get_param("p_list")
p_dict = rospy.get_param("p_dict")

rospy.loginfo("获取的数据:%d,%.2f,%d,%s",
int_value,
double_value,
bool_value,
string_value)
for ele in p_list:
rospy.loginfo("ele = %s", ele)

rospy.loginfo("name = %s, age = %d",p_dict["name"],p_dict["age"])

# get_param_cached
int_cached = rospy.get_param_cached("p_int")
rospy.loginfo("缓存数据:%d",int_cached)

# get_param_names
names = rospy.get_param_names()
for name in names:
rospy.loginfo("name = %s",name)

rospy.loginfo("-"*80)

# has_param
flag = rospy.has_param("p_int")
rospy.loginfo("包含p_int吗?%d",flag)

# search_param
key = rospy.search_param("p_int")
rospy.loginfo("搜索的键 = %s",key)
Copy

3.参数服务器删除参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#! /usr/bin/env python
"""
参数服务器操作之删除_Python实现:
rospy.delete_param("键")
键存在时,可以删除成功,键不存在时,会抛出异常
"""
import rospy

if __name__ == "__main__":
rospy.init_node("delete_param_p")

try:
rospy.delete_param("p_int")
except Exception as e:
rospy.loginfo("删除失败")