PDA

View Full Version : Stuttering Servo



Dick Ivers
- 26th March 2010, 18:39
I am testing a DT Instant interrupt routine which is supposed to set the length of time that two servos are on or off. Everything works OK except the servos runs very rough. The average position of the servos is correct, but the twitching movement is excessive, making it unuseable. The timing is based on the Elapsed Timer1 Program, from routines found on this Forum. For comparison purposes I have another routine that does not use interrupts, but relies on cycle counting. With this program the servos are smooth and quiet. The cycle counting demo follows here:


'device is PIC 16F684

'set registers
OPTION_REG.7 = 0 'enable porta pullups
CMCON0 = 7 'comparators off
ANSEL = 0 'porta pins all digital
TRISA = %111111 'set porta pins as input
TRISC = %001101 'set portc pins 0,2,3 as input, all others output
OSCCON = %1110000 'set internal osc. at 8 mhz, wait for stable freq.
OSCTUNE = 0 'internal osc. running at factory calibration

DEFINE OSC 8 '8 Mhz oscillator

while OSCCON.2 = 0 'wait for osc.to be stable
wend

'declare variables
i var word 'couting variable
led var portc.3 'led output on portc.3
dummy var byte 'variable needed to end porta mismatch
throttlepos var word 'servo1 pulse width in .01 seconds
servopos var word 'servo2 pulse width
pulsecnt var byte
start:
low led 'flash red LED for 0.5 sec to show circuit is functioning
pause 500
high led

pause 2000 'delay timer start 2 seconds

portc.1 = 0 'turn off servo
portc.4 = 0 'initialize servo pulse low
portc.5 = 0 'initialize throttle pulse low
throttlepos = 400 '2*(200) pulse width adjusted for 8 mhz osc
servopos = 400 '2*(200) pulse width adjusted for 8 mhz osc

low Led 'turn on led
portc.1 = 1 'turn on servos
for i = 1 to 500 'run servo for 10 seconds (500 cycles)
pulsout portc.5,throttlepos
pulsout portc.4,servopos
pause 16
next

high Led 'turn off led
throttlepos = 200 '2*(100) pulse width adjusted for 8 mhz osc
servopos = 400 '2*(200) pulse width adjusted for 8 mhz osc

for i = 1 to 75 'run servos for 1.5 seconds (75 cycles}
pulsout portc.5,throttlepos
pulsout portc.4,servopos
pause 16
next

low Led ' turn on led

for i = 1 to 750 'run servos for 15 seconds 750 cycles)
pulsout portc.5,throttlepos
pulsout portc.4,servopos
pauseus 16100
next

high led 'turn off led

DT: high portc.3 'turn off led
servopos = 200 'DT release position 2*(100)
pulsecnt = 75 'hold for 1.5 second
gosub pulse 'this section uses a subroutine to run the servo
servopos = 400 'home position
pulsecnt = 50 'hold for 1 second
gosub pulse 'return to home position
goto halt

'subroutine pulse runs the servo
pulse: portc.4 = 0 'initialize servo pulse low
for i = 1 to pulsecnt
pulsout portc.4,servopos
pause 18
next
return
halt:
portc.1 = 0 'turn off servo
end


The demo interrupt program is follows here. Two interrupts are used in this case, but it makes no difference; the servos runs rough even when the interrupt on change is taken out. The twitching is still there even if only one servo is used. Any ideas on why the rough running?


'device is PIC 16F684

'set registers
OPTION_REG.7 = 0 'enable porta pullups
CMCON0 = 7 'comparators off
ANSEL = 0 'porta pins all digital
TRISA = %111111 'set porta pins as input
TRISC = %001101 'set portc pins 0,2,3 as input, all others output
OSCCON = %1110000 'set internal osc. at 8 mhz, wait for stable freq.
OSCTUNE = 0 'internal osc. running at factory calibration

DEFINE OSC 8 '8 Mhz oscillator

while OSCCON.2 = 0 'wait for osc.to be stable
wend

'declare variables
i var byte
led var portc.3 'led output on portc.3
MTtime var word 'target motor runtime in tenths of seconds
BKtime var word 'target brake time in tenths of seconds
DTtime var word 'target DT time in tenths of seconds
dummy var byte 'variable needed to end porta mismatch
throttlepos var word
servopos var word
pulsecnt var byte
start:
low led 'flash red LED for 0.5 sec to show circuit is functioning
pause 500
high led

pause 2000 'delay timer start 2 seconds

INCLUDE "DT_INTS-14 for F684.bas" 'Base interrupt with wsave selected for 16F684
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 RAC_INT, _RDT, PBP, yes
INT_Handler TMR1_INT, _ClockCount, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

goto overint

'-------Interrupt Handler for RDT------------
RDT:
high led 'turn led off
dummy = porta 'needed to end mismatch for porta
IOCA.4 = 0 'disable porta.4 interrupt
@ INT_RETURN
'--------------------------------------------

overint:

portc.1 = 0 'turn off servo
portc.4 = 0 'initialize servo pulse low
portc.5 = 0 'initialize throttle pulse low
throttlepos = 400 '2*(200)
servopos = 400 '2*(200)
dummy = porta ' initialize dummy variable
IOCA.4 = 1 ' enable porta pin 4 for interrupt on change
MTtime = 100 ' 10.0 second motor run time
BKtime = 15 ' 1.5 second brake time
DTtime = 150 ' 15 second glide time
gosub ResetTime ' Reset Time to 0d-00:00:00.00
gosub StartTimer ' Start the Elapsed Timer

@ INT_ENABLE RAC_INT ; Enable PortA Change Interrupt
@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts

low Led 'turn on led
portc.1 = 1 'turn on servo
main:
pulsout portc.5,throttlepos
pulsout portc.4,servopos
pause 17
if IOCA.4 = 0 then
goto newtime1 'jump to end-time on interrupt
endif
if sum => MTtime then 'stop when target end time is reached
high led 'turn off led
goto newtime1
endif
goto main 'loop until endtime is reached

newtime1:
gosub StopTimer ' Stop Timer1
gosub ResetTime ' Reset Time to 0d-00:00:00.00
gosub StartTimer ' Start the Elapsed Timer
throttlepos = 200 ' 2*(100)
high Led 'turn off led
portc.5 = 0 'initialize throttle pulse low

brake:
pulsout portc.5,throttlepos
pulsout portc.4,servopos
pause 17
if IOCA.4 = 0 then
goto newtime2 'jump to end-time on interrupt
endif
if sum => BKtime then 'stop if elapsed time = target end-time
low led 'turn on led
goto newtime2
endif
goto brake

newtime2:
gosub StopTimer
gosub ResetTime ' Reset Time to 0d-00:00:00.00
gosub StartTimer ' Start the Elapsed Timer
IOCA.4 = 1 ' re-enable porta pin 4 for interrupt on change
low Led ' turn on led
portc.5 = 0 ' initialize throttle pulse low
portc.4 = 0 ' initialize servo pulse low

glide:
pulsout portc.5,throttlepos
pulsout portc.4,servopos
pause 17
if IOCA.4 = 0 then
goto DT 'jump to end-time on interrupt
endif
if sum => DTtime then 'stop if elapsed time = target end-time
high led 'turn off led
goto DT
endif
goto glide

@ INT_DISABLE RAC_INT ; Disable PortA Change Interrupt
@ INT_DISABLE TMR1_INT ; Disable Timer 1 Interrupts

DT: high portc.3 'turn off led
servopos = 200 'DT release position
pulsecnt = 75 'hold for 1.5 second
gosub pulse
servopos = 400 'home position
pulsecnt = 50 'hold for 1 second
gosub pulse 'return to home position
goto halt

'subroutine pulse runs the servo
pulse: portc.4 = 0 'initialize servo pulse low
for i = 1 to pulsecnt
pulsout portc.4,servopos
pause 18
next
return

halt:
portc.1 = 0 'turn off servo
end

mtripoli
- 26th March 2010, 18:41
What does the pulse train look like on an oscilloscope?

Dick Ivers
- 27th March 2010, 14:24
Good suggestion, but alas, I do not have a scope.

mackrackit
- 27th March 2010, 14:39
Could be anything from a weak power supply to weak code ;)
Try a simple code to run the servos without the "fancy" stuff to help narrow it down.

Acetronics2
- 27th March 2010, 15:46
Hi,

@ first look the problem comes because PULSOUT commands might not be " interrupted " ... and maybe also because time between two pulse must be kept, say, between 15 and 30 ms ...

Alain

Dick Ivers
- 27th March 2010, 22:24
Hello all,

I have tried a minimalist aproach. With only one servo, holding at one position, and no interrupt on change ... just the timer1 interrupt keeping track of elapsed time. The one servo is still very twitchy to the point of not being useable.

BTW, the accuracy of elapsed time is very good when checked with a stopwatch..

mackrackit
- 27th March 2010, 22:34
Ok
Show us the current test code and tell us about the hardware ( power supply, servo models, how it is all connected, etc )

Dick Ivers
- 28th March 2010, 02:24
As mentioned above, the servo runs smooth and quiet when driven by the non-interrupt routine. So, I think the servo and circuit are OK.

However, I now realize that timer1 interrupts are occuring every 10 ms, while the servo pulses are only 1 to 2 ms long. Just guessing, but it seems that timer interrupts that periodically occur during the pulse on-time can signifigantly disrupt the pulse period and cause jittering. Therefore, I think my interrupt-timed approach will not work.

Experiment over.

ardhuru
- 28th March 2010, 04:37
Good suggestion, but alas, I do not have a scope.

Not a problem! Capture the signal train on your sound card, and see it thru' a sound editor like Audacity as described on Dave Houston's website. Or alternately, for these frequencies a sound card based scope like the one at http://www.zeitnitz.de/Christian/scope_en (my favourite) would work fine. WYSIWYG!

Just remember to scale down the logic levels by 10:1 or more.

Regards,

Anand