转载: https://blog.csdn.net/u014695839/article/details/78348600
机器人工作时,我们有需要对机器人的参数(如传感器参数、算法的参数)进行设置。
有些参数(如机器人的轮廓、传感器的高度)在机器人启动时就设定好就行了;
有些参数则需要动态改变(特别是在调试的时候)。
ROS提供了参数服务器来满足这一需求。我们可以将参数设置在参数服务器,在需要用到参数的时候再从参数服务器中获取。
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 列出参数服务器中的参数
一般地,我们可以将需要设置的参数保存在yaml文件中,使用rosparam load [文件路径\文件名] 命令一次性将多个参数加载到参数服务器。
(yaml文件的格式和使用方法:https://www.ibm.com/developerworks/cn/xml/x-1103linrr/)
举个例子,一个名称为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
现在,我们要其中的参数加载到ROS的参数服务器中。
启动roscore,输入:
$ 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
另外,还可以参考turtlebot的navigation启动move_base节点的过程,保存在yaml文件中的参数是通过rosparam标签被加载到参数服务器中的。
-
& lt;node pkg= "move_base" type= "move_base" respawn= "false" name= "move_base" output= "screen"& gt;
-
& lt;rosparam file= "$(find turtlebot_navigation)/param/costmap_common_params.yaml" command= "load" ns= "global_costmap" /& gt;
-
& lt;rosparam file= "$(find turtlebot_navigation)/param/costmap_common_params.yaml" command= "load" ns= "local_costmap" /& gt;
-
& lt;rosparam file= "$(find turtlebot_navigation)/param/local_costmap_params.yaml" command= "load" /& gt;
-
& lt;rosparam file= "$(find turtlebot_navigation)/param/global_costmap_params.yaml" command= "load" /& gt;
-
& lt;rosparam file= "$(find turtlebot_navigation)/param/dwa_local_planner_params.yaml" command= "load" /& gt;
-
& lt;rosparam file= "$(find turtlebot_navigation)/param/move_base_params.yaml" command= "load" /& gt;
-
& lt;rosparam file= "$(find turtlebot_navigation)/param/global_planner_params.yaml" command= "load" /& gt;
-
& lt;rosparam file= "$(find turtlebot_navigation)/param/navfn_global_planner_params.yaml" command= "load" /& gt;
-
& lt;!-- external params file that could be loaded into the move_base namespace --& gt;
-
& lt;rosparam file= "$(arg custom_param_file)" command= "load" /& gt;
-
-
& lt;!-- reset frame_id parameters using user input data --& gt;
-
& lt;param name= "global_costmap/global_frame" value= "$(arg global_frame_id)"/& gt;
-
& lt;param name= "global_costmap/robot_base_frame" value= "$(arg base_frame_id)"/& gt;
-
& lt;param name= "local_costmap/global_frame" value= "$(arg odom_frame_id)"/& gt;
-
& lt;param name= "local_costmap/robot_base_frame" value= "$(arg base_frame_id)"/& gt;
-
& lt;param name= "DWAPlannerROS/global_frame_id" value= "$(arg odom_frame_id)"/& gt;
-
-
& lt;remap from= "cmd_vel" to= "navigation_velocity_smoother/raw_cmd_vel"/& gt;
-
& lt;remap from= "odom" to= "$(arg odom_topic)"/& gt;
-
& lt;remap from= "scan" to= "$(arg laser_topic)"/& gt;
-
& lt; /node>
当然,在ROS的代码中,我们也可以进行一些参数的操作:
-
-
-
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。我在上面的代码中没有接收返回值和判断,大家可以动手试试。
到了这里,大家应该知道为什么输出的前两行结果是“haha”和“666”了吧?
关闭第一次运行的节点(不关闭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 命令修改参数的值,可以观察到输出值的变化。
上面的一部分内容参考自:【ROS学习】(七)ROS参数服务(1)