Weichensteuerung für Zwängle mit dem Arduino

  • Hallo Freunde der Bits, Bytes und Lötkolben,


    für die Digitalos unter euch möchte ich mal die Welt der Arduinos vorstellen.
    In diesem Beispiel geht um meine Weichensteuerung für Zwängle.


    Meine Vorgabe war die Steuerung von Weichenstraßen mit Start- / Zieltastern. Ausschlaggebend war dabei meine verhasste DKW, bei der ich immer erst 'ne halbe Stunde überlegen muss, wie die Zungen gestellt werden müssen, um von A nach B zu kommen.


    Statt eines aufwendigen analogen Aufbaus, bei dem nachträgliche Änderungen ein Horror wäre, habe ich mich also für die digitale Variante entschieden.
    Hierfür sind die Mikrocontroller Arduino oder Raspberry Pi bestens geeignet. Damit können alle Arten von LED-, Servo-, (Stepper-)Motoren-, Relais-Steuerungen und noch vieles weiteres mehr umgesetzt werden. Für den Modellbahnbereich ergeben sich unendlich viele Anwendungsgebiete.
    Es ist alles so einfach gehalten, dass auch Hobby-Programmierer und -Elektroniker ohne großes Fachwissen hier schnell zu Erfolgen kommen.


    Meine Wahl fiel auf den Arduino Mega 2560 R3 (SunFounder) wegen seiner 50 frei programmierbaren Ein- und Ausgänge, des wahrlich günstigen Preises von etwa 18,- EUR (originale Arduino Mega kosten etwa das Doppelte als die China-Nachbauten) und der riesigen Arduino-OnlineCommunity.


    Für den schnellen Einstig in die Arduino-Welt eignet sich die Seite www.arduino-tutorial.de/.
    Was wird minimal benötigt?

    Zum Aufbau selbst:

    • Die Weichen werden von Servos über ESUs SwitchPilot Servo angetrieben.
    • Die Eingänge der SwitchPilots müssen mit potentialfreie Schalter/Taster betrieben werden, was die Verwendung von Relais hierfür notwendig macht. Ich hatte noch eine ganze Batterie von 15V-Relais herumliegen und brauchte diese hierfür auf.
    • Pro Servo sind 2 Relais notwendig. Einer zum Umschalten in die eine Richtung und der andere für die andere Richtung. Bei 8 Weichen macht das 16 Relais.
      Die Ausgänge des Arduino können aber nur 5V/40mA liefern (insgesamt auch nur knapp über 200mA glaub ich). Somit können die 15V-Relais nicht direkt an den Arduino angeschlossen werden.
      Macht aber nix - wir nehmen einfach den Treiber-Baustein ULN2803 (intern 8 Treiber) zur Ansteuerung der Relais. Der kann bis 50V Betriebsspannung ab.

    Nach ein paar Stunden war das Progrämmchen (programmiert wird in den Sprachen C oder C++) und die Schaltung entwickelt (ok - bin etwas elektronisch und programmiertechnisch beruflich vorbelastet).


    (Ins Bild klicken zum Vergrößern)



    Die 50 I/O-Pins sind frei als Ein- oder Ausgänge definierbar:

    • 11 Pins sind als Eingänge für die Taster definiert (Pin 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52)
      Die Eingänge sind im Code von mir als INPUT_PULLUP definiert und somit LOW-aktiv. D.h. im Grundzustand (Taster offen) liegen die Eingänge intern auf HIGH und die Taster schalten die Eingangspins gegen Masse (im Code deshalb Abfrage auf LOW).
    • 16 Pins sind als Ausgänge für die Relais definiert (Pin 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53)
      Die Ausgänge des Arduino gehen zu den beiden ULN2803 (2 x 8Treiber für 16 Relais) und diese schalten die Relais, welche an +15V hängen gegen Masse.


    Die Schaltung selbst ist recht simpel, hat mich aber im Aufbau doch einiges an Zeit gekostet:


    Hier das Bedienpanel mit den 11 Tastern (einer fehlt noch - hatte doch glatt einen zu wenig gekauft):



    Alles in ein Gehäuse eingebaut:

    • Links die Relais-Platine mit den beiden ULN2803
    • Links unten die Ausgänge. Per Flachbandkabel geht es weiter zu den ESU SwitchPilots.
    • Rechts der Arduino Mega


    Und von der anderen Seite:



    Hier die Verbindung zum Bedienpanel:



    Und in der Gesamtansicht:



    Gleich geht's weiter...


    Gruß Ralf

  • Und weiter geht's:


    Für den nachfolgenden Programmcode und die Weichenmatrix hier die Übersicht der Nummerierungen:

    • Die grünen Zahlen sind die Tasternummern.
    • Die roten Zahlen bezeichnen die Weichen-/Relaisnummern. Zur Weiche 2 gehören dann die beiden Relais Servo_2_Rel_1 und Servo_2_Rel_2.



    Die Weichenmatrix - bei welcher Taster-Kombination welche Relais geschalten werden müssen:



    Und hier der Programmcode:

    Code
    // Globale Variablen mit EingangsPins deklarierenint Input1 = 52;int Input2 = 50;int Input3 = 48;int Input4 = 46;int Input5 = 44;int Input6 = 42;int Input7 = 40;int Input8 = 38;int Input9 = 36;int Input10 = 34;int Input11 = 32; // Globale Variablen mit AusgangsPins deklarierenint Servo_1_Rel_1 = 53;int Servo_1_Rel_2 = 51;int Servo_2_Rel_1 = 49;int Servo_2_Rel_2 = 47;int Servo_3_Rel_1 = 45;int Servo_3_Rel_2 = 43;int Servo_4_Rel_1 = 41;int Servo_4_Rel_2 = 39;int Servo_5_Rel_1 = 37;int Servo_5_Rel_2 = 35;int Servo_6_Rel_1 = 33;int Servo_6_Rel_2 = 31;int Servo_7_Rel_1 = 29;int Servo_7_Rel_2 = 27;int Servo_8_Rel_1 = 25;int Servo_8_Rel_2 = 23;// Einmaliger Setup-Aufruf beim Programmstartvoid setup() { // EingangsPins als Eingang definieren: // INPUT_PULLUP = Eingang wird intern auf +5V gelegt, // dadurch Aktivierung durch "mit GND verbinden". pinMode(Input1, INPUT_PULLUP); pinMode(Input2, INPUT_PULLUP); pinMode(Input3, INPUT_PULLUP); pinMode(Input4, INPUT_PULLUP); pinMode(Input5, INPUT_PULLUP); pinMode(Input6, INPUT_PULLUP); pinMode(Input7, INPUT_PULLUP); pinMode(Input8, INPUT_PULLUP); pinMode(Input9, INPUT_PULLUP); pinMode(Input10, INPUT_PULLUP); pinMode(Input11, INPUT_PULLUP); // AusgangsPins als Ausgang definieren: pinMode(Servo_1_Rel_1, OUTPUT); pinMode(Servo_1_Rel_2, OUTPUT); pinMode(Servo_2_Rel_1, OUTPUT); pinMode(Servo_2_Rel_2, OUTPUT); pinMode(Servo_3_Rel_1, OUTPUT); pinMode(Servo_3_Rel_2, OUTPUT); pinMode(Servo_4_Rel_1, OUTPUT); pinMode(Servo_4_Rel_2, OUTPUT); pinMode(Servo_5_Rel_1, OUTPUT); pinMode(Servo_5_Rel_2, OUTPUT); pinMode(Servo_6_Rel_1, OUTPUT); pinMode(Servo_6_Rel_2, OUTPUT); pinMode(Servo_7_Rel_1, OUTPUT); pinMode(Servo_7_Rel_2, OUTPUT); pinMode(Servo_8_Rel_1, OUTPUT); pinMode(Servo_8_Rel_2, OUTPUT);}// loop() wird nach setup() fortwährend ausgeführt:void loop() { // Abfrage der Eingänge auf die gültigen Kombinationen // (digitalRead(EingangsPin, LOW), da LOW-aktiv) und // entsprechendes Schalten der Ausgänge (digitalWrite(AusgangsPin, HIGH)). if (digitalRead(Input1)==LOW) { if (digitalRead(Input2)==LOW) { digitalWrite(Servo_1_Rel_1, HIGH); waitForSwitchOff(Input2); } else if (digitalRead(Input5)==LOW) { digitalWrite(Servo_1_Rel_2, HIGH); digitalWrite(Servo_2_Rel_2, HIGH); digitalWrite(Servo_3_Rel_1, HIGH); waitForSwitchOff(Input5); } else if (digitalRead(Input6)==LOW) { digitalWrite(Servo_1_Rel_2, HIGH); digitalWrite(Servo_2_Rel_1, HIGH); digitalWrite(Servo_4_Rel_2, HIGH); waitForSwitchOff(Input6); } else if (digitalRead(Input7)==LOW) { digitalWrite(Servo_1_Rel_2, HIGH); digitalWrite(Servo_2_Rel_1, HIGH); digitalWrite(Servo_4_Rel_1, HIGH); waitForSwitchOff(Input7); } else if (digitalRead(Input8)==LOW) { digitalWrite(Servo_1_Rel_2, HIGH); digitalWrite(Servo_2_Rel_2, HIGH); digitalWrite(Servo_3_Rel_1, HIGH); digitalWrite(Servo_5_Rel_1, HIGH); digitalWrite(Servo_6_Rel_2, HIGH); waitForSwitchOff(Input8); } else if (digitalRead(Input9)==LOW) { digitalWrite(Servo_1_Rel_2, HIGH); digitalWrite(Servo_2_Rel_1, HIGH); digitalWrite(Servo_4_Rel_2, HIGH); digitalWrite(Servo_7_Rel_1, HIGH); waitForSwitchOff(Input9); } else if (digitalRead(Input10)==LOW) { digitalWrite(Servo_1_Rel_2, HIGH); digitalWrite(Servo_2_Rel_1, HIGH); digitalWrite(Servo_4_Rel_2, HIGH); digitalWrite(Servo_7_Rel_1, HIGH); digitalWrite(Servo_8_Rel_1, HIGH); waitForSwitchOff(Input10); } else if (digitalRead(Input11)==LOW) { digitalWrite(Servo_1_Rel_2, HIGH); digitalWrite(Servo_2_Rel_1, HIGH); digitalWrite(Servo_4_Rel_2, HIGH); digitalWrite(Servo_7_Rel_1, HIGH); digitalWrite(Servo_8_Rel_2, HIGH); waitForSwitchOff(Input11); } } else if (digitalRead(Input3)==LOW) { if (digitalRead(Input5)==LOW) { digitalWrite(Servo_3_Rel_2, HIGH); waitForSwitchOff(Input5); } else if (digitalRead(Input8)==LOW) { digitalWrite(Servo_3_Rel_2, HIGH); digitalWrite(Servo_5_Rel_1, HIGH); digitalWrite(Servo_6_Rel_2, HIGH); waitForSwitchOff(Input8); } else if (digitalRead(Input9)==LOW) { digitalWrite(Servo_3_Rel_2, HIGH); digitalWrite(Servo_5_Rel_2, HIGH); digitalWrite(Servo_6_Rel_2, HIGH); digitalWrite(Servo_7_Rel_2, HIGH); waitForSwitchOff(Input9); } else if (digitalRead(Input10)==LOW) { digitalWrite(Servo_3_Rel_2, HIGH); digitalWrite(Servo_5_Rel_2, HIGH); digitalWrite(Servo_6_Rel_2, HIGH); digitalWrite(Servo_7_Rel_2, HIGH); digitalWrite(Servo_8_Rel_1, HIGH); waitForSwitchOff(Input10); } else if (digitalRead(Input11)==LOW) { digitalWrite(Servo_3_Rel_2, HIGH); digitalWrite(Servo_5_Rel_1, HIGH); digitalWrite(Servo_6_Rel_1, HIGH); digitalWrite(Servo_7_Rel_2, HIGH); digitalWrite(Servo_8_Rel_2, HIGH); waitForSwitchOff(Input11); } } else if (digitalRead(Input4)==LOW) { if (digitalRead(Input8)==LOW) { digitalWrite(Servo_5_Rel_1, HIGH); digitalWrite(Servo_6_Rel_1, HIGH); waitForSwitchOff(Input8); } else if (digitalRead(Input9)==LOW) { digitalWrite(Servo_5_Rel_2, HIGH); digitalWrite(Servo_6_Rel_1, HIGH); digitalWrite(Servo_7_Rel_2, HIGH); waitForSwitchOff(Input9); } else if (digitalRead(Input10)==LOW) { digitalWrite(Servo_5_Rel_2, HIGH); digitalWrite(Servo_6_Rel_1, HIGH); digitalWrite(Servo_7_Rel_2, HIGH); digitalWrite(Servo_8_Rel_1, HIGH); waitForSwitchOff(Input10); } else if (digitalRead(Input11)==LOW) { digitalWrite(Servo_5_Rel_2, HIGH); digitalWrite(Servo_6_Rel_1, HIGH); digitalWrite(Servo_7_Rel_2, HIGH); digitalWrite(Servo_8_Rel_2, HIGH); waitForSwitchOff(Input11); } } else if (digitalRead(Input5)==LOW) { if (digitalRead(Input8)==LOW) { digitalWrite(Servo_5_Rel_1, HIGH); digitalWrite(Servo_6_Rel_2, HIGH); waitForSwitchOff(Input8); } else if (digitalRead(Input9)==LOW) { digitalWrite(Servo_5_Rel_2, HIGH); digitalWrite(Servo_6_Rel_2, HIGH); digitalWrite(Servo_7_Rel_2, HIGH); waitForSwitchOff(Input9); } else if (digitalRead(Input10)==LOW) { digitalWrite(Servo_5_Rel_2, HIGH); digitalWrite(Servo_6_Rel_2, HIGH); digitalWrite(Servo_7_Rel_2, HIGH); digitalWrite(Servo_8_Rel_1, HIGH); waitForSwitchOff(Input10); } else if (digitalRead(Input11)==LOW) { digitalWrite(Servo_5_Rel_2, HIGH); digitalWrite(Servo_6_Rel_2, HIGH); digitalWrite(Servo_7_Rel_2, HIGH); digitalWrite(Servo_8_Rel_2, HIGH); waitForSwitchOff(Input11); } } else if (digitalRead(Input6)==LOW) { if (digitalRead(Input9)==LOW) { digitalWrite(Servo_7_Rel_1, HIGH); waitForSwitchOff(Input9); } else if (digitalRead(Input10)==LOW) { digitalWrite(Servo_7_Rel_1, HIGH); digitalWrite(Servo_8_Rel_1, HIGH); waitForSwitchOff(Input10); } else if (digitalRead(Input11)==LOW) { digitalWrite(Servo_7_Rel_1, HIGH); digitalWrite(Servo_8_Rel_2, HIGH); waitForSwitchOff(Input11); } } else if (digitalRead(Input9)==LOW) { if (digitalRead(Input10)==LOW) { digitalWrite(Servo_8_Rel_1, HIGH); waitForSwitchOff(Input10); } else if (digitalRead(Input11)==LOW) { digitalWrite(Servo_8_Rel_2, HIGH); waitForSwitchOff(Input11); } } // Alle Ausgänge wieder ausschalten turnOffOutputs();}// Funktion wartet, bis angegebene Taste losgelassen wird.void waitForSwitchOff(int InputPin) { do { delay(200); } while (digitalRead(InputPin)==LOW);}// Funktion zum Ausschalten aller benutzten Ausgänge.void turnOffOutputs() { digitalWrite(Servo_1_Rel_1, LOW); digitalWrite(Servo_1_Rel_2, LOW); digitalWrite(Servo_2_Rel_1, LOW); digitalWrite(Servo_2_Rel_2, LOW); digitalWrite(Servo_3_Rel_1, LOW); digitalWrite(Servo_3_Rel_2, LOW); digitalWrite(Servo_4_Rel_1, LOW); digitalWrite(Servo_4_Rel_2, LOW); digitalWrite(Servo_5_Rel_1, LOW); digitalWrite(Servo_5_Rel_2, LOW); digitalWrite(Servo_6_Rel_1, LOW); digitalWrite(Servo_6_Rel_2, LOW); digitalWrite(Servo_7_Rel_1, LOW); digitalWrite(Servo_7_Rel_2, LOW); digitalWrite(Servo_8_Rel_1, LOW); digitalWrite(Servo_8_Rel_2, LOW);}



    So - ich hoffe für dem einen oder anderen eine Anregung gegeben zu haben.
    Bei Fragen stehe ich gerne zur Verfügung.


    Gruß Ralf

  • Hallo,


    sehr schöner sauberer Aufbau ... ich empfinde das jetzt allerdings irgendwie als "Materialschlacht". Um die Switch-Piloten anzusteuern, hätten doch auch Optokoppler gereicht (?). Oder das Servo-Signal ließe sich direkt über den Arduino generieren (dann wäre ggf. noch das Problem der Kabellänge zu den Servos). Momentan spielt der Arduino nur Diodenmatrix ? Oder habe ich da was übersehen ?


    Viele Grüße, Bodo

  • Hallo Bodo,


    viele Wege führen nach Rom... . Da hast Du sicher recht. Je nach persönlicher Neigung sind die Wege halt auch unterschiedlich schön.


    Ich kann sehr gut verstehen, dass Ralf die Sache mit einem Microcontroller gemacht hat... :-)


    Eine Optimierung wäre, besonders wenn man die Weichenstellung im Bhf. mit Seilzügen darstellt, die Weichen langsam nacheinander schalten zu lassen. Eine Wartezeit zwischen den Schaltvorgängen ist schnell eingebaut.


    Zwei freie Ausgänge sind m.E. noch da. Eine Signalsteuerung könnte noch mit eingebunden werden.


    ------------
    Hallo Ralf,


    Warum hast Du zwei Relais pro Weiche gebraucht? Haben die vorhandenen Relais keine Öffener oder Wechselkontakte?



    Gruß aus dem Süden,
    Bernd

    Schreibt mir ruhig bei Fragen und Anmerkungen. Ich bin meist recht umgänglich... :P

  • Hallo Bernd,


    klar macht der Arduino Sinn - lässt sich ja ggf. auch viel flexibler anpassen, als später mal an der Diodenmatrix was zu ändern. Und wenn die Switchpiloten schon installiert sind, kann man sie ja auch so verwenden, wie sie sind. Aber dann hätten m.E. zum Ansteuern der Switchpilot-Eingänge eben ein paar Optokoppler statt der Transistoren und Relais ausgereicht.


    Neu kaufen würde ich (also ich für mich - nicht als Empfehlung für andere ...) heute gar keine fertigen Bausteine mehr, weil sich irgendwie alles recht flexibel in dem Mikrocontroller unterbringen lässt - von der Ansteuerung der Servos bis zur Decodierung des DCC-Signals. Dass es immer auch Gründe für den Einsatz von Fertigbausteinen gibt, will ich gar nicht bestreiten - schließlich kann man auch mit der Programmierung eine Menge Zeit verbringen, die dann woanders fehlt ;-).


    Viele Grüße, Bodo

  • Hallo,


    Bodo:
    Optokoppler wären eine feine einfache Sache gewesen.
    Leider weist ESU daraufhin, dass die Eingänge potentialfrei angesteuert werden müssen, also über Schalter (die jeweiligen Pins überbrücken). Somit fällt der Optokoppler leider flach.


    Materialschlacht? Vielleicht - aber dafür bin ich flexibel mit Änderungen. Einfach PC anstöpseln und umprogrammieren...


    Außerdem habe ich noch 22 Pins frei, um noch Weiteres einzubauen.


    Bernd:
    Zu deiner Frage - ich benutze die Relais als "Taster". Die bekommen nur solange Strom, wie die Bedientaster gedrückt sind. Ich will nicht unnötig die Relais unter Dauerstrom halten. Darum brauche ich 2 pro Servo.
    Ist vielleicht Overkill, aber ich habe hier 30 dieser Relais seit Jahren rumliegen. Jetzt sind sie teilweise endlich im Einsatz.


    Gruß Ralf

  • Hallo


    Wunderbar!


    Als sich beim Ersten Österreichischen Eisenbahnmodellbauklub die Notwendigkeit ergab, auf der Spur-0-Anlage einen Bahnhof *) hinsichtlich der Steuerung der Weichen neu zu gestalten, war die erste Frage „wie mach’s man denn“.


    Gewünscht war ein Drucktastenstellpult mit Start/Ziel-Eingabe. Als Lösungsoptionen standen herkömmlich mit Diodenmatrix, eigener DCC-Bereich oder eigenständiger Mikroprozessor zur Diskussion. Gegen DCC sprachen die hohen Kosten und das Fehlen einer Stellpult-Lösung (wir fahren grundsätzlich analog, können aber auch digital, wenn jemand das Equipment anschließt); gegen die Diodenmatrix die fehlende Flexibilität und das Problem, später eine fahrstrassenabhängige Signalsteuerung dazuzubauen.


    So habe ich eine Mikroprozessorsteuerung aufgebaut, allerdings nicht mit einem Arduino oder Atmel, sondern ich bin einige Zeit vorher auf das britische Schul/Fortbildungssystem „PICAXE“ (http://www.picaxe.com/) gestoßen, aufgebaut auf die PIC-Prozessorfamilie, sehr simpel, programmiert wird in einem BASIC-Dialekt – und das System muss selbst zusammengelötet werden.


    Einziger Nachteil: Es gab keinen Chip mit genügend Ein/Ausgängen. Die Lösung war zwei Chips zu verwenden: der erste fragt die Stellpulttasten ab, stellt die Fahrstrasse fest und gibt diese als Zahl an den zweiten weiter, der dann die Weichenrelais **) steuert. Für die Signalsteuerung wird ein dritter Chip dazukommen, dem ebenfalls die Fahrstrasse mitgeteilt wird und der danach bei Eingabe zB von „Ausfahrt SÜD auf Frei stellen“ das der eingestellten Fahrstrasse entsprechende Signal stellt.


    Die folgenden Bilder zeigen das Schaltungsschema und das Aussehen der Schaltung (mit eingezeichneten Verbindungen und zur deutlicheren Darstellung noch ohne eingesteckte Chips).




    Kosten dieser Schaltung etwa € 20,-


    Mit freundlichen Grüßen aus Wien
    Helmut


    *) Unsere Anlage wird auf der ARGE-Hauptversammlung in Baden zu sehen sein, jedoch ohne diesen Bahnhof, der leider nicht transportabel ist.
    **) Zur Erklärung „Weichenrelais“: Dieses Relais schaltet den Weichenmotor, die Herzstückpolarisation und den Stromfluss in der Fahrstrasse und ist unter der Weiche/DKW montiert.

  • Hallo Christoph,


    Optokoppler ist ausgangsseitig ja ein Transistor. Somit muss ich in an einer Spannung betreiben und damit ist die Geschichte ja nicht mehr potentialfrei... (an den ESU- Eingängen)


    Ich kenne jetzt nicht die Eingangsbeschaltung der SwitchPilots, aber wenn es funktioniert um so besser.


    Hiermit bekunde ich äußerstes Interesse an eurer Schaltung (zwischen OK und ESU). Ich habe noch ähnliche Anwendungsfälle vor umzusetzen und da ziehe ich die OK-Lösung natürlich vor.


    Gruß Ralf

  • Hallo Ralf,


    ich hatte Deinen letzten Beitrag im Thread übersehen, tut mir leid. Hier ist die Ansteuerschaltung für den ESU Switch Pilot:




    Die Platine ist so designt, dass sie auf den Switch-Pilot direkt aufgesteckt werden kann. Die vordere Reihe der Ansteuerungs-Pins am Switch-Pilot führen Plus-Potential, diese sind mit den Kollektoren der Optokoppler verbunden. Wird ein Optokoppler mit einem positiven Impuls angesteuert, schaltet der Transistor durch und legt das Plus-Potential auf den Eingang des Switch-Pliloten - also wie mit einem Relais. Potentialfrei ist das Ganze, weil es keine elektrische Verbindung vom Eingang des Optokopplers zum Schalttransistor gibt. Alles klar?


    Die Eingänge für Schalter sind für manuelle Schalter, mit denen getestet werden kann. Auch Notbetrieb ist möglich, wenn die Fahrstraßenschaltung ausfällt. Wichtig bei Veranstaltungen. Die Widerstände sind bei 5V 330 Ohm, bei 12 V 680 Ohm.


    Wenn Du noch Fragen hast, bitte E-Mail.


    Gruß


    Christoph

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!