Einen guten Tag zusammen,
beim Werkeln und Scripten an meinem Nuntius-Drucker bin ich auf die Idee gekommen, dort auch eine Anzeige zu implementieren, die mir auf dem Bildschirm anzeigt, in wie vielen Metern die nächste Haltestelle kommt.
Man kennt das ja heutzutage vom ein oder anderen, modernen Drucker, wenn die mit GPS ausgestattet sind, dass sie anzeigen, wie weit die nächste Haltestelle noch entfernt ist.
Leider hat OMSI kein direktes Makro oder Variable, mit der es möglich ist, die Entfernung zur nächsten oder zwischen Haltestellen direkt abzufragen und anzuzeigen.
Dennoch dürfte es mit einigen Tricks und etwas Gerechne möglich sein, diese zumindest angenähert zu bestimmen.
Dieses Konzept möchte ich euch hier gerne kurz vorstellen. Ganz unten findet ihr dafür auch ein fertiges Script, was ihr gerne in euren Bussen und für eure Projekte verwenden dürft. Ich erhebe kein Copyright darauf. Feel free to do what you want.
Die Theorie
Für alle, die nicht einfach nur das fertige Script (ihr findet es unten) kopieren wollen, sondern auch tatsächlich verstehen wollen, warum und wie es funktioniert, hier die Erklärung, wie ich es mir überlegt habe und was der "Plot" ist:
Es ist zuerst wichtig, die folgenden Informationen bzw. Konzepte notwendig zu kennen/verstehen.
Wichtig ist noch, dass wir immer nur von einer Haltestelle zur nächsten denken. D.h. wir gehen immer davon aus, wir befinden uns gerade irgendwo zwischen zwei Haltestellen einer Route und wollen die Entfernung zur nächsten bestimmen.
- Mit den Makros (M.V.GetTTBusstopDep) und (M.V.GetTTBusstopArr) lassen sich die planmäßige Abfahrtszeit der letzten Haltestelle bzw. Ankunft an der nächsten abfragen.
- Über (M.V.GetTTDelay) lassen sich aus den planmäßigen Zeiten die tatsächlichen (bzw. prognostizierten für die nächste Haltestelle) errechnen.
- Vergleicht man diese nun mit der aktuellen Ingame-Uhrzeit ((L.S.Time)), kann man daraus einen relativen Wert bestimmen, wieviel Zeit bereits seit der letzten Haltestelle vergangen ist, bzw. wo auf der "Zeitachse" wir uns gerade zwischen Zeit Haltestellen befinden. Dazu ein Beispiel:
Tatsächliche Abfahrt an der letzten
Haltestelle (inkl. Verspätung): 12:00:00 Uhr
----------------------------------------------------------
Voraussichtliche Ankunft an der
nächsten Haltestelle
(Fahrplanzeit + derzeitige Verspätung): 12:01:00 Uhr
----------------------------------------------------------
Aktuelle Uhrzeit: 12:00:15 Uhr
----------------------------------------------------------
"An nächste Haltestelle - "Ab letzte Haltestelle" = 60 Sek.
"Aktuelle Uhrzeit" - "Ab letzte Haltestelle" = 15 Sek.
15 Sek. / 60 Sek. = 0.25
====
Alles anzeigen
Das bedeutet jetzt also, dass ein Viertel der Zeit zwischen beiden Haltestellen verstrichen ist. Wenn wir nun von einer konstanten Geschwindigkeit ausgehen, bedeutet das, dass auch ein Viertel der Strecke bereits zurückgelegt wurde und dementsprechend noch 3/4=0.75 fehlen.
Wenn wir jetzt auch noch von einem konstanten Haltestellenabstand insgesamt ausgehen würden, könnten wir die übrige Entfernung bereits exakt berechnen. Gerade auf Überlandmaps, wo innerhalb von Ortschaften Haltestellen eng zusammenliegen können, zwischen Orten aber auch große Entfernungen haben, ist das jedoch etwas doof. Deshalb wollen wir das nun ändern. Dazu brauchen wir nur die Variablen kmcounter_km und kmcounter_m, welche zusammen den Kilometerstand repräsentieren.
- Beim Verlassen einer Haltestelle merken wir uns den aktuellen Kilometerstand in einer Variable.
- Nun können wir jederzeit den aktuellen Kilometerstand mit dem gespeicherten vergleichen und so die zurückgelegte Strecke seit der letzten Haltestelle ermitteln.
- Aus all diesen Daten lässt sich nun bereits eine Prognose erstellen. Wir haben nun unsere zurückgelegte Strecke auf z.B. 100m bestimmt.
- Wenn wir weiterhin von einer konstanten Fahrtgeschwindigkeit ausgehen, so ergibt sich:
25% Zeit vergangen => 100m gefahren.
100m / 25% = 400m => gesamte Entfernung zwischen den Haltestellen
Bereits zurückgelegte Entfernung wieder subtrahieren:
400m - 100m = 300m
====
Damit haben wir nun also die Entfernung zu nächsten Haltestelle auf 300m bestimmt.
Wie bereits zum Anfang betont, ist das kein exakter Wert sondern nur eine Annäherung, da wir immer von einer konstanten Geschwindigkeit ausgehen müssen. Besser geht es leider nicht. Es ist und bleibt also immer eine "Prognose".
Der Wert wird jedoch genauer, je weiter wir fortgeschritten sind. Nach 10% Strecke haben wir nur eine sehr kleine Stichprobe an bestehenden Daten und die 90% übrige Strecke werden aus dieser Stichprobe nur "hochgerechnet". Das ist natürlich nicht so genau, wie wenn schon 90% gefahren wurden und nur noch 10% errechnet werden müssen.
Die Berechnung wird genauer, je dichter man die Zielhaltestelle erreicht.
Damit das ganze aktuell bleibt, muss man natürlich diese ganze Berechnung regelmäßig (z.B. alle 10 Sekunden) neu durchführen.
Wichtig ist, dass man nicht nur die Entfernungsberechnung ("2. Teil vom Beispiel") neu berechnet, sondern tatsächlich alles, da sich ja z.B. beim schnellen oder langsamen Fahren auch die Verspätung ändern kann, die man dann immer wieder neu einrechnen und daher auch die Haltestellenzeiten immer wieder neu berechnen sollte, um möglichst genaue Werte zu erhalten.
...und in OMSI
Hier findet ihr nun meine Implementierung der Idee in OMSI. Es sind Kommentare vorhanden, die das meiste klären sollten. Baut euch den "Scriptschnippsel" gerne in eure Busse ein.
Als erstes müsst ihr euch allerdings noch die folgenden Variblen in einer Varlist eintragen:
busstopDistance_timer
busstopDistance_lastKmCounter_km
busstopDistance_lastKmCounter_m
busstopDistance_nextBusstopDistance
busstopDistance_lastIndex
Dies ist dann der Codeabschnitt für die Script-Datei.
Den Bereich im Frame-Abschnitt solltet ihr euch am besten einfach in euren Bus- bzw. Drucker-Frame mit integrieren. Das Makro busstopDistance_recalculateDistance kann bzw. sollte also in jedem Frame ausgeführt werden.
Das Makro busstopDistance_restartDistanceCalc muss immer dann ausgeführt werden, wenn die Abstandsmessung neu begonnen soll, d.h. wir z.B: eine Haltestelle erreicht haben und nun von dort den Abstand zur darauf folgenden bestimmen wollen. Darum kümmert sich der Frame-Abschnitt hier.
Am Ende steht in der Variable busstopDistance_nextBusstopDistance immer die Entfernung zur nächsten Haltestelle in Metern bzw. "-1" falls der Wert nicht ermittelt werden kann. Diesen könnt ihr nun mit einem Textfeld verbinden oder z.B. auf eine Texttextur schreiben.
'Frame-Abschnitt (am besten in euer Frame-Makro mit einfügen)
{frame}
'Wenn ein Fahrplan aktiv ist und die nächste Haltestelle sich von der im letzten Frame unterscheidet...
(L.L.schedule_active)
(M.V.GetTTBusstopIndex) (L.L.busstopDistance_lastIndex) = ! &&
{if}
'...wollen wir die Messung für die nächste Haltestelle neu starten
(M.L.busstopDistance_restartDistanceCalc)
{endif}
'In jedem Frame lassen wir die Distanz aber ggf. neu berechnen
(M.L.busstopDistance_recalculateDistance)
'Und wir merken uns den neuen Haltestellenindex.
(M.V.GetTTBusstopIndex) (S.L.busstopDistance_lastIndex)
{end}
'Zurücksetzen der Messung (notwendig, wenn eine Haltestelle erreicht wurde und nun die Messung zur darauffolgenden Haltestelle starten soll
{macro:busstopDistance_restartDistanceCalc}
(L.L.kmcounter_km) (S.L.busstopDistance_lastKmCounter_km)
(L.L.kmcounter_m) (S.L.busstopDistance_lastKmCounter_m)
5 (S.L.busstopDistance_timer)
(M.L.busstopDistance_recalculateDistance)
{end}
'Berechnet die Entfernung zur nächsten Haltestelle
{macro:busstopDistance_recalculateDistance}
'Timer aktualisieren
(L.L.busstopDistance_timer) (L.S.Timegap) + s0 1 % (S.L.busstopDistance_timer)
'Wenn Timer < 1 (d.h. jede Sekunde) neu ausführen (= Entfernung neu berechnen)
l0 1 >=
{if}
'Wenn wir uns noch vor der ersten Haltestelle befinden oder garkein Fahrplan aktiv ist, ist leider keine sinnvolle Berechnung möglich (d.h. Wert auf "-1" für "undefiniert" setzen)
(M.V.GetTTBusstopIndex) s0 0 = (L.L.schedule_active) ! ||
{if}
-1 (S.L.busstopDistance_nextBusstopDistance)
{else}
'Register-Verwendung:
'0 = Aktueller Haltestellenindex
'1 = Aktuelle Verspätung (in Sekunden)
'2 = Tatsächliche Abfahrtszeit an der letzten Haltestelle (eigentlich nicht die tatsächliche, sondern die basierend auf der aktuellen Verspätung)
'3 = Tatsächliche (prognostizierte) Ankunftszeit an der nächsten Haltestelle
'4 = Zeitdifferenz zwischen der letzten und der nächsten Haltestelle (in Sekunden)
'5 = Verstrichene Zeit seit Verlassen der letzten Haltestelle (basierend auf der aktuellen Verspätung)
'6 = Prozent (0...1), wo wir uns zeitlich zwischen der letzten und der nächsten Haltestelle befinden
'Verspätung abrufen
(M.V.GetTTDelay) s1
'Tatsächliche Abfahrtszeit an der letzten Haltestelle und Ankunftszeit an der aktuellen berechnen (Fahrplanzeit + Verspätung)
l0 1 - (M.V.GetTTBusstopDep) l1 + s2
l0 (M.V.GetTTBusstopArr) l1 + s3
'Differenzen berechnen
l3 l2 - s4
(L.S.Time) l2 - s5
'Relativen Wert bestimmen, wo wir uns auf dem "Zeitstrahl" befinden
l5 l4 / s6
'Nur berechnen, wenn die Stichprobe groß genug ist.
'Das bedeutet, dass das Script erst ab einer bestimmten relativen, zurückgelegten Distanz überhaupt anfängt, die Entfernungen tatsächlich zu berechnen, da bei kleineren Stichproben die Werte viel zu ungenau sind.
'Ich habe hier mit dem Wert 0.5 (also ab Hälfte der Strecke) gute Erfahrungen gemacht:
0.5 >=
{if}
'Register-Verwendung (ab hier Änderungen):
'2 = Gesamter Abstand in Metern von der letzten Haltestelle zur aktuellen Position
'7 = Berechnete Gesamtdistanz zwischen der letzten und der nächsten Haltestelle
'Differenzen der Entfernungen berechnen
(L.L.kmcounter_km) (L.L.busstopDistance_lastKmCounter_km) - 1000 *
(L.L.kmcounter_m) (L.L.busstopDistance_lastKmCounter_m) -
'...und zu einem Wert zusammenfassen
+ s2
'Gesamtdistanz zwischen den Haltestellen berechnen
l2 l6 / s7
'...und den bereits zurückgelegten Wert davon abziehen
l7 l2 - (S.L.busstopDistance_nextBusstopDistance)
{else}
-1 (S.L.busstopDistance_nextBusstopDistance)
{endif}
{endif}
{endif}
{end}
Alles anzeigen
Das war's soweit. Viel Freude damit.
Wenn ihr weitere Fragen oder Anmerkungen habt, könnt ihr sie im Folgenden gerne posten.