第2章 ROS通信机制——参数服务器
2.3 参数服务器
参数服务器在ROS中主要用于实现不同节点之间的数据共享。参数服务器相当于是独立于所有节点的一个公共容器,可以将数据存储在该容器中,被不同的节点调用,当然不同的节点也可以往其中存储数据。
关于参数服务器的典型应用场景如下:导航实现时,会进行路径规划,比如:全局路径规划,设计一个从出发点到目标点的大致路径。本地路径规划,会根据当前路况生成时时的行进路径。
上述场景中,全局路径规划和本地路径规划时,就会使用到参数服务器:路径规划时,需要参考小车的尺寸,我们可以将这些尺寸信息存储到参数服务器,全局路径规划节点与本地路径规划节点都可以从参数服务器中调用这些参数参数服务器,一般适用于存在数据共享的一些应用场景。
概念:以共享的方式实现不同节点之间数据交互的通信模式。
作用:存储一些多节点共享的数据,类似于全局变量。
2.3.1参数服务器理论模型
参数服务器实现是最为简单的,该模型如下图所示,该模型中涉及到三个角色:
- 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
- 字典
注意:参数服务器不是为高性能而设计的,因此最好用于存储静态的非二进制的简单数据
2.3.2 参数操作(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
|
#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"; ros::NodeHandle nh; nh.setParam("nh_int", 10); nh.setParam("nh_double", 3.14); nh.setParam("nh_bool", true); nh.setParam("nh_string", "hello NodeHandle"); nh.setParam("nh_vector", stus); nh.setParam("nh_map", friends); nh.setParam("nh_int", 10000); 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; }
|
配置CMakeLists.txt,后面的操作同样需要设置不再说明
1 2 3 4 5 6
| add_executable(addParam src/addParam.cpp ) target_link_libraries(addParam ${catkin_LIBRARIES} )
|
编译之后运行
新终端
1 2
| source ./devel/setup.bash rosrun 包名 addParam
|
这样参数就会加入参数服务器,下面的命令查看参数
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
|
#include "ros/ros.h" int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); ros::init(argc, argv, "get_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); 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()); } ros::param::getCached("param_int", param_int_value); ROS_INFO("通过缓存获取数据:%d", param_int_value); 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; }
|
3.参数服务器删除参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
#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; }
|
2.3.3 参数操作(Python)
1.参数服务器新增(修改)参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| """ 参数服务器操作之新增与修改(二者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)
|
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
| """ 参数服务器操作之查询_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"]) int_cached = rospy.get_param_cached("p_int") rospy.loginfo("缓存数据:%d",int_cached)
names = rospy.get_param_names() for name in names: rospy.loginfo("name = %s",name) rospy.loginfo("-"*80) flag = rospy.has_param("p_int") rospy.loginfo("包含p_int吗?%d",flag) key = rospy.search_param("p_int") rospy.loginfo("搜索的键 = %s",key)
|
3.参数服务器删除参数
1 2 3 4 5 6 7 8 9 10 11 12 13
| """ 参数服务器操作之删除_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("删除失败")
|