Digitale DCC-Modellbahnsteuerung mit Arduino

Einleitung

Beim Freiluftbahner kommt bald mal der Wunsch auf, seine Fahrzeuge per Funk anstatt mit ortsgebundenen/verkabelten Fahrtrafos zu bedienen. Verwendet man zudem Akkus, riskiert man keinen Stromschlag. Werden diese vom Freiland-Modellzug noch selber mitgeschleppt, gehören Betriebsunterbrüche wegen verschmutztem Gleis der Vergangenheit an. Der Markt bietet solche Fernsteuerungen schon lange an. Für meinen Geschmack allerdings mit etwas zu üppigem Funktionsumfang und bisher nicht im Akku-Fahrstrombetrieb. Darum habe ich für mein Projekt folgendes festgelegt:

  • DCC-Protokoll (Einschränkung auf 8-Bit DCC-Funktionsbefehle)
  • Nur HG 4/4 Dampflok mit Standard-DCC-Adresse 3 unterstützt
  • Lok-Funktionen: Fahrstufe, Vor- Rückwärts, Licht, Sound on/off und Lokpfiff
  • Lok-Geschwindigkeit: 28 Fahrstufen je Fahrtrichtung
  • Basisstation mit zweifarbiger Kontroll-LED für Betriebszustand
  • Basisstation Fahrstrom und Elektronik (uC): 24-Volt Akku 6s-LiPo mit 4200mAh
    (Unterhalb 22 Volt kein vernünftiger Betrieb mit Zahnstange und 12 Prozent Steigung möglich!)
  • Basisstation: Kurzschlusssichere 5 Ampere-H-Brücke (STMicrölectronics L6203)
  • Gleisstrom: Kurzschlusssicher → Kontinuierliche Strommessung und Abschaltung bei Überstrom
  • Funkhandregler mit drei roten LEDs für Betriebszustands (LCD-Displays sind bei starkem Sonnenlicht schlecht ablesbar!)
  • Funkhandregeler: 3.7V-LiPo-Akku (Aufladbar per USB-Kabel)
    Während Ladevorgang: Funkstille und abgeschaltete Anzeige
  • Funkverbindung: ISM-433MHz. (Industrial, Scientific and Medical Band).
  • Mikrokontroller: Adafruit Feather M0 Radio (ATSAMD21G18 ARM Cortex M0, Taktrate 48MHz, 256k Flash-Speicher, 32k RAM)
  • Kein RailCom (Antworten vom Lokdecoder)
  • Weichenumschaltung per Funk

Das DCC-Protokoll

Modellbahnen werden schon längst digital gesteuert. Zum Beispiel mit dem DCC-Protokoll (Digital Command Control), das von allen Modellbahnherstellern unterstützt wird. Meine Wahl fiel auf DCC, weil es quelloffen ist und man auch entsprechende Normblätter im Internet findet, wie z.B. diese hier:

Das DCC-Gleissignal hat einerseits den Zweck, die Fahrzeuge mit Energie zu versorgen und andererseits, sie mit individuellen Fahrzeugkommandos zu steuern. Das folgende Bild zeigt den Signalverlauf eines Steuerbefehls. Logisch 0 und Logisch 1 wird nicht durch eine Spannungsdifferenz, sondern durch eine verschieden lange Pulsdauer unterschieden. Ein einfaches DCC-Paket besteht aus 44 Bit und setzt sich wie folgt zusammen:

Arduino als Entwicklungsplattform

Arduino ist eine quelloffene, aus Soft- und Hardware bestehende Physical-Computing-Plattform. Die Hardware besteht grundsätzlich aus einem E/A-Board mit einem Mikrocontroller und analogen und digitalen Ein- und Ausgängen. Die Programmierung erfolgt in einer C- bzw. C++-ähnlichen Programmiersprache, wobei technische Details wie Header-Dateien vor den Anwendern weitgehend verborgen werden und umfangreiche Bibliotheken und Beispiele die Programmierung vereinfachen.
Beispiel für ein Programm (Sketch), das eine an das Arduino-Board angeschlossene LED blinken lässt:

int ledPin = 13;               //LED an Pin 13

void setup()                   //Wird beim Start des Programms einmalig aufgerufen
{
  pinMode(ledPin, OUTPUT);     //LED-Pin als Ausgang festlegen
}

void loop()                    //Wird ständig wiederholt, bis das Arduino-Board ausgeschaltet wird
{
  digitalWrite(ledPin, HIGH);  //LED anschalten
  delay(1000);                 //1000 Millisekunden warten
  digitalWrite(ledPin, LOW);   //LED ausschalten
  delay(1000);                 //1000 Millisekunden warten
}

Die Hardware der Basisstation

Lokomotive mit Güterwagen als Träger der Basisstation und des LiPO-Akkus: Weicheantrieb mit Funksteuerung: Eigentlich war eine drehbare Weichenlaterne vorgesehen, die anzeigen würde, ob die Weiche auf «Gerade» oder «Abzweigend» steht. Nun kommt aber ein sogenanntes Zwergsignal zum Einsatz, das gemäss den SBB-Fahrdienstvorschriften den Rangierbetrieb regelt und nicht Weichenstellungen anzeigt. Um trotzdem sichtbar zu machen, wie der Zug die Weiche passieren wird und dabei die SBB-Fahrdienstvorschriften einigermassen zu erfüllen, besteht der Kompromiss darin, eine abzweigende Weiche mit «Fahrt mit Vorsicht» bzw. bei Geradeausfahrt mit «Fahrt» zu signalisieren. Bei besetzter Weiche oder während der Weichenumstellung zeigt das Zwergsignal «Halt». Das Weichenherz wird je nach Weichenstelung umgepolt. Als Gleisbesetztmelder wirkt eine IR-LED zur Distanzmessung bzw. Fahrzeugdedektierung. Die Ausgangslage der Weiche ist «Gerade» und wird per Funk auf «Abzweigend» umgestellt. Nach der Passage der Zuges oder nach einem Timeout keht die Weiche automatisch in die Ausgangsposition zurück. Die Schaltelektronik (uC) wird über das Gleis mit Strom versorgt. Bauteilliste:

  • Mikrokontroller: Adafruit (3177) Feather M0 Radio (ATSAMD21G18 ARM Cortex M0, Taktrate 48MHz, 256k Flash-Speicher, 32k RAM)
  • ISM 433MHz Antenne Molex inkl. uFl-Stecker (Die aufklebbare Flachantenne ist unter dem Gehäusedeckel angebracht)
  • Gleisbesetztmelder: Adafruit (3316) VL6180X Time of Flight Distance Ranging Sensor 5..100mm
  • Weichenherzpolarisierung: Adafruit (3191) 10-Ampere Power Relay FeatherWing (Non-latching type relay)
  • Weichenmotor/Servoansteuerung: Adafruit (2928) 8-Channel PWM or Servo FeatherWing
  • Weichenmotor/Servo: Miniatur-Servo KST X08 HV V6.0 im Alugehäuse und mit Metallgetriebe
  • Brückengleichrichter mit 470uF Elektrolytkondensator und L7805CV (Linear Fixed Voltage Regulator, 5V, 1.5A, TO-220)
  • 3 weisse LEDs mit Vorwiderständen




Extras ∇ ARDUINO C-CODE GEMEINSAMER HEADER



Extras ∇ ARDUINO C-CODE DER BASISSTATION



Extras ∇ ARDUINO C-CODE DES FUNKHANDREGLERS



Extras ∇ ARDUINO C-CODE DER WEICHENSTEUERUNG


Programmiertipps: Rechnen mit binären Operatoren

Beim Low-Level-Programmieren von z.B. Mikrokontrollern (Arduino) und in der Kommunikation können Berechnungen auf binärer Ebene (HEX, BIN) Vorteile bringen, wie z.B. eine schellere Programmausführung.

x >> n bedeutet: Bitfolge x um n-Stellen nach rechts verschieben (Rechts fallen die Bits heraus)
x << n bedeutet: Bitfolge x um n-Stellen nach links verschieben (Neue 0-Bits werden rechts eingefügt)
& AND/UND (AND-WHT: 00=0 / 01=0 / 10=0 / 11=1) Nicht zu verwechseln mit logischem AND &&
| OR/ODER (OR-WHT: 00=0 / 01=1 / 10=1 / 11=1) Nicht zu verwechseln mit logischem OR ||;
^ XOR (Exklusives ODER WHT: 00=0 / 01=1 / 10=1 / 11=0)
~ NOT/NICHT/INVERTER (Bsp. 1011 wird zu 0100)
(Die zur Verfügung stehende Bitbreite ist zu beachten! Stichwort: Data-Overflow)

Ganzzahlige Division durch 2
Zahlenbeispiel 1: 12 div 2 = 6
12 = 1100
1100 >> 1 = 110
110 = 6

Zahlenbeispiel 2: 15 div 2 = 7
15 = 1111
1111 >> 1 = 111
111 = 7

Restwert (Modulo) bei Division durch 2
LSB prüfen: 0→Rest-0, 1→Rest-1

Multiplikation mit dem Faktor 2
Zahlenbeispiel: 13 mul 2 = 26
13 = 1101
1101 << 1 = 11010
11010 = 26

Addition von 2 Bits inkl. Übertrag (Volladdierer)
(A=1.Bit, B=2.Bit, S=Summe, C1=Übertrag In, C2=Übertrag Out)
S = (A^B) ^ C1
C2= (A&B) | (C1&(A^B))

Zahlenbeispiel 1+0+1=10 oder 2
A = 1 (1. Bit)
B = 0 (2. Bit)
C1= 1 (Bit aus der vorangegangenen Binärstelle)
S = 0 (Summe)
C2= 1 (Übertrag in die nächste Binärstelle)

Bit auslesen
Zahlenbeispiel: Zweites Bit von links auslesen
a=0110
b=0011
c=0100
a & c = 0100
b & c = 0000

Bit setzen
Zahlenbeispiel: Zweites Bit von links setzen
a=0010
b=0110
c=0100
a | c = 0110 (Bit wurde gesetzt)
b | c = 0110 (Bit war schon gesetzt)

Bit löschen
Zahlenbeispiel: Zweites Bit von links löschen
a=0010
b=0110
c=0100   (Hinweis: ~c = 1011)
a & ~c = 0010 (Bit war schon gelöscht)
b & ~c = 0010 (Bit wurde gelöscht)