Bildergalerie
Wenn auch die Programmierung einen modularen Einsatz verfolgt, lässt sie sich einfacher wiederverwenden.
Mechatronischer Aufbau des Gesamtsystems
Beispiel Zylinder mit Zustandsmaschine
Interface iCylinder mit der Methode mStateMachine
Basisfunktionsbaustein der Zylinder
Aufruf der Zylinder-Funktionsbausteine

Um den ständig steigenden Anforderungen an Produktivität, Flexibilität und Verfügbarkeit einer Anlage Herr zu werden und dennoch die Kosten für den Engineering-Prozess, die Inbetriebnahme und die Wartung einer Anlage zu reduzieren, sind neue Methoden und Werkzeuge erforderlich. Ein möglicher Weg, um dies zu erreichen, ist die Anwendung eines mechatronischen Ansatzes. Dabei wird die Anlage in mechatronische Module (Objekte) zerlegt, welche einzelne Funktionen des Gesamtprozesses einer Anlage abbilden. Sind diese Module nicht nur funktional gekapselt, sondern die Schnittstellen zwischen diesen Modulen definiert, erhält man eine Art Baukasten, aus dem man sich bei der Projektierung neuer Anlagen bedienen kann. Die einzelnen Module des Baukastens bilden dabei die jeweilige Teilfunktion komplett ab. Sie umfassen also alle Facetten eines Moduls von der Mechanik über die Elektrotechnik bis hin zu den Steuerungsfunktionen, die nicht zwangsläufig auf einer eigenen Steuerung laufen.

Um diesen objektorientierten Gedanken auch im Bereich der Steuerungstechnik Rechnung zu tragen, müssen die verwendeten Sprachmittel um diese Möglichkeiten erweitert werden. Ziel kann es dabei aber nicht sein, eine neue objektorientierte Sprache einzuführen, sondern vielmehr zu ermöglichen, diese objektorientierten Erweiterungen in den Standardsprachen der Steuerungstechnik zur Verfügung zu stellen. An diesem Punkt setzt Twincat 3 an. Um der neuen modul- beziehungsweise objektorientierten Denkweise Rechnung zu tragen, wurden die Sprachmittel der IEC 61131-3 um zehn neue Schlüsselworte erweitert.

Technik im Detail

Kurze Geschichte der objektorientierten Programmierung
Die objektorientierte Programmierung begann Mitte der 1980er Jahre populärer zu werden, hauptsächlich durch den Einfluss von C++, das als syntaktische Erweiterung der Sprache C konzipiert war. Viele existierende Programmiersprachen erhielten seit dieser Zeit objektorientierte Erweiterungen. Weiter gefestigt wurde die Stellung der objektorientierten Programmierung durch die schnell wachsende Beliebtheit der grafischen Bedienoberflächen, die sich objektorientiert sehr einfach programmieren ließen. Die bekanntesten objektorientierten Sprachen sind heutzutage C#, C++ und Java.

Quelle: wikipedia.org

Neue Schlüsselworte machen Modularität möglich

Die neuen Schlüsselworte stehen in allen Sprachen der IEC 61131-3 zur Verfügung. Mit dem Schlüsselwort ‚Extends‘ lassen sich Funktionsbausteine von anderen Funktionsbausteinen ableiten. Dabei haben die abgeleiteten Funktionsbausteine dieselben Methoden und Eigenschaften wie die Basisfunktionsbausteine, die allerdings auf den Daten des abgeleiteten Funktionsbausteins arbeiten.

Beim Schlüsselwort ‚Interface‘ handelt es sich um virtuelle Klassen, die Methoden definieren, die von ihnen abgeleitete Objekte instanziieren müssen, um fehlerfrei kompilierbar zu sein. Sie lassen sich also dazu verwenden die Struktur beziehungsweise die Schnittstellen von Objekttypen zu definieren. Darüber hinaus ermöglichen sie durch Pointer auf das Interface, dass alle von ihnen abgeleiteten Funktionsbausteine über ebendiesen Interface-Pointer gleich angesprochen werden können.

Das Schlüsselwort ‚Implements‘ implementiert ein Interface in einem Funktionsbaustein.

Unter dem Schlüsselwort ‚Method‘ versteht man eine Art Funktion, die einem Funktionsbaustein zugewiesen sind. Mit anderen Worten sind diese keine eigene POUs (Program Organisation Units), sondern sind Bestandteil des Funktionsbausteines und arbeiten auf den Daten der sie beinhaltenden Funktionsbaustein-Instanz.

Mit dem Schlüsselwort ‚Property‘ sind Eigenschaften gemeint, die einem Funktionsbaustein oder einem Programm zugewiesen werden können. Diese Eigenschaften können jeweils eine Get- und eine Set-Methode enthalten und dienen als eine Art Schreib- und Leseschutz für interne Variablen. Dabei ist es ebenfalls möglich, in diesen Get- und Set-Methoden neben der eigentlichen Zuweisung noch weitere Anweisungen auszuführen, um den benötigten Wert zur Verfügung zu stellen oder den zugewiesenen Wert vor zu verarbeiten.

Mithilfe des ‚This-Pointers‘ ist es möglich, auf die Funktionsbausteininstanz selbst zu zeigen. Und mithilfe des ‚Super-Pointers‘ kann auf Methoden des vererbenden Funktionsbausteines gezeigt werden. In Anlehnung an Konstruktoren und Destruktoren werden die Methoden ‚FB_init/FB_reinit/FB_exit‘ beim Initialisieren, Kopieren und Verlassen der Funktionsbaustein-Instanz aufgerufen.

Praxisbeispiel: Objektorientierte Programmierung

Als Beispiel für den Einsatz von objektorientierter Programmierung soll eine Anlage dienen, in der mehrere Arten von Zylindern zum Einsatz kommen. Die Aufgabenstellung besteht nun darin, den Steuerungscode für diese Anlage so flexibel zu gestalten, dass der eigentliche Sollablauf der Anlage unabhängig vom eingesetzten Zylindertyp ist. Allen diesen Zylindertypen ist gemein, dass sie über die zwei Positionen links und rechts verfügen, die ein Endlagenschalter detektiert.

Als Lösungsansatz für dieses Beispiel wird nun definiert, dass entsprechend dem objektorientierten Gedanken die Funktionalität dieser Zylinder jeweils komplett in einem Funktionsbaustein abgebildet ist. Darüber hinaus wird definiert, dass alle Zylinder eine Zustandsmaschine besitzen, die mittels Ein- oder Ausgängen die geforderte Position des Zylinders übergeben bekommen oder die aktuelle Position des Zylinders zurückliefern soll.

Da laut Aufgabenstellung der jeweils in der Anlage eingesetzte Typ des Zylinders flexibel sein soll, muss das Interface, über das die Zylinder angesprochen werden, gleich sein. Aus diesem wird als erstes ein Interface ‚iCylinder‘ definiert, das alle Zylinder-Funktionsbausteine implementieren müssen. Dieses Interface besitzt eine Methode ‚mStateMachine‘, welche die Zustandsmaschine der Zylinder abbildet. Diese Methode hat die Eingänge ‚bPosLeftReq‘ und bPosRightReq‘ sowie die Ausgänge ‚bActPosLeft‘ und ‚bActPosRight‘, welche die Signale der Endlagenschalter repräsentieren. Diese Ein- und Ausgänge sind jeweils vom Typ Bool.

Basierend auf diesem Interface lässt sich nun ein Basisfunktionsbaustein ‚fbBaseCylinder‘ erstellen, in dem die Zustandsmaschine der Zylinder implementiert wird. Wählt der Programmierer beim Anlegen des Funktionsbausteines bereits aus, dass das Interface ‚iCylinder‘ implementiert werden soll, wird die Methode ‚mStateMachine‘ samt ihrer Ein- und Ausgänge automatisch angelegt und muss nur noch ausprogrammiert werden. Welche Interfaces ein Funktionsbaustein implementiert, wird mithilfe des Schlüsselwortes ‚Implements‘ definiert. Die Ableitung eines Funktionsbausteines von mehreren Interfaces ist dabei möglich. Ist der Basisfunktionsbaustein ausprogrammiert, können die Funktionsbausteine der verschiedenen Zylindertypen von ihm abgeleitet werden. Dies geschieht mit dem Schlüsselwort Extends.

Die abgeleiteten Funktionsbausteine erben nun alle Methoden und Eigenschaften des Basisbausteines. In diesem Beispiel bedeutet dies, dass die Funktionsbausteine der abgeleiteten Zylinder die Methode der ‚mStateMachine‘ vom Basisfunktionsbaustein erben. Der Vorteil hierbei ist, dass Erweiterungen in der Methode ‚mStateMachine‘, die alle Zylinder-Funktionsbausteine betreffen, nur im Basisfunktionsbaustein nachgepflegt werden müssen und dann sofort in allen abgeleiteten Funktionsbausteinen zur Verfügung stehen. Soll die Zustandsmaschine eines abgeleiteten Zylinders ein anderes Verhalten aufweisen, als die des Basisfunktionsbausteines, ist es möglich, diese Methode zu überschreiben. Dies geschieht, indem der abgeleitete Funktionsbaustein eine Methode mit demselben Namen implementiert, wie die des Funktionsbausteins der Basisklasse.

Zugriff über Interface

Um zu zeigen, dass die Aufgabenstellung mit diesem Lösungsansatz erfüllt wird, werden nun zwei Funktionsbausteintypen ‚Cylinder_TypA‘ und ‚Cylinder_TypB‘ vom Basisfunktionsbaustein abgeleitet und entsprechend ausprogrammiert. Dabei werden beiden Funktionsbausteintypen noch weitere, teilweise unterschiedliche, Ein- und Ausgänge hinzugefügt. Von beiden Typen wird im Programm ‚Main‘ jeweils eine Instanz angelegt. Da der Zugriff auf diese Funktionsbausteine über das Interface geschehen soll, wird ebenfalls ein Interface-Pointer angelegt, der auf das Interface ‚iCylinder‘ zeigt. Der eigentliche Aufruf der Zustandsmaschine erfolgt nun über den Aufruf der Methode ‚mStateMachine‘ des Interface-Pointers. Durch das Zuweisen einer Funktionsbaustein-Instanz auf den Interface-Pointer kann nun auch zur Laufzeit entschieden werden, welche Methode ‚mStateMachine‘ tatsächlich aufgerufen wird. Dies bezeichnet man als ‚Späte Bindung‘.

Eine weitere schöne Möglichkeit für die Anwendung von Interfaces ist zum Beispiel auch die Betriebsartenumschaltung von Modulen einer Anlage. Wird sichergestellt, dass alle Module einer Anlage ein Interface implementieren, das die Basisschnittstelle für die Betriebsartenumschaltung enthält, kann eine einzige Schleife über eine Struktur vom Typ dieses Interfaces ein Umschalten der Betriebsarten von allen Anlagenkomponenten herbeiführen.