Motorsteuerung mit MobaTools

Hallo Gemeinde,

wie bekomme ich es gebacken, in einem Programmablauf mit meheren Steppern und unter Verwendung derMobaTools Eieruhr ""TimerMotor1.setTime(2600);""TimerMotor1.expired()"" einen Motor ohne das Programm anzuhalten ständig eine definierte Vor und Zurückbewegung macht ""Motor1.setSpeed(3000);""Motor1.doSteps(-2400);"" während andere Teile des Programmes weiter abgearbeitet werden. Denn mit dem Befehl:""IF TimerMotor1.expired()"" wartet der Code ja auch bloß bis die Zeit abgelaufen ist. Denkfehler?

Mario

Nein, das tut er nicht. Er prüft das jedesmal wenn er da vorbeikommt. Bleibt da aber nicht stehen bis die Zeit um ist. Zeig einfach mal was Du bisher hast ( vergiss die Codetags nicht wenn Du Code postest :wink: ).
Eigentlich sind alle Klassen in den MobaTools dafür geschrieben, dass man 'leicht' blockadefreien Code schreiben kann. Ich wüsste jetzt nicht, dass es auch nur einen Aufruf gibt, der blockiert :thinking: :innocent:

Hallo MicroBahner,

das ging aber fix, ja das war wohl ein Denkfehler von mir, der Code prüft also ob Uhr abgelaufen, wenn ja führt er den weiteren Code aus, wenn nicht läuft er eine weiter Schleife bis Uhr abgelaufen. Kann ich eigendlich die Vor und Rückbewegung des Motors anders als so:`

Motor1.setSpeed(6000);
Motor1.doSteps(1940);
TimerMotor1.setTime(2000);
 
if (TimerMotor1.expired())
Motor1.doSteps(-1940);`       
TimerMotor1.setTime(2000); 

if (TimerMotor1.expired())

usw. realisieren?

Mario

Das würde ich nicht über einen Timer realisieren, sonder abfragen ob der Motor das Ziel erreicht hat. Z.B mit .moving().

Das muß ich mir morgen mal ganz genau anschauen. Im Endeffekt werden 6 Stepper zusammenarbeiten. Beim Start des Zählgerätes sollen die relevanten Motoren auf eine Lichtschranke fahren, um Ihre Startposition festzustellen. Von da aus wird es ja kein Problem sein, eine Endposition festzustellen.

Das hört sich an als ob du eine blockierende while-Schleife in deinem Code hast.
Vielleicht aber auch nicht.

Man könnte es beurteilen wenn du denn deinen kompletten Sketch gepostest hättest.

Hallo Jungens,

könnte sein, das der Code sehr unübersichtlich ist, hier eine kurze Erklärung dazu:
Zählgerät für Normteile mit Stufenförderer/Doppelförderband für Vereinzelung/Abstellband für Leerbehälter/Zuführband zum Zählen/Abschieber der gefüllten Behälter aufs Abstellband
Nach dem einschalten wird im Display die Anzahl der zu füllenden Becher (16 / 32) und die gewünschte Stückzahl eingegeben.
Danach fahren die Motoren mit Hilfe von Lichtschranken in Ihre Startposition (im Code noch nicht vorhanden)
Dann beginnt der Zählprozess:

// Abkürzungen : FB = Förderband
//               LB = Leerbecher
//               ZB = Zuführband
//               AB = Abschieber
//               PK = Anzahl Becher
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
#include <MobaTools.h>

const byte stepPin = 40;
const byte dirPin = 41;
const byte stepPin1 = 38;
const byte dirPin1 = 39;
const byte stepPin2 = 36;
const byte dirPin2 = 37;
const byte stepPin3 = 34;
const byte dirPin3 = 35;
const byte stepPin4 = 32;
const byte dirPin4 = 33;
const byte stepPin5 = 30;
const byte dirPin5 = 31;
const int stepsPerRev = 200;  // Steps per revolution - may need to be adjusted

Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

MoToStepper MotorSF(stepsPerRev, STEPDIR);   // Motor Stufenförderer
MoToStepper MotorFB1(stepsPerRev, STEPDIR);  // Motor Förderband 1
MoToStepper MotorFB2(stepsPerRev, STEPDIR);  // Motor Förderband 2
MoToStepper MotorLB(stepsPerRev, STEPDIR);   // Motor Leerbehälter
MoToStepper MotorZB(stepsPerRev, STEPDIR);   // Motor Zuführband
MoToStepper MotorAB(stepsPerRev, STEPDIR);   // Motor Abschieber

int qty = 0;           // quantity of parts counted
int del = 50;          // Globaler Entprellzeitraum für Tasten
int becherCount = 32;  // Benutzereingabe: Anzahl der zu füllenden Becher (32/16)
int becherfuell = 0;   // Anzahl der gezählten Becher  (max. 32)
int becherLB = 0;      // Anzahl der Schiebevorgänge aufs ZB (max. 4)
int becherZB = 0;      // Anzahl der Becherplätze ZB (max. 32)
int becherAB = 0;      // Anzahl der Schiebevorgänge vom ZB (max. 4)
int set = 0;           // Benutzereingabe: Anzahl der zu zählenden Teile
byte state = 0;
uint8_t i = 0;              // reads button input
const int signalPin = 23;   // Konstante für den Pin Lichtschranke SF einrichten
const int signalPin1 = 25;  // Konstante für den Pin Lichtschranke LB einrichten
const int signalPin2 = 27;  // Konstante für den Pin Lichtschranke ZB einrichten
const int signalPin3 = 26;  // Konstante für den Pin Lichtschranke AB einrichten
const int signalPin4 = 29;  // Konstante für den Pin Lichtschranke DIN 933 einrichten

int switchState = 0;  // Variable zur Speicherung des Werts des 1.switchPin einrichten
int switchState1, switchState2, switchState3, switchState4;
MoToTimer TimerMotorSF;
MoToTimer TimerMotorFB1;
MoToTimer TimerMotorFB2;
MoToTimer TimerMotorLB;
MoToTimer TimerMotorZB;
MoToTimer TimerMotorAB;

void setup() {
  MotorSF.attach(stepPin, dirPin);
  MotorSF.setSpeed(1200);  // 30 rev/min (if stepsPerRev is set correctly)
  MotorFB1.attach(stepPin1, dirPin1);
  MotorFB1.setSpeed(1200);  // 30 rev/min (if stepsPerRev is set correctly)
  MotorFB2.attach(stepPin2, dirPin2);
  MotorFB2.setSpeed(1200);
  MotorLB.attach(stepPin3, dirPin3);
  MotorLB.setSpeed(1200);  // 30 rev/min (if stepsPerRev is set correctly)
  MotorZB.attach(stepPin4, dirPin4);
  MotorZB.setSpeed(1200);  // 30 rev/min (if stepsPerRev is set correctly)
  MotorAB.attach(stepPin5, dirPin5);
  MotorAB.setSpeed(1200);

  pinMode(signalPin, INPUT);   // Den OUT Lichtschranke SF als Eingang einrichten
  pinMode(signalPin1, INPUT);  // Den OUT Lichtschranke LB als Eingang einrichten
  pinMode(signalPin2, INPUT);  // Den OUT Lichtschranke ZB als Eingang einrichten
  pinMode(signalPin3, INPUT);  // Den OUT Lichtschranke AB als Eingang einrichten
  pinMode(signalPin4, INPUT);  // Den OUT Lichtschranke DIN 933 als Eingang einrichten
  pinMode(22, OUTPUT);         // 5V Lichtschranke SF als Ausgang einrichten
  pinMode(24, OUTPUT);         // 5V Lichtschranke LB als Ausgang einrichten
  pinMode(26, OUTPUT);         // 5V Lichtschranke ZB als Ausgang einrichten
  pinMode(28, OUTPUT);         // 5V Lichtschranke AB als Ausgang einrichten
  pinMode(30, OUTPUT);         // 5V Lichtschranke DIN 933 als Ausgang einrichten

  lcd.begin(16, 2);  // Die Anzahl der Spalten und Zeilen des LCD-Displays einrichten
  lcd.setCursor(0, 0);
  lcd.print("PK    SET    QTY");  // Spaltenüberschriften auf dem LCD-Display
  Serial.begin(115200);
}

void loop() {
  uint8_t buttons = lcd.readButtons();
  switch (state) {
    case 0:
      lcd.setCursor(0, 1);
      lcd.print(becherCount);  // Display "becherCount" on the LCD
      lcd.setCursor(7, 1);
      lcd.print("   ");
      if (buttons) {
        if (buttons & BUTTON_UP && becherCount < 998) {
          becherCount = becherCount + 16;
        } else if (buttons & BUTTON_DOWN && becherCount >= 16) {
          becherCount = becherCount - 16;
        } else if (buttons & BUTTON_SELECT) {
          state = 10;  // Go to the next step
        }
        delay(250);  // Debouncing delay after button press
      }
      break;

    case 10:
      lcd.setCursor(6, 1);
      lcd.print(set);  // Display "set" on the LCD
      if (buttons) {
        if (buttons & BUTTON_UP && set < 998) {
          set = set + 1;
        } else if (buttons & BUTTON_DOWN && set > 1) {
          set = set - 1;
        } else if (buttons & BUTTON_RIGHT && set < 989) {
          set = set + 10;
        } else if (buttons & BUTTON_LEFT && set >= 10) {
          set = set - 10;
          lcd.setCursor(8, 1);
          lcd.print(" ");
        } else if (buttons & BUTTON_LEFT && set >= 100) {
          set = set - 10;
          lcd.setCursor(8, 1);
          lcd.print("F");
        } else if (buttons & BUTTON_SELECT) {
          state = 20;  // Switch to the next state for becherCount
        }
        delay(250);  // Debouncing delay after button press
      }
      break;

    case 20:  // Die ersten 4 Behälter werden aufs ZB geschoben
      digitalWrite(28, HIGH);
      lcd.setCursor(13, 1);
      lcd.print(qty);           // print "qty" to LCD
      if (becherCount == 32) {  // Überprüfen ob 32 Becher wahr
        MotorLB.setSpeed(6000);
        MotorLB.doSteps(-1940);
        becherZB = becherZB + 4;
        Serial.print("Die 1. 4 kleinen Behälter werden aufs ZB geschoben: ");
        Serial.println(becherZB);
        TimerMotorLB.setTime(2500);  // Timer für die Motorbewegung LB
        state = 21;
      } else if (becherCount == 16) {  // Überprüfen ob 16 Becher wahr
        MotorLB.setSpeed(6000);
        MotorLB.doSteps(-3870);
        becherZB = becherZB + 4;
        Serial.print("Die 1. 4 großen Behälter werden aufs ZB geschoben: ");
        Serial.println(becherZB);
        TimerMotorLB.setTime(5500);  // Timer für die Motorbewegung LB
        state = 21;
      }
      break;

    case 21:                                           //  Die ersten 4 Behälter werden 4 Plätze weg transportiert
      if (TimerMotorLB.expired()) {                    // Überprüfen ob Timer Motor LB abgelaufen
        if (becherCount == 32 || becherCount == 16) {  // Überprüfen ob 32 Becher wahr
          MotorZB.setSpeed(3000);
          MotorZB.doSteps(-4800);
          Serial.print("Die 1. 4 kleinen/großen Behälter werden 4 Plätze weg transportiert: ");
          Serial.println(becherZB);
          becherZB = becherZB + 4;
          TimerMotorZB.setTime(5000);  // Timer für die Motorbewegung ZB
        }
        state = 22;
      }
      break;

    case 22:                         // Die zweiten 4 Behälter werden aufs ZB geschoben
      if (TimerMotorZB.expired()) {  // Überprüfen ob Timer Motor ZB abgelaufen
        if (becherCount == 32) {     // Überprüfen ob 32 Becher wahr
          MotorLB.setSpeed(6000);
          MotorLB.doSteps(-1940);
          Serial.print("Die 2. 4 kleinen Behälter werden aufs ZB geschoben: ");
          Serial.println(becherZB);
          TimerMotorLB.setTime(2500);
          // Timer für die Motorbewegung LB
        } else if (becherCount == 16) {  // Überprüfen ob 16 Becher wahr
          MotorLB.setSpeed(6000);
          MotorLB.doSteps(-3870);
          Serial.print("Die 2. 4 großen Behälter werden aufs ZB geschoben: ");
          Serial.println(becherZB);
          TimerMotorLB.setTime(5000);  // Timer für die Motorbewegung LB
        }
        state = 23;  // Zustand für den nächsten Schritt setzen
      }
      break;
    case 23:                                           //  Die zweiten 4 Behälter werden 2 Plätze weg transportiert
      if (TimerMotorLB.expired()) {                    // Überprüfen ob Timer Motor LB abgelaufen
        if (becherCount == 32 || becherCount == 16) {  // Überprüfen ob 32 Becher wahr
          MotorZB.setSpeed(3000);
          MotorZB.doSteps(-2400);
          becherZB = becherZB + 2;
          Serial.print("Die 2. 4 kleinen/großen Behälter werden 2 Plätze weg transportiert: ");
          Serial.println(becherZB);
          TimerMotorZB.setTime(2600);  // Timer für die Motorbewegung ZB
          state = 24;
        }
        break;
        case 24:
          if (TimerMotorZB.expired()) {  //Überprüfen ob Timer Motor ZB abgelaufen
            state = 30;
          }
          break;

        case 30:
          lcd.setCursor(13, 1);
          lcd.print(qty);
          MotorFB1.setSpeed(1500);
          MotorFB1.rotate(-1);
          MotorFB2.setSpeed(1500);
          MotorFB2.rotate(1);
          switchState = digitalRead(signalPin4);

          if (switchState == 0) {  // if photointerrupt detects a part
            qty = qty + 1;
            state = 40;
          }
          break;

        case 40:
          // zählt Teile
          switchState = digitalRead(signalPin4);
          if (switchState == 1) {  // Wenn die Lichtschranke ein Teil erkennt
            state = 30;
          }
          if (qty == set) {
            becherfuell = becherfuell + 1;
            MotorFB1.stop();
            MotorFB2.stop();
            MotorZB.setSpeed(3000);
            MotorZB.doSteps(-1200);
            becherZB = becherZB + 1;
            Serial.print("Ein Becher wurde gefüllt: ");
            Serial.println(becherZB);
            TimerMotorZB.setTime(3000);
            state = 50;
          } else if (becherCount == becherfuell) {
            becherfuell = 0;
            state = 0;
          }
          break;

        case 50:
          if (TimerMotorZB.expired()) {
            Serial.println("Ein Becher wurde bewegt");
            qty = 0;  // Die gezählte Stückmenge zurücksetzen
            lcd.setCursor(13, 1);
            lcd.print("   ");
            lcd.setCursor(13, 1);
            lcd.print(qty);  // Schreibe LCD-Menge auf Null
            state = 51;
          }
          break;
        case 51:
          if ((becherCount == 32) && (becherZB == 5 || becherZB == 9 || becherZB == 13 || becherZB == 17 || becherZB == 21 || becherZB == 25 || becherZB == 29 || becherZB == 33)) {  // Zuerst die nächsten 4 großen Behälter aufs ZB schieben
            MotorAB.setSpeed(6000);
            MotorAB.doSteps(3000);
            state = 52;
          } else {
            state = 60;
          }
          break;
        case 52:
          MotorAB.setSpeed(6000);
          MotorAB.doSteps(-3000);
          state = 60;
      }
      break;
    case 60:
      if ((becherCount == 16) && (becherZB == 12 || becherZB == 16)) {  // Zuerst die nächsten 4 großen Behälter aufs ZB schieben
        MotorLB.setSpeed(6000);
        MotorLB.doSteps(-3870);
        Serial.print("4 große Behälter aufs ZB: ");
        Serial.println(becherZB);
        TimerMotorLB.setTime(4000);
        state = 61;
      } else if ((becherCount == 32) && (becherZB == 12 || becherZB == 16 || becherZB == 20 || becherZB == 24 || becherZB == 28 || becherZB == 32)) {
        // Dann die nächsten 4 kleinen Behälter aufs ZB schieben
        MotorLB.setSpeed(6000);
        MotorLB.doSteps(-1940);
        Serial.print("4 kleine Behälter aufs ZB: ");
        Serial.println(becherZB);
        TimerMotorLB.setTime(2000);
        state = 61;
      } else {
        state = 30;
      }
      break;
    case 61:
      if (TimerMotorLB.expired()) {                                                            // Der Zustand 61 für das Zurückbewegen von LB wird nach den Aktionen zum Behälterverschieben eingeführt
        if ((becherCount == 32 && becherZB == 32) || (becherCount == 16 && becherZB == 16)) {  // Nun LB zurückbewegen
          MotorLB.setSpeed(6000);
          MotorLB.doSteps(15450);
          Serial.println("Der LB Motor bewegt sich zurück");
          becherLB = 0;
          TimerMotorLB.setTime(15000);
          becherfuell = 0;
          state = 0;
          lcd.setCursor(0, 1);
          lcd.print(becherCount);  // Display "becherCount" on the LCD
          lcd.setCursor(7, 1);
          lcd.print("   ");
        } else {
          state = 30;
        }
      }
      break;

    case 70:
      // Zustand 70 Logik hier
      break;
  }
}

in dem du diesen Programmteil schlicht und ergreifend unabhängig vom Rest laufen lässt.
Du hast geschrieben

Ich verstehe das so: absolut immer ganz egal was das restliche Programm macht.
Das würde dann so aussehen

void loop() {
  motorStaendigVorZurueck();

  uint8_t buttons = lcd.readButtons();
  switch (state) {
....

Wenn es denn doch nicht immer sein soll, dann würde man noch einen booleschen Schalter (Auch nur eine boolesche Variable ) einbauen

void loop() {
  if (sortierenGestartet == true) {
    motorStaendigVorZurueck();
  }

  uint8_t buttons = lcd.readButtons();
  switch (state) {
....

Dein Code ist in der Tat unübersichtlich.
Als ersten Schritt würde ich mal statt der Zahlen im switchcasebreak constanten deklarieren deren Namen die Funktion selbsterklärend auf den Punkt bringt.

Desweiteren würde ich das Programm so weit in functions unterteilen, dass jede function wirklich nur EINE Sache macht. Wiederum mit einem function-namen der es selbsterklärend auf den Punkt bringt

case 0: würde dann vermutlich so etwas wie
case becherAnzahlEinstellen:
heißen
oder hier statt

case 20:  // Die ersten 4 Behälter werden aufs ZB geschoben

würde es heißen

case behaelterAufZaehlband:  // dann braucht man keinen Kommentar mehr

Hallo,
ich bin mittlerweile etwas weiter mit meinen Ausführungen. In der MobaTools Bibliothek gibt es den Befehl "if (not Stepper.moving();" Damit werden alle Motorbewegungen "Stepper.doSteps(1200);" bis zum Ende ausgeführt.
Nun komme ich aber an einen Punkt, wo der Stufenförderer kontinuierlich Auf-und Abwärtsbewegungen machen soll wärend gleichzeitig der Zählsensor Teile vor der Lichtschranke erkennen soll. Und da komme ich nicht weiter. Er fördert, aber er zählt nicht oder er zählt und fördert nicht:

        case 23:
          if (not MotorZB.moving() && not MotorSF.moving()) {  // Überprüfen, ob Zuführband und Stufenförderer nicht mehr bewegt werden
            MotorFB1.setSpeed(1500);                           // Förderband1 Abtransport bewegen
            MotorFB1.rotate(-1);
            MotorFB2.setSpeed(1500);  // Förderband2 Abtransport bewegen
            MotorFB2.rotate(1);
            MotorSF.setSpeed(5600);  // Stufenförderer nach oben bewegen
            MotorSF.doSteps(-5080);
            digitalWrite(30, HIGH);  // Kontinuierlich zählen während des Aufwärtsbewegungsprozesses
            lcd.setCursor(13, 1);
            lcd.print(qty);
            switchStateZ = digitalRead(signalPinZ);
            if (switchStateZ == 1) {  // Lichtschranke erkennt ein Teil
              qty = qty + 1;
            }
            state = 24;  // Wechsel zum nächsten Zustand
          }
          break;

        case 24:                       // Überprüfen, ob der Stufenförderer nicht mehr bewegt wird
          if (not MotorSF.moving()) {  // Stufenförderer nach unten bewegen
            MotorSF.setSpeed(5600);
            MotorSF.doSteps(5080);  // Kontinuierlich zählen während des Abwärtsbewegungsprozesses
            switchStateZ = digitalRead(signalPinZ);
            if (switchStateZ == 0) {  // Wenn die Lichtschranke kein Teil erkennt
              state = 23;
            }

            if (qty == set) {  // Wenn die gewünschte Anzahl an Teilen erreicht ist
              becherfuell = becherfuell + 1;
              MotorFB1.stop();
              MotorFB2.stop();
              MotorZB.setSpeed(1800);
              MotorZB.doSteps(-1200);
              becherZB = becherZB + 1;
              state = 26;
            } else if (becherCount == becherfuell) {
              becherfuell = 0;
              state = 0;
            }
          }
          switchStateZ = digitalRead(signalPinZ);  // Kontinuierlich zählen während des Abwärtsbewegungsprozesses
          if (switchStateZ == 1) {                 // Lichtschranke erkennt ein Teil
            qty = qty + 1;
            state = 23;  // Spiel beginnt von vorn
          }
          break;
      }
  }

Nur der Zählvorgang in einem Democode funktioniert:

    case 2:
      digitalWrite(30, HIGH);
      lcd.setCursor(13, 1);
      lcd.print(qty);
      switchStateZ = digitalRead(signalPinZ);
      if (switchStateZ == 1) {  // Lichtschranke erkennt ein Teil
        qty = qty + 1;          // Stufenförderer einrichten
        state = 3;
      }
      break;

    case 3:
      switchStateZ = digitalRead(signalPinZ);
      if (switchStateZ == 0) {  // Wenn die Lichtschranke kein Teil erkennt
        state = 2;
      }
      break;
  }
}

Wo liegt mein Denkfehler?

Mario

So wie ich dich verstehe, willst Du zählen, während die Motore sich bewegen. Du fragst die Lichschranke aber nur ab, wenn die Motore ihr Ziel ereicht haben.
Deshalb müssten diese Zeilen:

            if (switchStateZ == 1) {  // Lichtschranke erkennt ein Teil
              qty = qty + 1;
            }

aus dem if-Block raus, damit sie bei jedem Durchlauf von case 23 ausgeführt werden.

Und nimm dir den Tip von @StefanL38 bezügl. der Lesbarkeit deines Codes zu Herzen!

Hab mir schon den Kopf zermardert, wie ich es anstelle denn das if im case 23 muß ja erhalten bleiben damit der Stufenförderer (SF) seine Anzahl Schritte macht. Das zählen soll in der Tat unabhängig von der Motorbewegung SF erfolgen. Erst wenn qty==set werden verschiedene weitere Aktionen fällig. Das ist dann eine andere Geschichte. Und ja, der Code gehört aufgeräumt.

Mario

ich bin jetzt mit den Detailabläufen deiner Maschine nicht vertraut.
Und kann es auch nicht richtig werden weil du nur Zahlen im switch-case verwendest.

Diese Zahlen sagen dir in einem halben Jahr wenn du den Code verändern willst auch nix mehr.
Deswegen gebe dir einen Ruck und führe enum-konstanten ein.

Ich würde das so machen:
Zunächst nur als Kommentar hinter der Nummer

case 23: // dreiWortName  
          if (not MotorZB.moving() && not MotorSF.moving()) {  // Überprüfen, ob Zuführband und Stufenförderer nicht mehr bewegt werden
..
..
case 24:  // dreiWortName
          if (not MotorSF.moving()) {  // Stufenförderer nach unten bewegen

und dann wenn du die Konstanten hingeschrieben hast
alle in der enum-Definition zusammentragen.

Das gilt noch viiiel mehr für EIn/Ausgänge

digitalWrite(30, HIGH);  

statt der Zahl 30 eine Konstante definieren.
Du suchst dich dumm und dusselig wenn du den IO-pin noch einmal änderst und dann an einer Stelle im Programm vergisst die "30" in eine - keine Ahnung - "42" änderst.

Wenn es eine Konstante mit selbsterklärendem Namen ist verstehst du später dein eigenes Programm schneller und besser und wenn du es an dieser einen Stelle den Zahlenwert geändert hast dann stimmt er überall.

Zu der Abfrage der Zähllichtschranke:

Es könnte sein dass eine einfache Abfrage auf den Zustand
ausserhalb der anderen If-Bedingung

if (switchStateZ == 1) {  // Lichtschranke erkennt ein Teil
              qty = qty + 1;
            }

nicht funktioniert. Sondern dass es notwendig wird den Wechsel von LOW nach HIGH zu erkennen.
Das nennt man Flankenerkennung.

Und das ist noch eine Stelle wo sich Konstanten lohnen:

const byte teilVorLS = HIGH // LS wie L)icht-S)schranke
const byte keinTeilVorLS = !teilVorLS   // mit "!" das HIGH automatisch zum LOW invertieren

if (switchStateZ == teilVorLS) {
...}

if (switchStateZ == keinTeilVorLS ) {
...}

Aber es gibt eben auch Leute die ihr Leben nur dann spannend und interessant finden, wenn sie immer wieder aufs neue mit halbausgegorenen Schnellschüssen aus der Hüfte drei Stunden lang herumprobiert haben bis es läuft
statt
einmal 30 Minuten in gut formulierte Konstanten zu investieren
und dann zukünftig innerhalb von drei Minuten die Programmanpassung fertig haben.

Hallo,

ich war halt der Ansicht, da ich die Zählung schon bei einem anderen einfachen Gerät verwende, das eins zu eins auf diese Zählmaschine zu übertragen. Dort wird nur eine Drehbewegung gestartet bis qty= set.
Nun blockieren sich die if-Abfrage der Motorbewegung und die des Zählens gegenseitig.
Mit der Flankenerkennung könnte ich das Problem lösen? Oder gibt es weiter Möglichkeiten den Motor SF ständig (bis qty=set) nach oben und unten zu bewegen?

Mario

Hallo,

die für mich einfache Lösung mit dem rausschmeissen der Zählung aus dem if-Block hat leider nicht funktioniert, und auch der Stufenförderer will nach dem ersten Hoch und Runter nur noch nach unten:

case Zählung erkennt Teil:
  // Überprüfen, ob Zuführband und Stufenförderer nicht mehr bewegt werden
  if (not MotorZB.moving() && not MotorSF.moving()) {
    MotorFB1.setSpeed(1500);
    MotorFB1.rotate(-1);
    MotorFB2.setSpeed(1500);
    MotorFB2.rotate(1);
    MotorSF.setSpeed(5600);
    MotorSF.doSteps(-5080);
  }
  // Kontinuierlich zählen, unabhängig davon, ob die Motoren sich bewegen oder nicht
  digitalWrite(30, HIGH);
  lcd.setCursor(13, 1);
  lcd.print(qty);
  switchStateZ = digitalRead(signalPinZ);
  if (switchStateZ == 1) {
    qty = qty + 1;
  }
  state = Zählung erkennt kein Teil;  // Wechsel zum nächsten Zustand
  break;

case Zählung erkennt kein Teil:
  if (not MotorSF.moving()) {
    // Stufenförderer nach unten bewegen
    MotorSF.setSpeed(5600);
    MotorSF.doSteps(5080);
    state = Zählung erkennt Teil;
    switchStateZ = digitalRead(signalPinZ);
    if (switchStateZ == 0) { // Wenn die Lichtschranke kein Teil erkennt
      state = Zählung erkennt Teil;  // Wenn kein Teil erkannt wird, wechseln Sie zurück zu case 23
    }
    // Wenn die gewünschte Anzahl an Teilen erreicht ist
    if (qty == set) {
      becherfuell = becherfuell + 1;
      MotorFB1.stop();
      MotorFB2.stop();
      MotorZB.setSpeed(1800);
      MotorZB.doSteps(-1200);
      becherZB = becherZB + 1;
      state = Band weiter bewegen;
    } else if (becherCount == becherfuell) {
      becherfuell = 0;
      state = Eingabe Bechercount;
    }
  }
  break;

Was würde die Flankenerkennung beim Durchlaufen dieser cases schneller oder anders machen?

Mario

So ein Enum geht nicht. Wenn dann ZählungErkenntTeil

Wahrscheinlich muss das alles in einzelne States

und

Deine Zählung muss wahrscheinlich auch in eine eigne Statmaschiene.

In der loop hast du dann mehrere Statemachinen die (parallel) laufen.

Hallo Werner,

Das ist für mich absolutes Neuland. Wie wird sowas vom Code her aufgebaut, bzw so gesteuert, das eine gegenseitige Beeinflussung stattfindet ( if qty = set) MotorSF.stop() ?
Hängt das damit zusammen das der SF-Motor ständig die Richtung ändern muß?
In unserem Vorgängermodell drehte sich nur ein Motor in eine Richtung bis qty = set. Das hat sehr gut funktioniert.

Mario

Schau dir mal Arduino: Programmiertechniken/Entwicklung – Wikibooks, Sammlung freier Lehr-, Sach- und Fachbücher an. Da sind in dem letzten Beispiel 3 getrennte Statemaschinen die sich gegenseitig beeinflussen. Am Besten gehst du die ganze Entwicklung einmal durch.

Könnte dies ein Ansatz sein:

void loop() {
  switch (SF_States) {
    case hoch:
      if (not MotorSF.moving()) {
        MotorSF.setSpeed(5600);
        MotorSF.doSteps(-5080);
      }
      break;
    case runter:
      if (not MotorSF.moving()) {  // Stufenförderer nach unten bewegen
        MotorSF.setSpeed(5600);
        MotorSF.doSteps(5080);
      }
      break;
  }

  switch (Teilezähler) {
    case Lichtschranke_verdeckt:
      digitalWrite(30, HIGH);
      lcd.setCursor(13, 1);
      lcd.print(qty);
      switchStateZ = digitalRead(signalPinZ);
      if (switchStateZ == 1) {
        qty = qty + 1;
      }
      break;
    case Lichtschranke frei:
          if (switchStateZ == 0) {
        state = Lichtschranke_verdeckt;
      }
      break;

Mario

ja der Ansatz sollte so gehen.

Hab jetzt in den Einstellungen:

enum SF_States {
  hoch,    //1
  runter,  //2
};

enum Teilezaehler {
  Lichtschranke_frei,      //0
  Lichtschranke_verdeckt,  //1
};

Teilezaehler TeilezaehlerState = Lichtschranke_frei;
SF_States currentState = hoch;

void loop() {
  switch (TeilezaehlerState) {
    case Lichtschranke_frei:
      digitalWrite(30, HIGH);
      lcd.setCursor(13, 1);
      lcd.print(qty);
      switchStateZ = digitalRead(signalPinZ);
      if (switchStateZ == 1) {
        qty = qty + 1;
        TeilezaehlerState = Lichtschranke_verdeckt;  // Ändere den Zustand auf Lichtschranke verdeckt
      }
      break;
    case Lichtschranke_verdeckt:
      switchStateZ = digitalRead(signalPinZ);
      if (switchStateZ == 1) {
        currentState = hoch;  
      }
      break;
  }

switch (currentState) {  
    case hoch:
      if (not MotorSF.moving()) {
        MotorSF.setSpeed(5600);
        MotorSF.doSteps(-5080);
        currentState = runter;
      }
      break; 

    case runter:
      if (not MotorSF.moving()) {
        MotorSF.setSpeed(5600);
        MotorSF.doSteps(5080);
        TeilezaehlerState = Lichtschranke_frei;
      }
      break; 
}
}

Aber nun dachte ich, das er Zähl und Bewegungsschleife nacheinander durchläuft, macht er aber nicht, es wird die Drehrichtung des Motors erst nach Sekunden "
if (not MotorSF.moving()) {" geändert.

Mario