PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Servo-Ansteurung dreht nicht vollständig in gewünschte Position



ijjiij
22.06.2012, 10:40
Hallo!

Also ich habe gerade mit einer ganz simplen Ansteuerung versucht, einen Modelbauservo (robbe FS100) mittels AtMega32 anzusprechen.

Dabei hab ich die Stromversorgung des Servos aus einer eigenständigen Stromquelle (wie empfohlen) sichergestellt. Der Signal-Pin ist an den Port-B2 angelegt.

Zum Programm:

void servo2mitte()
{
PORTB |= (1<<PB2);
_delay_us( 1500 ); // in den 1500 steckt die Lageinformation
PORTB &= ~(1<<PB2);

_delay_ms( 18 ); // ist nicht kritisch
}

void servo2left()
{
PORTB |= (1<<PB2);
_delay_us( 2000 ); // in den 2000 steckt die Lageinformation
PORTB &= ~(1<<PB2);

_delay_ms( 18 ); // ist nicht kritisch
}

void servo2right()
{
PORTB |= (1<<PB2);
_delay_us( 1000 ); // in den 1000 steckt die Lageinformation
PORTB &= ~(1<<PB2);

_delay_ms( 18 ); // ist nicht kritisch
}



Die 3 Methoden rufe ich jetzt nacheinander auf, also links, mitte, rechts, mitte, links, ...

So, was passiert jetzt?
Der Servo dreht ca 2mm nach links, fängt dort zu zittern an, und das wars. Weiter passiert nichts.

Was ich geplant hatte?
Der Servo soll sich einfach bis zum Anschlag nach links drehen, dann in die Mitte, dann nach rechts, wieder in die Mitte, etc.

Ich komme jetzt leider einfach nicht dahinter wo mein Fehler liegt.
Bitte daher um Hilfe!
Btw: Ich wollte absichtlich auf den einsatz von Timern verzichten, weil ich mich mit denen noch nicht so gut auskenne.

LG



Nachtrag:
Der Port ist folgendermaßen difiniert:

DDRB |= (1<<PB2);
PORTB |= (0<<PB2);

PicNick
22.06.2012, 11:35
Ein Servo braucht die Lage-Position nicht nur einmal, sondern alle ~20 mS

ijjiij
22.06.2012, 11:54
Danke für deine Antwort!

Ich hab das ganze jetzt einfach mal wiederholt, also innerhalb der Methoden eine for-Schleife eingebaut die das Signal 10 mal wiederholt. Reicht das für eine komplette Servo-Stellung? Oder soll ich lieber mehr Wiederholungen versuchen? 50? 100?
Bis jetzt leider noch immer ergebnislos, also der Servo stellt sich ein kleines Stück in die gewünschte Richtung, verharrt dort und beginnt zu zucken...

PicNick
22.06.2012, 12:03
etwa so ?


for (int iX = 0; iX < 10;iX++)
{
PORTB |= (1<<PB2);
_delay_us( 1000 ); // in den 1000 steckt die Lageinformation
PORTB &= ~(1<<PB2);
_delay_ms( 18 ); // ist nicht kritisch
}


Schau mal, ob dein Servo eh' positive Pulse braucht.



Btw:
PORTB |= (0<<PB2);
ist für die Jetti-Tant'. "0" kann man nicht shiften.

Wenn du auf Null setzen willst, dann:
PORTB &= ~(1<<PB2);
(wie in deiner Schleife)

PicNick
22.06.2012, 12:09
Wo man sich noch verkühlen kann: Irgendwo ganz vorn muss die CPU-Taktgeschwindigkeit definiert werden, hängt von deinem Compiler ab.

Ein Beispiel dazu:
http://www.rn-wissen.de/index.php/LED-Blinken_ohne_Timer#Makefile

ijjiij
22.06.2012, 12:27
Ja, genau, meine Änderung schaut genau so aus wie die von dir gepostete.
Sind die 10 Wiederholungen hier überhaupt ausreichend?


Richtiges Datenblatt zum Servo find ich jetzt keines im Internet, es wird nur überall geschribenen das der Robbe FS100 ein Standart Modellbau-Servo ist den man überall einsetzen kann.
Weiß auch garnicht mehr wo ich den eig. her habe.

Was ich aber gelesen habe ist, das es digitale und analoge Servos gibt. Funktioniert meine Ansteurung jetzt für beide Arten, oder nur für Digitale? Sonst könnte es ja eventuell daran liegen?

Und Danke für den Hinweis mit dem shiften der 0-en, das wusste ich garnicht, erklärt aber einiges. :D

PicNick
22.06.2012, 12:42
Das mit dem Servo wird schon stimmen. Du könntest ja zur Sicherheit eine Gegenprobe machen, indem du die Polarität umdrehst:


PORTB &= ~(1<<PB2);
_delay_us( 1000 ); // in den 1000 steckt die Lageinformation
PORTB |= (1<<PB2);

Nutz's nix, schad's nix


10 ist vielleicht wirklich etwas wenig, das sind ~0.2 Sek., da kommt das Servo nicht weit. schreib einfach mal 100, was soll's.

oberallgeier
22.06.2012, 14:11
... Richtiges Datenblatt zum Servo find ich jetzt keines im Internet ... digitale und analoge Servos ...Vielleicht reicht Dir dies (klick mal) zur Information ? (http://www.rn-wissen.de/index.php/Servo) Da gibts auch einige Tips zu (den typischen) Fehlermöglichkeiten.

ijjiij
22.06.2012, 17:12
Also, habe jetzt noch etwas herumgespielt, den Servo ausgetauscht (gegen einen anderen der gleichen Art, also auch ein Robbe FS100).

Habe die Durchlaufzahl der Schleife jetzt mal zu Testzwecken auf 500 gesetzt (500 * 20ms = 10k ms = 10 sek), damit bin ich garantiert auf der sicheren Seite in Sachen "Stell-Zeit" habe ich mir gedacht.

Testablauf jetzt:
Habe den Servo per Hand in die Mittel-Lage gedreht als Ausgangsposition.
Ablauf sollte wie gehabt sein: links, mitte, rechts, mitte, links, ...
Ablauf IST:
SEKUNDE 0: Servo dreht ca 2 mm nach links
SEKUNDE 10: nichts passiert
SEKUNDE 20: nichts passiert
SEKUNDE 30: Servo dreht nach links bis zum Anschlag und zittert dort
SEKUNDE 40 - ca 180: Servo hört bei Sekunde 40 wieder auf zu zittern, dreht sich aber nicht weiter in irgend eine Richtung. Nachdem hier 150 Sekunden lang nichts passierte, habe ich den Test an dieser Stelle wieder abgebrochen.

Ich tippe mal auf einen Software-Fehler, daher hier der "komplette" Code:
(Codeteile die nur LEDs blinken lassen hab ich hier mal der Übersichtlichkeit wegen entfernt, diese Spielen aber lediglich auf Port D, berühren den Servo an Port B also garnicht.)



#include <avr/io.h>
#include <util/delay.h>

#define SERVO_2 PB1
#define SERVO_3 PB2

#define LEDRED PD6
#define LEDGREEN PD7

void init_portB(void)
{
//PORT B enthält: ISP-Anschluss + Servos
//PB0 =
//PB1 =
//PB2 = SERVO 2
//PB3 = SERVO 3
//PB4
//PB5 = MOSI für ISP (kann zusätzlich belegt werden)
//PB6 = MISO für ISP (kann zusätzlich belegt werden)
//PB7 = SCK für ISP (kann zusätzlich belegt werden)

DDRB |= (1<<SERVO_2) | (1<<SERVO_3); //setzt die LED-Pins auf Ausgang
PORTB |= (0<<SERVO_2) | (0<<SERVO_3); //setzt die LEDs auf OFF (low)

}

void init_AllPorts(void)
{
//init_portA();
init_portB();
//init_portC();
//init_portD();
}

void servo2mitte()
{
for(int i=0; i<500; i++)
{
PORTB |= (1<<PB2);
_delay_us( 1500 ); // in den 1500 steckt die Lageinformation
PORTB &= ~(1<<PB2);

_delay_ms( 18 ); // ist nicht kritisch
}
}

void servo2left()
{
for(int i=0; i<500; i++)
{
PORTB |= (1<<PB2);
_delay_us( 2000 ); // in den 1500 steckt die Lageinformation
PORTB &= ~(1<<PB2);

_delay_ms( 18 ); // ist nicht kritisch
}

}

void servo2right()
{
for(int i=0; i<500; i++)
{
PORTB |= (1<<PB2);
_delay_us( 1000 ); // in den 1500 steckt die Lageinformation
PORTB &= ~(1<<PB2);

_delay_ms( 19 ); // ist nicht kritisch
}
}

int main(void)
{
init_AllPorts();

while(1)
{
servo2left();
servo2mitte();
servo2right();
servo2mitte();
}
}

robo_tom_24
22.06.2012, 18:13
Hallo

1) Du musst die CPU Frequenz vor der Inkludierung der delay Lib definieren - kommt den keine Warnung vom Compiler?
2) Du musst dem Servo Zeit geben die Position anzufahren -> die Drehgeschwindigkeit steht im Datenblatt, bzw. auf der Servoverpackng ;)
Wird meistens in der Form *Sekundenwert*/*Winkel* angegeben, z.B. beim HS-81 @4,8V (bei 5V aus dem Regler ein bisschen schneller - aber unmerklich) 0.11sek/60° -> somit kannst du dir die Winkelgschwindigkeit (545,5 1/s) ausrechnen und bei einem guten Servoprogramm in die Einsteuerung einfließen lassen
3) Weißt du wie eine Servoansteuerung funktioniert? Du brauchst nicht 500 Signale das sich was tut, sondern es reichen wahrscheinloch 10 ach aus, nur dann ist das Servo ohne "Versorgung" -> kraftlos
Ein Servo braucht dauernd ein Signal -> Endlosschleife

Mach dir ein ganz einfaches Programm:


#define F_CPU 16000000 //deine Quarzfrequenz einsetzen
#define SERVO_PIN PINB1 //Deinen Pin einsetzen


#include <avr/io.h>
#include <util/delay.h>

void main (void)
{


DDRB | = 1<<SERVO_PIN; //als Ausgang definieren

while(1)
{

PORTB |= 1<<SERVO_PIN;
//Pin einschalten
_delay_us(1500);
//Positionsinformation einsetzen
PORTB &= ~(1<<SERVO_PIN);
//Pin ausschalten
_delay_ms(18);
//auf 20ms auffüllen
}

}


Wenn das funktioniert kannst du das immer noch variabel machen, LEDs dazu usw...

Ich weiß nicht welche Erfahrung du in Programmierung hast, aber ichs machs immer so, dass, wenn ich eine komplett neue Funktion für meinen Roboter dazubaue, ich zuerst ein Programm mit den "Basics", also Sachen die für den Roboter wichtig sind (Initialisierungen, 0-Stellungen (-> Motor aus usw.)) und meiner neuen Funktion. Wenn dann die Funktion funkioniert (:cool:) kannst du sie in ein Header-File setzen und in dein "Master" Programm einbauen.

ijjiij
23.06.2012, 18:22
Hallo!
Danke für die Antworten!

Also um speziell auf robo_tom_24 einzugehen jetzt mal:


1) Du musst die CPU Frequenz vor der Inkludierung der delay Lib definieren - kommt den keine Warnung vom Compiler?
Zu meiner Schande muss ich gestehen das ich die Warnung übersehen habe weil ausgeblendet.
Habe jetzt die Frequenz definiert, FuseBit gesetzt und Optimization Level auf 2 gesetzt.


2) Du musst dem Servo Zeit geben die Position anzufahren -> die Drehgeschwindigkeit steht im Datenblatt, bzw. auf der Servoverpackng :wink:
Ich nehme mal an in dem von dir geposteten Beispiel-Code wird das dann so gemacht werden? Habe jetzt mal deine "neue" Version des Programms getestet, kommt aber zum gleichen Ergebnis. mehr dazu weiter unten.


3) Weißt du wie eine Servoansteuerung funktioniert? Du brauchst nicht 500 Signale das sich was tut, sondern es reichen wahrscheinloch 10 ach aus
Wie schon geschrieben ist das hier mein erster Test, die 500 Impulse waren auch nur zu Testzwecken, um dem Servo mit 10 Sekunden genug Zeit für das Anfahren der Position zu geben. Im endgültigen Programm wird das natürlich nicht in dieser Form passieren.



So, hier mal die aktuelle Version des Testprogramms:


#define F_CPU 8000000UL //Quarzfrequenz

#include <avr/io.h>
#include <util/delay.h>

#define SERVO_2 PB1

int main (void)
{

DDRB |= 1<<SERVO_2; //als Ausgang definieren

while(1)
{
PORTB |= 1<<SERVO_2;
//Pin einschalten
_delay_us(1500);
//Positionsinformation einsetzen
PORTB &= ~(1<<SERVO_2);
//Pin ausschalten
_delay_ms(18);
//auf 20ms auffüllen
}

return 0; //wird nie erreicht
}


Der Aufbau ist noch immer der gleiche, also ein Servo an Pin B1 des AtMega32.

Ablauf:
Bei Einschalten des Netzteils dreht der Servo sich ca 2 mm (werden so ca 15° sein schätz ich mal) in die gewünschte Richtung.
Danach nichts mehr.

Beim herumspielen hab ich gerade festgestellt, das der Servo sich jedes mal, wenn ich die Servo-VCC-Leitung vom Netzteil abstecke und wieder anstecke erneut 15° dreht, bis er in Mittellage ist, danach zuckt er nur noch ganz leicht, verharrt aber in Mittellage.
Interessante neue Erkenntnis wie ich finde.
Kann das eventuell irgendwer deuten?
Ich "wackel" hier nicht mit dem Stecker des Servos (also kein Wackelkontakt im Anschluss), um das auszuschleißen habe ich die Spannungsversorgung über ein Steckbrett umgeleitet und stecke hier nur direkt am Steckbrett ab und an.

LG
ijjiij

PS: Mit beiden Servos das gleiche Ergebnis! Die Servos ansich sind nicht kaput und funktionieren einwandfrei.

radbruch
23.06.2012, 23:09
Hallo


// #define LEDRED PD6 Die rote LED hängt wohl an PD6
DDRD |= (1<<PD6); // LED-Pin ist Ausgang
while(1)
{
PORTD |= (1<<PD6); // LED-Pin high
_delay_ms(1000); // eine Sekunde warten
PORTD &= ~(1<<PD6); // LED-Pin low
_delay_ms(1000);
}Funktioniert das wie erwartet?


while(1)
{
//Pin einschalten
PORTB |= 1<<SERVO_2;
PORTD |= (1<<PD6); // LED high
_delay_us(1500);
//Positionsinformation einsetzen
//Pin ausschalten
PORTB &= ~(1<<SERVO_2);
PORTD &= ~(1<<PD6); // LED low
_delay_ms(18);
//auf 20ms auffüllen
}Das auch?

Mit einem Lautsprecher/Kopfhörer könnte man die 50 Hertz (http://de.wikipedia.org/wiki/Hertz_(Einheit)) des Servosignals hören:

http://www.youtube.com/watch?v=fGHDkUlJuh0
(Im Hintergrund brummen die 50 Hz)

Das Zucken der Servos beim Einschalten ist normal. Wie wird die Schaltung, speziell die Servos, mit Spannung versorgt?

Gruß

mic

[Edit]
"Dabei hab ich die Stromversorgung des Servos aus einer eigenständigen Stromquelle (wie empfohlen) sichergestellt."

Habe ich glatt überlesen. GND von Schaltung, Servo und Stromquelle verbunden?

ijjiij
24.06.2012, 09:56
Zum ersten Code:
Ja, funktioniert wie erwartet, die Rote LED leuchtet immer für ca 1 Sek, geht 1 Sek aus, wieder an, etc.

Zum 2. Code:
Funktioniert NICHT wie erwartet!
Die LED geht an, der Servo zuckt kurz (wie beschrieben, etwa 10-15° in die gewünschte Richtung). Die LED bleibt an und der Servo bewegt sich nicht mehr.
Bei (wie vorhin beschrieben) trennen und wieder anschließen der Servo-Spannung geht die LED kurz aus (blinkt) für nichtmal ne halbe Sekunde, der Servo dreht ca 10-15°.
Komplettes Trennen der Servo-Spannung ändert auch nichts, also die LED blinkt deswegen trotzdem nicht.

robo_tom_24
24.06.2012, 11:35
Kann es sein das du einen Fehler in deiner Schaltung hast?
Hast du die beiden GNDs verbunden?
Ist die Versorgungsspannung ausreichend?
-> Es gibt auch Servos mit 6 bzw 7.4V!
Wenn du eine Modellbaufernsteuerung + Empfänger hast, probier deine Servos dort einmal aus...

ijjiij
24.06.2012, 11:47
Hallo!

Ich hab den Fehler jetzt zwar nicht gefunden, aber immerhin soweit eingegrenzt das das ganze auf meinem Steckbrett funktioniert.
Also der Fehler dürfte wohl irgendwo auf meinem Servo-Board liegen.

Habe jetzt alle Verbindungen am Servo-Board nachgeprüft, alles soweit auch richtig verdrahtet.
Wenn ich das Board aber weglasse, das Signal direkt auf mein Steckbrett weiterleite genauso wie die Spannungsversorgung und die Servos (jetzt mal zu Testzwecken erstmal einen, dann beide am gleichen Signal), dann drehen die Servos beide wunderbar.

Gut, wie dem auch sei, der Fehler ist eingegrenzt, das Servoboard wird verschrottet und ein neues gebastelt.

Vielen lieben Dank euch allen!