- 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>
46 KiB
Klassenhierarchie
Bestandsaufnahme aller Python-Klassen in lib/ (Stand 2026-10-10). Kurzes
Ergebnis vorweg: es gibt praktisch keine Vererbung in diesem Code (eine
Ausnahme: DerivedTro(TroBase), plus die Standard-Exception
RegistrationError(RuntimeError)). Alles andere sind flache, eigenständige
Klassen — entweder @dataclass (veränderlicher Laufzeit-/Analysezustand) oder
Pydantic BaseModel (validierte Daten, die auch als JSON ein-/ausgehen). Eine
klassische "ist-ein"-Hierarchie zu suchen wäre hier der falsche Blickwinkel;
interessanter ist, wer wen enthält/referenziert und in welchem Modul-Layer
eine Klasse sitzt (siehe Layer-Kommentar oben in model.py).
Modul-Layer (wer darf wen importieren)
tro_catalog.py (Typ-Ebene: was ein TRO-Typ ist)
|
v
model.py (Instanz-Ebene: ein konkreter TRO, die TRO-JSON)
|
v
tro_flow.py (Ableitung: CSV-Graph -> Analysis -> TroDocument)
|
+----------------------+
v v
scl_context.py tro_annotate.py (Ausgabe: annotierte Zeichnung)
(TroDocument -> SclFile, Render-Kontext)
|
v
scl_skeleton.py (Ausgabe: SclFile -> FB_Main.scl, generisch oder per Jinja-Template)
material_flow.py dxf_registration.py (eigenständig, ohne Abhängigkeit auf obige)
tro_overrides.py (importiert model.Connection / model.TroCandidate)
e_planning.py (Brücke zur E-Planung; importiert dxf_registration, liest das
CSV über material_flow; scl_context kennt nur EplanDocument)
tro_flow.py und tro_annotate.py definieren keine eigenen Klassen (nur
Funktionen). scl_skeleton.py hat genau eine (SclTemplates, Jinja-Anbindung).
material_flow.py hat Graph-Dataclasses — das ist CSV-Rohmodell, nicht
TRO-Modell.
Vererbung (ASCII)
RuntimeError (stdlib) BaseModel (pydantic, stdlib: pydantic)
| |
+-- RegistrationError +-- _Positioned (model.py, Mixin)
(dxf_registration.py) |
+-- TroBase
| +-- DerivedTro
+-- TroCandidate
Das ist die gesamte class X(Y)-Liste im Projekt — alle anderen Klassen unten
haben object/BaseModel direkt als einzige Basis und erscheinen hier nur
noch als Gruppen nach Datei.
Klassen nach Datei, mit Komposition ("enthält")
lib/tro_catalog.py [Typ-Katalog, keine Instanzdaten]
├── TroItem (Konstanten-Klasse: Bauteilarten wie SEPARATOR, SWITCH)
├── TroSymbol (Konstanten-Klasse: Zeichensymbole wie CIRCLE, TRIANGLE)
├── TroStyle(BaseModel) Farbe/Darstellung einer Typgruppe
└── TroDefinition(BaseModel)
└─ style: TroStyle (1 TroDefinition hat genau 1 TroStyle)
lib/model.py [Instanz-Ebene / TRO-JSON]
├── TroBase(BaseModel)
│ └─ definition() --> TroDefinition (gelesen aus tro_catalog, nicht gespeichert)
│ └── DerivedTro(TroBase) [einzige echte Vererbung im Projekt]
│ └─ slots: list[Slot] (Stellen fuer die Hardwareplanung)
├── _Positioned(BaseModel) (Mixin: position {x,y,z}, describe_position)
│ ├── TroBase, TroCandidate, JamArea
├── Slot(BaseModel) (separator1/switch1/scanner1/drive + Rollen)
├── JamArea(_Positioned) (Staubereich J<Sep>: Eingang eines TRO)
├── Connection(BaseModel) (from/to/kind zwischen zwei TRO-IDs)
├── TroCandidate(_Positioned) (gemeldete Stelle, an der ein TRO erwartet wird)
├── Analysis(BaseModel)
│ ├─ tros: list[DerivedTro]
│ ├─ isolated: list[DerivedTro]
│ └─ boundaries: list[DerivedTro]
└── TroDocument(BaseModel) (= <csv>_tro.json)
├─ tros: list[DerivedTro]
├─ boundaries: list[DerivedTro]
├─ connections: list[Connection]
├─ candidates: list[TroCandidate]
└─ jam_areas: list[JamArea] (JSON: jamAreas)
lib/material_flow.py [CSV-Rohmodell -> Graph, @dataclass]
├── Element (1 CSV-Zeile)
├── Node
│ └─ element: Element
├── Edge
├── Graph
│ ├─ nodes: dict[str, Node]
│ ├─ edges: list[Edge]
│ └─ unassigned: list[Element]
├── TrackNode
│ └─ element: Element | None
├── TrackEdge
└── TrackGraph
├─ nodes: dict[str, TrackNode]
└─ edges: list[TrackEdge]
lib/tro_overrides.py [manuelle Korrekturen aus cfg/tro_overrides.ini, @dataclass]
├── TroOverride (Typkorrektur an einem abgeleiteten TRO: tro_id ODER separator)
├── SplitSpec (TRO aus einem bestehenden heraustrennen)
├── MergeSpec (mehrere TROs zu einem zusammenfassen)
└── Overrides (Sammelcontainer für eine CSV-Datei)
├─ tros: dict[str, TroOverride]
├─ splits: list[SplitSpec]
├─ merges: list[MergeSpec]
├─ connections: list[model.Connection]
└─ candidates: list[model.TroCandidate]
lib/dxf_registration.py [CSV<->DXF Koordinatentransform]
├── RegistrationError(RuntimeError)
└── Transform(BaseModel)
lib/scl_context.py [Render-Kontext für die SCL, BaseModel]
├── SclName (Wert + Merker todo: noch aus der E-Planung offen?)
├── SclSeparator (ein stInSeparator<n>-Block)
├── SclSwitch (ein stInSwitch<n>-Block + FC_Direction-Aufruf)
├── SclSwitchExit (Weichenabgang + darüber erreichbare TROs)
├── SclScanner (ein stInBarcodeReader-Block)
├── SclJam (Staubereich an Ein-/Ausgang)
├── SclTro (alles für eine REGION)
│ ├─ separators: list[SclSeparator]
│ ├─ switches: list[SclSwitch]
│ ├─ switch_exits: list[SclSwitchExit]
│ ├─ scanners: list[SclScanner]
│ ├─ jam_entries / jam_exits: list[SclJam]
│ └─ main_tro, safety, ... : SclName
└── SclFile (die ganze Datei)
└─ tros: list[SclTro] (in Fliessrichtung)
lib/scl_skeleton.py [SCL-Ausgabe]
└── SclTemplates (Ordner mit <fbType>.scl.j2, hält ein jinja2.Environment)
lib/e_planning.py [Brücke Layout <-> E-Planung]
├── EDevice(BaseModel) (ein BMK aus *_positionsdraw.json: VERW, Bezeichnung, Position)
├── LayoutPoint (@dataclass: punktartiges Layout-Bauteil in CSV-Koordinaten)
├── Rule (@dataclass: eine Regel aus cfg/e_planning.ini)
├── Assignment(BaseModel) (BMK in einer Rolle an einem Layout-Bauteil, mit Abstand)
├── Drive(BaseModel) (Motor MA ↔ Motorschutz FC)
└── EplanDocument(BaseModel) (= <csv>_eplan.json)
├─ transform: Transform (aus dxf_registration)
├─ assignments: list[Assignment]
└─ drives: list[Drive]
Auffälligkeiten für ein mögliches Refactoring
— erledigt 2026-10-10: zuOpenPointexistiert zweimalmodel.TroCandidatezusammengefasst (expect→type_name,x/y/z→position);ConnectionSpecdurchmodel.Connectionersetzt;tro_overrides.pyimportiert beide ausmodel.py.- Zwei parallele Graph-Hierarchien in
material_flow.py(Node/Edge/Graphvs.TrackNode/TrackEdge/TrackGraph) teilen sich keine Basisklasse, obwohl Struktur und Feldnamen sich stark ähneln (node_id, kind, .../src, dst, ...). Eine gemeinsame leichte Basis (z. B. ein generischesGraphBase[NodeT, EdgeT]) wäre möglich, aber angesichts der wenigen Stellen, die beide Typen anfassen, vermutlich mehr Abstraktion als Nutzen. TroItemundTroSymbolsind reine Konstanten-Namespaces (keine Instanzen, keine Methoden außerTroItem.all()), kein Pydantic-Modell wie der Rest vontro_catalog.py. Das ist bewusst so (siehe Docstring: "damit Tippfehler auffallen") und funktioniert wie einEnum-Ersatz — einStrEnumwäre eine nahe liegende, idiomatischere Alternative, falls ein Refactoring ansteht.- Die einzige echte Vererbung (
DerivedTro(TroBase)) ist sauber:TroBaseist bereits so geschnitten, dass es für Systemgrenzen (boundaries) wiederverwendet wird,DerivedTroergänzt nur das, was die CSV-Ableitung zusätzlich weiß. Kein Handlungsbedarf.
Fazit: Die Code-Basis nutzt Vererbung bewusst kaum — die Architektur trennt
stattdessen über Module (Typ-Katalog vs. Instanz vs. Ableitung vs. Ausgabe,
siehe model.py-Kopfkommentar) und über Komposition. Ein Refactoring in
Richtung "mehr Vererbung" wäre hier eher kontraproduktiv. Die doppelte
OpenPoint-Definition (1) ist behoben; offen bleibt nur optional StrEnum
statt Konstanten-Klassen (3).
Die komplexen Klassen im Einzelnen
Die folgenden Abschnitte beschreiben je Klasse, wozu sie da ist, was
darin passiert und wer sie erzeugt bzw. liest. Einfache Datenhalter
ohne eigene Logik — Connection, TroCandidate, Edge, TrackEdge,
TroItem/TroSymbol und die kleinen Blöcke SclSeparator, SclSwitch,
SclSwitchExit, SclScanner, SclJam — sind im Baum oben ausreichend
beschrieben und bekommen keinen eigenen Abschnitt.
TroDefinition (+ TroStyle) — lib/tro_catalog.py
Wozu: Beschreibt einen TRO-Typ, nicht eine Stelle in der Anlage: Kurzname
(1Sep1Swi), Siemens-FB (FB_ILS_MTRO_1Sep1Swi), Bauteile
({"Separator": 1, "Switch": 1}), Farbgruppe und CAD-Symbol. Der Katalog
aller Definitionen ist die ausführbare Form von doc/TRO_Typen.md.
Was passiert darin: Pydantic mit validate_assignment und extra="forbid" —
eine Definition kann nie ungültig werden, auch nicht über die set_*-Methoden.
_clean_items wirft Bauteile mit Anzahl ≤ 0 heraus. Ein eigener __init__
erlaubt die alte Positionsform TroDefinition("1Sep", "FB_...", {...}). Dazu
kommen Abfragen (get_items, has_item, get_item_fb, get_total_items) und
Darstellungshelfer (get_dot_attrs, mermaid_class/_classdef,
describe_items). TroStyle liefert nur die Farben einer Gruppe für Graphviz,
Mermaid und CAD.
Wer nutzt sie: Über get_tro(name)/catalog() jeder, der vom Typnamen auf
FB oder Bauteile kommen muss — vor allem TroBase.definition(); außerdem
tro_flow (Typprüfung), tro_annotate (Farbe/Symbol, --emit-lisp) und die
Doku-Grafiken.
TroBase / DerivedTro — lib/model.py
Wozu: Ein konkreter TRO in einer Anlage (Instanz). TroBase ist der Kern, den
jeder TRO hat, egal woher er stammt: tro_id, type_name, separators,
predecessors/successors, position. DerivedTro ergänzt, was tro_flow
beim Ableiten aus dem CSV zusätzlich weiß: hosts, scanners, reason,
colocated, position_from/position_points. Systemgrenzen (SYSn) sind
ebenfalls DerivedTro.
Was passiert darin:
fb_blockunditemssind berechnete Felder: bei jedem Zugriff aus dem Katalog gelesen (definition()→get_tro(type_name)), nie gespeichert. In der JSON stehen sie trotzdem (fbType,items), damit sie lesbar ist._check_catalog_fields(Validator vor dem Einlesen): steht in einer JSON einitems/fbType, das nicht zum Typ passt, ist das ein Fehler — "den Typ ändern, nicht die Bauteile". Danach werden die Felder verworfen.- Aliase: in der JSON
id/type, im Codetro_id/type_name(populate_by_name). _Positioned(Mixin) wandeltpositionzwischen Tupel und{"x","y","z"}und liefertx/y/zunddescribe_position().DerivedTro.connected: hat der TRO überhaupt Nachbarn?
Wer nutzt sie: tro_flow.derive_tros/derive_boundaries erzeugen sie,
scl_context liest sie (als TroBase), tro_annotate zeichnet sie.
Analysis — lib/model.py
Wozu: Das Arbeitsergebnis eines Ableitungslaufs, bevor daraus eine Datei wird. Enthält mehr als die JSON: Kanten als Tupel, Kantenarten, isolierte TROs, unbekannte Typen, Befunde, die verwendete Methode.
Was passiert darin: Fast nur Daten; by_id() sucht über TROs und
Systemgrenzen. Befüllt wird sie in tro_flow.analyse_tros in fester
Reihenfolge: derive_tros → derive_boundaries → locate_tros (Position,
nötig für die Reihenfolge auf einer Kreiselbahn) → link_tros (Kanten und
Kantenarten) → Prüfung gegen den Katalog.
Wer nutzt sie: tro_flow (Bericht, Diagramm, --json) und tro_annotate
(zeichnet direkt aus der Analysis, ohne Umweg über die JSON).
TroDocument — lib/model.py
Wozu: Die TRO-JSON <csv>_tro.json (Schema sps_skel-tro-v4) — die
Schnittstelle zwischen Ableitung (tro_flow --json) und SCL-Ausgabe
(scl_skeleton). Weil beide Seiten dieselbe Klasse benutzen, kann das Format
nicht unbemerkt auseinanderlaufen.
Was passiert darin: from_analysis() macht aus einer Analysis ein Dokument
(Kanten + Kantenarten → Connection-Liste, je TRO die slots aus
derive_slots(), die Staubereiche aus derive_jam_areas()). to_json() schreibt mit den
JSON-Aliasen, from_json() liest und prüft. extra="forbid" sorgt dafür, dass ein
umbenannter oder falscher Schlüssel als Fehler auffällt statt still einen
Standardwert zu bekommen; scl_skeleton.main meldet bei falschem schema
gezielt "mit tro_flow neu erzeugen".
Wer nutzt sie: geschrieben von tro_flow --json, gelesen von
scl_skeleton.load_document → scl_context.build_context.
Element, Graph, TrackGraph — lib/material_flow.py
Wozu: Das Rohmodell aus dem CSV-Export (ILS 2.0), noch ohne TRO-Begriff.
Element= eine CSV-Zeile: Art, ID, Name, Nachbarn,track_ids, Merkmale, Position, Bounding-Box, Anschlusspunkte K1..K4.Graph(Node/Edge) = grober Materialfluss-Graph: Transportobjekte (Strecke, Gefällestrecke, Kreisel-Bahn) als Knoten, Geräte (Separatoren, Weichen, Scanner …) an die Knoten gehängt (Node.devices), Stationen und Übergaben als Kanten.TrackGraph(TrackNode/TrackEdge) = feiner Bahnzusammenhang: jedes Bahnelement (AS, SEP, ES, Weiche, BTMT …) ist ein Knoten, verkettet in Bau- bzw. Drehrichtung (siehedoc/track.md).
Was passiert darin: Element hat viele abgeleitete Properties: Klassifizierung
(is_transport, is_circle, is_device, is_station, is_transfer,
is_entry/is_exit), Geometrie (x/y/z, bbox_x/y, height,
height_from/to, rise), Antrieb (drive_dir, rotation). Die Graphklassen
selbst sind reine Container; die Logik steckt in den Funktionen
build_graph() (Knoten bilden, Geräte zuordnen, Kanten sammeln, Fliessrichtung
aus Gefälle/Antrieb, Stationen und Übergaben einhängen) und
build_track_graph() (Ketten aus der Spalte TrackIds; ein Element in zwei
Containern verbindet diese automatisch). TrackNode kann ohne element
existieren (Platzhalter für eine nicht auflösbare Bahn, generisches
Ein-/Ausgang-Symbol).
Wer nutzt sie: material_flow selbst (DOT/SVG/connect.ini/Bericht) und
tro_flow.analyse_tros(graph, elements) als Eingang der TRO-Ableitung;
tro_annotate für Ankerpunkte des Lagebezugs.
Overrides (+ TroOverride, SplitSpec, MergeSpec) — lib/tro_overrides.py
Wozu: Von Hand gepflegte, vor Ort bestätigte Korrekturen aus
cfg/tro_overrides.ini für das, was die Ableitung nicht erkennen kann.
TroOverride: Typ eines TRO korrigieren. Adressiert übertro_idoder — stabiler — über einenseparator, weil TRO-Nummern sich zwischen Läufen verschieben, Separatornummern aus dem Export nicht (matches()).SplitSpec: Separatoren/Scanner aus einem TRO herauslösen und einen neuen TRO bilden (Übergabestelle, deren Zuordnung auf die Strecke statt auf die Kreiselbahn zeigt).MergeSpec: mehrere TROs zu einem Steuerobjekt zusammenfassen (z. B. zwei Sperren beiderseits eines Kreisel-Berührpunkts).Overrides: Sammelcontainer je CSV-Datei, dazu gesetzte Topologie (connections, ersetzt die abgeleiteten Kanten vollständig), erwartete TROs (candidates), Protokoll (applied) undwarnings.bool(overrides)ist True, sobald irgendeine Korrektur vorhanden ist.
Was passiert darin: load_overrides(csv_name) liest den INI-Abschnitt der
CSV-Datei und baut daraus die Objekte; Lesefehler landen in warnings statt
den Lauf abzubrechen.
Wer nutzt sie: Stand heute nur material_flow --connect
(render_connect_ini schreibt sie als [<Anlage>.manual]-Abschnitt). tro_flow
wendet sie (noch) nicht an — sie fliessen also nicht in die TRO-JSON und nicht
in die SCL.
Transform (+ RegistrationError) — lib/dxf_registration.py
Wozu: Der Lagebezug zwischen CSV-Export und BricsCAD-Zeichnung: eine starre
Transformation csv = R(rotation) · dxf + (dx, dy). Ohne sie landen die
TRO-Marker in tro_annotate an der falschen Stelle.
Was passiert darin: to_csv()/to_dxf() rechnen Punkte hin und zurück,
describe() fasst Verschiebung, Drehung, Punktzahl und Restfehler zusammen.
Die Ermittlung steckt in Funktionen: derive_transform() ordnet punktartige
Objekte gleicher Rolle (Separator, Scanner) aus CSV und DXF zu, stimmt über
Verschiebungen ab, gleicht aus und wählt den besten Kandidaten;
verify_transform() rechnet die Restfehler nach und schreibt sie ins Objekt;
load_transform()/save_transform() lesen/schreiben
cfg/dxf_registration.json. RegistrationError heisst: der Bezug liess sich
nicht nachweisbar bestimmen — dann lieber abbrechen als falsch zeichnen.
Wer nutzt sie: tro_annotate.resolve_transform (Reihenfolge: --offset →
abgelegter Bezug → neu ermitteln, jeweils mit Prüfung), dazu das geparkte
tro_extract.
SclFile, SclTro, SclName — lib/scl_context.py
Wozu: Der Render-Kontext für das FB_Main-Gerüst. Alles, was aus der
TRO-JSON abgeleitet wird, steht hier fertig drin; die Ausgabe
(emit_*-Funktionen oder Jinja-Templates) rechnet nichts mehr selbst, sie
liest nur noch. So können generischer Aufbau und Templates nicht
unterschiedlich ableiten.
Was passiert darin:
build_context(document, source, start_id)baut aus einemTroDocumenteinSclFile: Kopfdaten plus die TROs in Fliessrichtung.flow_order()bestimmt die Reihenfolge der REGIONs: Start bei--start, sonst beim TRO ohne Vorgänger, sonst beim TRO, den eine Station (SYSn) speist, sonst wird der Kreislauf willkürlich aufgetrennt — der Grund steht im SCL-Kopf (start_reason). Danach Breitensuche; nicht erreichte TROs werden hinten angehängt, damit keiner verloren geht._tro_context()baut je TRO einSclTro: so viele Separator-, Weichen- und Scannerblöcke, wie der Katalogtyp Bauteile hat (items); je Vorgänger ein Staubereich am Eingang, je Nachfolger einer am Ausgang;to1_destinationsnur bei genau einer Weiche (bei mehreren ist die Aufteilung eine Planungsentscheidung); die Zielliste je Weichenabgang überreachable_via()(Erreichbarkeit im TRO-Graphen, ohne über die Weiche zurückzulaufen).SclName= Wert + Merkertodo. Alles, was aus der E-Planung kommen muss (Separator-/Weichennummern, Sensor-/Aktoradressen, MainTro, Staubereichs-DB …), ist heute ein Platzhalter mittodo=True; die Ausgabe hängt daran den KommentarTODO(E-Planung). Spätere Namensregeln ersetzen nur den Wert und löschen den Merker — die Ausgabe ändert sich dafür nicht.
Wer nutzt sie: erzeugt in scl_skeleton.render()/main(), gelesen von
render_context(), den emit_*-Funktionen und den Templates (als t).
SclTemplates — lib/scl_skeleton.py
Wozu: Die Anbindung der parametrisierten SCL-Aufrufstellen
(lib/scl_templates/*.scl.j2) an die Ausgabe. Ein Objekt steht für einen
Template-Ordner.
Was passiert darin: Der Konstruktor baut ein jinja2.Environment mit
StrictUndefined (ein Tippfehler im Template wird zum Fehler statt zu einer
leeren SCL-Stelle), trim_blocks/lstrip_blocks und der globalen Variable
TODO. has(fb) prüft, ob <fb>.scl.j2 existiert; render(tro) rendert das
Template mit t = SclTro und fasst danach mehrfache Leerzeilen zusammen (statt
das mit {%- -%} im Template zu tun, was die Einrückung bricht).
Template ↔ TRO: Zuordnung und Einstieg in die Produktion
Zuordnung — es gibt keine Tabelle, nur eine Namenskonvention: Dateiname = FB-Typ. Die Kette:
DerivedTro.type_name "1Sep1Swi" (TRO-JSON, Feld "type")
-> tro_catalog.get_tro() TroDefinition
-> TroDefinition.fb_block "FB_ILS_MTRO_1Sep1Swi"
-> TroBase.fb_block (berechnet, nicht gespeichert)
-> SclTro.fb (scl_context._tro_context)
-> SclTemplates.has/render lib/scl_templates/FB_ILS_MTRO_1Sep1Swi.scl.j2
Ein neues Template für einen weiteren Typ heisst also einfach
<fbType>.scl.j2 und wird automatisch für alle TROs dieses Typs verwendet.
Heute gibt es nur den Piloten FB_ILS_MTRO_1Sep1Swi.scl.j2 (plus
_macros.scl.j2 mit gemeinsamen Makros). Alle anderen Typen laufen über den
generischen Aufbau (emit_region()).
Einstieg — nur per Schalter (opt-in):
scl_skeleton --templates [DIR](ohne DIR:lib/scl_templates).main()legt dann einSclTemplatesan;render_context()nimmt pro TROtemplates.render(tro), wenntemplates.has(tro.fb), sonstemit_region(). Der SCL-Kopf listet, welche FB-Typen aus Template bzw. generisch kamen.--strictbricht ab (Exit 1, keine SCL), wenn ein FB-Typ der Anlage kein Template hat. EinTemplateError(fehlende Variable, Syntaxfehler) bricht ebenfalls ab — lieber keine SCL als eine mit stillen Lücken.- Ohne
--templateswerden Templates gar nicht geladen; die Ausgabe ist die bisherige (Golden-Filestests/fixtures/scl/*_FB_Main.scl). Mit Templates pinnen*_FB_Main_templates.scldas Ergebnis. bin/scl_skeleton.bat/.shreichen die Schalter nur durch; der Standardaufruf ohne--templatesnutzt also keine Templates.
Nicht Produktion: doc/TRO_Katalog/scl_templates/*.scl sind die realen
Referenz-Aufrufstellen. Gegen sie prüft tests/test_scl_templates.py jedes
Template im Round-Trip; in die erzeugte SCL fliessen sie nicht ein.
Daten
Bestandsaufnahme aller Daten, die in den Referenz-Aufrufstellen und FB-Schnittstellen
unter doc/TRO_Katalog/scl_templates/*.scl vorkommen (Stand 2026-10-10), und woher
der Generator sie bekommen muss. Grundlage: die sieben Aufrufstellen
(FB_ILS_MTRO_1Sep, _1Sep1Swi, _1Sep2Swi, _1Sep_SSCC, _PinStore_Auto,
_Vario, _Vario_workStation_CallSite) und die VAR_INPUT/OUTPUT/IN_OUT-Abschnitte der
vier vollständig vorliegenden FBs (FB_ILS_MTRO_2Sep1Swi, FB_ILS_MTRO_Vario_workStation,
FB_EmptyCarrBuffer, FB_LoadingBoom_INBOUND). Die Beispielwerte stammen aus diesen
Dateien.
Quellen (Spalte "Quelle"):
| Kürzel | Quelle | Was sie liefert |
|---|---|---|
| L | Anlagen-Hardware = mechanisches Layout (CSV-Export ILS 2.0, data/*.csv) |
Bauteile (TeileArt: Separator, Scanner, Weiche, Kreisel, Strecke, Gefällestrecke, BTMT Be-/Entladung, Ein-/Ausschleuselement), Nachbarn/TrackIds, Merkmale (Drehrichtung, Antriebfahrtrichtung, Höhen, Längen, Anzahl Separatoren/Scanner, Zuordnung). Daraus abgeleitet: TRO-Typ, Topologie, Reihenfolge, Ziele. |
| E | Hardwareplanung = Elektroplanung (EA-Liste, TIA-Import, WSCAD-Import, *_positionsdraw.json; siehe doc/HundM/EA-Listen-Analyse.md) |
Betriebsmittelkennzeichen und Variablennamen (BG… Sensoren, MB… Ventile, MA… Motoren, FC… Motorschutz, SF… Taster, BX… Scanner), Hardware-Kennungen, welche optionalen Sensoren verbaut sind, Zuordnung zu Schaltschrank und Not-Halt-Kreis. |
| K | Namenskonvention | Name folgt aus TRO-Nummer bzw. Staubereichs-/Weichennummer (cMainTro<n>, cSep<n>.<i>, "DB_Interface_HMI".stTRO.TRO<n> …). Keine externe Quelle nötig, sobald Nummernkreis und Regel feststehen. |
| P | Parameter / Projektstandard | Weder Layout noch E-Planung: Zeiten, Schwellwerte, Projektkonstanten, WCS-/Inbetriebnahme-Logik. Kandidaten für Typ-Defaults (doc/TRO_Typen.md). |
L + E heisst: das Layout sagt, dass/wie viele es gibt und wo, die
E-Planung liefert den Namen/die Adresse. Das ist der häufigste Fall.
Die zwei folgenden Abschnitte listen alle Angaben, die die beiden externen
Quellen heute enthalten (Stand 2026-10-11, geprüft an data/*.csv und an den
Exporten unter kabellaengen/work/: easy_sps-1_EA/_TIA/_WSCAD.xlsx,
Mubea_positionsdraw.json). Was sich daraus für TROs und SCL gewinnen lässt und
zwei kommentierte SCL-Beispiele: doc/Datenquellen_Layout_Hardwareplanung.md.
Angaben 1: Anlagen-Hardware (mechanisches Layout, CSV)
Eine Zeile je Bauteil, Trennzeichen ;, utf-8-sig. Gelesen von
material_flow.load_elements().
Spalten (alle Bauteilarten)
| Spalte | Beispiel | Bedeutung | Nutzen für TRO/SCL |
|---|---|---|---|
Elementnummer |
1 |
laufende Zeilennummer des Exports | keiner (nicht stabil) |
TeileArt |
ILS 2.0 Separator |
Bauteilart (Liste unten) | Knotenart, TRO-Typ |
TeileId |
0008 |
stabile ID im Layout | Schlüssel für Topologie, Overrides, E-Brücke |
Bezeichnung |
VF_1, Kreisel :3 |
Klartext aus der Zeichnung | Anzeige, REGION-Kommentar |
Planquadrat |
B/1-C/4 |
Raster der Zeichnung | Bericht/Suche |
Anzahl |
1 |
Stückzahl | keiner |
Position |
5878.63, 4330.96, 2128.70 |
Einfügepunkt x, y, z in mm | Lagebezug zur E-Planung (dxf_registration), Abstände |
Boundingbox |
2837.82, 6404.92, 731.58 |
Ausdehnung x, y, z in mm | Lage von Weichen/Bahnen |
Insertpoint |
TV0UEkxg… |
kodierter Einfügepunkt (Base64) | intern |
K1–K4 |
AK41AC7XAFQk |
Anschluss-Koordinatensysteme (Base64, je x/y/z) | Anschlussseite, Lage der AS/ES (decode_kpoint) |
Nachbarn |
0006-L, 0014 |
berührende Bauteile, bei Kreiseln mit Bahn -L/-R |
Topologie (Kanten) |
TrackIds |
0044, 0027, 0026 |
Anbauteile eines Containers in Baureihenfolge bzw. Umlaufrichtung | Reihenfolge Separator/AS/ES auf Strecke und Kreisel |
Fehler, Warnungen |
nur ein Partner, unverbunden |
Prüfmeldungen des Exports | Qualitätsprüfung |
Merkmale |
JSON | artspezifische Eigenschaften (unten) | siehe unten |
Merkmale je TeileArt
| TeileArt | Merkmale | Nutzen für TRO/SCL |
|---|---|---|
ILS 2.0 Kreisel |
Name, Kreiselart (STANDARD), Drehrichtung (UZS/GUZ), Drehung, Höhe in m, Abstand (Kreiselachse A - Kreiselachse) in Meter, Anzahl der Separatoren, Anzahl der Scanner, Anzahl der Rampen, Geruest fuer Einzelmodul |
Host eines TRO (xInCarouselRun1/2), Umlaufrichtung → Reihenfolge, Länge → Staulänge; Anzahlen zur Plausibilisierung |
ILS 2.0 Strecke |
Typ (Streckengruppe), Seite_AS, Seite_ES, Winkel, VF_Winkel, DeltaH_mm, DeltaL_mm, L_VF_m (angetriebene Teilstücke), L_GF_m (Gefälleteilstücke), Montagehoehe_m, Hoehe_Von_mm, Hoehe_Bis_mm, Antriebfahrtrichtung (horizontal/Auf), Anzahl_Separator, Anzahl_Scanner, Separatorlist |
angetrieben (L_VF_m, Auf) → Vario/Antrieb; Längen → tConvEmpty, Staulänge; Anzahlen zur Plausibilisierung |
ILS 2.0 Gefaellestrecke |
wie Strecke, L_VF_m und Antriebfahrtrichtung leer |
Host "Gefälle" → 1Sep, xInCarouselRun1 := TRUE |
ILS 2.0 Separator |
Zuordnung (Host, ggf. mit Bahn -L/-R), ARTINR, Höhe, Drehung, Typ |
TRO-Anker: jeder Separator ist ein TRO oder Teil davon; Host → TRO-Typ |
ILS 2.0 Scanner |
Zuordnung, Naechster Separator, ARTINR, Höhe, Drehung, Typ |
Scanner am TRO (xPluggedScanner, stInBarcodeReader, REGION-Titel) |
ILS Weiche |
Kreisel A, Kreisel B, Achse von Kreisel, Beruehrung (Kreis/Kreis), Erzeugt aus |
Kreisel-Kreisel-Weiche → 1SepNSwi, xCar2NecRight/Left, zweiter Kreisel xInCarouselRun2 |
ILS Ausschleuselement |
Kreisel, Strecke/Förderer, Streckenende (Anfang), Element (AS_Element_90_links_3D), ARTINR, Erzeugt aus |
Abgang Kreisel → Strecke: Weichenausgang Exit3/4, Ziel je Abgang |
ILS Einschleuselement |
wie Ausschleuselement, Streckenende Ende |
Zusammenführung Strecke → Kreisel: Vorfahrt (xPrioDir, PriorityManager) |
ILS 2.0 BTMT Beladung / Entladung |
ARTINR, Höhe, Drehung |
Systemgrenze SYSn, xIsBorner, Ziele; Ladeschleife |
Eingang / Ausgang |
ARTINR, Höhe, Drehung |
Systemgrenze zu Nachbaranlage, Übergabe-Staubereich |
ARTINR (Artikelnummer) unterscheidet Bauarten, z. B. Separator 200000077,
Scanner 829534306; daran ließe sich die Weichenbauart (xNewSwitch) prüfen.
Zusätzlich gibt es den Sivas-Stücklisten-Export (data/*_sivas.csv:
SivasNummer, Dispogruppe, Laenge[mm], IDs, details mit
Förder-/Gefällegruppen, Kurven, MotorSeite). Er ist eine Stückliste, keine
Topologie, und wird nicht gelesen; brauchbar wäre MotorSeite und die
Gruppenlängen.
Nicht im Layout: Betriebsmittelkennzeichen, E/A-Adressen, welche optionalen Sensoren verbaut sind, Schaltschrank/Steuerung, Zeiten, Ziel-Nummern des WCS.
Angaben 2: Hardwareplanung (EA-Liste, TIA-Import, WSCAD-Import, positionsdraw)
Vier Exporte derselben E-Planung. Gemeinsamer Schlüssel ist das
Betriebsmittelkennzeichen (BMK) BG3306, MB3306 …; nur positionsdraw
kennt eine Lage, nur EA/TIA/WSCAD kennen die E/A-Adresse.
<projekt>-<n>_EA.xlsx — Blatt "Ein-, Ausgaenge", je SPS n eine Datei
| Spalte | Beispiel | Bedeutung |
|---|---|---|
Name |
E324.0 |
E/A-Adresse |
Kommentar |
Stausensor 1 (ILS-CV M0108) |
Funktionsrolle, lfd. Nr., Fördereinheit (M-Nummer), Bereich |
Zeile |
2 |
Verweis Schaltplan |
<projekt>-<n>_TIA.xlsx — Importdatei für das TIA Portal
| Blatt / Spalte | Beispiel | Bedeutung | Nutzen für SCL |
|---|---|---|---|
PLC Tags Name |
BG3240, MB3306, MA0062, FC0062 |
BMK = Variablenname | direkt die Namen in FB_Main (=> "MB3306", := "FC0145") |
PLC Tags Path |
Import |
Variablentabelle | Ordner der Variablentabelle |
PLC Tags Data Type |
Bool |
Datentyp (nur Bool) | – |
PLC Tags Logical Address |
%E324.0, %A006.2 |
Absolutadresse | Prüfung, FB_CallSensors |
PLC Tags Comment |
Stausensor 1 (ILS-CV M0108) |
wie EA-Kommentar | Rolle, M-Nummer |
PLC Tags Hmi Visible/Accessible/Writeable |
True |
HMI-Flags | – |
PLC Tags Typeobject ID, Version ID |
leer | – | – |
Constants Name |
cInBG3240, cInFC0062, cOutMA0062 |
Index-Konstante je Signal | genau die Indizes in "DB_Inputs".Sensors["cInBG3306"] |
Constants Data Type, Value |
Int, 1 |
Array-Index | Dimensionierung DB_Inputs |
<projekt>-<n>_WSCAD.xlsx — Importdatei für das E-CAD
| Spalte | Beispiel | Bedeutung | Nutzen für SCL |
|---|---|---|---|
Anschluss |
E324.0 |
E/A-Adresse | Schlüssel zu EA/TIA |
Kommentar |
wie EA | ||
Bezug |
=A01+UC0101-KF1DI1 |
Anlage, Feldstation (UC…), Baugruppe (KF1DI1, KF1FDQ2 = F-Karte) |
Steuerungs-/Schaltschrankzuordnung, Safety-Signale |
Symboltext, Sondertext 1..8 |
meist leer |
<zeichnung>_positionsdraw.json — Kabellängen-Tool, E-Symbole aus der Zeichnung
| Schlüssel / Attribut | Beispiel | Bedeutung | Nutzen für TRO/SCL |
|---|---|---|---|
sensors{BMK@SPS} |
BG0542@UNKNOWN |
Feldgeräte (BG, MB, MA …) | Hauptquelle der Brücke |
.IO / .B |
BG0542 |
BMK | Schlüssel zu TIA |
.pos |
[-42369.8, -11437.2] |
Lage in mm | Zuordnung zum Layout-Bauteil (e_planning.py) |
.VERW |
IN SEP, SEP, STAU_REF-LT, AE ABZWEIG, ABZWEIG-K104, BT BELADEN, SYNC P1..4, ABFR.FINGER, ÜBERGABE, ÜBERNAHME, BANDBRUCH, KETTENBRUCH, ZAPPLER P1, MOT_0,37kW |
Verwendung (kontrolliertes Vokabular) | Rolle des Signals im TRO |
.BEZEICHNUNG |
STAUSENSOR STR. 01, PRÜFUNG BT. POS.1 (KR-K0102 EINFAHRT PUFFER) |
Klartext | Strecken-/Kreiselnummer, Plausibilisierung |
.BESCHR |
STAUSENSOR |
Gerätebeschreibung | – |
.KENNZEICHNUNG |
=A1+UH01-KF102 |
Steuerung UH01, E/A-Station KF102 |
Steuerung, TRO-Nummernkreis, Schaltschrank |
.ARTINR |
829434300 |
Artikelnummer Gerät | Gerätetyp |
.SPS |
'', A/B |
SPS-Nummer (oft leer) | Steuerung |
.A, .C, .ID, .MENGE, .POSITION, .GRUPPE, .ETIKETTE, .AUFLOESE, .TEXT-D/E/ES/F |
Blockattribute des Symbols | – | |
schaltschrank_elemente{…} |
FC0200 MOTORSCHUTZ CONVEYER #100, SF… Taster, PF… Leuchten, QA7000 Hauptschütze, GF Encoder, BP Druckschalter |
Elemente im Schrank, ohne Feldlage | Motorschutz ↔ Motor, Bedienelemente, Encoder |
mappings |
UH01: [BMK …] bzw. Verteiler → BMK |
Zuordnung zur Steuerung/Verteiler aus der Verkabelung | Steuerungsaufteilung |
distributors, racks, tunnels |
Verteiler, Trassen | – | |
warnings, not_found, double_ids |
Prüfprotokoll | Qualitätsprüfung |
BMK-Präfixe: BG Sensor, SF Taster/Schalter, DI Diagnose, BP
Druckschalter, GF Encoder, BX Scanner (nur PROFINET, nicht in den Digitallisten),
MB Ventil (Stopper, Weiche, Ausschleuser), MA/QA Motor/Schütz, DQ
Sonderausgang, FC Motorschutz, PF Leuchtmelder.
Nicht in der Hardwareplanung: Topologie (wer auf wen folgt), TRO-Grenzen, Ziele/Weichenrichtungen, Zeiten, Analogwerte und PROFINET-Geräte (Cognex-Variablen stehen in der TIA-Gerätekonfiguration, nicht im Tag-Import).
TRO-Kopf und Instanzaufruf
| Daten | SCL-Stelle (Beispiel) | Quelle | Bemerkung |
|---|---|---|---|
| Existenz, Anzahl, Reihenfolge der TROs | REGION TRO 100 … |
L | tro_flow → DerivedTro; REGION-Reihenfolge scl_context.flow_order() |
| TRO-Typ / FB-Typ | FB_ILS_MTRO_1Sep1Swi |
L (→ Katalog) | Typ aus Separator-Host (doc/500573_Mubea/TRO_Identifikation_500573.md), FB aus tro_catalog |
| TRO-Nummer, Instanzname | #TRO107 |
L + E | Anzahl aus L; Nummernkreis je Steuerung (100er = UH01, 200er = UH02 …) ist Projektvorgabe |
| REGION-Titel | TRO 267 (1Sep2Switch)+Scanner(BX2100) |
L + E | Typ aus L, Scanner-BMK aus E |
nInMainTroNo |
"cMainTro100" |
K | Wert der Konstante in der PLC-Konstantentabelle |
nOutStateLast |
"DB_GLOB_TroState".arTroState["cMainTro100"] |
K | |
stInOutHMI |
"DB_Interface_HMI".stTRO.TRO100 |
K | PinStore/Puffer: eigener UDT UDT_HMI_TRO_PinStore |
xInRelease |
"DB_TRO_TEST".TRO100, TRUE, WCS-Verbindung aktiv |
P | Freigabe-/Testlogik, Inbetriebnahme |
xInAllRdyToStart, xInCancel, xInReset |
TRUE, "cTodoFalse" |
P | meist Konstante |
stInSettings.xIsBorner (xIsBorner1/2) |
TRUE |
L | erster TRO nach Einfahrt in die Anlage (Beladestation / Systemgrenze SYSn) |
stInSettings.nBornerDest(1/2) |
– | P | Standardziel für neu angelegte Carrier (WCS) |
stInSettings.bSepType (bSep1Type/2Type) |
.%X2 := TRUE |
E + P | X0 erstes Bein halten, X1 Beladekontrolle, X2 Beladeerfassung — hängt an verbauter Sensorik und Prozess |
stInSettings.nTroStopper1/2, nTroSwitchExit2/3 |
– | L + K | Nummern der Nachbar-TROs |
stInSettings.sJamSrc / sJamDest |
– | L + K | Namen der benachbarten Staubereiche |
stInSettings.xCar2NecRight/Left |
– | L | zweiter Kreisel nötig für Richtung rechts/links (Topologie an einer Kreisel-Weiche) |
tPartSenHigh, tInSenHigh, tDummyTimeNormal, tDummyTimeBorner |
FB-Defaults 500 ms / 3 s / 0 ms | P | Typ-Defaults |
Separator (stInSeparator<n>, xOutStopper<n>)
| Daten | SCL-Stelle (Beispiel) | Quelle | Bemerkung |
|---|---|---|---|
| Anzahl Separatoren je TRO | stInSeparator1, stInSeparator2 |
L | ILS 2.0 Separator + Zuordnung, Typ-Katalog items |
Settings.nSeparatorNo |
"cSep107.1" |
K | Layout-Separator-ID (TeileId) ist nicht diese Nummer |
Sensor im Stopper stSenInSep |
"DB_Inputs".Sensors["cInBG3242"] |
E | |
Sensor nach Stopper stSenSepLeft, Beladesensor stSenPart, Scan-Start stSenStartScan |
["cInBG4465"] |
E | nur wenn verbaut |
Stopperventil xOutStopper<n> / xOutStopper |
=> "MB3242" |
E | BG- und MB-Nummer sind in der E-Planung meist gleich (BG3242/MB3242) |
Settings.xPluggedJam |
TRUE |
E | Stausensor verbaut? |
Settings.xPluggedPart |
FALSE |
E | Beladesensor verbaut? |
Settings.xPluggedConfirm, xPluggedNullBT |
FALSE |
E | |
Settings.xPluggedScanner |
TRUE |
L | Scanner am Separator (DerivedTro.scanners) |
Settings.tDelayToNextItem |
"TimeForSepWaiting_Short" / _Medium |
P (+ L) | Wahl Short/Medium hängt am Host (Kreisel/Strecke/Gefälle) |
Settings.tTrailingTime, tHandlingTime |
t#600ms, t#200ms, "cTimeSepTrailing" |
P | Typ-Default, IBN |
Settings.tJam |
"TimeForSepJam" |
P | Projektkonstante |
Settings.tSenFree, tSenWait |
T#1500ms, T#4000ms |
P |
Staubereiche (Jam)
| Daten | SCL-Stelle (Beispiel) | Quelle | Bemerkung |
|---|---|---|---|
| Anzahl Ein-/Ausgänge und Zuordnung Exit-Nr ↔ Nachbar | arInOutJamEntr1, arInOutJamExit2..4 |
L | ein Eingang je eigenem Staubereich (TroDocument.jamAreas, Kennung J<Separator>; mehrere Vorgänger fahren in denselben ein), je Nachfolger/Weichenabgang ein Ausgang (SclJam) |
| Gleicher Staubereich auf beiden Seiten einer Kante | Exit von A = Entr von B | L | Identität aus der Topologie |
| Staubereichs-DB und -Index | "DB_JamArea0102".stJam0102_1.arCarrier / .stData |
K (+ E) | Nummerierung der Staubereiche ist Projektvorgabe |
| Stausensor je Ausgang | stInSenJam2 := "DB_Inputs".Sensors["cInBG3243"] |
E | |
| Übergabe-Staubereich an Steuerungsgrenze | #arCarrierHandoverJam5001, #stJamDataHandoverJam5001 |
L + E | Steuerungsaufteilung aus der E-Planung |
xInJamAtExit2/3 |
– | P | NIU |
Weiche (stInSwitch<n>, FC_Direction)
| Daten | SCL-Stelle (Beispiel) | Quelle | Bemerkung |
|---|---|---|---|
| Anzahl Weichen je TRO | stInSwitch1, stInSwitch2 |
L | ILS Weiche, Ausschleuselement, Typ-Katalog |
Settings.nSwitchNo |
"cSwi107.1" |
K | |
Settings.nTo1Destinations |
3 |
L | Erreichbarkeit im TRO-Graphen (reachable_via()); bei mehreren Weichen Planungsentscheidung |
| Zielliste je Abgang | cDest… |
L + P | welche Ziele: L; Zielnummern: Projekt/WCS |
Settings.xPluggedExSen3/4, stSenExit3/4 |
FALSE |
E | Abgangssensoren verbaut? |
Settings.xNewSwitch |
TRUE |
E | Weichenbauart (ggf. über ARTINR im CSV prüfbar) |
Weichenventile xOutSw<n>ExTo3/4, xOutSw1EntrTo1/2 |
=> "MB3304" |
E | |
FC_Direction-Aufruf |
nInSwitchNo := "cSwi107.1", InOutCarrier := …stJam0102_1.arCarrier[1] |
K + L | Carrier aus dem Eingangs-Staubereich |
Vorfahrt stInSettings.xPrioDir<n>, stInPriorityManagerDir<n> |
"DB_Prozessdaten".stPriorityManager.udt_TRO107.TroIn |
L + K | Vorfahrt nötig, wo zwei Ströme zusammenlaufen (Kreuzung/Zusammenführung) |
stInPriorityManager.xReleaseOk |
TRUE ("braucht keine Vorfahrtsregelung") |
L | TRUE, wenn keine Zusammenführung |
Scanner / Barcode / SSCC
| Daten | SCL-Stelle (Beispiel) | Quelle | Bemerkung |
|---|---|---|---|
| Scanner vorhanden, Anzahl | stInBarcodeReader, stInBarcodeReader1/2 |
L | ILS 2.0 Scanner, Anzahl_Scanner |
| Scanner-BMK und Index | #arCognexInterface["cScannerBX2100"] |
E | |
| Cognex-Variablen | "bx2100-TriggerReady", -TriggerAck, -Results Available, -General Fault, -TriggerEnable, -Trigger, -ResultsAck |
E | aus dem BMK nach Regel bildbar, wenn die TIA-Variablentabelle dem Muster folgt |
| Hardware-Kennung Ergebnisse | "=A01+UC021-BX2100~Ergebnisse_–_64_Bytes_1" |
E | |
| Kein Scanner | #stCognexInterfaceDummy |
L | |
Settings.xActivateCheckASCI, tTimeout |
TRUE, T#5s |
P | |
Settings.nStation, nScannerPurpose |
111, 0 |
P | WCS |
Zweck SSCC-Scanner, xInPluggedSSCC |
#stCognexIntfTro105 |
E + P | Layout kennt den zweiten Scanner, nicht seinen Zweck |
stSenEndMeasurement |
["cInBG3281"] |
E | |
FC_CARR_GLOB_CORRECTION |
nInStation := 0, Carrier aus Eingangs-Staubereich |
P + L | |
| WCS-Telegramm, HMI-SSCC-Ausgabe | FC_Send_GOHDReqM, "DB_Interface_HMI".stSSCC.SSCC1107 |
P | WCS-Schnittstelle |
Vario (stInVario) und Arbeitsplatz
| Daten | SCL-Stelle (Beispiel) | Quelle | Bemerkung |
|---|---|---|---|
| Vario vorhanden | FB_ILS_MTRO_Vario |
L | angetriebene Strecke / Variofoerderer |
Sensoren stSenCarrInPos, stSenFinger, stSenLastPos, stSenJam, stSenNextSep, stSenSepVario |
["cInBG3026"] … |
E | |
Motor xOutVarioMotor, Motorschutz xInMotorProtection |
"MA0145", "FC0145" |
E | |
Finger-Staubereich arInOutJamFinger |
"DB_JamArea4103".stJam4103_1 |
L + K | |
Settings.tConvEmpty |
T#45000ms |
L + P | aus Förderlänge (L_VF_m) und Geschwindigkeit ableitbar |
Settings.nCountCarrier, tWaitForJog, tWaitForStop, tCarrierInPosDelay, tCarrierInPosEdgeDelay, tRasterHigh/Low, xJamSenDelayActive, tJamSenDelay, xContinousEmptying, SettingsVarioFingerMonitoring |
1, T#300ms … |
P | |
Arbeitsplatz stInStationSensor, xInReleaseStation, fbConvVario.xBeladenError |
["cInBG3314"], #"rTrig_Workstation 1".CLK |
E | Taster/Sensor am Arbeitsplatz |
Antrieb, Sicherheit, Betriebsart
| Daten | SCL-Stelle (Beispiel) | Quelle | Bemerkung |
|---|---|---|---|
| Fördertechnik, die den TRO trägt | xInCarouselRun1 := #fbCarousel0102.xOutConveyorFullSpeed; Gefälle: TRUE |
L | Host-Kreisel aus DerivedTro.hosts; Instanzname nach K |
xInCarouselRun2 |
zweiter Kreisel | L | TRO an der Berührung zweier Kreisel |
xInConveyorRunIn/Out (PinStore) |
#fbSortConv1101, #fbExitConv1103 |
L + K | |
xInSftyOk |
"DB_InterfaceSafety".stFromSafety.EStopMainOF1.Q |
E | Not-Halt-Kreis |
stInOutMachineState |
#stInOutControlUnitCabinetOF1 |
E | Schaltschrank (OF1/OF2) |
xInAutomatic, xInErrorQuit, xInQuitLocal |
#t_Automatik_OF1 AND "SF0120", "SF0002", "SF0121" OR "SF0117" |
E | Bedienelemente |
nInTestTarget |
"IBN".nTestTarget111 |
P |
Pin-Lager (FB_ILS_MTRO_PinStore_Auto) und Leerträgerpuffer (FB_EmptyCarrBuffer)
| Daten | SCL-Stelle (Beispiel) | Quelle | Bemerkung |
|---|---|---|---|
| Anzahl Lagerlinien | nNoOfLines := 19, arInSep[1..5] |
L | Separatoren auf Kreisel mit Pinband / Separatorlist |
| Positionen je Linie, Staulänge | nNoOfPositions := 70, nJamLength := 4 / "cStorage111ExitJam2" |
L + P | aus Linienlänge und Teilung |
Liniensensoren arInSep[n].stSenTrolley, arInJamSensor[n], stInSenJamExit |
["cInBG3270"] |
E | |
Linienventile arOutSeparatorStore[n] |
"MB3270" |
E | |
Pin-Separator stInSeparatorPin, xOutSeparatorPin |
["cInBG3000"], "MB3000" |
E | |
Referenzsensor "Zappler" stInSensorReference |
["cInBG3001"] |
E | |
Encoder stInEncoderParameter |
#fbEncoderGF2200.nOutPosActDif |
E | |
nDestGeneral, nConvStations, nStationsMax, nStorageThreshold |
"cDest11100", "cHooksSorterMaxPin111" |
P | WCS/Projekt |
nInBufferNr, xInBufferReq/Release/ReleaseNext, xInPause |
101/102 |
P | Pufferlogik |
| Lager-/Stations-DBs | "DB_Storage1.1.1".arLine, "DB_ConveyorStations", "DB_HandshakeStorage" |
K + P | |
| Linien-Zeiten, Simulation | "cTimeSepHandlingStorageLine", stSimu.* |
P |
Ladeschleife (FB_LoadingBoom_INBOUND)
| Daten | SCL-Stelle (Beispiel) | Quelle | Bemerkung |
|---|---|---|---|
| Ladeschleife vorhanden, Lage | – | L | Beladestation (ILS 2.0 BTMT Beladung), prüfen |
Bedienelemente stInControl.* |
Taster, Knebel-/Schlüsselschalter | E | |
Ausleger/Stützfuß stInBoom.*, stInFoot.* |
Endlagen, Motorschutz, Bumper | E | |
Analogwerte stInTilt.wTilt, stInDistance.wDistance |
Neigung, Abstand | E | |
Sensoren stInSen2mThreshold, stInSenJamEntr/Exit1/Exit2, stInSenStopper1/2, stInSenGrid |
E | ||
Ausgänge stOutStopper.*, stOutBoom.*, stOutFoot.*, xOutLedMovement, xOutLight, xOutLedBumper, xOutCarousel |
E | ||
Schwellwerte nDiff, nZeroOk, nStartSlow/Fast, nDistanceZero, tDiff, tZero, nTiltComp |
P | Inbetriebnahme | |
stInSettings.* Zeiten |
tBoomInput := T#3500ms … |
P | |
Exit-Staubereich arInOutCarrierExit, stInOutCarrierExit |
L + K |
Zusammenfassung
- Aus dem Hardwarelayout (L) kommt die Struktur: welche TROs es gibt, ihr Typ
und damit FB und Anzahl der Parameterblöcke (Separatoren, Weichen, Scanner, Vario,
Lagerlinien), Vorgänger/Nachfolger und damit Ein-/Ausgangs-Staubereiche,
REGION-Reihenfolge, Ziele je Weichenabgang (
nTo1Destinations), Vorfahrt ja/nein, Systemgrenzen (xIsBorner), die tragende Fördertechnik (xInCarouselRun, Gefälle →TRUE), ob ein Scanner am Separator sitzt (xPluggedScanner) und Längen als Grundlage für Zeiten/Staulängen. Das meiste davon ist heute inDerivedTro→SclTroabgebildet; Vorfahrt,xIsBornerund Längen noch nicht. - Aus der Elektroplanung (E) kommen alle Namen und Adressen: jeder Sensor
(
BG), jedes Ventil (MB), Motor (MA), Motorschutz (FC), Taster (SF), Scanner (BX) samt Cognex-Variablen und Hardware-Kennung, diexPlugged*-Schalter (was ist tatsächlich verbaut), Weichenbauart, Not-Halt-Kreis, Schaltschrank und Steuerungsgrenzen. Im Render-Kontext sind das dieSclNamemittodo=True(TODO(E-Planung)). Offen ist die Brücke: die EA-Liste kennt keine Topologie; es braucht eine Zuordnung Layout-Bauteil (Separator-TeileId) ↔ BMK (BG3242/MB3242). Diese Brücke bautlib/e_planning.pyüber die Symbolpositionen in*_positionsdraw.jsondes Kabellängen-Tools (doc/E-Planung_Bruecke.md); heute kommen damit Separator-Sensor und Stopperventil in die SCL (scl_skeleton --eplan). - Namenskonvention (K):
cMainTro,cSep,cSwi, Staubereichs-DBs, HMI- und State-Pfade — sobald Nummernkreise feststehen, ohne weitere Quelle erzeugbar. - Parameter (P): Zeiten, Projektkonstanten, WCS-Ziele/Stationen, Test-/IBN-Signale — weder L noch E; gehören als Typ-Defaults in den Katalog bzw. in eine Projektkonfiguration.