Bootstrap

ROS:动态参数

一、前言

参数服务器的数据被修改时,如果节点不重新访问,那么就不能获取修改后的数据,例如在乌龟背景色修改的案例中,先启动乌龟显示节点,然后再修改参数服务器中关于背景色设置的参数,那么窗体的背景色是不会修改的,必须要重启乌龟显示节点才能生效。而一些特殊场景下,是要求要能做到动态获取的,也即,参数一旦修改,能够通知节点参数已经修改并读取修改后的数据,比如:
机器人调试时,需要修改机器人轮廓信息(长宽高)、传感器位姿信息…,如果这些信息存储在参数服务器中,那么意味着需要重启节点,才能使更新设置生效,但是希望修改完毕之后,某些节点能够即时更新这些参数信息。

在ROS中针对这种场景已经给出的解决方案: dynamic reconfigure 动态配置参数。

动态配置参数,之所以能够实现即时更新,因为被设计成 CS 架构,客户端修改参数就是向服务器发送请求,服务器接收到请求之后,读取修改后的是参数。

二、概念

一种可以在运行时更新参数而无需重启节点的参数配置策略。

三、作用

主要应用于需要动态更新参数的场景,比如参数调试、功能切换等。典型应用:导航时参数的动态调试。

四、实际用例

4.1需求

编写两个节点,一个节点可以动态修改参数,另一个节点时时解析修改后的数据。

4.2客户端

4.2.1流程

1.新建并编辑 .cfg 文件;
2.编辑CMakeLists.txt;
3.编译。

4.2.2新建功能包

新建功能包,添加依赖:roscpp rospy std_msgs dynamic_reconfigure

4.2.3添加.cfg文件

新建 cfg 文件夹,添加 xxx.cfg 文件(并添加可执行权限),cfg 文件其实就是一个 python 文件,用于生成参数修改的客户端(GUI)。

#! /usr/bin/env python
"""
 4生成动态参数 int,double,bool,string,列表
 5实现流程:
 6    1.导包
 7    2.创建生成器
 8    3.向生成器添加若干参数
 9    4.生成中间文件并退出
10
"""
# 1.导包
from dynamic_reconfigure.parameter_generator_catkin import *
PACKAGE = "demo02_dr"
# 2.创建生成器
gen = ParameterGenerator()

# 3.向生成器添加若干参数
#add(name, paramtype, level, description, default=None, min=None, max=None, edit_method="")
gen.add("int_param",int_t,0,"整型参数",50,0,100)
gen.add("double_param",double_t,0,"浮点参数",1.57,0,3.14)
gen.add("string_param",str_t,0,"字符串参数","hello world ")
gen.add("bool_param",bool_t,0,"bool参数",True)

many_enum = gen.enum([gen.const("small",int_t,0,"a small size"),
                gen.const("mediun",int_t,1,"a medium size"),
                gen.const("big",int_t,2,"a big size")
                ],"a car size set")

gen.add("list_param",int_t,0,"列表参数",0,0,2, edit_method=many_enum)

# 4.生成中间文件并退出
exit(gen.generate(PACKAGE,"dr_node","dr"))

chmod +x xxx.cfg添加权限

4.2.4配置 CMakeLists.txt

generate_dynamic_reconfigure_options(
  cfg/mycar.cfg
)

4.2.5编译

编译后会生成中间文件

C++ 需要调用的头文件:
在这里插入图片描述
Python需要调用的文件:
在这里插入图片描述

4.3服务端(C++)

4.3.1流程

1.新建并编辑 c++ 文件;
2.编辑CMakeLists.txt;
3.编译并执行。

4.3.2vscode配置

需要像之前自定义 msg 实现一样配置settings.json 文件,如果以前已经配置且没有变更工作空间,可以忽略,如果需要配置,配置方式与之前相同:

{
    "configurations": [
        {
            "browse": {
                "databaseFilename": "",
                "limitSymbolsToIncludedHeaders": true
            },
            "includePath": [
                "/opt/ros/noetic/include/**",
                "/usr/include/**",
                "/xxx/yyy工作空间/devel/include/**" //配置 head 文件的路径 
            ],
            "name": "ROS",
            "intelliSenseMode": "gcc-x64",
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "c11",
            "cppStandard": "c++17"
        }
    ],
    "version": 4
}

4.3.3服务器代码实现

新建cpp文件,内容如下:

#include "ros/ros.h"
#include "dynamic_reconfigure/server.h"
#include "demo02_dr/drConfig.h"
 /*  
    动态参数服务端: 参数被修改时直接打印
    实现流程:
        1.包含头文件
        2.初始化 ros 节点
        3.创建服务器对象
        4.创建回调对象(使用回调函数,打印修改后的参数)
        5.服务器对象调用回调对象
        6.spin()
*/

void cb(demo02_dr::drConfig& config, uint32_t level){
    ROS_INFO("动态参数解析数据:%d,%.2f,%d,%s,%d",
        config.int_param,
        config.double_param,
        config.bool_param,
        config.string_param.c_str(),
        config.list_param
    );
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    // 2.初始化 ros 节点
    ros::init(argc,argv,"dr");
    // 3.创建服务器对象
    dynamic_reconfigure::Server<demo02_dr::drConfig> server;
    // 4.创建回调对象(使用回调函数,打印修改后的参数)
    dynamic_reconfigure::Server<demo02_dr::drConfig>::CallbackType cbType;
    cbType = boost::bind(&cb,_1,_2);
    // 5.服务器对象调用回调对象
    server.setCallback(cbType);
    // 6.spin()
    ros::spin();
    return 0;
}

4.3.4编译配置文件

add_executable(demo01_dr_server src/demo01_dr_server.cpp)
...

add_dependencies(demo01_dr_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
...

target_link_libraries(demo01_dr_server
  ${catkin_LIBRARIES}
)

4.3.5执行

先启动roscore

启动服务端:rosrun 功能包 xxxx

启动客户端:rosrun rqt_gui rqt_gui -s rqt_reconfigurerosrun rqt_reconfigure rqt_reconfigure

最终可以通过客户端提供的界面修改数据,并且修改完毕后,服务端会即时输出修改后的结果,最终运行结果与示例类似。

注:ROS版本较新时,可能没有提供客户端相关的功能包导致rosrun rqt_reconfigure rqt_reconfigure调用会抛出异常。

4.4服务端(Python)

4.4.1流程

1.新建并编辑 Python 文件;
2.编辑CMakeLists.txt;
3.编译并执行。

4.4.2vscode配置

需要像之前自定义 msg 实现一样配置settings.json 文件,如果以前已经配置且没有变更工作空间,可以忽略,如果需要配置,配置方式与之前相同:

{
    "python.autoComplete.extraPaths": [
        "/opt/ros/noetic/lib/python3/dist-packages",
        "/xxx/yyy工作空间/devel/lib/python3/dist-packages"
    ]
}

4.4.3服务器代码实现

新建python文件,内容如下:

#! /usr/bin/env python
import rospy
from dynamic_reconfigure.server import Server
from demo02_dr.cfg import drConfig

"""
    动态参数服务端: 参数被修改时直接打印
    实现流程:
        1.导包
        2.初始化 ros 节点
        3.创建服务对象
        4.回调函数处理
        5.spin
"""
# 回调函数
def cb(config,level):
    rospy.loginfo("python 动态参数服务解析:%d,%.2f,%d,%s,%d",
            config.int_param,
            config.double_param,
            config.bool_param,
            config.string_param,
            config.list_param
    )
    return config

if __name__ == "__main__":
    # 2.初始化 ros 节点
    rospy.init_node("dr_p")
    # 3.创建服务对象
    server = Server(drConfig,cb)
    # 4.回调函数处理
    # 5.spin
    rospy.spin()

添加可执行权限:chmod +x *.py

4.4.4编辑配置文件

catkin_install_python(PROGRAMS
  scripts/demo01_dr_server_p.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

4.4.5执行

先启动roscore

启动服务端:rosrun 功能包 xxxx.py

启动客户端:rosrun rqt_gui rqt_gui -s rqt_reconfigurerosrun rqt_reconfigure rqt_reconfigure

最终可以通过客户端提供的界面修改数据,并且修改完毕后,服务端会即时输出修改后的结果,最终运行结果与示例类似。

注:ROS版本较新时,可能没有提供客户端相关的功能包导致rosrun rqt_reconfigure rqt_reconfigure调用会抛出异常。

参考视屏:赵虚左ros入门
在这里插入图片描述

;