Dieses Modul des RailFX-Systems steuert einen Bahnübergang 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
- 1x Arduino Nano*
- 1x Breadboard und Kabel*
- 2x TCRT5000 Lichtschranken*
- 2x Servo-Motoren* (Kann Sinn machen, bessere Servos zu kaufen, weil die ja relativ häufig auslösen müssen.)
- 3x 220 Ohm Widerstände
- LEDs*
Schaltplan

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 = 15; // 5 = schnell, 10 = mittel, 15 = langsam
Beim Upload muss man darauf achten, dass das richtige Board im Arduino-Menü ausgewählt ist. Dazu muss ebenfalls im Werkzeugemenü 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 das RailFX-Siedlung-Modul
#include <Servo.h>
/*
Rail-FX Bahnübergang
StartHardware.org
*/
/* ***** ***** 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[4] = {1000, 2000, 2000, 1000}; // Schrankenzustände {Blinken, Schließen, Öffnen, Blinken}
int schrankenGeschwindigkeit = 15; // 5 = schnell, 10 = mittel, 15 = 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 andreaskreuzBlinkPin = 5; // 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
/* 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 = 0;
long myTimer = 0;
#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
/* Servo Variablen */
myServo1.attach(schrankenServoPin1);
myServo2.attach(schrankenServoPin2);
pinMode(andreaskreuzBlinkPin, OUTPUT);
pinMode(sensorPin1, INPUT);
pinMode(sensorPin2, INPUT);
myServoPosition[0]=servo1Max;
myServoPosition[1]=servo2Max;
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 == 4) || (myState == 5)) myState = 2;
} else {
if (myState == 3) {
myState = 4;
myTimer = millis(); // Timer resetten
}
}
Serial.println(myState);
switch (myState) {
case 0: // idle
andreaskreuzAus();
break;
case 1: // blinken
andreaskreuzAn(); // Andreaskreuz linken
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 linken
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 linken
break;
case 4: // Schranke öffnen
andreaskreuzAn(); // Andreaskreuz linken
schrankenOeffnen();
if (myTimer + schrankeTimeouts[2] < millis()) { // wenn Zeit abgelaufen
myTimer = millis(); // Timer resetten
myState = 5; // gehe zum nächsten Zustand
}
break;
case 5: // blinken
andreaskreuzAn(); // Andreaskreuz linken
if (myTimer + schrankeTimeouts[3] < millis()) { // wenn Zeit abgelaufen
myTimer = millis(); // Timer resetten
myState = 0; // gehe zum nächsten Zustand
}
break;
}
delay(schrankenGeschwindigkeit);
}
void andreaskreuzAn() {
if (millis() % andreaskreuzBlinkgeschwindigkeit * 2 < andreaskreuzBlinkgeschwindigkeit) {
digitalWrite(andreaskreuzBlinkPin, LOW);
} else {
digitalWrite(andreaskreuzBlinkPin, HIGH);
}
}
void andreaskreuzAus() {
digitalWrite(andreaskreuzBlinkPin, HIGH);
}
void schrankenSchliessen() {
if (myServoPosition[0]>servo1Min) myServoPosition[0]--;
myServo1.write(myServoPosition[0]);
if (myServoPosition[1]>servo2Min) myServoPosition[1]--;
myServo2.write(myServoPosition[1]);
}
void schrankenOeffnen() {
if (myServoPosition[0]<servo1Max) myServoPosition[0]++;
myServo1.write(myServoPosition[0]);
if (myServoPosition[1]<servo2Max) myServoPosition[1]++;
myServo2.write(myServoPosition[1]);
}
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
}
RailFX-Module
Zurzeit gibt es folgende Projekt-Module:
Wenn dir das Projekt gefallen hat und du von weiteren interessanten Projekten inspiriert werden willst, sieh dir doch mal mein neues E-Book an!
Darin findest du die beliebtesten Arduino-Projekte von StartHardware. Jedes Projekt umfasst Schaltplan, Bauteile, Beschreibung und Code. Für Einsteiger gibt es ein Arduino-Schnellstart-Kapitel und einen kompakten Programmierkurs. Zusätzlich findest du Zwischenkapitel mit Expertenwissen zu den Komponenten, die verwendet werden. Alle Code-Beispiele gibt es natürlich als Download.
Weitere Informationen findest du auf der Produktseite. Klicke jetzt auf den Button, um Details anzusehen.
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
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é