go away spammer

Author Topic: Axon2/Webbotlib - Timers...  (Read 2657 times)

0 Members and 1 Guest are viewing this topic.

Offline KurtEckTopic starter

  • Robot Overlord
  • ****
  • Posts: 217
  • Helpful? 12
Axon2/Webbotlib - Timers...
« on: January 30, 2010, 09:56:23 AM »
I am having fun with working on my Lynxmotion biped Brat with an Axon2.  I am using webbotlib as a starting point, but having fun now writing my own servo group move functionality.  That is I tell a group of servos to go from one point to another in a set amount of time and my functions take care of figuring out how fast to move each servo...  I had this code working OK as a function I called off of the main loop (called from appControl), but decided to move it to a timer.  Currently using Timer1_compareA.  

Currently I have it hard coded to I think interrupt every 50mS.

A couple of questions:
1) Once I figure out the ticks per mS in the init software should I assume that this will remain a constant or should I recompute this each time in the timer interrupt?  My current init function looks like:
Code: [Select]
void InitServoGroupMove(SERVO_LIST* servos, const TimerCompare* channel)
{

// Save away pointer to servos.
s_msd.servos = servos;
const Timer* timer = compareGetTimer(channel);
if(timerIs16bit(timer)){
uint32_t tmp32;

// Select a prescaler that is bigger than the biggest pause.
// Added 5ms just in case other interrupts kick in.
uint16_t prescale;

// If the timer is already in use then make sure it uses the same mode
if(timerIsInUse(timer)){
prescale = timerGetPrescaler(timer);
if(timerGetMode(timer) != TIMER_MODE_NORMAL){
setError(PWM_TIMER_IN_USE);
}
}else{
prescale = timerGetBestPrescaler(timer, USPERMSERVOLOOP + 5 );
}


// Find how many timer ticks there will be for USPERMSERVOLOOP
tmp32 = ticks_per_ms(USPERMSERVOLOOP,prescale);

s_msd.servo_cycle = tmp32;
// make sure it fits
if( (tmp32 & 0xFFFF0000UL)!=0){
setError(SERVO_TIMING);
}



// Set the threshold to start interrupt chain
if(getError()==0){
compareAttach(channel, &__servoGMService,  compareGetThreshold(channel) + s_msd.servo_cycle, 0);
}
// Do this last as it then turns on the timer
timerSetPrescaler(timer,prescale);

}else{
// We need a 16 bit bit timer
setError(SERVO_TIMER_MUST_BE_16_BIT);
}
}
Currently in my timer function, I have it reset the timer like:
Code: [Select]
static void __servoGMService(const TimerCompare *timer_compare, void* data)
{
uint16_t delay; // The next delay in cycles
delay = s_msd.servo_cycle;
// Re-fire the timer.
...
// BUGBUG:: should maybe do something depending on if we have something to do or not... IE don't need to interrupt every
// n mS if there are no active group moves...
compareSetThreshold(timer_compare,delay + compareGetThreshold(timer_compare));
}

This code makes the assumption that the timer pre-scaller will not change after the init is called.  Is this a valid assumption or should I recompute this each time in the interrupt?

2nd question: Currently my code does the interrupt every 50mS regardless if a group move is going on or not.  would it be better to detach the timer when there is nothing current to do and reattach when there is?   If so is it safe to do a CompareDetach from the interrupt handler itself?  I have not done this as my quick look through for example servos.c makes me believe that the timer handler for servos does not detach itself when there are no servos to be processed.  Suggestions?

Thanks
Kurt

P.S. - Sorry if these questions have been answered before.
« Last Edit: January 31, 2010, 12:25:30 PM by KurtEck »

Offline Webbot

  • Expert Roboticist
  • Supreme Robot
  • *****
  • Posts: 2,165
  • Helpful? 111
    • Webbot stuff
Re: Axon2/Webbotlib - Timers...
« Reply #1 on: January 30, 2010, 01:52:42 PM »
Hi Kurt,

Lots of things here.

1. The reason for all the tests as to whether a Timer is in use etc is to make sure that they only get setup once and that they have a valid value. So once set then they should never change

2. Since you've cut'n'paste some of my code (pilfering is always Good!) - then I would query your parameter to 'setError'. You are using an 'internal Webbot Error number' - these are all negative. Since this is your own code then you should use any +ve numner. This helps to differentitate between WebbotLib generated errors and your own error messages. (Then we know where the blame lies !!).

3. All of the messing around with Timers, prescalers, and compare/overflow interrupts is really there for people creating new device drivers. Although I've not mentioned it before it may get dropped in later releases!!! Why - well if  WebbotLib allows you to connect stuff to any timer at runtime then I have to create an ISR for every timer overflow, compare match, input capture interrupt for everything. The code generated by the compiler is Huge (even with optimisation). I could improve on this by fixing the used interrupts at compile time.

So number 3 sounds scary but - there is a better and generic way to solve your problem (and most of the common 'callback' requirements) and that is to use the scheduler.
The scheduler ain't good at handling small frequencies (anything less than 1ms say). So you wouldn't use it to generate a servo pulse for example - thats why we have drivers for these devices.
But in your case you are calling it every 50ms - which is well within the abililties of the scheduler. The other advantage is that interrupts are re-enabled when you scheduled routine is called - so UARTs/servos etc continue to work in the background.

So I suggest you do 2 things:
Step 1: put your code that is currently called under interrupts into a separate function.
Step 2: change your timer interrupt to call the code
Step 3: make sure it still works
Step 4: Use the scheduler instead and get it to call your 'separate function' and remove the timer code
ie have a generic function that can be called from timers or from the scheduler. This will make it easier to flick between the two.

Satisfy yourself that the scheduler does the job - I'm convinced that it will.

If you need help with the scheduler then look towards the bottom of timer.c to see how error messages are scheduled to flash the status led.

Any problems/questions - give me a shout.

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 KurtEckTopic starter

  • Robot Overlord
  • ****
  • Posts: 217
  • Helpful? 12
Re: Axon2/Webbotlib - Timers...
« Reply #2 on: January 30, 2010, 02:30:12 PM »
Thanks,

I was pretty sure from looking at the timer/servo sources that they were setup to be init once but I thought I would ask, and yes I I do like to cut and paste especially if I know the code works...

Yes I think the scheduler should work well enough for this.  If I were using software generated servo pulses, I would be tempted to merge this stuff with the actual servo timer code, but since all of mine are hardware PWM based it should work great.

Also should be easy to split off as it's own function as it was one before I merged into the current timer code...

Again thanks!
Kurt

P.S. - I hope you don't mind that I am experimenting around like this :).  I am enjoying getting back to the AVR and it is fun using your library.

Offline Webbot

  • Expert Roboticist
  • Supreme Robot
  • *****
  • Posts: 2,165
  • Helpful? 111
    • Webbot stuff
Re: Axon2/Webbotlib - Timers...
« Reply #3 on: January 30, 2010, 04:36:06 PM »
P.S. - I hope you don't mind that I am experimenting around like this :).  I am enjoying getting back to the AVR and it is fun using your library.

No problem - enjoy!
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 KurtEckTopic starter

  • Robot Overlord
  • ****
  • Posts: 217
  • Helpful? 12
Re: Axon2/Webbotlib - Timers...
« Reply #4 on: January 31, 2010, 09:26:01 AM »
Thanks, I have the code in place to use the scheduler and it looks like it is walking still. 

However I am not getting an error blinking on the LED... So I updated my code to check for an error code and print it at the USB port.  The code that starts up the group move does:
Code: [Select]
...
CRITICAL_SECTION_START;
// Update the list of which servos have group move data.  Do this under critical section to make sure it keeps consistent.
// remember the state of which servos were active before we or it in, such that we know if our main callback function is running or not.
uWhichServosActiveBefore = s_msd.uWhichServosActive;
s_msd.uWhichServosActive |= uNewTimedServos;
CRITICAL_SECTION_END;

if ((uWhichServosActiveBefore == 0) &&  s_msd.uWhichServosActive)
{
scheduleJob(&SGMCallback, 0, clockGetus(), ((TICK_COUNT)MSPERSGMCALLBACK)*1000); // Schedule up our group move - start at the next MS
#ifdef DEBUG
if (getError() != 0)
{
rprintfInit(USB_ACTIVATE);
rprintf("ESGM: %d %x %x\n", getError(), uWhichServosActiveBefore, uNewTimedServos);
setError(0);
}
#endif

}
Likewise the scheduler code does:
Code: [Select]
// If there is still group moves going on, we will rescheule ourself.
s_cSGMCallback++;
if (s_msd.uWhichServosActive)
{
scheduleJob(&SGMCallback, 0, lasttime, (TICK_COUNT)(MSPERSGMCALLBACK)*1000); // reschedule our self, rember to conver mS to uS.
#ifdef DEBUG
if (getError() != 0)
{
rprintfInit(USB_ACTIVATE);
rprintf("ESGMCB: %d %d\n", getError(), s_cSGMCallback);
setError(0);
}
#endif
}
The idea is that if a GroupMove is already active then if I call group move again it will not schedule it again... This can happen if I have the legs moving and then want to rotate the head...

I am getting error code -5 (#define TIMER_COMPARE_CALLBACK_EXISTS -5)... I am still debugging.

Kurt

Offline KurtEckTopic starter

  • Robot Overlord
  • ****
  • Posts: 217
  • Helpful? 12
Re: Axon2/Webbotlib - Timers...
« Reply #5 on: January 31, 2010, 10:07:38 AM »
A follow up from the last message:

Unless I am missreading the code, I think it is a recursion problem in scheduler.c.  It is hard to describe in text but I will try

1. - I call scheduleJob with my job and a delay of 20mS....
2. - after 20mS __scheduleUpdate is called which is attached to the timer.  It removes itself from the timer by calling compareDetach.
    3) __scheduleUpdate calls my function, which does some work and decides to reschedule itself
    4) Since my reschedule is > 1ms it adds to queue and calls __scheduleUpdate, which again calls
           compare Detach...
    5) This call of __scheduleUpdate completes and calls compareAttach, which is fine and exits.
    6) My function exits...
7) The timer interrupt initiated call to __scheduleUpdate now calls compareAttach, but we are already attached and the call errors out.

Kurt

Edit: I wonder if it can be simply fixed by changing schedulejob to not call  __scheduleUpdate if __running is set...
Code: [Select]
}else if (! __running ){
const TimerCompare* channel = timerGetCompare(g_heartbeat,CHANNEL_NUM);
__scheduleUpdate(channel, null);
}
I think it will only be in the running state if the call to schedulejob happened while processing a job...
« Last Edit: January 31, 2010, 10:40:08 AM by KurtEck »

Offline Webbot

  • Expert Roboticist
  • Supreme Robot
  • *****
  • Posts: 2,165
  • Helpful? 111
    • Webbot stuff
Re: Axon2/Webbotlib - Timers...
« Reply #6 on: January 31, 2010, 10:37:58 AM »
A follow up from the last message:

Unless I am missreading the code, I think it is a recursion problem in scheduler.c.  It is hard to describe in text but I will try

1. - I call scheduleJob with my job and a delay of 20mS....
2. - after 20mS __scheduleUpdate is called which is attached to the timer.  It removes itself from the timer by calling compareDetach.
    3) __scheduleUpdate calls my function, which does some work and decides to reschedule itself
    4) Since my reschedule is > 1ms it adds to queue and calls __scheduleUpdate, which again calls
           compare Detach...
    5) This call of __scheduleUpdate completes and calls compareAttach, which is fine and exits.
    6) My function exits...
7) The timer interrupt initiated call to __scheduleUpdate now calls compareAttach, but we are already attached and the call errors out.

Kurt

Look in 'scheduler.c' it should be revision 1.5 - if not then you've got an old version of the lib
That revision fixed a recursive issue.
Let me know

PS. I note your use of setError(0) - as you may have noticed this doesn't do anything. Once an error is set it cant be cleared. Otherwise if you got one error, cleared it, got another etc. Then the statusLED would not be able to blink for the correct number of timers for the error msg.

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 KurtEckTopic starter

  • Robot Overlord
  • ****
  • Posts: 217
  • Helpful? 12
Re: Axon2/Webbotlib - Timers...
« Reply #7 on: January 31, 2010, 10:47:19 AM »
Thanks I have version 1.4...

I remember from the description that it said once it error was set it would continue to display that error.  But I was hoping that it would at least clear out the error for the next call to getError so I would remove extras outputs to the USB port if it was a one time thing....

Looked at the beta version of webbotlib and yep I see that it had the change that guessed at in the previous reply (A later edit)

Kurt

Offline Webbot

  • Expert Roboticist
  • Supreme Robot
  • *****
  • Posts: 2,165
  • Helpful? 111
    • Webbot stuff
Re: Axon2/Webbotlib - Timers...
« Reply #8 on: January 31, 2010, 11:03:36 AM »
If you get the latest release from sourceforge (Version 1.13) then it is fixed in there as well. You don't have to go to the pre release of Version 1.14 for those testing Project Designer
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 KurtEckTopic starter

  • Robot Overlord
  • ****
  • Posts: 217
  • Helpful? 12
Re: Axon2/Webbotlib - Timers...
« Reply #9 on: January 31, 2010, 11:37:20 AM »
Thanks, that fixed it!

Kurt

 


Get Your Ad Here

data_list