C++ Dynamic_reconfigure client API in ROS

Viewed 101

If we only implement dynamic_reconfigure in server side, we have to manually calibrate parameters in GUI. Calibrating parameters is tedious if we have a lot of parameters. I'm using ros kinetic to implement a client node in c++ that can subscribe to a topic error and dynamically calibrate parameters in server node based on the data from the subscription of the topic error. However, there is no c++ client API tutorial in official document. I can only look at the header file in Github for implementation, and I got the error for creating a client in my class. I want to implement a class Calibration to define my client node. The following is my implementation of client node and error message.

//in calibration.h
#include <ros/ros.h>
#include <string>
#include <vector>
#include <std_msgs/Float32.h>
#include <dynamic_reconfigure/client.h>
#include <calibration/HcNodeConfig.h>

using namespace std;

class Calibration {
    hc::HcNodeConfig config;
    ros::NodeHandle n;
    ros::Subscriber listener;
    //dynamic_reconfigure::Client<hc::HcNodeConfig> adjuster("adjuster", &Calibration::adjuster_callback); 

    public:
        Calibration();
        void callback(const std_msgs::Float32ConstPtr& msg);
        void adjuster_callback(hc::HcNodeConfig& params);
};


//in calibration.cpp
#include "calibration.h"


void Calibration::adjuster_callback(hc::HcNodeConfig& params) {
    cout << "this is a dynamic_reconfigure callback" << endl;
}


void Calibration::callback(const std_msgs::Float32ConstPtr& msg) {
    float error = msg->data;
    dynamic_reconfigure::Client<hc::HcNodeConfig> client("hc", &Calibration::adjuster_callback, NULL);
    if (error <= 0.0) {
        config.direction = 0.0;
        client.setConfiguration(config);
    }

}


    Calibration::Calibration() {
        listener = n.subscribe("/error", 100, &Calibration::callback, this);
        ros::spin();
    }
    
    
    
    
    
    int main(int argc, char ** argv) {
        ros::init(argc, argv, "adjuster");
        Calibration cal();
        return 0;
    }

I got the following error.

/opt/ros/kinetic/include/dynamic_reconfigure/client.h: In instantiation of ‘dynamic_reconfigure::Client<ConfigType>::Client(const string&, boost::function<void(const ConfigType&)>, boost::function<void(const dynamic_reconfigure::ConfigDescription_<std::allocator<void> >&)>) [with ConfigType = hc::HcNodeConfig; std::__cxx11::string = std::__cxx11::basic_string<char>]’:
/home/david-dev/workspace/lidar/src/calibration/src/online/calibration.cpp:11:100:   required from here
/opt/ros/kinetic/include/dynamic_reconfigure/client.h:332:19: warning: ‘dynamic_reconfigure::Client<hc::HcNodeConfig>::nh_’ will be initialized after [-Wreorder]
   ros::NodeHandle nh_;
                   ^
/opt/ros/kinetic/include/dynamic_reconfigure/client.h:326:8: warning:   ‘bool dynamic_reconfigure::Client<hc::HcNodeConfig>::received_configuration_’ [-Wreorder]
   bool received_configuration_;
        ^
In file included from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.h:5:0,
                 from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.cpp:1:
/opt/ros/kinetic/include/dynamic_reconfigure/client.h:68:3: warning:   when initialized here [-Wreorder]
   Client(
   ^
In file included from /usr/include/boost/function/detail/maybe_include.hpp:18:0,
                 from /usr/include/boost/function/detail/function_iterate.hpp:14,
                 from /usr/include/boost/preprocessor/iteration/detail/iter/forward1.hpp:52,
                 from /usr/include/boost/function.hpp:64,
                 from /opt/ros/kinetic/include/ros/forwards.h:40,
                 from /opt/ros/kinetic/include/ros/common.h:37,
                 from /opt/ros/kinetic/include/ros/ros.h:43,
                 from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.h:1,
                 from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.cpp:1:
/usr/include/boost/function/function_template.hpp: In instantiation of ‘static void boost::detail::function::function_void_mem_invoker1<MemberPtr, R, T0>::invoke(boost::detail::function::function_buffer&, T0) [with MemberPtr = void (Calibration::*)(hc::HcNodeConfig&); R = void; T0 = const hc::HcNodeConfig&]’:
/usr/include/boost/function/function_template.hpp:940:38:   required from ‘void boost::function1<R, T1>::assign_to(Functor) [with Functor = void (Calibration::*)(hc::HcNodeConfig&); R = void; T0 = const hc::HcNodeConfig&]’
/usr/include/boost/function/function_template.hpp:728:7:   required from ‘boost::function1<R, T1>::function1(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = void (Calibration::*)(hc::HcNodeConfig&); R = void; T0 = const hc::HcNodeConfig&; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/usr/include/boost/function/function_template.hpp:1077:16:   required from ‘boost::function<R(T0)>::function(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = void (Calibration::*)(hc::HcNodeConfig&); R = void; T0 = const hc::HcNodeConfig&; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/home/david-dev/workspace/lidar/src/calibration/src/online/calibration.cpp:11:100:   required from here
/usr/include/boost/function/function_template.hpp:231:28: error: no match for call to ‘(boost::_mfi::mf1<void, Calibration, hc::HcNodeConfig&>) (const hc::HcNodeConfig&)’
           BOOST_FUNCTION_RETURN(boost::mem_fn(*f)(BOOST_FUNCTION_ARGS));
                            ^
In file included from /usr/include/boost/bind/mem_fn.hpp:215:0,
                 from /usr/include/boost/mem_fn.hpp:22,
                 from /usr/include/boost/function/detail/prologue.hpp:18,
                 from /usr/include/boost/function.hpp:24,
                 from /opt/ros/kinetic/include/ros/forwards.h:40,
                 from /opt/ros/kinetic/include/ros/common.h:37,
                 from /opt/ros/kinetic/include/ros/ros.h:43,
                 from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.h:1,
                 from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.cpp:1:
/usr/include/boost/bind/mem_fn_template.hpp:163:7: note: candidate: R boost::_mfi::mf1<R, T, A1>::operator()(T*, A1) const [with R = void; T = Calibration; A1 = hc::HcNodeConfig&]
     R operator()(T * p, A1 a1) const
       ^
/usr/include/boost/bind/mem_fn_template.hpp:163:7: note:   candidate expects 2 arguments, 1 provided
/usr/include/boost/bind/mem_fn_template.hpp:168:25: note: candidate: template<class U> R boost::_mfi::mf1<R, T, A1>::operator()(U&, A1) const [with U = U; R = void; T = Calibration; A1 = hc::HcNodeConfig&]
     template<class U> R operator()(U & u, A1 a1) const
                         ^
/usr/include/boost/bind/mem_fn_template.hpp:168:25: note:   template argument deduction/substitution failed:
In file included from /usr/include/boost/function/detail/maybe_include.hpp:18:0,
                 from /usr/include/boost/function/detail/function_iterate.hpp:14,
                 from /usr/include/boost/preprocessor/iteration/detail/iter/forward1.hpp:52,
                 from /usr/include/boost/function.hpp:64,
                 from /opt/ros/kinetic/include/ros/forwards.h:40,
                 from /opt/ros/kinetic/include/ros/common.h:37,
                 from /opt/ros/kinetic/include/ros/ros.h:43,
                 from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.h:1,
                 from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.cpp:1:
/usr/include/boost/function/function_template.hpp:231:28: note:   candidate expects 2 arguments, 1 provided
           BOOST_FUNCTION_RETURN(boost::mem_fn(*f)(BOOST_FUNCTION_ARGS));
                            ^
In file included from /usr/include/boost/bind/mem_fn.hpp:215:0,
                 from /usr/include/boost/mem_fn.hpp:22,
                 from /usr/include/boost/function/detail/prologue.hpp:18,
                 from /usr/include/boost/function.hpp:24,
                 from /opt/ros/kinetic/include/ros/forwards.h:40,
                 from /opt/ros/kinetic/include/ros/common.h:37,
                 from /opt/ros/kinetic/include/ros/ros.h:43,
                 from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.h:1,
                 from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.cpp:1:
/usr/include/boost/bind/mem_fn_template.hpp:176:25: note: candidate: template<class U> R boost::_mfi::mf1<R, T, A1>::operator()(const U&, A1) const [with U = U; R = void; T = Calibration; A1 = hc::HcNodeConfig&]
     template<class U> R operator()(U const & u, A1 a1) const
                         ^
/usr/include/boost/bind/mem_fn_template.hpp:176:25: note:   template argument deduction/substitution failed:
In file included from /usr/include/boost/function/detail/maybe_include.hpp:18:0,
                 from /usr/include/boost/function/detail/function_iterate.hpp:14,
                 from /usr/include/boost/preprocessor/iteration/detail/iter/forward1.hpp:52,
                 from /usr/include/boost/function.hpp:64,
                 from /opt/ros/kinetic/include/ros/forwards.h:40,
                 from /opt/ros/kinetic/include/ros/common.h:37,
                 from /opt/ros/kinetic/include/ros/ros.h:43,
                 from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.h:1,
                 from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.cpp:1:
/usr/include/boost/function/function_template.hpp:231:28: note:   candidate expects 2 arguments, 1 provided
           BOOST_FUNCTION_RETURN(boost::mem_fn(*f)(BOOST_FUNCTION_ARGS));
                            ^
In file included from /usr/include/boost/bind/mem_fn.hpp:215:0,
                 from /usr/include/boost/mem_fn.hpp:22,
                 from /usr/include/boost/function/detail/prologue.hpp:18,
                 from /usr/include/boost/function.hpp:24,
                 from /opt/ros/kinetic/include/ros/forwards.h:40,
                 from /opt/ros/kinetic/include/ros/common.h:37,
                 from /opt/ros/kinetic/include/ros/ros.h:43,
                 from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.h:1,
                 from /home/david-dev/workspace/lidar/src/calibration/src/online/calibration.cpp:1:
/usr/include/boost/bind/mem_fn_template.hpp:184:7: note: candidate: R boost::_mfi::mf1<R, T, A1>::operator()(T&, A1) const [with R = void; T = Calibration; A1 = hc::HcNodeConfig&]
     R operator()(T & t, A1 a1) const
       ^
/usr/include/boost/bind/mem_fn_template.hpp:184:7: note:   candidate expects 2 arguments, 1 provided
make[2]: *** [CMakeFiles/calibration_calibration_node.dir/src/online/calibration.cpp.o] Error 1
make[1]: *** [CMakeFiles/calibration_calibration_node.dir/all] Error 2
make: *** [all] Error 2

I think I pass wrong parameters to the dynamic_reconfigure::Client constructor. Any fix and improvement to my code? Thank you so much.

1 Answers

I think it points to an issue in your node handle initialization order? Looking at the src code it uses the name of the node to lookup the nodehandle, but the node handle might not be ready yet? The safer option would be to explicitly pass your node handle into the constructor, only after its initialized. The following member usually gets initialized right after (bool received_configuration), but if the name/nodehandle is incorrect, that might warn.

Related