文章目录
1. 程序中的getparam与param
1.1 getparam(无默认值)
bool getParam (const std::string& key, parameter_type& output_value);
//返回值判断是否获取参数成功
参数说明如下:
- key是参数名(相当于接口,和话题类似),命名方法参考:ros命名(这个参考后续学习)
- output_value用来保持参数的值,parameter_type类型包含bool, int, double, string, 或 特定的 XmlRpcValue 类型,XmlRpcValue类型包含所有类型,甚至是lists/maps
举例:
std::string s;
n.getParam("my_param", s);
1.2 param(有默认值)
int i;
n.param("my_num", i, 42);//默认参数为42
1.3 删除参数
n.deleteParam("my_param");
1.4 程序中设置参数
n.setParam("my_param", "hello there");
1.5 检查参数
这个步骤不是必需的
if (!n.hasParam("my_param"))
{
ROS_INFO("No param named 'my_param'");
}
1.6 搜索参数
例如:如果参数服务器存在/a/b的参数,你的NodeHandle在/a/c工作空间,searchParam()搜索b会得到/a/b. 如果/a/c/b参数增加,搜索就会得到/a/c/b参数。举例如下:
std::string param_name;
if (n.searchParam("b", param_name)) {
// Found parameter, can now query it using param_name
int i = 0;
n.getParam(param_name, i);
}
else {
ROS_INFO("No param 'b' found in an upward search");
}
2. launch中参数设置方式
launch文件有三种设置参数方式,它们分别是:param,rosparam,arg
(1)Param
param是设置单个参数
,它在launch文件设置形式如下:
<launch>
<node name="ydlidar_node" pkg="ydlidar" type="ydlidar_node" output="screen">
<param name="port" type="string" value="/dev/ydlidar"/>
<param name="baudrate" type="int" value="115200"/>
<param name="frame_id" type="string" value="laser_frame"/>
<param name="angle_fixed" type="bool" value="true"/>
<param name="low_exposure" type="bool" value="false"/>
<param name="heartbeat" type="bool" value="false"/>
<param name="resolution_fixed" type="bool" value="true"/>
<param name="angle_min" type="double" value="-180" />
<param name="angle_max" type="double" value="180" />
<param name="range_min" type="double" value="0.08" />
<param name="range_max" type="double" value="16.0" />
<param name="ignore_array" type="string" value="" />
<param name="samp_rate" type="int" value="9"/>
<param name="frequency" type="double" value="7"/>
</node>
<node pkg="tf" type="static_transform_publisher" name="base_link_to_laser4"
args="0.2245 0.0 0.2 0.0 0.0 0.0 /base_footprint /laser_frame 40" />
</launch>
(2)rosparam
rosparam是用于加载参数文件
的,而参数文件可以包含许多参数,它在launch文件中设置参数形式如下:
<launch>
<node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen" clear_params="true">
<rosparam file="$(find dashgo_nav)/config/dashgo/costmap_common_params.yaml" command="load" ns="global_costmap" />
<rosparam file="$(find dashgo_nav)/config/dashgo/costmap_common_params.yaml" command="load" ns="local_costmap" />
<rosparam file="$(find dashgo_nav)/config/dashgo/local_costmap_params.yaml" command="load" />
<rosparam file="$(find dashgo_nav)/config/dashgo/global_costmap_params.yaml" command="load" />
<rosparam file="$(find dashgo_nav)/config/dashgo/base_local_planner_params.yaml" command="load" />
</node>
</launch>
(3)arg
由launch内部使用,类似于launch里面的语法
,它在launch文件中设置参数形式如下:
< arg name="gui" default="false" />
< param name="use_gui" value="$(arg gui)" />
#一起使用
3. 动态参数
仅仅使用ros的参数有时候不能满足我们的工作需求,比如在调试机器人的参数时,我们希望能够动态改变参数
,从而观察机器人的相应的反应,所以我们接下来介绍ros中的动态参数。
ros中的动态参数类似于话题的发布和订阅形式,一旦配置好动态参数文件,我们只需要在程序中订阅相应的参数即可。
(1)创建配置参数
- 创建ros包
catkin_create_pkg dynamic_tutorials rospy roscpp dynamic_reconfigure
如果自己已经有功能包了,只需要在CmakeList.txt和package.xml中自行添加dynamic_reconfigure。
- 创建cfg配置文件
在功能包的src同一级目录下创建文件夹cfg,并在cfg中添加一个文件命名为my_cfg.cfg。它的内容为:
#!/usr/bin/env python
PACKAGE = "dynamic_tutorials"
from dynamic_reconfigure.parameter_generator_catkin import *
gen = ParameterGenerator()
gen.add("int_param", int_t, 0, "An Integer parameter", 50, 0, 100)
gen.add("double_param", double_t, 0, "A double parameter", .5, 0, 1)
gen.add("str_param", str_t, 0, "A string parameter", "Hello World")
gen.add("bool_param", bool_t, 0, "A Boolean parameter", True)
size_enum = gen.enum([ gen.const("Small", int_t, 0, "A small constant"),
gen.const("Medium", int_t, 1, "A medium constant"),
gen.const("Large", int_t, 2, "A large constant"),
gen.const("ExtraLarge", int_t, 3, "An extra large constant")], "An enum to set size")
gen.add("size", int_t, 0, "A size parameter which is edited via an enum", 1, 0, 3, edit_method=size_enum)
exit(gen.generate(PACKAGE, "dynamic_tutorials", "my_cfg"))
可以看出它是由python形式实现的,下面简要介绍配置的内容。
创建参数生成器:
gen = ParameterGenerator()
动态配置参数:
gen.add("int_param", int_t, 0, "An Integer parameter", 50, 0, 100)
gen.add("double_param", double_t, 0, "A double parameter", .5, 0, 1)
gen.add("str_param", str_t, 0, "A string parameter", "Hello World")
gen.add("bool_param",bool_t,0, "A Boolean parameter", True)
动态参数的实现形式:add(name, type, level,description, default, min,max)。
- name:参数名,使用字符串描述;
- type:定义参数的类型,可以是int_t, double_t, str_t, 或者bool_t;
- level:需要传入参数动态配置回调函数中的掩码,在回调函数中会修改所有参数的掩码,表示参数已经进行修改;
- description:描述参数作用的字符串;
- default:设置参数的默认值;
- min:可选,设置参数的最小值,对于字符串和布尔类型值不生效;
- max:可选,设置参数的最大值,对于字符串和布尔类型值不生效;
枚举类型的动态参数实现形式如下:
size_enum = gen.enum([gen.const("Small",int_t,0,"A small constant"),
gen.const("Medium",int_t,1,"A medium constant"),
gen.const("Large",int_t, 2, "A large constant"),
gen.const("ExtraLarge",int_t,3,"An extra large constant")],"An enum to set size")
gen.add("size", int_t, 0, "A size parameter which is edited via an enum", 1, 0, 3, edit_method=size_enum)
生成C++和python相关的文件并且退出程序:
exit(gen.generate(PACKAGE, "dynamic_tutorials", "my_cfg"))
- dynamic_tutorials:包的名字
- my_cfg:创建的配置文件名(也可以不是配置文件名,但是它必须和程序中保持一致),也就是程序中需要包含的头文件
(2)创建服务端节点
服务端节点,也就是订阅节点,代码实现如下,详情看注释:
#include <ros/ros.h>
#include <dynamic_reconfigure/server.h>//实现动态参数的头文件
#include <dynamic_tutorials/TutorialsConfig.h>//cfg生成的头文件
/****回调函数****/
void callback(dynamic_tutorials::TutorialsConfig &config, uint32_t level) {
ROS_INFO("Reconfigure Request: %d %f %s %s %d",
config.int_param, config.double_param,
config.str_param.c_str(),
config.bool_param?"True":"False",
config.size);
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "node_dy_param");
dynamic_reconfigure::Server<dynamic_tutorials::TutorialsConfig> server;//创建了一个参数动态配置的服务端
dynamic_reconfigure::Server<dynamic_tutorials::TutorialsConfig>::CallbackType f;
f = boost::bind(&callback, _1, _2);//绑定回调
server.setCallback(f);
ROS_INFO("Spinning node");
ros::spin();
return 0;
}
增加CmakeList.txt内容:
add_executable(node_dy_param src/main.cpp)
target_link_libraries(node_dy_param ${catkin_LIBRARIES})
add_dependencies(node_dy_param ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(node_dy_param ${PROJECT_NAME}_gencfg)
(3)运行
启动订阅端节点:
roscore
rosrun dynamic_tutorials node_dy_param
运行发布端节点:
rosrun rqt_reconfigure rqt_reconfigure
4. 终端参数命令
ROS中关于参数服务器的工具是rosparam。其支持的参数如下所示:
命令 | 说明 |
---|---|
rosparam list | 列出当前的参数有哪些 |
rosparam get [parameter] | 获取参数值 |
rosparam set [parameter] [value] | 设置参数值 |
rosparam delete [parameter] | 删除参数 |
rosparam dump [file] | 将参数服务器保存到一个文件 |
rosparam load [file] | 加载参数文件到参数服务器 |
5. param几种方法的程序举例
设置参数后,记得删除param
,否则即使程序不运行,也会驻留在空间内。
getParam和param操作都会从空间中去找参数,所以为了避免出现驻留的情况,可以在程序中使用set操作
,这样每次程序重启都会set一个默认值,而不是从空间中去找参数了。
#include "ros/ros.h"
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
ros::init(argc, argv, "param_demo");
ros::NodeHandle nh;
int param1, param2, param3, param4, param5;
//==========================Get Param的三种方法===================
//方法一: ros::param::get()获取参数“param1”的value,写入到param1变量上
bool test1 = ros::param::get("param1", param1);
//方法二:ros::NodeHandle::getParam()获取参数,与方法一作用相同
bool test2 = nh.getParam("param2", param2);
//方法三:ros::NodeHandle::param()类似于方法一和方法二
//但如果get不到指定的param,它可以给param指定一个默认值(如3)
nh.param("param3", param3, 3);
//==========================set Param的2种方法===================
//方法一: ros::param::set()设置参数
param4 = 4;
ros::param::set("param4", param4);
//方法二: ros::NodeHandle::setParam()设置参数
param5 = 5;
nh.setParam("param5", param5);
//==========================has Param的2种方法===================
//方法一: ros::NodeHandle::hasParam()
bool ifparam5 = nh.hasParam("param5");
//方法二: ros::param::has()
bool ifparam6 = ros::param::has("param6");
//=========================del Param的2种方法===================
//方法一:ros::NodeHandle::deleteParam()
bool ifdeleted5 = nh.deleteParam("param5");
//方法二: ros::param::del()
bool ifdeleted6 = ros::param::del("param6");
ros::Rate loop_rate(1000);
while (ros::ok())
{
ros::param::get("param4", param4);
cout<<"param4: "<<param4<<endl;
nh.param("param3", param3, 3);
cout<<"param3: "<<param3<<endl;
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}