PDA

View Full Version : Servo Jumpy with DT Interrupt



Dick Ivers
- 29th November 2010, 01:04
I'm running a servo with a PBP routine which use the pulseout funtion to generate the required servo pulse width, followed by a pause to fill out the normal 20 ms servo time frame. A loop keeps the servo running continuously. I keep track of time by counting the number of 50 hz frames. The servo is quiet and moves smoothly in response to changes in pulse width.

In an effort to increase the accuracy of timekeeping, I recently added an Elapsed Timer using DT interrupts. It's a 100 hz timer set up to accumulate seconds and tenths of seconds. It works well. However, the servo is now twitching while the the interrupt routine is running. Why is this? Does PBP use the same Timer1 that the interrupt counter is using? Is there a possible interaction that accounts for the servo's jumpiness? Is there a fix?

BTW, pic is 16F690.

Jerson
- 29th November 2010, 01:10
The reason for the twitching is simply the way interrupts work. When an int occurs, it 'bites' away time from the main code which is executing. In your case, this main code happens to be doing the pulsout function. The int could be disturbing this by an amount equal to the executing time of the interrupt routine.

The way around it - have a variable that tells the int how much pulsewidth you need to be sent to the servo. then in the int, which is always running, you send this pulsewidth to the servo. This way you will avoid the pulsout. Now, there will be no twitching

Hope this helps

Archangel
- 29th November 2010, 03:00
I'm running a servo with a PBP routine which use the pulseout funtion to generate the required servo pulse width, followed by a pause to fill out the normal 20 ms servo time frame. A loop keeps the servo running continuously. I keep track of time by counting the number of 50 hz frames. The servo is quiet and moves smoothly in response to changes in pulse width.

In an effort to increase the accuracy of timekeeping, I recently added an Elapsed Timer using DT interrupts. It's a 100 hz timer set up to accumulate seconds and tenths of seconds. It works well. However, the servo is now twitching while the the interrupt routine is running. Why is this? Does PBP use the same Timer1 that the interrupt counter is using? Is there a possible interaction that accounts for the servo's jumpiness? Is there a fix?

BTW, pic is 16F690.
Hi Dick,
_With no disrespect to Jerson, as what he said is likely 100 percent right . . .
and keeping in mind, I who am NO expert, have not played with a servo in a very long time . . .

I seem to remember the servos jerking, each time the loop ran using software PWM or pulseout, as I remember it ran fine using HPWM.

Jerson
- 29th November 2010, 04:47
Hi Joe

Your observation seems to confirm what I'm saying. All software timed processes like Serout or Pulsout are affected by interrupts biting into their timing. I have had this experience before with regards to Serin and Serout. HPWM is a hardware timed process as is HSERIN or HSEROUT which work with devices that have the relevant hardware built in. Unfortunately, there is no HPULSIN or HPULSOUT in PbP.

I haven't used servos at all ;)

Acetronics2
- 29th November 2010, 12:51
Hi, Dick



In an effort to increase the accuracy of timekeeping


Could you just explain what you want to do ???

if you want your servo to work properly ...

OR you disable interrupts while the PULSOUT Command ...

OR you place the PULSOUT Command into the interrupt stubb ...

BUT you must not interrupt the Pulsout command.

So, I do not think you can reach your goal, if you keep a RTC timer interrupt period that is lower than the PULSOUT max duration ... :rolleyes:

Now ... I do not see any other way using pure PBP and Elapsed Timer with a 16F690 :o ... as it needs Timer 1.

Alain

Mike, K8LH
- 1st December 2010, 02:11
Have you considered using the PWM module? Many people don't realize you can run the PWM module at very low frequencies by using a software "helper" ISR (interrupt service routine) to link together several much smaller/faster PWM period "frames" to form a much longer/slower overall period.

This method provides many of the advantages of the PWM module (zero jitter, interrupt tolerant, very high resolution pulse width, etc.) at the cost of using a small low overhead ISR software "helper". You can also use the 1-msec interrupt interval as a basis for timer operations.

Perhaps one of the PBP gurus can convert, test, and qualify this code for you?

Happy Holidays!

Mike, K8LH



// setup a 1000 usec PWM period with PR2 = 249 and prescaler
// 16:1 (16 MHz clock) or 4:1 (4 MHz clock) and then link 20
// of these 1000 usec PWM "frames" together to form the much
// longer 20-ms servo period (1-usec pulse width resolution)

int servo = 1500; // 0..20000 in 1 usec steps
int frame = 1; // frame number 1..20

void interrupt() //
{ int width; // work variable
pir1.TMR2IF = 0; // clear Timer 2 interrupt flag
frame--; //
if (frame == 0) // if end of the 20 msec period
{ frame = 20; // reset for new 20 msec period
width = servo; // reset 'width' work variable
}
if ((width > 1000) // if width > 1000 usecs
{ ccpr1l = 250; // do a 100% duty cycle frame
ccp1con.CCP1Y = 0; //
ccp1con.CCP1X = 0; //
width -= 1000; // subtract 1000 usecs
}
else // else do a 0..1000 usec frame
{ ccpr1l = (width >> 2); // 0..250 (0..1000 usecs)
ccp1con.CCP1Y = (width & 1);
ccp1con.CCP1X = (width & 2);
width = 0; // force remaining frames to 0%
}
}

ScaleRobotics
- 1st December 2010, 15:18
That is interesting Mike. I had not seen that before. (ccp1x, ccp1y, and the register for ccpr1l are different on the 16f690, so some tinkering required).

You could also use Darrel's 18F servo code: http://www.picbasic.co.uk/forum/content.php?r=253-2-CH-Hardware-Servo-Driver

If you are not tied to hardware, you could do it (almost) exclusively in hardware with a 18f2431 or a 18f4431 chip. These allow PWM down to 19 hertz on their power control pwm port pins. They have a "single shot mode" which gives the servo a single shot pulse. An interrupt would run at 20 ms to tell the single shot pulse widths when to fire. See the bottom of this wiki for more info: http://www.picbasic.co.uk/forum/content.php?r=203-PWM-Servo-PWM-encode-decode

Dick Ivers
- 1st December 2010, 16:48
Guys,

Thanks for the suggestions. I'll follow your tips and see where they lead. It the meantime, here is a sample of the code that causes the servo to twitch.

I've observed that the jumps occur about 2 times per second, and are in a direction that a longer pulse width would cause. This supports Jerson's idea that the interrupt service is periodically adding to the pulse width. Maybe it would help if the ISR were written is assembly and therefore be faster?



'************************************************* ***************
'* Name : servo_demo.pbp *
'* Author : Dick Ivers *
'* Date : Nov 30, 2010 *
'* Notes : This is a simplistic demo of servo w/Elapsed Timer *
'************************************************* ***************
'435 program words
'device is PIC 16F690
'************************************************* ***************
'set device configuration
@ __config _HS_OSC & _WDT_ON & _MCLRE_ON & _CP_OFF

'set registers
CM1CON0.7 = 0 'comparator1 off
CM2CON0.7 = 0 'comparator2 off
ANSEL = 0 'porta pins all digital
ANSELH = 0 'all porta pins digital

DEFINE OSC 16 '16 Mhz oscillator

'declare variables
led var portc.5 'led output on portc.5
servopos var word
runtime var word 'motor runtime in tenths of seconds

start:
low led 'flash red LED for 0.5 sec to show circuit is functioning
pause 500
high led 'turn off led


INCLUDE "DT_INTS-14.bas" 'Base interrupt system
INCLUDE "ReEnterPBP.bas" 'Using PBP interrupts
INCLUDE "Elapsed_INT_RI2.bas" 'Elasped timer counting seconds and tenths seconds

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _ClockCount, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts

runtime = 100 ' run servo for 10.0 seconds
servopos = 600 ' hold at mid servo range (4*150)
gosub ResetTime ' Reset Time to 0d-00:00:00.00
gosub StartTimer ' Start the Elapsed Timer
low Led 'turn on led
low portc.4 'turn on servo
main:
pulsout portc.0,servopos
pause 18
if time => runtime then 'stop servo when target time is reached
high led 'turn off led
goto hold
endif
goto main 'loop until endtime is reached

hold:
@ INT_DISABLE TMR1_INT ; Disable Timer 1 Interrupts
high portc.4 'turn off servo
end

Mike, K8LH
- 2nd December 2010, 13:55
That is interesting Mike. I had not seen that before. (ccp1x, ccp1y, and the register for ccpr1l are different on the 16f690, so some tinkering required).
Yes, you would need to change bit labels to match the device you're using. Sorry!


You could also use Darrel's 18F servo code: http://www.picbasic.co.uk/forum/content.php?r=253-2-CH-Hardware-Servo-Driver
I didn't care for that method (it's not entirely interrupt tolerant) but it probably would work fine for the OP. The odd interrupt interval timing (26.2144-msecs) would make it difficult to use for for general purpose interval timers.


If you are not tied to hardware, you could do it (almost) exclusively in hardware with a 18f2431 or a 18f4431 chip. These allow PWM down to 19 hertz on their power control pwm port pins. They have a "single shot mode" which gives the servo a single shot pulse. An interrupt would run at 20 ms to tell the single shot pulse widths when to fire. See the bottom of this wiki for more info: http://www.picbasic.co.uk/forum/content.php?r=203-PWM-Servo-PWM-encode-decode

That's an excellent example. Thank you.

If anyone is interested, here's the link to another example of the PWM "frame" method for 8 or 16 "zero jitter" Servos with 250-nsec pulse width resolution (4000 steps between 1.0-2.0 msecs); 8 or 16 Servos using the PWM module (http://www.electro-tech-online.com/microcontrollers/29837-8-16-servos-using-pwm-module.html)

Happy Holidays everyone!

Cheerful regards, Mike

Dick Ivers
- 9th December 2010, 13:53
This message is just to close out this discussion in case someone is searching in the future.

I was not able to implement any of the proposed ideas using the CCP module. The project hardware is stuck with the 16F690. The CCP1 and CCP2 pins are already committed to other functions. The proposed ideas sound good, so I'll try them in the future upon redesign.

I measured the interrupt service routine of the present elapsed timer using the stopwatch function in MPASM. With a 16 mhz osc the ISR is only 2.5 usec. I don't think this is enough to account for the servo jitter, so the jitter must be coming from somewhere else.

I've ditched the elapsed timer and gone to servo frame cycle counting to keep track of time. That's working okay.