State Machine mit Stop nach fünf Durchgängen | kinetic sculpture | interactive art installation | GELÖST!

@Tommy56: Super, danke, das schaue ich mir mal an.

Die Frage ist jetzt aber nicht bezogen auf dieses Projekt, sondern auf das nächste;). Dieses Programm würde ich gerne selber schreiben mit Eurer Hilfe, deshalb würde ich mich sehr freuen wenn Ihr mir auf #38 antworten würdet:).

Herzlichst Leonardo

welcher ist jetzt "der neue Sketch"????
Bitte einfach noch einmal posten und dann auch eine Zeilennummer benennen
in der die Verzögerung steht.
Wenn es da mehr Verzögerung gibt als erwartet dann wird irgendwo anders noch eine Verzögerung sein.

Um herauszufinden wo
würde ich einfach an allen Stellen an denen das sinnvoll erscheint eine Ausgabe auf den seriellen Monitor machen. Am seriellen Monitor kann man einen Zeitstempel ein/ausschalten
damit kann man dann sehen welche Ausgabe zu welchem Zeitpunkt gemacht wurde.

Noch eine Möglichkeit bei Start eines Zyklusses mit millis() im Programm einen Zeitstempel machen und dann relativ dazu jeweils die vergangene Zeit ausgeben lassen. Umgerechnet von Millisekunden auf Sekunden.

vgs

das hier ist der neue Sketch:

// 30 ms sind zu knapp für die Software Verzögerung für die gegenseitig verriegelten Schütze, mit 500 geht es, vielleicht geht es auch mit weniger ich sollte es jedoch einfach so stehen lassen!
// Die Bewegung des Armes erfolgt erst nach 30000 ms nach dem Auslösen des Reed- Schalters s
// Mit einem Drücken des Tasters zwischen den Durchgängen passiert nichts, das ist aber auch gut so.
// Die Bewegung des Armes stoppt am oberen Punkt für 4000ms, so wie es sein soll!
// Pin - Definitionen
const uint8_t relaisNachOben = 8;
const uint8_t relaisNachUnten = 9;
const uint8_t Relais3 = 10; // unbenutzt
const uint8_t Relais4 = 11; // unbenutzt

const uint8_t Taster = 6;            // manuelle Ausloesung
const uint8_t ReedSchalter = 7;      // Magnetauslöser
const uint8_t EndschalterUnten = 12;
const uint8_t EndschalterOben = 13;

const uint32_t wartezeitUmschalten = 4000; // regelt die Zeit, die der Arm oben stehen bleibt

void setup()
{
  // Schnittstelle für den seriellen Monitor
  Serial.begin(9600);
  // Pin's vorbereiten
  pinMode(relaisNachOben, OUTPUT);
  pinMode(relaisNachUnten, OUTPUT);
  pinMode(Relais3, OUTPUT);
  pinMode(Relais4, OUTPUT);
  //Ausgangszustand herstellen
  digitalWrite(relaisNachOben, HIGH);
  digitalWrite(relaisNachUnten, HIGH);
  digitalWrite(Relais3, HIGH);
  digitalWrite(Relais4, HIGH);

  pinMode(ReedSchalter, INPUT_PULLUP);
  pinMode(EndschalterOben, INPUT_PULLUP);
  pinMode(EndschalterUnten, INPUT_PULLUP);
  pinMode(Taster, INPUT_PULLUP);
}

void loop()
{
  Verarbeitung();
}

void Verarbeitung()
{
  enum {warten, wartenUnten, ArmNachOben, ArmOben, wartenOben, ArmNachUnten, ArmUnten};
  static uint8_t zustand = warten;   // Anfangszustand ist Warten
  static uint8_t zaehler = 0;        // Variable für Schleifenzähler
  static uint32_t lastmillis = 0;    // Variable Zeitmerker
  static bool reedUnten = false;     // Zustand für ReedSchalter

  switch (zustand)
  {
    case warten:
      if (!digitalRead(Taster))  // wenn der Taster gedrückt wird...
      {
        zaehler = 0;             // Zähler wird 0 gesetzt
        zustand = wartenUnten;   // nächster Zustand
      }
      else if (digitalRead(EndschalterUnten))  // Wenn nicht an der Startposition, d.h wenn der Stecker gezogen wurde während der Bewegung dann fahre ich damit an die Referenzposition
      {
        digitalWrite(relaisNachUnten, LOW);
        delay(500);                            // Software- Verzögerung
        digitalWrite(relaisNachOben, HIGH);
      }
      else                                     // Wenn der Taster gedrückt ist...Mach alles aus und warte...
      {
        digitalWrite(relaisNachOben, HIGH);
        delay(500);                           // Software- Verzögerung
        digitalWrite(relaisNachUnten, HIGH);
      }
      break;

    case wartenUnten:
      if (!zaehler)                // Wenn der Zähler 0 ist
      {
        Serial.println(F("Arm geht nach oben"));
        zustand = ArmNachOben;  // nächster Zustand
      }

      else if (!digitalRead(ReedSchalter))   // Wenn der Zähler ungleich 0 ist und der ReedSchalter auslöst // KOMMT ES HIER ZU DER ZEITLICHEN VERSCHIEBUNG? WENN DER REED-SCHALTER EIN ZEITES MAL AUSLÖST, DANN wird lastmillis = millis; HIER MUSS DER FEHLER SEIN!
      {
        lastmillis = millis();
        reedUnten = true;                    // wird reedUnten wahr
      }
      if (millis() - lastmillis >= 20000 && reedUnten)    // wenn die Anfangspause vergangen ist und reedUnten wahr ist // IN DER ZEIT KANN lastmillis() NÄMLICH WIEDER 0 WERDEN!
      {
        zustand = ArmNachOben;            // nächster Zustand
        reedUnten = false;                // gespeicherten Zustand für ReedSchalter zurücksetzen
      }
      break;

    case ArmNachOben:
      digitalWrite(relaisNachOben, LOW); // Bewegung nach oben
      delay (500);                        // Software- Verzögerung
      digitalWrite(relaisNachUnten, HIGH);
      zustand = ArmOben;                // nächster Zustand
      break;

    case ArmOben:
      if (!digitalRead(EndschalterOben)) // Wenn der Endschalter oben gedrückt wird
      {
        Serial.println(F("Arm ist oben"));
        digitalWrite(relaisNachOben, HIGH);
        delay(500);
        digitalWrite(relaisNachUnten, HIGH);
        lastmillis = millis();
        zustand = wartenOben;            // nächster Zustand
      }
      break;

    case wartenOben:
      if (millis() - lastmillis >= wartezeitUmschalten)     // regelt die Zeit, die der Arm oben stehen bleibt
      {
        zustand = ArmNachUnten;
      }
      break;

    case ArmNachUnten:
      Serial.println(F("Arm geht nach unten"));
      digitalWrite(relaisNachUnten, LOW);
      delay(500);                      // Software- Verzögerung
      digitalWrite(relaisNachOben, HIGH);
      zustand = ArmUnten;            // nächster Zustand
      break;

    case ArmUnten:
      if (!digitalRead(EndschalterUnten))   // Wenn der EndschalterUnten gedrückt wird
      {
        Serial.println(F("Arm unten"));
        digitalWrite(relaisNachUnten, HIGH);
        delay(500);            // Software- Verzögerung
        digitalWrite(relaisNachOben, HIGH);
        zaehler++;                         // Schleifenzaehler- Variable wird eins größer
        if (zaehler > 3)                   // wenn zaehler über 3 dann wechsel in
        {
          zustand = warten;                // Zustand Warten
        }
        else                               // wenn nicht
        {
          lastmillis = millis();
          zustand = wartenUnten;           // nach wartenUnten
        }
      }
      break;
  }
}

Kann mir jemand verraten wie ich die Zeilennummer herausfinden kann, in der die Verzögerung steht, kann man sich die Zeilennummern irgendwie anzeigen lassen?

Ich poste hier jetzt einfach nochmal die Zeile, in der die Verzögerung steht:

else if (!digitalRead(ReedSchalter))   // Wenn der Zähler ungleich 0 ist und der ReedSchalter auslöst // KOMMT ES HIER ZU DER ZEITLICHEN VERSCHIEBUNG? WENN DER REED-SCHALTER EIN ZEITES MAL AUSLÖST (BEIM RUNTERFAHREN DES ARMES), DANN WIRD lastmillis = millis; ( EIN ZWEITES MAL!). HIER MUSS DER FEHLER SEIN!
      {
        lastmillis = millis();
        reedUnten = true;                    // wird reedUnten wahr
      }
      if (millis() - lastmillis >= 20000 && reedUnten)    // wenn die Anfangspause vergangen ist und reedUnten wahr ist // IN DER ZWISCHENZEIT KANN lastmillis() NÄMLICH WIEDER 0 WERDEN!
      {
        zustand = ArmNachOben;            // nächster Zustand
        reedUnten = false;                // gespeicherten Zustand für ReedSchalter zurücksetzen
      }

Meine Vermutung ist folgende: Wenn der Arm beim Hochfahren den Reed- Schalter auslöst, wird der reedUnten wahr und lastmillis = millis(). Beim Runterfahren des Armes löst wird der Reed- Schalter aber ein zweites Mal ausgelöst. Dann wird lastmillis = millis() ( ein zweites Mal) und es kommt zu einer weiteren Verzögerung.

Ich will jedoch, dass die Anfangspause schon abläuft wenn der Reed- Schalter das erste Mal auslöst.

Gibt es eine Möglichkeit das zu realisieren? Könnte man zum Beispiel im Sketch formulieren: Wenn reedUnten seinen Zustand gewechselt hat, dann wird lastmillis = millis()? Der reedUnten wechselt seinen Zustand ja nicht wenn der Reed- Schalter ein zweites Mal auslöst.

Du meinst vermutlich
else if (!digitalRead(ReedSchalter) && !reedUnten)

Aber "This topic has been solved" :slight_smile: von weiterer Hilfe wird abgeraten

Ja genau das meine ich!:smiley: Danke! Jetzt ist das Thema gelöst.

Danke für Eure Hilfe!

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.

Liebe communitiy,

Hier sind abschließend ein paar Fotos und ein Video des fertigen Projektes.

P.S.: Bilder von meinen anderen Projekten findet ihr hier: Leon Fiand (@leon_fiand) • Instagram photos and videos

Und hier gibt es noch ein Video der Arbeit "Zu zweit allein" auf YouTube:

Danke an Alle, die mir bei dem Projekt geholfen haben! Es ist herrlich wie hilfsbereit Ihr, diese community, seid! Vielen Dank dafür!

Herzliche Grüße Leonardo

Hier sind abschließend noch einmal die endgültigen Sketches, mit denen die Installation läuft:

  1. Sketch des Senders (die linke Figur, die nach dem Drücken des Tasters mit der Bewegung beginnt):
// 30 ms sind zu knapp für die Software Verzögerung für die gegenseitig verriegelten Schütze, mit 500 geht es, vielleicht geht es auch mit weniger ich sollte es jedoch einfach so stehen lassen!
// Die Bewegung des Armes erfolgt erst nach 30000 ms nach dem Auslösen des Reed- Schalters s
// Mit einem Drücken des Tasters zwischen den Durchgängen passiert nichts, das ist aber auch gut so.
// Die Bewegung des Armes stoppt am oberen Punkt für 4000ms, so wie es sein soll!
// Pin - Definitionen
const uint8_t relaisNachOben = 8;
const uint8_t relaisNachUnten = 9;
const uint8_t Relais3 = 10; // unbenutzt
const uint8_t Relais4 = 11; // unbenutzt

const uint8_t Taster = 6;            // manuelle Ausloesung
const uint8_t ReedSchalter = 7;      // Magnetauslöser
const uint8_t EndschalterUnten = 12;
const uint8_t EndschalterOben = 13;

const uint32_t wartezeitUmschalten = 4000; // regelt die Zeit, die der Arm oben stehen bleibt

void setup()
{
  // Schnittstelle für den seriellen Monitor
  Serial.begin(9600);
  // Pin's vorbereiten
  pinMode(relaisNachOben, OUTPUT);
  pinMode(relaisNachUnten, OUTPUT);
  pinMode(Relais3, OUTPUT);
  pinMode(Relais4, OUTPUT);
  //Ausgangszustand herstellen
  digitalWrite(relaisNachOben, HIGH);
  digitalWrite(relaisNachUnten, HIGH);
  digitalWrite(Relais3, HIGH);
  digitalWrite(Relais4, HIGH);

  pinMode(ReedSchalter, INPUT_PULLUP);
  pinMode(EndschalterOben, INPUT_PULLUP);
  pinMode(EndschalterUnten, INPUT_PULLUP);
  pinMode(Taster, INPUT_PULLUP);
}

void loop()
{
  Verarbeitung();
}

void Verarbeitung()
{
  enum {warten, wartenUnten, ArmNachOben, ArmOben, wartenOben, ArmNachUnten, ArmUnten};
  static uint8_t zustand = warten;   // Anfangszustand ist Warten
  static uint8_t zaehler = 0;        // Variable für Schleifenzähler
  static uint32_t lastmillis = 0;    // Variable Zeitmerker
  static bool reedUnten = false;     // Zustand für ReedSchalter

  switch (zustand)
  {
    case warten:
      if (!digitalRead(Taster))  // wenn der Taster gedrückt wird...
      {
        zaehler = 0;             // Zähler wird 0 gesetzt
        zustand = wartenUnten;   // nächster Zustand
      }
      else if (digitalRead(EndschalterUnten))  // Wenn nicht an der Startposition, d.h wenn der Stecker gezogen wurde während der Bewegung dann fahre ich damit an die Referenzposition
      {
        digitalWrite(relaisNachUnten, LOW);
        delay(500);                            // Software- Verzögerung
        digitalWrite(relaisNachOben, HIGH);
      }
      else                                     // Wenn der Taster gedrückt ist...Mach alles aus und warte...
      {
        digitalWrite(relaisNachOben, HIGH);
        delay(500);                           // Software- Verzögerung
        digitalWrite(relaisNachUnten, HIGH);
      }
      break;

    case wartenUnten:
      if (!zaehler)                // Wenn der Zähler 0 ist
      {
        Serial.println(F("Arm geht nach oben"));
        zustand = ArmNachOben;  // nächster Zustand
      }

      else if (!digitalRead(ReedSchalter) && !reedUnten)   // Wenn der Zähler ungleich 0 ist, der Reed- Schalter auslöst und und reed Unten false ist
      {
        lastmillis = millis();
        reedUnten = true;                    // wird reedUnten wahr
      }
      if (millis() - lastmillis >= 20000 && reedUnten)    // wenn die Anfangspause vergangen ist und reedUnten wahr ist
      {
        zustand = ArmNachOben;            // nächster Zustand
        reedUnten = false;                // gespeicherten Zustand für ReedSchalter zurücksetzen
      }
      break;

    case ArmNachOben:
      digitalWrite(relaisNachOben, LOW); // Bewegung nach oben
      delay (500);                        // Software- Verzögerung
      digitalWrite(relaisNachUnten, HIGH);
      zustand = ArmOben;                // nächster Zustand
      break;

    case ArmOben:
      if (!digitalRead(EndschalterOben)) // Wenn der Endschalter oben gedrückt wird
      {
        Serial.println(F("Arm ist oben"));
        digitalWrite(relaisNachOben, HIGH);
        delay(500);
        digitalWrite(relaisNachUnten, HIGH);
        lastmillis = millis();
        zustand = wartenOben;            // nächster Zustand
      }
      break;

    case wartenOben:
      if (millis() - lastmillis >= wartezeitUmschalten)     // regelt die Zeit, die der Arm oben stehen bleibt
      {
        zustand = ArmNachUnten;
      }
      break;

    case ArmNachUnten:
      Serial.println(F("Arm geht nach unten"));
      digitalWrite(relaisNachUnten, LOW);
      delay(500);                      // Software- Verzögerung
      digitalWrite(relaisNachOben, HIGH);
      zustand = ArmUnten;            // nächster Zustand
      break;

    case ArmUnten:
      if (!digitalRead(EndschalterUnten))   // Wenn der EndschalterUnten gedrückt wird
      {
        Serial.println(F("Arm unten"));
        digitalWrite(relaisNachUnten, HIGH);
        delay(500);            // Software- Verzögerung
        digitalWrite(relaisNachOben, HIGH);
        zaehler++;                         // Schleifenzaehler- Variable wird eins größer
        if (zaehler > 3)                   // wenn zaehler über 3 dann wechsel in
        {
          zustand = warten;                // Zustand Warten
        }
        else                               // wenn nicht
        {
          lastmillis = millis();
          zustand = wartenUnten;           // nach wartenUnten
        }
      }
      break;
  }
}
  1. Sketch des Empfängers ( die rechte Figur):
//State Machine // Bewegungsmelder ist jetzt ein Reed- Schalter 30ms sind zu kurz für die Software- Verzögerung! Mit 500ms geht es!

// Pin - Definitionen
const int Relais1 = 8;
const int Relais2 = 9;
const int Relais3 = 10;
const int Relais4 = 11;

const int ReedSchalter = 7;
const int EndschalterOben = 13;
unsigned long Pausenzeitgeber;
const int EndschalterUnten = 12;


//Zustände
const int Z_ArmUnten = 0;
const int Z_ArmNachOben = 1;
const int Z_ArmOben = 2;
const int Z_ArmNachUnten = 3;

//Variablen für Ereignisse
bool e_ReedSchalter;
bool e_EndschalterOben;
bool e_Pausenzeitgeber;
bool e_EndschalterUnten;


//Variablen für Zustände
int Zustand;

void ArmUnten()
{
  Serial.println("Arm unten");
  digitalWrite(Relais2, HIGH);
  delay(500); // Software- Verzögerung zum Beheben der Störung
  digitalWrite(Relais1, HIGH);
  Zustand = Z_ArmUnten;
  e_EndschalterUnten = false;
  e_ReedSchalter = false;
  e_EndschalterOben = false;
  e_Pausenzeitgeber = false;
}

void ArmNachOben()
{
  Serial.println("Arm geht nach oben nach Anfangspause");
  delay(20000); // Anfangspause// erst waren es 10000, das war mir ein bisschen zuschnell! 15000 sind okay aber vielleicht immer noch ein bisschen zu schnell
  digitalWrite(Relais1, LOW); // Das muss immerso herum
  delay(500); // Software- Verzögerung zum Beheben der Störung
  digitalWrite(Relais2, HIGH); // hier stehen, sonst kommt es zu einer Störung!
  Zustand = Z_ArmNachOben;
  e_EndschalterUnten = false;
  e_ReedSchalter = false;
  e_EndschalterOben = false;
  e_Pausenzeitgeber = false;
}

void ArmOben()
{
  Serial.println("Arm ist oben");
  digitalWrite(Relais1, HIGH);
  delay(500); // Software- Verzögerung zum Beheben der Störung
  digitalWrite(Relais2, HIGH);
  Zustand = Z_ArmOben;
  e_EndschalterUnten = false;
  e_ReedSchalter = false;
  e_EndschalterOben = false;
  e_Pausenzeitgeber = false;
  Pausenzeitgeber = millis();
}

void ArmNachUnten()
{
  Serial.println("Arm geht nach unten");
  digitalWrite(Relais2, LOW);
  delay(500); //Software- Verzögerung zum Beheben der Störung
  digitalWrite(Relais1, HIGH);
  Zustand = Z_ArmNachUnten;
  e_EndschalterUnten = false;
  e_ReedSchalter = false;
  e_EndschalterOben = false;
  e_Pausenzeitgeber = false;
}

void Ereignisse()
{
  if (digitalRead(ReedSchalter) == LOW) { // Reedschalter schaltet GND und ist INPUT_PULLUP
    e_ReedSchalter = true;
  }
  if (digitalRead(EndschalterOben) == LOW)
  {
    e_EndschalterOben = true;
    // hier darf: Pausenzeitgeber = millis(); nicht stehen, weil der Schalter ja gedrückt bleibt!!!
  }
  if (millis() - Pausenzeitgeber > 4000 && millis() - Pausenzeitgeber < 4500) // erst waren es 6000 und 6500, die Pause ist auf jeden Fall zu lang, Messung hat ergeben, dass 4000 ganz gut wären 
  {
    e_Pausenzeitgeber = true;
  }
  if (digitalRead(EndschalterUnten) == LOW )
  {
    e_EndschalterUnten = true;
  }
}

void Verarbeitung()
{
  if (e_ReedSchalter)
  {
    switch (Zustand)
    {
      case Z_ArmUnten: ArmNachOben(); break;
    }
  }
  if (e_EndschalterOben)
  {
    switch (Zustand)
    {
      case Z_ArmNachOben: ArmOben(); break;
    }
  }
  if (e_Pausenzeitgeber)
  {
    switch (Zustand)
    {
      case Z_ArmOben: ArmNachUnten(); break;
    }
  }
  if ( e_EndschalterUnten)
  {
    switch (Zustand)
    {
      case Z_ArmNachUnten: ArmUnten(); break;
    }
  }
}

void setup() {
  // Schnittstelle für den seriellen Monitor
  Serial.begin(9600);

  // Pin's vorbereiten
  pinMode(Relais1, OUTPUT);
  pinMode(Relais2, OUTPUT);
  pinMode(Relais3, OUTPUT);
  pinMode(Relais4, OUTPUT);

  pinMode(ReedSchalter, INPUT_PULLUP);
  pinMode(EndschalterOben, INPUT_PULLUP);
  pinMode(EndschalterUnten, INPUT_PULLUP);

  //Ausgangszustand herstellen
  digitalWrite(Relais1, HIGH);
  digitalWrite(Relais2, HIGH);
  digitalWrite(Relais3, HIGH);
  digitalWrite(Relais4, HIGH);

  Zustand = Z_ArmUnten;
  e_ReedSchalter = false;
  e_EndschalterOben = false;
  e_Pausenzeitgeber = false;
  e_EndschalterUnten = false;
}

void loop()
{
  Ereignisse();              // Ereignisse werden abgefragt
  Verarbeitung();            // Anhand der Ereignisse werden die einzelnen Funktionen abgerufen
}