Hallo Forum,
ich habe eine Anfrage erhalten, die Steuerung einer komplexen Maschine im Automotiv-Umfeld neu zu "denken".
Man stelle sich eine große Maschine vor mit vielen Sensoren (20+), Statusmeldungen, Knöpfen, Bedienteilen, LEDs, Anzeige und Aktoren (ca.30). Es gibt einen zentralen µC, der das alles steuert.
Aktuell wird das ganze in vielen verschachtelten Statemaschinen (FSMs) abgearbeitet. Dafür gibt es eine Planungssoftware, mit der man die States und Übergänge grafisch darstellen kann.
Das Problem bei der Sache ist, dass diese FSMs mittlerweile so komplex geworden sind, das nur noch Eingeweihte alles durchblicken. Zudem kommt der Kunde immer wieder mit neuen Anforderungen an die Funktionalität, so dass ich irgendeine andere Lösung suche, die Ablaufsteuerung irgendwie zu visualisieren und daraus Code zu generieren.
tldr:
Also die Aufgabe ist ein Möglichkeit zu finden ein komplexe Ablaufsteuerung (visuell) zu designen und daraus Code für µC 32bit in C (wenn möglich MISRA) abzuleiten.
Was seht ihr hier für mögliche Wege?
tldr:
Also die Aufgabe ist ein Möglichkeit zu finden ein komplexe
Ablaufsteuerung (visuell) zu designen und daraus Code für µC 32bit in C
(wenn möglich MISRA) abzuleiten.
Was seht ihr hier für mögliche Wege?
Eine DSL (domain specific language) dafuer herzunehmen, und im Sinne von test-driven-development gleich das Verifikationsszenario dafuer mitliefern. Grafisches Programmieren endet bei inkrementell wachsender Komplexitaet typischerweise mit kaum wartbaren Write-Only-Code (wie du ja schon anklingst). Kann da leider nur mit HDL- und Simulator-Konzepten dienen. Insofern kann ich dir nur den Tip geben, im Sinne eines Prozessor-Opcode deine Maschinenzustaende zu betrachten und auf der Basis Test & Coverage zu machen - moeglichst nicht grafisch. Schlussendlich wird dich auch die Safety gehoerig beschaeftigen...
Das Ganze in autarke Subsysteme aufspalten, zwischen denen nur die allernötigste Kommunikation stattfindet. Wenn möglich nicht nur die Soft, sondern auch die Hardware.
Jedes Subsystem einzeln und im gleichen "Style" entwickeln und testen, dann nach und nach zusammenfügen ...
Du hast (auftragsgeberseitig) Spezialisten, die die notwendigen Prozesse kennen, Entwickler, die sie komplett durchdenken müssen und Auftraggeber, die es verstehen müssen.
Dafür braucht es ausdrucksstarke Sprachen. Grafisch sieht verlockend aus, ist aber oft nur für oberflächliche (abstrakte) Konzepte oder für Spezialthemen (HW-Schaltplan) nützlich. Aus dem gleichen Grund, warum Physikbücher oft mehr Text als Bilder enthalten.
Ausdrucksstark ist nur das, was Beteiligte verstehen. UML (beispielsweise) kann detailliert und ausdrucksstark sein, ist aber fehl am Platz, wenn die Grafikelemente eher "intuitiv" benutzt werden.
Eine Sprache wie C ist niemals die Basis einer komplexen SW. Sondern maximal Ursprung einer oder mehrerer anwendungsspezifischer, ausdrucksstarker Sprachsysteme.
Je nach Kenntnis der 3 Gruppen musst Du überlegen, ob Du ein ausdruckstarkes System in C entwirfst und Dich um dessen graphische Darstellung kümmerst oder umgekehrt.
eine Seite Grafik entspricht selten mehr als einer Seite Code. Sobald es 20 Seiten werden, ist Grafik kaum noch zu analysieren, Code hingegen schon.
Jedes Subsystem einzeln und im gleichen "Style" entwickeln und testen,
dann nach und nach zusammenfügen ...
Ja, auf dem Papier eine ganz tolle Sache. In der Praxis kommt der Kunde dann mit Anforderungen, die jegliche Abstraktion oder Modularität zunichte machen. Da werden Abhängigkeiten von völlig unterschiedlichen Modulen verlangt, an die zuvor niemand hätte denken können.
tldr:
Also die Aufgabe ist ein Möglichkeit zu finden ein komplexe
Ablaufsteuerung (visuell) zu designen und daraus Code für µC 32bit in C
(wenn möglich MISRA) abzuleiten.
Was seht ihr hier für mögliche Wege?
Dann schau dir mal z.B. Jetbrains MPS [1] näher an. Ist aber eine steile Lernkurve.
Ich glaube nicht, dass grafische Programmierung die Sache vereinfacht. Habe ein paar Projekte mit erlebt, die nicht gut liefen. Bei den einfachen geradeaus-Fällen aus der Werbung sieht das immer überzeugend aus, aber reale Anwendung sind komplex und voller Sonderlocken. Da wird das schöne grafische Korsett schnell zum Hindernis.
Jedes Subsystem einzeln und im gleichen "Style" entwickeln und testen,
dann nach und nach zusammenfügen ...
Ja, auf dem Papier eine ganz tolle Sache. In der Praxis kommt der Kunde
dann mit Anforderungen, die jegliche Abstraktion oder Modularität
zunichte machen. Da werden Abhängigkeiten von völlig unterschiedlichen
Modulen verlangt, an die zuvor niemand hätte denken können.
Ja, das halte ich für möglich, aber nicht für wahrscheinlich.
Jemand, der eine komplexe Maschine beauftragt, wird sicher nicht wollen, dass die Maschine irgenwelche völlig sinnlosen Sachen macht. Also werden die (meisten) Änderungswünsche sinnvoll und logisch nachvollziehbar sein. Wenn das nicht abbildbar ist, war das Prozess- oder Datenmodell eben unvollkommen.
Ausserdem müssen nachträgliche Änderungen auch bezahlt werden, was den Schmerz sicher erträglich macht :-)
Ja, auf dem Papier eine ganz tolle Sache. In der Praxis kommt der Kunde
dann mit Anforderungen, die jegliche Abstraktion oder Modularität
zunichte machen. Da werden Abhängigkeiten von völlig unterschiedlichen
Modulen verlangt, an die zuvor niemand hätte denken können.
Das ist im Nachhinein (unter dem Aspekt, dass die Eigenschaften-Definition nicht grundlegend geaendert wird) kaum vermeidbar. Dafuer gibt's typischerweise Event-Knoten, die andere Knoten im Baum der Geraete-Eigenschaften benachrichtigen.
Aber dann kommen die Event-Handler ins Spiel: was soll bei welchem Wert gemacht werden?
Dann ist man eben schnell wieder bei einer bare-metal-Programmiersprache.
Zum 'grafischen Programmieren' gibt es hier eine Menge ausufernder Threads, der Knackpunkt neben Write-Only-"Code" ist vor allem der, dass damit weder vernuenftige Revisionskontrolle (Tracken von Aenderungen) noch automatische Testbench-Erstellung fuer Simulation und Coverage moeglich ist.
Wie ich das machen würde, ohne die genauen Anforderungen zu kennen:
In UML modellieren. Dabei darauf achten, dass man so viel wie möglich in Unter-FSMs ausgliedert.
Dann entweder händisch die FSMs programmieren. Dabei strikt dran denken, dass die so arbeiten:
State -> Event -> Action -> new state
Die FSMs kommunizieren untereinander nur mit Events. Es gibt kein Interface dazu. Die Events werden über Mailboxes gesendet und empfangen.
FSM1 schickt ein EventY an FSM2. Die arbeitet das ab und schickt ein event zurück an FSM1. Event wäre z.B. "position", "done" oder "timeout".
Events können auch parameter haben. Z.B. "position 123.45". Primitive, aber einfache Lösung dafür sind einfach Strings. Ja, das geht deutlich besser als mit strings.
Die FSMs werden einfach zyklisch aufgerufen
1
loop
2
MainFSM();
3
FSM1();
4
FSM2();
5
endloop;
Erweiterte Lösung:
Man bastelt sich eine eigene Beschreibungssprache die man einfach im Editor bearbeiten kann. Den Text lädt man dann in den uC, der parst das, baut daraus etliche Objekt für mehrere FSMs die dann wieder in einer loop aufgerufen werden.
Hab sowas schon gemacht, hat bestens funktioniert. Das ist aber initial viel Aufwand. Änderungen danach sind aber trivial, der C(++)-code bleibt gleich.
Zum Einlesen von Daten (DA20, für Ausschreibung-Vergabe-Abrechnung, Bauwesen) gibts ein wirres Gelbbuch. Um das zu abstrahieren, hab ich auch dafür eine Beschreibungssprache gebaut. Der Rest waren relativ einfach Objekte in C++ die von einem Datenstrom (der Eingabedatei) gefüttert wurden.
Erweiterte Lösung:
Man bastelt sich eine eigene Beschreibungssprache die man einfach im
Editor bearbeiten kann.
Wenn man mal auch nur ganz kurz überlegt, seit wie vielen Jahrzehnten es schon digital gesteuerte komplexe Maschinen gibt, könnte man dahinter kommen, daß es das alles schon gibt.
In UML modellieren. Dabei darauf achten, dass man so viel wie möglich in
Unter-FSMs ausgliedert.
Sehe ich ähnlich. Wenn schon soviel Aufwand betrieben wurde, FSMs zu spezifizieren, wozu das nicht nutzen. Nutzt man dann ein richtiges Modellierungstool wie Sparx EA, lassen sich die einzelnen Zustandsmodelle zusammenführen, simulieren und auch codemäßig synthetisieren in die Programmiersprache der Wahl. Setzt aber halt bisschen Modellierungs-Knowhow bzw. die Bereitschaft, sich modellgetrieben zu nähern, voraus. Wobei eine Offenheit im Automotivebereich für sowas wohl eher da ist, als in manch anderer Branche.
und auch codemäßig synthetisieren in die Programmiersprache der Wahl.
Ich würde das nicht machen, hab es aber nie probiert. :-)
Zeichne ich State-Machines nicht auf, und wenn, dann mit Bleistift und Papier.
Befürchte ich, dass Änderungen in der Darstellung unangenehme Konsequenzen im Code haben.
Bezweifle ich die Lesbarkeit des codes.
Aber ich hab da keine Erfahrung.
Ausser mal mit YACC. Aber in der Zeit bis das funktioniert und das Syntax-Diagramm in deren Schreibweise übersetzt habe, schreib ich den Parser echt selbst.
Es gibt einen Grund warum es heute noch Ampelanlagen historisch mit SPS
aufgebaut gibt.
Siemens.
Sonst keinen.
Es gibt auch andere Länder, die funktionierende Ampeln haben.
Da laufen auf dem Fußgängerübergang lustige grüne Männchen in LED, die dann 20 Sekunden vor Fußgängergrünphasenende beschleunigen und 10 Sekunden später richtig rennen.
Wird Siemens nie schaffen.
Da laufen auf dem Fußgängerübergang lustige grüne Männchen in LED
Was hat das mit der SPS zu tun? Glaubst du, dass die die Animation pixelweise an jede Ampel überträgt?
Was bringt das laufende Männchen? Wenn es für den Fußgänger auf Rot schaltet, startet sofort der Querverkehr?
Die Anforderungen in D-Land an Ampelschaltungen sind sehr hoch. Da wird jedes Leuchtmittel überprüft. Wenn eines nicht mehr geht, schaltet sich die Ampel sicher ab. In anderen Ländern ist das einfach egal.
Steuerung einer komplexen Maschine im Automotiv-Umfeld neu zu "denken".
Man stelle sich eine große Maschine vor mit vielen Sensoren (20+),
Statusmeldungen, Knöpfen, Bedienteilen, LEDs, Anzeige und Aktoren
(ca.30). Es gibt einen zentralen µC, der das alles steuert.
Zähle mal nach ... ist doch gar nicht soviel.
Was macht die Maschine .... einen Fest Programmierten Ablauf.
Dann ist das doch gar nichts...
Was machen die Sensoren - Fehlermeldung in einem gewissen Schritt/punkt ... => Stop
==> Maschinenbediener Störung beseitigen.
Bei FSMs benutze ich gerne das klassische State Pattern, also eine Klasse pro Zustand, und es existiert immer genau eine Instanz einer dieser Klassen; bei Zustandsübergängen wird die Instanz zerstört und stattdessen eine neue Instanz einer anderen Klasse erstellt. Für Firmware also typischerweise in C++, lässt sich natürlich auf alle OOP-Sprachen übertragen.
Man kann so alle Daten, die nur für einen Zustand relevant sind, in die jeweilige Klasse stecken; somit kann man auf diese Daten gar nicht versehentlich im falschen Zustand zugreifen. Bei Betreten und Verlassen eines Zustands werden Konstruktor bzw. Destruktor der Klasse aufgerufen. Indem man alle Zustandsklassen von einer gemeinsamen Basisklasse ableitet und dort virtuelle Funktionen definiert, kann man diese pro Zustand überschreiben, und damit pro Zustand individuell auf externe Ereignisse reagieren (I/O). Dadurch hat man sehr übersichtlich alles was zu einem Zustand gehört in der jeweiligen Klasse zusammen gesammelt. Der Nachteil ist i.W. dass es in C++ initial recht viel Schreibarbeit ist, das finde ich aber nicht so schlimm. Indem man die Klassen in eine std::variant oder union steckt braucht man auch keinen dynamischen Speicher.
Das Ganze kann man dann noch mit dem Observer-Pattern kombinieren, sodass Zustandsklassen auf Ereignisse anderer FSMs reagieren können (Callbacks). Man kann auch in einzelne Zustandsklassen wiederum komplette weitere FSMs hinein verschachteln. Damit kann man im Endeffekt ein komplett asynchrones/event-gesteuertes System umsetzen, braucht keine Message-Queues und auch keine zyklischen zeitgesteuerten Aufrufe - eine FSM wird nur genau dann tätig, wenn sich etwas verändert hat (typischerweise durch Interrupt erkannt). Den Rest der Zeit kann die CPU im Sleep-Modus rumhängen.
Bei vielen Zuständen wird der Code allerdings gerne mal recht unübersichtlich, weil die Zustandsübergänge über den ganzen Code verteilt sind (typischerweise in den einzelnen virtuellen Ereignis-Funktionen der Zustandsklassen) - anders als bei traditionellen Ansätzen mit einer zentralen Tabelle oder switch-case wo alle Übergänge gesammelt sind. Dafür ist aber alles, was zu einem Zustand gehört, zusammen gesammelt.
Da gibt's aber einen super Trick: Mit KI kann man ziemlich gut den Code analysieren und sich ein Zustandsdiagramm ausgeben lassen, z.B. in der "dot"-Sprache, die man dann per Graphviz in ein grafisches Diagramm (SVG) verwandeln kann. Da kann man sich auch schön die Bedingungen der Zustandsübergänge an die Pfeile schreiben lassen.
Das wäre dann der umgekehrte Weg, also Code->Grafik statt Grafik->Code wie z.B. bei QM. Wenn man im Diagramm Probleme entdeckt, überarbeitet man den Code und lässt das Diagramm neu generieren. Der Code ist die "Single-Source-of-Truth". Das Diagramm kann auch gern riesig werden, ist aber nicht so schlimm weil man es ja nicht direkt bearbeitet.
Man müsste mal ausprobieren, ob die auch den Weg Grafik->Code schafft, also z.B. ein handgezeichnetes Diagramm in ein Code-Gerüst überführen, das man dann manuell weiter bearbeiten kann. Würde etwas Tipparbeit ersparen.
tldr:
Also die Aufgabe ist ein Möglichkeit zu finden ein komplexe
Ablaufsteuerung (visuell) zu designen und daraus Code für µC 32bit in C
(wenn möglich MISRA) abzuleiten.
Was seht ihr hier für mögliche Wege?
Ich sehe erst einmal ohne zu wissen, was diese komplexe Maschine ist, keine Möglichkeit. Ich beschreib mal mit meinen Worten.
Komplexe Maschine = Roboter
Aufgabe z.B. Mülleimer entleeren
Also, Film mit einem Müllwerker drehen, dem Roboter den Film zeigen, der erstellt sein dafür notwendiges Programm in einer den Menschen einfach lesbarem Programm und legt los.
Neue Aufgabe: Strafzettel schreiben
Politesse filmen, der komplexen Maschine zeigen und ihn dann ein Programm schreiben lassen, welches in einer dem Menschen einfach nachvollziehbaren Form verständlich ist. Dann ihn auf die Straße schicken und arbeiten lassen.
Nächste Aufgabe Fenster putzen..
nächste Aufgabe...
usw.
Ok, bei diesen Gedanken muss ich leicht schmunzeln, so ähnlich ist ein Lackierroboter schon vor vielen Jahren vorgestellt worden. Da hat ein Lackierer im Anlernbetrieb die Farbspritze geführt und die Maschine hat diese zuerst über- und danach Optimierungen vorgenommen. Gut, nicht grafisch, dennoch ein Weg, um komplexe Systeme für eine Aufgabe einzurichten. Aber, die dafür notwendige Programmierung bleibt den Experten überlassen und auch die Pflege und Fehlersuche wird nicht in einfach verständlicher Form Jedermann zugänglich sein. Ich habe über 30 Jahre an Anlagen alle möglichen Programme geschrieben, neue Ideen umgesetzt und war immer bemüht, meinen Kollegen durchschaubaren Code zu liefern. Ehrlich, nicht jeder ist damit zurecht gekommen. Auch wenn eine grafische Dokumentation auf die Programmblöcke hinwies, nicht selten wurde auch das nicht verstanden. Ich halte es für Wunschdenken, einfach von Seiten einer Grafik ein Programm erstellen zu lassen, welches alle Anforderungen in Bezug auf Funktionalität, Sicherheit und Wartbarkeit erfüllt. Vielleicht hilft KI, doch ich wäre da eher skeptisch. Aber es ist vielleicht eine lebensfüllende Herausforderung, an der man selbst wachsen kann. Anfangen kann man bspw. mit einer Datenbank, in der die Funktion der Sensorik und Aktoren beschrieben ist, sowie Erfassen der möglichen Aufgaben, die für die komplexe Maschine in Frage kommen. Daraus könnte man Prozesse ableiten die möglicherweise in allgemein verständlicher Form dargestellt werden können. Einfach ausgedrückt PAP. Dieser würde in ein Programm transferiert werden können. Aber eben nur möglicherweise. Und das wäre auch nichts wirklich neues. Nur du weißt, mit was du zu tun hast. Du kennst die Beschaffenheit der Maschinen. Du kennst das Einsatzgebiet. Ohne diese Information sehe ich keine Chance, die eierlegende Wollmilchsau zu finden. Aber auch ich hätte an einer solchen Aufgabe Spaß, obwohl es meine aktuellen Fähigkeiten überträfe.
Also, viel Spaß
Gruß oldmax
Ich halte es für Wunschdenken, einfach von Seiten einer Grafik ein
Programm erstellen zu lassen, welches alle Anforderungen in Bezug auf
Funktionalität, Sicherheit und Wartbarkeit erfüllt.
Das ist der Punkt. Komplexe Programme sehen grafisch dargestellt noch viel komplexer aus, wenn die Grafik vollständig sein soll. Und wenn sie nicht vollständig ist, kann man daraus alleine noch keinen Code generieren.
In der Praxis lief es bei meiner Arbeit stets darauf hinaus, dass man
Grafik
Text
Code
zusammen erstellt. Sie ergänzen sich gegenseitig und sind alle drei notwendig. Keins der drei Dokumente lässt sich in ausreichender Qualität automatisch aus den anderen heraus generieren. Nur zum Teil - man muss manuell zuarbeiten.
Ich habe sehr gute Erfahrung damit gemacht, die Dokumentation in Form eines Wikis zu erstellen, z.B. in Gitlab. Man sollte auch rege davon Gebrauch machen, Anforderungs-Dokumente mit der daraus entstandenen Doku bidirektional zu verknüpfen, soweit das technisch möglich ist.