ROS参数服务器深度解剖(二)
作者:互联网
ROS参数服务器中使用的命令
rosparam 命令行工具:
rosparam 命令参数选项有(set, get, load, dump, delete, list),其中load, dump, delete选项同时可在luanch文件运行有效, 向set,get,load,list 选项应用前提是ros参数服务器中有参数,否则不能使用,当然参数一定要加上命名空间,下面是详解:
- set:假设节点有一个PI参数,参数默认值为3.14,那么运行节点PI的初始值是3.14,当执行rosparam set /node_name/PI 3.1415926 后(假设命名空间为“node_name”),当节点下次用到PI的值时已经被换成3.1415926了;
- get:rosparam get /node_name/PI 获取命名空间下PI的值;
- load: 加载yaml配置文件,rosparam load [file_name] [namespace];
- dump: rosparam dump xxx.yaml [namespace]文件,转存指定的命名空间参数到xxx.yaml文件中;
- delete: rosparam delete /node_name/PI 删除在参数服务器中PI参数;
- list : rosparam list 参数目前参数服务器中有哪些参数。
在终端,我们运行roscore 启动ros master,那么对应的参数服务器也就启动起来了。我们可以使用rosparam list 查看当服务器中的参数列表,默认ros参数服务器会自动添加这样的类似参数:
/rosdistro
/roslaunch/uris/host_honghu__37429
/rosversion
/run_id
我们可以通过rosparam load xxx.yaml
,如果没有报错,说明yaml语法没错,此时可以通过rosparam list
查看我们刚刚加载的参数列表,并且可以通过rosparam get xxx
查看 xxx 参数的数值。至于其他参数delete,dump就很简单了。
ROS 参数服务器在launch文件中
下面重点讲下load,dump,delete 在launch文件中使用,因为load, dump都是针对yaml文件的,所有后续讲yaml文件时还会回顾这节内容。前面所讲的阐述传递都是单个元素的参数变量,如果需要传递数据结构体型的变量参数,就是要使用yaml文件,当然launch文件也可以通过rosparam传递list结构数据。如下:
在launch文件中<node>的元素内加上:
<rosparam param="list">[1,23,4,5]</rosparam> <!--一维数组的使用 -->
然后在C++文件中获取:
std::vector<int> v;
nh.param(“list”,v,v); //说着使用nh.getParam() ,ros::param::get() 或者需要使用参数的完整名称
luanch 文件中使用二维或者多维数组,邻接矩阵、list等完整代码
<launch>
<arg name ="topic_name_arg" default="aaa"/>
<!-- <param name="topic_name" type = "str" value = "$(arg topic_name_arg)"/> -->
<node pkg = "param_pkg" type = "param_node" name = "param_node" output="screen">
<param name="topic_name" type = "str" value = "/$(arg topic_name_arg)"/>
<rosparam param="list">[1,23,4,5,456,6,7,9,222]</rosparam>
<rosparam param="v">
[[1,2]
[1,23,45,67],
[11,22,33,44,55]]
</rosparam> <!-- 此处同一个维度内内存不对齐的邻接矩阵 ,可以定义常见矩阵-->
<rosparam param="alpha">0.03</rosparam>
<rosparam file= "$(find param_pkg)/config/p.yaml" command="load"/>
</node>
</launch>
C++代码
std::vector<int> vec;
nh.param("list", vec, vec); //对于一维的数组或者链表可以使用直接读的方式
for(size_t i = 0; i < vec.size(); ++i)
{
ROS_INFO("vec[%d] = %d", i, vec[i]);
}
//二维以上的数组、或者邻接矩阵之类需要借助与XmlRpc::XmlRpcVlaue 类
std::vector<std::vector<int>> v;
nh.param("v", xml_v, xml_v);
v.resize(xml_v.size());
for(int i = 0; i < xml_v.size(); ++i)
{
for(int j = 0; j < xml_v[i].size(); ++j)
{
if(XmlRpc::XmlRpcValue::TypeInt == xml_v[i][j].getType()) //此处判断必不可少
{
v[i].push_back(static_cast<int>(xml_v[i][j]));
std::cout << v[i][j] << ",";
}
}
std::cout << std::endl;
}
ROS参数服务器加载yaml文件
下面是一个yaml示列,简单讲下yaml语法规则
语法规则:
YAML文件
-简单说明:YAML(YAML Ain’t a Markup Language)一种非标记语言,通用的数据串行化格式,方便人类的读写。
**基本语法规则: **
- 大小写敏感
- 使用缩进表示层级关系
- 缩进时不允许使用Tab键,只允许使用空格,当然如果编辑器设置了空格键替代Tab键也是可以的。
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
- 使用#表示注释
- 字符串可以不用引号标注, 出于编程习惯一般用双引号或者单引号。
YAML支持三种数据结构: - 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes)/ 词典(dictionary)。
- 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)。
-纯量(scalars):数据最小的单位, 单个的、不可再分的值。
先看一个简单的例子,依据例子来讲解。
%YAML 1.2 #yaml语法格式 定义版本
--- #yaml语法格式,必须要有
#所有冒号之后必须要空格,冒号后换行的情况例外。
object: animal # 单个键对的词典C++可以直接使用nh.param()等读取参数,不需要借助XmlRpc::XmlRpcValue
Position: {longitude: -2147483648, latitude: 2342, x: 234.9, y: 23.35} #两层的词典需要使用XmlRpc::XmlRpcValue读取参数,可以是直接使用std::map 在nh.param()中使用
factor: #与上述luanch代码中二维数组一样的使用方法
[[1,2],
[3,4,5],
[11,22,33,44,55,66,77,88,9],
[123,234,345,45,6,567,678]]
array: [1,2,3,4,5,6] #上述launch文件中一维数组一样的使用方法
Wheel: #词典可以一行定义,也可以分行定义,缩进必要使用空格,并对其
Car:
Radius: 0.6
Bicycle:
Radius: 0.3
Airplane:
Radius: 0.5
Class: #横杠‘-’表示数组定义,这里使用数组和词典组合定义
- Car:
Radius: 0.1
- Bicycle:
Radius: 0.3
- Airplane:
Radius: 0.5
以上yaml文件加载之后,使用rosparam list 查看ros参数服务器就可以看到以下参数列表:
/Class
/Position/latitude
/Position/longitude
/Position/x
/Position/y
/Wheel/Airplane/Radius
/Wheel/Bicycle/Radius
/Wheel/Car/Radius
/array
/factor
/object
/rosdistro
/roslaunch/uris/host_honghu__37429
/rosversion
/run_id
下面贴出C++代码
std::string obj;
std::map<std::string, double> pos; //可以直接使用map数据结构读取yaml中的二维词典
std::vector<std::vector<int>> factor;
std::vector<int> array;
XmlRpc::XmlRpcValue factor_xml;
XmlRpc::XmlRpcValue wheel_xml;
XmlRpc::XmlRpcValue class_xml;
double wheel_car_r = 0;
double wheel_bicycle_r = 0;
float wheel_airplane_r = 0;
double class_car_r = 0;
float class_bicycle_r = 0;
float class_airplane_r = 0;
nh.param("object", obj, obj);
ROS_INFO("object: %s", obj.c_str());
nh.param("array", array, array);
for(int i = 0; i < array.size(); ++i)
{
std::cout << array[i] << ",";
}
std::cout << std::endl;
nh.param("Postion", pos, pos);
for(auto it = pos.begin(); it != pos.end(); ++it)
{
std::cout << it->first << "," << it->second << std::endl;
}
nh.param("factor", factor_xml, factor_xml);
factor.resize(factor_xml.size());
for(int i = 0; i < factor.size(); ++i)
{
for(int j = 0; j < factor_xml[i].size(); ++j)
{
if(XmlRpc::XmlRpcValue::TypeInt == factor_xml[i][j].getType())
{
factor[i].push_back(static_cast<int>(factor_xml[i][j]));
std::cout << factor[i][j] << ",";
}
}
std::cout << std::endl;
}
nh.param("Wheel", wheel_xml, wheel_xml);
// wheel_car_r = float(atof(wheel_xml["Car"]["Radius"].toXml().c_str()));
if(XmlRpc::XmlRpcValue::TypeDouble == wheel_xml["Car"]["Radius"].getType())
{
wheel_car_r = double(wheel_xml["Car"]["Radius"]);
}
std::cout << " wheel_car_r: " << wheel_car_r << std::endl;
nh.param("Class", class_xml, class_xml);
// class_car_r = float(atof(class_xml[0]["Radius"].toXml().c_str()));
if(XmlRpc::XmlRpcValue::TypeDouble == class_xml[0]["Car"]["Radius"].getType())
{
class_car_r = double(class_xml[0]["Car"]["Radius"]);
}
std::cout << " class_car_r: " << class_car_r << std::endl;
float r = 0.f;
nh.param("/param_node/Wheel/Car/Radius", r, r);
std::cout << " radius " << r << std::endl;
ros::Rate loop_rate(10);
总结:
我们写好yaml文件后,可以先使用rosparam load xxx.yaml
命令检验yaml文件有没有存在语法错误。另外,在C++代码中使用XmlRpcVlaue 加载参数 ,词典参数需要用[name]名字访问,数组使用[]下表访问,可以看C++代码,同时需要注意由于ros 参数服务器只支持32位的数字参数,那么除去符号位,有效位只有31位因此,数值范围在
[
−
2
31
,
2
31
−
1
]
[-2^{31} , 2^{31}-1]
[−231,231−1] 即[-2147483648,2147383647],因此需要留意这个问题,可以使用yaml-cpp 库读取yaml文件绕开或者避免这个问题
有问题联系QQ(451800861)持续更新中…
标签:xml,std,rosparam,list,yaml,参数,服务器,ROS,解剖 来源: https://blog.csdn.net/HongHu_fly/article/details/117002739