-
frage zu servoprogramm
hallo, bin programmier grad an meinem neuen servo für n rp6 rum.....
mein ziel war es zum einstieg ein programm zu schreiben das den servo in mittelstellung verfahren lässt und sich dort hält. ich hab es so programmiert, dass der servo auf dem sda pin alle 20 ms ein high signal von der länge von 1,5 ms bekommt. leider dreht der servo lediglich beim einschalten wenige mm gegen den uhrzeigersinn und nicht in mittelstellung. dazu hab ich das folgende programm geschrieben:
#include "RP6RobotBaseLib.h"
#define SERVO_OUT SDA
void initSERVO(void)
{
DDRC |= SERVO_OUT; //SDA high
PORTC &= ~SERVO_OUT;//SDA low
startStopwatch1(); //stopwatch1 starten
}
void task_SERVO(void)
{if (getStopwatch1()>20) // nach Stopwatch1 >20 ms
{PORTC |= SERVO_OUT; // SDA auf high
startStopwatch2();} //Stopwatch2 starten
if (getStopwatch2()>1,5) //Stopwatch2 >1,5ms
{PORTC &= ~SERVO_OUT; //SDA auf low
setStopwatch1(0); //Stopwatch1 auf 0ms zurück
setStopwatch2(0);} //Stopwatch2 auf 0ms zurück
}
int main(void)
{
initRobotBase();
initSERVO();
while(true)
{
task_SERVO();
task_RP6System();
}
return 0;
}
wer kann mir sagen wo der fehler liegt?
gruß
-
Hallo
Die Stopuhren sind zu langsam für eine vernüftige Servoansteuerung (>1,5 ist eh Unsinn). Mit Bordmitteln (an eine LED angeschlossen) kann der RP6 Servos mit Sleep() ansteuern:
https://www.roboternetz.de/phpBB2/vi...56877ce#346075
Gruß
mic
-
is ja alles schön und gut... nur will ich meinen servo halt über die experimentierplatine ansteuern und nicht über leds. kannst mir deswegen vielleicht sagen, wo der fehler im oberen programm liegt? der grundgedanke vom programm dürfte ja stimmen.....
gruß
-
Die Stopwatches haben ein Auflosung von 1mS und basieren sich auf ein 16 bit integer. Das bedeutet das die jeden mal hochzahlen mit "1". Abfrage auf 1,5 macht dan kein Sinn. Er geht dan immer ab die Werte 2 (mS) auf TRUE. Eine andere Moglichkeit besthet darin das sie eine andere Timer brauchen mit eine Auflosung von 100µS. Die ist auch schon in Robotbaselib.c forgesehen.
Wichtig ist das die code in den ISR (interrupt sub routine) so kurz wie moglich ist. Diese ISR wird jeden 100µS bearbeitet. Wen da zu fiel code derin steht, geht das nicht mehr in diese 100µS und dan ist Schluss.
-
jetzt hab ich mal nochmal ein anderes programm entworfen und den servo auch an ne led angeschlossen. bei dem programm müsste der servo immer jeweils von einem ende zum anderen schwenken und dabei immer zwischen jedem schwenken 2 sekunden pause machen sollte. leider schwenkt der servo nur zu beginn an ein ende und bleibt da stehen. hier das programm:
#include "RP6RobotBaseLib.h"
uint16_t servopos = 20;
void servoposi(void)
{sleep(servopos); // nach 20ms
setLEDs(1); // Servo high
sleep(1); // nach 1 ms
setLEDs(0); // Servo low
sleep(2000); // 2000 ms Pause
sleep(servopos); // nach 20ms
setLEDs(1); // Servo high
sleep(2); // nach 2 ms
setLEDs(0); // Servo low
sleep(2000);
}
int main (void)
{
initRobotBase();
while (true)
{
task_RP6System();
servoposi();
}
return 0;
}
gruß
-
Der servo braucht sowieso jeden 20 mS ein puls !! Sie geben 1 mal ein Puls von 1 mS und dan 2 sek nichts. Danach 2 mS ein puls und wieder 2 sek nichts. So geht das nicht.
Die function sleep ist auch nicht gans genau. Grund ist das noch immer Interrupts bearbeitet werden. Sleep gibt eine "mnimale" wartezeit. Under umstanden kan diese Wartezeit langer sein. Wen robby farht, kommen sowieso die interrupts von die Wheelencoder. Mit diesen function soll der Servo wahrscheinlich nur bedingt ruhig sein. Dabei ist Sleep auch noch eine "Blocking" function, so da wird nicht anderes mehr gemacht ( nur interrupts). Versuchs mal mit diesen 100µS timer in der Robotbaselib.
-
In diesem Post gibt es ein paar funktionierende Programme zu Servo-Ansteuerung (RP6Base und M32):
https://www.roboternetz.de/phpBB2/viewtopic.php?t=34407
Gruß Dirk
-
Hallo
So funktioniert es:
Code:
RP6 steuert ein Servo an der SL1-LED mit Sleep() 1.5.2008 mic
include "RP6RobotBaseLib.h" // Denn vollen Funktionsumfang der Lib bezahlen
// wir mit den störenden Interrupts
uint8_t stellzeit, servopos=15; // 15=Servomitte, Drehbereich ca. 5-25
int main(void)
{
initRobotBase();
setLEDs(0); // alle LEDs aus/kein Impuls
while(1)
{
stellzeit=30; // Wiederholungen für Stellzeit vorbelegen
while(stellzeit--) // Wir geben dem Servo Zeit zum Positionieren
{ // und senden solange das Steuersignal
setLEDs(1); // Servo Impuls Anfang
sleep(servopos); // Sleep() läuft mit 10kHz: 15 entspricht 1,5ms
setLEDs(0); // Servo Impuls Ende
sleep(200-servopos); // Das Signal soll alle 20ms gesendet werden
} // Am Ende der Schleife sollte das Servo im Ziel sein
servopos+=5; // Nächste Position berechnen
if(servopos > 25) servopos=5; // Ende Drehbereich, zurück auf andere Seite
mSleep(500); // Platzhalter für andere Aufgaben
}
return(0);
}
Zwei Probleme: Die Auflösung ist gering (5-25) weil Sleep() nicht so flott ist. Und die Pulslängen schwanken wegen der internen RP6-Interrupts. Deshalb zittern die Servos leicht.
Gruß
mic
Edit: Kommentare im Programm angefügt
-
Hi,
anstatt der sleep(); könnte man doch auch einfach die Funktion delayCycles(); hernehmen, oder? Ich glaube die hat ne auflösung von einem Taktcyclus (stimmt, jetzt nachgeschaut)
damit wäre dann auch das ruckeln so ziemlich verschwunden, ich bin auch mit meiner Servoansteuerungs-Lib für alle ATMegas bald fertig, d.h. die geht auch für den RP6
sie iss zwar auch nicht mehr ganz so genau wegen interrupts, aber ich hab jetz eine idee:
man könnte doch beim aufrufen der Servofunktion die ganzen Interrupts deaktivieren und am ende wieder alle anmachen, z.b. mit initRobotBase();
MfG Pr0gm4n
-
danke für eure antworten. jetzt noch ne frage die hauptsächlich radbruch betrifft... und zwar, könntest du mir bitte speziell zu deinem geposteten servoprogramm noch mehr kommentare dazu schreiben?
wär voll nett, dann könnt ich nämlich das programm besser verstehen....
gruß