Pendelzugsteuerung mit Arduino

Das ein Arduino wahrscheinlich weitaus mehr kann, als auf der Eisenbahnanlage ein paar Ampeln zu steuern oder Befehle von einem Stellpultprogramm auszufĂŒhren bzw. zurĂŒckzumelden dĂŒrfte inzwischen klar sein. Nichtsdestotrotz werde ich da skleine Board versuchen einzusetzen, wo es eben geht. Beim Thema Pendelzugsteuerung gibt es zwar auch fertige zu kaufen - aber was wĂ€re die Modellbahn ohne Bastelei :)

Grundproblem ist fĂŒr mich immer die Überlegung, dass ich gerne mit Gleisbesetztmeldern arbeiten wĂŒrde, um Reedkontakte und Magnete zu vermeiden. Alle Besetztmelder, die ich gefunden habe, arbeiten nach dem Prinzip, dass ein Stromverbraucher (Motor, Beleuchtung) auch Strom verbraucht und somit die Spannung abfĂ€llt. Das stellen diese Melder fest, indem sie die Spannung des ĂŒberwachten Bereiches mit der 'unverbrauchten' Fahrspannung vergleichen - ist sie niedriger, dann ist der Abschnitt halt besetzt. So weit so gut - aber: Ein Abschnitt, in dem eine Lok nur steht, weil der Abschnitt abgeschaltet ist, kann ja nicht wirklich verglichen werden - vielleicht sehe ich das falsch, wer also etwas zu dem Thema weiß darf sich gerne bei mir melden :)

Bestehende Pendelzugsteuerungen haben zudem (meistens) die Angewohnheit, dass nur an einem Ende der Pendelstrecke ein Ausweichgleis existiert und somit "nur" zwei ZĂŒge pendeln - damit fĂ€hrt zwangslĂ€ufig ein Zug hin und direkt wieder zurĂŒck. Doof. Will ich nicht. Ich will, dass auch am zweiten Endpunkt der Pendelstrecke ein anderer Zug zurĂŒckfĂ€hrt, damit der Pendelbetrieb nicht so offensichtlich wird - gerade bei Straßenbahnen wĂŒrde das doch sehr auffallen.

Also kam mir grundsÀtzlich die Idee, vor dem Halteabschnitt des Endhaltepunktes in jedes Gleis einen Kontakt einzusetzen. Im Grunde fand ich die Idee gut - bis mir auffiel, dass dieser Kontakt ja richtungsunabhÀngig ausgelöst wird, d.h. er wird ausgelöst, wenn ein Zug den Haltebereich verlÀsst oder in diesen EinfÀhrt. Das oder stört, aber gewaltig. Andererseits: Wenn jeder Halteabschnitt an den Endpunkten so einen Kontakt hat dann kann ich doch die Reihenfolge messen, mit denen diese Kontakte durchfahren werden...

...bei 4 Endgleisen sind das 4 Kontakte. Bedeutet im Klartext: Es gibt nur 4 ZustÀnde, in denen die Kontakte im Pendelbetrieb nacheinander durchfahren werden, nÀmlich immer VON einem Endgleiskontakt NACH einem Endgleiskontakt. Zur Verdeutlichung mal eine Zeichnung einer Pendelstrecke mit je 2 Endgleisen:

w_93

Wie man sieht, sind es 4 verschiedene ZustĂ€nde, nach denen sich das Spiel wiederholt - der fĂŒnfte "Zustand" entspricht dem ersten, auch wenn die ZĂŒge andere sind.
Und zwar fÀhrt ein Zug immer von:

1 -> 2 oder
3 -> 1 oder
4 -> 3 oder
2 -> 4

Und da kommt ein Arduino in's Spiel: Wenn man jedem Kontaktgleis einen Eingang des Arduino-Boards zuweist kann man feststellen, welches Kontaktgleis gerade durchfahren wurde. Die Reihenfolge steht dann fĂŒr den Schaltvorgang, der ausgelöst werden muss. Und die Reihenfolge ist immer eindeutig: "12", "31", "43" oder "24". Die Logiktabelle sieht dann wie folgt aus:

w_92

Soweit noch ganz einfach. Jetzt muss ich nur noch (haha) ein wenig Gedanken an das Programm verschwenden, in welcher Reihenfolge wann was abgefragt und wann was gesteuert werden muss - die GrundzĂŒge dazu habe ich fertig (Programmflussdiagramm - das ist eine schematische Darstellung, was das Programm wann macht und welche Entscheidungen es trifft). Was mir gerade noch so einfĂ€llt - der Teufel ist ein Eichhörnchen und steckt im Detail - ist, dass ich ja auch die Stromrichtung umkehren muss... grĂŒbel...

So, gut ein Jahr ist in’s Land gegangen, und da meine Anlage sich dem Rohbaustadium nĂ€hert, werden die Gedankn zu einigen Problemchen wieder dichter: Könnte man auch eine Pendelstrecke anlegen mit je drei Endgleisen, also fĂŒr fĂŒnf ZĂŒge? Hmja, das geht:

Pendelzugsteuerung fĂŒr 5 ZĂŒge

Pendelstrecke_5_Bahnen

Das Bildchen zeigt die Logik, die dahintersteht, sowie die daraus resultierenden Abfragen, also z.B.:

WENN L1 besetzt UND L2 besetzt UND L3 besetzt UND R1 besetzt UND R2 besetzt UND R3 frei DANN Strom nach rechts UND Weichen von L3 nach R3 schalten UND Fahrt in L3 freigeben.

In Basic kann ich das...

...jetzt nur noch im Arduino, denn das kleine Board kann so etwas auch eigenstĂ€ndig und muss nicht nur als Schaltzwischenbaustein fĂŒr VB2010 herhalten!

// *********************************************
//                                             *
//       Pendelzugsteuerung fĂŒr 5 ZĂŒge         *
//           - 3 Gleise pro Seite -            *
//                                             *
// *********************************************

  // AnschlĂŒsse:

    //a: Melder

    

    int L1 = 97;     // Links 1 Melder - PIN A0

    int L2 = 96;     // Links 2 Melder - PIN A1

    int L3 = 95;     // Links 3 Melder - PIN A2

    int R1 = 94;     // Rechts 1 Melder - PIN A3

    int R2 = 93;     // Rechts 2 Melder - PIN A4

    int R3 = 92;     // Rechts 3 Melder - PIN A5

    

    //b: Weichen

    

    int WL2_G = 6;     // Weiche Links2 geradeaus - PIN 2

    int WL2_A = 7;     // Weiche Links2 abzweigend - PIN 3

    int WL3_G = 1;     // Weiche Links3 geradeaus - PIN 4

    int WL3_A = 5;     // Weiche Links3 abzweigend - PIN 5

    int WR2_G = 15;    // Weiche Rechts2 geradeaus - PIN 6

    int WR2_A = 16;    // Weiche Rechts2 abzweigend - PIN 7

    int WR3_G = 17;    // Weiche Rechts3 geradeaus - PIN 8

    int WR3_A = 18;    // Weiche Rechts3 abzweigend - PIN 9

    

    //c: Strom links

    

    int SL1H = 23;   // Strom Links1 High - PIN 10

    int SL1L = 24;   // Strom Links1 Low - PIN 11

    int SL2H = 25;   // Strom Links2 High - PIN 12

    int SL2L = 26;   // Strom Links2 Low - PIN 13

    int SL3H = 64;   // Strom Links3 High - PIN 14

    int SL3L = 63;   // Strom Links3 Low - PIN 15

    

    //d: Strom rechts

    

    int SR1H = 78;     // Strom Rechts1 High - PIN 22

    int SR1L = 77;     // Strom Rechts1 Low - PIN 23

    int SR2H = 76;     // Strom Rechts2 High - PIN 24

    int SR2L = 75;     // Strom Rechts2 Low - PIN 25

    int SR3H = 74;     // Strom Rechts3 High - PIN 26

    int SR3L = 73;     // Strom Rechts3 Low - PIN 27

    

    //e: Stromrichtung

    

    int SR_L = 59;     // Strom Fahrtrichtung Links - PIN 31

    int SR_R = 58;     // Strom Fahrtrichtung Rechts - PIN 32

    

    

    void setup() {             

      // Pins als OUTPUT oder INPUT definieren

    

      pinMode(L1, INPUT); pinMode(L2, INPUT); pinMode(L3, INPUT);

      pinMode(R1, INPUT); pinMode(R2, INPUT); pinMode(R3, INPUT);

      pinMode(WL2_G, OUTPUT); pinMode(WL2_A, OUTPUT);

      pinMode(WL3_G, OUTPUT); pinMode(WL3_A, OUTPUT);

      pinMode(WR2_G, OUTPUT); pinMode(WR2_A, OUTPUT);

      pinMode(WR3_G, OUTPUT); pinMode(WR3_A, OUTPUT);

      pinMode(SL1H, OUTPUT); pinMode(SL1L, OUTPUT);

      pinMode(SL2H, OUTPUT); pinMode(SL2L, OUTPUT);

      pinMode(SL3H, OUTPUT); pinMode(SL3L, OUTPUT);

      pinMode(SR_L, OUTPUT); pinMode(SR_R, OUTPUT);

    

    

    // Anfangszustand - wird nicht benötigt

    

    }

    

    void loop() {

    

    // von L3 -> R3

    if (L1 == HIGH && L2 == HIGH && L3 == HIGH && R1 == HIGH && R2 == HIGH && R3 == LOW) {

       digitalWrite(SR_L, LOW); digitalWrite(SR_R, HIGH);

       digitalWrite(WR3_G, LOW); digitalWrite(WR3_A, HIGH);

       digitalWrite(WL3_A, LOW); digitalWrite(WL3_G, HIGH);

       digitalWrite(SR3H, LOW); digitalWrite(SR3L, HIGH);

       digitalWrite(SL3L, LOW); digitalWrite(SL3H, HIGH);

      }

    

    // von L3 -> R2

    if (L1 == HIGH && L2 == HIGH && L3 == LOW && R1 == HIGH && R2 == HIGH && R3 == HIGH) {

       digitalWrite(SR_R, LOW); digitalWrite(SR_L, HIGH);

       digitalWrite(WR3_G, LOW); digitalWrite(WR3_A, HIGH);

       digitalWrite(WL3_A, LOW); digitalWrite(WL3_G, HIGH);

       digitalWrite(WR2_G, LOW); digitalWrite(WR3_A, HIGH);

       digitalWrite(SL3H, LOW); digitalWrite(SL3L, HIGH);

       digitalWrite(SR2L, LOW); digitalWrite(SR2H, HIGH);

      }

    

    // von L2 -> R2

    if (L1 == HIGH && L2 == HIGH && L3 == HIGH && R1 == HIGH && R2 == LOW && R3 == HIGH) {

       digitalWrite(SR_L, LOW); digitalWrite(SR_R, HIGH);

       digitalWrite(WR3_G, LOW); digitalWrite(WR3_A, HIGH);

       digitalWrite(WL3_G, LOW); digitalWrite(WL3_A, HIGH);

       digitalWrite(WR2_G, LOW); digitalWrite(WR2_A, HIGH);

       digitalWrite(WL2_G, LOW); digitalWrite(WL2_A, HIGH);

       digitalWrite(SL2L, LOW); digitalWrite(SL2H, HIGH);

       digitalWrite(SR2H, LOW); digitalWrite(SR2L, HIGH);

      }

    

    // von R1 -> L2

    if (L1 == HIGH && L2 == LOW && L3 == HIGH && R1 == HIGH && R2 == HIGH && R3 == HIGH) {

       digitalWrite(SR_R, LOW); digitalWrite(SR_L, HIGH);

       digitalWrite(WR3_G, LOW); digitalWrite(WR3_A, HIGH);

       digitalWrite(WL3_G, LOW); digitalWrite(WL3_A, HIGH);

       digitalWrite(WR2_A, LOW); digitalWrite(WR2_G, HIGH);

       digitalWrite(WL2_G, LOW); digitalWrite(WL2_A, HIGH);

       digitalWrite(SL2H, LOW); digitalWrite(SL2L, HIGH);

       digitalWrite(SR1L, LOW); digitalWrite(SR1H, HIGH);

      }

    

    // von L1 -> R1

    if (L1 == HIGH && L2 == HIGH && L3 == HIGH && R1 == LOW && R2 == HIGH && R3 == HIGH) {

       digitalWrite(SR_L, LOW); digitalWrite(SR_R, HIGH);

       digitalWrite(WR3_G, LOW); digitalWrite(WR3_A, HIGH);

       digitalWrite(WL3_G, LOW); digitalWrite(WL3_A, HIGH);

       digitalWrite(WR2_A, LOW); digitalWrite(WR2_G, HIGH);

       digitalWrite(WL2_A, LOW); digitalWrite(WL2_G, HIGH);

       digitalWrite(SR1H, LOW); digitalWrite(SR1L, HIGH);

       digitalWrite(SL1L, LOW); digitalWrite(SL1H, HIGH);

      }

    

    // von R3 -> L1

    if (L1 == LOW && L2 == HIGH && L3 == HIGH && R1 == HIGH && R2 == HIGH && R3 == HIGH) {

       digitalWrite(SR_R, LOW); digitalWrite(SR_L, HIGH);

       digitalWrite(WR3_A, LOW); digitalWrite(WR3_G, HIGH);

       digitalWrite(WL3_G, LOW); digitalWrite(WL3_A, HIGH);

       digitalWrite(WL2_A, LOW); digitalWrite(WL2_G, HIGH);

       digitalWrite(SL1H, LOW); digitalWrite(SL1L, HIGH);

       digitalWrite(SR3L, LOW); digitalWrite(SR3H, HIGH);

      }

 

}