Ansteuerung von elektrischer Seilwinde | kinetic sculpture | interactive art installation | GELÖST!

Ich habe jetzt zwei Taster in mein Setup eingebaut. Einer soll durch Auslösen das Signal für "Arm oben" geben und der Andere das Signal für "Arm unten". ( siehe Skizze 1)

Natürlich muss ich meinen ursprünglichen Sketch jetzt verändern, weil sich delay() mit den beiden Tastern als Signalgeber nicht so gut versteht. Denn wenn der Arduino auf Grund von delay() gerade "schläft" kann er das Signal für "Arm unten" oder "Arm oben" nicht empfangen und somit die Seilwinde auch nicht stoppen.

Ich habe mir als Hilfe eine Skizze gemacht, die den Bewegungsablauf, den ich mit dem Sketch realisieren will, illustriert. Ich habe die Bewegung in 7 Schritte gegliedert.

Hallo
das ist eine gute Funktionsbeschreibung. Damit kannst du eine Schrittkette programmieren, die durch die Taster, Zeitgeber und Bewegungsmelder gesteuert wird.

Ich habe den Sketch jetzt umgeschrieben, aber das delay() drin gelassen. Ich kann den Sketch() schlecht mit millis() schreiben, weil ich nicht genau weiß wie lange die einzelnen Schritte beim Bewegungsablauf dauern.

int Relais1 = 8;
int Relais2 = 9;
int Relais3 = 10;
int Relais4 = 11;

int pirPin = 7; // Input for HC-S501 // pirPin ist LOW wenn keine Bewegung registriert wurde und wird HIGH wenn eine Bewegung registiriert wird
int TasterArmOben = 6;
int TasterArmUnten = 5;

int pirValue = LOW; // Place to store read PIR Value // Platz an dem der gelesene PIR- Wert gespeichert wird
int Bewegungswert = LOW; // Der Bewegungswert ist zu Beginn LOW / 0


void setup()
{
  pinMode(Relais1, OUTPUT);
  pinMode(Relais2, OUTPUT);
  pinMode(Relais3, OUTPUT);
  pinMode(Relais4, OUTPUT);
  pinMode(pirPin, INPUT);
  pinMode(TasterArmOben, INPUT);
  pinMode(TasterArmUnten, INPUT);

  digitalWrite(Relais1, HIGH); // regelt, dass die Relais offen bleiben (normally open) wenn Strom angelegt wird
  digitalWrite(Relais2, HIGH);
  digitalWrite(Relais3, HIGH);
  digitalWrite(Relais4, HIGH);
}

void loop() {

  // Bewegungsablauf
  pirValue = digitalRead(pirPin);                // der gelesene Wert von pirPin wird auf pirValue gespeichert
  if (pirValue == HIGH && Bewegungswert == LOW ) // wenn pirValue = HIGH und Bewegungswert = LOW
  {
    Bewegungswert = HIGH;
  }
  if ( Bewegungswert == HIGH)
  {
    if (Relais1 == HIGH && Relais2 == HIGH && TasterArmUnten == LOW)
    {
      delay(1000);                // Anfangspause, die dazu dient erst zu starten wenn die Bewegung des Anderen abgeschlossen ist!
      digitalWrite(Relais1, LOW); // Aufwärtsbewegung
      digitalWrite(Relais2, LOW);
    }
    if ( Relais1 == LOW && Relais2 == LOW && TasterArmOben == LOW)
    {
      digitalWrite(Relais1, HIGH); // Ende der Aufwärtsbewegung
      digitalWrite(Relais2, HIGH);
      delay (4000);                //regelt die Zeit der Pause "Arm oben"
      digitalWrite(Relais3, LOW); // Abwärtsbewegung
      digitalWrite(Relais4, LOW);
    }
    if ( Relais3 == LOW && Relais4 == LOW && TasterArmUnten == LOW)
    {
      digitalWrite(Relais3, HIGH); // Bewegungsende
      digitalWrite(Relais4, HIGH);
      Bewegungswert = LOW;         // Bewegungswert LOW setzen
    }
  }
}

Findet ihr Fehler im Sketch? Oder seht Ihr eine einfachere Möglichkeit den Sketch zu gestalten?

paulpaulson:
Hallo
das ist eine gute Funktionsbeschreibung.

Sehe ich auch so. Da ist ein kreatives Köpfchen am Werk.

@paulpaulson: Danke. Kennst Du eine Internetseite, die als gutes Beispiel für eine Schrittkette dient oder wo das gut erklärt wird?:slight_smile:

LeonardoFiando:
@paulpaulson: Danke. Kennst Du eine Internetseite, die als gutes Beispiel für eine Schrittkette dient oder wo das gut erklärt wird?:slight_smile:

ich schaue nachher mal in meine Sketche-Reste Kiste

Ich habe ein YouTube- Tutorial gefunden wo es anschaulich erklärt wird: State Machine - ganz einfach - YouTube

Ich versuche jetzt mein Glück und lasse Euch wissen wie es voran geht;).

Hallo
hier kommt der Sketch aus der Reste-Kiste, den du noch um die entsprechenden Funktionen anpassen musst.

enum {Anfang, ArmGehtnachOben, Oben, ArmGehtNachUnten};
unsigned int zustand;
void setup() {
  Serial.begin(9600);
  zustand = Anfang;
}
void loop() {
  // put your main code here, to run repeatedly:
  switch (zustand)
  {
      static unsigned int caseOld = -1;
    case Anfang:
      if (caseOld != zustand) caseOld = zustand, Serial.println("Anfang");
      // Wenn Bewegungsmelder, dann motor(rauf) und Zustand =ArmGehtnachOben
      break;
    case ArmGehtnachOben:
      if (caseOld != zustand) caseOld = zustand, Serial.println("ArmGehtnachOben");
      //wenn EndschalterOben, dann motor(aus), starte PausenZeitGeber und Zustand=Oben;
      break;
    case Oben:
      if (caseOld != zustand) caseOld = zustand, Serial.println("Oben");
      //wenn PausenZeitGeber, dann motor(runter) und Zustand=ArmGehtNachUnten;
      break;
    case ArmGehtNachUnten:
      if (caseOld != zustand) caseOld = zustand, Serial.println("ArmGehtNachUnten");
      // wenn EndschalterUnten, dann motor(aus), Zustand=Anfang;
      break;
  }
}

@paulpaulson:
Super! Vielen Dank! Ich schaue mir den Sketch mal an und versuche ihn zu verstehen;).

Ich habe hier eine Skizze angefertigt, in der man die Zustände (SCHWARZ), die Ereignisse (ROT), welche die Übergänge auslösen und die Aktionen (BLAU), die dabei ausgeführt werden, sieht. Das hat mir geholfen besser durchzublicken.

Ich habe mir im Internet dieses Video hier angeschaut State Machine - ganz einfach - YouTube und diesen Beispielcode, der im Video vorkommt:

/***********************************
 * State machine 4, Vers. 1.0 
 * Einfache Schaltung mit Taster
 * Taster 1 schaltet Zustände rot - gelb - grün - rot
 * Der Hobbyelektroniker, 12.06.2018
 ***********************************/

// Pin - Definitionen
const int PIN_LED_GRUEN = 12;
const int PIN_LED_GELB = 11;
const int PIN_LED_ROT = 10;

const int PIN_TASTE1 = 7;
const int PIN_TASTE2 = 6;

// Zustände //hier muss man dazusagen, dass 
const int Z_KEINE = 0;
const int Z_ROT = 1;
const int Z_GELB = 2;
const int Z_GRUEN = 3;

// Variablen für Ereignisse
bool e_taste1;
bool e_taste2;

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

void keine() {
  digitalWrite(PIN_LED_GRUEN,LOW);
  digitalWrite(PIN_LED_GELB,LOW);
  digitalWrite(PIN_LED_ROT,LOW);
  zustand = Z_KEINE;    // der Zustand wird Z_KEINE, weil Z_Keine aber das gleich ist wie 0 wird er auch 0
  e_taste1 = false;
  e_taste2 = false;
}

void rot() {
  Serial.println("rot");
  digitalWrite(PIN_LED_GRUEN,LOW);
  digitalWrite(PIN_LED_GELB,LOW);
  digitalWrite(PIN_LED_ROT,HIGH);
  zustand = Z_ROT;
  e_taste1 = false;
}

void gruen() {
  Serial.println("gruen");
  digitalWrite(PIN_LED_GRUEN,HIGH);
  digitalWrite(PIN_LED_GELB,LOW);
  digitalWrite(PIN_LED_ROT,LOW);
  zustand = Z_GRUEN;
  e_taste1 = false;
}

void gelb() {
  digitalWrite(PIN_LED_GRUEN,LOW);
  digitalWrite(PIN_LED_GELB,HIGH);
  digitalWrite(PIN_LED_ROT,LOW);
  zustand = Z_GELB;
  e_taste1 = false;
}

void ereignisse() {
  if (digitalRead(PIN_TASTE1) == LOW) {
    e_taste1 = true;
    delay(300); 
  }
  if (digitalRead(PIN_TASTE2) == LOW) {
    e_taste2 = true;
    delay(300); 
  }
}

void verarbeitung() {
  if (e_taste2) keine(); // Taste 2 schaltet sofort aus
  if (e_taste1) { // Die Aktion hängt vom aktuellen Zustand ab
    switch(zustand) { // Die Variable zustand wird der Reihe nach mit den case verglichen, bei Übereinstimmung wird die Anweisung nach dem Doppelpunkt durchgeführt. Wenn der Vergleich üereinstimme unterbrückt break die weiteren Tests
      case Z_KEINE: rot(); break; // Wenn Zustand (0= KEINE) und (
      case Z_ROT: gelb(); break;
      case Z_GELB: gruen(); break;
      case Z_GRUEN: rot(); break;
    }
  }
}


void setup() {
  // Pin's vorbereiten
  pinMode(PIN_LED_GRUEN,OUTPUT);
  pinMode(PIN_LED_GELB,OUTPUT);
  pinMode(PIN_LED_ROT,OUTPUT);

  pinMode(PIN_TASTE1,INPUT_PULLUP);
  pinMode(PIN_TASTE2,INPUT_PULLUP);

  // Ausgangszustand herstellen
  digitalWrite(PIN_LED_GRUEN,LOW);
  digitalWrite(PIN_LED_GELB,LOW);
  digitalWrite(PIN_LED_ROT,LOW);
  zustand = Z_KEINE;
  e_taste1 = false;
  e_taste2 = false;
}

void loop() {
  ereignisse();
  verarbeitung();
}

Diesen habe ich soweit verstanden. Ich habe dann versucht diesen auf meine Bedürfnisse umzuschreiben. Das ist dabei rausgekommen:

//State Machine

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

const int Bewegungsmelder = 7;
const int EndschalterOben = 6;
const int EndschalterUnten = 5;

//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_Empfaenger;

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

void ArmUnten()
{
  Serial.println("Arm ist unten");
  digitalWrite(Relais1, HIGH);
  digitalWrite(Relais2, HIGH);
  digitalWrite(Relais3, HIGH);
  digitalWrite(Relais4, HIGH);
  Zustand = Z_ArmUnten;
  e_Empfaenger = false;
}

void ArmNachOben()
{
  Serial.println("Arm geht nach oben");
  digitalWrite(Relais1, LOW);
  digitalWrite(Relais2, LOW);
  digitalWrite(Relais3, HIGH);
  digitalWrite(Relais4, HIGH);
  Zustand = Z_ArmNachOben;
  e_Empfaenger = false;
}

void ArmOben()
{
  Serial.println("Arm ist oben");
  digitalWrite(Relais1, HIGH);
  digitalWrite(Relais2, HIGH);
  digitalWrite(Relais3, HIGH);
  digitalWrite(Relais4, HIGH);
  Zustand = Z_ArmOben;
  e_Empfaenger = false;
}

void ArmNachUnten()
{
  Serial.println("Arm ist unten");
  digitalWrite(Relais1, HIGH);
  digitalWrite(Relais2, HIGH);
  digitalWrite(Relais3, HIGH);
  digitalWrite(Relais4, HIGH);
  e_Empfaenger = false;
}

void Ereignisse()
{
  if (digitalRead(Bewegungsmelder) == HIGH || digitalRead(EndschalterOben) == HIGH || digitalRead(EndschalterUnten) == HIGH) { // ich weiß leider nicht wie ich das anders lösen soll
    e_Empfaenger = true;
  }
}

void Verarbeitung()
{
  if (e_Empfaenger)        // Wenn einer der Empfaenger ausgelöst hat
  {
    switch (Zustand)
    {
      case Z_ArmUnten: ArmNachOben(); break;
      case Z_ArmNachOben: ArmOben(); break;
      case Z_ArmOben: ArmNachUnten(); break;
      case Z_ArmNachUnten: ArmUnten; break;
    }
  }
}

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

  pinMode(Bewegungsmelder, INPUT);
  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_Empfaenger = false;
  // hier fehlt noch ein der Pausenzeitgeber als Empfänger
}

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

Ich habe keine Ahnung wie ich den Pausenzeitgeber, der als Ereignis dienen soll um vom Zustand "Arm oben" in den Zustand "Arm nach unten" zu wechseln bewerkstellige. Kann mir da bitte jemand helfen?

@paulpaulson: Danke für den Code, den Du mir geschickt hast, leider verstehe ich da vieles nicht, sodass mir das Umbauen des Codes aus dem Video lieber war. Ich verstehe bei dem code zum Beispiel nicht wo die Ereignisse Platz finden sollen, die den Übergang zwischen den Zuständen auslösen. Auch bei dem Sketch den ich umgeschrieben habe war das die große Schwierigkeit.

void Ereignisse()
{
  if (digitalRead(Bewegungsmelder) == HIGH || digitalRead(EndschalterOben) == HIGH || digitalRead(EndschalterUnten) == HIGH) { // ich weiß leider nicht wie ich das anders lösen soll
    e_Empfaenger = true;
  }
}

Ich habe jetzt einfach aus allen möglichen Empfängern, ein Ereignis gemacht, bin mir aber nicht ganz sicher ob das so funktioniert.

P.S.: Wie Ihr seht bin ich nicht so der Crack, ich habe alles gegeben, aber jetzt bin ich reif für die Heia:D. Ich würde mich sehr über Eure Hilfe freuen! Gute Nacht.

Hallo, gestern sind die neuen Relais gekommen. Ich will sie ins Setup einbauen, aber die neuen Relais, haben andere Anschlüsse. In der Skizze seht ihr die Anschlüsse der beiden Relais im Vergleich. Das "alte Relais" habe ich mit galvanischer Trennung angeschlossen. Das scheint beim "neuen Relais" auf jeden Fall nicht mehr zu funktionieren, da ein zweiter VCC - und der JD- VCC Anschluss fehlt. Würdet Ihr das "neue Relais" auch so anschließen wie in meiner Skizze?

Hallo, Ich glaube mir ist gerade eine Möglichkeit eingefallen den Pausenzeitgeber als Ereignnis zum Umschalten in den nächsten Zustand in meinen Sketch zu integrieren:

Ich habe in der Funktion void ArmOben() jetzt einfach millis() = Pausenzeitgeber gesetzt. Und wenn millis() - Pausenzeitgeber == 3000 wird e_Empfaenger true und dient dann als Ereignis für das Umschalten in den nächsten Zustand. Ist das eine Lösung?

Hier ist der Sketch:

//State Machine

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

const int Bewegungsmelder = 7;
const int EndschalterOben = 6;
const int EndschalterUnten = 5;

//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_Empfaenger;
unsigned long Pausenzeitgeber;


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

void ArmUnten()
{
  Serial.println("Arm unten");
  digitalWrite(Relais1, HIGH);
  digitalWrite(Relais2, HIGH);
  digitalWrite(Relais3, HIGH);
  digitalWrite(Relais4, HIGH);
  Zustand = Z_ArmUnten;
  e_Empfaenger = false;
}

void ArmNachOben()
{
  Serial.println("Arm geht nach oben");
  digitalWrite(Relais1, LOW);
  digitalWrite(Relais2, LOW);
  digitalWrite(Relais3, HIGH);
  digitalWrite(Relais4, HIGH);
  Zustand = Z_ArmNachOben;
  e_Empfaenger = false;
}

void ArmOben()
{
  Serial.println("Arm ist oben");
  digitalWrite(Relais1, HIGH);
  digitalWrite(Relais2, HIGH);
  digitalWrite(Relais3, HIGH);
  digitalWrite(Relais4, HIGH);
  Zustand = Z_ArmOben;
  e_Empfaenger = false;
  Pausenzeitgeber = millis();

}

void ArmNachUnten()
{
  Serial.println("Arm ist unten");
  digitalWrite(Relais1, HIGH);
  digitalWrite(Relais2, HIGH);
  digitalWrite(Relais3, HIGH);
  digitalWrite(Relais4, HIGH);
  e_Empfaenger = false;
}

void Ereignisse()
{
  if (digitalRead(Bewegungsmelder) == HIGH || digitalRead(EndschalterOben) == HIGH || digitalRead(EndschalterUnten) == HIGH || millis() - Pausenzeitgeber == 3000) {
    e_Empfaenger = true;
  }
}

void Verarbeitung()
{
  if (e_Empfaenger)        // Wenn einer der Empfänger ein Signal bekommen hat
  {
    switch (Zustand)
    {
      case Z_ArmUnten: ArmNachOben(); break;
      case Z_ArmNachOben: ArmOben(); break;
      case Z_ArmOben: ArmNachUnten(); break;
      case Z_ArmNachUnten: ArmUnten; break;
    }
  }
}

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

  pinMode(Bewegungsmelder, INPUT);
  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_Empfaenger = false;
  // hier fehlt noch ein der Pausenzeitgeber als Empfänger
}

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

"==" halte ich nicht für eine gute Lösung bei Zeitbedingungen. Da musst Du genau die Millisekunde treffen.
">=" wäre geschickter; also mindestens 3000, aber wenn es zwei oder drei mehr sind macht es auch nix.

@wno158: Da hast Du Recht. Das Problem ist aber, dass die if- Bedinging, dann sehr lange true sein wird, und die anderen Operanden gar nicht mehr zu Zug kommen. Habe es jetzt so gelöst:

void Ereignisse()
{
  if (digitalRead(Bewegungsmelder) == HIGH || digitalRead(EndschalterOben) == HIGH || digitalRead(EndschalterUnten) == HIGH || millis() - Pausenzeitgeber > 3000 && millis() < 3500) {
    e_Empfaenger = true;
  }
}

Na ja, das stimmt. In diesem Fall ist die Bedingung recht lange erfüllt. Eine halbe Sekunde ist aber auch recht lang :slight_smile:

Vermutlich willst Du ja, dass sie genau einmal erfüllt ist und dann erst wieder an einer anderen Stelle "scharf geschaltet" wird (in ArmOben).

Also wäre es doch eine Idee, nicht nur einen Merker e_Empfaenger (irgendein Ereignis) zu haben, sondern auch noch einen für "Zeitbedingung war schon erfüllt", die dann in ArmOben zugleich mit dem Setzen von Pausenzeitgeber zurückgesetzt wird.

Danke wno158,

Ich versuche es gleich mal so zu realisieren. Eine Zwischenfrage hätte ich noch:

Ich glaube inzwischen, dass ich mein neues Relais so anschließen muss (siehe Skizze). Ist das richtig?

Da ich nicht weiß, was für ein Relaismodul das ist (und ob ich es selbst schon benutzt habe) halte ich mich besser aus der Hardware raus. Da fließt mir zu viel Strom :wink:

Zeig doch mal ein reales Bild der Unterseite des Moduls, ob das überhaupt für die Spannung von 230V geeignet ist. (oder hast Du gar 400V?)

Gruß Tommy

Hier hier sind Fotos von dem Relais. Würdet Ihr das so wie auf der Skizze mit dem Arduino verbinden?

Hier ist noch die Unterseite: