声明:以下内容全为原创,大家有疑问可以留言或直接私信我。

该功能包的所有内容我放到了百度网盘下,大家可以自取下载解压到自己的工作空间下。如下

链接: https://pan.baidu.com/s/12T8av-sAM8vPxjIx1Y0l5Q 提取码: ksdv

1.如题,我们知道在c++中,可以通过nodehandle.param从launch文件或yaml文件中获取配置的参数,传入顺序是yaml文件——launch文件——cpp文件。通过这种做法,我们可以直接在yaml文件中很方便的设置变量的值,将其传进cpp里作为具体参数。

2.但这种做法有问题。就是我们在想修改参数的时候。我们都需要找到yaml文件进行修改,然后再重新启动cpp。这样就十分不方便。熟悉navigation导航包的同学会知道,我们在调试真实小车时,可以打开rqt中的dynamic_configure工具去实时调试move_base节点参数的值(如小车的最大加速度,最大速度等),而不需要修改yaml里的默认配置和重新启动节点。

3.那这是怎么做到的呢,接下来我将通过一个简单的例子给大家展示。

4.首先在你的工作空间的src目录下打开终端创建一个功能包(如没有工作空间,新建一个,并新建一个src目录),接下来通过这行命令创建一个功能包

catkin_create_pkg dynamic_test roscpp rospy dynamic_reconfigure

在创建好后,进入该功能包,新建cfg、launch、param文件夹,分别用于存放cfg、launch、yaml配置文件。

5.接下来我们先来创建用于配置动态参数的test.cfg文件,打开文件,输入以下内容。具体解释以及注释在代码段里。

#!/usr/bin/env python
PACKAGE = "dynamic_test"

from dynamic_reconfigure.parameter_generator_catkin import *


gen = ParameterGenerator()


gen.add("acc_x",        double_t, 0, "the acc x velocity of vehicle ",  .5, 0,  2)
gen.add("obtain_name",  str_t,    0, "topic name" , "fff")
gen.add("acc_y",        double_t, 0,  "the acc y velocity of vehicle", 0.5, 0 , 2)
gen.add("use_dwa",      bool_t,   0, "whether use dwa or not", True )
# 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)

# 最后一个参数是生成的动态参数头文件名字,如这里生成的应是testConfig.h
exit(gen.generate(PACKAGE, "dynamic_test", "test"))

6.接下来我们先来编译刚才配置的动态参数,以产生之后cpp文件里需要用的头文件。

 这时打开cmakelists.txt,将我们要编译的cfg文件路径输入,如下(将这行代码插入你cmakelists.txt即可)。

generate_dynamic_reconfigure_options(
  cfg/test.cfg
)

7.好,接下来进入你的工作空间下,使用catkin_make命令进行编译。编译如果没有问题,通过后你会在devel/include/dynamic_test路径下找到一个头文件,这个头文件就是之后我们在cpp中要include进去的。如下图

 8.在功能包的src目录下,新建一个test.cpp,将如下内容复制进去。

#include <ros/ros.h>
#include <dynamic_reconfigure/server.h>
#include "dynamic_test/testConfig.h" //刚才我们通过编译生成的头文件


double x,y;
std::string name;
bool use_dwa_;
namespace dynamic_test{
    void callback(testConfig &config,uint32_t level)
    {
        
        x = config.acc_x;
        y = config.acc_y;
        name = config.obtain_name;
        std::cout<<x<<std::endl;
        std::cout<<y<<std::endl;
        std::cout<<name<<std::endl;
        use_dwa_ = config.use_dwa;
        if(use_dwa_){
            std::cout<<x+y<<std::endl;
        }
    }
}

int main(int argc, char** argv){
    ros::init(argc,argv,"dynamic_test");
    // 创建句柄节点
    ros::NodeHandle nh;
    ros::NodeHandle nhPrivate("~");

    // 通过param获取参数
    nhPrivate.param("acc_x",x,0.2);
    nhPrivate.param("acc_y",y,0.2);
    nhPrivate.param<std::string>("obtain_name",name,"ss");
    nhPrivate.param<bool>("use_dwa",use_dwa_,false);

    std::cout<<x<<std::endl;
    std::cout<<y<<std::endl;
    std::cout<<name<<std::endl;

    //创建动态参数服务,并绑定回调函数
    dynamic_reconfigure::Server<dynamic_test::testConfig> srv;
    dynamic_reconfigure::Server<dynamic_test::testConfig>::CallbackType ca = boost::bind(&dynamic_test::callback,_1,_2);
    srv.setCallback(ca);

    ros::spin();
    return 0;
}

9.这时,我们需要在cmakelists.txt中加入编译规则,将以下代码添加到你的cmakelists.txt中(我的完整cmakelists.txt在文章末尾)

add_executable(${PROJECT_NAME} src/test.cpp)
add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(${PROJECT_NAME}
  ${catkin_LIBRARIES}
)

10.接下来可以进行编译,进入工作空间,然后catkin_make。

11.你会发现这时我们还没有配置launch文件和yaml文件。接下来分别在luanch文件夹和param文件夹下创建test.launch和test.yaml,并分开输入以下内容

<launch>

 <node pkg="dynamic_test" type="dynamic_test" name="dynamic_test" output="screen">
    <!-- 参数可以直接在launch文件中通过param设置,也可以用yaml文件传参,以下acc_x就是直接在launch文件中设置 -->
    <param name="acc_x" value="0.4"/>
    <rosparam file="$(find dynamic_test)/param/test.yaml" command="load"/>

</node>

</launch>
acc_y: 0.4
obtain_name: aaa
use_dwa: false

12.保存配置,我们之后直接通过启动launch文件来启动cpp源文件。如下编译之后,source一下,然后启动launch文件。

 13.启动之后我们会发现终端输出了一些数,如下图

 这里的输出就是我们在cpp里cout的。我们分别在main函数和callback函数中输出了acc_x,acc_y,和obtain_name。所以这里输出了6行数据,其值就是我们在yaml文件里设置的值,说明yaml的参数正确传入了cpp中。

13.打开一个新终端,运行rqt_reconfigure工具。rosrun rqt_reconfigure rqt_reconfigure。打开过后界面如下。

 从这个工具我们就可以动态设置参数了,并且不会影响我们在yaml文件里设置的默认值,十分方便实时的调试。

如下图,我们调整一次参数,cpp就会执行一次回调函数callback里的代码。

 14.我完整的cmakelists.txt大家可以下载百度网盘里的功能包查看。但最好按照我的步骤一步一步来,这样才能学习到东西。