Posted on

SCADA/HMI-Optimierung mit SVG und netpp

Die Erstellung einer klassischen Prozessansicht in der Automation sieht im Arbeitsprozess aus, wie folgt:

  • Registertabellen aus der modbus-Sektion abtippen und mit einer Widget-ID der HMI-Anzeige verbinden
  • Zustand eines Elements, z.B. Ventil innerhalb der Prozesskette in verschiedene Bitmaps codieren, z.B.:
    • 0 : Initialisierung des Ventils (Zustand unbekannt)
    • 1: Ventil offen
    • 2: Ventil zu
    • 3: Fehler
  • In der Abfrage wird laufend der Zustandswert aus dem Register ausgelesen und die entsprechende Bitmap an der Stelle der Prozessübersicht gezeichnet.

Mit dem weitverbreiteten und gut standardisierten Vektorformat SVG geht das eleganter:

  • Einem Element in der Grafik einen Namen geben
  • Dem Namen über eine Datenbank allenfalls eine Registeradresse zuweisen
  • Die ganze Prozedur der Aktualisierung einem Framework überlassen

Diverse SCADA-Lösungen setzen teils auf Browser-Technologien auf, da sie von Haus aus Unterstützung für das SVG-Format mitbringen. Diese benötigen typischerweise einen embedded Webserver, der die regelmässige Abholung der Registerdaten in der ganzen Prozesskette organisiert und für den Browser entsprechend der bereitstehenden REST-APIs aufbereitet. Es gibt aber auch kompaktere Lösungen, die Support für SVG mitbringen, wie die OpenSource-Lösung pvbrowser von Rainer Lehrig.

Hier wird insbesondere die Integration in den pvhub-Prozesskontrolle-Server mit dem netpp-Subsystem beschrieben. Dabei arbeitet man allerdings in der anderen Richtung, d.h. die Netpp-Property-Namen dienen als Namen (‚id‘) für das zugeordnete SVG-Element und die zentrale Datenbank fällt weg.

Anleitung

Am Beispiel eines Zwei-Wege-Verteilers soll hier eine kurze Anleitung gegeben werden, wie der Zustand eines Elements elegant in die Grafik überführt wird. Dazu benutzen wir das mächtige Opensource-Tool Inkscape, siehe auch Download. Der Zustand des ZWV ist in einem Register-Bitfeld codiert, welches durch ein netpp-Property vom Typ MODE beschrieben wird. Dieses MODE-Property enthält die möglichen Zustände als Kinder, z.B:

Type : Mode [RWV]
Child: (m) [200000d5] 'LR_PUR'
Child: (m) [200000d6] 'L_PUR'
Child: (m) [200000d7] 'R_PUR'
Child: (m) [200000d8] 'OFF'
Child: (m) [200000d9] 'LR_ALARM'
Child: (m) [200000da] 'L_ON'
Child: (m) [200000db] 'R_ON'
Child: (m) [200000dc] 'L_ERR'
Child: (m) [200000dd] 'R_ERR'

Zeichnen Sie dabei für jeden Zustand eine einzelne Grafik. Arbeiten Sie dabei am besten mit Hilfe von Layern, dass die einzelnen Grafiken direkt übereinander zu liegen kommen. Das erspart nachträgliche und aufwendigere Translationen.

Gruppieren Sie anschliessend jede Grafik per Zustand einzeln. Danach teilen Sie dieser Gruppe einen eindeutigen Namen zu, und zwar den vollen hierarchischen Namen des netpp-Property-Zustands, z.B.

Monitor.ProcessingUnit.Crumbler[0].TwoWayDistState.L_ON

Benutzen Sie dazu allenfalls den XML-Editor in Inkscape:

Die Einzelgrafiken werden schlussendlich in einen Layer aufeinander kopiert. Schliesslich müssen alle Zustandsgrafiken noch ein letztes Mal mit Ctrl-G gruppiert werden, dieser Gruppe weisen Sie dann den Namen des Property zu:

Monitor.ProcessingUnit.Crumbler[0].TwoWayDistState

Für eine einfache Umsetzung reicht zunächst, die SVG-Grafik mit dem Rapid-Prototying-Tool pvdevelop (Teil der pvbrowser-Software) einzubinden und ihm die Objekt-ID der gesammelten Monitor-Hierarchie zu übergeben, also: „_#Monitor“. Die Prefix ‚_‘ sorgt für die Property-Abfrage, das ‚#‘ markiert ein Property das im lokalen Cache gepuffert wird (was eine ineffiziente Abfrage vieler Einzel-Properties optimiert).

Der Ablauf der Prozessanzeige sieht dann aus wie folgt:

  • Das Monitor-Property wird einmal pro Intervall abgefragt
  • Alle Kinder davon werden „besucht“ und deren Zustand ermittelt, der Name des Zustands wird dann verwendet, um das entsprechende Objekt in der Grafik sichtbar zu machen. Dabei werden a priori alle Zustandsgrafiken unsichtbar gemacht und nur die Grafik zum aktiven Zustand wird sichtbar.

Für andere Arten von Eigenschaften nimmt das Framework eine Standard-Anzeige vor, diese ist auch insbesondere vom zugewiesenen Namen des Property abhängig. Dabei werden normalerweise einfache Primitiven (Polygone oder Kreise, etc.) in der Zeichnung verwendet, deren Füllfarbe einfach ausgetauscht wird. Im folgendenden eine kurze Auflistung:

  • BOOL: Wert True (1) wird durch grüne Füllfarbe markiert, 0 mit rot
  • INT:
    • Name: Rotation, Wert von 0..359: Grafik wird entsprechend rotiert
    • Name: Position, enthält Min und Max Kinder: Grafik wird um den Wert in X verschoben. Die effektive Positionierung errechnet sich dabei aus der Skalierung des Parent-Property-Objekts. Falls keine Kinder angegeben sind, ist der Wert eine Prozentangabe von 0..100.
    • Name: Fill, von 0..100, sofern keine Min oder Max Kinder angegeben, definiert den Füllstand eines Tanks. Die Grafik des Tanks muss dabei die entsprechenden Dimensionen einhalten, die Skalierung findet via das übergeordnete Gruppierungselement statt.

Fazit

Für den Integrator wird die Erstellung einer HMI-Anzeige somit weniger aufwendig, vorausgesetzt die Datenbank der einzelnen Geräte steht bereits oder ist durch bereits netpp-fähige Geräte abgedeckt.

Sie können somit die Grafik und die nötigen Animationen selbst erstellen, und anhand der vorliegenden Property-Referenz einzeln zuweisen. Allfällige Anpassungen der SVG-Grafik sind dabei meist unproblematisch.

Schliesslich können Sie die Anzeige wie gewohnt per pvbrowser aufrufen und sehen entsprechend die Zustände der Elemente in der so animierten SVG-Grafik.

Monitor Prozesskontrolle

Ein weiterer Vorteil: Die SVG-Grafik benötigt gegenüber der Pixelgrafik weniger Speicherplatz. Somit kann es auch auf limitierten netpp-Geräten im SPI-Flash untergebracht und per Property Monitor.SVGImage abgefragt werden.

Stolperfallen/Tips

Bei der Erstellung der SVG-Grafiken gilt es, einiges zu beachten:

  • Zeichnen Sie die Elemente am besten von Anfang an masstabsgetreu, d.h. nutzen Sie mm als Einheit. Typischerweise werden die HMI-Anzeigen so abgestimmt, dass das Element in der richtigen Grösse gezeichnet wird
  • Gruppieren Sie erst am Schluss, bevor Sie den Namen zuweisen. Bei Gruppierungsaktionen können Namen verlorengehen.
  • Nutzen Sie auch den Objects-Editor (Menü: Object->Objects) zur Kontrolle der Hierarchien und Sichtbarkeit.
  • Sie können zusätzlich zur ID auch ein ‚Label‘ vergeben, was denselben Namen haben kann, aber nicht eindeutig vorkommen muss. Das erleichtert das Auffinden im Objects-Editor.
  • Achten Sie darauf, dass bei rotierenden Animationen der Nullpunkt des Objekts als Rotationszentrum gilt. Die Position kann dann durch eine übergeordnete Gruppe definiert werden. Kennzeichnen Sie ansonsten den Rotationsmittelpunkt durch ein Kreuz, o.ä.
Posted on

Hardwaredesign und CI/Cloud computing — Open source

Automatisches Testen und Verifizieren von Software ist spätestens mit dem Schlagwort „CI“ – Continuous Integration zum Standard für grössere Softwareprojekte geworden. Bei aller möglichen Überflutung mit derartigen Reizwörtern darf man hier kurz innehalten und nachfragen: Was ist das genau? Bringt mir das was?

Ein paar Aspekte für den klassischen innovativen Entwickler zusammengefasst:

  1. Man wird älter und kann/will sich nicht mehr alles merken
  2. Man hat beim allgemeinen Preiskampf weniger Zeit für ausführliche Dokumentation
  3. Die Bibliothek oder das Sammelsurium an möglichst (!) wiederverwartbarem Sourcecode ist angewachsen und der kontiuierliche Unterhalt wird immer aufwendiger
  4. Implementiere ich etwas Neues, mache ich vielleicht etwas Altes kaputt

Diverse Technologien zur Virtualisierung von Komponenten (Docker, Virtuelle Maschinen, Linux Container, …) lösen das Problem insofern, dass sich Bausteine aus Projekt A nicht Baustellen aus Projekt (oder gar Problem) B in die Quere kommen (und umgekehrt). Trotzdem möchte man möglichst viele Gemeinsamkeiten abdecken. Also ergibt sich eine klassische NxM-Komplexität: N Bausteine müssen gegen M Konfigurationen/Varianten getestet werden.

Nichts leichter als das: Systeme aus der Opensource-Szene wie Tinderbox oder der Nachfolger buildbot, oder auch teilkommerzielle Dienste wie Travis CI sind beim Testen von Software soweit behilflich, dass für alle Beteiligten, sei es OpenSource oder proprietär/Closed Source, ein Produkt aus der automatisierten Pipeline ploppt, welches – zumindest im Idealfall – gegen eine Menge Fehlerszenarien und Konfigurationen automatisch getestet worden ist.

Test-Szenarien

Gegen was muss denn jetzt typischerweise getestet werden? Nehmen wir an, unsere Software bietet eine Funktionalität einer Bibliothek, d.h. ein Nutzer soll Funktionen aufrufen können. Generell bietet sich der Ansatz einer Bibliothek aus Erfahrung immer an, mit dem Fokus auf:

  • Wiederverwertbarkeit von Code und Algorithmen
  • Optimale Interoperabilität
  • Optimale Abdeckung vieler Anwendungsfälle und Szenarien

Der Aufruf einer Funktion bedingt immer: Eingabe-Daten haben eine mehr oder minder sinnvolle Ausgabe zur Folge, oder gar einen Absturz oder eine Endlos-Schleife. Standard-Strategie ist bei uns, diese Funktionen mit einem virtuellen ‚Adapter‘ so zum umwickeln (‚wrappen‘), dass sie aus der mächtigen Scriptsprache Python aufgerufen und gegen Szenarien oder Messdaten getestet werden können.

So weit ist das alles mit erträglichem Aufwand für Software implementierbar.

Testen von Hardware

Das Testen von Hardware ist eindeutig kniffliger. Hier lässt sich a priori nicht einfach ein Script schreiben, typischerweise geht es um sogenannte parallel auftretende ‚Test-Vektoren‘. Vereinfacht: Angenommen, wir haben einen (virtuellen) Chip, der 16 Eingänge und 16 Ausgänge besitzt. Rhetorische Frage: Kann der Chip mit allen möglichen Eingangssignalen sinnvolle Ausgangssignale erzeugen, so dass alle Zustände definiert sind?

Da die Eingänge unterschiedliche Funktion haben, wie z.B. Takteingänge, reicht eine statische Analyse niemals aus, und die Testszenarien müssen im Grunde genommen immer auf die Funktion der Ein/Ausgänge zurechtgeschnitten werden. Geht auch alles, allerdings mit erheblich höherem Aufwand als für die Software. Wenn alle möglichen Zustände und Sequenzen irgendwie abgefangen werden müssen, um entweder in einem OK oder ERROR-Status zu enden, wird das Problem je nach Komplexität nicht mehr handhabbar, bzw. reicht ein einziger PC nicht dazu aus.

Dazu kommt, dass die Simulationstools, die solche Fehlerszenarien durchspielen können, noch nicht allzulange auf mehreren Rechnern ohne Kostenexplosion verteilbar sind. D.h. für die „Cloud“ ist das für den einfachen Anwender oder die Kleinfirma keine legale Option. Es muss also auf OpenSource zurückgegriffen werden, was aber weitere Risiken mit sich bringt: Opensource ist, spätestens nach dem Download, nicht mehr kostenfrei und es gibt – ohne einen vorliegenden Supportvertrag – keine Garantie für gewünschte Funktionalität.

Der Paradigmenwechsel

Wie schon vor vielen Jahren die Gnu Compiler Collection (GCC) teure, proprietäre Compilerlösungen abgelöst hat, und bei allen Unkenrufen zum Trotz die Nummer Eins beim Übersetzen von Sourcecode für andere Architekturen geworden ist, zeichnet sich auch in der Hardware-Welt ein Paradigmenwechsel ab. Wird sind eigentlich an dem Punkt, wo jeder mit entsprechend Know-How in der Lage ist, sich sein eigenes Computerdesign zu entwerfen und es auch zu testen, ohne dass es an Geld für entsprechende Werkzeuge mangelt. Die Übergänge zwischen Software- und Hardware (in der akademischen Welt oft noch klar getrennt) werden fliessender, gefragt sind robuste Lösungen, Gesetzgeber pochen mehr auf Garantie und Haftung — auch bei kleinen innovativ-agilen Entwicklern.

Wie löst sich diese gordische Knoten?

Dazu liesse sich ein Buch schreiben. Aber warum nicht gleiches mit Gleichem vergelten: In der Opensource-Welt hört man schon mal den Spruch: Read the source, Luke.

Also möchte ich schliesslich auf das OpenSource-Konzept ‚MaSoCist‘ verweisen, was wiederum auf einem Sammelsurium an existierenden OpenSource-Tools aufbaut, seien genannt:

  • Der gcc GNU compiler
  • GHDL – ein OpenSource VHDL Simulator
  • Linux, GNU Make
  • … und eine Handvoll Software-Tools aus dem eigenen Hause

Als Sourcecode-Hoster wurde github ausgewählt, so findet sich entsprechend das Code-Repository unter

https://github.com/hackfin/masocist

Kurzumriss MaSoCist

Der MaSoCist ist im Grunde genommen eine komplexe Anleitung und Regelsammung um Hardware zu bauen. Dazu gehört a priori die Simulation derselbigen. Bei dieser Art der Entwicklung muss man sich dabei auf sehr viele Dinge verlassen, insbesondere darauf, dass:

  • Die OpenSource-Werkzeuge (die teilweise gebaut werden) korrekt funktionieren
  • Die Abhängigkeiten von externen Werkzeugen und Bibliotheken stimmen

Das heisst, wir müssen unsere Tools auch laufend gegentesten, denn irgend jemand könnte im Laufe der Entwicklung etwas beschädigen.

So ist der MaSoCist nicht nur ein Baukasten für Hardware, er testet sich zudem selbst, dank einiger Dienste, die die OpenSource-Welt für uns bereitstellt.

Was baue ich jetzt genau mit dem MaSoCist?

Grob lässt sich das wie folgt auflisten:

  • Es wird ein virtueller (oder auch für FPGA synthetisierbarer) Mikroprozessor gebaut
  • Es wird die zugehörige Peripherie (UART, I2C, …) gebaut
  • Es wird die Test-Firmware für eine gewisse Plattform übersetzt und als ROM-Datei in die Simulation integriert
  • Das Ganze lässt sich wie ein Linux-Kernel konfigurieren, d.h. CPU core, Anzahl und Art der Interfaces lassen sich entsprechend der Möglichkeiten, die die mitgelieferten Style-Sheets bieten, auswählen.
  • Schliesslich: Die virtuelle Architektur wird mit externen Stimuli per sog. Co-Simulation auf korrekte Funktion getestet

Optional erstellt der MaSoCist auch die komplette Systemdokumentation aller Register, usw. Natürlich muss manuell die passende Dokumentation zum ‚Chip‘ erstellt werden.

Simulationsszenarien

Mehrere Ansätze sind hier gängig:

  • Simulation eines Hardware-Designs ohne CPU gegen externe Software, Daten, oder Stimuli (UART-Eingaben, ..)
  • Simulation des Gesamtsystems mit der innewohnenden Firmware und CPU, allenfalls ohne externe Stimuli

Der MaSoCist nutzt hierbei die Möglichkeiten, die GHDL bietet, um entweder eine Simulation mit statischen/fixen Testmustern zu stimulieren (wie aus einer VHDL-Testbench heraus) oder die dynamischen Ansätze der Co-Simulation über unsere ghdlex Bibliothek. Hierbei können einfache Kommandozeilenaufrufe oder ein Python-Script die Simulation ansteuern und auf Herz und Nieren (in der Cloud) testen.

Wie beginne ich?

Am besten mit einem Docker Container. Das hat den Vorteil, dass keine Software  – ausser allenfalls dem Docker-Dienst oder einer virtuellen Linux-Maschine – installiert werden muss.

Das ganze kann auch komplett im Browser ablaufen.

Die Details dazu finden Sie hier. Viel Spass!