【ROS 基础教学系列】ROS参数服务器(Param)

农民  金牌会员 | 2024-11-14 04:24:01 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 871|帖子 871|积分 2613

ROS 基础教学系列-ROS参数服务器(Param)


  

前言

参数服务器在ROS中重要用于实现不同节点之间的数据共享。
参数服务器相当于是独立于全部节点的一个公共容器,可以将数据存储在该容器中,被不同的节点调用,当然不同的节点也可以往其中存储数据。
使用场景一般存储一些机器人的固有参数,如产品定义、全局配置等。
重要头脑就是一个共享数据域,供不同节点使用。

一、参数服务器通讯模型

参数服务器模型涉及到三个角色:


  • Master (管理者)
  • Setter(设置者)
  • User(使用者)
Master 负责管理参数与 Setter/User 的利用,Setter 可以向 Master 设置参数,User 可以从 Master 获取参数。
这里只是方便分析,实际上通讯方利用参数前不会向 ROS Master 注册身份信息,以是对 ROS Master 而言,没有 Setter 与 User 之分,每个访问参数服务器的通讯方都是使用者。

通讯流程:
1)Setter设置参数
​ Setter 通过 RPC 向参数服务器设置参数(包罗参数名与参数值),ROS Master 将参数生存到参数列表中。
2)User获取参数
​ User 通过 RPC 向参数服务器发送参数查找请求,请求中包含要查找的参数名。
3)ROS Master返回参数信息
​ ROS Master 根据请求提供的参数名查找参数值,并将查询结果通过 RPC 发送给 User。
参数服务器使用 XMLRPC 数据格式存储参数,支持的数据范例如下:


  • 32-bit integers
  • booleans
  • strings
  • doubles
  • iso8601 dates
  • lists
  • base64-encoded binary data

二、Param Hello World

代码学习开始于 Hello World,同样,使用Hello World先容参数服务器的简单使用。
使用参数服务器,通讯方利用参数前没有向 ROS Master 注册身份信息,直接对参数进行利用。
接下来实现一个简单的参数利用,设置不同数据范例的参数,如机器人的 名字(name)、长(length)、宽(width)、高(height) 等,并对其进行读取删除等利用。
2.1 创建并初始化功能包

(这一步不是必须,这里只是为了方便清楚的分析,也可以使用已有的包,在包里新增节点等方法)
首先创建 param_hello_world 包,下令如下:
  1. catkin_create_pkg param_hello_world roscpp rospy
复制代码
创建后,文件布局如下:

2.2 利用参数(C++版)

ROS 为 C++ 提供了两套 API,如下:
通过 ros::NodeHandle 对象调用
通过 ros::param 名空间调用
示例如下:
在创建的 param_hello_world 包路径下有一个 src 目录,在这里存储C++源码,我们创建 param_hello_world_set.cpp 和 param_hello_world_get.cpp ,修改 CMakeLists.txt ,添加如下内容:
  1. add_executable(${PROJECT_NAME}_set src/param_hello_world_set.cpp)
  2. add_executable(${PROJECT_NAME}_get src/param_hello_world_get.cpp)
  3. target_link_libraries(${PROJECT_NAME}_set
  4.   ${catkin_LIBRARIES}
  5. )
  6. target_link_libraries(${PROJECT_NAME}_get
  7.   ${catkin_LIBRARIES}
  8. )
复制代码
编辑 param_hello_world_set.cpp 内容如下:
  1. #include <ros/ros.h>
  2. int main(int argc, char **argv)
  3. {
  4.     setlocale(LC_ALL, "");
  5.     ros::init(argc, argv, "param_hello_world_set");
  6.     ros::NodeHandle nh;
  7.     std::cout << std::endl
  8.               << "********** ros::NodeHandle **********" << std::endl;
  9.     {
  10.         std::string name = "vbot";
  11.         std::string geometry = "rectangle";
  12.         double wheel_radius = 0.1;
  13.         int wheel_num = 4;
  14.         bool vision = true;
  15.         std::vector<double> base_size = {0.7, 0.6, 0.3};
  16.         std::map<std::string, int> sensor_id = {{"camera", 0}, {"laser", 2}};
  17.         // 设置参数
  18.         std::cout << "-- 设置参数 --" << std::endl;
  19.         nh.setParam("name", "vbot");               // 字符串, char*
  20.         nh.setParam("geometry", geometry);         // 字符串, string
  21.         nh.setParam("wheel_radius", wheel_radius); // double
  22.         nh.setParam("wheel_num", wheel_num);       // int
  23.         nh.setParam("vision", vision);             // bool
  24.         nh.setParam("base_size", base_size);       // vector
  25.         nh.setParam("sensor_id", sensor_id);       // map
  26.         // 验证是否设置成功
  27.         system("rosparam get name");
  28.         system("rosparam get geometry");
  29.         system("rosparam get wheel_radius");
  30.         system("rosparam get wheel_num");
  31.         system("rosparam get vision");
  32.         system("rosparam get base_size");
  33.         system("rosparam get sensor_id");
  34.     }
  35.     std::cout << std::endl
  36.               << "********** ros::param **********" << std::endl;
  37.     {
  38.         std::string name = "vbot";
  39.         std::string geometry = "rectangle";
  40.         double wheel_radius = 0.1;
  41.         int wheel_num = 4;
  42.         bool vision = true;
  43.         std::vector<double> base_size = {0.7, 0.6, 0.3};
  44.         std::map<std::string, int> sensor_id = {{"camera", 0}, {"laser", 2}};
  45.         // 设置参数
  46.         std::cout << "-- 设置参数 --" << std::endl;
  47.         ros::param::set("name_p", "vbot");               // 字符串, char*
  48.         ros::param::set("geometry_p", geometry);         // 字符串, string
  49.         ros::param::set("wheel_radius_p", wheel_radius); // double
  50.         ros::param::set("wheel_num_p", wheel_num);       // int
  51.         ros::param::set("vision_p", vision);             // bool
  52.         ros::param::set("base_size_p", base_size);       // vector
  53.         ros::param::set("sensor_id_p", sensor_id);       // map
  54.         // 验证是否设置成功
  55.         system("rosparam get name_p");
  56.         system("rosparam get geometry_p");
  57.         system("rosparam get wheel_radius_p");
  58.         system("rosparam get wheel_num_p");
  59.         system("rosparam get vision_p");
  60.         system("rosparam get base_size_p");
  61.         system("rosparam get sensor_id_p");
  62.     }
  63.     return 0;
  64. }
复制代码
编译运行,结果如下:
编辑 param_hello_world_get.cpp 内容如下:
  1. #include <ros/ros.h>
  2. int main(int argc, char **argv)
  3. {
  4.     setlocale(LC_ALL, "");
  5.     ros::init(argc, argv, "param_hello_world_get");
  6.     ros::NodeHandle nh;
  7.     std::cout << std::endl
  8.               << "********** ros::NodeHandle **********" << std::endl;
  9.     {
  10.         // 修改参数
  11.         std::cout << std::endl
  12.                   << "-- 修改参数 --" << std::endl;
  13.         nh.setParam("name", "mybot");        // 字符串, char*
  14.         nh.setParam("geometry", "circular"); // 字符串, char*
  15.         nh.setParam("wheel_radius", 0.15);   // double
  16.         nh.setParam("wheel_num", 2);         // int
  17.         nh.setParam("vision", false);        // bool
  18.         std::vector<double> base_size = {0.2, 0.04};
  19.         nh.setParam("base_size", base_size); // vector
  20.         std::map<std::string, int> sensor_id = {{"camera", 0}, {"laser", 2}};
  21.         sensor_id.insert({"ultrasonic", 5});
  22.         ros::param::set("sensor_id", sensor_id); // map
  23.         // 获取参数
  24.         std::cout << std::endl
  25.                   << "-- 获取参数 --" << std::endl;
  26.         std::string name;
  27.         std::string geometry;
  28.         double wheel_radius;
  29.         int wheel_num;
  30.         bool vision;
  31.         nh.getParam("name", name);
  32.         nh.getParam("geometry", geometry);
  33.         nh.getParam("wheel_radius", wheel_radius);
  34.         nh.getParam("wheel_num", wheel_num);
  35.         nh.getParam("vision", vision);
  36.         nh.getParam("base_size", base_size);
  37.         nh.getParam("sensor_id", sensor_id);
  38.         ROS_INFO("ros::NodeHandle getParam, name: %s, geometry: %s, wheel_radius: %lf, wheel: %d, vision: %s, base_size: (%lf, %lf)",
  39.                  name.c_str(), geometry.c_str(), wheel_radius, wheel_num, vision ? "true" : "false",
  40.                  base_size[0], base_size[1]);
  41.         for (auto sensor : sensor_id)
  42.         {
  43.             ROS_INFO("ros::NodeHandle getParam, %s_id: %d", sensor.first.c_str(), sensor.second);
  44.         }
  45.         // 删除参数
  46.         std::cout << std::endl
  47.                   << "-- 删除参数 --" << std::endl;
  48.         nh.deleteParam("vision");
  49.         system("rosparam get vision");
  50.         // 其他操作函数
  51.         std::cout << std::endl
  52.                   << "-- 其他操作函数 --" << std::endl;
  53.         double wheel_radius1;
  54.         wheel_radius1 = nh.param("wheel_radius", wheel_radius1);
  55.         ROS_INFO("param, wheel_radius: %lf", wheel_radius1);
  56.         nh.getParamCached("wheel_radius", wheel_radius1);
  57.         std::vector<std::string> keys_v;
  58.         nh.getParamNames(keys_v);
  59.         for (auto key : keys_v)
  60.         {
  61.             ROS_INFO("getParamNames, key: %s", key.c_str());
  62.         }
  63.         if (nh.hasParam("vision"))
  64.         {
  65.             ROS_INFO("hasParam, 存在该参数");
  66.         }
  67.         else
  68.         {
  69.             ROS_INFO("hasParam, 不存在该参数");
  70.         }
  71.         std::string result;
  72.         nh.searchParam("name", result);
  73.         ROS_INFO("searchParam, result: %s", result.c_str());
  74.     }
  75.     std::cout << std::endl
  76.               << "********** ros::param **********" << std::endl;
  77.     {
  78.         // 修改参数
  79.         std::cout << std::endl
  80.                   << "-- 修改参数 --" << std::endl;
  81.         ros::param::set("name_p", "mybot");        // 字符串, char*
  82.         ros::param::set("geometry_p", "circular"); // 字符串, char*
  83.         ros::param::set("wheel_radius_p", 0.15);   // double
  84.         ros::param::set("wheel_num_p", 2);         // int
  85.         ros::param::set("vision_p", false);        // bool
  86.         std::vector<double> base_size = {0.2, 0.04};
  87.         ros::param::set("base_size_p", base_size); // vector
  88.         std::map<std::string, int> sensor_id = {{"camera", 0}, {"laser", 2}};
  89.         sensor_id.insert({"ultrasonic", 5});
  90.         ros::param::set("sensor_id_p", sensor_id); // map
  91.         // 获取参数
  92.         std::cout << std::endl
  93.                   << "-- 获取参数 --" << std::endl;
  94.         std::string name;
  95.         std::string geometry;
  96.         double wheel_radius;
  97.         int wheel_num;
  98.         bool vision;
  99.         ros::param::get("name_p", name);
  100.         ros::param::get("geometry_p", geometry);
  101.         ros::param::get("wheel_radius_p", wheel_radius);
  102.         ros::param::get("wheel_num_p", wheel_num);
  103.         ros::param::get("vision_p", vision);
  104.         ros::param::get("base_size_p", base_size);
  105.         ros::param::get("sensor_id_p", sensor_id);
  106.         ROS_INFO("ros::param get, name: %s, geometry: %s, wheel_radius: %lf, wheel: %d, vision: %s, base_size: (%lf, %lf)",
  107.                  name.c_str(), geometry.c_str(), wheel_radius, wheel_num, vision ? "true" : "false",
  108.                  base_size[0], base_size[1]);
  109.         for (auto sensor : sensor_id)
  110.         {
  111.             ROS_INFO("ros::param getParam, %s_id: %d", sensor.first.c_str(), sensor.second);
  112.         }
  113.         // 删除参数
  114.         std::cout << std::endl
  115.                   << "-- 删除参数 --" << std::endl;
  116.         ros::param::del("vision_p");
  117.         system("rosparam get vision_p");
  118.         // 其他操作函数
  119.         std::cout << std::endl
  120.                   << "-- 其他操作函数 --" << std::endl;
  121.         double wheel_radius1;
  122.         wheel_radius1 = ros::param::param("wheel_radius", wheel_radius1);
  123.         ROS_INFO("param, wheel_radius: %lf", wheel_radius1);
  124.         ros::param::getCached("wheel_radius", wheel_radius1);
  125.         std::vector<std::string> keys_v;
  126.         ros::param::getParamNames(keys_v);
  127.         for (auto key : keys_v)
  128.         {
  129.             ROS_INFO("getParamNames, key: %s", key.c_str());
  130.         }
  131.         if (ros::param::has("vision"))
  132.         {
  133.             ROS_INFO("has, 存在该参数");
  134.         }
  135.         else
  136.         {
  137.             ROS_INFO("has, 不存在该参数");
  138.         }
  139.         std::string result;
  140.         ros::param::search("name", result);
  141.         ROS_INFO("search, result: %s", result.c_str());
  142.     }
  143.     return 0;
  144. }
复制代码
编译运行,结果如下:

2.3 其他利用参数的函数

除了上文提到的setParam()、getParam()、deleteParam() 函数,还有一些其他的参数利用函数,如下:
这里只以通过 ros::NodeHandle 对象调用为例,通过 ros::param 名空间调用类似,只多了一个 unsubscribeCachedParam函数,后面分析
1.param
获取 param_name 的值,如果 param_name 不存在,则返回 default_val
原型: T param(const std::string& param_name, const T& default_val) const
  1. double wheel_radius2;
  2. wheel_radius2 = nh.param("wheel_radius", wheel_radius2);
  3. ROS_INFO("param, wheel_radius: %lf", wheel_radius2);
复制代码
2.getParamCached()
与getParam()使用方法一样。
初次调用会判定该参数是否获取过,如果获取过则从缓存读取,并向 Master 订阅该参数的变革,不再像getParam()一样通过 RPC 向 Master获取,以提高效率。
示例参考 getParam()。
3.getParamNames()
获取全部设置到 Master 的参数的键,并通过 vector 返回。
原型:bool getParamNames(std::vectorstd::string& keys) const;
  1. std::vector<std::string> keys_v;
  2. nh.getParamNames(keys_v);
  3. for (auto key : keys_v)
  4. {
  5.     ROS_INFO("getParamNames, key: %s", key.c_str());
  6. }
复制代码
4.hasParam()
判定是否存在该参数
原型:bool hasParam(const std::string& key) const;
  1. if (nh.hasParam("vision"))
  2. {
  3.     ROS_INFO("存在该参数");
  4. }
  5. else
  6. {
  7.     ROS_INFO("不存在该参数");
  8. }
复制代码
5.searchParam()
搜索给定参数名,如果存在,返回键名,不存在返回空字符串。
原型:bool searchParam(const std::string& key, std::string& result) const;
  1. std::string result;
  2. nh.searchParam("name", result);
  3. ROS_INFO("searchParam, result: %s", result.c_str());
复制代码
2.4 利用参数(Python版)

与 C++ 不同,ROS 只为 Python 提供了一套利用参数的 API。
在创建的 param_hello_world 包路径下 src 目录的同级,创建一个 scripts 目录,在这里存储脚本(如python脚本),修改 CMakeLists.txt ,添加如下内容:
  1. catkin_install_python(PROGRAMS
  2.   scripts/param_hello_world_set.py
  3.   scripts/param_hello_world_get.py
  4.   DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
  5. )
复制代码
在 scripts 中创建 param_hello_world_set.py 编辑内容如下:
  1. import rospy
  2. import os
  3. if __name__ == "__main__":
  4.     rospy.init_node("param_hello_world_set")
  5.     # 设置参数
  6.     rospy.set_param("name", "vbot")                         # 字符串, string
  7.     rospy.set_param("geometry", "rectangle")                # 字符串, string
  8.     rospy.set_param("wheel_radius", 0.1)                    # double
  9.     rospy.set_param("wheel_num", 4)                         # int
  10.     rospy.set_param("vision", True)                         # bool
  11.     rospy.set_param("base_size", [0.7, 0.6, 0.3])           # list
  12.     rospy.set_param("sensor_id", {"camera": 0, "laser": 2}) # dictionary
  13.     # 验证是否设置成功
  14.     os.system("rosparam get name")
  15.     os.system("rosparam get geometry")
  16.     os.system("rosparam get wheel_radius")
  17.     os.system("rosparam get wheel_num")
  18.     os.system("rosparam get vision")
  19.     os.system("rosparam get base_size")
  20.     os.system("rosparam get sensor_id")
复制代码
在 scripts 中创建 param_hello_world_get.py 编辑内容如下:
  1. import rospy
  2. if __name__ == "__main__":
  3.     rospy.init_node("param_hello_world_get")
  4.     # 修改参数
  5.     rospy.set_param("name", "mybot")             # 字符串, string
  6.     rospy.set_param("geometry", "circular")      # 字符串, string
  7.     rospy.set_param("wheel_radius", 0.15)        # double
  8.     rospy.set_param("wheel_num", 2)              # int
  9.     rospy.set_param("vision", False)             # bool
  10.     rospy.set_param("base_size", [0.2, 0.04])    # list
  11.     rospy.set_param("sensor_id", {"camera": 0, "laser": 2, "ultrasonic": 5}) # dictionary
  12.     # 获取参数
  13.     name = rospy.get_param("name")                    # 字符串, string
  14.     geometry = rospy.get_param("geometry")            # 字符串, string
  15.     wheel_radius = rospy.get_param("wheel_radius")    # double
  16.     wheel_num = rospy.get_param("wheel_num")          # int
  17.     vision = rospy.get_param("vision")                # bool
  18.     base_size = rospy.get_param("base_size")          # list
  19.     sensor_id = rospy.get_param("sensor_id")          # dictionary
  20.     rospy.loginfo("get_param, name: {}, geometry: {}, wheel_radius: {}, wheel: {}, vision: {}, base_size: ({}, {})"
  21.                   .format(name, geometry, wheel_radius, wheel_num, vision, base_size[0], base_size[1]))
  22.     for key, value in sensor_id.items():
  23.         rospy.loginfo("get_param, sensor: {}, id: {}".format(key, value))
  24.     # 删除参数
  25.     rospy.delete_param("vision")
  26.     # 其他操作
  27.     wheel_radius1 = rospy.get_param_cached("wheel_radius")
  28.     keys = rospy.get_param_names()
  29.     for key in keys:
  30.         rospy.loginfo("get_param_names, key: {}".format(key))
  31.     if rospy.has_param("vision"):
  32.         rospy.loginfo("has_param, 存在该参数")
  33.     else:
  34.         rospy.loginfo("has_param, 不存在该参数")
  35.     result = rospy.search_param("name")
  36.     rospy.loginfo("search_param, result: {}".format(result))
复制代码
编译执行结果如下:


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农民

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表