ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

Multiple instances of a dynamic_reconfigure server in the same client node

asked 2018-04-18 12:35:15 -0500

updated 2018-04-19 09:44:45 -0500

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 retag flag offensive close merge delete

Comments

Passing extra arguments to callbacks: #q63991 (also a complete non-class example #q289061)

lucasw gravatar image lucasw  ( 2018-04-18 16:16:25 -0500 )edit

Thanks! I see that working for topics, but will it work for dynamic_reconfigure, will rqt_reconfigure show me a list of motors with their parameters using that design ? I'll give it a try.

Cyril Jourdan gravatar image Cyril Jourdan  ( 2018-04-19 02:51:20 -0500 )edit

Thanks for your hint lucasw, I've published an answer in my question.

Cyril Jourdan gravatar image Cyril Jourdan  ( 2018-04-19 09:37:33 -0500 )edit

@Cyril_J great you got it working. You can post your solution as an answer and accept that as correct. This will help other users stumbling upon the same problem...

mgruhler gravatar image mgruhler  ( 2018-04-19 09:42:12 -0500 )edit

1 Answer

Sort by ยป oldest newest most voted
1

answered 2018-04-19 09:44:09 -0500

updated 2018-04-19 10:07:53 -0500

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<dynamic_reconfigure::Server<osa_control::MotorDynConfig>*> motor_dyn_config_server_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(dof_name.c_str());

        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);

        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.

edit flag offensive delete link more

Comments

1

ROS1 has a limitation of 1 node per process. Multiple nodehandles will not create more nodes, but could introduce additional namespaces. Afaik the only thing required for multiple dyn_recfg servers is exactly that: multiple namespaces so topics don't clash.

gvdhoorn gravatar image gvdhoorn  ( 2018-04-19 09:46:10 -0500 )edit
ros::NodeHandle *node_handle = new ros::NodeHandle(dof_name.c_str());

This line created an additional namespace.

gvdhoorn gravatar image gvdhoorn  ( 2018-04-19 09:46:45 -0500 )edit

Yes exactly. @gvdhoorn Is there a way to create just the namespace ?

Cyril Jourdan gravatar image Cyril Jourdan  ( 2018-04-19 09:54:25 -0500 )edit

You can just directly pass in a NodeHandle instance. No need to keep them around yourself. The dynamic_reconfigure::Server instance owns them.

But you do need the NodeHandle instance.

gvdhoorn gravatar image gvdhoorn  ( 2018-04-19 09:59:04 -0500 )edit

Thanks for your advice @gvdhoorn, I've simplified the code and updated my answer. I works just as well.

Cyril Jourdan gravatar image Cyril Jourdan  ( 2018-04-19 10:08:47 -0500 )edit

It's worth pointing out: https://github.com/ros/dynamic_reconf... the constructor to the server can be given a mutex and a nodehandle

 new dynamic_reconfigure::Server<foo::Bar>(reconfig_mutex, node_handle)
lucasw gravatar image lucasw  ( 2018-05-04 15:29:25 -0500 )edit

You must construct the dynamic_reconfigure Server via the new operator. It doesn't work when you just use config_server(nh). Using the latter syntax, it will get destroyed when it goes out of scope.

Loy gravatar image Loy  ( 2018-09-17 02:37:41 -0500 )edit

Question Tools

3 followers

Stats

Asked: 2018-04-18 12:35:15 -0500

Seen: 1,997 times

Last updated: Apr 19 '18