Table of Contents
Positionsbestimmung
Rangierbeispiel → Positionsbestimmung → Erweitertes Rangierbeispiel → Rangieren mit Frachtscheinen→ IoT Fahrplananzeiger
Positionsbestimmung von Wagons in einem Block mit Hilfe eines XML-Scripts
Ab Revision 11.715+
Vorwort
Im diesem Tutorial geht es darum, den Wagons eine Position innerhalb eines Zuges oder eines Blocks zu geben. Eine Rangierlok kann schließlich keine Wagons aus der Mitte herausnehmen und diese bewegen. Sie kann nur am Anfang oder am Ende einer Wagonkette Wagons aufnehmen. Dazu muß die Position jedes Wagons innerhalb eines Zuges oder wenn ein Zug erst zusammengestellt werden soll, innerhalb eines Abstellgleises bestimmt werden. In diesem Tutorial wird nicht weiter auf die Basics von Rocrail eingegangen und Grundkenntnisse von XML-Scripten vorausgesetzt. Beschreibungen und Erklärungen sind hierzu im Wiki beschrieben.
Dieses Tutorial wurde von Gerrit Schulze erstellt und erhebt keinen Anspruch auf Vollständigkeit.
Das Szenario
- Ein Zug kommt in einem Block an. Die Position eines jeden Wagons im Zug soll auf den Block Übertragen werden.
- Ein Zug verläßt einen Block. Die Position eines jeden Wagons im Block soll auf den Zug übertragen werden.
Warum ist das Wichtig?
Nun - anhand alleine der Wagonkennung weiß man noch nicht, wo sich der Wagon von der Position her befindet. Wenn also Wagon „X“ bewegt werden soll, kann es sein das mehrere Wagon „Y“ davor stehen, jedoch alle im selben Block. Verwendet man z.B. RFID als Identifizierung eines Wagons., muß jeder Wagon einzeln über einen Sensor bewegen werden, bis der passende Wagon gefunden wurde. Das macht automatisierte Rangierabläufe nicht einfacher. Mit zwei Scripten weiß Rocrail aber wo sich jeder Wagen von der Position her befindet und man kann auf diese Information direkt zugreifen. Es muß die Position eines jeden Wagons erfasst werden, damit z.B. beim Rangieren der oder die richtigen Wagons ausgewählt werden.
Die Positionsbestimmung
Es gibt zwei definierte Situationen, in denen die Position eines Wagons ermittelt und festgelegt werden kann. Diese sind bei Einfahrt eines Zuges „Enter“ und bei Ausfahrt „Depart“. Dazwischen werden die Wagen z.B. mit einem Script „Rangieren“ einem Zug zugeordnet, aus einem Zug entfernt oder auf einem Gleis stehen gelassen. Es sind also zwei Scripte notwendig, die nur der Positionsbestimmung dienen. Es ist sinnvoll, diese auch separat zu lassen, damit auch beim manuellen Zuordnen oder Entfernen eines Wagens im Zug, anschließend die Position ermittelt wird.
Das Script „enter.xml“ wird mit Hilfe einer Aktion bei ENTER in einem Block ausgeführt. Das Script „depart.xml“ entsprechend bei DEPART in einem Block. Hier gibt es eine wichtige Sache zu beachten:
Das Script für DEPART wird nur in Blöcken ausgeführt, in denen der Zug hält. Bei durchfahrenden Zügen gibt es kein DEPART. Das würde also dazu führen, daß zwar das Script für ENTER, aber nicht für DEPART ausgeführt wird, womit die Zählung dann durcheinander gewürfelt wird. Also, entweder die entsprechenden Blöcke, in denen die Position bestimmt werden soll, auf „Warten“ einstellen, oder in den Aktionsbedingungen die Ausführung der Scripte auf haltende Züge einschränken (z.B. über den Zugtyp oder Klassen).
Desweiteren ist es wichtig in Endblöcken nicht die Option Kopfbahnhof, sondern die Option Richtungswechsel erlauben zu aktivieren. Ansonsten kann es bei der Erfassung der Positionen der Wagons zu Fehlern kommen.
Das Enter-Script
Zur Verdeutlichung eine schematische Darstellung:
Die Betrachtung erfolgt über die Block-Einfahrtseite. Dabei ist es unerheblich, ob eine Lok schiebt oder zieht. Über die Einfahrtseite betrachtet bleibt der erste Wagon der „Erste“ und der letzte Wagon der „Letzte“.
Die Erfassung aller notwendigen Parameter für die Positionsbestimmung erfolgt über Variablen. Dazu werden folgende Variablen benötigt:
- Eine Variable mit dem Namen der Zugkennung für jeden Zug
- Eine Variable mit dem Namen der Lokkennung für jede Lok
- Eine Variable mit dem Namen des Blocks für jeden Block
- Eine Variable mit dem Namen Pos_Block für jeden Block (wird als Hilfszähler und für die Speicherung der Block-Einfahrtseite benötigt)
- Eine Variable mit den Namen der Wagenkennung für jeden Wagen
Der Aufbau des Scripts:
<!-- Variablen von Block und Zug setzen --> <vr id="%callerid%" text="%operatorid%"/> <vr id="Pos_%callerid%" value="0"/>
Zuerst wird die Zug-Kennung %operatorid%
in das Textfeld der Variablen mit der Block-Kennung %callerid%
geschrieben, dann der Hilfszähler Pos_%callerid%
auf NULL gesetzt.
<!-- Anzahl Wagen im Zug ermitteln (Hilfszaehler)--> <foreach table="carlist" condition="@%callerid% = %operatorid%"> <vr id="Pos_%callerid%" value="#Pos_%callerid% + 1"/> </foreach>
Über eine <foreach>-Schleife die Anzahl der Wagons im Zug ermittelt.
<!-- Wenn Wagen gefunden, dann ist Variablen-Wert groesser NULL --> <if condition="#Pos_%callerid% > 0"> <then> <!-- Wenn Einfahrtseite der Lok plus ist --> <if state="lc %lcid% = +"> <then> <!-- DANN, Variablen-Text auf plus setzen --> <vr id="Pos_%callerid%" text="plus"/> </then> </if> <!-- Wenn Einfahrtseite der Lok minus ist --> <if state="lc %lcid% = -"> <then> <!-- DANN, Variablen-Text auf plus setzen --> <vr id="Pos_%callerid%" text="minus"/> </then> </if> </then> </if>
Wenn der Hilfszähler größer NULL ist, wird die Einfahrtseite der Lok ermittelt und in das Textfeld vom Hilfszähler geschrieben. Dieses wird später beim Depart-Script benötigt.
<vr id="%lcid%" value="1"/> <!-- Wagenliste prüfen, solange Wagen im Block, Variable ist Hilfszaehler --> <while condition="#Pos_%callerid% > 0" max="10"> <!-- DANN, Prüfen welcher Wagen der Erste mit der Einfahrtseite vom Zug ist --> <foreach table="carlist" condition="@%callerid% = %operatorid%|#%oid% = #%lcid%"> <!-- Variable Block erhöhen --> <vr id="%callerid%" value="#%callerid% + 1"/> <!-- Wagenposition im Block und Zugkennung in Variable vom Wagen schreiben --> <vr id="%oid%" value="#%callerid%"/> <vr id="%oid%" text="%operatorid%"/> <!-- Variable Zugkennung um EINS reduzieren --> <vr id="%operatorid%" value="#%operatorid% - 1"/> <!-- Hilfszaehler um EINS reduzieren --> <vr id="Pos_%callerid%" value="#Pos_%callerid% - 1"/> <break condition="Pos_%callerid% = 0"/> <vr id="%lcid%" value="#%lcid% + 1"/> </foreach> </while>
Jetzt muß die Position eines jeden Wagons im Zug auf den Block übertragen werden. Das geschieht, in dem die Wagenliste so oft durchlaufen wird, wie der Hilfszähler größer Null ist. Also wird die <foreach>-Schleife in eine <while>-Schleife eingebunden. Dabei wird die Variable der Lok auf EINS gesetzt, denn es wird bei der Zählweise immer mit dem ersten Wagon begonnen (siehe schematische Darstellung). Wird also ein passender Wagon gefunden, dann wird die Variable vom Block um EINS erhöht <vr id="%callerid%" value="#%callerid% + 1"/>
. Befinden sich bereits Wagons im Block (z.B. durch Rangieren), so wird aus dem ersten Wagon im Zug der X-te Wagon im Block <vr id="%oid%" value="#%callerid%"/>
.
Was wurde jetzt erreicht ?
Bei Einfahrt eines Zuges (enter) werden die Positionen der Wagons aus dem Zug auf die Position im Block übertragen.
Das Depart-Script
Auch an dieser Stelle eine schematische Darstellung zur Verdeutlichung:
Wie man aus der schematischen Darstellung sehen kann, gibt es zwei Möglichkeiten, wie die Wagons in den Block abgestellt wurden. Entweder mit der Block-Einfahrtseite „-“ oder „+“ Das ist übrigens in der Variablen „Pos_%callerid%“, also im Hilfszähler, zwischengespeichert. Die Lok, die Wagons in den Zug übernimmt, hat ebenfalls zwei Möglichkeiten den Block mit der Einfahrtseite „-“ oder „+“ zu verlassen. Es ergeben sich also 4 Kombinationsmöglichkeiten, auf die im nachfolgenden Script geprüft werden muß, um die Position der Wagons im Block auch der richtigen Position im Zug beim Verlassen des Blocks zuzuordnen. Dabei ist es im übrigen auch unerheblich, von welcher Seite die Lok in den Block eingefahren ist, also ob der Zug geschoben oder gezogen wird, denn bei „Depart“ hat die Lok evtl. die Platzierung (also Einfahrtseite) bereits gewechselt.
Der Aufbau des Scripts:
<!-- Zaehler auf EINS setzen, da erster Wagen mit Position EINS beginnt --> <vr id="%lcid%" value="1"/>
Als Erstes wird die Variable der Lok auf 1 gesetzt, da der erste Wagon im Zug mit EINS beginnt.
<!-- Wenn Einfahrtseite der Lok plus ist --> <if state="lc %lcid% = +"> <then>
Dann wird die Einfahrtseite der Lok geprüft mit der sie den Block verläßt. Die Lok fährt also auf der „-“-Seite des Blocks heraus.
<!-- Variablen setzen --> <vr id="%callerid%" text="%operatorid%"/> <vr id="Pos_%callerid%" value="0"/>
Dann werden die Variablen gesetzt. Die Variable vom Block bekommt die Zug-Kennung zugeordnet und der Hilfszähler wird auf NULL gesetzt.
<!-- Anzahl Wagen im Zug ermitteln --> <foreach table="carlist" condition="@%callerid% = %operatorid%"> <vr id="Pos_%callerid%" value="#Pos_%callerid% + 1"/> <!-- Text-Variable des Wagens auf cargo setzen (wird zur Differenzierung in der Schleife benötigt) --> <vr id="%oid%" text="cargo"/> </foreach> <vr id="@%callerid%" value="#Pos_%callerid%"/>
Jetzt wird die Wagonliste in einer Schleife durchlaufen und geprüft welcher Wagon die gleiche Zugkennung hat, die in der Variablen vom Block abgespeichert ist. Dabei wird der Hilfszähler jeweils um EINS erhöht und in die Variable vom Wagon „cargo“ geschrieben, damit in der nachfolgenden Schleife nach den Wagons, die in den Zug übernommen wurden, differenziert werden kann. Danach wird noch der Wert vom Hilfszähler in die Variable der Zug-Kennung geschrieben (Gesamtzahl Wagons im Zug) <vr id="@%callerid%" value="#Pos_%callerid%"/>
.
<!-- Zaehlweise vorwaerts (Einfahrtseite Wagen, gleiche Einfahrtseite Lok) --> <if condition="@Pos_%callerid% = plus"> <then> <!-- Wagenliste prüfen, solange Wagen im Zug --> <while condition="#Pos_%callerid% > 0" max="10"> <!-- DANN, Prüfen welcher Wagen sich im Zug befindet und als Text-Variable cargo haben--> <foreach table="carlist" condition="@%callerid% = %operatorid%|@%oid% = cargo"> <!-- Text in Variable vom Wagen löschen, um Doppelzählung zu vermeiden --> <vr id="%oid%" text=""/> <!-- Variable Hilfszähler um EINS reduzieren --> <vr id="Pos_%callerid%" value="#Pos_%callerid% - 1"/> <!-- Variable Block reduzieren --> <vr id="%callerid%" value="#%callerid% - 1"/> </foreach> </while> <!-- script verlassen --> <vr id="%lcid%" value="0"/> <exit/> </then> </if>
Als Nächstes wird geprüft, ob der Variablen-Text vom Hilfszähler „plus“ enthält, also die Wagons die gleiche Einfahrtseite haben, wie die Lok. Wenn das der Falls ist, so wird die Wagenliste so lange durchlaufen, bis der Hilfszähler auf NULL ist, also alle Positionen in die Wagon-Variablen geschrieben sind <while condition="#Pos_%callerid% > 0" max="10">
. In der Wagonliste wird jetzt nur auf die Zugkennung und den Variablen-Text „cargo“ geprüft. Die Position der Wagons bleibt unverändert, da die Einfahrtseite der Wagons gleich der Einfahrtseite der Lok ist. So wird sichergestellt, daß nur Wagons berücksichtigt werden, die sich auch in dem Zug befinden und nicht in dem Block stehen bleiben sollen. Die Variable vom Block wird entsprechen um die Anzahl der Wagons im Zug reduziert.
<!-- Zaehlweise rueckwaerts (Einfahrtseite Wagen, entgegengesetzte Einfahrtseite Lok) --> <if condition="@Pos_%callerid% = minus"> <then> <!-- Wagenliste prüfen, solange Wagen im Zug --> <while condition="#Pos_%callerid% > 0" max="10"> <!-- DANN, Prüfen welcher Wagen sich im Zug befindet und als Text-Variable cargo haben--> <foreach table="carlist" condition="@%callerid% = %operatorid%|@%oid% = cargo|#%oid% = #%callerid%"> <!-- Wagenposition in Variable vom Wagen schreiben --> <vr id="%oid%" value="#%lcid%"/> <!-- Text in Variable vom Wagen löschen, um Doppelzählung zu vermeiden --> <vr id="%oid%" text=""/> <!-- Variable Zug um EINS reduzieren --> <vr id="Pos_%callerid%" value="#Pos_%callerid% - 1"/> <!-- Variable Zaehler um EINS erhöhen --> <vr id="%lcid%" value="#%lcid% + 1"/> <!-- Variable Block reduzieren --> <vr id="%callerid%" value="#%callerid% - 1"/> </foreach> </while> <!-- script verlassen --> <vr id="%lcid%" value="0"/> <exit/> </then> </if>
Wenn der Variablen-Text im Hilfszähler „minus“ enthält ist der letzte Wagon im Block der erste Wagon im Zug und es muß „rückwärts gerechnet werden. Das bedeutet die Schleife wird jetzt ebenfalls so oft durchlaufen, wie der Hilfszähler größer NULL ist. Allerdings wird in der Wagonliste zusätzlich auf die Variable Wagon = Variable Block #%oid% = #%callerid%
geprüft. Also wird bei jedem Durchlauf der Schleife nur der Wagon mit der höchsten Positionsnummer genommen. Innerhalb der Schleife von der Wagonliste wird dann in die Variable des Wagons der Wert von der Variablen der Lok geschrieben <vr id="%oid%" value="#%lcid%"/>
und um Doppelzählungen zu vermeiden der Text in der Variablen des Wagons gelöscht <vr id="%oid%" text=""/>
. Die Variable des Hilfszähler wird um EINS reduziert <vr id="Pos_%callerid%" value="#Pos_%callerid% - 1"/>
, die Variable der Lok um EINS erhöht <vr id="%lcid%" value="#%lcid% + 1"/>
und die Variable des Blocks ebenfalls um EINS reduziert <vr id="%callerid%" value="#%callerid% - 1"/>
.
Damit das Script jetzt noch vollständig wird und alle 4 Kombinationsmöglichkeiten abgedeckt sind, muß das Ganze noch für die Lok-Einfahrtseite „-“ nach dem selben Prinzip eingefügt werden.
<!-- Wenn Einfahrtseite der Lok minus ist --> <if state="lc %lcid% = -"> <then> <!-- Variablen von Block und Zug setzen --> <vr id="%callerid%" text="%operatorid%"/> <vr id="Pos_%callerid%" value="0"/> <!-- Anzahl Wagen im Zug ermitteln --> <foreach table="carlist" condition="@%callerid% = %operatorid%"> <vr id="%oid%" text="cargo"/> <vr id="Pos_%callerid%" value="#Pos_%callerid% + 1"/> </foreach> <vr id="@%callerid%" value="#Pos_%callerid%"/> <!-- Zaehlweise vorwaerts (Einfahrtseite Wagen, gleiche Einfahrtseite Lok) --> <if condition="@Pos_%callerid% = minus"> <then> <!-- Wagenliste prüfen, solange Wagen im Zug --> <while condition="#Pos_%callerid% > 0" max="10"> <!-- DANN, Prüfen welcher Wagen sich im Zug befindet und als Text-Variable cargo haben--> <foreach table="carlist" condition="@%callerid% = %operatorid%|@%oid% = cargo"> <!-- Text in Variable vom Wagen löschen, um Doppelzählung zu vermeiden --> <vr id="%oid%" text=""/> <!-- Variable Zug um EINS reduzieren --> <vr id="Pos_%callerid%" value="#Pos_%callerid% - 1"/> <!-- Variable Block reduzieren --> <vr id="%callerid%" value="#%callerid% - 1"/> </foreach> </while> <!-- script verlassen --> <vr id="%lcid%" value="0"/> <exit/> </then> </if> <!-- Zaehlweise rueckwaerts (Einfahrtseite Wagen, entgegengesetzte Einfahrtseite Lok) --> <if condition="@Pos_%callerid% = plus"> <then> <!-- Wagenliste prüfen, solange Wagen im Zug --> <while condition="#Pos_%callerid% > 0" max="10"> <!-- DANN, Prüfen welcher Wagen sich im Zug befindet und als Text-Variable cargo haben--> <foreach table="carlist" condition="@%callerid% = %operatorid%|@%oid% = cargo|#%oid% = #%callerid%"> <!-- Wagenposition in Variable vom Wagen schreiben --> <vr id="%oid%" value="#%lcid%"/> <!-- Text in Variable vom Wagen löschen, um Doppelzählung zu vermeiden --> <vr id="%oid%" text=""/> <!-- Variable Zug um EINS reduzieren --> <vr id="Pos_%callerid%" value="#Pos_%callerid% - 1"/> <!-- Variable Zaehler um EINS erhöhen --> <vr id="%lcid%" value="#%lcid% + 1"/> <!-- Variable Block reduzieren --> <vr id="%callerid%" value="#%callerid% - 1"/> </foreach> </while> <!-- script verlassen --> <vr id="%lcid%" value="0"/> <exit/> </then> </if> </then> </if>
Was wurde jetzt erreicht ?
Beim Verlassen des Blocks werden die Positionen der Wagons aus dem Block in der richtigen Reihenfolge auf den Zug übertragen.
Mit weiteren Scripten kann man jetzt Rangierabläufe erstellen, die beim Block-Status „occupied“ ausgeführt werden. So kann man Script gesteuert Wagons aus einem Zug lösen oder hinzufügen, ihnen ein Ziel geben, nach Untergruppen auf Abstellgleise bewegen und vieles mehr. Unabhängig davon funktionieren die beiden Scripte aber auch, wenn man manuell (also über das Menü von Rocrail) Wagons bewegen will. Man muß dann nur die Wagons vor dem Verlassen eines Blocks entsprechend dem Zug hinzufügen oder herauslösen.