Files
sps_skel/doc/Konzept_Layout_Hardware_SCL.md
T
Michael StanglandClaude Opus 5.5 0115ef68b7 TRO-JSON v4: Slots je TRO und Staubereiche (jamAreas)
- model: Slot (separator/switch/scanner/drive + Rollen), JamArea (J<Separator>,
  Eingang eines TRO mit allen Vorgaengern), derive_slots, derive_jam_areas;
  Schema sps_skel-tro-v4, v3-Dateien werden weiter gelesen
- scl_context: ein JamEntr je eigenem Staubereich statt je Vorgaenger (wie
  UH01-UH05), Ausgaenge nennen den Staubereich des Nachfolgers
- Golden Files neu erzeugt, Tests fuer Slots/Staubereiche, Doku nachgezogen

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 22:44:02 +02:00

19 KiB
Raw Blame History

Konzept: Layout und Hardwareplanung → Anlagen-JSON → SCL

Stand 2026-10-11. Zielbild für den Ausbau der Pipeline, damit die beiden Fachabteilungen unabhängig voneinander und zeitversetzt liefern können. Welche Angaben aus welcher Quelle kommen, steht in doc/Datenquellen_Layout_Hardwareplanung.md; die Rohangaben beider Quellen in doc/Klassenhierarchie.md, Kapitel "Daten".

Ausgangslage

Die Produktion läuft über zwei Abteilungen:

  1. Anlagenlayout (aus dem Angebotswesen, detaillierter aus der Projektierung). Liefert alles für die TROs: Bauteile, Abfolge, Weichen, Staubereiche, Systemgrenzen.
  2. Hardwareplanung (Karten, Kabel, Sensoren, Aktoren). Liefert die globalen Variablen und die tatsächlichen Sensoren und Aktoren mit Namen und Adressen.

Die Hardwareplanung kommt Tage bis Wochen später als das Layout. Das System muss deshalb mit dem Layout allein ein brauchbares SCL-Skelett erzeugen und die Hardware später nachtragen können, ohne Layout-Arbeit zu wiederholen.

Zielbild

Abteilung 1: Anlagenlayout                 Abteilung 2: Hardwareplanung (später)
CSV ──tro_flow──> <csv>_tro.json           EA/TIA/WSCAD.xlsx, positionsdraw.json
                  (TROs, Abfolge,           ──hw_import──> <projekt>_hw.json
                   Staubereiche, Slots)                    (globale Variablen, Geräte)
                        │                                        │
                        └──────────── hw_assign ─────────────────┘
                                          │
                                   <csv>_anlage.json  (Layout + Zuordnungen)
                                          │
                                   scl_skeleton ──> FB_Main.scl, FB_CallSensors.scl, …
Stufe Skript Eingabe Ausgabe Status
1 Layout tro_flow.py --json CSV, cfg/tro_overrides.ini <csv>_tro.json vorhanden, wird erweitert
2 Hardware hw_import.py *_TIA.xlsx, *_EA.xlsx, *_WSCAD.xlsx, *_positionsdraw.json <projekt>_hw.json neu
3 Zuordnung hw_assign.py <csv>_tro.json, <projekt>_hw.json, Regeln, cfg/hw_overrides.ini <csv>_anlage.json, Bericht .md neu (Logik aus e_planning.py)
4 SCL scl_skeleton.py <csv>_anlage.json (oder nur <csv>_tro.json) .scl vorhanden, wird umgestellt

Grundsätze:

  • Stufe 1 allein reicht für ein Skelett. Ohne Hardware wird jeder offene Wert wie heute TODO(E-Planung).
  • Die Stufen verändern sich nicht gegenseitig. Die Zuordnung legt ihre Ergebnisse neben das Layout, statt es zu überschreiben. Ein neuer Layoutstand oder ein neuer Hardwarestand heißt: die betroffene Stufe und alles danach neu ausführen.
  • Lieber eine Lücke als ein falscher Name (wie heute in cfg/e_planning.ini): was keine Regel sicher trifft, bleibt offen und steht im Bericht.
  • Drei Quellen, jede sichtbar: Layout, Hardwareplanung und Defaults (cfg/defaults.ini, Typ-Katalog). Jede SCL-Zeile lässt sich einer davon zuordnen.

Umbauten

1. TRO-JSON zur Layout-JSON ausbauen (Stufe 1)

Heute fehlt der Zuordnung ein Ziel: die TRO-JSON sagt nicht, welche Stellen ein TRO hat, an die Hardware gehört. Daran scheitern heute Stausensoren und Weichenventile (doc/E-Planung_Bruecke.md, "Offen").

  • Slots je TRO: je Separator, Weiche, Ausgang und Antrieb ein Eintrag mit der Layout-ID des Bauteils und den Rollen, die die Hardwareplanung dort füllen muss.

    "slots": [
      {"slot": "separator1", "layoutId": "0008", "roles": ["sensor", "stopper", "jamSensor?", "partSensor?"]},
      {"slot": "switch1",    "layoutId": "0037", "exit": 3, "roles": ["valve", "exitSensor?"]},
      {"slot": "drive",      "layoutId": "0002", "roles": ["carouselRun"]}
    ]
    

    Die Slots ergeben sich aus dem Katalogtyp (items) und der Topologie; ? = optional, fehlt das Gerät, wird der zugehörige xPlugged*-Schalter FALSE.

  • Staubereiche als eigene Liste jamAreas[]: ein Staubereich je TRO-Eingang, mit allen Vorgängern, dem Förderer, auf dem er liegt, und seiner Lage auf dem Förderer (siehe "Staubereiche" unten). Heute nur abgeleitet beim Rendern (scl_context.SclJam). Dabei korrigieren: scl_skeleton erzeugt heute je Vorgänger einen eigenen Eingang (arInOutJamEntr1, …Entr2); in den Referenzen laufen mehrere Vorgänger in einem Staubereich zusammen, der TRO hat einen Eingang (Ausnahme 2Sep1Swi, PinStore).

  • Weitere Layout-Angaben: xIsBorner, Vorfahrt ja/nein, tragender Förderer mit Rolle (heute hosts ohne Rolle), Längen für tConvEmpty und Staulängen.

  • Ableitungen aus scl_context nach tro_flow/model verschieben, damit die JSON sie trägt und nicht erst das Rendern sie kennt.

  • Schema sps_skel-tro-v4.

Stand (2026-10-11), erster Teil umgesetzt:

  • model.Slot und DerivedTro.slots: separator<n>, switch<n>, scanner<n>, drive mit Rollen, Anzahl aus dem Katalog (derive_slots). Weichen-Slots haben noch keine layoutId: tro_flow hält das Weichen- bzw. Ausschleuselement nicht am TRO fest.
  • model.JamArea und TroDocument.jamAreas: je Separator laut Katalog ein Eingangs-Staubereich J<Separator> mit allen Vorgängern, dem Host und der Lage (derive_jam_areas). Bei 2Sep-Typen ist die Aufteilung der Vorgänger auf die zwei Eingänge offen (Hinweis im Feld note); beim PinStore heißt der Eingang vorläufig nach dem ersten Linien-Separator.
  • scl_context liest die Staubereiche aus der JSON: ein JamEntr je eigenem Staubereich statt je Vorgänger (Abweichung zu UH01–UH05 behoben), jeder Ausgang nennt im Kommentar den Staubereich des Nachfolgers. Golden Files neu erzeugt. Eine v3-Datei ohne jamAreas wird weiter gelesen.
  • Noch offen aus Umbau 1: Layout-ID der Weichen, xIsBorner, Vorfahrt, Host-Rolle, Längen (tConvEmpty, Staulängen), <NNNN>/<k> für den SCL-Namen der Staubereiche.

2. Neues Skript hw_import.py (Stufe 2)

  • Liest TIA-Import (PLC Tags + Constants), EA-Liste, WSCAD-Import und optional positionsdraw.json.
  • Schreibt ein neues Modell HardwareDocument:
    • Geräte je BMK: Adresse, Index-Konstante (cInBG3306), Kommentar, VERW, Steuerung, Station/Schrank, Position (falls vorhanden);
    • globale Variablen: alle Tags und Konstanten, Motor↔Motorschutz-Paare, Taster, Not-Halt.
  • Prüft die Exporte gegeneinander: BMK fehlt in einer Liste, doppelte BMK, Adresse ohne Tag.
  • Übernimmt aus e_planning.py: load_positionsdraw, EDevice, pair_drives.
  • Erste Quelle: der TIA-Import, weil er Namen und Konstanten 1:1 liefert und die spätere Prüfung des SCL ermöglicht.

3. Neues Skript hw_assign.py (Stufe 3)

  • Eingabe: <csv>_tro.json + <projekt>_hw.json; das CSV wird nicht mehr gelesen.

  • Zuordnungswege, als Regeln in einer INI (heute cfg/e_planning.ini):

    • räumlich über positionsdraw: die bestehende Logik aus e_planning.py (Lagebezug über dxf_registration, Höchst-/Sollabstand), jetzt gegen die Slots;
    • Nummernregel: MB = BG + 1 bzw. gleiche Nummer, Motor = Motorschutz;
    • nur EA-Liste, ohne Positionen: über die Kommentare ("in Separator 1 (ILS-CV M0108)") und eine von Hand gepflegte Tabelle M-Nummer → Layout-Förderer.
  • Handkorrekturen in cfg/hw_overrides.ini (analog cfg/tro_overrides.ini).

  • Ausgabe <csv>_anlage.json: Layoutteil unverändert, daneben

    "bindings": [
      {"layoutId": "0008", "role": "sensor", "bmk": "BG3306", "constant": "cInBG3306",
       "address": "%E330.6", "source": "positionsdraw", "rule": "raeumlich",
       "distance": 12.0, "status": "zugeordnet"}
    ]
    

    status: zugeordnet | offen | widerspruch.

  • Stabile Schlüssel: Zuordnungen hängen an TRO-ID + Slot + Rolle. Die TRO-IDs sind ab der Festlegung durch die SPS-Programmierer stabil (siehe "TRO-IDs" unten). Die Layout-TeileId taugt dafür nicht: sie ändert sich zwischen zwei CSV-Exporten (siehe dort). layoutId in bindings dient nur zur Nachverfolgung im aktuellen Stand.

  • Gegenprüfung beider Quellen (Anzahl Separatoren vs. IN SEP, Weichen vs. AE ABZWEIG, angetriebene Strecken vs. MA) in den Bericht.

4. scl_skeleton.py / scl_context.py (Stufe 4)

  • Liest eine Eingabe: <csv>_anlage.json; ohne Hardwareteil wie heute <csv>_tro.json.
  • --eplan und die Zusammenführung in scl_context._separator entfallen; der Kontext liest Namen aus bindings, offene Slots werden TODO(E-Planung).
  • Prüfung gegen die globalen Variablen: jeder Tag und jede cIn…-Konstante im SCL muss im TIA-Import stehen, sonst Abbruch mit Liste.
  • Neue Bausteine nach Stufe 2: FB_CallSensors aus der Sensorliste, Antriebsaufrufe (fbCarousel0102) aus den Motorpaaren, Staubereichs-DBs.

5. Defaults als dritte Quelle

Zeiten und Projektkonstanten, die heute fest in scl_skeleton.py stehen (t#600ms, T#1500ms …), wandern in den Typ-Katalog (tro_catalog.py) bzw. eine Projektdatei cfg/defaults.ini.

Bestehende Programme

Programm Rolle im neuen Ablauf
material_flow.py, tro_flow.py bleiben Stufe 1; Ausbau um Slots und jamAreas
tro_catalog.py, model.py, tro_overrides.py, dxf_registration.py bleiben Bibliotheken; model.py bekommt Slots, jamAreas, Anlagen-JSON
e_planning.py wird aufgeteilt (unten)
tro_annotate.py bleibt als Kontrollansicht, liest künftig die JSON (unten)
tro_extract.py entfällt bzw. wird umgebaut (unten)
scl_skeleton.py, scl_context.py Stufe 4, Umstellung auf <csv>_anlage.json

e_planning.py → hw_import + hw_assign

Teil heute Wohin
load_positionsdraw, EDevice, pair_drives hw_import.py
resolve_transform, load_rules, _assign_spatial, _assign_by_number, Bericht hw_assign.py, Ziele = Slots statt CSV-Bauteile
cfg/e_planning.ini Regeldatei von hw_assign
EplanDocument / <csv>_eplan.json entfällt, ersetzt durch bindings[]

Übergang: e_planning.py bleibt kurz als Hülle, die hw_import und hw_assign nacheinander aufruft, damit bin/e_planning.bat weiter funktioniert; danach löschen.

tro_annotate.py → Kontrollansicht für Layout und Zuordnung

  • Aus der JSON zeichnen statt analyse_tros selbst aufzurufen: die Zeichnung zeigt dann genau das, woraus das SCL entsteht.
  • Zuordnungen einzeichnen: neben jedem Slot das BMK (BG3306, MB3306), offene Slots und Widersprüche rot. Für die Hardwareplanung die schnellste Kontrolle der räumlichen Zuordnung.
  • --emit-lisp (TROEDIT) bleibt, solange Marker in BricsCAD bearbeitet werden; hängt an der Entscheidung zu tro_extract.

tro_extract.py → entfällt im neuen Ablauf

Es wäre ein dritter Korrekturweg neben cfg/tro_overrides.ini (Layout) und cfg/hw_overrides.ini (Zuordnung) und schreibt noch das alte Schema sps_skel-tro-extract-v1, das niemand mehr liest.

  • Löschen (Empfehlung), zusammen mit TROEDIT/--emit-lisp. Korrekturen nur in den INI-Dateien: nachvollziehbar und versioniert.
  • Umbauen, falls die Projektierung in BricsCAD korrigieren will: es schreibt dann Einträge in tro_overrides.ini/hw_overrides.ini, keine eigene JSON.

Bis zur Entscheidung bleibt es geparkt.

Festlegungen (2026-10-11)

TRO-IDs

Festgelegt: Die TRO-IDs vergeben die SPS-Programmierer, die zugleich die Anwender der Skripte sind. Eine ID muss nur eindeutig sein. Üblich ist eine Nummerierung entlang des Materialflusses und eine Benennung nach den Bauteilen (Kreisel usw.), vorgeschrieben ist das nicht. Sobald größere Teile des SPS-Codes stehen, ändern sich die IDs nicht mehr; in der frühen Projektphase dürfen sie mehrmals neu vergeben werden.

Befund: Heute vergibt tro_flow laufende Nummern je Lauf (TRO01, TRO02 …, tro_flow.py Zeile ~1163); cfg/tro_overrides.ini warnt bereits, dass sich die Nummern bei neuer Datenbasis verschieben. Die Layout-TeileId ist ebenfalls nicht stabil: Vergleich zweier Exporte derselben Anlage

Vergleich Bauteile gleiche Id und Lage gleiche Lage, andere Id
mubea.csv ↔ mubea_export.csv 119 / 125 46 27
HundM05.csv ↔ HundM05_14.csv 45 / 44 22 16

Stabil ist nur die Lage des Bauteils.

Umgesetzt (2026-10-11, lib/tro_ids.py, Schalter in tro_flow.py; Einzelheiten in doc/Python_Scripts.md §4 "TRO-IDs"):

  • Eine versionierte ID-Datei je Anlage, cfg/<csv>_tro_ids.ini, Abschnitt [tro]: je TRO die ID und die Lage seines Anker-Separators (x, y in mm), der Kommentar dahinter nennt Typ, Bezeichnung und Separatoren. Von tro_flow angelegt, von den SPS-Programmierern umbenannt. Weitere Abschnitte (später Separator- und Förderernummern) bleiben bei jedem Lauf erhalten. Ein anderer Export derselben Anlage nutzt dieselbe Datei über --ids.

    [tro]
    TRO01 = -400.0, 13920.0    ; 1Sep1Swi | Separator 0003 auf Kreisel2 Bahn L | Sep 0003
    K0302_1 = 10310.0, -440.1  ; von Hand umbenannt
    
  • Standard (IDs halten): tro_flow liest die ID-Datei und findet jeden TRO über die Lage seiner Separatoren wieder (Toleranz --id-tolerance, Standard 100 mm, nächster Treffer zuerst, je TRO ein Eintrag). Gefundene TROs behalten ihre ID, auch umbenannte. Neue TROs bekommen die nächste freie Nummer und werden an [tro] angehängt; weggefallene stehen im Bericht (mit dem TRO, der ihren Separator jetzt enthält), bleiben in der Datei, ihre ID wird nicht wiederverwendet. tro_annotate liest dieselbe Datei, schreibt sie aber nicht.

  • Programmschalter --renumber (frühe Phase): alle IDs neu entlang des Materialflusses vergeben (Tiefensuche ab den Beladestationen, auf Kreisel und Strecke in TrackIds-Reihenfolge) und [tro] neu schreiben. Ohne ID-Datei geschieht dasselbe beim ersten Lauf.

  • Geprüft mit mubea.csv → mubea_export.csv (andere TeileIds): 18 TROs wiedergefunden, darunter eine umbenannte ID; TRO14 als weggefallen gemeldet, weil der Export die Separatoren 0005 und 0036 zu einem 2Sep2Swi (TRO13) zusammenfasst.

  • Noch offen: die Abschnitte [mubea.csv.tro.TRO03] usw. in cfg/tro_overrides.ini hängen an der alten Nummerierung und passen schon heute nicht mehr (TRO03 ist dort Sep 0010, im aktuellen Lauf Sep 0011). Sie werden auf die IDs der ID-Datei umgestellt, sobald tro_flow die Overrides wieder liest.

  • Dadurch werden auch die Abschnitte [<csv>.tro.<TRO-ID>] in cfg/tro_overrides.ini und die Zuordnungen von hw_assign stabil.

Staubereiche

Bisheriges Namensschema (Referenzen UH01–UH05, doc/TRO_Katalog/connect.ini, 286 Staubereiche):

"DB_JamArea<NNNN>".stJam<NNNN>_<k>      Kurzform JA<NNNN>_<k>
  • <NNNN> = Förderer, auf dem der Staubereich liegt, ein DB je Förderer: 0102 = Kreisel K0102 (vgl. #fbCarousel0102), 0103/0104 = Strecken, 4103/4104 = Vario-Förderer.
  • <k> = laufende Nummer entlang des Materialflusses auf diesem Förderer; Kreisel K0102 hat _1 … _6 in Umlaufrichtung.
  • 249 der 286 folgen diesem Schema. Sonderfälle: Lagerlinien Storage1.1.2 (24), Übergabe an eine andere Steuerung IO_Device_UHxx_TO_UHyy… bzw. lokal #arCarrierHandoverJam5000 (9), JamBuffer101 im Leerträgerpuffer (2), F2H (1).

Prüfung der Annahme "ein Staubereich = Ausgang des Vorgängers und Eingang des Nachfolgers":

  • Kein Staubereich hat mehr als einen Nachfolger-TRO.
  • 65 Staubereiche haben mehrere Vorgänger: dort laufen Ströme zusammen, z. B. JA0102_2 mit Vorgängern TRO101, TRO106 und TRO107 (Weichenausgang), alle mit Nachfolger TRO112.
  • Jeder TRO hat genau einen Eingangs-Staubereich; einzige Ausnahme sind die PinStore-TROs (zusätzlich die Lagerlinie).

Ein Staubereich ist also immer der Eingang genau eines TRO, aber nicht immer der Ausgang genau eines Vorgängers. Ein Name nach dem Schema ja_tro3tro4 ist bei Zusammenführungen nicht eindeutig.

Vorschlag:

Ergänzung (2026-10-11): In einem Mubea-Layout heißen die Staubereiche nach ihrem Separator: der Staubereich vor Sep1024 heißt J1024. Das passt zum Befund oben: der Staubereich ist die Warteschlange vor dem Stopper, also der Eingang genau eines TRO bzw. genau eines Separators. Das Layout liegt nicht im Repo; Quelle der Separatornummer (Zeichnungsbeschriftung, E-Planung, Vergabe durch die SPS-Programmierer) noch klären.

  • Kennung nach dem Separator: J<Separatornummer>, z. B. J1024. Das ist feiner als eine Kennung je TRO und deckt TROs mit mehreren Separatoren (2Sep1Swi mit JamEntr1/JamEntr2) ohne Sonderregel ab. Zusammenführungen sind kein Problem, weil der Name nur am Nachfolger hängt.

  • Separatornummern wie TRO-IDs behandeln: in derselben ID-Datei, über die Lage des Separators wiedergefunden, von den SPS-Programmierern vergeben bzw. übernommen; --renumber vergibt sie in der frühen Phase neu.

  • Name im SCL — festgelegt: Standard sind die SCL-Dateien UH01–UH05, also "DB_JamArea<NNNN>".stJam<NNNN>_<k>. J<Separatornummer> ist nur die Kennung in der JSON (und die Beschriftung im Layout), nicht der SCL-Name. Für den SCL-Namen braucht es je Staubereich:

    • <NNNN>: die Förderernummer des Förderers, auf dem der Staubereich liegt (Kreisel K0102 → 0102); vergeben von den SPS-Programmierern bzw. aus der Hardwareplanung (KR-K0102), gepflegt in der ID-Datei wie TRO-IDs und Separatornummern;
    • <k>: laufende Nummer entlang des Materialflusses auf diesem Förderer, aus dem Layout abgeleitet (Kreisel in Umlaufrichtung, beginnend an einer festzulegenden Stelle, z. B. nach der Einschleusung).

    Ohne Förderernummer bleibt der Name TODO(E-Planung) wie heute.

  • Ausnahmen bleiben Sonderfälle mit eigenem Namen: Lagerlinien, Übergabe an eine andere Steuerung, Leerträgerpuffer.

Korrekturen in BricsCAD

Zurückgestellt. Eine Alternative wäre, die <csv>_tro.json zu visualisieren und von Hand zu bearbeiten. Bis dahin bleibt tro_extract.py geparkt, TROEDIT unverändert.

Reihenfolge

  1. TRO-IDs stabil machen: ID-Datei, Wiederfinden über die Lage, --renumber. Darauf bauen Overrides, Staubereiche und Zuordnungen auf. Erledigt (2026-10-11).
  2. Slots und jamAreas in die TRO-JSON (Umbau 1), ein Eingangs-Staubereich je TRO — ohne Slots hat die Zuordnung kein Ziel. Erster Teil erledigt (2026-10-11, siehe Umbau 1 "Stand").
  3. hw_import mit dem TIA-Import als erster Quelle.
  4. hw_assign mit der räumlichen Logik aus e_planning.py; e_planning.py als Übergangshülle.
  5. scl_skeleton auf <csv>_anlage.json umstellen, --eplan entfernen; tro_annotate auf JSON umstellen.
  6. Defaults (cfg/defaults.ini), FB_CallSensors, EA-Liste ohne Positionen.

Zu jedem Schritt: bin/-Wrapper für neue Skripte, Tests unter tests/ (kleine TIA-Datei als Testdaten), Golden Files bei Schemawechsel bewusst neu erzeugen, doc/Python_Scripts.md ergänzen.

Offene Entscheidungen

  • Staubereiche: woher die Separatornummer (Sep1024 → J1024) stammt; wo auf einem Kreisel die Zählung <k> beginnt (Referenz K0102 prüfen). Das SCL-Schema ist festgelegt (UH01–UH05).
  • Toleranz beim Wiederfinden der TROs über die Lage: vorläufig 100 mm (--id-tolerance). Ein weiter verschobener Separator wird als "neu" und "weggefallen" gemeldet, der Programmierer übernimmt die ID von Hand in der ID-Datei. Mit echten Layoutänderungen prüfen, ob der Wert passt.
  • Korrekturen in BricsCAD oder in der JSON: zurückgestellt.