# Vorschlag: Vereinheitlichung der MainTRO-Bausteine (`FB_ILS_MTRO`) Stand: 2026-07-13 ## Ausgangslage Die Anlage verwendet derzeit **sieben verschiedene MainTRO-Bausteine**, die aus dem SPS-Code extrahiert wurden: | Typ | Separatoren | Weichen | Eingänge | Ausgänge (Richtungen) | Prio-Manager | Scanner | Besonderheit | |---|---|---|---|---|---|---|---| | `FB_ILS_MTRO_1Sep` | 1 | 0 | 1 | 1 (Exit2) | 1 | 1 | Borner/Dummy-Handling | | `FB_ILS_MTRO_1Sep_SSCC` | 1 | 0 | 1 | 1 | 1 | 2 (+SSCC) | Endmess-Sensor | | `FB_ILS_MTRO_1Sep1Swi` | 1 | 1 | 1 | 2 (Exit2/3) | 2 (Dir1/2) | 1 | 2. Kreisel | | `FB_ILS_MTRO_1Sep2Swi` | 1 | 2 | 1 | 3 (Exit2/3/4) | 1 | 1 | 2. Kreisel | | `FB_ILS_MTRO_2Sep1Swi` | 2 | 1 | 2 | 2 | 4 (Dir1-4) | 2 | 2 Eingänge, 2 Kreisel | | `FB_ILS_MTRO_Vario` | 1 | 0 (Vario) | 1 | 1 (+Finger-Jam) | 1 | 1 | Kettenförderer, Finger-/Pos-Sensoren, Motorschutz | | `FB_ILS_MTRO_PinStore_Auto` | 1 + 21 | n | 1 | n Stationen | 1 | 1 | **Ausreißer** — Lagerblock, Encoder, Lagerlinien | ## Kernerkenntnis Alle MainTRO-Varianten basieren auf **demselben Grundgerüst**: ein `FB_StateManager` mit identischer Schrittkette (`WaitForTrolley → Scan → CheckLoad → CheckSep → GetDirection → CheckJam → CheckSwitch → ReleaseSep → Buchen`), plus zusammengesetzte Sub-TRO-Bausteine (`FB_ILS_STRO_Sep`, `FB_ILS_STRO_Switch`, `FB_ILS_STRO_Vario`, `FB_BarcodeReaderCognex`). Was sich zwischen den Typen unterscheidet, ist fast ausschließlich die **Anzahl** einiger Sub-Module und die entsprechende Zahl an Staubereichen/Richtungen. Das Namensschema `SepSwi` bringt es auf den Punkt: Es sind keine 7 Verhaltensweisen, sondern **ein Verhalten**, instanziiert mit 1–2 Separatoren, 0–2 Weichen, 1–4 Richtungen. Der skalare Teil der Schnittstelle ist **überall identisch**: `stInSettings` (Borner, Jam-Src/Dest, `bSepType`, Timings), `nInMainTroNo`, `xInSftyOk`, `xInAllRdyToStart`, `xInTestMode`, `xInCancel`, `xInAreaStopActive`, `xInRelease`, dazu die Ausgänge `xOutCorrection / nOutStateLast / nOutScanResult / xOutNewScan` und die In-Outs `stInOutMachineState / stInOutCognexInterface / stInOutHMI`. Lediglich die *wiederholten* Elemente werden von Hand vervielfältigt und durchnummeriert (`...1`, `...2`, `Dir1..Dir4`, `Exit2..Exit4`). ## Vorschlag: ein einziger Baustein `FB_ILS_MTRO` Die von Hand nummerierten Member werden durch **Arrays von zusammengesetzten UDTs** ersetzt, plus einen **Konfigurations-/Routing-Deskriptor**, der angibt, wie viele Elemente jeder Art existieren und wie jede Richtung verdrahtet ist. Der skalare Kern bleibt unverändert. ### 1. Vereinheitlichte TRO-Typdefinition (ersetzt die 7 `fbType`-Namen) ```json { "$def": "FB_ILS_MTRO", "description": "Single MainTRO block, shaped by config instead of by type name", "config": { "nNoOfSeparators": { "type": "USInt", "range": [1, 2] }, "nNoOfSwitches": { "type": "USInt", "range": [0, 2] }, "nNoOfCarousels": { "type": "USInt", "range": [1, 2] }, "nNoOfDirections": { "type": "USInt", "range": [1, 4] }, "xScannerPlugged": { "type": "Bool" }, "xSsccPlugged": { "type": "Bool" }, "xVarioMode": { "type": "Bool" } }, "arrays": { "arInSeparator": "Array[1..2] of UDT_MTRO_SeparatorIf", "arInSwitch": "Array[1..2] of UDT_MTRO_SwitchIf", "arInDirection": "Array[1..4] of UDT_MTRO_DirectionIf", "arInPriorityManager": "Array[1..4] of UDT_Response", "arInCarouselRun": "Array[1..2] of Bool", "arInOutJamEntr": "Array[1..2] of UDT_JamArea", "arInOutJamExit": "Array[1..4] of UDT_JamArea" }, "scalarCore": [ "stInSettings", "nInMainTroNo", "xInSftyOk", "xInAllRdyToStart", "xInTestMode", "xInCancel", "xInAreaStopActive", "xInRelease", "stInOutMachineState", "stInOutHMI" ] } ``` ### 2. Die zusammengesetzten UDTs, die als Array geführt werden ```json { "UDT_MTRO_SeparatorIf": { "stSenInSep": "UDT_Sensor", "stSenSepLeft": "UDT_Sensor", "stSenPart": "UDT_Sensor", "stSenStartScan": "UDT_Sensor", "stSenJamExit": "UDT_Sensor", "Settings": "SettingsSeparator", "bSepType": "Byte", "xIsBorner": "Bool", "nBornerDest": "Int" }, "UDT_MTRO_SwitchIf": { "stSenExit3": "UDT_Sensor", "stSenExit4": "UDT_Sensor", "Settings": "SettingsSwitch" }, "UDT_MTRO_DirectionIf": { "xPrioRelevant": "Bool", "nSepIndex": "USInt", "nSwitchIndex": "USInt", "nSwitchPos": "USInt" }, "UDT_JamArea": { "arCarrier": "Array[*] of stCarrier", "stData": "stJamData" } } ``` ### 3. Per-Instanz-Konfiguration, die jeden alten Typ reproduziert (die "Anreicherung") ```json { "instances": [ { "name": "TRO101", "replaces": "FB_ILS_MTRO_1Sep", "config": { "nNoOfSeparators": 1, "nNoOfSwitches": 0, "nNoOfCarousels": 1, "nNoOfDirections": 1, "xScannerPlugged": true, "xSsccPlugged": false, "xVarioMode": false }, "direction": [ { "nSepIndex": 1, "nSwitchIndex": 0, "nSwitchPos": 0, "xPrioRelevant": false } ] }, { "name": "TRO102", "replaces": "FB_ILS_MTRO_1Sep_SSCC", "config": { "nNoOfSeparators": 1, "nNoOfSwitches": 0, "nNoOfCarousels": 1, "nNoOfDirections": 1, "xScannerPlugged": true, "xSsccPlugged": true, "xVarioMode": false } }, { "name": "TRO103", "replaces": "FB_ILS_MTRO_1Sep1Swi", "config": { "nNoOfSeparators": 1, "nNoOfSwitches": 1, "nNoOfCarousels": 2, "nNoOfDirections": 2, "xScannerPlugged": true, "xSsccPlugged": false, "xVarioMode": false }, "direction": [ { "nSepIndex": 1, "nSwitchIndex": 1, "nSwitchPos": 3, "xPrioRelevant": true }, { "nSepIndex": 1, "nSwitchIndex": 1, "nSwitchPos": 4, "xPrioRelevant": true } ] }, { "name": "TRO104", "replaces": "FB_ILS_MTRO_1Sep2Swi", "config": { "nNoOfSeparators": 1, "nNoOfSwitches": 2, "nNoOfCarousels": 2, "nNoOfDirections": 3, "xScannerPlugged": true, "xSsccPlugged": false, "xVarioMode": false } }, { "name": "TRO105", "replaces": "FB_ILS_MTRO_2Sep1Swi", "config": { "nNoOfSeparators": 2, "nNoOfSwitches": 1, "nNoOfCarousels": 2, "nNoOfDirections": 4, "xScannerPlugged": true, "xSsccPlugged": false, "xVarioMode": false } }, { "name": "TRO106", "replaces": "FB_ILS_MTRO_Vario", "config": { "nNoOfSeparators": 1, "nNoOfSwitches": 0, "nNoOfCarousels": 1, "nNoOfDirections": 1, "xScannerPlugged": true, "xSsccPlugged": false, "xVarioMode": true } } ] } ``` ### 4. Einbindung in die bestehende `units[]`-Skeleton-Struktur Heute schreibt `create_skel.py` einen `fbType`-String pro Einheit. Im Vorschlag wird dieses eine Feld zu `fbType: "FB_ILS_MTRO"` plus ein `config`-Objekt, das der Generator aus den gezählten Rollen füllt: ```json { "unit": "M0101", "fbType": "FB_ILS_MTRO", "config": { "nNoOfSeparators": 1, "nNoOfSwitches": 1, "nNoOfCarousels": 2, "nNoOfDirections": 2, "xScannerPlugged": true, "xSsccPlugged": false, "xVarioMode": false }, "io": { "sensorInSep": ["BG0101"], "switchOutput": ["MB0102"], "stopperOutput": ["MB0101"], "sensorJam": ["BG0103"] } } ``` `guess_fbtype()` (liefert heute einen der 7 Namen, siehe `lib/create_skel.py:558-563`) würde stattdessen `"FB_ILS_MTRO"` zurückgeben plus einen zählenden Regelsatz: ```json { "configRules": { "nNoOfSeparators": "count(roles == 'sensorInSep')", "nNoOfSwitches": "count(roles == 'switchOutput')", "nNoOfDirections": "count(roles == 'switchOutput') + 1", "xScannerPlugged": "any(role == 'sensorStartScan')", "xVarioMode": "has(roles, 'sensorFinger') or has(roles, 'sensorCarrInPos')" } } ``` ## Abbildung der alten Typen auf den neuen Baustein (Übersicht) | Alter Typ | Konfiguration, die ihn reproduziert | |---|---| | `1Sep` | Sep=1, Swi=0, Car=1, Dir=1 | | `1Sep_SSCC` | Sep=1, Swi=0, Dir=1, `xSsccPlugged=TRUE` | | `1Sep1Swi` | Sep=1, Swi=1, Car=2, Dir=2 | | `1Sep2Swi` | Sep=1, Swi=2, Car=2, Dir=3 | | `2Sep1Swi` | Sep=2, Swi=1, Car=2, Dir=4 | | `Vario` | Sep=1, Swi=0, Dir=1, `xVarioMode=TRUE` | Sieben Bausteine → **ein Baustein + ein Konfigurationsdatensatz pro Instanz**. ## Was separat bleibt - **`FB_ILS_MTRO_PinStore_Auto`** ist ein echter Ausreißer — 21 Linien-Separatoren, Encoder-Positionserfassung, Lagerlinien-Daten (`arInOutStorageLines`), Auslager-Stationen. Es ist ein *Lager*-Controller, kein Routing-TRO. Die übrigen sechs werden in `FB_ILS_MTRO` zusammengeführt; PinStore bleibt eigenständig (oder wird zu `FB_ILS_STORE`). - **Vario** ist ein Grenzfall: Es tauscht die Weiche gegen einen Kettenförderer mit Finger-/Positionssensoren. Es passt als `xVarioMode` (ein Sub-Modul-Schalter), weil es weiterhin denselben Separator + State-Manager nutzt. Falls die Finger-Schrittkette zu stark abweicht, ist ein dünner Wrapper über den gemeinsamen Kern der Mode-Flag vorzuziehen. ## Abwägung - **Pro:** ein Baustein zum Testen/Versionieren/Dokumentieren; `create_skel.py` wird deutlich einfacher (kein `FBTYPE_TEMPLATE`-Mapping, ein Aufruf-Template); das in der Standardisierungsanalyse markierte "Versionschaos" entfällt. - **Contra:** Arrays mit `nNoOf...`-Guards sind weniger selbsterklärend als ein benannter `1Sep1Swi`; ungenutzte Array-Elemente kosten pro Instanz weiterhin DB-Speicher. Multi-Instanz-Sub-FB-Arrays und `Array[*]`-In-Outs werden auf dem Zielsystem (CPU 1518F) gut unterstützt — es gibt keinen Plattform-Blocker. ## Nächste Schritte (offen) 1. `FB_ILS_MTRO.scl`-Skelett prototypisieren (mit `FOR`-Schleifen-Aufrufen der Sub-TROs und einer datengetriebenen Richtungs-Tabelle). 2. `create_skel.py` anpassen, sodass es den einzelnen Baustein mit `config`-Block ausgibt statt der sieben Templates.