Modellbahn-Basteleien Teil2

sorry, das machte man doch noch vor digital schon gefühlt 30 Jahre so, dass man vor einem Haltesignal eine Bremstrecke hat und zu Beginn der Bremsstrecke runterbremmst und man musste dafür sorgen, dass die Bremstrecke für den langsamsten Bremser = längster Halteweg immer ausreicht. Das ist doch wirklich nichts neues in der alten Modellbahn!

@schorsch55: Genau so ist meine Vorstellung. Problematisch wird es bei der Rückwärtsfahrt, wenn der letzte Wagen keinen Magneten hat.

Ich hoffe Du verstehst, worum meine Gedanken kreisen :thinking:

Richtig und wir schreiben aneinander vorbei??? Etwas anderes soll doch mein H1 nicht machen, Bremsvorgang auslösen bis zum Halt =0. Wozu dann noch ein extra H2?

Und wieso Rangierfahrt und dann Rangierfahrt auf 0 und nicht gleich bei H1 Runterbremsen bis 0? Ich verstehe diesen Gedankengang nicht, vielleicht bin ich auch schon auf Rangierfahrt???

Kleine Rangiergeschwindigkeit bedeutet kurzer, gut kalkulierbarer Bremsweg ohne Justiernotwendigkeit.

bevor ich es lösch'

ein einfacher "Modellbahntrafo" zum Anfangen:

Leute ohne Hardware (Loks) können auf der Seriellen Schnittstelle mitschauen was passiert...

/*
  https://forum.arduino.cc/t/modellbahn-basteleien-teil2/876508/74
*/

class Controller {
  protected:
    const byte inAPin;           // GPIO to in 1
    const byte inBPin;           // GPIO to in 2
    const byte pwmPin;           // GPIO to EN
    const byte interval = 5;     // low value = fast acceleration
    uint32_t previousMillis = 0;
    byte speed = 0;              // Sollgeschwindigkeit
    byte currentSpeed = 0;       // aktuelle Geschwindigkeit
    int8_t dir  = 1;             // 1 Vowärts, -1 Rückwärts;

  public:
    Controller (byte inAPin, byte inBPin, byte pwmPin) :
      inAPin{inAPin},
      inBPin{inBPin},
      pwmPin{pwmPin}
    {}

    void begin()
    {
      pinMode(inAPin, OUTPUT);
      pinMode(inBPin, OUTPUT);
      pinMode(pwmPin, OUTPUT);
    }

    void setSpeed(byte newSpeed)
    {
      speed = newSpeed;
      if (speed > 0)
      {
        setDirection(dir);   // falls der Motor abgeschaltet wäre, wieder einschalten
      }
    }

    void setDirection(int8_t newDirection)   
    {
      // Könnte man noch absichern dass das nur bei currentSpeed==0 möglich ist:
      dir = newDirection;
      if (dir == 1)
      {
        digitalWrite(inAPin, LOW);
        digitalWrite(inBPin, HIGH);
      }
      else if (dir == -1)
      {
        digitalWrite(inAPin, HIGH);
        digitalWrite(inBPin, LOW);
      }
    }

    void setForward()   // damit sich der Anwender nicht (1) merken muss
    {
      setDirection(1);
    }

    void setBackward()  // damit sich der Anwender nicht (-1) merken muss
    {
      setDirection(-1);
    }

    void emergencyOff()
    {
      Serial.println(F("emergency off"));
      digitalWrite(inAPin, LOW);
      digitalWrite(inBPin, LOW);
      analogWrite(pwmPin, 0);
      speed = 0;
      currentSpeed = 0;
    }

    void run()
    {
      uint32_t currentMillis = millis();
      if (currentMillis - previousMillis > interval)
      {
        if (speed > currentSpeed)
        {
          currentSpeed++;
          analogWrite(pwmPin, currentSpeed);
          Serial.print(F("currentSpeed=")); Serial.println(currentSpeed);
        }
        if (speed < currentSpeed)
        {
          currentSpeed--;
          analogWrite(pwmPin, currentSpeed);
          Serial.print(F("currentSpeed=")); Serial.println(currentSpeed);
        }
        previousMillis = currentMillis;
      }
    }
};

Controller trafoA(9, 8, 10);  // trafo definieren, Pins übergeben)

// demobuttons
const byte startPin = A0;
const byte fastPin = A1;
const byte stopPin = A2;
const byte emergencyPin = A3;

void setup() {
  Serial.begin(115200);
  trafoA.begin();

  pinMode(startPin, INPUT_PULLUP);
  pinMode(fastPin, INPUT_PULLUP);
  pinMode(stopPin, INPUT_PULLUP);
  pinMode(emergencyPin, INPUT_PULLUP);

  trafoA.setSpeed(200);  // irgend eine Geschwindigkeit als Beispiel zum anfangen
}

void loop() {
  trafoA.run();
  if (digitalRead(startPin) == LOW) trafoA.setSpeed(50);
  if (digitalRead(fastPin) == LOW) trafoA.setSpeed(255);
  if (digitalRead(stopPin) == LOW) trafoA.setSpeed(0);
  if (digitalRead(emergencyPin) == LOW) trafoA.emergencyOff();
}

NICHT löschen, bist du des Wahnsinns??!! Ich habe es erstmal nur überflogen, aber da steckt doch alles drin, was solche Experten wie ich, brauchen. Ist für einen Motor (Lok) mit einer H-Bridge (L298N), richtig? Also ich werde es speichern und mit deiner frdl. Erlaubnis für unsere bedarften Z-Bahner auskommentieren und zur Anregung weiter reichen. Die sollen ja auch was zum Mitdenken kriegen. Danke

probiers mal mit Hardware aus ... ich bin da im Blindflug unterwegs.
hab grad gesehen, da war im emergencyOff zweimal der gleiche Pin, das musst du nachbessern.
Genau deswegen braucht es Tests mit Hardware.

Wenns klappt kann man es ja mal auf eine einfache Pendelzugsteuerung erweitern. Aber zunächst muss der einfache "Trafo" funktionieren, sonst macht es keinen Sinn.

@schorsch55 kannst du mir dazu bitte Feedback geben:

der Pendelzug fährt nämlich auch schon - nur ohne dem ersten Schritt zeige ich das nicht.

Mach ich und Blindflug ist mein 2. Vorname. Ich berichte..

Hallo,

wenn ich einen Kommentar abgeben darf.

Man benötigt dringend einen Hallsensor an der Position wo der Zug auch wirklich stoppen soll. Man kann nicht davon ausgehen das nach Beginn eines Bremsvorgangs der Zug immer an der gleichen Stelle hält. Auch reagieren verschiedene Loks sehr unterschiedlich und auch die gleiche Lok je nachdem ob kalt oder warm gefahren verhält sich unterschiedlich. Leite den Bremsvorgang mit H1 ein, bremse ihn sanft aber sicher runter bis auf Kriechgeschwindigkeit. Wenn H2 erreicht einfach stoppen. Das ist auch die letzte Chance überhaupt einen Zug zu stoppen.

Desweiteren solltest du dir noch Gedanken mit dem Signal von den Hallsensoren machen. Denn wenn die Züge einmal von links und einmal von rechts reinfahren, dann ist ja dessen Bedeutung anders. Dann würde ein Zug bei H2 ja sofort stoppen und der Rest steht außerhalb vom Bahnhof.

Ich habe das auf meiner Teststrecke wie folgt gelöst. Ich habe immer generell 2 Hallsensoren Paarweise in den Schwellen versenkt. Der Magnet kann beide Hallsensoren überdecken. Damit habe ich mir praktisch einen Gray Encoder gebaut. Ich weiß beim überfahren des Hallsensorpaares immer aus welcher Richtung sie überfahren werden. Auch günstig wenn man Schranken auf der Strecke steuern möchte.

Desweiteren habe ich alle Loks ausgemessen bezüglich Geschwindigkeit. Wie schnell fährt welche Lok mit welchen PWM Duty Cycle. Das habe ich umgerechnet damit jede Lok Maßstabsgetreu ihre Vmax fahren kann. Die Daten habe ich hinterlegt. Jetzt weiß ich genau bei welchen Duty Cycle welche Lok wie schnell fährt. Im warm gefahrenen Zustand versteht sich. Das heißt ich kann beim einfahren in den Bahnhof fast immer präzise bis kurz vorm endgültigen Stopp runterbremsen. Das letzte Stück an Kriechstrecke ist damit als letzter Puffer kurzgehalten.

Noch ein Gedanke. Wenn man die Richtung des Zuges kennt, kann man auch wunderbar die Weichen schalten die da so voraus auf der Strecke liegen.

Ein Bahnhofsgleis kann von links und rechts, vorwärts wie rückwärts befahren werden, steht im Plan von @schorsch55 . Wenn nur die Lok einen Magneten hat, weiß ich nicht, wie ein Halt zu realisieren wäre.

Hast Du eine aus der Praxis geborene Idee?

... und er will in einige Abstellgleise einfahren.
... und die Lock ist nicht immer vorne in Fahrtrichtung.
Imho braucht es kurz vorm Puffer eine Lichtschranke (oder einen weiteren Magneten am letzten Wagon (oder viele ausgemessene "Timer").

Falls ich es überlesen habe, sorry, aber was verwendet ihr als Hallsensor?

@schorsch55: So, wie Du es derzeit planst, wird es m. E. nicht funktionieren.

Bevor Du Deine komplette Anlage angehst, braucht es daher eine Teststrecke, wo Du die Abläufe, besonders das Anhalten, genau studierst!

@Doc_Arduino

Du musst, weil immer gut. Also das Prinzip habe ich verstanden und werde es so umsetzen, 1 Hall für Bremsen und der 2. für definiertes Halt.

Das ist cool,habe ich so noch nicht betrachtet. Kannst du da mal ein Beispiel zeigen, von den gemessenen und dann umgerechneten Daten einer Lok?

Das ist so auch geplant. Nach dem Stopp-Hall (so heißt der jetzt), und der Warten-Zeit, soll der nächste Zyklus ausgelöst werden,. Entsprechend die dazugehörigen Weichen und Strom/Spannungsabschnitte (hier noch mal der Plan)


Die Halls sind ja auch nach der 2-er Variante schon da, müssen nur entsprechend weiter positioniert werden.
@noiasca
genau da wird es kompliziert. Denn spätestens wenn ich mal ein Gleis rückwärts befahre, muss ich den Hallsensor am ausfahrenden Gleis irgendwie ignorieren??!!
Ich verwende momentan Hallsensor A3144 https://www.elecrow.com/download/A3141-2-3-4-Datasheet.pdf.
Der hat den Vorteil, das er beide Magnetpole erkennt, also bipolar, no-latching. Das könnte man evt. nutzen, in dem man die Magneten unterschiedlich mit dem Pol zum Sensor ausrichtet, oder die Halls unterschiedlich einbaut, N/S-Seite jeweils. Mein Gott (ob der hilft??) ist das schlimm, wird ja immer schlimmer. Habe ich gerade mit

/*
  DC-Motorsteuerung mit L298N zum Regeln
  von Anfahr- und Bremsverhalten mit 2 Hallsensoren,
  mit Pause  zwischen dem Brems- und Anfahrstart
  von Schorsch für ZFI
  23.05.21
*/

// Definition Hallpins und Hallstatus
const int hallSensorPin = 2;
const int hallSensorPin2 = 3;
bool hallStatus = LOW;     // 1. Hall aktiv
bool hallStatus2 = HIGH; // 2. Hall paasiv

// Gleichstrommotor 1
const byte GSM1 = 10;
const byte in1 = 9;
const byte in2 = 8;

// Gleichstrommotor 2
const byte GSM2 = 5; //IN B
const byte in3 = 7; // IN 3
const byte in4 = 6;  // IN 4
unsigned long anfang = 0;
const unsigned long warte = 2000; //Pause zwische M1 und M2 im Loop
void setup()
{
  Serial.begin(9600);
  pinMode(GSM1, OUTPUT);
  pinMode(GSM2, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  pinMode(hallSensorPin, INPUT);
  pinMode(hallSensorPin2, INPUT);
  if (hallStatus == LOW)
  { // Beschleunigen M1 als Zustand nach Einschalten
    for (int i = 0; i <= 240; i += 40) //in 40-iger Schritten bis Maximalgeschwindigkeit
    {
      digitalWrite(in1, HIGH);
      digitalWrite(in2, LOW);   // Motor 1 beginnt zu rotieren
      analogWrite(GSM1, i); // Motor 1 beschleunigt
      delay(100); // delay(100) steuert die Geschwindigkeit des Hochzählens im for
    }
  }
}
void HALL1A() // Funktion für Hallsensor1
{
  // Bremsen M2
  if (hallStatus == LOW)
  {
    for (int i = 240; i >= 0; i -= 40) //in 40-iger Schritten bis Maximalgeschwindigkeit
    {
      digitalWrite(in3, HIGH);
      digitalWrite(in4, LOW);   // Motor 2 beginnt zu rotieren
      analogWrite(GSM2, i); // Motor 2 bremst
      delay(500);
    }
  }
  // Beschleunigen M1
  if (hallStatus == LOW)
  {
    anfang = millis();
    while (millis() - anfang < warte); //nach dem Bremsen M1 warten=Halt, dann
    for (int i = 0; i <= 240; i += 40) //in 40-iger Schritten bis Maximalgeschwindigkeit
    {
      digitalWrite(in1, HIGH);
      digitalWrite(in2, LOW);   // Motor 1 beginnt zu rotieren
      analogWrite(GSM1, i); // Motor 1 beschleunigt
      delay(100);
    }
  }
}
void HALL1B() //Funktion für Hallsensor 2
{
  // Bremsen M1
  if (hallStatus2 == LOW)
  {
    for (int i = 240; i >= 0; i -= 40) //in 40-iger Schritten bis Maximalgeschwindigkeit
    {
      digitalWrite(in1, HIGH);
      digitalWrite(in2, LOW);   // Motor 1 beginnt zu rotieren
      analogWrite(GSM1, i); // Motor 1 bremst
      delay(500);
    }
  }
  anfang = millis();
  while (millis() - anfang < warte);
  // Beschleunigen M2
  if (hallStatus2 == LOW)
  {
    for (int i = 0; i <= 240; i += 40)
    { //in 40-iger Schritten bis Maximalgeschwindigkeit
      digitalWrite(in3, HIGH);
      digitalWrite(in4, LOW);   // Motor 2 beginnt zu rotieren
      analogWrite(GSM2, i); // Motor 2 beschleunigt
      delay(100);
    }
  }
}
//=============================
void loop()
{
  hallStatus = digitalRead(hallSensorPin);
  hallStatus2 = digitalRead(hallSensorPin2);
  HALL1A();
  HALL1B();
}

getestet, Magnet verpolt, auf Rückseite vom Hall, funzt.
@agmue
ist ja schon im Bau.

Da bin ich wohl zu ungeduldig :relaxed:

Hallo Schorsch,

dafür brauchst du kein Bsp. von mir. Bevor ich dir die Tabelle erklärt habe haste dich selbst reingedacht. So eine Tabelle baut auch jeder anders auf. Im einfachsten Fall nimmste eine hohe Geschwindigkeit bei der die Lok noch nicht! aus der Kurve fliegt. Dann vermisst du einen Streckenabschnitt mittels den Hallsensoren und misst die millis Zeit für die bekannte Länge. Das rechnest du in km/h oder m/s um oder lässt es bei mm/ms bzw. rechnest die Realgeschwindigkeit vom Original Maßstabsgerecht runter. Bei mir mit TT 1:120. Das heißt die Modellbahnlok muss um Faktor 120 langsamer fahren. Dann kannste die Meßwerte mit den Maßstabsgerechten Werten vergleichen. Zu all den Werten kennst du den Duty Cycle Wert mit der die Lok gefahren ist. Der Rest sind lineare Gleichungen. Das kann man noch mit einem Steigungsfaktor und Offset für Vmin garnieren. Am Ende sind die Werte normiert. Bei mir auf eine Skala von 0 bis 1023, wegen 10 Bit analogen Eingang, weil ich auch umschalten kann auf Joystickbedienung. Das führt dazu das jede Lok mit ihrer eigenen Maßstabsgerechten Vmax fährt wenn ich die Geschwindigkeit auf "1023" hochnehme.

Praktisch gesehen bin ich das von hinten angegangen. Meine Duty Cycle Ansteuerung der H-Brücke von dessen Index 0...1023 Umrechnung war ja schon fertig. Ich bin die Meßstrecken also mit verschiedenen Indexwerten abgefahren und habe die Zeiten gemessen und alles in eine Tabelle eingetragen. Danach habe ich den allgmeinen Zusammenhang zwischen Indexwert (Duty Cycle) und gewünschter Geschwindigkeit hergestellt. Excel ist geduldig.

Bspw. konnte ich damit eine BR118 von ihren im Maßstab wahnsinnigen 160km/h auf der Platte auf Originalgetreue 120km/h einbremsen. Das sieht auch optisch besser aus. Die Modellbahnloks fahren nämlich in der Regel alle viel zu schnell. Wobei die Hersteller das ja mittels Motoranpassung und Getriebeabstufung von Haus aus anpassen könnten. Rein analog betrachtet.

Soweit so unklar. Nur wegens des Verständnisses. Wenn du die 1023 erwähnst, klingt das nach Steppermotor mit map. Und meinst du mit dyty Cycle? Die Schrittweite für den DC-Motor?

Hallo,

oh oh, mein Kommentar war wohl zu voreilig.
Ne ne, dass hat nichts mit Schrittmotor zu tun. Wo soll der herkommen? Es gibt ja keinen.
Die 0...1023 ist einfach meine Skala, meine eigene Normierung auf die sich all meine Berechnungen beziehen. Du kannst das auf sonstwas für eine Skala normieren. Ich hatte ja erwähnt das ich auch noch manuell fahren kann. Dafür hängt an einem analogen Eingang quasi ein Poti. Der ADC hat 10Bit Auflösung, was der Skala 0...1023 entspricht, habe ich für mich für brauchbar gefunden und als Basis für alles angesetzt.

Du möchtest doch deine H-Brücke und damit letztlich den Motor der Lok mit PWM steuern? Richtig? Damit du die Geschwindigkeit regeln kannst musst du das Tastverhältnis des PWM Signals ändern. Das Tastverhältnis nennt man auch Duty Cycle.