Zum Inhalt springen
RailFX Modellbahn, Modellbau Arduino Bahnübergang mit Schranke und Andreaskreuz

RailFX – Bahnübergang mit Arduino

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

Schaltplan: Bahnübergang mit Arduino

RailFX Modellbahn, Modellbau Arduino Bahnübergang mit Schranke und Andreaskreuz Schaltplan Circuit

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.


Sieh dir jetzt meinen neuen Arduino-Videokurs an: Jetzt ansehen!


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


0 0 votes
Article Rating
Abonnieren
Benachrichtige mich bei

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden.

20 Comments
Newest
Oldest Most Voted
Inline Feedbacks
Alle Kommentare anzeigen
Hans-Georg
2 Jahre zuvor

Betr.: RailFX „Bahnübergang“
Hallo Stefan,
ich habe festverbaute Servos, die Richtung des Servo-Lenkhebels müsste umgekehrt verlaufen, damit beim Blinken die Schranke schließt und umgekehrt. An welcher Stelle kann ich im Code etwas ändern, um diese Umkehr zu erreichen? Danke im Voraus für eine Antwort.
Gruß
Hans-Georg

Mirco Scheurich
2 Jahre zuvor

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.

Patrick
2 Jahre zuvor

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

sven
3 Jahre zuvor

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

Sven
Antworte an  Stefan Hermann
3 Jahre zuvor

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

Sven
Antworte an  Sven
3 Jahre zuvor

Was für Servos setzt ihr denn so ein für ? langsame Bewegungen

Geyer
3 Jahre zuvor

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

Uwe Weber
4 Jahre zuvor

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

Uwe Weber
Antworte an  Stefan Hermann
4 Jahre zuvor

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

heiko
Antworte an  Uwe Weber
8 Monate zuvor

Hallo Uwe,
das Problem hatte ich auch. Ich habe das so geändert.
alt case 4: // Schranke öffnen
if (myTimer + schrankeTimeouts[2] < millis()) { // wenn Zeit abgelaufen
myTimer = millis(); // Timer resetten
myState = 5; // gehe zum nächsten Zustand

zu case 4: // Schranke öffnen
andreaskreuzAn(); // Andreaskreuz blinken
if (myTimer + schrankeTimeouts[2] < millis()) { // wenn Zeit abgelaufen
myTimer = millis(); // Timer resetten
myState = 5; // gehe zum nächsten Zustand
}
seid dem geht das Blinken in der Wartezeit nicht mehr aus.
Ansonsten habe ich schon 5 der Module nachgebaut und ich finde es einfach nur super.
Gruß Heiko

Günter Müller
4 Jahre zuvor

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 ?

Markus Schulz
Antworte an  Günter Müller
4 Jahre zuvor

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

Berthold Spitzhüttl
Antworte an  Günter Müller
3 Jahre zuvor

Hallo Gunter Müller
Du mußt im Sketch den Wert höher einstellen dann wird sie langsammer.
Gruß Berthold Spitzhüttl

André Seißler
4 Jahre zuvor

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é

20
0
Ich würde mich über deine Meinung freuen.x