#10 Geschwindigkeitsmesser

Modellbahngeschwindigkeit mit einem Arduino Messen

                                 - Egal ob Spur N, H0 oder sonst eine Spurweite.



Ich habe schon viele Modellbahn-Züge gesehen, die viel zu schnell unterwegs waren. 

Mein Zeil war es schon früh in meiner Modellbahn-Kariere, meine Züge möglichst Maßstabsgetreu in "original"-Geschwindigkeit fahren zu lassen.

Langsame Züge lassen sich viel besser beobachten

Aber wie soll man denn die tatsächliche Geschwindigkeit eines Modellzuges ermitteln.

Eine Modellbahnsteuerungssoftware wie iTrain bietet die Möglichkeit eine Lok einzulesen. Aber nicht jeder möchte mehrere Hundert € für eine solche Software investieren.

Aber 10€ sin ein überschaubares Investment

Alles was du brauchst ist:

- ein Arduino (geht eigentlich mit jedem, ich nutz ein Arduino Nano)

- ein 4-Stelliges 7-Segment Display mit Punkten

- 2 Infrarot Lichtschranken

und ein paar Kabel aus der Bastelkiste

Achte beim Kauf deines Display darauf, dass du eins mit Punkten und nicht eins mit einem Doppelpunkt kaufst.

Wir möchten nämlich später die Geschwindigkeit mit Nachkommastellen anzeigen können.


Hier erkläre ich euch in einem Video das Funktionsprinzip, den Aufbau und den Sketch.


Funktionsprinzip


Die beiden Lichtschranken messen, wie lange die Lok für einen festgelegten Abstand benötig. 

Der Arduino berechnet dann über eine Formal die Geschwindigkeit. 

Im Maßstab umgerechnet, zeigt das Display dir das Ergebnis an.


Aufbau


Der Aufbau ist denkbar einfach:

5V an das Display und die beiden Sensoren.

DO der Sensoren auf Pin 7 & 8

CLK des Display an Pin 2 und DIO des Display an Pin 3


Programm


#include <TM1637TinyDisplay.h>

 

// ------Einstellungen-------

const float DISTANZ_CM = 100.0;   // Abstand der Lichtschranken

const int MASSSTAB = 160;         // Spur N = 1:160

 

// Pins

const int LS1_PIN = 7;

const int LS2_PIN = 8;

const int TM_CLK = 2;

const int TM_DIO = 3;

 

// Anzeige

TM1637TinyDisplay display(TM_CLK, TM_DIO);

 

// --------Variablen---------

unsigned long startTime = 0;

unsigned long stopTime  = 0;

bool messungAktiv = false;

 

void setup() {

  pinMode(LS1_PIN, INPUT_PULLUP);

  pinMode(LS2_PIN, INPUT_PULLUP);

  display.setBrightness(5);   // 0–7

  display.begin();

}

void loop() {

  bool ls1 = (digitalRead(LS1_PIN) == LOW);

  bool ls2 = (digitalRead(LS2_PIN) == LOW);

 

  // ----Start der Messung-----

  if (!messungAktiv && ls1) {

    startTime = millis();

    messungAktiv = true;

    display.showString("run");   // <<< TEXT AUSGABE

    delay(50);                   // Entprellen

  }

 

  // -----Ende der Messung-----

  if (messungAktiv && ls2) {

    stopTime = millis();

    float delta_s = (stopTime - startTime) / 1000.0;  // ms → s

 

    // --Errechnung der Geschwindigkeit--

    if (delta_s > 0.01) {  // Sicherheit: keine Nullteilung

      float speed_cm_s     = DISTANZ_CM / delta_s;

      float speed_kmh_real = speed_cm_s * 0.036;

      float speed_kmh_mod  = speed_kmh_real * float(MASSSTAB);

 

      // --Geschwindigkeit anzeigen--

      if (speed_kmh_mod < 100.0) {

        display.showNumber(speed_kmh_mod, 2, 4, 0); // <100 → 2 Nachkommastellen

      } else {

        display.showNumber(speed_kmh_mod, 1, 4, 0); // >=100 → 1 Nachkommastelle

      }

    }

    messungAktiv = false;

    delay(500); // Sperrzeit bis zur nächsten Messung

  }

}


Messung in beide Richtungen


Der Aufbau bleibt der gleiche nur die Abfragen werden ein wenig komplizierter:

Programm


#include <TM1637TinyDisplay.h>

 

// ------ Einstellungen -------

const float DISTANZ_CM = 100.0;   // Abstand Lichtschranken

const int MASSSTAB = 160;         // Spur N

 

// Pins

const int LS1_PIN = 7;

const int LS2_PIN = 8;

const int TM_CLK = 2;

const int TM_DIO = 3;

 

// Anzeige

TM1637TinyDisplay display(TM_CLK, TM_DIO);

 

// -------- Variablen --------

unsigned long startTime = 0;

unsigned long stopTime  = 0;

unsigned long resetMillis = 0;

 

bool messungAktiv = false;

bool messungAktiv1zu2 = false;

bool messungAktiv2zu1 = false;

 

void setup() {

  pinMode(LS1_PIN, INPUT_PULLUP);

  pinMode(LS2_PIN, INPUT_PULLUP);

 

  display.begin();

  display.setBrightness(5);

}

 

void loop() {

 

  bool ls1 = (digitalRead(LS1_PIN) == LOW);

  bool ls2 = (digitalRead(LS2_PIN) == LOW);

 

  // ---------- Start Messung ----------

  if (!messungAktiv && ls1) {

    startTime = millis();

    messungAktiv = true;

    messungAktiv1zu2 = true;

    display.showString("run");

  }

 

  if (!messungAktiv && ls2) {

    startTime = millis();

    messungAktiv = true;

    messungAktiv2zu1 = true;

    display.showString("run");

  }

  // ---------- Ende Messung ----------

  if ((messungAktiv1zu2 && ls2) || (messungAktiv2zu1 && ls1)) {

    stopTime = millis();

    float delta_s = (stopTime - startTime) / 1000.0;

    if (delta_s > 0.01) {

      float speed_cm_s     = DISTANZ_CM / delta_s;

      float speed_kmh_real = speed_cm_s * 0.036;

      float speed_kmh_mod  = speed_kmh_real * MASSSTAB;

      if (speed_kmh_mod < 100.0) {

        display.showNumber(speed_kmh_mod, 2, 4, 0);

      } else {

        display.showNumber(speed_kmh_mod, 1, 4, 0);

      }

    }

    messungAktiv1zu2 = false;

    messungAktiv2zu1 = false;

    resetMillis = 0;   // Reset-Überwachung starten

  }

  // ---------- Freigabe nach kompletter Durchfahrt ----------

  if (messungAktiv && !messungAktiv1zu2 && !messungAktiv2zu1) {

    // beide Lichtschranken frei

    if (!ls1 && !ls2) {

      if (resetMillis == 0) {

        resetMillis = millis();

      }

      // 1 Sekunde dauerhaft frei

      if (millis() - resetMillis >= 1000) {

        messungAktiv = false;

        resetMillis = 0;

      }

    } else {

      // wieder belegt → Timer zurücksetzen

      resetMillis = 0;

    }

  }

}

 

Viel Spaß beim nachbauen