Weichensteuerung Schritt für Schritt

Hallo zusammen.

Ich bin absolut unfähig :smiley: = neu hier.... aber interessiert und motiviert.
Zur Zeit baue ich eine Modellbahn auf und verwende dort alte M-Gleis Weichen mit je 2 Spulenantrieben ohne Rückmeldung. Ich möchte eine Wechselgleis-Automatisierung im verborgenen Anlagenbereich einfügen.

Aufgabe:
Steuerung von 4 Gleisen (2 Fahrbereiche) und 2 Weichen mit 4 Reetkontakten (Taster) mit einem Uno (Elegoo) und einem 8-Wechselrelais-Board (Elegoo).
Dabei sollen je 2 Reets (Taster) im Wechsel den Gleisstrom via Relais steuern (Dauerkontakt) und die Weiche umwerfen (300ms)

Also für 2 Gleise:

Taster1 =HIGH //Lok löst kurz bei Überfahrt in Gleis1 den Reetkontakt aus, Gleis1 belegt
Relais1 (Strom für Gleis 1/2) = LOW (dauerhaft) //belegtes Gleis1 stromlos schalten, Lok steht,
damit wechselseitig Gleis 2 bestromt, eventuelle Lok fährt raus
Relais2 Weiche1 = HIGH (300ms) //eingehende Weiche wird auf bestromtes Gleis2 geschaltet

Das soll jetzt so bleiben, bis eine Lok in Gleis 2 einfährt, und dort den Reed auslöst:
Dann:
Taster2 =HIGH //Lok löst kurz bei Überfahrt in Gleis2 den Reetkontakt aus, Gleis2 belegt
Relais1 (Strom für Gleis 1/2) = HIGH (dauerhaft) //belegtes Gleis2 stromlos schalten, Lok steht,
damit wechselseitig Gleis 1 bestromt, eventuelle Lok fährt raus
Relais3 Weiche1 = 1 (300ms) //eingehende Weiche wird auf bestromtes Gleis1 geschaltet

Und das im Wechsel.
Unabhängig davon für den 2ten Fahrkreis mit Taster 3,4, Relais 4,5,6 das gleiche

Schematischer Aufbau:

===Relais1 (Gleisstrom1)====Taster1 (Reedkontakt1)====
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Relais 2,3 (Weiche1)=======
===Relais1 (Gleisstrom2)====Taster2 (Reedkontakt2)====


===Relais4 (Gleisstrom1)====Taster3 (Reedkontakt3)====
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Relais 5,6 (Weiche2)=======
===Relais4 (Gleisstrom2)====Taster4 (Reedkontakt4)====

Bisher habe ich die Taster definiert und an die PINs 2,3,4,5 gehängt und die Relais an die PINS 6,7,8,9,10,11.

Erster Teil: Ich finde nicht heraus, wie ich mit einem Tasterimpuls das Relais1 dauerhaft und das Relais2 gleichzeitig nur für 300ms schalten kann.
Zweiter Teil: Der Taster2 muss dann Relais1 abschalten und Relais 3 für 300ms betätigen.

Alles, was ich bisher erreicht habe, sind dauerhaft geschaltete Relais oder per delay alle 300ms umschaltend. Wenn die Steuerung von 2 Kreisen gleichzeitig nicht machbar/zu kompliziert ist, nehme ich dazu auch noch einen weiteren Arduino und ein weiteres Relaisboard...
Habt Ihr Tips für mich zur Umsetzung?

Zu Randbedingungen wie Erkennen von Stellungen bei Neustart oder sicherer Neustart gerne später... Ich würde wahrscheinlich Schalter in Reihe zum Gleisstrom setzen und einzeln manuell starten...

Die Frage ist, ob du diesen Zustand beibehalten möchtest....

Ich weiß, das sagt uns die Forensoftware auch.

Was du da beschreibst, scheint mir das klassischen Bild einer Ablaufsteuerung zu sein. Eines endlichen Automaten.

Für die Zeit Steuerung solltest du dir die Nachtwächter Erklärung mal durchlesen.

Hallo combie.
Danke für den Link. Ich schaue mir das an. Bei Rothschopf habe ich es ehlich noch nicht verstanden.

Nö... :smiley:

Viele Grüße, Michael

Hallo Michael,
speziell für uns Modellbahner habe ich mal im Stummiforum ein Tutorial für Ablaufsteuerungen und Programmierung ohne delay geschrieben.
Tommy hat das in komprimierter Form als PDF auf seiner Webseite gehostet.
Vielleicht hilft dir das weiter.
P.S. Die Beispielsketche dazu sind auch bei Tommy zu finden.

Hi MicroBahner.
Da ich dort auch herumstreune, werde ich mir das ganz sicher parallel auch ansehen. Vielen Dank für die Links!
Ich habe hier jetzt so viel Input bekommen... werde daheim erstmal etwas spielen müssen :wink:
Liebe Grüße, Michael

Besonders im Norden Deutschlands kennt man das Reetdach, das aber mit dem Reed-Relais wenig gemein hat, außer man vergleicht die beweglichen Halme mit den Kontakten.

Schau mal im Thema Millis Befehl, Steuerung Schattenbahnof., ob Du da nützliche Hinweise findest.

Hi Agmue,
danke für den Link. Den werde ich mir auch anschauen. Mir raucht schon die Rübe :woozy_face:
Den Einsatz von Reethalmen statt Reed-Schaltern halte ich auch mal für eher wenig zielführend. Hast Recht :smiley:
Liebe Grüße, Michael

... damit unfähig in fähig wechselt :roll_eyes:

Die arbeiten häufig mit aktiv=LOW, da muß man aufpassen.

Die UNOs haben eingebaute PullUp-Widerstände, weshalb die Reedkontakte gegen GND schalten sollten, also aktiv=LOW.

Der Uno wird sich langweilen!

dann könntest du die Gelegenheit packen, darzulegen was du gelesen hast (Seite verlinken) , was genau du nicht verstanden hast, und wie man dir vieleicht konkret weiterhelfen kann.

Ich glaube auf der Seite geht es nicht so sehr um Modellbahn. Aber eins weis ich ganz sicher: da steht: zeichne den Ablauf auf. Visualisiere was in welchen Schritten geschehen soll. Wenn der Ablaufplan fest steht, mach dich an die Programmierung. Aber zunächst: Wo ist dein Ablaufplan?

lg
Werner

Hallo.

Sorry, hat etwas gedauert. Ich bin recht eingespannt.
Ich habe trotzdem einiges gelesen, Code geklaut und zusammen geschnipselt.... vielleicht auch ein bisschen was gelernt. Testen konnte ich das noch nicht, immerhin kommt keine Fehlermeldung :smiley:
Ich habe zwar ein einfaches Testfeld mit Reeds und LEDs aufgebaut, aber noch nicht angeschlossen. Kommt wohl morgen.

Zur Skizze: Ich glaube, das habe ich entweder nicht verstanden, oder oben schon falsch versucht.
Ich habe 2 Gleise, die von einer Weiche abgehen. Zug kommt von links:

Gleis1=====Schaltbereich====Reedrelais====
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Weiche.....<= Zug einfahrend
Gleis2=====Schaltbereich====Reedrelais====

Der Zug überfährt das Reed, der Schaltbereich wird abgeschaltet (Zug hält dann dort) und die Weiche auf das andere Gleis gestellt. Das immer im Wechsel und in 2 Blöcken (Fahrkreisen) unabhängig
Grenzen (An/Aus/Fehler...) habe ich noch nicht betrachtet.

So schaut der Code bis jetzt inklusive bestimmt überflüssiger Dinge aus:

//Wechselsteuerung je 2-Gleisig in 2 Fahrkreisen Blöcken
//Entprellung bei   scynd.de/tutorials/arduino-tutorials/1-taster/1-2-taster-entprellt.html
// und bei  michaelsarduino.blogspot.com/2015/08/button-entprellen.html


// Taster (Reedrelais) Zugerkennung
const int T1 = 12;    //Taster1, Gleis1 Zugerkennung, an Pin 12
const int T2 = 11;    //Taster2, Gleis2 Zugerkennung, an Pin 11
const int T3 = 10;    //Taster3, Gleis3 Zugerkennung, an Pin 10
const int T4 = 9;     //Taster4, Gleis4 Zugerkennung, an Pin 9

int T1State = LOW;    //aktueller Status T1 OFF    HIER SCHON INVERTIERT?
int T2State = LOW;
int T3State = LOW;
int T4State = LOW;

int T1ON = 0;         //abfragen, ob Taster gedrückt wurde
int T2ON = 0;
int T3ON = 0;
int T4ON = 0;

int entprellZeit = 300;   //Entprellzeit für Taster, anpassen bis Funktion sicher

unsigned long T1Zeit = 0; //Zeit beim Drücken des Tasters
unsigned long T2Zeit = 0;
unsigned long T3Zeit = 0;
unsigned long T4Zeit = 0;


// Relais Block1
const int G1G2 = 8; //Relais für Stromumschaltung Gleis1 zu Gleis2, Test LEDweiß
const int W11 = 7;  //Relais für Weiche11 geradeaus, LEDgrün
const int W12 = 6;  //Relais für Weiche12 abbiegend, LEDgelb
int G1G2State = 0;  //Relais für Stromumschaltung OFF, Gleis1 hat Strom(grün)
int W11State = 0;   //aktueller Status Spule Weiche11 OFF
int W12State = 0;   //aktueller Status Spule Weiche12 OFF

//Relais Block2
const int G3G4 = 5; //Relais für Stromumschaltung Gleis3 zu Gleis4, Test LEDweiß
const int W23 = 4;  //Relais für Weiche23 geradeaus, LEDgrün
const int W24 = 3;  //Relais für Weiche24 abbiegend, LEDgelb
int G3G4State = 0;  //Relais für Stromumschaltung OFF, Gleis3 hat Strom(grün)
int W23State = 0;   //aktueller Status Spule Weiche23 OFF
int W24State = 0;   //aktueller Status Spule Weiche24 OFF


//Variablen Ausgänge zu Relais für Weichen
bool geschaltetW11 = false; //Variable Weiche1 geradeaus auf G1
bool geschaltetW12 = false; //Variable Weiche1 abbiegen auf G2
bool geschaltetW23 = false; //Variable Weiche2 geradeaus auf G3
bool geschaltetW24 = false; //Variable Weiche2 abbiegen auf G4

int empfindlichkeit = 200;

unsigned long TW11_timestore; //Variable Speicher für Systemzeit T an W11
unsigned long TW12_timestore; //Variable Speicher für Systemzeit T an W12
unsigned long TW23_timestore; //Variable Speicher für Systemzeit T an W23
unsigned long TW24_timestore; //Variable Speicher für Systemzeit T an W24


//Funktion zum Schaltimpuls mit dem bösen DELAY
void Schaltimpuls(byte pin)
{
  digitalWrite (pin, HIGH);
  delay (300);                    //300ms Schaltdauer für Spulen Weichenantriebe
  digitalWrite (pin, LOW);
}

void setup()                    //Definition Eingang - Ausgang
{
  pinMode(T1, INPUT_PULLUP);      //Achtung, PULLUP invertiert LOW HIGH
  pinMode(T2, INPUT_PULLUP);
  pinMode(T3, INPUT_PULLUP);
  pinMode(T4, INPUT_PULLUP);
  pinMode(G1G2, OUTPUT);
  pinMode(W11, OUTPUT);
  pinMode(W12, OUTPUT);
  pinMode(G3G4, OUTPUT);
  pinMode(W23, OUTPUT);
  pinMode(W24, OUTPUT);
}


void loop()
{

  //Block1 Gleis1
  // Lesen des tasterPin
  T1State = digitalRead(T1);

  // Zug auf Gleis 1 betätigt Reed T1:
  if (T1State == LOW)
  {
    T1Zeit = millis();    //aktuallisiere Tasterzeit (entprellen)
    T1ON = 1;           //speichert, dass der Taster gedrückt wurde
  }
  // wenn entprellZeit um und Taster gedrückt war…
  if ((millis() - T1Zeit > entprellZeit) && T1ON == 1)
  {
    Schaltimpuls(W12);         //Weiche schaltet auf G2
    digitalWrite(G1G2, HIGH);  //G1 stromlos, G2 Strom
    T1ON = 0;                  //setzt gedrückten Taster zurück
  }

  //Block1 Gleis2
  T2State = digitalRead(T2);
  if (T2State == LOW)
  {
    T2Zeit = millis();
    T2ON = 1;
  }
  if ((millis() - T2Zeit > entprellZeit) && T2ON == 1)
  {
    Schaltimpuls(W11);
    digitalWrite(G1G2, LOW);
    T2ON = 0;
  }

  //Block2 Gleis3
  T3State = digitalRead(T3);
  if (T3State == LOW)
  {
    T3Zeit = millis();
    T3ON = 1;
  }
  if ((millis() - T3Zeit > entprellZeit) && T3ON == 1)
  {
    Schaltimpuls(W24);
    digitalWrite(G3G4, HIGH);
    T3ON = 0;
  }

  //Block2 Gleis4
  T4State = digitalRead(T4);
  if (T4State == LOW)
  {
    T4Zeit = millis();
    T4ON = 1;
  }
  if ((millis() - T4Zeit > entprellZeit) && T4ON == 1)
  {
    Schaltimpuls(W23);
    digitalWrite(G3G4, LOW);
    T4ON = 0;
  }
}

Bei den Reedrelais habe ich festgestellt, dass die auslösende Lok 2 Impulse verursacht. Ich denke, dass liegt daran. das ich den TestReed an den Mittelleiter vom M-Gleis geklebt habe und die vorstehenden Puks des Leiterstrangs das Magnetfeld an ihrer Position verstärken.
Also habe ich versucht, die Reedrelais zu entprellen.

Da sind Millis drin.
Ich denke, ich probiere das auch mal als Schaltzeitbegrenzung bei den Weichenantrieben.

Es ist Dein Projekt :slightly_smiling_face:

Ich empfehle Strg+T zum Formatieren in der IDE und code-Tags für das Programm:

Hier Dein Programm!

Eine Schrittkette (=endlicher Automat, =finite state machine) könnte Dir helfen.

Moin.
Die Code Tags hatte ich gesetzt, wie in html... Sieht trotzdem blöd aus. Muss ich noch etwas machen?
EDIT war da: Ja, wenn ich gleich eckige Klammern genommen hätte, hätte das auch geklappt :smiley:
Strg+T hab ich jetzt auch ausgeführt.

Danke!

Schrittkette lese ich mich noch ein. Habe ehrlich noch Probleme mit der Logik.

Die roten LEDs im Test kann ich mir auch schenken, diese werden ja nicht angesteuert, wenn ich die Relais G1G2 & G3G4 als Umschalter verwende und die Spannung dort abfällt. Sag ja...bei der Logik hakt es.

Also...mit LEDs hat das geklappt.
Mit dem Relaisboard nicht. Im Moment kämpfe ich mit den Variablen, bekomme die Relais aber nach Neustart nicht im OFF. Sie sind aktiviert und somit würden Weichenantriebe durchbrennen. Und das bei stromlosem Arduino, wie auch bei startendem Arduino.
Im Moment muss ich alle Reeds einmal betätigen, dann läuft es. Ich finde den Fehler nicht.
Bin ja auf Suche...aber habt ihr einen Tipp?

Sieht gleich viel besser aus :slightly_smiling_face:

Nach Reset werden Ausgänge mit LOW initialisiert, wenn Du es nicht explizit anders möchtest. Probiere mal dies:

  digitalWrite(G1G2, HIGH);
  pinMode(G1G2, OUTPUT);

So scheint mir das besser:

//Funktion zum Schaltimpuls mit dem bösen DELAY
void Schaltimpuls(byte pin)
{
  digitalWrite (pin, LOW);        //Ein
  delay (300);                    //300ms Schaltdauer für Spulen Weichenantriebe
  digitalWrite (pin, HIGH);       //Aus
}

Hi Shannon.
Genial! Danke!
Die Drehung im "Schaltimpuls" hatte ich versucht und warumauchimmer hat das nicht funktioniert.
Aber die Drehung vor der OUTPUT Definition im Setup funktioniert perfekt. Da wäre ich nie drauf gekommen:


void setup()                    //Definition Eingang - Ausgang
{
  pinMode(T1, INPUT_PULLUP);      //Achtung, PULLUP invertiert LOW HIGH
  pinMode(T2, INPUT_PULLUP);
  pinMode(T3, INPUT_PULLUP);
  pinMode(T4, INPUT_PULLUP);
  digitalWrite(G1G2, HIGH);
  pinMode(G1G2, OUTPUT);
  digitalWrite(W11, HIGH);
  pinMode(W11, OUTPUT);
  digitalWrite(W12, HIGH);
  pinMode(W12, OUTPUT);
  digitalWrite(G3G4, HIGH);
  pinMode(G3G4, OUTPUT);
  digitalWrite(W23, HIGH);
  pinMode(W23, OUTPUT);
  digitalWrite(W24, HIGH);
  pinMode(W24, OUTPUT);
}

Das, was mich jetzt noch stört, ist die Lösung mit dem Delay im Schaltimpuls. Das ist zwar nur 1/3 Sekunde und wenn der Arduino wegen der Zeit keinen Reedimpuls verarbeiten kann, fährt der betreffende Zug eben einfach durch...aber ich denke, ich werde da auch einmal eine Lösung mit Millis probieren einzusetzen.

Ich habe inzwischen Teile des Codes ausgeklammert, die keine Funktion haben:

/*
//Variablen Ausgänge zu Relais für Weichen
bool geschaltetW11 = false; //Variable Weiche1 geradeaus auf G1
bool geschaltetW12 = false; //Variable Weiche1 abbiegen auf G2
bool geschaltetW23 = false; //Variable Weiche2 geradeaus auf G3
bool geschaltetW24 = false; //Variable Weiche2 abbiegen auf G4

int empfindlichkeit = 200;

unsigned long TW11_timestore; //Variable Speicher für Systemzeit T an W11
unsigned long TW12_timestore; //Variable Speicher für Systemzeit T an W12
unsigned long TW23_timestore; //Variable Speicher für Systemzeit T an W23
unsigned long TW24_timestore; //Variable Speicher für Systemzeit T an W24
*/

Vielleicht finde ich ja raus, was damit bezweckt worden ist. Die "unsignedLong" werde ich für die Millis der Weichen brauchen. Aber bools? Und empfindlichkeit? Ich lerne... :smiley:

Hallo
Da du ein größeres Projekt in Arbeit hast möchte ich dir dazu das Studium des EVA-Prinzips nahelegen, auch wenn alles schon mal 'betrachtet' worden ist.
Hier kommt die Kurzversion:
E=Eingabe -> alle Eingangssignale einlesen
V=Verarbeitung -> alle Eingangssignale miteinander verarbeiten und daraus die Ausgangszustände erzeugen, aber nicht ausgeben.
A=Ausgabe -> aber nun, die oben erzeugten Ausgangszustände, evt. zeitlich bedingt, ausgeben.
Viel Erfolg

Das wirst Du mit der Schrittkette los.

Mal ein Beispiel:

int T1State = LOW;
...
T1State = digitalRead(T1);

Der Typ int braucht auf dem UNO 16 Bits und beherbergt eigentlich vorzeichenbehaftete Werte. Für LOW und HIGH braucht es aber nur ein Bit, da genügt der Typ bool. OK?

Hast Du in Deinem Schattenbahnhof nur diese zwei Weichen, die Du so steuern möchtest, oder gäbe es da noch mehr?

1 Like

na dann schmeiss weg dein delay und arbeite nach dem Mutter aller Sketche "BlinkWithoutDelay".
Leider verwendest du noch keine Arrays daher schreibst du auch viel doppelten Code.
Daher braucht es noch einen kleinen Helfer um von Pins auf einen Array Index zu kommen.

das folgende ersetzt deine alte Funktion Schaltimpuls.
die Funktion abschalten() musst du so oft wie möglich aufrufen, also nicht vergessen, im loop aufrufen und keine weiteren delays verwenden.

const byte weichenPin[] {W11, W12, W23, W24};
const byte anzahlWeichen = sizeof(weichenPin)/sizeof(weichenPin[0]); // sicherheitshalber solange die Variablengröße noch nicht gesäubert sind...
uint32_t previousMillis[anzahlWeichen];

byte pin2index(byte pin)                  // suche Pin im Weichen Array
{
  for (byte i = 0; i < anzahlWeichen; i++)
  {
    if (pin == weichenPin[i]) return i;
  }
  return 255; // nicht gefunden
}

void Schaltimpuls(byte pin)                // schaltet Weichenantrieb ein
{
  byte index = pin2index(pin);
  digitalWrite (pin, HIGH);
  previousMillis[index] = millis();
}

void abschalten()                          // schaltet Weichenantriebe nach Zeitablauf ab
{
  uint32_t currentMillis = millis();
  for (byte i = 0; i < anzahlWeichen; i++)
  {
    byte currentPin = weichenPin[i];
    if (digitalRead(currentPin) == HIGH && currentMillis - previousMillis[i] > 300) digitalWrite(currentPin, LOW);
  }
}

Sketch mal nur mit LEDs probieren gell :wink: - denn ich habe keine Hardware zum Testen.
p.s.: prüfe JEDE deiner Variablen ob dafür wirklich ein int notwendig ist, oder nicht auch schon 1 Byte Variablen reichen!
p.s.s: schalte die Compiler-Warnungen in der Arduino IDE ein, dein Code wirft ein Warning wegen Vergleich signed / unsigned.

Moin Werner,
darf ich noch eine kleine defensive Sicherheitsabfrage zusätzlich vorschlagen?
pin2index() bereitet das ja passend vor...

void Schaltimpuls(byte pin)                // schaltet Weichenantrieb ein
{
  byte index = pin2index(pin);
  if (index < 255) 
  {
    digitalWrite (pin, HIGH);
    previousMillis[index] = millis();
  }
}

Gruß Walter

immer.
du könntest auch gegen eine echten Pin im Array weichenPin prüfen...

Aber eigentlich sollte man den ganzen Sketch ein wenig zusammenräumen..