Hey! Sie scheinen aus United States zu kommen, möchten Sie auf die Englisch Webseite wechseln?
Switch to Englisch site
Skip to main content

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

Nun sind Sie bei Teil 4 angelangt. Wenn Sie eine Zusammenfassung benötigen, lesen Sie sich Teil 1, Teil 2 und Teil 3 durch.

Wir führen die GUI für unser System auf demselben RevPi-System aus, auf dem der PID-Regler ausgeführt wird. Es kann mit jedem Browser darauf zugegriffen werden. Zunächst müssen wir jedoch einen MQTT-Broker installieren.

Wir kehren zu unserer PuTTY-Sitzung zurück und verwenden den folgenden Befehl, um einen MQTT-Broker auf diesem System zu installieren:

sudo apt-get install mosquitto mosquitto-clients

Was ist die Aufgabe eines MQTT-Brokers? Er akzeptiert Werte, die von Clients stammen. Die Clients „veröffentlichen“ solche Kennzahlen („Metrics“) unter einem Thema („Topic“), einer Art benanntem Container. Andere Clients können solche Themen „abonnieren“. Sobald ein neuer Wert an den Broker gesendet wird, leitet er diesen Wert an alle Clients weiter, die das Thema des Werts abonniert haben. Sie könnten diese Datenverteilung durch Verschlüsselung sichern, für diese Demonstration verzichte ich jedoch der Einfachheit halber auf die Verschlüsselung.

Der RevPiPyLoad-Dienst kann so konfiguriert werden, dass alle E/A-Werte aus dem mit „export“ gekennzeichneten Prozessabbild für einen MQTT-Broker veröffentlicht werden. Kehren wir zur RevPiPyControl-Anwendung zurück und öffnen „PLC“ -> „PLC options...“ (SPS -> SPS-Optionen...). Es wird ein neues Fenster angezeigt:

image075_51203798601db56c853b13efbb65310eb68b2ea0.jpgimage077_695f3419862047e13cfd2ef88e1225c4dffb9137.jpgimage0791_7884c79a6113376f8fec24ea537b637e5dbf2fe8.jpg

Stellen Sie im Abschnitt „RevPiPyLoad Server Services“ (RevPiPyLoad-Serverdienste) die Kennzeichnung auf „MQTT Process Image Publisher“ (MQTT-Prozessabbild-Publisher) und klicken Sie auf „Settings“ (Einstellungen). Verwenden Sie die Einstellung des Bildschirmauszugs dieser Demonstration. Wenn Sie einen MQTT-Broker an einer beliebigen Stelle in Ihrem Netzwerk verwenden, sollten Sie eine Verlängerung des Veröffentlichungsintervalls von 1 Sekunde auf z. B. 10 Sekunden in Betracht ziehen.

Klicken Sie zweimal auf „Save“ (Speichern) und Ihr RevPi beginnt sofort mit der Veröffentlichung der Kennzahlen aus dem Prozessabbild an den Mosquitto MQTT-Broker. Jeder Client kann diese Themen abonnieren,

  • RevPiProcessImage/event/PWM_heater1
  • RevPiProcessImage/event/PWM_heater2
  • RevPiProcessImage/event/Temp10
  • RevPiProcessImage/io/PWM_heater1
  • RevPiProcessImage/io/PWM_heater2
  • RevPiProcessImage/io/Setpoint
  • RevPiProcessImage/io/Temp10

um die veröffentlichten Werte zu empfangen.

Wir verwenden Node-Red als MQTT-Client, um diese Werte zu abonnieren und sie auf einer Benutzeroberfläche anzuzeigen. Node-Red ist ein wunderbares Tool zur Software-Erstellung per Drag & Drop. Es wurde von IBM entwickelt und an den Open Source-Pool der JS-Foundation übergeben. Die IDE funktioniert browserbasiert und Sie können ganz einfach sogenannte „Flows“ (Nachrichtenflüsse) einrichten. Sie müssen lediglich „Node“-Komponenten aus einer Auswahl vordefinierter Nodes (Knoten) in einen Flow ziehen und ablegen. Anschließend verbinden („wire“) Sie die Node-Ausgänge über die Maus mit den Node-Eingängen. Alle Nodes können durch Anklicken mit Parametern konfiguriert werden.

Node-Red ist auf jedem RevPi vorinstalliert und dieser Serverdienst muss nur gestartet werden. Mit den folgenden Befehlen (verwenden Sie Ihre PuTTY-Sitzung) starten und schalten Sie Node-Red dauerhaft ein:

sudo systemctl enable nodered.service
sudo systemctl start nodered

Wenn Sie „Flows“ programmiert und gespeichert („deployed“ [bereitgestellt]) haben, werden sie nach dem Start automatisch ausgeführt (Sie müssen jetzt nicht neu starten, Node-Red wurde bereits manuell gestartet).

Wir müssen neue „Nodes“ zur Node Red-IDE hinzufügen, daher installieren wir „npm“ (den Paketmanager für das JavaScript-Laufzeitsystem „Node.js“) mit dem folgenden Befehl:

sudo apt-get install npm

Wir sind fast fertig – wir müssen nur den Flow einrichten. Ich kann die IDE mit meinem Browser über den PC unter der folgenden IP-Adresse und Portadresse erreichen: http://192.168.0.241:1880 (Sie müssen sie durch die IP-Adresse Ihres RevPi ersetzen). Die IDE-Sprache ist die bevorzugte Sprache Ihres Browsers.

In der linken Seitenleiste finden Sie alle „Nodes“, die Sie in den leeren Flow in der Mitte des Fensters ziehen und ablegen können. Wir müssen die Dashboard-Nodes (Benutzeroberflächen-Knoten) hinzufügen. Dank npm geht dies schnell, indem Sie auf das Menüsymbol (rechte obere Ecke) klicken und „Manage Palette“ (Palette verwalten) auswählen. Wählen Sie die Registerkarte „Install“ (Installieren) und geben Sie „Dashboard“ als Suchzeichenfolge ein. Geben Sie dem System etwas Zeit, um die Ergebnisse abzurufen, wählen Sie „node-red-dashboard“ und klicken Sie auf „Install“ (Installieren). Schließen Sie dann den Paletten-Manager und aktualisieren Sie Ihren Browser (F5). Die neu installierten Nodes befinden sich nun in der Palette auf der linken Seite unter dem Titel „Dashboard“.

Gehen Sie zum Abschnitt „Input“ (Eingabe) in der Palette und ziehen Sie den MQTT-Node in den Ablaufbereich und legen Sie ihn ab. Doppelklicken Sie auf den Node, um ihn zu konfigurieren:

image083_f6d5f229acad936f20cb0fd062064e40bb115e7a.jpg

Geben Sie das Thema „RevPiProcessImage/io/Temp10“ ein und klicken Sie auf „Done“ (Fertig). Wir möchten, dass die Temperatur in °C angezeigt wird. Daher muss die Kennzahl aus dem Prozessabbild (das wir vom MQTT-Broker erhalten) mit 10 multipliziert werden. Dies kann mit einem „Funktions“-Node (dem ersten Node unter dem Abschnitt „Function“ (Funktion)) erfolgen. Ziehen Sie ihn rechts neben den MQTT-Node, legen Sie ihn dort ab und doppelklicken Sie darauf, um ihn zu konfigurieren:

image085_36a685f53c17ebfbb30ad2beecf3d19745f1a47f.jpg

Der „Function“-Editor (Funktion) ermöglicht die Eingabe von Java-Code. Alle Nodes kennen das Objekt „msg“, also die Nachricht, die von ihm empfangen und ausgesendet wird. Um den Inhalt einer Nachricht zu ändern, verwenden wir seine „Payload“ (Nutzdaten) (den primären Inhalt aller Node-Nachrichten, Sie können bewusst jede neue Inhaltsvariable hinzufügen). Somit erledigt „msg.payload = msg-payload/10“ die auszuführende Aufgabe. Klicken Sie auf „Done“ (Fertig).

Fügen Sie nun zwei Dashboard-Nodes hinzu, ziehen Sie sie rechts neben den Funktions-Node und legen Sie sie dort ab:

Der „Gauge Node“ (Messknoten) und der „Chart Node“ (Diagrammknoten) sind wie folgt konfiguriert:

image087_6ae760fcf22dee35add9d70fdea8eb74b1096a1c.jpgimage089_79746cf3cf9e5b578d914b6605386af5ca3606a6.jpg

Jetzt verbinden („wire“) wir die Nodes durch Klicken auf die kleinen Kreise am rechten Rand der Nodes (=Ausgabe des Knotens), halten die Maustaste gedrückt und zeichnen eine Linie zu einem Kreis am linken Rand eines Nodes (=Eingabe). Wie Sie sehen, können Sie mehrere Verbindungen an einem Kreis verwenden:

image091_c0c518e5f07562e87971b7e842c633f1883eb977.jpg

Die blauen Punkte signalisieren nicht gespeicherte („undeployed“) Nodes. Wir klicken also auf „Deploy“ (Bereitstellen) und unser Flow wird ausgeführt. Wenn eine MQTT-Nachricht empfangen wird, wird ihr Wert mit 10 multipliziert und als Eingangswert für das Element der Benutzeroberfläche verwendet. Doch wie können wir das Ergebnis sehen? Das ist ganz einfach: Öffnen Sie einfach ein Browserfenster unter http://192.168.0.241:1880/ui (ersetzen Sie die IP durch die IP-Adresse Ihres RevPi):

image093_174bbbf28e98a287e2018cbfebac96c251f92ce3.jpg

Verwenden Sie das Menü „Dashboard“ auf der rechten Seite, um den Namen der Benutzeroberflächenseite („Home“) und den Gruppennamen („Default“) zu einem gewünschten Text zu ändern:

image0951_5f9c56a893404daf004293740f58e23ee03e4bb3.jpg

Ich füge als Lernaufgabe für Sie ein Diagramm und eine Messanzeige für den PWM-Wert hinzu. Sie sollten das MQTT-Thema „RevPiProcessImage/event/PWM_heater1“ verwenden.

image0971_4627c7ec857c1badd073fc01ea68b86a5ea59ba4.jpg

image099_a53dd48fce32689b80c68442bdb1ed041dc2b8da.jpg

Wenn Sie unser Demonstrationsprojekt weiterhin spannend finden, können Sie weitermachen und einen Sollwert-Schieberegler hinzufügen:

Ich ziehe einen Schieberegler in den Flow, lege ihn ab und füge ihn einer dritten Benutzeroberflächengruppe namens „Setpoint“ (Sollwert) hinzu (ich verwende einen Bereich von 30 bis 50 °C mit einer Schrittgröße von 0,5 und einem Ausgang, der auf „Only on release“ [Nur bei Freigabe] eingestellt ist). Ich verbinde diesen Node mit einem MQTT-Ausgangs-Node. Der MQTT-Ausgangs-Node ist mit dem Veröffentlichungsthema „Setpoint“ (Sollwert) konfiguriert:

image101_bf710a32861a2575a13dc904be48797ae465a952.jpg

image103_5aa3529fd805e2580ba46b80ed9cebfaf061ca59.jpg

Wir verwenden unsere Python-Software, um diesen Wert zu abonnieren und ihn anstelle eines konstanten Werts als Sollwert für den PID-Funktionsaufruf zu verwenden. Daher müssen wir die Python-MQTT-Client-Bibliothek mit dem Namen „paho mqtt“ installieren. Verwenden Sie PuTTY und geben Sie Folgendes ein:

sudo pip3 install paho-mqtt

Bearbeiten Sie dann den Python-Code. Fügen Sie die Importanweisung für die Bibliothek hinzu. Fügen Sie mit der Anweisung „def“ eine sogenannte „Call-back“-Funktion hinzu. Diese Funktion wird vom Paho MQTT-Client aufgerufen, sobald ein abonniertes Thema eine neue Nachricht vom MQTT-Broker erhält. Mit fünf zusätzlichen Codezeilen initialisieren und starten wir den MQTT-Client und abonnieren „Setpoint“ (Sollwert).

from simple_pid import PID
import revpimodio2
import time
import paho.mqtt.client as mqtt

def on_message(client, userdata, message):
    TempController.setpoint = int(float(message.payload)*10)

client = mqtt.Client("myplc")
client.connect("localhost")
client.on_message=on_message
client.subscribe("Setpoint",2)
client.loop_start()

TempController = PID(5,0.13,10.5,sample_time=0.1, setpoint=400, output_limits=(0,100))
rpi = revpimodio2.RevPiModIO(autorefresh=True)

while True:
    Temp = rpi.io.Temp10.value
    pwm = TempController(Temp)
    rpi.io.PWM_heater1.value = int(pwm)
    rpi.io.PWM_heater2.value = int(pwm)
    time.sleep(0.05)

Speichern wir nun dieses Skript im „auto execution folder“ (Ordner für die automatische Ausführung) von RevPiPyLoad, „/var/lib/revpipyload“, und nennen wir es „program.py“ (diese beiden Parameter können in der Konfigurationsdatei geändert werden, die Sie zu Beginn unseres kleinen Projekts bearbeitet haben). Sie können dies im IDLE-Editor nicht über „Save as …“ (Speichern unter) durchführen, da der Pfad „/var/“ Administratorrechte benötigt, um Dateien dort hinein zu schreiben. Daher verwenden wir zum letzten Mal PuTTY und geben folgenden Linux-Befehl ein:

sudo mv ~/myplc.py /var/lib/revpipyload/program.py

„Sudo“ ist das Zauberwort, das Ihnen Administratorrechte für die Ausführung dieses einzelnen Befehls gewährt.

Klicken Sie im Fenster „RevPiPyControl“ auf „PLC restart“ (SPS-Neustart) und die rote Fehlermeldung sollte verschwinden. Ein grüner Balken zeigt den erfolgreichen Start des Python-SPS-Skripts an:

image105_96e8936baa856cf84b8b9c17c4ce0fa687f4b6bb.jpg

Ich hoffe, Sie konnten dieser Schritt-für-Schritt-Anleitung gut folgen. Obwohl wir viele Konfigurationsschritte durchführen mussten, haben wir letztendlich nur 19 Zeilen Python-Code erhalten (ich habe den Debug-Print-Code entfernt). Warum probieren wir nicht den IBM Watson-Node aus? Sie werden begeistert sein, wie einfach es ist, Werte in die Cloud zu laden (IBM bietet Ihnen einen kostenlosen „Quickstart“-Zugang für experimentelle Zwecke). Rufen Sie diese Adresse auf, um zu sehen, ob mein Gerät online ist und wie hoch die Temperatur in meinem Büro ist. Wenn beim Versuch, Ihren RevPi Python-Regler zu erstellen, Probleme auftreten, hinterlassen Sie hier einen Kommentar oder senden Sie mir eine Nachricht. Sven Sager, der Autor von RevPiModIO, möchte Ihnen einige Anregungen dazu geben, wie aus dieser Demonstration eine professionelle Version erstellt werden kann. Er wird seine Ideen wahrscheinlich bald in den Kommentaren veröffentlichen. Bleiben Sie also dabei, wenn Sie tiefer in Python für Automatisierungslösungen eintauchen möchten.

image107_795a02e3f1e5c467fa0c0f936ec1b185773cbbdd.jpg

 

__________________________________________________________________________

Sven Sager, the author of the RevPiModIO library and other tools mentioned in this article, has kindly sent this comment:

Just some thoughts about the „while True“ loop:

If we are on a dedicated micro controller – arduino and things like that, we have to use some kind of endless loop to keep our program running. Handle all the hardware stuff, calculate values, do some input output and so on – Main thing: we are the only process on that CPU.

But now we are using a Debian based Revolution Pi with a Linux kernel. Our program is not the only one on that CPU, and we have to understand how an operating system is handling processes.

Startup our program is very simply. It is done by RevPiPyLoad, Systemd, via shell, double click, or whatever. So now our program is running in our “while True” loop and does all the stuff we want – everything is fine, till we want to exit the program!

Doesn’t matter if we Ctrl+C, push “Stop PLC” button in RevPiPyLoad or shut down our Revolution Pi. The operating system’s penguin is sending the "TERM" signal to our program, a friendly request to quit! Now we should leave our “while True” loop, save some data, disconnect from databases or do some other clean up stuff. BUT: We can not leave “while True”, we can not quit our program and the penguin pecks us with his beak sending a "KILL" signal! No matter if we are writing a file, saving data to a database, communicate to a network partner – It's over now! No chance to finish the file, commit changes or disconnect.

So, if you are developing programs, services, or whatever, take a look to signals (link 1 below).

In our case, we are using RevPiModIO, and I included all that signal stuff to the library. We just have to activate the signal handling by calling ".handlesignalend()" right after creating our rpi object (link 2 below). If our program gets "SIGTERM", RevPiModIO will set an "exitevent", which we can use to leave our endless loop. Just change “while True:” to “while not rpi.exitevent.is_set():”.
RevPiModIO has some more features to create professional control programs for the Revolution Pi. If we take our example, we have a cyclic program. The lines in our while loop are called every 50 milliseconds, but not in sync with the process image!
The cycle of a PLC should read all inputs from process image, run your cyclic function with frozen input values, write all outputs to process image and start over again. Why is this important? Simple: If you set 14 outputs to the value of one input, you will expect, that the outputs have all the same value. But if we use “while True” it could happen, that the input changes its value after we set 10 outputs, so the next 4 outputs have a different value.

With RevPiModIO we can use the ".cycleloop" (link 3 below)! Just replace the “while True:” with “def cycle(cycletools):”, remove "time.sleep(0.05)" and call "rpi.cycleloop(cycle, cycletime=50)" on the end of file, that’s it! RevPiModIO will call your function every 50 milliseconds. Of course, ".handlesignalend" will work, too!

So this is our modified example program, which handles operating system signals and handle the cycle function in sync with process image – As a further side effect, the run time of the function is monitored and you get some cycletools to work with (link 4 below)!

from simple_pid import PID
import revpimodio2
import paho.mqtt.client as mqtt

def on_message(client, userdata, message):
    TempController.setpoint = int(float(message.payload)*10)

client = mqtt.Client("myplc")
client.connect("localhost")
client.on_message=on_message
client.subscribe("Setpoint",2)
client.loop_start()

TempController = PID(5,0.13,10.5,sample_time=0.1, setpoint=400, output_limits=(0,100))
rpi = revpimodio2.RevPiModIO(autorefresh=True)
rpi.handlesignalend()

def cycle(cycletools):
    Temp = rpi.io.Temp10.value
    pwm = TempController(Temp)
    rpi.io.PWM_heater1.value = int(pwm)
    rpi.io.PWM_heater2.value = int(pwm)

rpi.cycleloop(cycle, cycletime=50)
​

Links:

  1. https://docs.python.org/3/library/signal.html
  2. https://revpimodio.org/en/doc2/#handlesignalend
  3. https://revpimodio.org/en/doc2/#cycleloop
  4. https://revpimodio.org/en/doc2/cycletools/
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.

Kommentare