Seifenblasenmaschine mit Lichtschranken steuern

Hallo beisammen
Es geht um folgendes Problem: Der Hebearm einer Seifenblasenmaschine fährt zwischen einem Seifenlaugenbehälter und einem Ventilator hin- unf her. Das ganze soll über zwei Gabellichtschranken gesteuert werden.
PAP:
Der Hebearm soll kurz (2-3sec) in die Lauge tunken
dann nach oben fahren bis zur oberen Lichtschranke am Ventilator
vor dem Ventilator kurz warten (3sec), damit Seifenblasen gepustet werden
dann wieder nach unten fahren zur unteren Lichtschranke am Behälter
das ganze dann wieder von vorne

ich habs mit zwei Codes probiert:
Code mit Interrupt: der Hebearm fährt gut zwischen den Lichtschranken hin- und her, macht aber keine Pause. Sowohl delay als auch millis für Pause funktioniert nicht (geht nicht mit interrupt)

const int LS1 = 2;          // Lichtschranke 1 (LS1) unten
const int LS2 = 3;          // Lichtschranke 2 (LS2) oben
const int in1 = 9 ;           // Die beiden Motorpins an der Motorwendeplatine L298N
const int in2 = 10 ;
const int enA = 11;

volatile int LS1Status = 0;     //Vektoren für die Lichtschranken werden definiert    
volatile int LS2Status = 1; 
                   
void setup() {
          pinMode(in1, OUTPUT);            //in1 HIGH fährt nach unten 
          pinMode(in2, OUTPUT);            //in2 HIGH fährt nach oben
          pinMode(enA, OUTPUT);
          pinMode(LS1, INPUT);             //Lichtschranke offen = 0       Lichtschranke zu =1 
          pinMode(LS2, INPUT); 
           
          attachInterrupt(0,LS1gehtzu, RISING) ;      //LS1 von 0 nach 1           
               
          attachInterrupt(1,LS2gehtzu, FALLING) ;      //LS2 von 0 nach 1           
                                                                                      
        }
void loop() {                                   //loop bleibt leer      
  }
  
void LS1gehtzu(){                                 //LS1 unten von 0 nach 1 
 
    
  digitalWrite (in2,HIGH);            //soll in2 HIGH sein => Motor dreht sich wieder und fährt Hebearm aus LS1 nach oben
  digitalWrite (in1,LOW);
  analogWrite (enA,50);
 
  }
  
void LS2gehtzu() {                            //LS2 oben von 0 nach 1 

    
  digitalWrite (in1,HIGH);            //soll in1 HIGH sein => Motor dreht sich wieder und fährt Hebearm aus LS2 nach unten
  digitalWrite (in2,LOW);  
  analogWrite (enA,50);
  
  }
  

Code mit switch case: Der Motor fährt aus der Lichtschranke raus, zwischen den Lichtschranken gibt der Motor aber nur ein hohes Summen ab, es passiert nichts. Wahrscheinlich ist der Zustand beide Lichtschranken 0 nicht eindeutig.

const int LS1 = 2; // Lichtschranke 1 unten
const int LS2 = 3; // Lichtschranke 2 oben
int in1 = 9;
int in2 = 10;
int statusLS1 = 0;
int statusLS2 = 0;
const byte start = 0;
const byte fahrt_nach_oben = 1;
const byte dispenser_oben = 2;
const byte fahrt_nach_unten =3;
const byte dispenser_unten =4;
const long wartezeit = 3000;
unsigned long previousMillis = 0; 
int state = start;

void setup() {

  pinMode (LS1, INPUT);       //LS offen ==0  LS geschlossen==1
  pinMode (LS2, INPUT);       //LS offen ==0  LS geschlossen==1
  pinMode (in1, OUTPUT);      //in1 HIGH fährt nach unten
  pinMode (in2, OUTPUT);      //in2 HIGH fährt nach oben

}

void loop() {

  statusLS1 = digitalRead (LS1);
  statusLS2 = digitalRead (LS2);

  
  unsigned long currentMillis = millis();
   
  switch (state) {

  case start:
      digitalWrite (in1, HIGH);                         //in1 HIGH fährt nach unten
      digitalWrite (in2, LOW);
      if (statusLS1 == 1 || statusLS2 == 0) {          //LS unten schließt 
          state = fahrt_nach_oben;
     }
     
  case fahrt_nach_oben:
      digitalWrite (in2, HIGH);                           //in2 HIGH fährt nach oben
      digitalWrite (in1, LOW);
      if (statusLS1 == 0 || statusLS2 == 1) {            //LS oben schließt
            state = dispenser_oben;
      }
      break;

  case dispenser_oben:
      digitalWrite (in2, LOW);
      digitalWrite (in1, LOW);
      if (currentMillis - previousMillis >= wartezeit){  //Motor steht für 3sec oben
            previousMillis = currentMillis;
            digitalWrite (in2, LOW);
            digitalWrite (in1, LOW);
      } 
      digitalWrite (in1, HIGH);                        //in1 HIGH fährt nach unten
      digitalWrite (in2, LOW);
      
      if (statusLS1 == 0 || statusLS2 == 0) {         //beide LS offen
            state = fahrt_nach_unten;
      }
      break;

  case fahrt_nach_unten:
      digitalWrite (in1, HIGH);                          //in1 HIGH fährt nach unten
      digitalWrite (in2, LOW);
      if (statusLS1 == 1 || statusLS2 == 0) {           //LS unten schließt
            state = dispenser_unten;
      }
      break;

  case dispenser_unten:
     digitalWrite (in1, LOW);
     digitalWrite (in2, LOW);
     if (currentMillis - previousMillis >= wartezeit){  //Motor steht für 3sec unten
            previousMillis = currentMillis;
            digitalWrite (in1, LOW);
            digitalWrite (in2, LOW);
      }
      digitalWrite (in2, HIGH);                          //in2 HIGH fährt nach oben
      digitalWrite (in1, LOW);
      if (statusLS1 == 0 || statusLS2 == 0) {             //beide LS offen
            state = fahrt_nach_oben;
      }
      break;
  } 
}

Bin dankbar für jeden Tip.
Danke schonmal!

Und wofür brauchst du da den Interrupt?

Und warum eröffnest du einen zweiten Thread zum selben Thema.

Und wie Franz schon vermutet, du brauchst dafür keinen Interrupt.

  case start:
      digitalWrite (in1, HIGH);                         //in1 HIGH fährt nach unten
      digitalWrite (in2, LOW);
      if (statusLS1 == 1 || statusLS2 == 0)            //LS unten schließt
      {
        state = fahrt_nach_oben;
      }

Das ist schon grundsätzlich zu hinterfragen.
Das ODER dazwischen ist doch gar nicht notwendig.
Du willst eine Schrittkette.
Dann prüfe doch nicht das Ende UND den Anfang.

Frage 1: Überfährt der Antrieb die Lichtschranke?
Wenn ja, hast Du keinen Startpunkt und weisst nicht wo Du stehst.
Alles was Du dann versuchst geht ins Leere.

Frage 2: Wenn der Sensor überfahren werden kann, wieviel Zeit vergeht bis zum Halt? UND wenn Du die Überfahrzeit (bis zum Halt) verdoppelst, bleibt dann noch eine mögliche Lücke, bevor der Löffel anschlägt?

Ich habe eine Seifenblasmaschiene mit einem Servo und einem Motor mit Propeller (Du findest Ihn wenn Du nach L9110 suchst) gebaut.

Da braucht es keine Positionssensoren des Arms.

Der Blasring wird über einen Faden an den 2 Dräten als Führung hochgezogen. Der Faden läuft über das Rad das der Servo (andere Seite montiert) bewegt wird.

Wenn man ein ordentiches Foto sucht findet man keines. Ich mache morgen eines.
Die Idee zum Aufbau stammt von einem Foto und Video eines Workshps des Fablabs München Bau einer Arduino-gesteuerten Seifenblasen-Maschine
Grüße Uwe

Hööö, das Ding schaut ja gut aus :grinning:

Nein, der Sensor wird nicht überfahren, sondern ist quasi der Endpunkt, von wo aus der Motor dann seine Drehrichtung ändert. Benutze dafür eine Motorwendeplatine L298N.

Mach mal ein Foto des Aufbaus.
Welchen Motor hast Du?

Wenn das garantiert ist, kannst das kürzer machen.
Möchtest mal probieren?

const byte lichtSchrankeUnten = 2; // Lichtschranke 1 unten
const byte lichtSchrankeOben = 3; // Lichtschranke 2 oben
const byte fahreHoch = 9;
const byte fahreRunter = 10;
unsigned long pauseStart = 0;
const unsigned long pauseZeit = 3000;
enum {fahrtAuf, dispenserOben, fahrtAb, dispenserUnten, error};
byte schritt = fahrtAb;
const bool geschlossen = true;
const bool offen = false;
void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  pinMode(lichtSchrankeUnten, INPUT);     // LS offen == LOW
  pinMode(lichtSchrankeOben, INPUT);      // LS geschlossen == HIGH
  digitalWrite(fahreRunter, LOW);
  digitalWrite(fahreHoch, LOW);
  pinMode(fahreRunter, OUTPUT);           // HIGH fährt nach unten
  pinMode(fahreHoch, OUTPUT);             // HIGH fährt nach oben
  if (lichtSchrankeOben == offen)         // Wenn nicht oben angeschlagen
    schritt = fahrtAuf;
}

void bewegungAb()
{
  digitalWrite(fahreHoch, LOW);
  digitalWrite(fahreRunter, HIGH);
}

void bewegungAuf()
{
  digitalWrite(fahreRunter, LOW);
  digitalWrite(fahreHoch, HIGH);
}

void bewegungHalt()
{
  digitalWrite(fahreRunter, LOW);
  digitalWrite(fahreHoch, LOW);
}

void loop()
{
  if (lichtSchrankeOben == geschlossen &&
      lichtSchrankeUnten == geschlossen) schritt = error;
  switch (schritt)
  {
    case fahrtAuf:
      bewegungAuf();
      if (lichtSchrankeOben == geschlossen)
      {
        bewegungHalt();
        pauseStart = millis();
        schritt = dispenserOben;
        Serial.println(F("Nächster Schritt: oben eintauchen"));
      }
      break;
    case dispenserOben:
      bewegungHalt();
      if (millis() - pauseStart >= pauseZeit)
      {
        schritt = fahrtAb;
        Serial.println(F("Nächster Schritt fahre runter"));
      }
      break;
    case fahrtAb:
      bewegungAb();
      if (lichtSchrankeUnten == geschlossen)
      {
        bewegungHalt();
        pauseStart = millis();
        schritt = dispenserUnten;
        Serial.println(F("Nächster Schritt: unten eintauchen"));
      }
    case dispenserUnten:
      bewegungHalt();
      if (millis() - pauseStart >= pauseZeit)
      {
        schritt = fahrtAuf;
        Serial.println(F("Nächster Schritt fahre hoch"));
      }
      break;
    case error:
      Serial.println(F("Sensoren reinigen - dann reset"));
      while (1);
      break;
  }
}

Vielen Dank für den Code, aber leider läuft das ganze nicht wie gewünscht. Die Motor fährt nur nach unten.


Hier ein Foto meines Aufbaus, vereinfacht ohne Seifenblasen.
Also Motor benutze ich einen RU280, den gibts bei Traudl&Riess.
https://www.traudl-riess.de/shop.php?groupIDX=6196&itemIDX=26851&txt=Motor%20RU%20280
Motorwendeplatine ist L298N und ich verwende einen Arduino UNO.

Das ganze ist ein Schulprojekt in Klasse 9, der Code sollte also so einfach wie möglich gehalten werden, sonst blicken die Schüler nicht mehr durch.

Wie sehen die Ausgaben auf dem Seriellen Monitoor aus?
Ich schau nochmal drauf, aber wenn ich es nicht finde, muss er irgendwo stehen bleiben... :wink:

ich habs.
In der Ursprungsversion war die Abfrage der Sensoren auch ausgelagert - dann hab ich beim suchen und ersetzen die Funktionen gelöscht, aber das digitalRead( vergessen.

Es muss sowohl für lichtSchranke Oben als auch für lichtSchrankeUnten heissen:

 if (digitalRead(lichtSchrankeOben)

bzw.

 if (digitalRead(lichtSchrankeUnten)

Code komplett:

const byte lichtSchrankeUnten = 2; // Lichtschranke 1 unten
const byte lichtSchrankeOben = 3; // Lichtschranke 2 oben
const byte fahreHoch = 9;
const byte fahreRunter = 10;
unsigned long pauseStart = 0;
const unsigned long pauseZeit = 3000;
enum {fahrtAuf, dispenserOben, fahrtAb, dispenserUnten, error};
byte schritt = fahrtAb;
const bool geschlossen = true;
const bool offen = false;
void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  pinMode(lichtSchrankeUnten, INPUT);     // LS offen == LOW
  pinMode(lichtSchrankeOben, INPUT);      // LS geschlossen == HIGH
  digitalWrite(fahreRunter, LOW);
  digitalWrite(fahreHoch, LOW);
  pinMode(fahreRunter, OUTPUT);           // HIGH fährt nach unten
  pinMode(fahreHoch, OUTPUT);             // HIGH fährt nach oben
  if (lichtSchrankeOben == offen)         // Wenn nicht oben angeschlagen
    schritt = fahrtAuf;
}

void bewegungAb()
{
  digitalWrite(fahreHoch, LOW);
  digitalWrite(fahreRunter, HIGH);
}

void bewegungAuf()
{
  digitalWrite(fahreRunter, LOW);
  digitalWrite(fahreHoch, HIGH);
}

void bewegungHalt()
{
  digitalWrite(fahreRunter, LOW);
  digitalWrite(fahreHoch, LOW);
}

void loop()
{
  if (digitalRead(lichtSchrankeOben) == geschlossen &&
      digitalRead(lichtSchrankeUnten) == geschlossen) schritt = error;
  switch (schritt)
  {
    case fahrtAuf:
      bewegungAuf();
      if (digitalRead(lichtSchrankeOben) == geschlossen)
      {
        bewegungHalt();
        pauseStart = millis();
        schritt = dispenserOben;
        Serial.println(F("Nächster Schritt: oben eintauchen"));
      }
      break;
    case dispenserOben:
      bewegungHalt();
      if (millis() - pauseStart >= pauseZeit)
      {
        schritt = fahrtAb;
        Serial.println(F("Nächster Schritt fahre runter"));
      }
      break;
    case fahrtAb:
      bewegungAb();
      if (digitalRead(lichtSchrankeUnten) == geschlossen)
      {
        bewegungHalt();
        pauseStart = millis();
        schritt = dispenserUnten;
        Serial.println(F("Nächster Schritt: unten eintauchen"));
      }
      break;
    case dispenserUnten:
      bewegungHalt();
      if (millis() - pauseStart >= pauseZeit)
      {
        schritt = fahrtAuf;
        Serial.println(F("Nächster Schritt fahre hoch"));
      }
      break;
    case error:
      Serial.println(F("Sensoren reinigen - dann reset"));
      while (1);
      break;
  }
}