PDA

View Full Version : Servo troubles.



Glenn
- 19th September 2008, 20:02
Hi, this is my first message, and I hope my problems isnt too stupid..

Anyway, I'm building something with RC-servos and stumbled upon PBP wich looked like an very easy way for me to control them, however, my first little test aint working, and I have no idea why, I given up with my original code and hammered it down to just some testroutine that, in my opinion SHOULD work..

Here is the testcode:



@ device INTRC_OSC_NOCLKOUT,MCLR_OFF,LVP_OFF,WDT_OFF,PROTEC T_OFF
'@ device HS_OSC,MCLR_OFF,LVP_OFF,WDT_OFF,PROTECT_OFF
DEFINE OSC 4

ct var byte

ct = 150

pause 250

low portb.1 ' force the status-LED off.

pulsout portb.0, ct ' this should place the servo in middle position.

pause 1000 ' Wait a while..

loop:

for ct = 1 to 255 step 1

pulsout portb.0, ct ' put the value of the counter to the servo.

Next ct

high portb.1 ' turn the status-LED on.

pause 1000 ' Wait..

low portb.1 ' Turn the status-LED off again.

goto loop


..This little code would in my opinion first put my servo in middle position, wait 1000, and then start to step it from one end position to the other. ..Then the status-LED should light up, wait 1000, and then go black again, and after than it should start to move the same again.

..This is not what happens, the servo does NOT enters the middle position, its goes to a position very near one end, then it moves back and forward a few millimeters, the LED acts as excpected.

Why ? ..first I thought that it was the internal oscillator that was the problem so I put a xtal with two caps at pin 15 and 16, and changed the first line to use an external clock, no difference at all.

Any idea ?

..Even more strange is that if I try to set the servo to 150 permanently it goes to one endstop and stops there ?


..I have a feeling that everything kinda works, but are completly " off scale", and I have no idea why.

..Oh, forgot, the pic is an 16F628A and the xtal is 4MHz.

skimask
- 19th September 2008, 20:04
Servo's need to be continuously updated about 50 times per second.
Those pauses are screwing with your servo causing it to lose it's mind.

Glenn
- 19th September 2008, 20:28
Aha.. Hmm, but my original code didnt have those pauses, and still doesnt work..

But I'll change my testcode and remove the pauses and makes it update continuosly.

..Also, if I make a loop that just send 150 to the servo, it stands in one of the nedpositions.. shouldnt that (150) be the middle position ?

skimask
- 19th September 2008, 21:19
Aha.. Hmm, but my original code didnt have those pauses, and still doesnt work..
But I'll change my testcode and remove the pauses and makes it update continuosly.
..Also, if I make a loop that just send 150 to the servo, it stands in one of the nedpositions.. shouldnt that (150) be the middle position ?
If your original code was going too FAST, you might see the same results.
And a middle position of 150 (1.5ms) is almost an arbitrary number...might be 160, might be 140-ish. Depends on the servo and what day of the week it was made...


@ device INTRC_OSC_NOCLKOUT,MCLR_OFF,LVP_OFF,WDT_OFF,PROTEC T_OFF
DEFINE OSC 4
ct var byte : ct2 var byte : ct = 150 : low portb.1
main:
for ct = 150 to 250 step 1 'sweep one way
for ct2 = 1 to 50
pulsout portb.0, ct
pause 18
next ct2
next ct
for ct2 = 1 to 50 'hang out there for a bit
pulsout portb.0, ct
pause 18
next ct2
for ct = 250 to 150 step -1 'sweep the other way
for ct2 = 1 to 50
pulsout portb.0, ct
pause 18
next ct2
next ct
for ct2 = 1 to 50 'hang out there for a bit
pulsout portb.0, ct
pause 18
next ct2
goto main

Glenn
- 20th September 2008, 02:00
Hmm, well that works, sort of.. its not centering and its not full to the ends..

I tried my old "center the servo" code with slightly modifications too:



' servocenter
@ device INTRC_OSC_NOCLKOUT,MCLR_OFF,LVP_OFF,WDT_OFF,PROTEC T_OFF
DEFINE OSC 4

start:
pulsout portb.0, 150
pause 18
goto start


..Well, this is strange..

The first time I tried it it seemed to work.. but if i moved the servoarm (with power disconnected ofcourse) it gives very strange results.

If its in 180 degrees position, or close to that, it will work, it will center (more or less) the arm and hold it there.. HOWEVER.. if its in another position, it will just hold the current position ??

this is so strange.

Glenn
- 20th September 2008, 02:04
Ok, now I suspected the servo, so I changed the brand new chinese servo to an old one from my box of "old RC stuff", and with two different (working) hitec servos (different models) I get another result, they go to one endpoint and stay there, regardless of the original position ??

skimask
- 20th September 2008, 05:09
Ok, now I suspected the servo, so I changed the brand new chinese servo to an old one from my box of "old RC stuff", and with two different (working) hitec servos (different models) I get another result, they go to one endpoint and stay there, regardless of the original position ??

That's why when you buy a transmitter, it has trim settings on it. when you change servo's in an airplane, generally you have to re-center it, reset the endpoints, etc.etc.etc.
If the one servo isn't going end to end, increase the end points in the program.
And I was wrong. The endpoints in that previous program should've been 100 and 200, not 150 and 250.

Acetronics2
- 20th September 2008, 20:31
Hi, Glenn

Just try

LOW PortB.0

just before the PULSOUT Command ...

Alain

skimask
- 20th September 2008, 23:02
Just try
LOW PortB.0
just before the PULSOUT Command ...


Arg! In post #4, that should've been a PortB.0 instead of the posted PortB.1 in the third line!!!

Macgman2000
- 21st September 2008, 01:00
try just a simple code to make sure your servo is functioning correctly. I found a servo that seemed to drift. I thought it was my code. So i wrote a simple code that sets my pulse widths to left, center and right limits.
Yes I do violate the 20ms refresh rate but if all you care about is moving to positions to verify servo operation this is quick and dirty.

start:
portd.0=1
pausus 1000
portd.0=0

pause 2000

portd.0=1
pausus 1500
portd.0=0

pause 2000

portd.0=1
pausus 2000
portd.0=0

pause 2000

goto start


Nick

Glenn
- 21st September 2008, 01:14
Strangly enough, it kinda work now.. a bit out of scale and so on, but mostly work, after the 'low bortb.0'

HOWEVER..

Now I got to the next part, trying to actually being able to move the servo myself.. so I wrote a bit of code that I thought should work.



@ device HS_OSC,MCLR_OFF,LVP_OFF,WDT_OFF,PROTECT_OFF
DEFINE OSC 4

'Use b1 to hold pulse width variable for servo 1

b1 var byte

'initialize variables

b1 = 150

low portb.0 ' put the servoport low.

main:

pulsout portb.0, b1 'send current servo 1 position out

if porta.0 = 0 then left1 'check for pressed switch 0
if porta.1 = 0 then right1 'check for pressed switch 1

pause 18

goto main

left1:
b1 = b1 + 1
if b1 >254 then max1
goto main

right1:
b1 = b1 - 1
if b1 <75 then min1
goto main

max1:
b1 = 75
goto main

min1:
b1 = 254
goto main


..I have pullup-resistors (10k) on a0 and a1 and wiring them to ground when I activates them.

..Well, the problem is that the servo just goes to one endposition and stay there regardless what I do with a0 and a1 ?

..HOWEVER.. if I comment out theese two lines:



if porta.0 = 0 then left1 'check for pressed switch 0
if porta.1 = 0 then right1 'check for pressed switch 1


..The servo "works", it put itself in the middle position (well not really middle but more or less.)

Why ? ..I could think that my subroutines are destroying the timing, bit it aint working even if I dont touch the inputs ?

Glenn
- 21st September 2008, 01:18
Btw, thanks for all help, I'm completly stuck, and I know noone else that uses PBP :)

skimask
- 21st September 2008, 02:44
@ device HS_OSC,MCLR_OFF,LVP_OFF,WDT_OFF,PROTECT_OFF
DEFINE OSC 4
'Use b1 to hold pulse width variable for servo 1
b1 var byte
'initialize variables
b1 = 150
low portb.0 ' put the servoport low.
main:
low portb.0
pulsout portb.0, b1 'send current servo 1 position out
if porta.0 = 0 then left1 'check for pressed switch 0
if porta.1 = 0 then right1 'check for pressed switch 1
if b1 > 150 then
b1 = b1 - 1
else
b1 = b1 + 1
endif
pause 18 : goto main
left1: b1 = b1 + 1 : if b1 >254 then max1
goto main
right1: b1 = b1 - 1 : if b1 <75 then min1
goto main
max1: b1 = 75 : goto main
min1: b1 = 254 : goto main
END

This should go left with one button, go right with the other button, and if no buttons are pressed, should 'walk' back to center.
Note the BOLDED statements

Glenn
- 21st September 2008, 12:36
This should go left with one button, go right with the other button, and if no buttons are pressed, should 'walk' back to center.
Note the BOLDED statements

Unfortunatly it gives exactly the same result, the servo goes to the endpoint and stay there..

..And just like in my program, if I uncomment the if-lines it "works" as in it stands in the middle position (more or less)

Strange.

Acetronics2
- 21st September 2008, 12:55
Hi,

Just place

PAUSE 18

just after PULSOUT command ...

instead of Before " GOTO Main" .

Alain

Glenn
- 21st September 2008, 17:18
Hi,

Just place

PAUSE 18

just after PULSOUT command ...


No, exactly the same result :(

Acetronics2
- 21st September 2008, 17:49
That was to get a decent frame duration whatever you do with the buttons.

Seems the pot cursor is out of its lane ... or see PS !!!

Now, you should place the Max value for b1 to 200 and min value to 100 ... I know servos not responding for values out of this range.

something possible is the méchanical travel is over the pot travel ... not good at all.

and remember Futaba analogic servos MECHANICAL center is +/- 1300µs. you must take this into account if you try more than the +/- 500µS trip ...

Now ... an interesting question ...


Where do your servo take its power ???

Alain

PS1: you sure PORTA.0 AND PORTA.1 can't be 0 together ???
PS2: you sure your comparators are disabled ??? ... 16F628 !!!

... Lol ...

skimask
- 21st September 2008, 18:32
Ok, try this...


@ device HS_OSC,MCLR_OFF,LVP_OFF,WDT_OFF,PROTECT_OFF
DEFINE OSC 4
temp var byte
main:
for temp = 0 to 255
pulsout portb.0, temp
pause 18
next temp
for temp = 255 to 0 step -1
pulsout portb.0, temp
pause 18
next temp
goto main
END

This should do nothing more than swing the servo back and forth, from endpoint to endpoint. It'll probably hang up for a bit at the endpoints and might even move too fast or jerk around a bit trying to catch up to the program.
If it doesn't, you've got something else going on.
It all boils down to breaking it down to it's simplest form and building it back up again.
Try it and report back...

Glenn
- 21st September 2008, 20:30
That was to get a decent frame duration whatever you do with the buttons.

Seems the pot cursor is out of its lane ... or see PS !!!

Now, you should place the Max value for b1 to 200 and min value to 100 ... I know servos not responding for values out of this range.


Well but it work with the lines uncommented, and stands fairly in the middle.

I also tried three different servos.



Now ... an interesting question ...
Where do your servo take its power ???


Well, my testsetup is built on an breadboard, and the servo is connected via a pinstrip and directly to the same power as the rest of the setup, which is powered from the +5V 2A output on my lab power supply.

Btw I'm using a pickit2 from microchip to program the pic via ICSP, and its permanently connected to the pic.




PS1: you sure PORTA.0 AND PORTA.1 can't be 0 together ???


Yes, I used a switch with three positions, (on)off(on) first, but now I just use a cable directly on the breadboard.



PS2: you sure your comparators are disabled ??? ... 16F628 !!!


No idea, how do I do that ?

Glenn
- 21st September 2008, 20:32
This should do nothing more than swing the servo back and forth, from endpoint to endpoint. It'll probably hang up for a bit at the endpoints and might even move too fast or jerk around a bit trying to catch up to the program.
If it doesn't, you've got something else going on.
It all boils down to breaking it down to it's simplest form and building it back up again.
Try it and report back...

Well, it swings the servoarm to one endpoint, stops for a while, then all the way to the other endpoint (or near it anyway) and directly start to go back again and repeats everything.

Its not a very smooth movement but it looks ok.

skimask
- 22nd September 2008, 01:57
Well, it swings the servoarm to one endpoint, stops for a while, then all the way to the other endpoint (or near it anyway) and directly start to go back again and repeats everything.

Its not a very smooth movement but it looks ok.

Ok, that's good...at least you know stuff is working.

Now take the program and modify it to 'pull the endpoints' in a bit until you get to the actual endpoints.
When it 'stops for awhile', the program is probably trying to drive the servo past it's endpoints. The program goes to 0ms pulse width, but the servo can only actually drive to a 1ms pulse width, actually it'll probably drive farther than that, a lot farther, just not all the way to zero, or by the same token, won't drive all the way to 2.55 ms pulse width.



@ device HS_OSC,MCLR_OFF,LVP_OFF,WDT_OFF,PROTECT_OFF
DEFINE OSC 4
temp var byte
main:
for temp = 100 to 200
pulsout portb.0, temp
pause 17 'try lower numbers until it starts acting even stupider than it's acting now
next temp
for temp = 200 to 100 step -1
pulsout portb.0, temp
pause 18 'try lower numbers until it starts acting even stupider than it's acting now
next temp
goto main
END

Decrease the 100 until it starts pausing at one end (meaning the PIC is trying to over-drive the servo) and increase the 200 until it starts pausing at the other end (again, meaning the PIC is trying to over-drive the servo in the other direction).

Acetronics2
- 22nd September 2008, 09:15
Hi, Glenn

This one Should run




@ device HS_OSC,MCLR_OFF,LVP_OFF,WDT_ON,PROTECT_OFF
DEFINE OSC 4

CMCON = 7 ' Disable comparators

PORTA = %00000011
PORTB = 0

TRISA = %00000011
TRISB = 0

'Use b1 to hold pulse width variable for servo 1

b1 var byte

'initialize variables
b1 = 150

low portb.0 ' put the servoport low.
main:

low portb.0
pulsout portb.0, b1 'send current servo 1 position out
if porta.0 = 0 then left1 'check for pressed switch 0
if porta.1 = 0 then right1 'check for pressed switch 1

bugtrap:

if b1 > 150 then
b1 = b1 - 1

else
if b1 < 150 then b1 = b1 + 1

endif
pause 18 : goto main

left1:
IF porta.1 = 0 Then bugtrap
b1 = b1 + 1
if b1 > 199 then max1
Pause 8 : goto main

right1:
IF Porta.0 = 0 Then bugtrap
b1 = b1 - 1
if b1 < 100 then min1
Pause 8 : goto main

max1: b1 = 100 : goto main ; jump to other side

min1: b1 = 200 : goto main ; jump to other side

END



and do not forget : courtesy SKI !!!

Alain

Glenn
- 22nd September 2008, 12:50
Decrease the 100 until it starts pausing at one end (meaning the PIC is trying to over-drive the servo) and increase the 200 until it starts pausing at the other end (again, meaning the PIC is trying to over-drive the servo in the other direction).

Well, as you said before the values depends on which servo I use, I settled for the servo that I'm going to use (the brand new china-made) and with that 75 and 255 seem to be the correct values, however, when its 255, its still not at the endpioint, its a few mm more left. ..However this doesnt matter.

Glenn
- 22nd September 2008, 13:42
Hi, Glenn

This one Should run



Well, it kind of works, the servo stands still until I touch the switch, but it moves in very strange ways, I'll try to adjust the values a bit and see if it changes anything.

But it sure looks like the comparators was the problem, great!

Acetronics2
- 22nd September 2008, 14:02
Well, it kind of works, the servo stands still until I touch the switch,


Looks it should be in the 1500µs position ...



but it moves in very strange ways, I'll try to adjust the values a bit and see if it changes anything.



should reach slowly one end, then RUN to the other end, then slowly to the other end , Then RUN ...

WHILE pushing a button

and going back to center if buttonS realeased ... or both buttons pushed.




But it sure looks like the comparators was the problem, great!



Alain

skimask
- 22nd September 2008, 14:26
however, when its 255, its still not at the endpioint, its a few mm more left. ..However this doesnt matter.

Change your BYTE variable to a WORD variable and you'll be able to go beyond 2.55 ms. But that sounds a bit goofy since a 2.55ms pulse width is out of spec for most servo's. But hey, if it works for you, go with it...

Acetronics2
- 22nd September 2008, 15:04
Hi, SKI

The maximum I ever reached is 250 µs to 2600 µs ... with a Futaba S3001 or a Robbe RS100 ...

not linear at all between 250 and 600µs !!!

regards
Alain

Acetronics2
- 23rd September 2008, 08:33
Hi, Glenn

I Think I've found what looks "strange" to you ...




@ device HS_OSC,MCLR_OFF,LVP_OFF,WDT_ON,PROTECT_OFF
DEFINE OSC 4

CMCON = 7 ' Disable comparators

PORTA = %00000011
PORTB = 0

TRISA = %00000011
TRISB = 0

'Use b1 to hold pulse width variable for servo 1

b1 var WORD

'initialize variables
b1 = 150 << 4

low portb.0 ' put the servoport low.
main:

low portb.0
pulsout portb.0, ( b1 >> 4 ) 'send current servo 1 position out
if porta.0 = 0 then left1 'check for pressed switch 0
if porta.1 = 0 then right1 'check for pressed switch 1

bugtrap:

if b1 > ( 150 << 4 ) then
b1 = b1 - 1

else
if b1 < ( 150 << 4 ) then b1 = b1 + 1

endif
pause 18 : goto main

left1:
IF porta.1 = 0 Then bugtrap
b1 = b1 + 1
if b1 > ( 3199 ) then max1
Pause 8 : goto main

right1:
IF Porta.0 = 0 Then bugtrap
b1 = b1 - 1
if b1 < ( 1601 ) then min1
Pause 8 : goto main

max1: b1 = ( 100 << 4 ) : goto main ; jump to other side

min1: b1 = ( 200 << 4 ) : goto main ; jump to other side

END

This is not the "perfect movement" ... but the maximum to get from this coding style.

Alain

PS : Question : Why multiply b1 per 16 ( << 4 ) and divide it per 16 ( >> 4 ) when outputting the pulse.
The answer to last trouble is here !!!