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

Dynamic parameters update from the code (cpp)

asked 2016-02-23 03:35:03 -0500

postal gravatar image

updated 2016-03-16 03:28:14 -0500

gvdhoorn gravatar image

Hello, folks!

I am having trouble to update the dynamic parameters from c++ code. My first attempt was to follow hokuyo_node tutorial. So I put this line in my code:
system("rosrun dynamic_reconfigure dynparam set My_node My_param Value &");
The & sign in the end was due to the information I print in my code. Without it the code stops. But when I started to test the code in Gazebo and invoked the command much often, processor load went to around 100% (without the line it worked on 40-50%). Maybe I need to invoke the command in another way?

Another solutions I found regarding my problem:

the solution presented in first two links didn't work for me (maybe because of my wrong initialization of dynamic_reconfigure::Server inside the class, I will put my code below). If I initialize dynamic_reconfigure::Server giving my node as an argument, nothing shows up in rqt_reconfigure.
The code from the last "Notify changes ... " was more similar to mine - it also based on classes, so It showed some work ability. But when I started rqt_reconfigure the parameter's values in my node were completely random and didn't change with my inputs.
Here is how my code look like:

main

int main(int argc, char * *argv)  
{  
    ros::init(argc, argv, "flight_controller");  
    ros::NodeHandle my_node;  
    static My_class *class = new My_class(my_node);  
}

My_class

class My_class  
{  
private:  
ros::NodeHandle node;  
    dynamic_reconfigure::Server<Config> param_server;  
    dynamic_reconfigure::Server<Config>::CallbackType call_type;  
public:  
    My_class(ros::NodeHandle &node_)  
    //,param_server(node)   if this line uncomment, rqt_reconfigure doesn't see the node  
    {  
        node = node_;  
        call_type = boost::bind(&My_class::parametersCallback, this, _1, _2);  
        param_server.setCallback(call_type);  
    }  
}

Thank you in advance for help!


Edit: @ahendrix
So I am not changing the parameters often. But there is one parameter being changed inside the program, but not rqt_reconfigure. I want those parameters to be synchronized. Lets say I have parameters A=1 and B=2 (I can see it in rqt_reconfigure). Program changes value A=3, rqt_reconfigure continue to display A=1. When I after change through rqt B=4, it changes B=4 and A=1!, since it was the last value displayed in rqt_reconfigure and rqt call_back looks like that:

parametersCallback(prodrone::ProdroneConfig &config, uint32_t level)
{
A = config.a;
B = config.b;
}

I want to change only B, without touching A, so that A has to be updated in rqt as soon as it changes inside the program.

edit retag flag offensive close merge delete

Comments

Did you look at this question/answer?

Thomas D gravatar image Thomas D  ( 2016-02-23 08:15:06 -0500 )edit

Thank you Thomas! I did try but I'm having the same problem that was mentioned by lucasw (Jul 8 '15) in comments.

postal gravatar image postal  ( 2016-03-15 10:27:02 -0500 )edit

2 Answers

Sort by ยป oldest newest most voted
1

answered 2016-03-22 05:05:40 -0500

postal gravatar image

So I found the solution for my self, not exactly what I wanted, but it works.

I finally managed the code from Notify changes to dynamic_reconfigure question to work. My problem was that I didn't initialize the dyn_config properly in a class constructor, which entailed the parameters to constantly update with random, out-of-scope numbers. But this solution didn't work for me eventually and here is why. From the example, in the link above, we can see the function void ScitosBase::dynamicReconfigureUpdaterLoop that updates the parameters every ros::Rate loop_rate = 0.5 sec. The problem is how the rqt_reconfigure node reacts on these updates: if you didn't manage to move the slider at the position you want within this 0.5 sec to change the value, it put it to the position you had it taken from; whereas if you try to change the value by typing manually, you should also do it in a half of second, otherwise the pointer drop out from typing bar. So this solution doesn't work for me - I need the parameters to update fast while having the time to type a new value.

So what I do in short - I don't update the values constantly with some specific update rate, but run the analog of void ScitosBase::dynamicReconfigureUpdaterLoop each time I update the dyn_param value from the code:
main

int main(int argc, char * *argv)  
{  
    ros::init(argc, argv, "flight_controller");  
    ros::NodeHandle my_node;  
    static My_class *class = new My_class(my_node);      
}

My_class

class My_class  
{  
private:  
    ros::NodeHandle node;  
    void parametersCallback(Config &config, uint32_t level);  
    dynamic_reconfigure::Server<Config> param_server;  
    dynamic_reconfigure::Server<Config>::CallbackType call_type;  
    boost::recursive_mutex config_mutex; //I am not sure whether I need it 
public:  
    My_class(ros::NodeHandle &node_)  
    {  
        node = node_;  

        boost::recursive_mutex::scoped_lock dyn_reconf_lock(config_mutex);  
        dyn_reconf_lock.unlock();  

        call_type = boost::bind(&My_class::parametersCallback, this, _1, _2);  
        param_server.setCallback(call_type);  
        /* Initialize the parameters at once, otherwise the values will be random */
        Config config;
        param_server.getConfigDefault(config);
        param_server.updateConfig(config);
    }  
void dynamicReconfigureUpdate(); 
double a,b; 
}

void My_class::dynamicReconfigureUpdate()  
{  
    Config config;
    /* You need to assign every single value of you dyn_parameters configuration. Unassigned values will turn into random at rqt_reconfigure */
    config.a = my_a_value_in_code;
    config.b = my_b_value_in_code;
    boost::recursive_mutex::scoped_lock lock(config_mutex); // I am not sure I need it
    param_server.updateConfig(config);
    lock.unlock();
}

void My_class::parametersCallback(Config &config, uint32_t level)  
{
    a = config.a;  
    b = config.b;
}

So each time I am changing a or b within my program I run My_class::dynamicReconfigureUpdate() to update the rqt_reconfigure. It will not work if you call the function less than it takes for you to move rqt slider or input the value manually, which is not my case.

The last question I have is regarding the recursive_mutex. It is said here that you need to implement it if you call void updateConfig(const ConfigType &config) but I am not familiar with the recursive_mutex and I am not sure I am using it right. Can somebody give me a hint?

edit flag offensive delete link more

Comments

Found your code useful. When I implemented similar, I got a warning when 'updateConfig' is called telling me I need a mutex. I'm guessing you did too and expect this code still to.

Add ": param_server(config_mutex)" to your constructor and the mutex gets used. Otherwise it does nothing.

Dave Barnett gravatar image Dave Barnett  ( 2017-11-02 05:09:24 -0500 )edit
0

answered 2016-02-23 04:00:44 -0500

ahendrix gravatar image

dynamic_reconfigure is intended for parameters that change occasionally; not for continuous parameter updates.

You probably shouldn't be trying to transfer parameters from one node to another at a high rate using dynamic_reconfigure. Why not use topics instead?

(as a side note, the trailing & on your command will cause it to run as a background task. It will still take just as long, but it won't block your main thread, and if you call it frequently you will end up with lots of background tasks, all running at the same time. This is probably why you're seeing high CPU usage.)

edit flag offensive delete link more

Comments

Thank you for the answer. I am mainly use dynamic_reconfigure for debugging and it's GUI pretty convenient. So I do not use it at high rates. And I think dyn_reconfigure has the feature I need, although it's not documented. You can discover it from "Notify changes to dynamic_reconfigure" link.

postal gravatar image postal  ( 2016-02-23 04:54:45 -0500 )edit

In your question you said you were using dynamic reconfigure frequently, from code:

But when I started to test the code in Gazebo and invoked the command much often, processor load went to around 100%

ahendrix gravatar image ahendrix  ( 2016-02-23 15:57:55 -0500 )edit

You're also not clear about whether your node is updating itself, or whether the update is coming form a separate process. The tutorial specifically references the case where you want to update the parameters in a separate node.

ahendrix gravatar image ahendrix  ( 2016-02-23 15:59:46 -0500 )edit

Thank you for your help and sorry for such a late reply! I had a bug that was recursively calling dyn_param callback, so I managed it to work using system("rosrun dynamic_reconfigure dynparam set My_node My_param Value &"); but this solution sometimes gives bugs, for instance:

postal gravatar image postal  ( 2016-03-15 10:20:52 -0500 )edit

If you run from c++ code these lines: system("rosrun dynamic_reconfigure dynparam set My_node My_param_1 Value &") system("rosrun dynamic_reconfigure dynparam set My_node My_param_2 Value &") It may change My_param_2 before it changes My_param_1

postal gravatar image postal  ( 2016-03-15 10:25:33 -0500 )edit

Regarding node I am calling from: I tried both cases from the same node and from other - the result was the same.

postal gravatar image postal  ( 2016-03-15 10:26:09 -0500 )edit

I still don't understand why you're trying to do this.

ahendrix gravatar image ahendrix  ( 2016-03-15 13:12:26 -0500 )edit

With your update; it's pretty obvious that you want to take the third option: http://answers.ros.org/question/57498... . Just look at the example more closely and fix the bug that causes it to call itself recursively.

ahendrix gravatar image ahendrix  ( 2016-03-16 12:46:50 -0500 )edit

Question Tools

2 followers

Stats

Asked: 2016-02-23 03:35:03 -0500

Seen: 6,087 times

Last updated: Mar 22 '16