Hallo,
habe mal wieder en kleines Problem und ich hoffe ihr könnt mir helfen!
Ich will einen kleinen Servo mit einem Atmega8 ansteuern, was ja auch
kein Problem ist.
Nur fährt er die Sollposition viel zu schnell an, was für mein Projekt
sehr ungünstig ist.
Hab auch schon probiert die Sollposition in mehreren Schritten
anzunähern, doch entweder er macht garnichts oder fährt normal zur
Sollposition.
Kann mir vielleicht jemand einen Tipp geben, wie man das richtig macht,
also dass der Servo langsam eine Position anfährt.
Achso ich habe alles in C Programmiert und kenne mich mit den anderen
Sprachen nicht sonderlich gut aus.
Vielen Dank schon mal an alle im Voraus!
Gruß Patrick
du musst die strecke von der ist- zur sollposition in ausreichend viele
schritte aufteilen (je nach gewünschter geschwindigkeit) und die dann
der reihe nach anfahren und an jeder position kurz warten...
Patrick A. schrieb:> Hab auch schon probiert die Sollposition in mehreren Schritten> anzunähern, doch entweder er macht garnichts oder fährt normal zur> Sollposition.>> Kann mir vielleicht jemand einen Tipp geben, wie man das richtig macht,> also dass der Servo langsam eine Position anfährt.
Genau so, wie du das versucht hast. Indem man das Servo in kleinen
Schritten an die Zielposition führt. Wenn das immer noch zu schnell ist,
dann müssen da eben noch mehr Zwischenschritte rein oder die zeitliche
Distanz zwischen den Schritten vergrößert werden.
Hallo,
habe noch mal etwas rum probiert aber es funktioniert immer noch nicht.
Erst soll er von der Mittelstellung schnell(hier ist es ok wenn es
schnell geht) nach links fahren und da bleiben.
Soweit so gut und dann kommt das Problem: Von dort soll er dann langsam
wieder nach rechts fahren und zu einem späteren zeitpunkt wieder nach
links.
Ich fasse mal kurz zusammen was er macht:
Von links nach rechts>> er fährt schnell und brummt bis das Signal zu
Ende ist.
Von rechts nach links>> er brummt nur und bewegt sich garnicht.
Ich füge mal den Code hier ein. Vielleicht sieht ja jemand den Fehler.
a = 50; // Schnell nach links
while (a>0)
{
PORTB |= (1<<PB2);
_delay_us(2000);
PORTB &=~(1<<PB2);
_delay_ms(18);
a--;
}
.
.
uint8_t b=60; // Langsam nach rechts
uint8_t c=2000;
uint8_t d;
while (b>0)
{
d=0;
PORTB |= (1<<PB2);
while(d<c)
{
_delay_us(1);
d++;
}
PORTB &=~(1<<PB2);
_delay_ms(18);
PORTB |= (1<<PB2);
d=0;
while(d<c)
{
_delay_us(1);
d++;
}
PORTB &=~(1<<PB2);
_delay_ms(18);
PORTB |= (1<<PB2);
d=0;
while(d<c)
{
_delay_us(1);
d++;
}
PORTB &=~(1<<PB2);
_delay_ms(18);
PORTB |= (1<<PB2);
d=0;
while(d<c)
{
_delay_us(1);
d++;
}
PORTB &=~(1<<PB2);
_delay_ms(18);
b--;
a=20;
while (a>0)
{
a--;
c--;
}
//c=c-20;
.
.
.
b=60; // Langsam wieder nach links
c=800;
while (b>0)
{
d=0;
PORTB |= (1<<PB2);
while(d<c)
{
_delay_us(1);
d++;
}
PORTB &=~(1<<PB2);
_delay_ms(18);
PORTB |= (1<<PB2);
d=0;
while(d<c)
{
_delay_us(1);
d++;
}
PORTB &=~(1<<PB2);
_delay_ms(18);
d=0;
PORTB |= (1<<PB2);
while(d<c)
{
_delay_us(1);
d++;
}
PORTB &=~(1<<PB2);
_delay_ms(18);
d=0;
PORTB |= (1<<PB2);
while(d<c)
{
_delay_us(1);
d++;
}
PORTB &=~(1<<PB2);
_delay_ms(18);
b--;
a=20;
while (a>0)
{
a--;
c++;
}
}
Viellen Dank noch mal!!!
Gruß Patrick
so wird das nix.
Mach dir mal eine Funktion die als Parameter die Microsekunden erwartet
(integer).
Dort setzt du den Portpin, wartest die übergebene Zeit, schaltest den
Pin aus und wartest die 18 Milisekunden.
Im Hauptprogramm rufst du diese Funktion mit den Werten von 1000 bis
2000 auf.
Und dann überlegst du dir wie oft und mit welchen Werten du die Funktion
aufrufst.
Besser wäre das mit Timer, aber soweit bist du noch nicht.
Holger
Hallo
Holger W. schrieb:> Besser wäre das mit Timer, aber soweit bist du noch nicht.
Der M8 hat einen 16 Bit timer, mit welchem du ganz easy einen Servo
ansteuern kannst. Dafür reichen sogar 8 Bit.
Dazu ein PWM Signal erzeugen, hab das auch schon mit einem Tiny13
gemacht. Ich würde den 1. Timer dazu verwenden alle viertel Sekunde den
Servostand um x Grad zu verschieben, den 8 Bit Timer für die PWM.
Es gibt zig Beispiele im Netz dazu.
Nettes Pdf: http://mil.ufl.edu/5666/handouts/ATMPWM.pdf
Tm
Hallo,
meintest du das mit der Funktion so oder habe ich da was falsch
verstanden?
void servo(uint8_t warten)
{
PORTB |=(1<<PB2);
_delay_us(warten);
PORTB &=~(1<<PB2);
_delay_ms(18);
}
im Hauptprogramm dann:
Von 2000 nach 800
a=60;
b=2000;
while (a>0)
{
servo(b);
b=b-20;
a--;
}
Gruß Patrick
OK Vielen Dank
Hab nur noch das Problem, dass der Compiler merkert, dass bei
_delay(warten) keine Variable verwendet werden könnte.
Wie kann ich das Umgehen?
Gruß Patrick
Dann warte in einer Scheife den übergebenen Wert 1 Microsekunde lang.
Der Lösungsansatz insgesamt ist nicht sehr schön, aber um einen Servo zu
bewegen und zu verstehen wie das geht, schon ok.
Holger
Holger W. schrieb:> Dann warte in einer Scheife den übergebenen Wert 1 Microsekunde lang.> Der Lösungsansatz insgesamt ist nicht sehr schön, aber um einen Servo zu> bewegen und zu verstehen wie das geht, schon ok.
Nicht wirklich, denn die Wartezeiten sind dann völlig daneben. Bei 1 Mhz
Prozessortakt wäre eine Mikrosekunde genau einen Taktzyklus lang. Ich
weiß jetzt nicht, ob _delay_us inzwischen überhaupt so eine kurze
Wartezeit machen kann, aber die Schleife braucht für sich selbst noch
zusätzlich mehrere Taktzyklen, also sind die tatsächlichen Wartezeiten
ein Vielfaches von der angegebenen.
Holger W. schrieb:> Besser wäre das mit Timer, aber soweit bist du noch nicht.
@Patrick
Das wär die beste Lösung. Daher solltest du da reinbeissen.
Servoansteuerung, bei der man sowohl das Pulssignal als auch
Verfahrzeiten im Auge behalten muss, machen keinen Spass.
Die Pulserzeugung muss von alleine ablaufen und von den Verfahrzeiten
und Wegen gestrennt sein. Alles andere bedeutet Aufwand ohne Ende
Rolf Magnus schrieb:> Holger W. schrieb:>> Dann warte in einer Scheife den übergebenen Wert 1 Microsekunde lang.>> Der Lösungsansatz insgesamt ist nicht sehr schön, aber um einen Servo zu>> bewegen und zu verstehen wie das geht, schon ok.>> Nicht wirklich, denn die Wartezeiten sind dann völlig daneben. Bei 1 Mhz> Prozessortakt wäre eine Mikrosekunde genau einen Taktzyklus lang. Ich> weiß jetzt nicht, ob _delay_us inzwischen überhaupt so eine kurze> Wartezeit machen kann, aber die Schleife braucht für sich selbst noch> zusätzlich mehrere Taktzyklen, also sind die tatsächlichen Wartezeiten> ein Vielfaches von der angegebenen.
Ein Modellservo mit einer Auflösung von 1µs anzusteuern ist schon
gewagt.
Sowas geht natürlich wunderbar mit der o.g. Methode, dass ein Timer mit
der OnCapture-Einheit verwendet wird, dem man alle paar ms einen neuen
Vergleiswert vorgibt.
Wenn man unbedingt Delay-Konstrukte verwenden will, sollte eine
Auflösung von 10µs ausreichen.
Dann kann man auch das ganz einfach in geschachtelten Schleifen
realisieren:
Pseudocode:
setze Endmarke
setze Impulsmarke
wiederhole bis Impulsmarke = Endmarke:
{
setze Pulsdauer auf 0
wiederhole bis Pulsdauer = Impulsendmarke erreicht:
{
warte 10µs
inkrementiere Pulsdauer
}
wiederhole bis Pulsdauer = 20ms erreicht:
{
warte 10µs
inkremtieren Pulsdauer
}
setze Impulsmarke auf neuen Wert
}
Das Setzen der der Pulsdauer kann durch Inkrementieren oder Dekrementier
erfolgen. Je nachdem, in welche Richtung gedreht werden soll.