Sie müssen zwei Probleme behandeln:
- arithmetischer Überlauf
- Integrator Windup
Der arithmetische Überlauf recht einfach ist - wann immer Sie integer Mathe tun, stellen Sie sicher , dass Sie größere Breitenzwischenwerte verwenden: zum Beispiel, wenn a
und b
sind 16-Bit, und Sie addieren / subtrahieren, verwenden Sie eine 32-Bit - Zwischen und begrenzen Sie ihn auf den Bereich eines 16-Bit-Werts (0 bis 65535 für vorzeichenlose Werte, -32768 bis 32767 für vorzeichenbehaftete Werte), bevor Sie ihn auf 16 Bit zurücksetzen. Wenn Sie absolut sicher sind , dass Sie niemals überlaufen können, weil Sie absolut sicher sind , welche Bereiche die Eingabevariablen haben, können Sie diesen Schritt überspringen, aber Vorsicht.
Das Problem mit dem Integrator-Windup ist subtiler. Wenn Sie über einen längeren Zeitraum einen großen Fehler haben, so dass Sie die Sättigungsgrenze Ihres Controller-Ausgangs erreichen, der Fehler jedoch immer noch ungleich Null ist, sammelt der Integrator weiterhin Fehler an und wird möglicherweise viel größer, als er erreichen sollte Gleichgewichtszustand. Sobald der Controller nicht mehr gesättigt ist, muss der Integrator wieder heruntergefahren werden, was zu unnötiger Verzögerung und möglicherweise zu Instabilität der Controller-Reaktion führt.
Noch ein Hinweis:
Ich würde dringend empfehlen (ja, ich weiß, dass diese Frage 18 Monate alt ist, also sind Sie wahrscheinlich mit Ihrer Aufgabe fertig, aber zum Wohle der Leser tun wir so, als wäre dies nicht der Fall), den Integralbegriff anders zu berechnen: Anstelle von Ki * (integrierter Fehler), Integral von (Ki * -Fehler) berechnen.
Dafür gibt es mehrere Gründe. Sie können sie in einem Blogbeitrag lesen, den ich über die korrekte Implementierung von PI-Controllern geschrieben habe .
<stdint.h>
füruint8_t
unduint16_t
anstelle vonunsigned int
undunsigned char
.unsigned
Variablen für einen PI-Regler? Dies erhöht die Komplexität Ihres Codes. Die einzelnenif/else
Fälle sind nicht erforderlich (es sei denn, Sie verwenden je nach Fehlerzeichen unterschiedliche Verstärkungen). Sie verwenden auch den absoluten Wert der Ableitung, der falsch ist.PID_derivative
Zuordnung an. Sie erhalten den gleichen Wert, wenn SiePID_error
und wechselnPID_lastError
. Und im Übrigen haben Sie bereits dasPID_error
Vorzeichen verloren: Wenn Sie das letzte MalsetMotorSpeed =8
undcurrentMotorSpeed = 15
und dieses MalsetMotorSpeed = 15
undcurrentMotorSpeed = 8
, dann erhalten Sie denPID_derivative
Wert 0, was falsch ist.unsigned char
es sich um einen 8-Bit-Typ undunsigned int
einen 16-Bit-Typ handelt: WennPID_kd = 8
undPID_derivative = 32
, dann ist ihr Produkt(unsigned char)256 == 0
, weil in C auch das Produkt zweier Ganzzahlen desselben Typs T von diesem ist Gleicher Typ T. Wenn Sie eine 8x8 -> 16-Multiplikation durchführen möchten, müssen Sie einen der Begriffe vor der Multiplikation in eine vorzeichenlose 16-Bit-Zahl umwandeln oder einen Compiler verwenden (MCHP nennt sie "Builtins") Geben Sie eine 8x8 -> 16 Multiplikation.