Skip to main content
shopping_basket Warenkorb 0
Einloggen

PYTHON – Automatisierung mit der „Monty-Sprache”: Teil 3

VdH
0

Wenn Sie diese Reihe verfolgen, haben Sie den Hardware-Aufbau aus Teil 1 bereits erfolgreich durchgeführt und den Installationsmarathon aus Teil 2 überlebt. Bisher haben wir allerdings noch kein einziges Byte Python-Code geschrieben. Das muss sich ändern.

Da ich gerne die interaktiven Möglichkeiten zum Testen und Debuggen nutzen möchte, verwende ich die Python-IDE „IDLE“, die im Lieferumfang des RevPi enthalten ist. Wir verwenden die VNC-Verbindung, um sie vom RevPi-Desktop aus zu starten:

Klicken Sie auf die rote Himbeere, öffnen Sie „Programming“ (Programmierung) und klicken Sie auf „Python 3“ (IDLE). Wenn Sie an der Diskussion über die Verwendung von Python 2 oder Python 3 interessiert sind, können Sie gerne über eine Internetsuche in diesen „Religionskrieg“ eintauchen. Folgen Sie mir fürs Erste einfach bei der Verwendung von Python 3 und ich garantiere Ihnen, dass Sie am Ende zufrieden sein werden ;-)

Wenn Sie dies getan haben, wird ein Fenster mit der Python-Shell geöffnet:

Die Meldung „>>>“ zeigt an, dass das System auf die Ausführung eines Python-Ausdrucks wartet. Python ist eine interpretierte Sprache und nichts wird im Vorfeld kompiliert. Alles, was Sie eingeben, wird ausgeführt. Geben Sie also den Ausdruck „4+5“ ein, drücken Sie <enter> und Sie erhalten die Systemantwort „9“:

>>> 4+5

9

>>> 

Ich nutze diese Möglichkeit häufig, um eine Codezeile auszuführen, wenn ich mir nicht sicher bin, ob die Syntax oder der Ergebnistyp korrekt ist. Wenn man z. B. 2^8 eingibt, um 2 mit der Leistung von 8 zu erhalten, erhält man:

>>> 2^10

10

Dies zeigt, dass die Syntax falsch ist, während bei 2**8 das gewünschte Ergebnis angezeigt wird:

>>> 2**8

256

Erwarten Sie hier keine Python-Referenz oder ein Python-Tutorial. Im Internet gibt es viel Material für Sie und ich ziehe häufig die offizielle Dokumentation zu Rate, um schnell Antworten zu finden.

Fast alle Python-Skripte verfügen zu Beginn über einen Abschnitt „import“. In diesem Abschnitt wird dem Interpreter mitgeteilt, welche Bibliotheken für das Skript verwendet werden sollen. Python verwendet Bibliotheken in hohem Maße. Ich bin überzeugt, dass dieses Konzept, einen minimalen Satz gemeinsamer Sprachelemente zu haben und den Rest den Bibliotheken zu überlassen, zu denen eine riesige weltweite Gemeinschaft beiträgt, der Kern des Erfolgs dieser Sprache ist. Alles beruht auf „Schwarmintelligenz“. Wenn Sie ein bestimmtes Problem haben, suchen Sie eine Python-Bibliothek im Internet und die Wahrscheinlichkeit ist hoch, dass Sie sie finden. Das ist der Fall beim PID-Steueralgorithmus. Ich habe z. B. „simple-pid“ gefunden. Bevor Sie eine Bibliothek verwenden können, müssen Sie sie meistens auf Ihrem System installieren. Ich verwende meine SSH-Sitzung (PuTTY), um den Shell-Befehl „sudo pip install simple-pid“ einzugeben (im folgenden Bildschirmauszug wurde die Bibliothek bereits installiert):

Übrigens: Dazu hätte ich auch ein Terminalfenster auf dem RevPi-Desktop verwenden können:

„pip“ ist ein großartiges Tool, das versucht, die Bibliothek aus einem zentralen Repository der Python-Organisation zu beziehen und dann auf Ihrem System zu installieren. Zuvor haben wir bereits „python3-revpimodio2“ und „revpipyload“ aus dem KUNBUS-Repository mit dem Linux apt-get-Befehl installiert.

Wenn die Installation erfolgreich war, führt Ihr Ausdruck zum Importieren dieser Bibliotheken nicht zu einer Fehlermeldung:

>>> from simple_pid import PID

>>> import revpimodio2

Okay, schreiben wir nun das Skript. Wir verwenden das Python-Shell-Menü „File“ -> „New File“ (Datei -> Neue Datei), um ein neues leeres Editorfenster zu öffnen und die Importausdrücke als die ersten beiden Zeilen einzugeben. Sie werden feststellen, dass der Editor Ihnen hilft, indem er Python-Schlüsselwörter sofort in einer anderen Farbe markiert.

Es ist ärgerlich, Zeit durch einen Systemabsturz zu verlieren, daher sollten Sie diese Datei regelmäßig abspeichern. Sie finden den Befehl unter „File“ -> „Save“ (Datei -> Speichern). Um diese Anweisungen zu befolgen, empfehle ich, sie im Verzeichnis „/home/pi“ unter dem Namen „myplc.py“ zu speichern.

Auf GitHub finden Sie viele Bibliotheken sowie Dokumentationen. Hier finden Sie unsere Bibliothek. Dort finden wir auch ein Beispiel, das die Nutzung sofort verständlich macht. Wir folgen dem Beispiel und erstellen eine Instanz „TempController“ der PID-Objektklasse durch den Ausdruck:

TempController = PID(1,0.1,0.0, setpoint=250, output_limits=(0,100))

In der Dokumentation für den Aufruf zur Initialisierung der Klasse sind die Funktionsparameter aufgeführt:

  • Kp = 1.0 Wert für die proportionale Verstärkung (als „Steuereinheit-Verstärkung“ bezeichnet)
  • Ki = 0.1 Wert für die integrale Verstärkung
  • Kd = 0.0 Wert für die derivative Verstärkung
  • Sollwert = 250 Anfangssollwert, den der PID-Regler zu erreichen versucht (in unserem Fall die Temperatur von 25 °C *10)
  • sample_time = 0.1 die Zeit in Sekunden, die die Steuereinheit warten soll, bevor ein neuer Ausgangswert generiert wird. Der PID-Regler funktioniert am besten, wenn er ständig aufgerufen wird (z. B. in einem Loop), jedoch mit einer Abtastzeit, die so eingestellt ist, dass der Zeitunterschied zwischen den einzelnen Aktualisierungen (annähernd) konstant ist. Bei der Einstellung „None“ (Keine) berechnet der PID-Regler bei jedem Aufruf einen neuen Ausgangswert. Ich verwende 100 ms, da ich mit der 10-W-Heizung sehr langsame Temperaturänderungen erhalte.
  • output_limits = (0, 100) Die zu verwendenden Ausgangsgrenzwerte, angegeben als wiederholbar mit zwei Elementen, z. B. (unterer, oberer Wert). Der Ausgang wird niemals unter den unteren Grenzwert fallen oder den oberen Grenzwert übersteigen. 
  • rpi.io.PWM_heater1.value = int(pwm)
    rpi.io.PWM_heater2.value = int(pwm)
    ​

    Einer der Grenzwerte kann auch auf „None“ (Keine) eingestellt werden, um in dieser Richtung keine Begrenzung zu haben. Durch das Festlegen von Ausgangsgrenzwerten wird auch eine Integriersättigung vermieden, da der Integralwert niemals die Grenzwerte über- oder unterschreiten darf. In unserem Fall möchten wir die PWM-Werte von 0 % bis 100 % verwenden.

    • proportional_on_measurement = False Legt fest, ob der Proportionalwert direkt am Eingang und nicht am Fehler berechnet werden soll (was die traditionelle Methode darstellt). Durch die Verwendung von „proportional-on-measurement“ wird bei einigen Systemtypen ein Überschwingen vermieden. Ich verwende als Standardeinstellung „= False“.

    •  

      auto_mode = True Dies ist die Standardeinstellung (PID-Regler aktiviert)

Wenn Sie mit PID-Steueralgorithmen nicht vertraut sind, können Sie auf dieser Seite weitere Erläuterungen zu den Einstellungsparametern Kp, Ki und Kd finden. Wir können diese Einstellungsparameter nicht vorhersagen und müssen sie durch Testen des Regelverhaltens einstellen (siehe weiter unten in diesem Artikel).

Außerdem müssen wir eine Instanz der Revpimodio-Klasse erhalten. Anhand der Dokumentation auf den revpimodio-Webseiten können wir den Aufruf zur Initialisierung dafür finden:

rpi = revpimodio2.RevPiModIO(autorefresh=True)

Es gibt drei Funktionen, die wir zyklisch aufrufen müssen, um den PID-Regler zu betreiben:

Die erste ist das Abrufen der Ist-Temperatur aus dem Prozessabbild:

Temp = rpi.io.Temp10.value

Die zweite ist die Berechnung des PID-Ausgangswerts:

pwm = TempController(Temp)

Die letzte ist die Einstellung der PWM-Ausgänge auf den berechneten Wert durch Schreiben in das Prozessabbild:

Da der PWM-Wert im Prozessabbild eine vorzeichenlose Ganzzahl ist, müssen wir den PID-Ausgang anhand der Funktion „int()“ konvertieren. Ich habe diese vier Zeilen mithilfe der While-Schleife von Python in einer Endlosschleife mit dem Argument „True“ platziert. Wenn Sie nicht mit Python vertraut sind, beachten Sie bitte, dass in Python keine {}-Paare zum Gruppieren von Code vorhanden sind. Der Code wird mithilfe des „Leerzeichens“ (= Einrückung) gruppiert, was Sie vor den vier Statements in der While-Schleife sehen können.

Da wir über ein Multitasking-Linux-System verfügen, möchten wir die CPU nicht durch eine straffe Endlosschleife in unserer Aufgabe blockieren. Daher verwende ich die Bibliothek „time“ und die Funktion „sleep(n)“, um die Schleife mit einer Pause von 0,05 Sekunden zu versehen. Um jede Sekunde Debug-Ausgänge zu erhalten, habe ich zudem eine Zählervariable hinzugefügt, die in jedem Zyklus der Schleife bis auf 20 erhöht wird und nach dem Drucken der Ein- und Ausgabewerte auf 0 zurückgesetzt wird.

Hier ist das komplette Programm:

from simple_pid import PID
import revpimodio2
import time

TempController = PID(5,0.13,10.5, sample_time=0.1, setpoint=400, output_limits=(0,100))
rpi = revpimodio2.RevPiModIO(autorefresh=True)
n=0
while True:
    Temp = rpi.io.Temp10.value
    pwm = TempController(Temp)
    rpi.io.PWM_heater1.value = int(pwm)
    rpi.io.PWM_heater2.value = int(pwm)
    n +=1
    if n==20:
        n=0
        print(Temp, int(pwm))
    time.sleep(0.05)

Wenn Sie dieses Skript mit <F5> oder über das Menü „Run“ -> „Run Module“ (Ausführen -> Modul ausführen) starten, wird der zyklische Wert im Python-Shell-Fenster angezeigt. Sie können die Ausführung anhalten, indem Sie „STRG C“ drücken.

Jetzt ist es an der Zeit, mit den Einstellungswerten zu experimentieren. Diese sind sicherlich von der physikalischen Rückmeldung zwischen Wärmequelle und Temperatursensor abhängig. Ich möchte diese Rückmeldung annähern. Daher habe ich einen kleinen Abstand zwischen dem Sensor und den Glühlampen gewählt:

I could also put them in a case or aluminium foil which catches the heat.

Ich könnte sie auch in ein Gehäuse oder in Aluminiumfolie legen, die die Wärme speichert.

In meinem Fall konnte ich jedoch mit zwei 10-W-Heizquellen und einer Solltemperatur von ca. 40 °C die drei Einstellungsparameter anpassen, um eine nahezu perfekte Regelung zu erzielen. Dazu stellte ich Ki und Kd auf 0 ein. Bei den Werten 1, 5, 10 und 20 für Kp konnte ich eine stabile Endtemperatur für 10 beobachten. Das bedeutet: Für jede Unterschreitung des Sollwerts von 0,1 °C gibt die Regelfunktion eine 10 % höhere PWM beim Einschalten zurück. Bei einem Wert von 20 traten Schwingungen von mehr als 1 °C auf. Dann nahm ich die Hälfte des stabilen Werts 10, also 5 für Kp. Dies resultierte in einer sehr stabilen Endtemperatur, die einen negativen Offset des Sollwerts aufwies – statt 40 °C erreichte die Temperatur nur ca. 39 °C. Ich begann, Ki sehr langsam anzuheben, was den Offset ausglich, die Oszillation jedoch verstärkte. Mit einem Wert von 0,13 erhielt ich eine stabile Spitzenschwingung von 1 °C um den Sollwert von 40 °C. Beim Erhöhen von Kd „injizierte“ der Regler kurze Impulse in einen höheren oder niedrigeren PWM-Wert. Dadurch wurde die Schwingung verringert. Schließlich erhielt ich einen Wert von ca. 10 für Kd mit einer Schwingung von +/- 0,1 °C (was der Gesamtpräzision der Temperaturmessung entspricht). Hier sehen Sie das Ergebnis der Einstellung:

Um 15:57 Uhr wurde der Regler bei einer Umgebungstemperatur von 34 °C eingeschaltet (ja, in kriege den Klimawandel in meinem Büro zu spüren!). Um 15:59 Uhr (nach 2 Minuten) erreichte die Temperatur einen stabilen Wert von 40 °C (Sollwert). Die zweite Abbildung zeigt die sehr geringe Schwingung um den Sollwert.

Wenn Ihre Textausgabe einen akzeptablen Rückführungskreis anzeigt, können Sie mit dem nächsten Schritt fortfahren: mit der Erstellung einer kleinen GUI für unseren Heizungsregler unter Verwendung von MQTT und Node-Red, um schöne Diagramme wie die oben dargestellten Zeitverläufe zu erhalten. Aber alles Weitere dazu in Teil 4

Volker de Haas started electronics and computing with a KIM1 and machine language in the 70s. Then FORTRAN, PASCAL, BASIC, C, MUMPS. Developed complex digital circuits and analogue electronics for neuroscience labs (and his MD grade). Later: database engineering, C++, C#, industrial hard- and software developer (transport, automotive, automation). Designed and constructed the open-source PLC / IPC "Revolution Pi". Now offering advanced development and exceptional exhibits.

Verwandte Inhalte

DesignSpark Electrical Logolinkedin