Author Topic: Webbotlib main loop time keeping issue  (Read 2269 times)

0 Members and 1 Guest are viewing this topic.

Offline madsci1016Topic starter

  • Contest Winner
  • Supreme Robot
  • ****
  • Posts: 1,450
  • Helpful? 43
    • Personal Website
Webbotlib main loop time keeping issue
« on: March 15, 2010, 05:06:45 PM »
Alright guys, this one is bugging the heck out of me.

I'm trying to run the main Loop at a 10Hz rate accounting for time it takes to complete the loop. Here's my main loop:

Code: [Select]
TICK_COUNT appControl(LOOP_COUNT loopCount, TICK_COUNT loopStart){

switch (mode)
{
case 0 :
read_sensors();
read_commands();
follow_heading();
sendSensorData();
time_left = 100000 - (clockGetus() - loopStart);  // take up the rest of the time in the 10Hz rate
rprintf("  %ld, %ld, %ld \n", (clockGetus() / 1000), (loopStart / 1000), (time_left / 1000));
//cpu_load = ((time_left / (float)100000) * 100);
break;


}

return time_left; // wait for 1 second before calling me again. 1000000us = 1 second
}

This is what i get as output:

341, 295, 54
390, 351, 60      (The second number (351) should be 341 + 54, but it's not. And so on for the next lines)
458, 412, 54
506, 467, 60

So the library is not delaying as much as it should. It calculates the remaining time out of 100ms per loop, and sets 'time_left' as that number fine, and i return that number, but it's not delaying that long before the loop starts again. time_left is a TICK_COUNT type.

 Any ideas what's going on here?

Offline madsci1016Topic starter

  • Contest Winner
  • Supreme Robot
  • ****
  • Posts: 1,450
  • Helpful? 43
    • Personal Website
Re: Webbotlib main loop time keeping issue
« Reply #1 on: March 15, 2010, 05:46:31 PM »
I just did some more checking,

Code: [Select]
TICK_COUNT appControl(LOOP_COUNT loopCount, TICK_COUNT loopStart){

TICK_COUNT start = clockGetus();

switch (mode)
{
case 0 :
read_sensors();
read_commands();
follow_heading();
sendSensorData();
time_left = 100000 - (clockGetus() - loopStart);  // take up the rest of the time in the 10Hz rate
rprintf("  %ld, %ld, %ld \n", (clockGetus() / 1000), (loopStart / 1000), (time_left / 1000));
//cpu_load = ((time_left / (float)100000) * 100);
break;


}
TICK_COUNT end = clockGetus();

rprintf("Start   %ld, End   %ld,\n", (start / 1000), (end / 1000) );
return 100000; // wait for 1 second before calling me again. 1000000us = 1 second
}

So i have Start and End recording time, and a hard set return of 100ms, yes i only see a delay of around 50ms.

Here's serial output:

Start   700, End   749,
Start   801, End   849,
Start   901, End   949,


Also, newest version of Webbot lib, 1.15b.

Offline madsci1016Topic starter

  • Contest Winner
  • Supreme Robot
  • ****
  • Posts: 1,450
  • Helpful? 43
    • Personal Website
Re: Webbotlib main loop time keeping issue
« Reply #2 on: March 15, 2010, 05:53:42 PM »
Well, looking through Webbot lib source, it seems it's clock already accounts for the delay of actually running your code,
(what i was doing with time_left = 100000 - (clockGetus() - loopStart);) 

IE, when you delay 1 second, you delay from loopStart, not from when you actually finish the loop and return the delay amount.

It is not clear at all in the PDF manual if this is true, but that seems to be the case. Can anyone confirm?


Offline Webbot

  • Expert Roboticist
  • Supreme Robot
  • *****
  • Posts: 2,165
  • Helpful? 111
    • Webbot stuff
Re: Webbotlib main loop time keeping issue
« Reply #3 on: March 15, 2010, 06:26:16 PM »
Yep - it tries to pad out your appControl to be the time delay you return - as if your appControl took 0ms to execute.
If you want your appControl to be executed every 100ms then 'return 100,000' microseconds.

This was done to try to hide the implications of interrupts etc from the newb who may think the main loop always takes the same amount of time.

Advanced users:- It also means I could graph the CPU utilization. If appControl returns 100,000 then my main loop knows how long your appControl actually took and how long to idle for. The 'time remaining' is dead time and just wasted (by me) in a delay. If your appControl took more than 100ms to run then my delay has nothing to do as the CPU is 'saturated'.
Webbot Home: http://webbot.org.uk/
WebbotLib online docs: http://webbot.org.uk/WebbotLibDocs
If your in the neighbourhood: http://www.hovinghamspa.co.uk

Offline madsci1016Topic starter

  • Contest Winner
  • Supreme Robot
  • ****
  • Posts: 1,450
  • Helpful? 43
    • Personal Website
Re: Webbotlib main loop time keeping issue
« Reply #4 on: March 15, 2010, 07:12:38 PM »
I don't know if you saw this line in my code:

time_left = 100000 - (clockGetus() - loopStart);
//cpu_load = ((time_left / (float)100000) * 100);

but uncommented, that should show CPU utilization correctly, right? Assuming the delay is set to 100ms. Is there a simplified way to do this and avoid floating point?

Seems like it(CPU load) would be a good built in function of the lib, and have a lib error if the load stays above 100, so the user knows he's got an issue keeping the frequency they expected.
« Last Edit: March 15, 2010, 07:28:54 PM by madsci1016 »

Offline Webbot

  • Expert Roboticist
  • Supreme Robot
  • *****
  • Posts: 2,165
  • Helpful? 111
    • Webbot stuff
Re: Webbotlib main loop time keeping issue
« Reply #5 on: March 15, 2010, 07:55:38 PM »
So you've got 2 numbers (commas added for legibility):
TICK_COUNT time_taken = clockGetus() - loopStart;
TICK_COUNT total_time = 100,000

So the precentage busy is:-
uint16_t utilisation_percentage = 100 * time_taken / total_time;

So your problem is whether this will exceed integer values and you dont wanna use floating point.
Well the answer doesn't have to be 'very exact' so if you are worried about numeric overflows then dont forget that if you divide 'tike_taken' by 2 and 'total_time' by 2 then you will get the same answer (ish).

So you could do:
while(time_taken > 0xffffUL){
  time_taken >>= 1;  // Div by 2
  total_time >>= 1; // div by 2
 }
// Now both numbers fit in a 16 bit unsigned so cast them:-
// uint16_t taken16 = time_taken; // no need to do this - see next step
uint16_t total16 = total_time;

Now our 100* expression may result in more than 16 bits on the top so lets leave time_taken as a 32bit number
So:
uint16_t utilisation_percentage = time_taken * 100 / total16;


NB Haven't tested that code - its just off the top of my head. But the key thing to avoid exceeding the variable limits is to divide the top and the bottom by 2. This gives the same integer answer.
Webbot Home: http://webbot.org.uk/
WebbotLib online docs: http://webbot.org.uk/WebbotLibDocs
If your in the neighbourhood: http://www.hovinghamspa.co.uk

Offline madsci1016Topic starter

  • Contest Winner
  • Supreme Robot
  • ****
  • Posts: 1,450
  • Helpful? 43
    • Personal Website
Re: Webbotlib main loop time keeping issue
« Reply #6 on: March 15, 2010, 09:01:14 PM »
Disclaimer, this only works for a delay of 100,000 uS.

Wouldn't just

cpu_load = (clockGetus() - loopStart) / 1000;

work for me since i am running at 10Hz, 100ms delay?

Offline Webbot

  • Expert Roboticist
  • Supreme Robot
  • *****
  • Posts: 2,165
  • Helpful? 111
    • Webbot stuff
Re: Webbotlib main loop time keeping issue
« Reply #7 on: March 16, 2010, 08:24:16 PM »
I was trying to get to a percentage busy - without knowing what loop time you want. Am sure either would work.
Webbot Home: http://webbot.org.uk/
WebbotLib online docs: http://webbot.org.uk/WebbotLibDocs
If your in the neighbourhood: http://www.hovinghamspa.co.uk

 


Get Your Ad Here