In der Anlage haben wir einen Problem. Die Platte wird zustark geschwingt und die Kugel rollt nicht genau in die gewünschte Position. Die Servomotoren zappeln in ihrer Ruhelage. Kann mir jemand helfen?
Kann man den Fehler denn im Programmcode sehen? Stimmt das Modell? Stimmt der Scheduler? Rauscht der Sensor?
Verstehe ich das richtig? Es gibt also eine Fläche die mit infrarotsensoren (photodioden?) ausgestattet ist, mit welchen die Position einer Kugel auf der Fläche bestimmen werden kann. Der Mittelpunkt der Fläche ist der nullpunkt des Koordinatensystems. Die Fläche kann um die X und Y Achse des Koordinatensystems rotiert werden. Die Rotationsberechnung im Code war:
1 | ex = (xsoll - posx); |
2 | phix = phix0 - ( ex*KP + KD * (ex - exalt)); |
3 | exalt = ex; |
Somit ist e der Vector von pos nach soll. KP und KD sind vermutlich von der Trägheit der Kugel und der Fläche abhängende experimentell ermittelte konstanten. e - ealt ist eine ungenaue verrauschte Berechnung des Beschleunigungsvektors der Kugel. Dieser wird verwendet um zu verhindern, dass die Kugel zu schnell wird. Das System weist nun eine ungenauigkeit und instabilität auf, dessen uhrsache gefunden und behoben werden müssen. Die Genauigkeit des systems ist u.a. von der Auflösung der Sensoren und Aktoren, sowie der Genauigkeit der Berechnung abhängig. Um die genauigkeit des systems zu erhöhen muss vermutlich die formel prezieser, die Kugel mit einem Objekt mit mehr reibung ersetzt, und die uhrsachen des zappelns der Servomotoren ermittelt werden.
Allenfalls sind die Aktoren nichts. Servos, im speziellen Modellbauservos haben einen endliche Aufloesung. Dadurch werden sie immer etwas zappeln. Zudem zappeln analoge Servos sobald sie Drehmoment aufbringen muessen. Allenfalls ist der Regelkreis auch noch zu langsam.
:
Bearbeitet durch User
Ich wiederrum denke, dass ein PD Regler ganz einfach dazu nicht geeignet ist. Da muss schon ein PI Regler ran. Man kann ihm noch ein D Glied spendieren aber ohne I Glied wird es immer eine Regelabweichung geben. Der Rest ist dann: Ein PID Regler steht und fällt mit seinen Koeffizienten. Wenn dir die Auflösung (wegen Integer Rechnung) nicht ausreicht um die Koeffizienten fein genug variieren zu können, dann muss man eben auf Fixpunkt Arithmetik ausweichen um sich eine (oder mehrere) 'Kommastellen' zuschaffen.
:
Bearbeitet durch User
Im übrigen: Du hast ein LCD. Das kann man auch benutzen um sich nicht nur die Dinge ausgeben zu lassen, die man ohnehin an den Servos sieht (nämlich welche Position sie anfahren sollen). Das kann man auch benutzen um sich zb so Dinge wie Regelfehler oder Summe des Regelfehlers ausgeben zu lassen und dann daraus seine Schlüsse zu ziehen, wie es kommt, dass phix sich nicht auf einen konstanten Wert einregelt. Hilfreich ist dazu natürlich, wenn man mal anfangen würde sich ein paar Komfortfunktionen zu bauen. Und das beginnt damit, dass man sich erst mal ein paar vernünftige LCD Funktionen baut. In dem Zustand, in dem die jetzt sind, sind sie zwar die unterste Ebene, aber der ganze Mittelbau fehlt da und das ist schwachsinnig. Wenn man für eine Wertausgabe da jedesmal die Sequenz
1 | BOD = 0; |
2 | SDatLCD = 0x83; //DDRAM address 00 |
3 | LCDWriteByte(); //1. Zeichen 1. Zeile |
4 | BOD = 1; |
5 | |
6 | sprintf(zeile1, "%3d", phix); |
7 | for (i = 0; i < 6; i++) { |
8 | SDatLCD = zeile1[i]; |
9 | LCDWriteByte(); |
10 | };
|
selbst hinprogrammieren muss, anstatt da ein paar Hilfsfunktionen zu haben
1 | void lcdString( const char* str ) |
2 | {
|
3 | while( *str ) { |
4 | SDatLCD = *str++; |
5 | LCDWriteByte(); |
6 | }
|
7 | }
|
8 | |
9 | void lcdInt( int wert ) |
10 | {
|
11 | char buffer[10]; |
12 | sprintf( "%3d", wert ); |
13 | lcdString( buffer ); |
14 | }
|
so dass man anstelle des Originalwustes zumindest mal schreiben kann
1 | BOD = 0; |
2 | SDatLCD = 0x83; //DDRAM address 00 |
3 | LCDWriteByte(); //1. Zeichen 1. Zeile |
4 | BOD = 1; |
5 | |
6 | lcdInt( phix ); |
und sich dann vielleicht sogar noch eine Funktion schreibt, mit der man den Cursor dadurch positioniert, indem man Zeile und Spalte angibt
1 | void lcdGoto( int zeile, int spalte ) |
2 | {
|
3 | ....
|
4 | }
|
so dass man dann nicht mehr als Programmierer selbst die 0x83 ausrechnen muss, sondern nur noch
1 | ...
|
2 | lcdGoto( 0, 0 ); |
3 | lcdInt( phix ); |
4 | |
5 | lcdGoto( 1, 0 ); |
6 | lcdInt( phiy ); |
7 | ...
|
schreibt, dann verliert auch die Ausgabe der anderen internen Werte ihren Schrecken, weil sich das einfach und simpel während der Entwicklung machen lässt. So wie es jetzt ist, ist das LCD Subsystem zu simpel gestrickt, so dass klarerweise jeder davor zurückschreckt Werte wie zb den gemessenen IstWert mal auf dem LCD ausgeben zu lassen. Fazit: Etwas Zeit in Basisroutinen zu investieren lohnt sich, wenn dadurch die restliche Programmentwicklung einfacher und schneller wird. Und dann kann man auch mal die Werte online und live studieren um rauszufinden ob und was da schwingt und warum die Servos ständig neue Positionen anfahren sollen und wie sich diese neuen Positionen aus den gemessenen Istpositionen und der Regelgleichung ergeben. Und plötzlich ist man dann tatsächlich Entwickler der aktiv an seinem Programm arbeitet und nicht mehr Fragesteller in einem Forum, der andere braucht um rauszufinden warum das von ihm Hingeklatschte dynamische System nicht funktioniert.
:
Bearbeitet durch User
Mein Input dazu. Man MUSS ein UART haben, das mit dem PC kommunuiziert. Mit dem kann man dann online Parameter verstellen, Werte aufzeichen und uebertragen. Und wenn die Geschwindigkeit nicht hinkommt, spendiert man einen 8 fach DAC, auf dem dann Echtzeitwerte, die man nicht sowieso messen kann, ausgibt, damit man sie zusammen mit den anderen Signalen auf dem Oszilloskop verfolgen kann.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.