Author Topic: Help -- Timers with WebbotLib  (Read 3464 times)

0 Members and 1 Guest are viewing this topic.

Offline madsci1016Topic starter

  • Contest Winner
  • Supreme Robot
  • ****
  • Posts: 1,450
  • Helpful? 43
    • Personal Website
Help -- Timers with WebbotLib
« on: January 18, 2010, 01:43:01 AM »
I don't think this is a webbot lib thing, so i'm not posting it in the bugs thread.

I want to use a timer as the basis for my PID heading controller. I am trying to set it up like this:

Code: [Select]
unsigned int  result=((65537.0-(62500/10))+0.5); //the 0.5 is for rounding;
 

  TCCR3A = 0;
  TCCR3B = 1<<CS32 | 0<<CS31 | 0<<CS30; //256 prescale
 
  //Timer3 Overflow Interrupt Enable   
  TIMSK3 = 1<<TOIE3;

  //load the timer for its first cycle
  TCNT3=result;

If i put this in any of the webbot functions (appint_hardware or software) i get complier errors saying the registers (like TCCR3A and the rest) are not defined as a variable. If i put it outside the webbot functions, i get (for all the registers)

../SAGAR.c:108: warning: type defaults to 'int' in declaration of 'TIMSK3'
../SAGAR.c:111: warning: data definition has no type or storage class

and a error of TCNT3:


../SAGAR.c:111: warning: type defaults to 'int' in declaration of 'TCNT3'
../SAGAR.c:111: error: initializer element is not constant

I have done this in the arduino IDE no problem. How do i setup timers in Winavr with Webbot library?

Offline Admin

  • Administrator
  • Supreme Robot
  • *****
  • Posts: 11,703
  • Helpful? 173
    • Society of Robots
Re: Help -- Timers with WebbotLib
« Reply #1 on: January 18, 2010, 02:46:04 AM »
For WebbotLib, you shouldn't even touch registers, timers, and scaling and such. WebbotLib is all high level programming.

In fact, the WebbotLib timer system is a major reason I like it so much . . .

In the manual, look up the timer. It'll explain exactly how to do it.

modified from page 97 v1.13 from WebbotLib manual:

Code: [Select]
TICK_COUNT time_start = clockGetus();
stuff_happens();//your code here, probably doing other non-PID stuff
TICK_COUNT time_end = clockGetus();
TICK_COUNT time_passed=time_end-time_start;

PID_system(time_passed);//your code, feed time passed into your PID equation

Offline madsci1016Topic starter

  • Contest Winner
  • Supreme Robot
  • ****
  • Posts: 1,450
  • Helpful? 43
    • Personal Website
Re: Help -- Timers with WebbotLib
« Reply #2 on: January 18, 2010, 09:16:46 AM »
Hmm, I'll consider that. I'm not used to having a control system that has no set frequency.

Still though, why would Win AVR complain about the registers so much?

Hmm, i seem to have most most of what i need:

timerSetMode(1, TIMER_MODE_NORMAL);
timerSetPrescaler(1, 256);
timerOverflowAttach(3, controller, NULL);

whats left is a way to set the counter. There is a timerGetCounter() but i don't see a timerSetCounter()
« Last Edit: January 18, 2010, 10:23:04 AM by madsci1016 »

Offline madsci1016Topic starter

  • Contest Winner
  • Supreme Robot
  • ****
  • Posts: 1,450
  • Helpful? 43
    • Personal Website
Re: Help -- Timers with WebbotLib
« Reply #3 on: January 18, 2010, 10:39:17 AM »
The other thing i don't like about your method, Admin, as I hope in the future to implement some processor intensive stuff, like mapping and feature based navigation, and as my code get more intensive, the slower my heading controller will be going. I'd rather have an interrupt so the dynamics of my heading control stay constant throughout my tinkering of other stuff.

I am looking through his uartsw.c to see how he used a timer in compare mode to time sampling the rx pin. I have only used overflow method before, i have no idea how to use compare to generate a timed sequence.
« Last Edit: January 18, 2010, 11:44:05 AM by madsci1016 »

Offline rgcustodio

  • Robot Overlord
  • ****
  • Posts: 217
  • Helpful? 0
  • Use "Search" and ye might find answers!
Re: Help -- Timers with WebbotLib
« Reply #4 on: January 18, 2010, 04:57:19 PM »
Are you sure you're defining the correct processor type?

As we all know (or should know by now), not all of the AVR are created equal. Some don't have the 3rd timer. The compiler deals with this clout by magic.. Well actually no, it uses a series of defines so that it can load the correct header files.

i.e.
AVR640 __AVR_ATmega640__
AVR168 __AVR_ATmega168__
AVR168P __AVR_ATmega168P__
etc

This all happens behind the scenes.

Users who use a GUI usually don't need to define this because it is automagically generated by the tool. The tool also usually puts it in the Makefile.

Users who really know what they're doing define this manually in the Makefile or in one of the headers.

<I know I've answered this types of questions before, but without the magic thingie>

Quote
If i put this in any of the webbot functions (appint_hardware or software) i get complier errors saying the registers (like TCCR3A and the rest) are not defined as a variable. If i put it outside the webbot functions, i get (for all the registers)

../SAGAR.c:108: warning: type defaults to 'int' in declaration of 'TIMSK3'
../SAGAR.c:111: warning: data definition has no type or storage class

and a error of TCNT3:


../SAGAR.c:111: warning: type defaults to 'int' in declaration of 'TCNT3'
../SAGAR.c:111: error: initializer element is not constant

The best thing one can do when it's raining is to let it rain. - H. W. Longfellow

understanding is the path to enlightenment

Offline madsci1016Topic starter

  • Contest Winner
  • Supreme Robot
  • ****
  • Posts: 1,450
  • Helpful? 43
    • Personal Website
Re: Help -- Timers with WebbotLib
« Reply #5 on: January 18, 2010, 06:09:39 PM »
I don't have a makefile (or at least not one I made). Win AVR sets up the makefile, and yes, i set my processor correctly in the project settings. 

Offline Webbot

  • Expert Roboticist
  • Supreme Robot
  • *****
  • Posts: 2,165
  • Helpful? 111
    • Webbot stuff
Re: Help -- Timers with WebbotLib
« Reply #6 on: January 18, 2010, 07:45:22 PM »
Since my library sets up certain timers for the hardware you use - then I actually #undefine a lot of the hardware registers.
This is done on purpose.
For example the system clock is dynamically allocated out of whatever timer resources are left unused - so the user doesn't even know that its happening.

So the last thing I need is someone changing timer prescalers, modes etc by themselves as this can mess up the whole library.

As you have seen there are timer functions available for you to use that make sure you dont mess up the rest of the timer code.

And my lib DOES have a set frequency. Use the clockGetus() function and you will always get a time in microseconds regardless of the processor and clock frequency. This time is the time since power up and you can ALWAYS subtract one reading from another to get a duration. So in the example that Admin posted earlier then the 'time_passed' variable will always be in microseconds.
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 Webbot

  • Expert Roboticist
  • Supreme Robot
  • *****
  • Posts: 2,165
  • Helpful? 111
    • Webbot stuff
Re: Help -- Timers with WebbotLib
« Reply #7 on: January 18, 2010, 07:51:56 PM »
Sorry for double post - but its a kinda TIP

Create a global variable
TICK_COUNT now;

In your appInitSoftware you are passed a TICK_COUNT which is the current time of day so in this routine do:
now = the parameter

In your main control loop you are also passed a TICK_COUNT for the latest time of day so you can write:
TICK_COUNT elapsed = the parameter - now;
now = the parameter;

And your 'elapsed' variable will be the number of microseconds since the control loop was last called.

« Last Edit: January 18, 2010, 07:53:20 PM by Webbot »
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: Help -- Timers with WebbotLib
« Reply #8 on: January 18, 2010, 08:36:47 PM »
I finally got a system working, i just have a 16 bit timer with a \8 prescaller and no load value (since i couldn't figure out how) give me roughly around 30Hz.

I used this to do it:
Code: [Select]
timerSetMode(TIMER3, TIMER_MODE_NORMAL);
timerSetPrescaler(TIMER3, 8);// 8
timerOverflowAttach(TIMER3, heading_controller, NULL);

This won't mess with the lib functions, right?

Anyway, I see how you (webbot) and admin are recommending to do it. Instead of having a set change in time dt by using an interrupt, you simple measure the time passed since the last loop round the appControl() function and plug that in as dt in the control equation.

However, the problem i see with this is as i add more and more stuff for the MCU to do in the appControl() function, the slower the actual control loop frequency. Even though the PID equations are still correct since dt is measured, the dynamics of the physical system changes. What were good controller gains at 100Hz will be horrible at 10Hz, and by robot goes from good closed loop heading control to overshooting and oscillating.

If i use an interrupt however, the control loop maintains a constant 30Hz no matter how complicated (to a degree) my main code gets.

Offline Admin

  • Administrator
  • Supreme Robot
  • *****
  • Posts: 11,703
  • Helpful? 173
    • Society of Robots
Re: Help -- Timers with WebbotLib
« Reply #9 on: January 18, 2010, 10:31:25 PM »
Hmmm I think we misunderstood what you wanted . . .

So you want your PID equation to have a fixed dt, right? And to do this, you want your main code to always stop at that fixed time using an interrupt to run PID, right?

Webbot, does WebbotLib have a timer interrupt that the user can call? For example, something like:

timer_interrupt(time_passed,function_to_call);

If not, it *definitely* needs to be added! Or is the scheduler.h on page 81 of v1.13 what he needs?

Offline Webbot

  • Expert Roboticist
  • Supreme Robot
  • *****
  • Posts: 2,165
  • Helpful? 111
    • Webbot stuff
Re: Help -- Timers with WebbotLib
« Reply #10 on: January 19, 2010, 03:19:06 PM »
@madsci1016
The timer code you've done will work. But you will get a runtime error (flashing LED) if TIMER3 suddenly gets used by something else. Its also not very portable as it means the board must have a TIMER3 and if you swap to a different clock speed then the frequency will go mad. Equally if you move between 8 and 16 bit timers then the timing will also go mad.

So how do you make it more portable? ...

@Admin (and madsci1016)
You got it!! The scheduler.....

The scheduler is a 'one-shot' timer that triggers something to happen at a later date. So if you need it to repeat then your scheduler service routine should re-queue the job to run again.

I use this to flash the error/status LED.

It has a granularity of around 18ms but there is stuff in there to tell you about any undershoot or overshoot on the timing. ie if you wanted something to happen every 5 seconds and, lets pretend the first trigger happened after 5.5 seconds, then you know it has overshot by 0.5 seconds. Its then up to you to queue up the next trigger to happen in either 5 seconds time or in 4.5 seconds time (to get you back on a 5 second cycle) depending on your needs.

The scheduler purposely doesn't handle 'very frequent' events - otherwise its easy to kill the main foreground task. So if you ask it to do something in a few microseconds time then it just does a 'delay' and calls it immediately.

'Scheduled' events run with interrupts re-enabled so that hardware interrupts such as UART transmission continue to happen - but should still be as quick as possible.

So lets say you want something to happen every second (ie 1000000 microseconds):-

In your main code ask for the first event:-

scheduleJob(&myCode, null, clockGetus(), 0);

The last parameter in this case '0' is the delay before 'myCode' first gets called.
The second parameter can also be a pointer to a data structure that you want to get passed to 'myCode'

Now create the handler
void myCode(void * data, TICK_COUNT lastTime, TICK_COUNT overflow){
   ... do what you need ...
   ... re-queue the event if you want it to happen again ...as follows
   TICK_COUNT delay;
   ... set 'delay' to the number of microseconds to wait, starting from 'lastTime' before calling me again
   scheduleJob(&myCode, data, lastTime, delay);

}

See that 'overflow' parameter well that shows you the under/over run. So you can always subtract that from your ideal 'delay' if you want to keep on a given time line.

Because we are dealing with interrupts here - then any variables changed by 'myCode' should be marked as 'volatile'. Equally any variables that are bigger than 8 bits wide which are read by the foreground task should be wrapped in a CRITICAL_SECTION_START/END so that 'myCode' doesn't change them whilst they are being written. Equally if you have a complex type (eg x,y,z) and you want the foreground task to read these atomically then wrap the entire read of x,y,z with CRITICAL_SECTION_START/END otherwise 'myCode' may suddenly change one of them whilst the foreground is trying to read them all.

NB This is not a WebbotLib thing - its just good programming practice to avoid issues with interrupts.

Hope that helps



« Last Edit: January 19, 2010, 03:26:29 PM by Webbot »
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: Help -- Timers with WebbotLib
« Reply #11 on: January 19, 2010, 05:45:29 PM »
The biggest issue i have with your scheduler is this:

Quote
It has a granularity of around 18ms


If it want a control system is software to run at 35Hz, (every 28ms), an error of 18ms is 65% possible error. Even though i can correct change in time by the 'overflow', it would throw off my controller gains. I would have to spend ALOT of time trying to model equations for the gains of my controller over different frequencies, do a best fit, then run calculations ever time with the overflow value. I don't have access to the equipment needed to properly model the dynamics of my control system, so the only way i can do it is by experimentation, and that takes me days, just at one frequency.

For a fast control system, i don't think the scheduler would work well. The only real solution(I know of) is to keep the frequency as accurate as possible is a hardware timer interrupt.

If portability is what you main goal is, could you not write a function like

attachTimerInterrupt(int frequency, &function);

that would see what timers were unused, find one with a (either 8 or 16 bit) divider that would give the correct frequency and attach the function either by compare interrupt, or overflow with a re-seed after the function executes?


Offline Webbot

  • Expert Roboticist
  • Supreme Robot
  • *****
  • Posts: 2,165
  • Helpful? 111
    • Webbot stuff
Re: Help -- Timers with WebbotLib
« Reply #12 on: January 19, 2010, 08:00:03 PM »
Ok a few things here

If portability is what you main goal is, could you not write a function like

attachTimerInterrupt(int frequency, &function);

that would see what timers were unused, find one with a (either 8 or 16 bit) divider that would give the correct frequency and attach the function either by compare interrupt, or overflow with a re-seed after the function executes?


That of course assumes that there IS an available timer - and even on the Axon series its easy enough to run out if you've got lots of hardware PWM etc going on.
But lets assume there is one. Lets also assume you also call 'attachTimerInterrupt' several times to queue up different things. More timers?
Before you know it:- you need a scheduler preferably working from the one timer !
So what you are asking for is a scheduler.

Quote
The biggest issue i have with your scheduler is this:
Quote
It has a granularity of around 18ms

I'm giving you a worst case scenario here (always best to be pessimistic!). And here's the techno garb:-
Lets assume several jobs are already queued up and you add another. The scheduler adds your job and then calcs the next 'compare match interrupt' for the 'soonest' event. But since the compare match on the ATMegas works only on an 'exact match' then it could be that by the time you set it then it gets missed. I can't reseed the counter back to zero as you would then get lots of cumulative errors on all queued jobs. So the 18ms is the pessimistic view of how long it then takes to cycle back around to that number (18ms will vary depending on cpu clock speed).  There's no way to avoid this without adding a heck of a lot of processing overhead - which, since the scheduler is called under interrupts, would be bad.

My suggestion is that you should just try it. Its easy enough to set up a scheduled event called every 30ms and the let the foreground event 'rprintf' how long it took to be called say 100 times.

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: Help -- Timers with WebbotLib
« Reply #13 on: January 19, 2010, 09:55:13 PM »
I'm trying to setup an accuracy test, but can't get it to work.

I use

scheduleJob(&myCallback, NULL, clockGetus(),1000);

both in appInitSoftware and at the end of the Callback function. It gets a call at least once, as i have a rprintf right before the scheduleJob at the end of myCallBack function ; and it prints out the test message once, so that also tells me it's not getting stuck in my code either. I am not hijacking any timers. Any idea  what i should look for to get that working?

Also, in your sample code in the pdf for scheduler, you have

scheduleJob(&myCallback, someData, timerGetus(),1000);

but for what i can tell, there is not timerGetus() function, so did you mean clockGetus()?????

And you're still not really selling me on the scheduler thing. I don't want my controller to drift past +- 10% of the intended frequency (+-3ms of the period) in order to keep it a stable control system. I can setup a test now, but I would have to repeat the test every time i added a new layer of complexity to the foreground process, to make sure it does cause the scheduler to 'drift' into the worse case.

Can you, with a very high degree of certainty, tell me that the scheduler can stay within that limit, even as my foreground code grows to include complex stuff like sensor based mapping, and even other jobs getting pushed on the scheduler? If not, then it's just not suited for what I want, and I rather stick to a timer interrupt (which guarantees accuracy now and in the future), and just deal with having my code not 100% portable.

Offline Webbot

  • Expert Roboticist
  • Supreme Robot
  • *****
  • Posts: 2,165
  • Helpful? 111
    • Webbot stuff
Re: Help -- Timers with WebbotLib
« Reply #14 on: January 20, 2010, 05:23:43 PM »
It gets a call at least once, as i have a rprintf right before the scheduleJob at the end of myCallBack function ; and it prints out the test message once, so that also tells me it's not getting stuck in my code either. I am not hijacking any timers. Any idea  what i should look for to get that working?
Are you using the latest release? There was something freaky going on elsewhere that was upsetting the scheduler on earlier versions?

Quote
Also, in your sample code in the pdf for scheduler, you have

scheduleJob(&myCallback, someData, timerGetus(),1000);

but for what i can tell, there is not timerGetus() function, so did you mean clockGetus()?????

Thanks - I'll fix the docs.

Quote
And you're still not really selling me on the scheduler thing. I don't want my controller to drift past +- 10% of the intended frequency (+-3ms of the period) in order to keep it a stable control system. I can setup a test now, but I would have to repeat the test every time i added a new layer of complexity to the foreground process, to make sure it does cause the scheduler to 'drift' into the worse case.

Can you, with a very high degree of certainty, tell me that the scheduler can stay within that limit, even as my foreground code grows to include complex stuff like sensor based mapping, and even other jobs getting pushed on the scheduler? If not, then it's just not suited for what I want, and I rather stick to a timer interrupt (which guarantees accuracy now and in the future), and just deal with having my code not 100% portable.
The scheduler uses hardware interrupts - its as good as you can make it. Of course: you will always need to re-test after changes and when adding new callbacks to the scheduler. If your program is interrupt intensive: eg software PWM, software uarts, lots of frequent scheduler tasks then you have the usual problem that AVRs have no interrupt priority mechanism. I also cant vouch for your interrupt routines:- eg if they are calling a PID with lots of floating point maths that takes a long time to process. But at that point your custom written interrupts would all fall apart as well.
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: Help -- Timers with WebbotLib
« Reply #15 on: January 21, 2010, 04:52:36 PM »
I am traveling for work, I will check when i get back.

And FYI,

I love your library, I'm not trying to be negative towards it at all. I just know hardware (I'm an EE), and hardware timers, and i feel more comfortable with what i know.
« Last Edit: January 21, 2010, 04:54:55 PM by madsci1016 »

 


Get Your Ad Here

data_list