tro_flow: Weichen-Separator nach Laufrichtung, Weichen-Slots mit Bauteil

Steuernder Separator einer ILS Weiche (_find_weiche_separators) ist der
letzte freie Separator in Laufrichtung VOR der Weiche, gemessen auf dem
Kreisel-Umlauf aus Lage und Drehrichtung (kreisel_junctions.separators_before)
- nicht mehr der CSV-Nachbar. Ein Nachbar hinter der Weiche steuert sie nie;
Hoechstabstand weiche_vorlauf_max in cfg/parameter.ini [tro_flow]. Mubea
(Export 2026-10-16): 2Sep2Swi = 0005 (Ausschleus 0061) + 0036 (Weiche 0130)
statt 0005 + 0012; 0012 bleibt 1Sep, Kreisel1 wieder angebunden. Dematic,
HundM05, showroom, test_system unveraendert.

TRO-JSON: DerivedTro.switches (optional) nennt die Weichen-Bauteile in
Slot-Reihenfolge (switch<i> gehoert bei 2Sep-Typen zu separator<i>);
derive_slots traegt sie in die switch<n>-Slots, merge_hw_layout bindet das
Ventil dort. e_planning.ini: Rollen ventil -> valve (Slot-Rolle der SCL),
neue Regel Ausschleus_Weiche.valve fuer Ausschleusventile an Kreisel-Weichen.
Mubea: MB0715, MB0724, MB0627, MB0671 statt TODO(E-Planung).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-16 13:42:16 +02:00
parent 39b445a7c4
commit d414bd6cf3
8 changed files with 297 additions and 46 deletions
+41 -8
View File
@@ -324,8 +324,30 @@ any other switch. The type follows from the count: separators × switches. The
host of each separator is the lane it physically lies on, not its `Zuordnung`.
If the two Kreisel run against each other at the touch point (both `UZS` at a
pulley-to-pulley touch, as in Mubea and Dematic — probably an export error), no
junction is formed, a finding is written, and the ILS Weiche is handled by the
older neighbour rule (`_find_weiche_separators`, step 3c').
junction is formed, a finding is written, and the ILS Weiche is handled by
`_find_weiche_separators` (step 3c'). The same happens when a junction separator
already controls an Ausschleuselement (step 3b) — step 3d then merges both.
**Controlling separator of an ILS Weiche** (`_find_weiche_separators`, step 3c').
Measured on the Kreisel loop from position and `Drehrichtung`, **not** from
`TrackIds` or the `Nachbarn` column (`kreisel_junctions.separators_before`):
1. For each Kreisel the Weiche lies on, only the **last separator before** it
in the direction of travel counts. A separator behind the Weiche never
controls it, even if it is a CSV neighbour (finding).
2. It must be free (not already the controller of an Ausschleuselement, not a
VF-chain separator) and at most `weiche_vorlauf_max` mm of travel before the
Weiche (`cfg/parameter.ini [tro_flow]`, default 3000).
3. If several remain (one per Kreisel): CSV neighbour first, then one with a
scanner, then the shortest travel distance. A choice outside the CSV
neighbours is reported as a finding.
Only when the Weiche lies on no Kreisel loop (no geometry or `Drehrichtung`) does
the old neighbour rule apply (neighbour with scanner, else the only neighbour).
Mubea export 2026-10-16: Weiche 0130 has neighbours 0061/0012, but 0012 lies
behind it on Kreisel2 and 0005 (before it) already controls Ausschleuselement
0061; the controller is 0036, 1303 mm before it on Kreisel1, so step 3d gives
`2Sep2Swi` 0005 + 0036 and 0012 stays `1Sep`.
A scanner mounted on a separator does **not** change the type (stays `1Sep`);
the `1Sep_SSCC` special case can't be recognized from the mechanical layout
@@ -583,12 +605,14 @@ layout is `anlage.layout`; names come from `bindings[]` by TRO-ID + slot + role
|---|---|
| `separator<n>` `sensor` / `stopper` / `partSensor` | `stSenInSep`, `xOutStopper<n>`, `stSenPart` |
| `line<n>` `sensor` / `stopper` / `jamSensor` | PinStore storage lines |
| `switch<n>` `valve` | `xOutSw<n>ExTo3` |
| `switch<n>` `valve` | `xOutSw<n>ExTo3` — the slot names the switch part from `switches` of the TRO-JSON (Ausschleuselement or ILS Weiche; `switch<i>` belongs to `separator<i>` in 2Sep types) |
| `drive` `motor` / `motorProtection` / `sen*` | Vario motor, `xInMotorProtection`, `stSenCarrInPos` … (motor/protection fall back to the conveyor of the TRO's host) |
| `conveyors[]` on the TRO's host | `xInCarouselRun` = `#fbCarousel<NNNN>.xOutConveyorFullSpeed` (Kreisel only); jam DB `"DB_JamArea<NNNN>".stJam<NNNN>_____` — still `TODO`, the running number `<k>` is not fixed yet |
Not filled yet: jam sensors at the exits (`stInSenJam<n>`, the `Ausschleus.stau`
bindings have no slot), scanners, separator/switch/MainTro numbers. The
bindings have no slot), scanners, separator/switch/MainTro numbers. Switch
valves are filled since 2026-10-16 (Mubea: MB0627, MB0715, MB0724, MB0671 for
TRO14/18/09). The
templates are unchanged — a known name simply drops its marker. Afterwards
every inserted name is checked against the hardware planning (`hwFile` of the
plant JSON in `%SKEL_RESULTS%`, or `--hw NAME`): names missing there are listed
@@ -660,7 +684,14 @@ Steps:
| `nummer_von`, `nummer_versatz` | numbering rule: BMK number = number of the given role + offset (Mubea: valve = sensor + 1) — tried first, distance only for the rest |
Shipped rules (tuned on Mubea): `Separator.sensor`, `Separator.stopper`,
`Ausschleus.stau`, `Ausschleus.ventil`, `Weiche.ventil`. `VERW` texts and the
`Ausschleus.stau`, `Ausschleus.valve` (storage lines: fixed ~1414 mm, number =
jam sensor + 1), `Ausschleus_Weiche.valve` (`layout = Ausschleus`; switch
outfeeds of a Strecke: nearest `AE ABZW*` valve within 1000 mm, only what the
rule before left over), `Weiche.valve`. The role after the dot is the slot role
of the TRO-JSON (`sensor`, `stopper`, `valve`, `exitSensor`): only then does
`merge_hw_layout` put the match into a slot; any other role (`stau`) stays
`ohne_slot`. Several rules may fill the same role if their section names
differ (`layout` names the kind). `VERW` texts and the
numbering rule are project-specific — in the reference SCL (UH01..UH05)
sensor and stopper share the number (BG3242/MB3242), i.e. offset `0`.
4. **Drives**: motor `MAnnnn` ↔ motor protection `FCnnnn` (same number), for the
@@ -784,8 +815,10 @@ Steps:
part — key **TRO-ID + slot + role**. A `PinStore_Auto` now has a slot per
storage line (`line1` … `lineN`, same split as `scl_context._store`);
`separator1` and `line1` can be the same part and both get the binding.
Parts without a slot (outfeed elements, switches — `tro_flow` does not keep
them on the TRO yet) stay visible as `ohne_slot`.
The `switch<n>` slots name the TRO's switch parts (`switches`: the
Ausschleuselement or ILS Weiche it controls), so their valve binds there.
Parts without a slot (storage-line outfeeds, roles like `stau` that no slot
has) stay visible as `ohne_slot`.
4. **Conveyors**: the E-planning names (`K0102`) and the layout names
(`Kreisel3`) do not match, so every field device whose text names a conveyor
votes for the nearest layout conveyor (distance to its bounding box, at most
@@ -874,7 +907,7 @@ tro_flow.py (writes) · scl_skeleton.py (reads) · tro_annotate.py (draws)
| Class | What it is |
|---|---|
| `TroBase` | Core of every TRO: `id`, `type`, `confidence`, `separators`, `predecessors`, `successors`, `position` (`{x,y,z}` in JSON). `definition()`, `fb_block` (JSON `fbType`) and `items` are **read from the catalog** on every access, never stored — so they follow a type change and cannot go stale. |
| `DerivedTro` | `TroBase` + what `tro_flow.py` knows from the derivation: `label`, `hosts`, `scanners`, `reason`, `colocated`, `positionFrom`, `positionPoints`, `slots`. Also used for the system boundaries `SYSn` (no slots). |
| `DerivedTro` | `TroBase` + what `tro_flow.py` knows from the derivation: `label`, `hosts`, `scanners`, `switches` (switch parts in slot order, `switch<i>` with `separator<i>`; since 2026-10-16, optional), `reason`, `colocated`, `positionFrom`, `positionPoints`, `slots`. Also used for the system boundaries `SYSn` (no slots). |
| `Slot` | A place on a TRO where hardware belongs: `slot` (`separator1`, `switch1`, `scanner1`, `drive`, `line<n>` for the storage lines of a store — the stable key together with the TRO-ID), `layoutId` (TeileId in the current export, for tracing only; empty for switches, whose element `tro_flow` does not keep yet), `roles` the hardware planning must fill (`sensor`, `stopper`, `jamSensor?` …; `?` = optional). Built by `derive_slots()` from the catalog type. |
| `JamArea` | A jam area = the queue in front of a separator, the entry of exactly one TRO: `id` (`J<Separator>`, e.g. `J0042`), `tro`, `entry` (1, 2 for 2Sep types), `separator`, `host`, `predecessors` (all TROs/stations feeding it — merges have several), `note`, `position`. Built by `derive_jam_areas()`; the SCL name `"DB_JamArea<NNNN>".stJam<NNNN>_<k>` needs the conveyor number from the hardware planning and is not stored. |
| `Connection` | Directed edge `from` → `to` with its `kind` (transfer / umlauf / weiche / unbestimmt / normal / bahn). |