PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : frage zu servoprogramm



proevofreak
29.04.2008, 22:38
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ß

radbruch
29.04.2008, 23:00
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/viewtopic.php?p=346075&sid=e3750f38979daf136b0aef29f56877ce#346075

Gruß

mic

proevofreak
30.04.2008, 09:23
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ß

RP6conrad
30.04.2008, 11:11
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.

proevofreak
30.04.2008, 11:13
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ß

RP6conrad
30.04.2008, 12:42
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.

Dirk
30.04.2008, 13:05
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

radbruch
30.04.2008, 13:06
Hallo

So funktioniert es:


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

Pr0gm4n
30.04.2008, 15:56
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

proevofreak
30.04.2008, 22:43
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ß

Pr0gm4n
01.05.2008, 15:23
Hallo,

ich hab das mal schnell für radbruch gemacht (keine Angst, will keinen Code klauen)



/*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
//d.h. du setzt "servopos" auf einen Wert 5-25 entsprechend der Position, die der Servo anfahren soll
int main(void)
{
initRobotBase();
setLEDs(0); // alle LEDs aus/kein Impuls, da da ja auch die Servos mit dranhängen--> Störsignale vermeiden
while(1)
{
stellzeit=30; // Wiederholungen für Stellzeit vorbelegen (zeit in [20ms], wie lange der Servo zum stellen der Postition braucht)
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, kannst du natürlich auch anders, z.B. dass du Taster, Sensoren etc. einliest
if(servopos > 25) servopos=5; // Ende Drehbereich, zurück auf andere Seite
mSleep(500); // Platzhalter für andere Aufgaben
}
return(0);
}


so, ich hoffe ich konnte dir nun etwas helfen, eventuell kann ich dir in ein bis zwei wochen eine noch genauere Lösung anbieten, meine Servolib

damit ruft man nurnoch task_Servos(Parameter); auf und als Parameter gibt man lediglich ein, welche Stellung der Servo annehmen soll, dabei sind allerdings ein paar #define's nötig...


MfG Pr0gm4n

PS: radbruch, wie lange braucht so ein Servo für linker Anschlag bis rechter Anschlag? (deine Miniservos z.B.)

proevofreak
01.05.2008, 15:53
@radbruch: dein programm ist irgendwie fehlerhaft. gut du hast die # bei include vergessen aber auch mit der # lässt sich das programm nicht kompilieren....

gruß

radbruch
01.05.2008, 16:48
Sorry, das passiert, wenn man nach dem Editieren nicht mehr kompiliert:


// 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);
}
Aber es war schon spät und eigentlich nicht schwer zu finden: das # bei include und // bei der ersten Zeile...


wie lange braucht so ein Servo für linker Anschlag bis rechter Anschlag?
Mach hier den Wert schrittweise kleiner bis das Servo nicht mehr sauber alle Positionen anfährt:

stellzeit=30;


..ich hab das mal schnell für radbruch gemacht (keine Angst, will keinen Code klauen)
War das nötig? Ist es nun verständlicher? Und zum Code klauen: Selbstverständlich sind alle meine hier geposteten Codeschnippsel open-source.

Gruß

mic

Pr0gm4n
01.05.2008, 17:13
Hi radbruch,

aus meiner Sicht waren deine Kommentierungen sehr gut ausreichend, ich möchte hier nur auf



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....


verweisen

das mit dem codklauen etc. sagte ich, weil einige leute meinen, es wäre so wichtig, dass ihr name im code einkommentiert drinsteht, auch wenn ihn dann jemand anderer per copy & paste editiert, verwendet oder im Inet anbietet, ein Kumpel von mir iss da schonmal voll ausgerastet, dass ich seine dummen Kommentierungen gelöscht hab bzw. glaub sogar nur geändert hab


ich hab jetzt mal mein Servo-Ansteuerungsprogramm fertig, in wiefern ich es Open-Source mache steht noch nicht fest, aber vermutlich poste ich es einfach irgendwo bzw. da es mehr ne art Lib ist biete ich es irgendwo zum Download

es geht für alle Atmels mit maximal 266 MHz :)


@radbruch: Ich schick dir das Servoteil dann mal irgendwie, kann ich dir 1716 Codezeilen per PN schicken? Wäre nett wenn du dir das mal anschaust

Wenn du dich wunderst warum ich da einige Funktionen mit gleichem Namen drinnen habe, das sind sog. Überladene Funktionen, ich denke zwar, dass die nur der Compiler kann, aber die Herren im Unterforum AVR-C-Programmierung meinten, das ginge auch so, könnte aber auch sein, ich werds sehen...


MfG Pr0gm4n

proevofreak
01.05.2008, 17:17
danke. jetzt läuft des programm. wolltest du aber nicht in programm schreiben, wo den servo ständig von linken zu rechten schwenken lässt? jetzt schwenkt der motor mit 3 mal anhalten nach rechts und dann durchgehend nach links.

gruß

radbruch
01.05.2008, 17:32
Hallo Pr0gm4n


aus meiner Sicht waren deine Kommentierungen sehr gut ausreichend
...weil du den Beitrag und die Kommentare erst nach meinem Edit (Zuletzt bearbeitet von radbruch am 01.05.2008, 00:21, insgesamt ein Mal bearbeitet) gelesen hast. Die erste Version war völlig ohne Kommentare...


Ich schick dir das Servoteil dann mal irgendwie...
Danke für's Angebot, aber das ist wirklich nicht nötig. Du kannst deinen Entwurf auch in einem Thread zur Disskusion stellen. Ich hätte aber keinen Bedarf an einer Servo-Lib. Meiner Meinung nach sind Servoanwendungen meist Speziallösungen die man mit einer Lib nicht vereinfachen kann. Ich lasse mich aber gerne vom Gegenteil überzeugen.

@proevofreak: Mehr kann das Programm nicht:


servopos+=5; // Nächste Position berechnen
if(servopos > 25) servopos=5; // Ende Drehbereich, zurück auf andere Seite
Es ging ja nur um die Theorie. Wie man das anwenden kann ist eure Aufgabe.

Gruß

mic

Pr0gm4n
01.05.2008, 17:37
Hi,

ich versteh zwar nicht, warum der Servo am linken Anschlag bleibt, aber versuch doch mal das: (nichtmehr nur 3 mal Anhalten)


// 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
stellzeit=30; // Wiederholungen für Stellzeit vorbelegen
while(1)
{

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+=1; // 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);
}


Ich hab auch das Stellzeit=30; vor die while-schleife um es nicht ständig neu definieren zu müssen, das spart rechenzeit -->ruckeln

ist zwar nur ein Takt, aber wenn man das immer macht kommt doch manchmal was mit 0.05 ms oder so zusammen, was das ruckeln erheblich verbessert


MfG Pr0gm4n

radbruch
01.05.2008, 18:21
Hallo


Ich hab auch das Stellzeit=30; vor die while-schleife um es nicht ständig neu definieren zu müssen, das spart rechenzeit -->ruckeln
Das ist völliger Quatsch! Mit dieser Änderung wird stellzeit nur einmalig mit 30 geladen, alle weiteren Schleifendurchgänge starten dann mit 255, weil stellzeit vom Anfahren der letzten Position mit 0 belegt war. Das wird nur nicht offensichtlich weil anschliesend immer ein mSleep(500); folgt. Wenn man das auskommentiert wird man sehen, dass die Wartezeit ab der zweiten Position deutlich größer ist. Zudem werden wohl einige Positionen übersprungen.


ist zwar nur ein Takt, aber wenn man das immer macht kommt doch manchmal was mit 0.05 ms oder so zusammen, was das ruckeln erheblich verbessert
Auch das ist Unsinn. Die Impulslänge wird hier gebildet:

setLEDs(1); // Servo Impuls Anfang
sleep(servopos); // Sleep() läuft mit 10kHz: 15 entspricht 1,5ms
setLEDs(0); // Servo Impuls Ende

Einzig ein Interrupt kann die Ausführungsdauer von Sleep() beeinflussen. Ein Ausschalten der Interrupts mit cli()/sei() führt hier aber nicht zum Ziel...

Und schlieslich:
ich versteh zwar nicht, warum der Servo am linken Anschlag bleibtDas Servo bleibt nicht am linken Anschlag sondern startet dort einen neuen Demozyklus. Genau das macht "if(servopos > 25) servopos=5;" Wenn Position größer rechts dann Position=links.

Gruß

mic

Pr0gm4n
01.05.2008, 18:55
Hi,

erstmal sorry für all den mist den ich da geschrieben hab, frag mich grad, wie ich darauf gekommen bin...

trotzdem eine Beanstandung:



Und schlieslich:Zitat:
ich versteh zwar nicht, warum der Servo am linken Anschlag bleibt
Das Servo bleibt nicht am linken Anschlag sondern startet dort einen neuen Demozyklus. Genau das macht "if(servopos > 25) servopos=5;" Wenn Position größer rechts dann Position=links.


Ich habe dabei darauf geantwortet:



jetzt schwenkt der motor mit 3 mal anhalten nach rechts und dann durchgehend nach links.


er hat gesagt, dass bei deinem Programm der Servo erst an einen Anschlag fährt und dann bleibt er stehen und dass er das nicht versteht warum...

dann habe ich gemeint, das könnte ich ihm auch nicht sagen, denn eigentlich müsste der Servo ja dauernd hin- und herfahren...


MfG Pr0gm4n

PS: ich mach nen Thread auf in AVR-C-Programmierung, die sollen sich den doch ma anschauen, ob alles passt

radbruch
01.05.2008, 18:59
erstmal sorry für all den mist den ich da geschrieben hab, frag mich grad, wie ich darauf gekommen bin...
Sorry für meinen pampigen Ton...


ich mach nen Thread auf in AVR-C-Programmierung

Gute Idee :)

Dirk
01.05.2008, 19:07
@radbruch:

Einzig ein Interrupt kann die Ausführungsdauer von Sleep() beeinflussen. Ein Ausschalten der Interrupts mit cli()/sei() führt hier aber nicht zum Ziel...
Warum nicht?
Der Impuls würde dadurch nicht unterbrochen und die Länge bliebe konstant, oder?

Gruß Dirk

P.S.: Zumindest habe ich es so in meinem blockierenden Beispiel gemacht,- funktioniert ganz gut. Auch die task_RP6System() ließ sich durch die 1-2ms Unterbrechung nicht irritieren (zumindest die Motorkontrolle).

radbruch
01.05.2008, 19:40
Warum nicht?
Weil Sleep() ohne Interrupts ins Nirwana stürzt. Dass ein Fast-Robotik-Einstein in so eine offensichtliche Falle tappt... *lol*

Dirk
02.05.2008, 07:25
();
Weil Sleep() ohne Interrupts ins Nirwana stürzt.
Stimmt ... :oops:

Ich hatte auch nicht Sleep, sondern delayCycles() genommen. Hatte ich vergessen. Damit klappt's natürlich.

Gruß Dirk

P.S.: Wir stellen uns doch hier keine "Fallen", oder? Wäre ja unfair ... und wenig hilfreich ... und ... ... Nein, das tun wir nicht ...