Signalstereuerung mit Arduino
In unserem Gleisbildstellpult Projekt hatten wir im ersten Schritt die Weichensteuerung via Start und Zieltaster realisiert. Den ausführlichen Bericht findest Ihr hier: Arduino Weichensteuerung
Da es auf der Modellbahn nicht nur Weichen sondern auch Signale geschaltet werden müssen haben wird die Realisierung einer Signalsteuerung mit Hilfe des Arduinos in Angriff genommen.
Wir haben zunächst an der grundsätzlichen Logik der Signalsteuerung gearbeitet und festgelegt unter welchen Bedingungen kann das Signal auf Fahrt frei (Hp1) oder Halt (Hp0) geschaltet werden. Die hier vorgestellte Programmierung berücksichtigt aktuelle keine Langsamfahrt (Hp2), was aber durch entsprechende Anpassung des Arduino Sketches auch möglich wäre.
Damit die Signalsteuerung funktioniert, war es auch nötig den Arduino UNO von meiner Gleisbesetztmeldung mit dem Arduino MEGA vom Gleisbildstellpult mittels I2C Bus zu verbinden. Zu diesem Thema wird es einen extra Bericht geben
Grundsätzliche Funktionsweise im Flowchart
Die grundsätzliche Funktionsweise der Signalsteuerung ist im folgenden Flowchart erklärt:
Gehen wir mal davon aus das Signal S1 ist auf Halt gestellt und wir möchten es mit Hilfe des Signaltasters S1 auf Fahrt frei schalten. Wir starten oben links in der Ecke bei dem „S“ in dem Flowchart. Nun prüft das Programm ob der Taster S1 gedrückt wurde, was in unserem Beispiel zutrifft. Am nächsten Entscheidungspunkt werden folgende Punkte geprüft:
- Ist Weichen W1 für die Ausfahrt richtig gestellt
- Ist der zu befahrende Block B4 frei
- Steht das Signal auch auf Halt
Erst wenn diese Bedingungen alle erfüllt sind wird das Signal auf Fahrt frei geschaltet und auch die Entsprechende Anzeige im Stellpult geändert. Nun kann der Zug ausfahren…
Das Signal kann nun auf zwei arten wieder auf Halt zurückgestellt werden:
- Der vom Bahnhof ausfahrende Zug fährt in den nächsten Block B4 ein oder
- Durch wieder betätigen des Signaltasters S1
Nun schauen wir uns mal an wie das Ganze im Arduino Sketch programmiert wurde
Arduino Sketch
Als erstes werden die Pin´s für die Signaltaster und die Signal LED´s im Stellpult festgelegt.
const int Button_inSig1 = 27; const int Led_outSig1Red = 44; const int Led_outSig1Green = 45;
Für die korrekte Programmausführung benötigen wir noch folgende Variablen:
int Button_stSig1; int ButtonLast_stSig1 = HIGH; int Button_stReadingSig1; int SignalState_stSig1 = LOW; int State_stSig1 = LOW;
- In der Variable Button_stSig1 wird der Status des Signaltasters gespeichert
- In der Variable ButtonLast_stSig1 wird der vorhergehende Status des Signaltasters gespeichert
- Die Variable Button_stReadingSig1 wir benötigt um den aktuellen Status des Signals Tasters auszulesen
- Die Variable SignalState_stSig1 gibt die aktuelle Signalstellung wieder, wobei Low = Hp0 (Halt) und high=Hp1 (freie Fahrt)
- In der Variable State_stSig1 wird die Schaltanfrage für das Signal hinterlegt, wobei auch wieder hier Low = Hp0 (Halt) und high=Hp1 (freie Fahrt) bedeuten.
All diese Variablen habe ich auch für die anderen Signal auf der Anlage definiert und einfach nur fortlaufend hochgezählt (Button_stSig2, ButtonLast_stSig2…).
Da ich die Betätigung des Signaltaster noch Endprellt habe, müssen noch ein paar Timer definiert werden.
unsigned long Time_tiLastDebounceTime_Sig1 = 0; unsigned long Time_tiDebouncingSig = 50;
- In der Variable Time_tiLastDebounceTime_Sig1 wird die Zeit abgelegt, wann sich der Status vom Signaltaster geändert hat
- In der Variable Time_tiDebouncingSig=50 wird die nötige Endprellzeit von 50ms definiert
Durch das entprellen soll verhindert werde das durch flackern am Arduino Eingang für den Signaltaster fälschlicherweise eine Schaltung der Signale ausgelöst wird. Mit der aktuellen Programmierung muss der Taster mindestens 50ms gedrückt sein ansonsten wird keine Schaltung ausgelöst
Void setup:
Im Void setup hab ich noch die initialwerte für die Taster und LED festgelegt.
pinMode(Button_inSig1, INPUT_PULLUP); pinMode(Led_outSig1Red, OUTPUT); pinMode(Led_outSig1Green, OUTPUT); digitalWrite(Led_outSig1Red, HIGH); digitalWrite(Led_outSig1Green, LOW);
Void loop:
Im Void loop Teil des Sketches ist die Programmierung der eigentliche Signalsteuerung zu finden.
Button_stReadingSig1 = digitalRead (Button_inSig1); if (Button_stReadingSig1 != ButtonLast_stSig1) { Time_tiLastDebounceTime_Sig1 = millis(); } if (((millis() - Time_tiLastDebounceTime_Sig1) > Time_tiDebouncingSig)) { if (Button_stReadingSig1 != Button_stSig1) { Button_stSig1 = Button_stReadingSig1; if ((Button_stSig1 == LOW)&&(Led_stWeiche1Turn == 1)&&(Led_stTrack4==LOW)&&(SignalState_stSig1==LOW)) { State_stSig1 = !State_stSig1; } if ((Button_stSig1 == LOW)&&(SignalState_stSig1 ==HIGH)) { State_stSig1 = !State_stSig1; } } } if (((Led_stTrack4==HIGH))&&(SignalState_stSig1 ==HIGH)){ State_stSig1 = LOW; } if (State_stSig1 == LOW) { digitalWrite(Led_outSig1Red, HIGH); digitalWrite(Led_outSig1Green, LOW); SignalState_stSig1 =LOW; } if (State_stSig1 == HIGH) { digitalWrite(Led_outSig1Red, LOW); digitalWrite(Led_outSig1Green, HIGH); SignalState_stSig1 =HIGH; } ButtonLast_stSig1 = Button_stReadingSig1;
Fall 1: Signaltaster nicht gedrückt
Im ersten Schritt wird der Zustand des Signal Tasters abgefragt und in die Variable Button_stReadingSig1 geschrieben. Die darauffolgenden If Abfrage prüft nun, ob sich der Zustand vom Signaltaster geändert hat oder der nicht.
In unserem Beispiel ist er gleich geblieben, da der Taster nicht betätigt wurde. Aus diesem Grund wird die erste If Abfrage übersprungen und wir kommen zur nächsten If Abfrage, in der geprüft wird ob das Signal auf Fahrt frei gestellt ist und der nächste Gleisabschnitt belegt ist.
Da der Signalstatus SignalState_stSig1 mit Low initialisiert wird trifft dies Bedingung nicht zu und wir kommen zu nächsten Abfrage, die die eigentliche Schaltung der LED´s im Schaltpult und des Signals übernimmt.
Da das SignalState_stSig1=Low initialisiert wurde trifft diese Bedingung zu und die rot LED im Schaltpult wir angeschaltet und die Grüne ausgeschaltet und der SignalState_stSig1 auf Low gesetzt.
Als letzter Schritt wird der aktuelle Signaltasterstatus in die Variable ButtonLast_stSig1 geschrieben. Das ist nötig damit man bei nächsten durchlauf vom Sketch feststellen kann ob der Taster nun gedrückt wurde oder nicht.
Fall 2: Signaltaster gedrückt
Spielen wir nun mal den Fall durch, dass der Signaltaster für mehr als die 50ms Endprellzeit gedrückt wurde.
Also fangen wir wieder von vorne an…
In diesem Falle geht zunächst Button_stReadingSig1 auf High und die darauffolgende If Abfrage wäre jetzt erfüllt ,da sich der Status des Tasters gegenüber des vorhergehenden durchlauf des Sketches geändert hat. Nun wird die aktuelle Zeit von millis in Time_tiLastDebounceTime_Sig1 gespeichert.
Im der nächsten if Abfrage wird geprüft ob die Endprellzeit von 50ms abgelaufen ist. Diese Überprüfung erfolgt anhand der Differenzbildung zwischen der aktuellen Zeit millis und der abgespeicherten Zeit beim ersten betätigen des Signaltasters
Ist diese Bedingung erfüllt wird in einer weiteren If Abfrage gecheckt ob die Änderung am Taster Status immer noch vorhanden ist, also in unserem Falle der Taster immer noch gedrückt ist. Wenn das zutrifft, wird der Aktuelle Taster Status (Button_stReadingSig1) in die Variable Button_stSig1 geschrieben. Nun wird in einem weiteren Schritt geprüft ob das Signale überhaupt auf Hp1 also fahrt gestellt werden kann. Wie indem Flowchart beschrieben müssen dafür einige Bedingungen erfüllte sein:
- Signaltaster ist gedrückt
- Weichen W1 für die Ausfahrt richtig gestellt
- Ist der zu befahrende Block B4 frei
- Steht das Signal auch auf Hp0 (Halt)
Sind all diese Kriterien erfüllt wird die Variable State_stSig1 auf High gesetzt und diese If Anweisung wird verlassen.
Anschließend springen wir zu den If Abfragen, die die eigentlich Schaltung des Signals und der LED´s im Schaltpult übernehmen. Hier wird nun überwacht welchen Wert State_stSig1 hat, also ins unserem Falle High.
Somit wird die Rote LED über digitialWrite(Led_outSig1Red)=Low ausgeschaltet und die grüne LED über digitalWrite(Led_outSig1Green)=High eingeschaltet und die Variable SignalState_stSig1 ebenfalls auf high gesetzt.
Die Variable SignalState_stSig1 kann später dazu eingesetzt werden ein bestimmtes Signalbild zu schalten.
Fall 3: Signal zurückstellen
Wie bereits im Flowchart erklärt gibt es hier zwei Möglichkeiten.
- Das Signal wird durch erneutest betätigen des Signaltaster zurückgestellt oder
- Wenn der Gleisabschnitt nach dem Signal von der Lok befahren wird
Beginnen wir mit dem zweiten Möglichkeit und hierzu gibt es wieder eine If Abfrage die Prüft ob der Gleisabschnitt belegt ist, also LedstTrack4=High und die aktuelle Signalstellung HP1 also SignalState_stSig1=High ist.
Treffen diese Bedingungen zu, wird State_stSig1 von High auf Low gesetzt und entsprechend die LED´s im Stellpult und das Signalbild über die untere If- Abfrage geschaltet.
Kommen wir nun zur ersten Möglichkeit dem erneuten betätigen des Signaltasters:
Zunächst läuft wieder die Logik für die Endprellung des Tasters durch, wie bereit im Fall 2 beschriebe. Da die Aktuelle Signalstellung Hp1 (SignalState_stSig1=High) ist, wird die If Abfrage erfüllt die überwacht ob der Taster gedrückt wurde und die aktuelle Signalstellung Fahrt frei ist. Dies führt dazu, das State_stSig1 von High auf Low gesetzt wird und entsprechend die LED´s im Stellpult und das Signalbild über die untere If- Abfrage geschaltet werden.
Das komplette Arduino Sketch von meinem Stellpult mit Weichen, Andreaskreuz und der in diesem Bericht vorgestellten Signalsteuerung könnt ihr hier kostenlos herunterladen: > Download Arduino Signalsteuerung Sketch
Wie immer für euch das ganze auch in einem Video Dokumentiert
Hallo,
ich bin über YouTube zu euch gestolpert. Mir gefällt euer Tastenpult Layout sehr gut.
Würdet ihr die Datei dazu auch online stellen?
Das wäre wirklich schön.
Gruß kay
Hallo,
gibt es eine Möglichkeit mit der Technik auch ein Lichtsignal mit Grün, Rot und Gelb zu schalten ?
Viele Grüße
Moritz
Hallo Moritz,
Das ist ohne Probleme mögliche. Um die einzelnen LED´s im Lichtsignal anzusteuern werden die gleichen Befehle verwendet wie zur Ansteuerung der LED´s im Gleisbildstellpult.
Viele Grüße
Sebastian
Hallo Modellbahnfreunde,
erstmal Danke für die Anleitung zum Thema Weichensteuerung.
Ich verwende dafür ebenfalls einen Arduino Mega. Ich habe
das Sketch von Euch für meine Bedürfnisse anpassen und sogar noch etwas erweitern können. Alles funktioniert super.
Nun aber zu meinem Problem.
Die digitalen Anschlusskapazitäten meines Mega sind erschöpft.
Mir fehlt allerdings noch eine simple Signalsteuerung, bei der beim
Auswählen der jeweiligen Fahrstraße das Einfahrtssignal auf „grün“
gestellt wird.
Nun ist das Stichwort I2C. Ich habe mir Eure Sketche zum Thema
Signalsteuerung und Gleisbelegtmeldung angesehen, finde aber
keine Möglichkeit dass der Master (Mega 1) eine gewählte Fahrstraße an den Slave (Mega 2) sendet, der wiederum die Signalschaltung vornimmt.
Vielleicht könnt Ihr mir da etwas unter die Arme greifen.
Viele Grüße
Carsten
Hallo Carsten,
Schön zu hören das alles wie gewünscht bei Dir funktioniert und wir Dir mit unseren Beiträgen weiterhelfen konnten.
Ich hatte ein ähnliches Problem wie Du….
Hier hat mir das „Experiment 1“ der folgenden Homepage geholfen http://www.sachsendreier.com/asw/projekteundexperimente/i2c/i2c.php
Probiere das mal aus, wenn Du nicht weiter kommst, melde Dich nochmal bei uns dann kann ich Dir mein Sketch mal schicken.
LG
Sebastian
hallo,
kann man mit dem arduino auch das lichtsignal programmieren das es realistisch wirkt? also zb. rot geht langsam aus, dann ist 1sek. alles aus.. und grün geht langsam an? ich wüsste ne schaltung mit transistor und kondensatoren.. aber wenn eh schon die led auf der stelltafel umgestellt werden, und ich das 1zu1 aufs signal geben kann. warum dann keine realistische variante mit dem arudino..:)
Mit freundlichen Grüßen
m.halle