Ask Your Question

Revision history [back]

Multiple instances of a dynamic_reconfigure server in the same client node

Hello,

I'm using ROS Kinetic. I'd like to have multiple instances of a dynamic_reconfigure server in a node, and I'm wondering how to achieve that. I have different robots that I define in YAML files with a specific number of motors for each robot. I have a dynamic_reconfigure config file in my package that allows me to set min, max, offset and enable parameters for a motor.

But I need to be able to tune those parameters for each motor defined in the YAML file, and that is unknown at compile time. I can't dynamically allocate some array of server because at runtime I don't have the callbacks created. A way, which I don't really like, could be to add a string or int field to the parameters, and type the motor name or index to apply the values to that specific motor in the code. There could be a bool parameter also to apply the new values in the client node when set to true. Another way could be to create a nodelet class of a motor with its own dynamic reconfigure server and callback, and have a vector of them in the main node, and push back as many as needed. The other way could be to use services instead, but then I couldn't use the rqt_reconfigure gui.

Is there a good practice for doing this kind of thing ? Thanks!

Multiple instances of a dynamic_reconfigure server in the same client node

Hello,

I'm using ROS Kinetic. I'd like to have multiple instances of a dynamic_reconfigure server in a node, and I'm wondering how to achieve that. I have different robots that I define in YAML files with a specific number of motors for each robot. I have a dynamic_reconfigure config file in my package that allows me to set min, max, offset and enable parameters for a motor.

But I need to be able to tune those parameters for each motor defined in the YAML file, and that is unknown at compile time. I can't dynamically allocate some array of server because at runtime I don't have the callbacks created.

A way, which I don't really like, could be to add a string or int field to the parameters, and type the motor name or index to apply the values to that specific motor in the code. There could be a bool parameter also to apply the new values in the client node when set to true. true.

Another way could be to create a nodelet class of a motor with its own dynamic reconfigure server and callback, and have a vector of them in the main node, and push back as many as needed. needed.

The other way could be to use services instead, but then I couldn't use the rqt_reconfigure gui.

Is there a good practice for doing this kind of thing ?

Thanks!

Multiple instances of a dynamic_reconfigure server in the same client node

Hello,

I'm using ROS Kinetic. I'd like to have multiple instances of a dynamic_reconfigure server in a node, and I'm wondering how to achieve that. I have different robots that I define in YAML files with a specific number of motors for each robot. I have a dynamic_reconfigure config file in my package that allows me to set min, max, offset and enable parameters for a motor.

But I need to be able to tune those parameters for each motor defined in the YAML file, and that is unknown at compile time. I can't dynamically allocate some array of server because at runtime I don't have the callbacks created.

A way, which I don't really like, could be to add a string or int field to the parameters, and type the motor name or index to apply the values to that specific motor in the code. There could be a bool parameter also to apply the new values in the client node when set to true.

Another way could be to create a nodelet class of a motor with its own dynamic reconfigure server and callback, and have a vector of them in the main node, and push back as many as needed.

The other way could be to use services instead, but then I couldn't use the rqt_reconfigure gui.

Is there a good practice for doing this kind of thing ?

Thanks!

EDIT:

I tried something pointed out by lucasw and it works! I found that a dynamic_reconfigure server is linked to a NodeHandle and there can only be one instance otherwise you get the error: "tried to advertise a service that is already advertised in this node". So I created a vector of NodeHandle that I link to each server. Also I had to make sure to call ros::init(...) before creating any instance of my class that has the CallbackType as a member otherwise I got the error: Couldn't find an AF_INET address...

My class is for filtering motor commands, here are a few lines of code that focus on solving this problem: In my header file :

class CommandFilter
{
    /* some functions */

    void motorDynConfigCallback(osa_control::MotorDynConfig &config, uint32_t level, const int idx);

private:
    std::vector<ros::NodeHandle*> nh_list_;
    std::vector<dynamic_reconfigure::Server<osa_control::MotorDynConfig>*> motor_dyn_config_server_list_;
    std::vector<dynamic_reconfigure::Server<osa_control::MotorDynConfig>::CallbackType> motor_dyn_config_callback_f_list_;
    osa_control::MotorDynConfig motor_param_;
    /* other class members */
};

In my implementation file:

bool CommandFilter::init()
{
/* some init code */

for(int i=0; i<ptr_robot_description_->getRobotDof(); i++)
{
        const std::string dof_name = ptr_robot_description_->getControllerList().at(i)->getName();

        ros::NodeHandle *node_handle = new ros::NodeHandle(dof_name.c_str());
        nh_list_.push_back(node_handle);

        dynamic_reconfigure::Server<osa_control::MotorDynConfig> *s = new dynamic_reconfigure::Server<osa_control::MotorDynConfig>(*node_handle);
        dynamic_reconfigure::Server<osa_control::MotorDynConfig>::CallbackType f;

        f = boost::bind(&CommandFilter::motorDynConfigCallback, this, _1, _2, i);
        motor_dyn_config_callback_f_list_.push_back(f);

        s->setCallback(f);
        motor_dyn_config_server_list_.push_back(s);
}

/* some init code */
}

void CommandFilter::motorDynConfigCallback(osa_control::MotorDynConfig &config, uint32_t level, const int idx)
{
    ROS_INFO("Dynamic Reconfigure Request for dof%d [%s]: %s %d %d %d", idx+1, ptr_robot_description_->getControllerList().at(idx)->getName().c_str(), config.enable?"True":"False", config.min_pos, config.max_pos, config.offset_pos);

    motor_param_ = config;
}

Note that it's a first cut solution and the code can be improved, but it works and give me exactly what I needed.

Multiple instances of a dynamic_reconfigure server in the same client node

Hello,

I'm using ROS Kinetic. I'd like to have multiple instances of a dynamic_reconfigure server in a node, and I'm wondering how to achieve that. I have different robots that I define in YAML files with a specific number of motors for each robot. I have a dynamic_reconfigure config file in my package that allows me to set min, max, offset and enable parameters for a motor.

But I need to be able to tune those parameters for each motor defined in the YAML file, and that is unknown at compile time. I can't dynamically allocate some array of server because at runtime I don't have the callbacks created.

A way, which I don't really like, could be to add a string or int field to the parameters, and type the motor name or index to apply the values to that specific motor in the code. There could be a bool parameter also to apply the new values in the client node when set to true.

Another way could be to create a nodelet class of a motor with its own dynamic reconfigure server and callback, and have a vector of them in the main node, and push back as many as needed.

The other way could be to use services instead, but then I couldn't use the rqt_reconfigure gui.

Is there a good practice for doing this kind of thing ?

Thanks!

EDIT:EDIT and ANSWER:

I tried something pointed out by lucasw and it works! I found that a dynamic_reconfigure server is linked to a NodeHandle and there can only be one instance otherwise you get the error: "tried to advertise a service that is already advertised in this node". So I created a vector of NodeHandle that I link to each server. Also I had to make sure to call ros::init(...) before creating any instance of my class that has the CallbackType as a member otherwise I got the error: Couldn't find an AF_INET address...

My class is for filtering motor commands, here are a few lines of code that focus on solving this problem: In my header file :

class CommandFilter
{
    /* some functions */

    void motorDynConfigCallback(osa_control::MotorDynConfig &config, uint32_t level, const int idx);

private:
    std::vector<ros::NodeHandle*> nh_list_;
    std::vector<dynamic_reconfigure::Server<osa_control::MotorDynConfig>*> motor_dyn_config_server_list_;
    std::vector<dynamic_reconfigure::Server<osa_control::MotorDynConfig>::CallbackType> motor_dyn_config_callback_f_list_;
    osa_control::MotorDynConfig motor_param_;
    /* other class members */
};

In my implementation file:

bool CommandFilter::init()
{
/* some init code */

for(int i=0; i<ptr_robot_description_->getRobotDof(); i++)
{
        const std::string dof_name = ptr_robot_description_->getControllerList().at(i)->getName();

        ros::NodeHandle *node_handle = new ros::NodeHandle(dof_name.c_str());
        nh_list_.push_back(node_handle);

        dynamic_reconfigure::Server<osa_control::MotorDynConfig> *s = new dynamic_reconfigure::Server<osa_control::MotorDynConfig>(*node_handle);
        dynamic_reconfigure::Server<osa_control::MotorDynConfig>::CallbackType f;

        f = boost::bind(&CommandFilter::motorDynConfigCallback, this, _1, _2, i);
        motor_dyn_config_callback_f_list_.push_back(f);

        s->setCallback(f);
        motor_dyn_config_server_list_.push_back(s);
}

/* some init code */
}

void CommandFilter::motorDynConfigCallback(osa_control::MotorDynConfig &config, uint32_t level, const int idx)
{
    ROS_INFO("Dynamic Reconfigure Request for dof%d [%s]: %s %d %d %d", idx+1, ptr_robot_description_->getControllerList().at(idx)->getName().c_str(), config.enable?"True":"False", config.min_pos, config.max_pos, config.offset_pos);

    motor_param_ = config;
}

Note that it's a first cut solution and the code can be improved, but it works and give me exactly what I needed.

Multiple instances of a dynamic_reconfigure server in the same client node

Hello,

I'm using ROS Kinetic. I'd like to have multiple instances of a dynamic_reconfigure server in a node, and I'm wondering how to achieve that. I have different robots that I define in YAML files with a specific number of motors for each robot. I have a dynamic_reconfigure config file in my package that allows me to set min, max, offset and enable parameters for a motor.

But I need to be able to tune those parameters for each motor defined in the YAML file, and that is unknown at compile time. I can't dynamically allocate some array of server because at runtime I don't have the callbacks created.

A way, which I don't really like, could be to add a string or int field to the parameters, and type the motor name or index to apply the values to that specific motor in the code. There could be a bool parameter also to apply the new values in the client node when set to true.

Another way could be to create a nodelet class of a motor with its own dynamic reconfigure server and callback, and have a vector of them in the main node, and push back as many as needed.

The other way could be to use services instead, but then I couldn't use the rqt_reconfigure gui.

Is there a good practice for doing this kind of thing ?

Thanks!

EDIT and ANSWER:

I tried something pointed out by lucasw and it works! I found that a dynamic_reconfigure server is linked to a NodeHandle and there can only be one instance otherwise you get the error: "tried to advertise a service that is already advertised in this node". So I created a vector of NodeHandle that I link to each server. Also I had to make sure to call ros::init(...) before creating any instance of my class that has the CallbackType as a member otherwise I got the error: Couldn't find an AF_INET address...

My class is for filtering motor commands, here are a few lines of code that focus on solving this problem: In my header file :

class CommandFilter
{
    /* some functions */

    void motorDynConfigCallback(osa_control::MotorDynConfig &config, uint32_t level, const int idx);

private:
    std::vector<ros::NodeHandle*> nh_list_;
    std::vector<dynamic_reconfigure::Server<osa_control::MotorDynConfig>*> motor_dyn_config_server_list_;
    std::vector<dynamic_reconfigure::Server<osa_control::MotorDynConfig>::CallbackType> motor_dyn_config_callback_f_list_;
    osa_control::MotorDynConfig motor_param_;
    /* other class members */
};

In my implementation file:

bool CommandFilter::init()
{
/* some init code */

for(int i=0; i<ptr_robot_description_->getRobotDof(); i++)
{
        const std::string dof_name = ptr_robot_description_->getControllerList().at(i)->getName();

        ros::NodeHandle *node_handle = new ros::NodeHandle(dof_name.c_str());
        nh_list_.push_back(node_handle);

        dynamic_reconfigure::Server<osa_control::MotorDynConfig> *s = new dynamic_reconfigure::Server<osa_control::MotorDynConfig>(*node_handle);
        dynamic_reconfigure::Server<osa_control::MotorDynConfig>::CallbackType f;

        f = boost::bind(&CommandFilter::motorDynConfigCallback, this, _1, _2, i);
        motor_dyn_config_callback_f_list_.push_back(f);

        s->setCallback(f);
        motor_dyn_config_server_list_.push_back(s);
}

/* some init code */
}

void CommandFilter::motorDynConfigCallback(osa_control::MotorDynConfig &config, uint32_t level, const int idx)
{
    ROS_INFO("Dynamic Reconfigure Request for dof%d [%s]: %s %d %d %d", idx+1, ptr_robot_description_->getControllerList().at(idx)->getName().c_str(), config.enable?"True":"False", config.min_pos, config.max_pos, config.offset_pos);

    motor_param_ = config;
}

Note that it's a first cut solution and the code can be improved, but it works and give me exactly what I needed.