# Setting Timer period for next callback

Hi, I have a ros::Timer that I want to change the period for at each callback. In the callback function, I'm calculating the time I want the next callback to occur at and calling setPeriod. However, calling setPeriod doesn't seem to affect the very NEXT callback. The next one will still occur at the "old" period. The callbacks start occurring at the new period on the second callback after I call setPeriod.

void myCallback(const ros::TimerEvent& e)
{
ROS_INFO("Time between callbacks: %f", (e.current_real - e.last_real).toSec());
// do stuff in callback

if(callbackCount == 0)
{
double t = calculateNextTimeForCallback();

myDuration = ros::Duration(t);

myTimer.setPerior(myDuration);
}
}


I end up with:

Time between callbacks: ros::Time::now (first one)
Time between callbacks: old time
Time between callbacks: new time
Time between callbacks: new time
...
Time between callbacks: new time


I'd like to have the new period to take effect on the callback immediately following the one where I call setPeriod. So then I could set a new time for each one. When I try to set the period in EACH callback (rather than just the first), the new periods never take effect.

It seems that the time a new callback occurs is based on the period and the TimerEvent's period.last_duration member. The TimerEvent is const though so I cannot change period.last_duration to hack a way for it to work. I have tried stopping and starting the timer at the end of the callback functions, but that will set the period.last_duration to 0 so the time between one ending and a new one beginning will be the new period which will always be too long.

I'm on Ubuntu 14.04 and Indigo.

If anyone can help me make this work or explain why it won't work, that would be great. If anything is unclear, please comment and I can explain further.

EDIT:

So in my example above, I was doing stuff in the callback that generally took around .3-.6 seconds. I tried to test with a callback that did almost nothing:

void myCallback(const ros::TimerEvent& e)
{
ROS_INFO("Time between callbacks: %f", (e.current_real - e.last_real).toSec());

// timer originally set to 2.0s
myDuration = ros::Duration(0.2);
myTimer.setPeriod(myDuration);
}


In that example, it actually worked just fine. So I tried another simple example that took some time for the callback to process:

void myCallback(const ros::TimerEvent& e)
{
ROS_INFO("Time between callbacks: %f", (e.current_real - e.last_real).toSec());
ROS_INFO("Last duration: %f", e.profile.last_duration.toSec());

for(int i=0;i<5000;i++)
{
ROS_INFO("Line %i", i);
}

// timer originally set to 2.0s
myDuration = ros::Duration(1.8);
myTimer.setPeriod(myDuration);
}


When I print out lots of text, the problem arises again. The time between each callback is last_duration+period. So in the last example, it generally took around .4 seconds to print the lines, and the time between callbacks was generally around 2.2 seconds.

edit retag close merge delete

Sort by » oldest newest most voted

Can you clarify why you want to use a Timer? If you calculate your own timeouts, you could just use ros::Duration(T).sleep(). If you want to sleep, but take execution time of your algorithm into account, use ros::Rate, which already does what you are trying to do (see roscpp/Overview/Time).

more

Well changing the periods is something I just started trying to do. Previously I did not want to change the period times so I had everything set up with Timers. I'm not married to the Timers, but my first thought was to change the Timer periods and then I ran into this issue. I'll try using Rates.

( 2015-03-26 10:12:20 -0600 )edit

Ok, well I think they should allow you to do what you want, without having to manually keep track of execution time and calculating new timeouts.

( 2015-03-27 04:51:12 -0600 )edit

So I reread the Time overview and tutorials and it's not clear to me what the difference between Timers and Rates is. The roscpp tutorial ( http://wiki.ros.org/roscpp_tutorials/... ) states that Timers are more flexible than Rates. Do Timers not considering execution time?

( 2015-03-27 12:22:59 -0600 )edit

Afaik, no. Timers just fire at their configured period. Rates are basically sleeps, but take into account what the execution time has been since the last call to my_rate.sleep(). They then compensate for that time by reducing the time to sleep.

( 2015-03-27 15:50:36 -0600 )edit

Just got around to trying this...used Rates for that console-printing example and it works very well. Now I'll start migrating my algorithm to using Rates. Thanks for the help!

( 2015-03-28 14:00:12 -0600 )edit

I feel it's important to note that Timers do have their use, and are more accurate than Rates. Rates can be used when you want to structure your application around a while-loop (which does more than just call ros::spinOnce()). Timers are preferred if you just want to publish at specific intervals.

( 2015-03-29 01:45:27 -0600 )edit

At the time of this question the Timer class did not consider elapsed time when you called setPeriod. Now the Timer class can handle calling setPeriod at any time so this should not be a problem any longer.

( 2015-07-23 08:16:59 -0600 )edit

Could you link to an issue or PR where this was changed?

( 2015-07-23 08:33:36 -0600 )edit