ROS 8: 参数的使用与编程
在ROS Master中有一个参数服务器,它是一个全局字典,用来保存各个节点的配置参数的,这些参数是各个节点都可以全局访问的。
可以简单理解为,这是一个用来存放全局变量的空间
有关参数的使用,有如下命令行工具
一、参数的命令行工具
我们在命令行会使用rosparam
,用于从ROS参数服务器获取、设置和删除参数。
rosparam is a command-line tool for getting, setting, and deleting parameters from the ROS Parameter Server.
Commands:
rosparam set set parameter
rosparam get get parameter
rosparam load load parameters from file
rosparam dump dump parameters to file
rosparam delete delete parameter
rosparam list list parameter names
如果参数比较多的时候,我们会用*.yaml
文件来存参数。
以下是rosparam在命令行的工具使用介绍
-
列出参数
rosparam list
- 如果此时你运行turtlesim,你可以使用
rosparam list
看到参数名:
/rosversion /run_id /turtlesim/background_b /turtlesim/background_g /turtlesim/background_r
-
如果你设置了命名空间,还需要在后面加上命名空间的名字,如:
rosparam list /namespace
这里的命名空间可以类比为c++中的
using namespace xxx
中的xxx
具体内容放在第三Part介绍
- 如果此时你运行turtlesim,你可以使用
-
显示某个参数值
rosparam get <param_key>
-
设置某个参数值
rosparam set <param_key> <param_value>
比如要修改turtlesim的background对应的RGB值,输入:
rosparam set /turtlesim/background_g 255
然后turtlesim需要收到一次
/clear
请求,才会重新读取背景值rosservice call /clear "{}"
如果此时你正在运行上述代码,你就可以看到,海龟仿真器的背景颜色已经修改了。
-v:显示详细输出。
-t <text_file>, --textfile <text_file> :将参数设置为文本文件的内容。
-b <binary_file>, --binfile <binary_file> :将参数设置为二进制文件的内容。参数服务器将值存储为XML-RPC二进制类型(基64编码)。
-
保存参数到文件
rosparam dump <file_name>
-
从文件读取参数
rosparam load <file_name>
此时,在工作空间使用
rosparam dump param.yaml
指令,ros就会把当前的参数配置保存到该yaml文件中。使用
rosparam load param.yaml
就可以加载以前保存好的参数yaml文件会存储类似于以下的内容,
rosdistro: 'melodic ' roslaunch: uris: xxx: http://xxx:44429/ rosversion: '1.14.10 ' run_id: 80cf1b56-0e4b-11ed-9d12-000c29d50405 turtlesim: background_b: 255 background_g: 255 background_r: 255
-
删除参数
rosparam delete <param_key>
删除当前系统载入的参数。
二、参数在编程上的使用
c++代码实现
1、设置参数
ros::NodeHandle::setParam()
ros::param::set()
在c++中,在代码中获取参数时,除了上述代码使用的ros::param::get
方法之外,还可以使用句柄来获取参数:ros::NodeHandle::getParam()
。需要的参数是一样的:
//ros::NodeHandle::setParam()
ros::NodeHandle nh;
nh.setParam("/global_param", 5);
nh.setParam("relative_param", "my_string");
nh.setParam("bool_param", false);
都是需要输入参数名和存放的变量名
//ros::param::set()
ros::param::set("/global_param", 5);
ros::param::set("relative_param", "my_string");
ros::param::set("bool_param", false);
需要注意的是,如果使用NodeHandle,还需要注意他对应的命名空间。
对于命名空间来说,节点名前面直接加个/
号,代表着这个节点是放在全局的,比如/turltesim
。如果需要使用对应命名空间里的节点,需要写上空间名,如:/my/turtlesim
2、检查参数是否存在
ros::NodeHandle::hasParam()
ros::NodeHandle nh;
if (nh.hasParam("my_param")){...}
ros::param::has()
if (ros::param::has("my_param")){...}
3、删除参数
ros::NodeHandle::deleteParam()
ros::NodeHandle nh;
nh.deleteParam("my_param");
ros::param::del()
ros::param::del("my_param");
4、访问私有参数
根据使用的是“句柄”接口还是“裸”接口,访问私有参数的方式是不一样的。在句柄接口中,您必须创建一个新的ros::NodeHandle
以私有命名空间作为其命名空间:
ros::NodeHandle nh("~");
std::string param;
nh.getParam("private_name", param);
在裸界面中,可以使用描述私有参数的相同符号来访问它们,例如:
std::string param;
ros::param::get("~private_name", param);
5、搜索参数键
ros::NodeHandle::searchParam()
std::string key;
if (nh.searchParam("bar", key))
{
std::string val;
nh.getParam(key, val);
}
ros::param::search()
std::string key;
if (ros::param::search("bar", key))
{
std::string val;
ros::param::get(key, val);
}
6、demo
模仿本案例开头的修改turtlesim背景案例,我们所需要的头文件有:
#include <ros/ros.h>
#include <string>
#include <std_srvs/Empty.h>
主函数:
int main(int argc,char **argv){
// 初始化ros
ros::init(argc,argv,"param_code");
ros::NodeHandle param_node;
int red,green,blue;
//参数获取,类比命令行rosparam的get
ros::param::get("/turtlesim/background_r",red);
ros::param::get("/turtlesim/background_g",green);
ros::param::get("/turtlesim/background_b",blue);
ROS_INFO("Get Backgroud Color[%d, %d, %d]", red, green, blue);
//参数设置,类比命令行rosparam的set
ros::param::set("/turtlesim/background_r",255);
ros::param::set("/turtlesim/background_g",255);
ros::param::set("/turtlesim/background_b",255);
ROS_INFO("Set Backgroud Color[255, 255, 255]");
//参数获取,类比命令行rosparam的get
ros::param::get("/turtlesim/background_r",red);
ros::param::get("/turtlesim/background_g",green);
ros::param::get("/turtlesim/background_b",blue);
ROS_INFO("Get Backgroud Color[%d, %d, %d]", red, green, blue);
// 参考我们上面讨论的参数使用方法,我们知道turtlesim需要接受/clear请求才会更新turtlesim的参数。
//调用/clear服务,用来刷新背景颜色
ros::service::waitForService("/clear");
ros::ServiceClient clear_background = param_node.serviceClient<std_srvs::Empty>("/clear");
std_srvs::Empty srv;
clear_background.call(srv);
sleep(1);
return 0;
}
程序编译:
打开功能包的CMakeLists,使用如下语句即可使用catkin_make
add_executable(learn_param src/learn_param.cpp)
target_link_libraries(learn_param ${catkin_LIBRARIES})
python代码实现
1、获取参数
rospy.get_param(参数名称)
如果使用get_param()
来获取名称空间,则会返回一个字典,其中的键等于该名称空间中的参数值。
global_name = rospy.get_param("/global_name")
relative_name = rospy.get_param("relative_name")
private_param = rospy.get_param('~private_name')
default_param = rospy.get_param('default_param', 'default_value')
# fetch a group (dictionary) of parameters
gains = rospy.get_param('gains')
p, i, d = gains['p'], gains['i'], gains['d']
2、设置参数
rospy.set_param(参数名称,参数值)
# 使用rospy和原始python对象
rospy.set_param('a_string', 'baz')
rospy.set_param('~private_int', 2)
rospy.set_param('list_of_floats', [1., 2., 3., 4.])
rospy.set_param('bool_True', True)
rospy.set_param('gains', {'p': 1, 'i': 2, 'd': 3})
# 使用rosparam和yaml字符串
rosparam.set_param('a_string', 'baz')
rosparam.set_param('~private_int', '2')
rosparam.set_param('list_of_floats', "[1., 2., 3., 4.]")
rosparam.set_param('bool_True', "true")
rosparam.set_param('gains', "{'p': 1, 'i': 2, 'd': 3}")
rospy.get_param('gains/p') #should return 1
3、参数存在
rospy.has_param(param_name)
如果存在该参数,返回True,否则False。
if rospy.has_param('to_delete'):
rospy.delete_param('to_delete')
4、删除参数
rospy.delete_param(参数名称)
其实就是从参数服务器删除参数
try:
rospy.delete_param('to_delete')
except KeyError:
print("value not set")
5、搜索参数键
rospy.search_param(参数名称)
查找最接近的参数名,从私有名称空间开始,向上一直搜索到全局名称空间。
param_name = rospy.search_param('global_example')
v = rospy.get_param(param_name)
如果上面的代码出现在/foo/bar节点中,
rospy.search_param
会试着按照以下顺序找到参数
/foo/bar/global _example
/foo/global _example
/global _example
6、获取参数名
rospy.get_param_names()
7、demo
以下demo和c++的功能完全一样。
# -*- coding: utf-8 -*-
import rospy
from std_srvs.srv import Empty
import sys
def param_set():
rospy.init_node('param_py')
# 读取背景颜色参数
red = rospy.get_param('/background_r')
green = rospy.get_param('/background_g')
blue = rospy.get_param('/background_b')
rospy.loginfo("Get Backgroud Color[%d, %d, %d]", red, green, blue)
# 设置背景颜色参数
ros.set_param('/background_r',100)
ros.set_param('/background_g',100)
ros.set_param('/background_b',100)
rospy.loginfo("Set Backgroud Color[100, 100, 100]")
# 读取背景颜色参数
red = rospy.get_param('/background_r')
green = rospy.get_param('/background_g')
blue = rospy.get_param('/background_b')
rospy.loginfo("Get Backgroud Color[%d, %d, %d]", red, green, blue)
rospy.wait_for_service('/clear')
try:
clear_background = rospy.ServiceProxy('/clear', Empty)
# 请求服务调用,输入请求数据
response = clear_background()
return response
except rospy.ServiceException, e:
print "Service call failed: %s"%e
if __name__ == '__main__':
param_set()