hallo,
wie errechnest du Ta?
wie sind deine ganzen Variablen definiert?
wie sieht die komplette Schleife aus, incl aller delays, und samt Motor-Befehlen?
Hallo!
Ich bin in Sachen Regelungstechnik ein blutiger Anfänger und hoffe, dass mir hier vielleicht jemand mit ausreichend Fachwissen behilflich sein kann
Ich arbeite zurzeit im Rahmen eines Projekts daran die Abstandsregelung eines Roboters mit Mecanum Rädern zu realisieren. Der Roboter ist von der Firma Makeblock und wird über einen Arduino Uno programmiert.
Ansteuerung der Motoren funktioniert, den Regler habe ich als PID-Regler ebenfalls bereits implementiert. Der Code dazu sieht so aus:
Die Tastzeit Messungen haben Werte zwischen ca. 17000 und 25000 µs ergeben. Nun wollte ich versuchen, vernünftige Werte für die Regler Parameter zu finden. Dazu wollte ich zunächst empirisch vorgehen. Deshalb habe ich mit einem kleinen Wert für den P Anteil angefangen. Grundsätzlich verhält der Regler sich auch richtig (Roboter versucht Soll-Abstand herzustellen), allerdings fällt eine Sache mMn schwer ins Gewicht. Der Roboter scheint "zeitversetzt" auf den Regelfehler zu reagieren. Ich habe dann mit den Werten rum experementiert, habe es allerdings nicht geschafft bessere Regelergebnisse zu erhalten. Das Problem mit der zeitlichen Verzögerung fällt meiner Vermutung nach zu schwer ins Gewicht. Zum besseren Verständnis des Problems habe ich mal ein kleines Video angehängt (hier ist nur ein P-Anteil von 1,5 vorhanden).Code:if(currentMicros - previousMicros > TaMicros) { previousMicros = currentMicros; //Fehler bestimmen e = d_soll - d_ist; //Integration approximieren; mit Anti-Windup-> wenn Stellgröße zu groß Aufintegrieren stoppen if((vy < 1) && (vy > -1)) esum = esum + e; //Reglergleichung vy = -( Kp*e + Ki*Ta*esum + Kd*(e-ealt)/Ta ); //Ableitung approximieren ealt = e; //Stellgröße begrenzen if(vy > 1) vy = 1; if(vy < -1) vy = -1;
Kann es sein, dass ich es hier mit einer sehr großen Totzeit der Regelstrecke zu tun habe? Und wenn ja, gibt es eine Möglichkeit diese zu umgehen?
Vielen Dank im Voraus!
hallo,
wie errechnest du Ta?
wie sind deine ganzen Variablen definiert?
wie sieht die komplette Schleife aus, incl aller delays, und samt Motor-Befehlen?
Hi, schon mal danke für deine Antwort!
Ta habe ich mithilfe dieses Codes gemessen (am Ende der Loop platziert):
Dabei kamen dann Werte zwischen 17000 und 25000 µs raus, was ich als Taktzeit interpretiert habe. Ich habe dann für Ta einfach mal einen Wert in der Mitte angenommen. Meine Variablen sind wie folgt definiert:Code:unsigned long cycleTime; unsigned int cycleCount; cycleCount++; if (cycleCount>=100) { Serial.print("Cycle Time: "); Serial.print((micros()-cycleTime)/cycleCount); Serial.println(" microseconds"); cycleCount=0; cycleTime=micros();
Die Loop-Schleife sieht dann so aus:Code:float d_soll = 0.4, d_ist; float e, esum = 0, ealt = 0; unsigned long TaMicros = 20000; //Abtastzeit in Mikrosekunden float Ta = (float)TaMicros/1000000; unsigned long currentMicros; unsigned long previousMicros = 0; float vy = 0; float Kp = 1.5; float Ki = 0; float Kd = 0;
Hoffe das ist ausreichend, um dir eine Ahnung zu von dem was ich treibe zu verschaffenCode:currentMicros = micros(); d_ist = ultraSensor.distanceCm()/100; //Methode des Herstellers (eigene Library) zum Auslesen des Sensors regelung(); //ist in meinem ersten Post enthalten motor1.runSpeed(vy,0); //Methoden des Herstellers zum Ansteuern der Motoren motor2.runSpeed(vy,0); //Umrechnung in für den Motor zu verarbeitende Drehzahlen findet an anderer Stelle statt motor3.runSpeed(vy,0); motor4.runSpeed(vy,0);
meine ersten Ideen:
Einheit aller Timestamps immer in identischen Einheiten berechnen (also immer micros oder immer millis)
Du solltest die Zeit pro Schleifendurchlauf exakt stoppen (machst du glaube ich per cycletime)
Ta müsste exakt die Dauer des aktuellen Schleifendurchlaufs sein, also Ta=(float)cycletime (kannst du auch direkt einsetzen, ohne zusätzliches Ta)
Die delays pro Schleife würde ich so wählen, dass ca. 10 millisec = 10000 micros pro Schleife anfallen
Kp, Ki und Kd können theoretisch durchaus Werte zwischen 0.001 bis 1000000 annehmen, also nicht begrenzen
Ki allerdings neigt zu übermäßigem Aufsummieren, daher zusätzlich mit einem Dämpfungsfaktor multiplizieren:
esum = 0.7*( esum + e);
edit:
der Dämpfungsfaktor (hier 0,7) mag irgendwo zwischen 0,5 und 0,9 liegen
Geändert von HaWe (03.03.2018 um 10:27 Uhr)
Mir scheint der Roboter nicht zeitlich sondern räumlich versetzt zu starten, als wenn die Antriebe erst bei einer bestimmten Reglerausgabe oder Schwellwert anlaufen. Du kannst vielleicht eine Fahrprobe machen mit Spannungen vom einem Poti vorgegeben, um zu schauen, ob die Antriebe eine Anlaufspannung haben. Wenn du diese Anlaufspannung herausrechnest, könnte das Regelverhalten besser werden.
Geändert von witkatz (02.03.2018 um 20:32 Uhr)
Bei meinem archie rechne ich auf nem mega1284/20MHz. Dort ist für zwei Regelkreise PID (rechter und linker DC-Motor - also Motor vor dem Getriebe/Antriebsstrang) genug Zeit um mit 100 Hz zu regeln. JEDE Seite separat, also zeitversetzt mit brutto 200 Hz. Regelung im Interrupt, Drehzahl/Drehzeit wird per Interrupt auf Flanken des Encoders gemessen. Geregelt wird nur mit Integers, mittlerweile 16bittig. Mein MiniD0 regelte noch 8bittig - sonst vergleichbare Regelung, aber im selben Zeitraster. Etwa doppelt so schnell wie Du; wie Deine Tastzeit vermuten lässt... Tastzeit Messungen .. 17000 und 25000 µs .. Werte für die Regler Parameter zu finden .. scheint "zeitversetzt" auf den Regelfehler zu reagieren ..
Was ist bei Dir die Tastzeit ? Die Abtastzeit der Drehzeiten von Motor oder Antriebsstrang oder die Abstände für die Regelung ?
Wie schnell, in welchem Zeitraster stellst Du die Drehzeiten bereit ?
. . . . . . Interrupt oder im Hauptprogramm ?
Wie schnell, in welchem Zeitraster wird die Regelung gefahren ?
. . . . . . Interrupt oder im Hauptprogramm ?
Wie genau ist die Drehzeiterfassung ? In Sekunden und Drehwinkel.
Was wird geregelt? Motordrehzahl oder Raddrehzahl ?
Kann es sein, dass Du in Deinen Rechnungen alles oder einige Werte FP rechnest (floating point) ? Denn das ist recht zeitintensiv.
Grundsätzlich hatte ich zu Beginn der Regelung immer ne Sprungantwort aufgenommen, natürlich im "Endausbau" des Fahrzeugs. Daraus hatte ich dann die Regelungskennwerte abgeschätzt - Motorzeitkonstante, Parameter für P, I und D. Einen gewissen Fortschritt brachte es für mich, als ich mir die Skizze der Regelungsschleife hernahm und alle Größen mit MEINEN Namen beschriftet hatte. Sieh mal hier (klick). Das brachte - mir - den Durchblick. Nochn bisschen über meinen Regelungsaufwand steht hier.
Vielleicht helfen Dir diese Anmerkungen etwas weiter?
Ciao sagt der JoeamBerg
wieso braucht er Encoder?
Und wieso muss er die Geschwindigkeit oder Drehzahl "messen"?
Gemessen und geregelt wird doch wohl der Abstand zum anderen Fahrzeug, und zwar je nach Abstand mit verschieden schnellen Motordrehzahlen (über pwm vermutlich) und ggf. mit Richtungsumkehr.
Ansonsten halte ich den Ansatz schon für richtig, so wie er ist, mit ein paar kleineren Änderungen.
https://www.roboternetz.de/community...l=1#post642966
Der Rest ist Tuning und Fein-Tuning von Kp, Ki und Kd.
edit,
PS:
auch der PID-Regler PID_v1 für Arduinos rechnet immer mit float, und das ist auch auf AVRs absolut schnell genug.
Geändert von HaWe (03.03.2018 um 12:28 Uhr)
Lesezeichen