ROS的参数服务器使用

1.使用意义

参数服务器的使用旨在提高ROS 节点的灵活性和可配置性,其意义从两个方面去理解:

        在机器人系统中,参数传递十分重要,机器人工作时,我们有需要对机器人的参数(如传感器参数、算法的参数)进行设置。有些参数(如机器人的轮廓、传感器的高度)在机器人启动时就设定好就行了,有些参数则需要动态改变(特别是在调试的时候)。无论是传感器的设置,还是控制参数的调整,都需要留出方便的参数调试接口。ROS提供了参数服务器来满足这一需求,我们可以将参数设置在参数服务器,在需要用到参数的时候再从参数服务器中获取。使用参数服务器配置系统的参数,是全局可见的,方便我们检索和更改系统的配置状态。

        参数服务器为ROS节点之间提供了另一种信息交互方式(常用的方式还有消息和服务)。其主要思想是使用集中参数服务器( parameter server )维护一个变量集的值,节点可以主动查询其感兴趣的参数的值。

rosparam命令可对ROS参数服务器上的参数进行操作。通过rosparam -h命令,可以看到有下面的一些方法:

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 列出参数服务器中的参数

2. 使用要点

ROS为我们提供了操作参数的roslaunch .launch接口、命令行接口、roscpp接口和rospy接口,使用要点如下:
2.1 roslaunch .launch接口

该接口用于在启动的时候将参数配置好。用launch文件配置参数的好处:1、可以不查看源程序就可以知道节点用到的参数以及给定的初始值;2、要修改参数的初始值,可以将它保存到launch文件而不必修改和重新编译源程序。
    2.1.1 使用<param>标签直接定义参数

<param name="publish_frequency" type="double" value="10.0" />

使用标签<rosparam>配置参数

    2.1.2 从YAML文件读取参数:

         一般地,我们可以将需要设置的参数保存在yaml文件中,使用rosparam load [文件路径\文件名] 命令一次性将多个参数加载到参数服务器。

举个例子,一个名称为param.yaml的参数文件,内容为:

#There are some params which will be loaded
yaml_param_string1: abcd123
yaml_param_string2: 567efg
 
yaml_param_num1: 123.123
yaml_param_num2: 1234567
 
yaml_param_set:
  param_set_string1: zzzzz
  param_set_num1: 999
  param_set_string2: a6666
  param_set_num2: 2333
 
  param_subset:
    param_set_string1: qwer
    param_set_num1: 5432
    param_set_string2: a12s3
    param_set_num2: 1111

终端中载入参数:

$ rosparam load param.yaml

然后,输入命令:

$ rosparam list

可以看到,参数已经被全部加载了:

/rosdistro
/roslaunch/uris/host_clp_virtual_machine__46453
/rosversion
/run_id
/yaml_param_num1
/yaml_param_num2
/yaml_param_set/param_set_num1
/yaml_param_set/param_set_num2
/yaml_param_set/param_set_string1
/yaml_param_set/param_set_string2
/yaml_param_set/param_subset/param_set_num1
/yaml_param_set/param_subset/param_set_num2
/yaml_param_set/param_subset/param_set_string1
/yaml_param_set/param_subset/param_set_string2
/yaml_param_string1
/yaml_param_string2

通过rosparam set [参数名] [参数值] 可以设置参数值;

通过rosparam get [参数名] 可以查看参数值;

也可以在launch文件中通过rosparam标签载入到参数服务器中:

可以参考turtlebot的navigation启动move_base节点的过程,保存在yaml文件中的参数是通过rosparam标签被加载到参数服务器中的。

<node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
    <rosparam file="$(find turtlebot_navigation)/param/costmap_common_params.yaml" command="load" ns="global_costmap" />
    <rosparam file="$(find turtlebot_navigation)/param/costmap_common_params.yaml" command="load" ns="local_costmap" />   
    <rosparam file="$(find turtlebot_navigation)/param/local_costmap_params.yaml" command="load" />   
    <rosparam file="$(find turtlebot_navigation)/param/global_costmap_params.yaml" command="load" />
    <rosparam file="$(find turtlebot_navigation)/param/dwa_local_planner_params.yaml" command="load" />
    <rosparam file="$(find turtlebot_navigation)/param/move_base_params.yaml" command="load" />
    <rosparam file="$(find turtlebot_navigation)/param/global_planner_params.yaml" command="load" />
    <rosparam file="$(find turtlebot_navigation)/param/navfn_global_planner_params.yaml" command="load" />
    <!-- external params file that could be loaded into the move_base namespace -->
    <rosparam file="$(arg custom_param_file)" command="load" />
    
    <!-- reset frame_id parameters using user input data -->
    <param name="global_costmap/global_frame" value="$(arg global_frame_id)"/>
    <param name="global_costmap/robot_base_frame" value="$(arg base_frame_id)"/>
    <param name="local_costmap/global_frame" value="$(arg odom_frame_id)"/>
    <param name="local_costmap/robot_base_frame" value="$(arg base_frame_id)"/>
    <param name="DWAPlannerROS/global_frame_id" value="$(arg odom_frame_id)"/>

    <remap from="cmd_vel" to="navigation_velocity_smoother/raw_cmd_vel"/>
    <remap from="odom" to="$(arg odom_topic)"/>
    <remap from="scan" to="$(arg laser_topic)"/>
</node>

    2.1.3 删除参数

<rosparam command="delete" param="my/param" />

    2.1.4 直接赋值参数

<rosparam param="a_list">[1, 2, 3, 4]</rosparam>

或者

<rosparam>
  a: 1
  b: 2
</rosparam>

2.2 命令行接口

该接口使我们可以通过命令行参数灵活地查看和配置参数。

范例

$ rosparam list /namespace
$ rosparam get parameter_name
$ rosparam set parameter_name value
$ rosparam delete parameter_name 

2.3 roscpp参数接口

该接口使我们能够定制ROS节点如何处理参数。roscpp的参数API有两套:一套在ros::param名字空间下,另一套封装在handle中,通过ros::NodeHandle接口访问:

    1. 为参数设置默认值
        nh.param<<variable_type>>("<param_name>", variable, <default_value>);
        ros::param::param<<variable_type>>("<param_name>", variable, <default_value>);

    上述代码功能是用名为<param_name>、值为<default_value>的参数初始化类型的变量variable。

    2. 从参数服务器获取一个参数值。
        ros::NodeHandle::getParam("<param_name>", variable)
        ros::param::get("<param_name>", variable)

    上述代码功能是从参数服务器获取名为<param_name>的参数的值,赋值给变量variable
        cache方式获取
 

ros::NodeHandle::getParamCached() and ros::param::getCached() provide local caching of parameter data. Using these versions informs the Parameter Server that this node would like to be notified when the parameter is changed, and prevents the node from having to re-lookup the value with the parameter server on subsequent calls.

Cached parameters are a significant speed increase (after the first
call), but should be used sparingly to avoid overloading the master. Cached parameters are also currently less reliable in the case of intermittent connection problems between your node and the master.

配置参数

ros::NodeHandle::setParam("<param_name>",<param_value>)
ros::param::set("<param_name>",<param_value>)

将参数<param_name>赋值为<param_value>

判断参数是否存在

ros::NodeHandle::hasParam("<param_name>")
ros::param::has("<param_name>")

判断参数<param_name>是否存在

删除参数

ros::NodeHandle::deleteParam("<param_name>")
ros::param::del("<param_name>")

删除参数<param_name>


在ROS的代码中,我们也可以进行一些参数的操作:

#include <ros/ros.h>
 
int main(int argc, char** argv)
{
	ros::init(argc, argv, "param_demo");
	ros::NodeHandle n;
	ros::NodeHandle pn("~my_namespce");
 
	std::string s;
	int num;
	
	n.param<std::string>("string_param", s, "haha");
	pn.param<int>("int_param", num, 666);
	
	//输出被初始化后的变量值
	ROS_INFO("string_param_init: %s", s.c_str());
	ROS_INFO("int_param_init: %d", num);
 
	//设置参数的值
	n.setParam("string_param", "hehe");
	pn.setParam("int_param", 222);
 
 
	//设置循环的频率为1Hz
	ros::Rate loop_rate(1);	
 
	while(ros::ok())
	{	
		//获取参数的值
		n.getParam("string_param", s);
		pn.getParam("int_param", num);
		
		//输出参数
		ROS_INFO("string_param: %s", s.c_str());
		ROS_INFO("int_param: %d", num);
		
		ros::spinOnce();
		loop_rate.sleep();
	}
	
	return 0;
}

编译后,先使用roscore启动ros,然后用rosrun运行节点。运行的结果为:

[ INFO] [1508962647.123025215]: string_param_init: haha
[ INFO] [1508962647.123388114]: int_param_init: 666
[ INFO] [1508962647.126034003]: string_param: hehe
[ INFO] [1508962647.126118085]: int_param: 222
[ INFO] [1508962648.127348007]: string_param: hehe
[ INFO] [1508962648.127499096]: int_param: 222
[ INFO] [1508962649.129554752]: string_param: hehe
[ INFO] [1508962649.130092222]: int_param: 222
[ INFO] [1508962650.128275652]: string_param: hehe
[ INFO] [1508962650.128455601]: int_param: 222
[ INFO] [1508962651.127771182]: string_param: hehe
[ INFO] [1508962651.128003505]: int_param: 222
[ INFO] [1508962652.128101292]: string_param: hehe
[ INFO] [1508962652.128249473]: int_param: 222
[ INFO] [1508962653.127405633]: string_param: hehe
[ INFO] [1508962653.127529541]: int_param: 222
[ INFO] [1508962654.126999255]: string_param: hehe
[ INFO] [1508962654.127161917]: int_param: 222
[ INFO] [1508962655.129154583]: string_param: hehe
[ INFO] [1508962655.129287685]: int_param: 222
……

此时,输入命令:

$ rosparam list

可以看到,参数已经存在参数服务器中了。结果如下:

/param_demo/my_namespce/int_param
/rosdistro
/roslaunch/uris/host_clp_virtual_machine__33415
/rosversion
/run_id
/string_param

代码解释:

定义NodeHandle对象n时用默认的全局命名空间,定义NodeHandle对象pn的时候使用了私有的命名空间:

ros::init(argc, argv, "param_demo");
ros::NodeHandle n;
ros::NodeHandle pn("~my_namespce");

因此“string_param”是全局的参数,“int_param”是在命名空间my_namespace下的参数。

接下来有两行代码:

n.param<std::string>("string_param", s, "haha");
pn.param<int>("int_param", num, 666)

官方文档对ros::NodeHandle::param()函数的描述如下:

param()函数从参数服务器取参数值给变量。如果无法获取,则将默认值赋给变量。这个函数的功能和getParam()函数类似,而区别是param()函数还提供了一个默认值。

    //设置参数的值
    n.setParam("string_param", "hehe");
    pn.setParam("int_param", 222);

设置参数的值。如果注释这两行代码,rosparam list命令将看不到“string_param”和“int_param”,这是因为参数服务器没有设置这两个参数。

n.getParam("string_param", s);
pn.getParam("int_param", num);

getParam()函数可以从参数服务器获取参数值。如果成功,变量s和num的值将会被修改为参数值,函数返回true;如果不成功(譬如参数服务器没有设置这个参数),变量s和num将保持原值,函数会返回false。

关闭第一次运行的节点(不关闭roscore),然后第二次运行该节点。结果为:

[ INFO] [1508962846.716579651]: string_param_init: hehe
[ INFO] [1508962846.716882790]: int_param_init: 222
[ INFO] [1508962846.719913219]: string_param: hehe
[ INFO] [1508962846.720229965]: int_param: 222
[ INFO] [1508962847.721341491]: string_param: hehe
[ INFO] [1508962847.721696804]: int_param: 222
[ INFO] [1508962848.724312549]: string_param: hehe
[ INFO] [1508962848.724606197]: int_param: 222
[ INFO] [1508962849.723765176]: string_param: hehe
[ INFO] [1508962849.724541585]: int_param: 222
[ INFO] [1508962850.721549217]: string_param: hehe
[ INFO] [1508962850.722647030]: int_param: 222
[ INFO] [1508962851.722353260]: string_param: hehe
[ INFO] [1508962851.722608120]: int_param: 222
[ INFO] [1508962852.725476354]: string_param: hehe
[ INFO] [1508962852.726797059]: int_param: 222
[ INFO] [1508962853.723994285]: string_param: hehe
[ INFO] [1508962853.724691083]: int_param: 222
……

将第二次运行结果和第一次运行结果对比,string_param_init和int_param_init的值发生了变化。这是因为在第一次运行节点后,参数string_param和num_param已经存在于参数服务器中,所以第二次运行节点时,默认值“haha”和“666”将不被使用,因此输出结果为“hehe”和222。


另外,在节点运行的过程中,我们用rosparam set 命令修改参数的值,可以观察到输出值的变化。

原文链接:

https://blog.csdn.net/wanghuiquan0712/article/details/78763144

https://blog.csdn.net/u014695839/article/details/78348600

https://blog.csdn.net/wengge987/article/details/50620121

猜你喜欢

转载自blog.csdn.net/sunlin972913894/article/details/103556936