PDA

View Full Version : Simple Servo Position Control Program - Is this right?



marcusvm
- 22nd December 2010, 19:38
I have a pretty simple process that I need carried out via a 16F88 and a servo.

I have an arm that has a heating element on the tip of it. I need this heating element to be lowered onto a bed of grass for one second, then lifted out of the grass. I am testing the flammability of grass within a climate controlled wind tunnel. I want this to be triggered from a simple push of a NO button, then have it carry out the whole process from there. Problem is that I have not messed with a servo motor before and I am not sure if I am controlled it in the correct way. The button is on A0 and the servo control output would be on A1. What I have for code is



'Set internal clock settings for 16F88
Define OSC 8
OSCCON.4=1
OSCCON.5=1
OSCCON.6=1

'Turn off A/D conversion
ANSEL=0


'Define variables and pins
I VAR BYTE
BUTTON VAR PORTA.0
SERVO VAR PORTA.1

'Continuous loop until triggered by ignition button
buttonloop:

If (BUTTON=0) Then goto buttonloop
Pause 10

If (BUTTON=1) Then goto positionloop

goto button loop

'Servo position control loop
positionloop:

Pulsout PORTA.1, 100 'pulse to servo for a length of 1 ms to rotate servo CCW certain number of degrees
For I=1 TO 100 'pulse to servo every 10 ms for a total of 1 second
Pause 1000
NEXT

Pulsout PORTA.1, 150 'pulse to servo for a length of 1.5 ms to move to "zeroed" position

goto buttonloop

End 'end of program never reached

Is this the correct way of doing it? Any help/suggestions would be great!

-Marcus

HenrikOlsson
- 22nd December 2010, 21:10
Hi,
You need to provide the servo with pulses continously if you want it to "hold position", usually at a frequency of 50hz. In your application though it sounds like it would be enough to have it move to position and then "release" it. However, it's still not enough to just give it a single pulse.

There are a couple of problems with your code

Pulsout PORTA.1, 100 'pulse to servo for a length of 1 ms to rotate servo CCW certain number of degrees
For I=1 TO 100 'pulse to servo every 10 ms for a total of 1 second
Pause 1000
NEXT
This will only send a single a pulse to servo because the Pulsout is outside of the for next-loop. On top of that you are pausing 1000ms (1 second) each time thru the loop. I'd try something like:

For I = 0 to 100
Pulsout PortA.1, 100
Pause 19 'Pause 19ms for a total of 20ms which is 50Hz
NEXT


You have the same problem when trying to move the servo back to "zero". You only send a single pulse when you need to send it several in order to move it to position (and keep sending them at 50Hz) to "guarentee" that it stays there.

/Henrik.

marcusvm
- 22nd December 2010, 21:26
This will only send a single a pulse to servo because the Pulsout is outside of the for next-loop. On top of that you are pausing 1000ms (1 second) each time thru the loop. I'd try something like:
Code:

For I = 0 to 100
Pulsout PortA.1, 100
Pause 19 'Pause 19ms for a total of 20ms which is 50Hz
NEXT


Thanks for the help. That makes sense now that I think about it. The timing of it was probably the biggest problem I was having.

With moving the servo back to its "zeroed" position- I was thinking that if I send it one pulse to lift it up at the end of the one second test, so that it doesn't sit there until it decides to return to its "zeroed" position on its own. So, with the one pulse I send it at the end, I am helping the servo return to its natural "zeroed" position. Does that make sense?

I am going to do the programing and wiring here in a bit and play with the actual position of the servo in relation to the pulse width. Hopefully all goes smoothly.

-Marcus

HenrikOlsson
- 22nd December 2010, 21:44
Does that make sense?
Yeah, kind of. But it won't work if the mechanical load on the servo doesn't happen to be exactly as much as is needed to "coast" back to "zero" with the help of a single pulse.....

I'm pretty sure the servo won't decide to move anywhere on its own. It might move due to external load on it if you don't "refresh" it continously though.

So, when you're moving it back to "zero", do something similar to when you're moving into position, ie. pulse it at least enough times to make sure it reaches position.

Good luck!

marcusvm
- 22nd December 2010, 22:01
Ok. I wasn't thinking about the load on the servo. What I think I'll do then is put the pulse that controls the "zero" position in the loop that is waiting for the button to be pressed (so that it is "zeroed" when button is NO), then have the movement pulse in the second loop.



'Continuous loop until triggered by ignition button
buttonloop:

Pulsout PORTA.1, 150 'pulse to servo for a length of 1.5 ms to move to "zeroed" position

If (BUTTON=0) Then goto buttonloop
Pause 10

If (BUTTON=1) Then goto positionloop

goto button loop

'Servo position control loop

positionloop:


FOR I=1 TO 100
Pulsout PORTA.1, 100 'pulse to servo for a length of 1 ms to rotate servo CCW certain number of degrees
Pause 19 'pulse to servo every 10 ms for a total of 1 second
NEXT

goto buttonloop

End 'end of program never reached


Thanks!

Acetronics2
- 23rd December 2010, 11:10
Hi, Marcus

this one should work as desired ...



'************************************************* ***************
'* Name : GrassBurner.BAS *
'* Author : Acetronics *
'* Notice : Copyright (c) 2010 *
'* : All Rights Reserved *
'* Date : 23/12/2010 *
'* Version : 1.0 *
'* Notes : *
'* : *
'************************************************* ***************
'
@ __config _CONFIG1, _INTRC_IO & _WDT_ON & _LVP_OFF & _CP_OFF
' DEFINES
Define OSC 8
Define BUTTON_PAUSE 0
' Internal Osc 8Mhz
OSCCON = %01110010
' Turn off A/D conversion - Digital Inputs
ADCON0 = 0
ANSEL = 0
' Comparators Off
CMCON = 7

'Define variables and pins
I VAR BYTE
Position var WORD
Delay var Byte
OldButton var bit
PORTA = 0
TRISA = %11111101
BUTTON_ VAR PORTA.0
SERVO VAR PORTA.1

buttonloop: ' Button check loop
OldButton = 0
LOW Servo
Pulsout SERVO, 300 ' pulse to place servo to neutral
Pause 19

BUTTON BUTTON_,1,255,0,Delay,0,Buttonloop
OldButton = 1 ' Launched ... We've pressed it !!!
'************************************************* *****************************
positionloop: 'Servo position control loop

I = 0 ' Reset time counter
While ( OldButton AND ( I < 75 )) ' if button has been pushed and time < 1.5s

IF I >= 50 THEN ' 1 second is ... 50 x 20 ms !
position = 300
ELSE
POSITION = 200
ENDIF

LOW Servo
Pulsout SERVO, Position ' pulse to servo

PAUSEUs 19813 - ( Position * 5 ) ' time between pulses

I = I+1 'Increase Time counter
Wend ' go for seeking a new button push ...

goto buttonloop
End 'end of program supposed never reached


may be you'll have to modify a bit the " @ __config ......" line if you use PM as an assembler.

Also correct " IF I >= 50 ..." to i.e. " IF I >= 55 " to take servo positionning time into account ... knowing 1 unit is 20 ms.

Alain

marcusvm
- 23rd December 2010, 16:24
Alain,

Thanks for that code. I had some of my own code that was partially working (servo would only go one direction) that I was in the lab troubleshooting right now. But, I think I might break your code down a little bit to where I'll have two buttons controlling the CW and CCW movement. That way I can make sure I fully understand the overall process of the code.

Thanks again.

-Marcus

El_AMPo
- 7th February 2011, 21:19
I've made some code that might help you.
It was for a high voltage SPDT servo switch for my research.

It sends a 1 second burst signal to the servo and then release it.
Usually thats more than enough time for the servo to react



'//ON INITIAL CONFIG
A VAR BYTE 'counter
SerPos var word 'servo position variable

sers var PORTB.0 'servo signal pin out

'//ON MAIN PROGRAM ROUTINE
'-Set servo position
serpos = 1300 'uS pulse width: 0º -> 1000uS / 180º -> 2000uS
gosub servout 'send pulse for 1 second

'//ON SUBROUTINES
servOUT: 'sends servo a PWM position signal for 1 sec.
for a = 0 to 59 '60hz
Sers = 1
pauseus serpos
Sers = 0
PAUSEUS 2000-serpos '2ms TOTAL
pauseus 14667 '2+14.667ms = 16.667ms -> 60hz -> 1seg total refresh time
next a

return

marcusvm
- 28th March 2011, 04:49
Not to bring up a dead subject, and I am not sure if anybody is going to have any interest in helping out. But if I am using a code similar to Alain's that he posted above ^^^, how can I slow down the movement of the servo? Basically, the servo goes straight from one point to another. I want to add something that will make it so that rather then jumping from position one to position two and back again that it takes, say 10 seconds, to gradually move from position one to position two. I have an idea in mind to basically have it move from say position 200 to 300 by 1 every .1 seconds so that after 10 seconds it has reached the second position. I would think a counting function or something would work so that it would go


IF I >= 50 THEN
position=200
pause 100
position=201
pause 100
position=202
pause 100
...
ELSE
POSITION = 200
ENDIF


And if that is what it takes that I need to type out the whole process count down then so be it. But I would think there would be an easier option..

Application: My problem right now is that there is a 4 inch piece of copper rod on the servo with a ceramic insulator attached to the end of that copper arm. So whenever it moves from position one to position two, the momentum of the mass of the ceramic insulator is causing the servo to overshoot its programmed position. Maybe its a servo issue, but I thought I would start with this.

Any thoughts or help?

Ioannis
- 28th March 2011, 08:22
Simple solution:



For position=start to finish
pause 100
gosub Servo_Control
Next position


Ioannis

marcusvm
- 8th April 2011, 01:37
Ioannis, would you mind explaining that code a little bit to me? I'm a bit of a newbie and haven't dealt with a lot of different code. Is it as simple as copy and pasting in ....


For position=start to finish
pause 100
gosub Servo_Control
Next position

Or are there values for start and finish? and is
gosub Servo_Control another program loop? If so what for? Sorry if this is a simple code and I am being an idiot.

Thanks.

-Marcus