#7 Weichenstraße

Manuelles Schalten wie in einem Stellwerk. Das bereitet sehr viel Fahrspaß und jede Menge Abwechslung.

Aber wie umsetzten? Komplexe Relaissteuerungen hart verdrahtet? 

Die Lösung welche ich euch vorstellen mochte, heißt wie so oft: Arduino.

hier können wir Weichenstraßen programmieren, Servos schalten, Signale schalten und wer möchte sogar Relais welche gewisse Gleispannung greifen beeinflussen.

Was wird benötigt? 
- Arduino je nach Größe des Projekts (in meinem Beispiel ein Arduino Mega)

- Servos bzw Magnetartikel zum Schalten der Weichen (in meinem Beispiel Servos)

- Taster zum ansteuern (ja Start-/Zielpunkt einen)
- Pull-Down Widerstände ca 10kOhm (je Taster einen)

Dieses mal zeige ich euch etwas neues: Funktionen
Funktionen gebraucht man idealerweise dann, wenn man die gleichen Berechnungen oder Abläufe an mehreren Stellen braucht. Auch wenn die ein oder andere Variable unterschiedlich sein mag, denn diese kann man der Funktion mit übergeben.
Aus einer Funktion kann auch eine Variable zurück kommen… muss aber nicht.
Wird ein Wert zurück gegeben muss der Typ der Funktion des Typs des Wertes entsprechen.
Klingt etwas kompliziert - aber zusammen erarbeiten
Wir möchten den Hier gezeigten Bahnhof Projektieren
Zunächst legen wir ein neues Projekt an.Wie erfahrt ihr in #2 Erstes Projekt
Da ich die Weichen per Servo ansteuern möchte, brauchen wir die Servo.h library.
Als nächstes benennen wir unsere Hardware.
Da hätten wir zunächst unserer 4 Servos.
Die bekommen einfach nur mal einen Namen.
Und dann noch unsere 5 Taster.
Dazu legen wir eine int Variable an mit dem Namen den wir verwenden wollen und weißen dieser direkt den Wert zu welcher die Pin hat an dem wir den Taster anschließen.
Soweit so gut. Da wir später noch eine Variable brauchen können wir diese auch gleich anlegen: int Grad.
Diese Variable ein keinen Startwert daher einfach mit einem Smikolon die Zeile schließen.
Im Setup müssen wir dann noch klarstellen das die Pins der Taster Eingänge sind.
So weit so gut. Und ich denke bis hier her auch für jeden verständlich.
Nun kommen wir zu den Funktionen.
Überlegen wir mal was wird sich in unsrem Programm ständig wiederholt.
Ich denke die kleinste Funktion die sich ständig wiederholt ist die Tatsache das ein Servo auf eine bestimmte Position fahren soll.
Moment magst du sagen. Das ist ja jedesmal ein anderer Servo und jedesmal eine andere Postion. Stimmt ABER wir haben ja gesagt das wir Variablen mit in die Funktion übergeben können.
Wir nennen die Funktion einfach „schalten“.
Wenn wir aus der Funktion einen Wert zurück erwarten muss die Funktion vom Typ her dem Typ des Wert entsprechen. Z.B. int oder double.
In unserem Fall erwarten wir nichts zurück, daher trägt unsere Funktion den Typ void was NICHTIG oder LEER bedeutet.
Danach können wir in einer Klammer die Variablen definieren die wir übergeben möchten. Das lassen wir aber im Moment noch leer. Die geschweifte Klammer öffnet die Funktion.
Der nun folgende 4 Zeiler kennen wir ja aus dem Teil 4 Meiner Arduino Reihe.
Da wir weder den Pin noch den Servo und auch nicht die gewünschte Position kennen, setzten wir dafür Variablen ein. Diese 3 Unbekannten müssen also von außerhalb der Funktion jedesmal neu definiert werden. Damit dies Möglich ist, müssen wir diese in die ()Klammer eintragen und gleich einen Typ dafür auswählen.
In unserem Fall: Int Weiche, int Pin, int Winkel
Damit ist unsere erste Funktion auch schon abgeschlossen.
Wie rufen wir diese Funktion denn nun auf?
  Name(Variablen);
  Also: schalten(Weiche1, 2, 20);
Damit kommen wir schon zu unserer zweiten Funktion.
Und zwar ist das Problem die Gradzahl. Die wissen wir ja noch gar nicht so genau. Oder vielleicht müssen wir da später mal etwas nacharbeiten.
Vielleicht ist deine erste Intuition: Oben Variable anlegen und dann trage ich die einfach überall ein wo ich den Winkel brauche. Von der Idee nicht schlecht. Hat aber ein hohes Fehlerpotential, dass ich beim Kopieren und einfügen doch mal vergesse eine Variable zu ändern. Deswegen zeige ich euch jetzt eine andere Möglichkeit auch wieder mit Funktionen.
Wir nennen die nächste Funktion einfach mal W1 für die Weiche1 in dieser Funktion können wir dann die Beiden Gradzahlen die wir anfahren möchten angeben.
Da wir wieder keinen Wert aus der Funktion zurück erwarten ist es wieder eine Funktion des Typs Void. Als Information müssen wir in die Funktion die Richtung geben. Also gerade oder abbiegend. Ich würde vorschlagen wir machen das mit 0 und 1… 0-gerade 1-abbiegen.
Dazu brauchen wir wieder eine Variable. Nennen wir sie Stellung - Typ int.
Jetzt können wir sagen:
Wenn Stellung 0 ist dann … und jetzt nehmen wir den Funktionsaufruf den wir schon programmiert haben.
Das gleiche machen wir für den Fall das die Stellung 1 ist.
So richtig übersichtlich ist das noch nicht….
Daher würde ich den Funktionsaufruf aus den If Klammern heraus nehmen. Und die Gradzahl durch eine Variable ersetzen. Nennen wir sie „Grad“
Diese Variable haben wir zu beginn des Sketches schon definiert.
Dann weißen wir der Variablen jetzt einen Wert in den If-Klammer zu.
Und schon haben wir eine Übersichtliche Art die Weiche 1 anzusteuern.
Das wiederholen wir jetzt schnell für die Weichen 2-4
Dann kommen wir jetzt zum Loop.
Zunächst fragen wir ab, ob die Taste für die Ein-Ausfahrt gedrückt wird.
digitalRead(T_W) == HIGH
Solange wir diese Taste gedrückt halten, Fragen wir die anderen Tasten ab.
Dazu packen wir die Abfrage in eine "while"-Schleife. Und in der "while"-Schleife fragen wir nun die Möglichen Ziel Punkt ab. Z.B. Gleis1
digitalRead(T_G1) == HIGH
Wenn diese Taste auch gedrückt wird wollen wir weichen schallten.
Im Bild ganz oben sehen wir das wir die Weiche 1 auf abbiegen schalten müssen.
Also Rufen wir die Funktion W1 auf und übergeben den Wert 1 für Abbiegen.
Mehr muss in dieser Weichenstraße nicht geschalten werden.
Fragen wir dann das 2. Mögliche Zeil ab: Gleis2
Indetisch zu Gleis 1 nur mit anderen Weichen.
W1 gerade
W2 gerade
Fertig
Dann noch für Gleis 3
Das selbe für die Ein-Ausfahrt Ost
Dann noch wenn Gleis 1 der Startpunkt ist. Die Weichen die wir schalten sind zwar die selben ob wir von West nach 1 fahren wie von 1 nach West. Aber wenn ihr noch Signale oder Relais für die Fahrspannung mit einbauen möchtet, müssen wir die Richtung unterscheiden.
Dann könntet ihr in die "while"-Schleife der jeweiligen Fahrstraße einfach einen Pin ansteuern der z.B. euer Signal schaltet.
digitalWrite(Pin, Status);
also z.B. digitalWrite(Signal1grün, HIGH);
Wobei wir hier "Signal1grün" im Vorfeld definieren müssen und dieser Variablen den Wert des Pins zuweißen an dem wir die LED anschließen.
int Signal1grün = 40;
Das soll es dann mal soweit gewesen sein.
Bei Fragen hierzu: schreibt mich einfach an.
#include <Servo.h>
Servo Weiche1;
Servo Weiche2;
Servo Weiche3;
Servo Weiche4;
int T_W = 53;
int T_O = 52;
int T_G1 = 51;
int T_G2 = 50;
int T_G3 = 49;
int Grad;
//___________________VOID SETUP______________
void setup() {
  pinMode(T_W, INPUT);
  pinMode(T_O, INPUT);
  pinMode(T_G1, INPUT);
  pinMode(T_G2, INPUT);
  pinMode(T_G3, INPUT);
}
//___________FUNKTION "schalten"________________
void schalten (Servo Weiche, int PIN, int Winkel) {
  Weiche.attach(PIN);
  Weiche.write(Winkel);
  delay(300);
  Weiche.detach();
}
//___________FUNKTION "W1"___________________
void W1(int Stellung) {               //0=gerade - 1=abbiegen
  if(Stellung == 0) {                 //Stellung gerade aus
    Grad = 0;                         //Position in Grad       
  }
  if(Stellung == 1) {                 //Stellung abbiegend
    Grad = 20;                        //Position in Grad
  }
  schalten(Weiche1, 2, Grad);         //(Servo, Anschlusspin, Position)
}
//___________FUNKTION "W2"___________________
void W2(int Stellung) {               //0=gerade - 1=abbiegen
  if(Stellung == 0) {                 //Stellung gerade aus
    Grad = 0;                         //Position in Grad       
  }
  if(Stellung == 1) {                 //Stellung abbiegend
    Grad = 20;                        //Position in Grad
  }
  schalten(Weiche2, 3, Grad);         //(Servo, Anschlusspin, Position)
}
//___________FUNKTION "W3"___________________
void W3(int Stellung) {               //0=gerade - 1=abbiegen
  if(Stellung == 0) {                 //Stellung gerade aus
    Grad = 0;                         //Position in Grad       
  }
  if(Stellung == 1) {                 //Stellung abbiegend
    Grad = 20;                        //Position in Grad
  }
  schalten(Weiche3, 4, Grad);         //(Servo, Anschlusspin, Position)
}
//___________FUNKTION "W4"___________________
void W4(int Stellung) {               //0=gerade - 1=abbiegen
  if(Stellung == 0) {                 //Stellung gerade aus
    Grad = 0;                         //Position in Grad       
  }
  if(Stellung == 1) {                 //Stellung abbiegend
    Grad = 20;                        //Position in Grad
  }
  schalten(Weiche4, 5, Grad);         //(Servo, Anschlusspin, Position)
}
//_____________VOID LOOP______________________
void loop() {
  while(digitalRead(T_W) == HIGH) {       //Start Ein-Ausfahrt West
    while(digitalRead(T_G1) == HIGH) {       //Ziel Gleis1
      W1(1);
    }
    while(digitalRead(T_G2) == HIGH) {       //Ziel Gleis2
      W1(0);
      W2(0);
    }
    while(digitalRead(T_G3) == HIGH) {       //Ziel Gleis3
      W1(0);
      W2(1);
    }
  }
  while(digitalRead(T_O) == HIGH) {       //Start Ein-Ausfahrt Ost
    while(digitalRead(T_G1) == HIGH) {       //Ziel Gleis1
      W4(0);
      W3(1);
    }
    while(digitalRead(T_G2) == HIGH) {       //Ziel Gleis2
      W4(0);
      W3(0);
    }
    while(digitalRead(T_G3) == HIGH) {       //Ziel Gleis3
      W4(1);
    }
  }
 
  while(digitalRead(T_G1) == HIGH) {      //Start Gleis1
    while(digitalRead(T_W) == HIGH) {        //Ziel Ein-Ausfahrt West
      W1(1);
    }
    while(digitalRead(T_O) == HIGH) {        //Ziel Ein-Ausfahrt Ost
      W3(1);
      W4(0);
    }
  }
  while(digitalRead(T_G2) == HIGH) {      //Start Gleis2
    while(digitalRead(T_W) == HIGH) {        //Ziel Ein-Ausfahrt West
      W2(0);
      W1(0);
    }
    while(digitalRead(T_O) == HIGH) {        //Ziel Ein-Ausfahrt Ost
      W3(0);
      W4(0);
    }
  }
  while(digitalRead(T_G3) == HIGH) {      //Start Gleis3
    while(digitalRead(T_W) == HIGH) {        //Ziel Ein-Ausfahrt West
      W2(1);
      W1(0);
    }
    while(digitalRead(T_O) == HIGH) {        //Ziel Ein-Ausfahrt Ost
      W4(1);
    }
  }
}


Downloads

Download
Bahnhof mit Gleisbild
Bild 4 mit Namen.png
Portable Network Grafik Format 182.8 KB
Download
Arduino Programm
Weichenstrassen.zip
Komprimiertes Archiv im ZIP Format 1.3 KB