SCL-Templates fuer alle Typen mit Referenz-Aufrufstelle (Schritt 5)
- neue Templates: FB_ILS_MTRO_1Sep (TRO100), _Vario (TRO115), _Vario_workStation (TRO421), _1Sep2Swi (TRO267), _1Sep_SSCC (TRO105), _PinStore_Auto (TRO208); zusammen mit dem Pilot 1Sep1Swi 7 von 11 Typen. 2Sep1Swi, EmptyCarrBuffer, LoadingBoom, 2Sep2Swi bleiben generisch (keine reale Aufrufstelle) - scl_context: Felder nur fuer die Templates - Cognex-Verdrahtung je Scanner, part_sensor, carriers/data je Staubereich, jam_in/jam_out (dieselben Objekte wie erster Ein-/Ausgang), error_quit, automatic, is_border, correction_station, Bloecke sscc/work_station/store (PinStore: eine Linie je Speicherbahn aus dem Layout statt der 19 aus dem Katalog) - _macros: cognex_in/cognex_out/cognex, correction, todo_mehr - tests/test_scl_templates.py: Rundlauf je Template gegen seine Referenz (PinStore: von der Referenz abgekuerzte Teile ausgenommen); Normalisierung vereinheitlicht ":="/"=>"-Abstaende - Golden-Files *_templates neu geschrieben (gewollt: mehr TROs aus Templates); generische Golden-Files unveraendert - Doku: SCL_Templates.md (§6 Entscheidungen je Template, §11 Schritt 5, §13 offene Fragen 9-12), Python_Scripts.md, CLAUDE.md, README.md Zeilenentscheidungen sind Vorschlaege, noch mit den SPS-Kollegen zu bestaetigen. Geprueft: 39 Tests gruen, jede Rundlauf-Pruefung erkennt eine geaenderte Zeile; tro_flow --json + scl_skeleton --templates auf allen 8 CSVs ohne Fehler. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5764df1ac8
commit
41df841317
+184
-14
@@ -39,6 +39,10 @@ __all__ = [
|
||||
"SclSwitchExit",
|
||||
"SclScanner",
|
||||
"SclJam",
|
||||
"SclSscc",
|
||||
"SclWorkStation",
|
||||
"SclStoreLine",
|
||||
"SclStore",
|
||||
"SclTro",
|
||||
"SclFile",
|
||||
"build_context",
|
||||
@@ -77,6 +81,8 @@ class SclSeparator(BaseModel):
|
||||
no: SclName
|
||||
sensor: SclName
|
||||
stopper: SclName
|
||||
# Teilesensor (stSenPart) - nur in Templates, deren Referenz ihn hat (1Sep2Swi)
|
||||
part_sensor: SclName
|
||||
|
||||
|
||||
class SclSwitchExit(BaseModel):
|
||||
@@ -106,12 +112,21 @@ class SclSwitch(BaseModel):
|
||||
|
||||
|
||||
class SclScanner(BaseModel):
|
||||
"""Ein stInBarcodeReader-Block ("" als Suffix, wenn es nur einen gibt)."""
|
||||
"""Ein stInBarcodeReader-Block ("" als Suffix, wenn es nur einen gibt).
|
||||
|
||||
Die Cognex-Verdrahtung (nur in den Templates): ``interface`` ist der
|
||||
Schluessel in #arCognexInterface (z. B. "cScannerBX2100"), ``tag`` der
|
||||
Praefix der Hardware-Symbole ("bx2100-TriggerReady" ...), ``hw_results``
|
||||
das Ergebnis-Symbol der Kamera.
|
||||
"""
|
||||
|
||||
model_config = _CONFIG
|
||||
|
||||
n: int
|
||||
suffix: str
|
||||
interface: SclName
|
||||
tag: SclName
|
||||
hw_results: SclName
|
||||
|
||||
|
||||
class SclJam(BaseModel):
|
||||
@@ -125,6 +140,74 @@ class SclJam(BaseModel):
|
||||
db: SclName
|
||||
# Stausensor des Ausgangs (stInSenJam<n>); None an Eingaengen
|
||||
sensor: SclName | None = None
|
||||
# Traeger-Array und Staudaten des Bereichs - im Normalfall <db>.arCarrier
|
||||
# bzw. <db>.stData; an Uebergaben auch eigene Variablen (#arCarrierHandover...)
|
||||
carriers: SclName
|
||||
data: SclName
|
||||
|
||||
|
||||
class SclSscc(BaseModel):
|
||||
"""SSCC-Scanner eines 1Sep_SSCC: zweite Kamera, Endmessung, HMI-Anzeige."""
|
||||
|
||||
model_config = _CONFIG
|
||||
|
||||
# interface ist hier die Struktur selbst (z. B. "#stCognexIntfTro105")
|
||||
scanner: SclScanner
|
||||
end_sensor: SclName
|
||||
# Schluessel der HMI-Anzeige, z. B. "SSCC1107"
|
||||
hmi: SclName
|
||||
|
||||
|
||||
class SclWorkStation(BaseModel):
|
||||
"""Arbeitsplatz eines Vario_workStation."""
|
||||
|
||||
model_config = _CONFIG
|
||||
|
||||
station_sensor: SclName
|
||||
station_release: SclName
|
||||
loaded_error_sensor: SclName
|
||||
|
||||
|
||||
class SclStoreLine(BaseModel):
|
||||
"""Eine Speicherlinie eines PinStore_Auto (arInSep[n])."""
|
||||
|
||||
model_config = _CONFIG
|
||||
|
||||
n: int
|
||||
# Separatornummer der Linie aus dem Layout
|
||||
layout: str
|
||||
jam_length: SclName
|
||||
sensor: SclName
|
||||
jam_sensor: SclName
|
||||
stopper: SclName
|
||||
|
||||
|
||||
class SclStore(BaseModel):
|
||||
"""Alles fuer ein automatisches Pin-Lager (PinStore_Auto)."""
|
||||
|
||||
model_config = _CONFIG
|
||||
|
||||
encoder: SclName
|
||||
dest: SclName
|
||||
conv_stations: SclName
|
||||
stations_max: SclName
|
||||
threshold: SclName
|
||||
reference_sensor: SclName
|
||||
station: SclName
|
||||
quit_local: SclName
|
||||
test_target: SclName
|
||||
run_in: SclName
|
||||
run_out: SclName
|
||||
db: SclName
|
||||
removal: SclName
|
||||
conv_db: SclName
|
||||
# Einschleus-Separator (Pin) - aus dem Layout, wenn tro_flow einen
|
||||
# steuernden Separator vor den Linien gefunden hat, sonst "?"
|
||||
pin_layout: str
|
||||
pin_sensor: SclName
|
||||
pin_stopper: SclName
|
||||
# Eine Linie je Speicherbahn im Layout (nicht die 19 aus dem Katalog)
|
||||
lines: list[SclStoreLine]
|
||||
|
||||
|
||||
class SclTro(BaseModel):
|
||||
@@ -169,6 +252,22 @@ class SclTro(BaseModel):
|
||||
# nicht in der TRO-JSON - deshalb immer offen (doc/SCL_Templates.md §6).
|
||||
carousel_run: SclName
|
||||
|
||||
# -- nur fuer die Templates (Referenz-Aufrufstellen, doc/SCL_Templates.md §6)
|
||||
# Einziger Staubereich am Ein-/Ausgang fuer FBs ohne Nummerierung
|
||||
# (Vario: JamEntr/JamFinger, PinStore: JamEntr/JamExit): der erste
|
||||
# Vorgaenger bzw. Nachfolger, sonst ein offener Platzhalter
|
||||
jam_in: SclJam
|
||||
jam_out: SclJam
|
||||
error_quit: SclName
|
||||
automatic: SclName
|
||||
# Vario: stInSettings.xIsBorner (Bedeutung mit SPS klaeren)
|
||||
is_border: SclName
|
||||
# Station fuer FC_CARR_GLOB_CORRECTION (1Sep_SSCC, PinStore_Auto)
|
||||
correction_station: SclName
|
||||
sscc: SclSscc | None = None
|
||||
work_station: SclWorkStation | None = None
|
||||
store: SclStore | None = None
|
||||
|
||||
@property
|
||||
def has_scanner(self) -> bool:
|
||||
return bool(self.scanners)
|
||||
@@ -282,6 +381,59 @@ def _nummer(tro_id: str) -> str:
|
||||
# Kontext bauen
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _scanner(n: int, suffix: str, interface: str = "cScanner____") -> SclScanner:
|
||||
return SclScanner(
|
||||
n=n, suffix=suffix, interface=_offen(interface), tag=_offen("bx____"),
|
||||
hw_results=_offen("BX____~Ergebnisse_\u2013_64_Bytes_1"),
|
||||
)
|
||||
|
||||
|
||||
def _jam(n: int, neighbour: str, jam_db: str, sensor: SclName | None = None) -> SclJam:
|
||||
return SclJam(
|
||||
n=n, neighbour=neighbour, db=_offen(jam_db), sensor=sensor,
|
||||
carriers=_offen(f"{jam_db}.arCarrier"), data=_offen(f"{jam_db}.stData"),
|
||||
)
|
||||
|
||||
|
||||
def _store(tro: TroBase) -> SclStore:
|
||||
"""PinStore_Auto: eine Linie je Speicherbahn (Host) des Layouts.
|
||||
|
||||
tro_flow legt die Separatoren als [steuernde ..., Linien ...] ab; die
|
||||
Linien sind die letzten len(hosts). Fehlen Hosts (fremde JSON), zaehlt
|
||||
jeder Separator als Linie.
|
||||
"""
|
||||
hosts = list(getattr(tro, "hosts", []) or [])
|
||||
seps = list(tro.separators)
|
||||
anzahl = len(hosts) if 0 < len(hosts) <= len(seps) else len(seps)
|
||||
steuer, linien = seps[:len(seps) - anzahl], seps[len(seps) - anzahl:]
|
||||
return SclStore(
|
||||
encoder=_offen("#fbEncoder____"),
|
||||
dest=_offen("cDest____"),
|
||||
conv_stations=_offen("cHooksSorterMaxPin____"),
|
||||
stations_max=_offen("cStationsMax____"),
|
||||
threshold=_offen("cNoPositionsBlock____"),
|
||||
reference_sensor=_offen("cInBG____"),
|
||||
station=_offen("____"),
|
||||
quit_local=_offen('"SF____"'),
|
||||
test_target=_offen('"IBN".nTestTarget____'),
|
||||
run_in=_offen("#fbSortConv____.xOutConveyorFullSpeed"),
|
||||
run_out=_offen("#fbExitConv____.xOutConveyorFullSpeed"),
|
||||
db=_offen('"DB_Storage____"'),
|
||||
removal=_offen('"DB_HandshakeStorage".Str_StorageRemoval.'
|
||||
'arrudt_StorageRemovalHandshakeTROsLvl1[____]'),
|
||||
conv_db=_offen('"DB_ConveyorStations".stConveyorStations____'),
|
||||
pin_layout=", ".join(steuer) or "?",
|
||||
pin_sensor=_offen("cInBG____"),
|
||||
pin_stopper=_offen("MB____"),
|
||||
lines=[
|
||||
SclStoreLine(n=n, layout=sep, jam_length=_offen('"cStorage____ExitJam"'),
|
||||
sensor=_offen("cInBG____"), jam_sensor=_offen("cInBG____"),
|
||||
stopper=_offen("MB____"))
|
||||
for n, sep in enumerate(linien, start=1)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def _tro_context(tro: TroBase, alle: dict[str, TroBase]) -> SclTro:
|
||||
items = tro.items
|
||||
n_sep = items.get(TroItem.SEPARATOR, 1)
|
||||
@@ -297,6 +449,7 @@ def _tro_context(tro: TroBase, alle: dict[str, TroBase]) -> SclTro:
|
||||
no=_offen("cSep_____"),
|
||||
sensor=_offen("cInBG____"),
|
||||
stopper=_offen("MB____"),
|
||||
part_sensor=_offen("cInBG____"),
|
||||
)
|
||||
for i in range(1, n_sep + 1)
|
||||
]
|
||||
@@ -322,6 +475,17 @@ def _tro_context(tro: TroBase, alle: dict[str, TroBase]) -> SclTro:
|
||||
SclSwitchExit(via=abgang, targets=reachable_via(tro_id, abgang, alle))
|
||||
for abgang in tro.successors
|
||||
] if n_swi else []
|
||||
# Staubereiche: je ankommender/abgehender Verbindung einer. Welche
|
||||
# DB-Struktur dahintersteht, ist eine Planungsentscheidung - hier steht
|
||||
# nur, WIE VIELE es sein muessen und zu welchem Nachbarn sie gehoeren.
|
||||
jam_entries = [
|
||||
_jam(n, _nachbar(vor, alle), jam_db)
|
||||
for n, vor in enumerate(tro.predecessors, start=1)
|
||||
]
|
||||
jam_exits = [
|
||||
_jam(n, _nachbar(nach, alle), jam_db, sensor=_offen("cInBG____"))
|
||||
for n, nach in enumerate(tro.successors, start=2)
|
||||
]
|
||||
|
||||
return SclTro(
|
||||
id=tro_id,
|
||||
@@ -340,22 +504,12 @@ def _tro_context(tro: TroBase, alle: dict[str, TroBase]) -> SclTro:
|
||||
has_vario=has_vario,
|
||||
vario_sensors=vario_sensors,
|
||||
scanners=[
|
||||
SclScanner(n=i, suffix="" if n_scan == 1 else str(i))
|
||||
_scanner(i, "" if n_scan == 1 else str(i))
|
||||
for i in range(1, n_scan + 1)
|
||||
],
|
||||
storage_lines=items.get(TroItem.STORAGE_LINE, 0),
|
||||
# Staubereiche: je ankommender/abgehender Verbindung einer. Welche
|
||||
# DB-Struktur dahintersteht, ist eine Planungsentscheidung - hier steht
|
||||
# nur, WIE VIELE es sein muessen und zu welchem Nachbarn sie gehoeren.
|
||||
jam_entries=[
|
||||
SclJam(n=n, neighbour=_nachbar(vor, alle), db=_offen(jam_db))
|
||||
for n, vor in enumerate(tro.predecessors, start=1)
|
||||
],
|
||||
jam_exits=[
|
||||
SclJam(n=n, neighbour=_nachbar(nach, alle), db=_offen(jam_db),
|
||||
sensor=_offen("cInBG____"))
|
||||
for n, nach in enumerate(tro.successors, start=2)
|
||||
],
|
||||
jam_entries=jam_entries,
|
||||
jam_exits=jam_exits,
|
||||
main_tro=_offen("cMainTro____"),
|
||||
safety=_offen('"DB_InterfaceSafety".stFromSafety.EStopMain.Q'),
|
||||
release=f'"DB_TRO_TEST".{tro_id}',
|
||||
@@ -367,6 +521,22 @@ def _tro_context(tro: TroBase, alle: dict[str, TroBase]) -> SclTro:
|
||||
# Vorschlag aus der Referenz TRO107, Prioritaet bleibt Planungsentscheidung
|
||||
prio_dir2=_offen("TRUE"),
|
||||
carousel_run=_offen("#fbCarousel____.xOutConveyorFullSpeed"),
|
||||
# dasselbe Objekt wie der erste Ein-/Ausgang: ein Name, den die
|
||||
# Namensregeln dort setzen, gilt damit auch hier
|
||||
jam_in=jam_entries[0] if jam_entries else _jam(1, "-", jam_db),
|
||||
jam_out=jam_exits[0] if jam_exits else _jam(2, "-", jam_db),
|
||||
error_quit=_offen('"SF____"'),
|
||||
automatic=_offen("#t_automatik"),
|
||||
is_border=_offen("TRUE"),
|
||||
correction_station=_offen("0"),
|
||||
sscc=(SclSscc(scanner=_scanner(1, "SSCC", "#stCognexIntf____"),
|
||||
end_sensor=_offen("cInBG____"), hmi=_offen("SSCC____"))
|
||||
if items.get(TroItem.SSCC) else None),
|
||||
work_station=(SclWorkStation(station_sensor=_offen("cInBG____"),
|
||||
station_release=_offen('#"rTrig_Workstation ____".CLK'),
|
||||
loaded_error_sensor=_offen("cInBG____"))
|
||||
if items.get(TroItem.WORK_STATION) else None),
|
||||
store=_store(tro) if items.get(TroItem.STORAGE_LINE) else None,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user