Hello SPS! Teil 2: Mit OpenPLC vom Lernen zum Anwenden

Seite 3: Ran an die PLC – mit einem einfachen Beispiel

Inhaltsverzeichnis

Nach diesen Grundlagen und Installationshinweisen ist es an der Zeit, ein "echtes" Programm für einen Mikrocontroller mit dem OpenPLC-Editor zu schreiben, um es anschließend als OpenPLC-Runtime auf das Board zu übertragen. Die Qual der Wahl besteht darin, die für diesen Zweck richtige Sprache des IEC 61131-3-Standards auszuwählen. Alle Sprachen vorzustellen, würde den Rahmen dieses Artikels sprengen, deshalb hat sich der Autor entschieden, exemplarisch die grafische und anschauliche Sprache LD (Ladder Diagram) zu verwenden.

Als Einstieg eignet sich folgendes simples Beispiel, das lediglich aus einem Schalter und einer Lampe/LED besteht. Drückt jemand den Schalter (Push Button), soll die Lampe/LED für eine vorgegebene Zeit angehen und nach abgelaufener Zeit wieder ausgehen.

Das SPS-Programm benötigt dazu drei Komponenten. Als Eingabe den Schalter, als Ausgabe die Lampe/LED und einen TOF-Timer als Funktionsblock für die gewünschte Leuchtdauer (Eingang PT = Preset Time). Den Timer können Entwicklerinnen und Entwickler mit einer vordefinierten Zeit konfigurieren. Läuft die Zeit ab, schaltet der TOF-Timer seinen Ausgang Q, wodurch dieser Strom zur Lampe/LED durchlässt und diese leuchtet.

Ein neues Projekt lässt ich über File/New (Datei/Neu) im OpenPLC-Editor anlegen und in einem neuen Verzeichnis speichern. Es darf kein existierendes Verzeichnis sein, in dem sich schon Dateien befinden. Jedes so angelegte Verzeichnis enthält also exakt ein Projekt.

Danach erscheint ein Dialog, der fragt, welchen Namen das Projekt haben soll, in welcher Sprache die Programmierung erfolgt und welche Art von POU (Program Organization Unit) erstellt werden soll:

  • Ein Program ist eine vollständige Anwendung, die auf einer PLC läuft.
  • Eine Function repräsentiert eine wiederverwendbare Funktion mit einem Resultatswert.
  • Ein Function Block ist ein wiederverwendbarer Codeblock, der sich seinen Zustand zyklusübergreifend mithilfe von Variablen merken kann.

An dieser Stelle wählt der Autor beispielsweise “LEDTimer”, “Program” und “LD”, worauf OpenPLC eine Konfiguration, eine Ressource (bestehend aus einem Task und einer Instanz) anlegt, die sich im Projektfenster selektieren und inspizieren lassen.

Projektverzeichnis im OpenPLC-Editor: Ist das Projekt angelegt, erzeugt der Editor eine baumartige Projektstruktur aus Programmname und Ressourcen.

Ganz oben im Hauptfenster zeigt sich – nach Doppelklick auf das Projektsymbol LEDTimer (oberhalb des Ressource-Symbols) im Projektverzeichnis – nun ein Formular, in das sich die Variablen (-> +-Symbol) eintragen lassen.

Beispiele:

  • Schalter auf einem ersten digitalen Eingabeport mit dem Typ Bool.
  • LED auf einem digitalen Ausgabeport ebenfalls mit dem Typ Bool.

Die IEC-Adressen in Spalte 5 wie etwa %IX0.0 oder %QX0.0 fehlen hier freilich noch.

Auf dem Hauptfenster lassen sich die Variablen, Eingänge, Ausgänge für das Programm festlegen.

Unter Tasks lässt sich die Zykluszeit definieren. In der Regel dürften die Werte bei 20 ms und mehr liegen. Ist die Zahl zu hoch, reagiert die PLC unter Umständen zu träge. Ist sie zu niedrig, etwa 1 ms, könnte es sein, dass die PLC nicht in der Lage ist, die Zykluszeit einzuhalten. Standardmäßig ist eine Zykluszeit von 20 ms voreingestellt.

Es kann losgehen, mittels der LD-Icons im Editor-Fenster das Programm zu komponieren – zumindest fast:

Bei der Programmierung mit Ladder Logic lassen sich Komponenten aus dem oberen Menü des Editors auf das Programm ziehen.

Zunächst ist allerdings noch ein kleiner Ausflug zum Thema wiederverwendbare Funktionsblöcke notwendig. Sobald man ein Programm für OpenPLC erstellt, stehen vordefinierte Funktionsblöcke wie Flip-Flops, Timer, Zähler und vieles mehr zur Verfügung. Entwicklerinnen und Entwickler greifen auf diese Bibliothek sehr gerne und häufig zu. Zusätzlich lassen sich auch eigene Funktionsblöcke einbinden, was aber momentan zu Änderungen des internen Editor-Codes führt. Eine einfachere Möglichkeit gibt es leider nicht.

Die vordefinierten Funktionsblöcke sind im Editor-Code fest integriert, die eigenen Funktionsblöcke kommen zum Sourcecode hinzu und müssen per Kompilation zu einer Binärdatei verschmolzen werden. Sobald ein neues Update für OpenPLC installiert wird, gehen aus diesem Grund die eigenen Funktionsblöcke unwiderruflich verloren, weshalb man deren Quellen immer separat sichern sollte.

Zu beachten ist des Weiteren, dass OpenPLC als Implementierungssprache C nutzt (OpenPLC transpiliert also Programme wie die in Ladder Diagram nach C). Microcontroller-Firmware wie zum Beispiel die bei einem Arduino-Board setzt aber C++ ein. Daher müssen Funktionsblöcke, die auf Arduino-Funktionalität zugreifen wollen, eine Brücke zwischen beiden Welten vorsehen, etwa den Aufruf von Arduino-C++-Funktionalität über den Extern-C-Mechanismus von C++. Mehr zum Thema gibt es in der Dokumentation zum OpenPLC-Editor.

Im Beispiel (siehe übernächstes Bild) würde man eine linke Ladder/Leiter (Input) und eine rechte Ladder/Leiter (Output) mit jeweils mehreren Strängen über das Menü in den Editor ziehen. Linke Ladder referenzieren die Eingänge, rechte Ladder die Ausgänge. Die horizontalen Verbindungen, von denen es auch mehrere geben kann, führen daher immer von linker Ladder zu rechter Ladder. Danach lässt sich der Schalter (normal offener Schalter mit positiver Flanke) auf die Schaltung ziehen und mit der linken Ladder verbinden. Über die Bibliothek holen wir uns als Standardbaustein einen Off-Timer (TOF) und verbinden dessen IN-Eingang mit dem Schalter.

OpenPLC enthält zahlreiche vordefinierte Bausteine wie zum Beispiel Timer.

Am PT-Eingang (PT = Preset Time) des TOF steht per Konstante die Leuchtdauer fest, also beispielsweise 5000 Millisekunden als T#5000ms. Der Ausgang Q des Timers lässt sich mit der LED verbinden und diese wiederum mit der rechten Ladder. Jetzt ist die Verbindung von linker Ladder zu rechter Ladder geschlossen. Den ET-Ausgang (Elapsed Time) des TOF-Bausteins könnten Developer theoretisch für die Abfrage nutzen, wie lange der Timer schon läuft. Im vorliegenden Beispiel bleibt er unbenutzt.

Einfaches Ladder-Logic-Programm, bei dem beim Schließen eines Schalters eine Lampe für eine festgelegte Zeit leuchtet.

Durch Betätigen des "laufenden Mannes" im Menü lässt sich das Beispiel simulieren. Zur Visualisierung der Simulation drückt man das oberste Brillensymbol im Bereich links unten. Durch Anklicken weiterer Brillen-Symbole lassen sich die zugehörigen Variablen beobachten. Hier eignet sich am besten der Schalter, da der Autor durch dessen Schließen die gewünschte Reaktion erzielen möchte.

Noch passiert nichts, weil der Schalter standardmäßig offen (FALSE) bleibt. Selektiert man den Schalter und schließt ihn per Kontextmenü, indem man auf das Schlosssymbol des Schalters klickt und ihn auf TRUE setzt (Schalter-Variable -> TRUE), so startet der Timer und die Lampe fängt an zu leuchten. Im Simulator bedeutet dies, dass die Lampe und die zu ihr führende Leitung nun grün erscheinen. Nach 5 Sekunden läuft der Timer ab und setzt dann seinen Q-Ausgang auf FALSE, wodurch die Lampe erlischt (Lampe und Zuleitung sind dann wieder schwarz).

Programme lassen sich in OpenPLC simulieren. Grün bedeutet an, Schwarz aus.

Ist das Ergebnis der Simulation zufriedenstellend, klickt man auf das Arduino-Icon im Menü, um das Programm beziehungsweise die OpenPLC-Firmware auf das Mikrocontrollerboard hochzuladen. Dazu wählt der Autor das von ihm verwendete Board aus dem Dialog und gibt weitere benötigte Angaben wie Boardtyp, SSID des optionalen WiFi-Netzes, Passwort und so weiter ein.

Im Vorfeld hat der Autor an das Board einen Push-Button über einen Pull-Down-Widerstand (1 bis 10 kOhm) an einen digitalen Eingang angeschlossen und die LED über einen 220+-100 Ohm-Widerstand an einen digitalen Ausgang des Boards. Die Variablen im OpenPLC-Editor haben einen Schalter und LED mit den richtigen Adressen – z. B. %IX0.0 und %QX0.0 – erhalten.

Der OpenPLC-Editor erlaubt den Upload der Firmware (des Programmes) auf die Zielhardware.

In Ladder-Diagram-Programmen lassen sich einzelne Komponenten zu logischen Kombinationen verbinden (siehe nachfolgende Abbildung). Die Eingänge haben eckige Klammern, die Ausgänge runde Klammern oder Kreise. Hinter allem stecken Variablen. Ein Ausgang ist auch als Eingang (für die nächsten Schritte) nutzbar. Das Ausführen dieser Programme passiert von links nach rechts und von oben nach unten. Funktionsblöcke enthalten eigene Logik hinter einer Black Box, verwenden Eingänge für Parameter und Ausgänge für Resultate.

Logische Verarbeitung im Ladder Diagram.

Es handelt sich hierbei um ein recht einfaches Beispiel – in komplexeren finden sich auch Verzweigungen, mehrfach auftretende Variablen, Bausteine und verschiedene parallele Verbindungen zwischen den beiden Laddern. Das folgende Beispielbild zeigt eine Ampelschaltung von Yekki inklusive Start-Schalter:

Ladder-Logic-Diagramme können auch sehr komplex werden, wie das Beispiel einer Ampelschaltung (inklusive Start-Schalter) zeigt.

(Bild: Yekki, 2020)

Hier noch ein weiteres Exemplar für ein PLC-Programm mit einem Funktionsblock (siehe folgende Abbildung). Es nutzt einen Zähler des Typs CTUD, der sowohl hoch- als auch runterzählen kann. Das zugehörige LD-Programm verändert abhängig vom Wert der Sensoren IN_sensor_A und IN_sensor_B den Zählerstand. Die Sensoren stellen fest, sobald Personen ein Restaurant (Kapazität : 25 Personen) betreten oder verlassen. Sobald der CTUD-Funktionsblock in der Variablen CV (Current Value) den Schwellwert von 25 erreicht, hat das Restaurant seine Kapazität ausgeschöpft und signalisiert dies über eine an der PLC angeschlossene Anzeigetafel nach aussen. Die beiden Sensoren könnten sich beispielsweise auf Lichtschranken beziehen, die vor und nach der Eingangstür platziert sind.

Stimmen die Eingangsbedingungen zählt der Counter entweder hoch oder runter, bis die vordefinierte Grenze von 25 erreicht ist.

(Bild: techocrazed.com)

Ein Up-Down-Counter (CTUD) verfügt über folgende Eingänge und Ausgänge:

  • Eingang CU (Count Up): inkrementiert Zählerstand bei jedem Signal.
  • Eingang CD (Count Down): dekrementiert Zählerstand bei jedem Signal.
  • Eingang R (Reset): dient zum Reset des Counters.
  • Eingang PV (Preset Value): Schwellwert, bis zu dem der Counter hochzählt.
  • Eingang LD (Load): setzt Zählerstand auf Wert von PV zurück.
  • Eingang PV (Preset Value): Schwellwert, bis zu dem der Counter hochzählt.
  • Ausgang QU (Output for Count Up): wird aktiv, sobald der Zähler CV den Wert von PV erreicht.
  • Ausgang QD (Output for Count Down): wird aktiv, sobald der Zähler CV den Wert 0 annimmt.
  • Ausgang CV (Current Value): aktueller Zählerstand.

Dem LD-Programm ist Folgendes zu entnehmen:

  • Wenn NOT IN_sensor_A einen Wert TRUE besitzt und gleichzeitig IN_sensor_B mit einer negativen Flanke von TRUE auf FALSE geändert wurde, erfolgt ein Inkrementieren des Counters (am CU-Eingang). Das könnte zum Beispiel den Vorgang Gast betritt von Straße aus das Restaurant repräsentieren.
  • Wenn der Eingang NOT IN_sensor_B den Wert TRUE hat und gleichzeitig IN_sensor_A mit einer negativen Flanke von TRUE auf FALSE gesetzt wurde, erfolgt ein Dekrementieren des Counters (am CD-Eingang). Das wiederum könnte den Vorgang Gast betritt vom Restaurant aus die Straße darstellen.
  • Der Counter lässt sich über den Schalter IN_switch_reset am R(ESET)-Eingang zurücksetzen.
  • Der obere Schwellwert (PV) liegt in der Momentaufnahme bei 25, der augenblickliche Zählerstand (CV) bei 0.
  • Der QU-Ausgang versendet ein Signal, sobald PV == CV (Zählerstand) gilt.

Es gibt bei anderen Versionen des CTUD noch zwei weitere Eingänge CD_T (Count Down Time) und CU_T (Count Up Time), an denen man über Konstanten festlegen kann, wie lange ein Dekrementieren beziehungsweise Inkrementieren in Millisekunden dauern soll.

Darüber hinaus gibt es auch rein inkrementierende Zähler (CTU) oder rein dekrementierende Zähler (CTD) als Funktionsblöcke.

Doch damit genug zu LD-Beispielen. Wie bereits erwähnt, ist LD nur eine von fünf Sprachen des IEC-Standards, die OpenPLC zur Verfügung stellt. Eine weitere Sprache heißt ST (Structured Text). Diese Sprache ist in diesem Zusammenhang insofern interessant, als zum einen OpenPLC jedes Programm letztendlich nach ST übersetzt (und ST wiederum nach C), und als es sich zum anderen im Gegensatz zu LD um eine rein textuelle Sprache handelt. Hier ein kleines Code-Fragment, das dies veranschaulicht. Darin geht es um Starten und Stoppen einer Pumpe, abhängig vom Zustand eines Kontrollventils.

(* Diese Routine startet eine Pumpe sobald das Kontrollventil geöffnet ist und
stoppt die Pumpe, wenn das Kontrolventil schließt oder nicht offen ist *)
IF #Kontrollventil1_Closed = false AND #Kontrollventil1_Open = True THEN
    #Pumpen_Start := True;
ELSIF #Kontrollventil1_Closed = true OR #Kontrollventil1_Open = False THEN
    #Pumpen_Start := False;
END_IF;

ST unterstützt unter anderem:

  • while- und repeat-Schleifen
  • for-Schleifen,
  • bedingte Anweisungen,
  • case-Anweisungen,
  • arithmetische Operationen,
  • logische Operationen,
  • Vergleichsoperatoren,
  • Zuweisungen,
  • Aufrufe von Funktionen und Funktionsblöcken,
  • und einiges mehr.

Das ist zwar nur ein minimales Beispiel, vermittelt aber zumindest eine Idee von der Syntax und der Semantik. Offensichtlich können die Schöpfer von ST eine gewisse Verwandtschaft zu Algol- oder C-artigen Programmiersprachen nicht abstreiten.

Im Übrigen sind LD und ST zwei der am meisten genutzten Sprachen aus dem IEC-Standard, weshalb der Fokus auf diese Sprachen nicht ganz zufällig war.