[轉] rosparam和ROS參數服務

 

機器人工作時,我們有需要對機器人的參數(如傳感器參數、算法的參數)進行設置。

有些參數(如機器人的輪廓、傳感器的高度)在機器人啓動時就設定好就行了;

有些參數則需要動態改變(特別是在調試的時候)。

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

通過rosparam set [參數名] [參數值] 可以設置參數值;
通過rosparam get [參數名] 可以查看參數值;
大家可以多多嘗試。

另外,還可以參考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>


當然,在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()函數的描述如下:

(參考自:http://docs.ros.org/kinetic/api/roscpp/html/classros_1_1NodeHandle.html#a05941572641a453fd416c6603b91d39f)


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 命令修改參數的值,可以觀察到輸出值的變化。
————————————————
版權聲明:本文爲CSDN博主「培培哥」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u014695839/article/details/78348600

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章