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
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.
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.
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
#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
}
}
Der Aufbau bleibt der gleiche nur die Abfragen werden ein wenig komplizierter:
#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
Diese Webseite wurde mit Jimdo Creator erstellt! Jetzt kostenlos registrieren auf https://de.jimdo.com