Dieses Modul des RailFX-Systems steuert einen Bahnübergang mit Arduino. Es bestehend aus zwei Schranken, zwei Andreaskreuzen und einer Beleuchtung für die Nacht. Ausgelöst wird die Schließung durch zwei TCRT5000 Lichtschranken.
Für die korrekte Funktionsweise der Beleuchtung muss dieses Modul mit dem RailFX-Control-Modul verbunden werden.
Bauteile
- 2x TCRT5000 Lichtschranken*
- 2x Servo-Motoren* (Es kann Sinn ergeben, bessere Servos zu kaufen, weil diese relativ häufig auslösen müssen.)
- 4x 220 Ohm Widerstände
- LEDs*
Schaltplan: Bahnübergang mit Arduino

Auch dieses Modul arbeitet mit einem Arduino Nano. Die rote LED im Schaltplan ist über einen 220 Ohm-Widerstand am digitalen Pin 5 am Arduino-Board angeschlossen. Man kann hier einfach mehr LEDs parallel zu der roten LED anschließen. Sie sollten sich aber zusammen in Reihe weithin einen Widerstand teilen. Am Pin 3 und 6 können LEDs als Straßenbeleuchtung angeschlossen werden, wobei die am Pin 6 per Zufall flackert.
Die Schrankenservos sind an den Pins 8 und 9 angeschlossen. Die Pins 2 und 4 sind mit den digitalen Pins (D0) zweier TCRT5000 Lichtschranken verbunden. Ihre Empfindlichkeit lässt sich durch die integrierten Potentiometer einstellen. Sobald eine der Lichtschranken auslöst, blinken die Andreaskreuze und nach einstellbarer Zeit schließen sich die Schranken. Sind beide Lichtschranken wieder offen, öffnet sich die Schranke und die Andreaskreuze hören auf zu blinken.
Achtung: Am Pin A4 ist wird das Control-Signal des RailFX Control-Moduls angelegt. Es steuert die Tageszeit und ist für die korrekte Funktionsweise der Straßenbeleuchtung erforderlich.
Einstellungen im Code
Im Code lassen folgende Einstellungen vornehmen:
- Einschaltzeit der Straßenlampen (ms)
- Flackern der Straßenlampe am Pin 6
- Blinkgeschwindigkeit der LEDs des Andreaskreuzes
- Minimum (geschlossen) und Maximum (geöffnet) der Servos
- Schaltdauer der Schrankenabläufe (Blinken, Schließen, Öffnen, Blinken)
- Geschwindigkeit der Schrankenbewegung
Im folgenden Teil des Programmes lassen sie die genannten Parameter anpassen:
int strassenlampenTimeout = 100; // Einschaltzeit der Straßenlampen (ms) int strassenlampeFlackern = 1000; // Je höher der Wert, desto langsamer flackert die LED an Pin 6 int andreaskreuzBlinkgeschwindigkeit = 1000; // Blinkgeschwindigkeit des Andreaskreuzes int servo1Min = 40; // Servo 1 Minimum (geschlossen) int servo2Min = 40; // Servo 2 Minimum (geschlossen) int servo1Max = 160; // Servo 1 Maximum (geöffnet) int servo2Max = 160; // Servo 2 Maximum (geöffnet) int schrankeTimeouts[4] = {1000, 2000, 2000, 1000}; // Schrankenzustände {Blinken, Schließen, Öffnen, Blinken} int schrankenGeschwindigkeit = 5; // 5 = schnell, 25 = mittel, 50 = langsam
Beim Upload muss man darauf achten, dass das richtige Board im Arduino-Menü ausgewählt ist. Dazu muss ebenfalls im Werkzeuge-Menü im Unterpunkt Prozessor »ATmega328P (Old Bootlaoder)« ausgewählt sein.
Der folgende Programmcode kann mit den oben erwähnten Änderungen einfach kopiert und auf das Arduino-Nano geladen werden.
Code für RailFX: Bahnübergang mit Arduino
#include <Servo.h> /* Rail-FX Bahnübergang StartHardware.org Permalink: https://starthardware.org/railfx-bahnuebergang/ */ /* ***** ***** Einstellungen ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** */ int strassenlampenTimeout = 100; // Einschaltzeit der Straßenlampen (ms) int strassenlampeFlackern = 1000; // Je höher der Wert, desto langsamer flackert die LED an Pin 6 int andreaskreuzBlinkgeschwindigkeit = 1000; // Blinkgeschwindigkeit des Andreaskreuzes int servo1Min = 40; // Servo 1 Minimum (geschlossen) int servo2Min = 40; // Servo 2 Minimum (geschlossen) int servo1Max = 160; // Servo 1 Maximum (geöffnet) int servo2Max = 160; // Servo 2 Maximum (geöffnet) int schrankeTimeouts[5] = {1000, 2000, 1000, 2000, 1000}; // Schrankenzustände {Blinken, Schließen, Warten vor Öffnung, Öffnen, Blinken} int schrankenGeschwindigkeit = 5; // 5 = schnell, 25 = mittel, 50 = langsam /* ***** ***** Ab hier beginnt der Programmcode, der nicht angepasst werden muss ***** ***** ***** ***** */ int strassenlampenPin1 = 3; // an diesem Pin sind Straßenlampen angeschlossen int strassenlampenPin2 = 6; // an diesem Pin ist eine flackernde Straßenlampe angeschlossen int andreaskreuzBlinkPin1 = 5; // an diesem Pin sind die LEDs des Andreaskreuzes angeschlossen int andreaskreuzBlinkPin2 = 7; // an diesem Pin sind die LEDs des Andreaskreuzes angeschlossen int schrankenServoPin1 = 8; // an diesem Pin ist ein Schrankenservo angeschlossen int schrankenServoPin2 = 9; // an diesem Pin ist ein Schrankenservo angeschlossen int sensorPin1 = 2; // an diesem Pin ist ein Abstandssensor angeschlossen int sensorPin2 = 4; // an diesem Pin ist ein Abstandssensor angeschlossen /* Speicher-Variablen */ int strassenlampenHelligkeit = 0; // speichert, wie hell die Straßenlampen leuchten int myState = 0; // speichert den aktuellen Zustand des Bahnüberganges: 0 = frei, 1 = blinken, 2 = Schranke schließen, 3=Schranke geschlossen, 4 = Schranke öffnen boolean durchfahrt = false; // speichert, ob gerade ein Zug durchfährt /* Timer Variablen */ long strassenlampenTimer = 0; // Timer der Straßenlampen long myTimer = 0; // Timer long servoTimer = 0; // Timer der Servos /* Servo Objekte */ Servo myServo1; // Servo Objekt 1 Servo myServo2; // Servo Objekt 2 int myServoPosition[2] = {80, 80}; // speichert die aktuellen Servo-Positionen /* Variablen vom Controlmodul um die Uhrzeit festzustellen*/ boolean receive = false; boolean receiveStarted = false; int receiveTimeout = 10; long receiveTimer = 0; int receivedTime = 0; int receivePulse = 0; int lastReceivePulse = 0; int receivePin = 18; int myTime = 23; #define PAYLOAD_SIZE 2 // nötig für die Kommunikation zum Master int uhrzeit = 0; // speichert die uhrzeit vom Master-Modul (0 und 255) byte nodePayload[PAYLOAD_SIZE]; // speichert die Daten vom Master-Modul zwischen void setup() { Serial.begin(115200); // started die serielle Kommunikation pinMode(receivePin, INPUT); // Empfangspin vom Control-Modul /* Servo Variablen */ myServo1.attach(schrankenServoPin1); myServo2.attach(schrankenServoPin2); myServo1.write(servo1Min); myServo2.write(servo2Min); myServoPosition[0] = servo1Min; myServoPosition[1] = servo2Min; delay(500); // Servos werden auf Ausgangsposition gefahren pinMode(andreaskreuzBlinkPin1, OUTPUT); pinMode(andreaskreuzBlinkPin2, OUTPUT); pinMode(sensorPin1, INPUT); pinMode(sensorPin2, INPUT); strassenlampenAus(); } void loop() { receiveFunction(); // Führe Anweisungen für Empfang aus if (receiveStarted == false) { // Falls gerade keine Daten empfangen werden: if (myTime > 22) { // ***** Später Abend ***** strassenlampenAn(); // Straßenlampen an } else if (myTime > 18) { // ***** Abend ***** strassenlampenAn(); // Straßenlampen an } else if (myTime > 12) { // ***** Nachmittag ***** strassenlampenAus(); // Straßenlampen aus } else if (myTime > 9) { // ***** Vormittag ***** strassenlampenAus(); // Straßenlampen aus } else if (myTime > 7) { // ***** Morgen ***** strassenlampenAn(); // Straßenlampen an } else { // ***** Nacht ***** strassenlampenAn(); // Straßenlampen an } if ((digitalRead(sensorPin1) == 0) || (digitalRead(sensorPin2) == 0)) { if (myState == 0) { myState = 1; myTimer = millis(); } else if ((myState == 5) || (myState == 6)) myState = 2; } else { if (myState == 3) { myState = 4; myTimer = millis(); // Timer resetten } } Serial.print("Sensor1: ");Serial.print(digitalRead(sensorPin1));Serial.print(" Sensor2: ");Serial.print(digitalRead(sensorPin2)); Serial.print(" myState: ");Serial.println(myState); switch (myState) { case 0: // idle andreaskreuzAus(); break; case 1: // blinken andreaskreuzAn(); // Andreaskreuz blinken if (myTimer + schrankeTimeouts[0] < millis()) { // wenn Zeit abgelaufen myTimer = millis(); // Timer resetten myState = 2; // gehe zum nächsten Zustand } break; case 2: // Schranke schließen andreaskreuzAn(); // Andreaskreuz blinken schrankenSchliessen(); if (myTimer + schrankeTimeouts[1] < millis()) { // wenn Zeit abgelaufen myTimer = millis(); // Timer resetten myState = 3; // gehe zum nächsten Zustand } break; case 3: // Schranke geschloseen andreaskreuzAn(); // Andreaskreuz blinken break; case 4: // Schranke öffnen if (myTimer + schrankeTimeouts[2] < millis()) { // wenn Zeit abgelaufen myTimer = millis(); // Timer resetten myState = 5; // gehe zum nächsten Zustand } break; case 5: // Schranke öffnen andreaskreuzAn(); // Andreaskreuz blinken schrankenOeffnen(); if (myTimer + schrankeTimeouts[3] < millis()) { // wenn Zeit abgelaufen myTimer = millis(); // Timer resetten myState = 6; // gehe zum nächsten Zustand } break; case 6: // blinken andreaskreuzAn(); // Andreaskreuz blinken if (myTimer + schrankeTimeouts[4] < millis()) { // wenn Zeit abgelaufen myTimer = millis(); // Timer resetten myState = 0; // gehe zum nächsten Zustand } break; } } } void andreaskreuzAn() { if (millis() % andreaskreuzBlinkgeschwindigkeit * 2 < andreaskreuzBlinkgeschwindigkeit) { digitalWrite(andreaskreuzBlinkPin1, LOW); digitalWrite(andreaskreuzBlinkPin2, HIGH); } else { digitalWrite(andreaskreuzBlinkPin1, HIGH); digitalWrite(andreaskreuzBlinkPin2, LOW); } } void andreaskreuzAus() { digitalWrite(andreaskreuzBlinkPin1, HIGH); digitalWrite(andreaskreuzBlinkPin2, HIGH); } void schrankenSchliessen() { if (servoTimer + schrankenGeschwindigkeit < millis()) { if (myServoPosition[0] > servo1Min) myServoPosition[0]--; myServo1.write(myServoPosition[0]); if (myServoPosition[1] > servo2Min) myServoPosition[1]--; myServo2.write(myServoPosition[1]); servoTimer = millis(); } } void schrankenOeffnen() { if (servoTimer + schrankenGeschwindigkeit < millis()) { if (myServoPosition[0] < servo1Max) myServoPosition[0]++; myServo1.write(myServoPosition[0]); if (myServoPosition[1] < servo2Max) myServoPosition[1]++; myServo2.write(myServoPosition[1]); servoTimer = millis(); } } void strassenlampenAn() { if (strassenlampenTimer + strassenlampenTimeout < millis()) { strassenlampenHelligkeit++; if (strassenlampenHelligkeit > 255) strassenlampenHelligkeit = 255; strassenlampenTimer = millis(); analogWrite(strassenlampenPin1, 255 - strassenlampenHelligkeit); } if (random(strassenlampeFlackern) == 1) analogWrite(strassenlampenPin2, random(255) - strassenlampenHelligkeit); } void strassenlampenAus() { strassenlampenHelligkeit = 0; analogWrite(strassenlampenPin1, 255); analogWrite(strassenlampenPin2, 255); strassenlampenTimer = millis(); } void receiveFunction() { // Empfängt die Uhrzeit vom Control-Modul receivePulse = digitalRead(receivePin); // Lies den Empfangspin aus if ((receiveTimer + receiveTimeout < millis()) && (receiveStarted == true)) { // Bei Timeout und aktivem Empfang receiveStarted = false; // beende aktiven Empfang myTime = receivedTime - 1; // speichere die empfangene Zeit receivedTime = 0; // setze die Hilfsvariable zum Zeitempfang zurück Serial.println(myTime); // serielle Ausgabe } // falls ein Puls am Empfangspin erfasst wird, der vorher nicht da war if ((receivePulse == 0) && (lastReceivePulse == 1)) { receiveTimer = millis(); // starte Timer neu if (receiveStarted == false) receiveStarted = true; // starte aktiven Empfang, wenn noch nicht geschehen receivedTime++; // es gab einen Puls, also erhöhe die Hilfsvariable zum Zeitempfang } lastReceivePulse = receivePulse; // aktuellen Zustand am Pin für nächsten Durchlauf merken }
Hier findest du weitere RailFX-Module
Wenn dir das Projekt gefallen hat und du von weiteren interessanten Projekten inspiriert werden willst, sieh dir doch mal mein neues E-Book »Arduino Projekte Volume 1« an!
- Die beliebtesten Arduino-Projekte von StartHardware
- Inklusive Schaltplan, Beschreibung und Code
- Arduino-Schnellstart-Kapitel
- Kompakter Programmierkurs
Ich habe probleme das control modul auf zu bauen .ich habe es genau so aufgebaut und den sketch geladen aber das display zeigt mir nichts an. es bleibt schwarz.
Hallo, bei mir tritt vorgehender Fehler auf. Die LED blinkt dauernd und geht wenn der Servo arbeitet auf an. Nach auslösen des 2 Sensors geht die Schranke hoch und LED blinkt wieder. Habe nur die Ausgänge an eine vorhandene Schaltung angepasst.
Danke schon mal für die Antworten
Hallo hat wer den Sketch schon mal so angepasst das man die Geschwindigheit ändern kann ? Wenn ich die Bibliothek (moba.h) auswechsel kommt immer eine Fehlermeldung. trotz installierter Libery
Schöne Grüsse Sven
Hi Sven, welche Geschwindigkeit willst du ändern? Wie sich die Schranken bewegen? Liebe Grüße Stefan
Hallo Stefan
Ja genau wie langsam sich die Schranken bewegen.
Ich habe die Servo.h durch die Moba.h ersetzt und vorab die MobaTools installiert. leider kommt dann einer Fehler “No such file or directory)
Hast Du da eine Servo Empfehlung damit die sauber laufen ? Meine zucken immer so
Schönen Gruss und Danke für Deine Geduld
Was für Servos setzt ihr denn so ein für ? langsame Bewegungen
Hallo Sefan,
habe ein Problem mit dem BÜ. Control funktioniert einwandfrei.
Bei BÜ ist bei mir immer der Sensor an D4 aktiv, LED leuchtet. Habe den Sensor schon ausgetauscht gegen einen anderen. Auch getauscht mit dem Sensor von D2. Sensor an D2 funktioniert einwandfrei.
Verdrahtung ist ok, habe ich mehrmals überprüft.
Hast Du eine Idee?
Gruss Mario
Hi Mario, schwer zu sagen. Kannst du mir ein paar Fotos von deiner Schaltung an hallo@starthardware.org schicken? Dann gucke ich es mir an. Liebe Grüße Stefan
Hallo zusammen,
ein tolles Projekt das viel Spaß macht, für mich als Arduino Neuling schon eine Herausforderung die Programmierung zu verstehen.
Deshalb eine Frage, die Schranke öffnet sich sofort nachdem die Lichtschranke nicht mehr bedeckt ist. Das ist nicht so glücklich, eine kurze Verzögerungszeit wäre hier hilfreich. Wenn zwischen den vorbeifahrenden Waggons eine Lücke ist gehen die Schranken kurz hoch und gleich wieder runter.
Hat dazu jemand eine Idee das zu implementieren?
Wie gesagt, ich als Neuling stehe da vor einer Herausforderung, beste Grüße Uwe
Hi Uwe,
danke für deine Anfrage. Ja, das ist tatsächlich ein Problem. Ich hab den Code verändert. Probier mal diese aktuelle Version. Es gibt nun einen fünften Zustand im schrankeTimeouts[5]-Array. Der dritte Eintrag ist für die Zeitverzögerung, bevor die Schranke wieder aufgeht. Und schick mir gerne Fotos von deiner Anlage, dann packe ich sie mit in den Beitrag :-)
Liebe Grüße
Stefan
Moin Stefan,
ich habe deinen geänderten Sketch ausprobiert, bei mir funktioniert es nur, wenn ich PWM Ausgänge (D5 und D6) für die Servos verwende. Die Zeitverzögerung klappt wunderbar, aufgefallen ist mir, dass, solange die Verzögerungszeit läuft, das Blinken des Andreaskreuzes eingefroren ist. Wenn du da noch eine Idee dazu hast, wäre super, ist aber eher eine Marginalie, damit kann ich leben. Ein Foto werde ich irgendwann mal beisteuern können, zur Zeit ist alles nur ein Versuchsaufbau!
Danke
Gruß Uwe
Hallo, super gemacht.
Ich habe die https://starthardware.org/bahnuebergang-schranke-und-andreaskreuz-mit…
im Einsatz, funktioniert eigentlich tadellos, aber die Schranke öffnet sich so schnell.
Im Sketch habe ich es auf 1 gestellt, aber immer noch zu schnell. Wie kann ich das Servo noch langsamer machen, hast Du einen Tipp ?
Hi Günter,
gucke ich mir am WE an. Da finden wir bestimmt eine Lösung :-)
Liebe Grüße
Stefan
Hi Günter,
ersetze die servo.h durch moba.h, dort kannst Du die Geschwindigkeit super drosseln.
https://www.arduinolibraries.info/libraries/moba-tools
Gruß
Markus
Hallo Gunter Müller
Du mußt im Sketch den Wert höher einstellen dann wird sie langsammer.
Gruß Berthold Spitzhüttl
Hallo Stefan
Die Schaltung von BÜ funktioniert super.
Ist es möglich eine zweite Rote Led zu integrieren mit mit der ersten
Im Wechsel blinkt??
Grüsse André
Hi André, ist integriert :-) Liebe Grüße Stefan