Arduino Kleinteilezählgerät programieren

Hallo Forum,

ich habe das Modell eines Kleinteilezählgerätes gebaut. Mit diesem sollen Normteile gezählt und in kleine Behälter gefüllt werden.
Der Aufbau ist folgender:
Drehteller 1 oben zum separieren der Normteile angetrieben durch Steppermotor 1
Lasersensor (Sender & Empfänger) zum zählen der separierten Teile
Drehteller 2 unten für die fertig abgezählten VEs

Funktionsbeschreibung:

  1. Einstellung der abzuzählenden Menge am Adafruit LCD Shield 16x2 Zeichen 2 x I2C Pins
  2. Bestätigung über Taster (Es geht los)
  3. Drehteller 1 setzt sich in Bewegung und separiert die Normteile
  4. Laser zählt die Stückzahl hoch, wenn Stückzahl erreicht stoppt Drehteller 1
  5. Nach Füllung des Auffangbehälters dreht Drehteller 2 30 Grad weiter (12 Behälter)
  6. dann setzt sich Drehteller 1 wieder in Bewegung und das Spiel beginnt von vorn bis die Anzahl der programierten Wiederholung (12) erreicht ist.
  7. Stellt der Laser wärend der Schritte 5 und 6 keinen Durchlauf fest, dreht der Teller 1 kurz und schnell im Urzeigersinn zurück um Verstopfungen und Verhakungen aufzulösen.

Nun habe ich im Internet eine Seite entdeckt, da hat jemand einen Vibrationsförderer mit dem Arduino verbunden, und einen Code eingestellt. Der schaltet nach erreichen der eingestellten Menge ein Relais.
Bei mir arbeiten zwei A4988 und zwei NEMA17 1.5A 17HS4401.
Die Zählung erreiche ich mit einem Linienlaser und vier in Reihe geschalteten Fotowiderständen.
Um nun alles einzeln funktionierenden Abläufe miteinander zu verknüpfen fehlt mir jegliche Erfahrung.
Kurz, ich benötige Eure Hilfe, gern auch gegen Gebühr.

MfG
Mario

#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>

Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

int qty = 0; // quantity of parts counted
int del = 50; // global debounce duration for buttons
int set = 0; // user input number of parts to be counted
uint8_t i = 0; // reads button input
const int signalPin = A0; // set up a constant for the photointerrupt signal pin
int switchState = 0; // variable to hold the value of the switchPin
int prevSwitchState = 0; // variable to hold previous value of the switchpin
int pwr = 13; // power pin to vibration on/off relay

void setup()
{
pinMode(signalPin, INPUT); // set up the switch pin as an input
pinMode(pwr, OUTPUT); // set pwr pin to output
lcd.begin(16, 2); // set up the LCD's number of columns and rows
lcd.setCursor(0, 0);
lcd.print("SET QTY"); // print LCD column headers
}

void loop()
{
lcd.setCursor(0, 1);
lcd.print(set); // print "set" to LCD
lcd.setCursor(13, 1);
lcd.print(qty); // print "qty" to LCD

uint8_t buttons = lcd.readButtons();

if (buttons) // if any button is pressed
{
lcd.setCursor(0, 1);
lcd.print(" "); //clear LCD bottom row for new values

if (buttons & BUTTON_UP && set <= 998) // if "UP" button is pressed
{
set = set + 1; // increase "set" value by one
delay(del); // debounce
}

if (buttons & BUTTON_DOWN && set >= 1) // if "DOWN" button is pressed
{
set = set - 1; // decrease "set value by one
delay(del); //debounce
}

if (buttons & BUTTON_RIGHT && set <= 989) // if "RIGHT" button is pressed
{
set = set + 10; // increase "set" value by ten
delay(del); // debounce
}

if (buttons & BUTTON_LEFT && set >= 10) // if "LEFT" button is pressed
{
set = set - 10; // increase "set" value by ten
delay(del); // debounce
}

if (buttons & BUTTON_SELECT) // if "SELECT" button is pressed
{
digitalWrite(pwr, HIGH); // start vibration
delay(del); // debounce
}
}

 

switchState = analogRead(signalPin); // check the status of the photointerrupt

if (switchState != prevSwitchState) // compare the switchState to its previous state
{
if (switchState == LOW) // if photointerrupt detects a part
{
qty = qty + 1; // increment part count by one
delay(20); // debounce
}
}

{
if (qty == set)
{
delay(400); // delay to clear ramp of counted pieces before stopping vibration.
digitalWrite(pwr, LOW); // stop vibration
qty -= qty; // reset counted part quantity
lcd.setCursor(14, 1);
lcd.print(" "); // write LCD qty zero
}
prevSwitchState = switchState; // reset photointerrupt's state
}
}
1 Like

Hat da eine super intelligente Maschine void setup grammatisch richtig übersetzt? Das wieder rückgängig zu machen helfe ich auf keinen Fall. Mit solchen Maschinen fange ich keinen Streit an. :stuck_out_tongue:

Sorry Michael,

hab es gerade im Original eingefügt. Blöde Autoübersetzung.

Geht das denn mit deinem gefundenen Sketch?

Den Punkt 7. kannst du ja erstmal weglassen

Punkte 5/6 ist ja sehr ähnlich zu 1-4 nur mit anderen Daten: statt Zähler die Fertigmeldung des unterlagerten Schritt 4 und als Anzahl nicht die in deinem Eingabegerät eingestellte Zahl sondern die feste 12.

Es ist keine gute Idee, den Code nachträglich zu ersetzen, da weiß bald niemand mehr auf welche Version sich welcher Kommentar bezieht.

Inzwischen sieht der Code doch ganz passabel aus. Laß ihn mal laufen und berichte, was es für Probleme gibt.

Möglicherweise müssen alle Schritte einzeln getestet werden, wenn das noch nicht geschehen ist.

@DrDiettrich Ich verstehe das Problem so, dass er zwar gut aussieht, aber für etwas anderes gemacht ist. (Das generelle Problem mit "gefundenem" )

Genau das ist es,

Der Sketch kam meinen Anforderungen am nächsten.
Allerdings gibt es da nur einen Motor welcher per Relais geschaltet wird.

Lass ich den (das) Sketch durchlaufen, kann ich die Menge wählen und es findet auch eine Zählung bis zur eingestellten Menge statt. Ist diese erreicht, beginnt die Zählung bei 0. Der Teil funktioniert also.
Nun muß jedoch die Relaisschaltung für einen DC Motor gegen zwei A4988 Schaltungen für Steppermotoren ausgetauscht werden. Und hier fehlt mir das benötigte Wissen.

Mario

Upps...

Gespaltene Persönlichkeit?

Gruß mTommy

Gruppenarbeit?

Ach Man,

Den ersten Beitrag schrieb ich am PC, nun bin ich unterwegs und hab mich in Ermangelung der Einlogdaten neu im Forum angemeldet. Will doch Eure Beiträge kommentieren und nicht bis morgen warten müssen.

Transparenz ist das Alpha und Omega guter Kommunikation!

Ich bin unbezahlbar :rofl:

Meine Anmerkungen:

  1. Mir erschließt sich nicht, warum Drehteller 1 mit einem Schrittmotor angetrieben werden soll. Ein DC-Motor mit H-Brücke zur Richtungsumkehr täte es auch.
  2. Zum Antrieb von Drehteller 2 schreibst Du hingegen nichts. Der positioniert die Behälter, weshalb ein Schrittmotor sinnvoll ist.
  3. Zur Ansteuerung von Schrittmotoren empfehle ich die Bibliothek MobaTools, zu installieren über der Bibliotheksverwalter der IDE.
  4. delay() mußt Du aus Deinen Programmen verbannen, verträgt sich nicht mit Echtzeitanwendungen.
  5. Vom Adafruit LCD Shield lese ich in diesem Forum das erste Mal, da könnte die Unterstützung dünn sein. Ich hoffe, ich irre!
  6. Willst Du wirklich diese Miniaturtaster für eine produktive Maschine einsetzen? Dann könnte ich mit meinen Wurstfingern nicht bei Dir arbeiten :worried:

er hat eh die Adafruit lib dazu installiert. Ansonsten kann ich auch auf meine verweisen https://werner.rothschopf.net/microcontroller/202105_arduino_liquid_crystal_mcp23017_en.htm. Du magst die MCP23017 ja normalerweise eh gern, vieleicht probierst du mal so ein Modul :wink:

Sorry für OT.

@mariob77 ... mich wundert ja dass dein Sketch nur annährnd das machst was du brauchst. Aber generelle Taktik wäre, die einzelnen Schritte die du in #1 beschrieben hast in einzelnen Funktionen auszulagen, jede Funktion einzeln zu testen und dann stückchenweise mit einer "Finite Stat Machine" der Reihe nach aufrufen zu lassen bzw. dieser FSM den Ablauf zu überlassen.

Ein logisches Schaltbild,
einen Programmablauf zeichnen,
dann einen Code machen.

nicht das Pferd von hinten aufzäumen.

Zu Deinen Fragen agmue,

  1. Ich wählte den Schrittmotor wegen des höheren Drehmomentes. Da werden dann Muttern & U-Scheiben durch gequirlt.
  2. Der untere Drehteller kommt in dem kopierten Code nicht vor, da wird einfach nur die obere Zuführung gestoppt.
  3. MobaTools schaue ich mir an.
  4. Austausch durch millis?
  5. Das funktioniert mit der lib ganz gut.
  6. Nein die Taster sind nur beim Test-Modell so verbaut.

Mit der AccelStepper lib und den entsprechenden Werten drehen sich meine Stepper schon. Ich fahre im Vollschritt wegen Drehmoment.

Nun aber alles in die richtige Reihenfolge und Logic zu packen, da fehlen mir etliche Windungen.

Das konstruieren der Teile scheint der kleinere Teil der Lösung zu sein.

Zu 4. Ja, allgemeiner formuliert blockadearme Programmierung, daher auch kein while.

Wenn der Plural ernst gemeint ist, dann frage ich mich, wo der zweite Stepper verbaut ist.

Bist Du Dir da sicher? Ohne Getriebe wird das nix mit hohem Drehmoment, und dann kann man auch einen DC Motor statt Stepper nehmen. Im Stillstand schaltet man den DC Motor einfach ab, während der Stepper dann den meisten Strom zieht.

Bei der Positionierung würde ich mich auch nicht auf den Schrittmotor verlassen, dafür sollte an jeder Position ein Bündig-Schalter benutzt werden, wie bei Aufzügen. Dafür genügt 1 Schalter und Nocken am Drehteller die mechanisch oder optisch abgetastet werden. Einen Schalter brauchst Du auch beim Stepper, für die Anfangsposition, das wird auch nicht einfacher als mit dem DC Motor.

Dann packe die einzelnen Schritte jeweils in ein Unterprogramm, das sich einzeln austesten läßt. Zuletzt werden diese Schritte im fertigen Programm der Reihe nach aufgerufen.

Hallo Mario,

es ist üblich und völlig normal, das man eine neue Coderversion in einem neuen Posting postet.
Als Code-Section verbraucht es nicht viel Bildschirmhöhe.

Nach dem reinen "funktioniert die Baugruppe?"-Test mit einem Breadboard
steige ich auf Lochrasterplatine mit Buchsen/Stiftleisten-Steckverbindungen um.

Da ist mir persönlich der Drahtverhau auf einem Breadboard zu "lose"
Vor allem wenn auch noch Mechanik mit dabei ist.
Wenn man da immer so gaaanz vorsichtig anfassen muss wie beim Entschärfen einer Bombe
mag ich das nicht.

Ansonsten stimme ich zu. Jede Teilfunktion in eine eigene function diese Teilfunktion austesten
dann kommt die nächste.
vgs

Hallo,
Ich Danke Euch für Eure Unterstützung.
Nun läuft das ganze wie es soll.
Feinheiten sind noch einzustellen, wie die Motorgeschwindigkeit oder die Empfindlichkeit der Fotowiderstände.
Ich hab jetzt 12x case /state & break verwendet. Die schließenden Klammern am Ende sind noch suboptimal.

#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
#include <MobaTools.h>
 
const byte stepPin = 3;
const byte dirPin = 2;
const byte stepPin1 = 5;
const byte dirPin1 = 4;
 
const int stepsPerRev = 200;    // Steps per revolution - may need to be adjusted
 
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
 
MoToStepper MotorOben( stepsPerRev, STEPDIR );  // create a stepper instance
MoToStepper MotorUnten( stepsPerRev, STEPDIR );  // create a stepper instance
 
int qty = 0; // quantity of parts counted
int del = 50; // global debounce duration for buttons
int set = 0; // user input number of parts to be counted
byte state = 0;
uint8_t i = 0; // reads button input
const int signalPin = A0; // set up a constant for the photointerrupt signal pin
int switchState = 0; // variable to hold the value of the switchPin
int prevSwitchState = 0; // variable to hold previous value of the switchpin
 
void setup() {
  MotorOben.attach( stepPin, dirPin );
  MotorOben.setSpeed( 1000 );              // 30 rev/min (if stepsPerRev is set correctly)
 
  MotorUnten.attach( stepPin1, dirPin1 );
  MotorUnten.setSpeed( 1000 );              // 30 rev/min (if stepsPerRev is set correctly)
 
  pinMode(signalPin, INPUT); // set up the switch pin as an input
  lcd.begin(16, 2); // set up the LCD's number of columns and rows
  lcd.setCursor(0, 0);
  lcd.print("SET          QTY"); // print LCD column headers
  Serial.begin(9600);
}
 
void loop() {
  lcd.setCursor(0, 1);
  lcd.print(set); // print "set" to LCD
  lcd.setCursor(13, 1);
  lcd.print(qty); // print "qty" to LCD
  uint8_t buttons = lcd.readButtons();
  switchState = analogRead(signalPin);
  Serial.println("aktueller Wert: " + String(switchState));
 
  if (buttons) { // if any button is pressed
    lcd.setCursor(0, 1);
    lcd.print(" "); //clear LCD bottom row for new values
 
    if (buttons & BUTTON_UP && set <= 998) { // if "UP" button is pressed
      set = set + 1; // increase "set" value by one
      delay(del); // debounce
    } else if (buttons & BUTTON_DOWN && set >= 1) { // if "DOWN" button is pressed
      set = set - 1; // decrease "set value by one
      delay(del); //debounce
    } else if (buttons & BUTTON_RIGHT && set <= 989) {// if "RIGHT" button is pressed
      set = set + 10; // increase "set" value by ten
      delay(del); // debounce
    } else if (buttons & BUTTON_LEFT && set >= 10) { // if "LEFT" button is pressed
      set = set - 10; // increase "set" value by ten
      delay(del); // debounce
    }
    if (buttons & BUTTON_SELECT) { // if "SELECT" button is pressed
        MotorOben.setSpeed( 300 );
        MotorOben.rotate( 1 );
      state = 1;
    }
  }
 
  switch (state) {
    case 0:
      //Nix, warten auf Go Button
      break;
    case 1:
      switchState = analogRead(signalPin);
      Serial.println("aktueller Wert: " + String(switchState));
        if (switchState > 600) { // if photointerrupt detects a part
        qty = qty + 1; // increment part count by one
        delay(50); // debounce
        }
        if (qty == set) {
        delay(0); // delay to clear ramp of counted pieces before stopping vibration.
        MotorOben.stop(  );
        }
        if (qty == set) {
        delay(100); // delay to clear ramp of counted pieces before stopping vibration.
        MotorUnten.doSteps( -500 );
        qty -= set; // reset counted part quantity
        lcd.setCursor(14, 1);
        lcd.print("   "); // write LCD qty zero
        if (qty < set) {
        delay(2000);
        MotorOben.setSpeed( 300 );
        MotorOben.rotate( 1 );
        state = 2;
     break;
     case 2:
        switchState = analogRead(signalPin);
        if (switchState > 600) { // if photointerrupt detects a part
        qty = qty + 1; // increment part count by one
        delay(50); // debounce
        }
        if (qty == set) {
        delay(0); // delay to clear ramp of counted pieces before stopping vibration.
        MotorOben.stop(  );
        }
        if (qty == set) {
        delay(100); // delay to clear ramp of counted pieces before stopping vibration.
        MotorUnten.doSteps( -500 );
        qty -= set; // reset counted part quantity
        lcd.setCursor(14, 1);
        lcd.print("   "); // write LCD qty zero
        if (qty < set) {
        delay(2000);
        MotorOben.setSpeed( 300 );
        MotorOben.rotate( 1 );
        state = 3;
     break;
     case 3:
        switchState = analogRead(signalPin);
        if (switchState > 600) { // if photointerrupt detects a part
        qty = qty + 1; // increment part count by one
        delay(50); // debounce
        }
        if (qty == set) {
        delay(0); // delay to clear ramp of counted pieces before stopping vibration.
        MotorOben.stop(  );
        }
        if (qty == set) {
        delay(100); // delay to clear ramp of counted pieces before stopping vibration.
        MotorUnten.doSteps( -500 );
        qty -= set; // reset counted part quantity
        lcd.setCursor(14, 1);
        lcd.print("   "); // write LCD qty zero
        if (qty < set) {
        delay(2000);
        MotorOben.setSpeed( 300 );
        MotorOben.rotate( 1 );
        state = 4;
     break;
     case 4:
        switchState = analogRead(signalPin);
        if (switchState > 600) { // if photointerrupt detects a part
        qty = qty + 1; // increment part count by one
        delay(50); // debounce
        }
        if (qty == set) {
        delay(0); // delay to clear ramp of counted pieces before stopping vibration.
        MotorOben.stop(  );
        }
        if (qty == set) {
        delay(100); // delay to clear ramp of counted pieces before stopping vibration.
        MotorUnten.doSteps( -500 );
        qty -= set; // reset counted part quantity
        lcd.setCursor(14, 1);
        lcd.print("   "); // write LCD qty zero
        if (qty < set) {
        delay(2000);
        MotorOben.setSpeed( 300 );
        MotorOben.rotate( 1 );
        state = 5;
     break;
     case 5:
        switchState = analogRead(signalPin);
        if (switchState > 600) { // if photointerrupt detects a part
        qty = qty + 1; // increment part count by one
        delay(50); // debounce
        }
        if (qty == set) {
        delay(0); // delay to clear ramp of counted pieces before stopping vibration.
        MotorOben.stop(  );
        }
        if (qty == set) {
        delay(100); // delay to clear ramp of counted pieces before stopping vibration.
        MotorUnten.doSteps( -500 );
        qty -= set; // reset counted part quantity
        lcd.setCursor(14, 1);
        lcd.print("   "); // write LCD qty zero
        if (qty < set) {
        delay(2000);
        MotorOben.setSpeed( 300 );
        MotorOben.rotate( 1 );
        state = 6;
     break;
     case 6:
        switchState = analogRead(signalPin);
        if (switchState > 600) { // if photointerrupt detects a part
        qty = qty + 1; // increment part count by one
        delay(50); // debounce
        }
        if (qty == set) {
        delay(0); // delay to clear ramp of counted pieces before stopping vibration.
        MotorOben.stop(  );
        }
        if (qty == set) {
        delay(100); // delay to clear ramp of counted pieces before stopping vibration.
        MotorUnten.doSteps( -500 );
        qty -= set; // reset counted part quantity
        lcd.setCursor(14, 1);
        lcd.print("   "); // write LCD qty zero
        if (qty < set) {
        delay(2000);
        MotorOben.setSpeed( 300 );
        MotorOben.rotate( 1 );
        state = 7;
     break;
     case 7:
        switchState = analogRead(signalPin);
        if (switchState > 600) { // if photointerrupt detects a part
        qty = qty + 1; // increment part count by one
        delay(50); // debounce
        }
        if (qty == set) {
        delay(0); // delay to clear ramp of counted pieces before stopping vibration.
        MotorOben.stop(  );
        }
        if (qty == set) {
        delay(100); // delay to clear ramp of counted pieces before stopping vibration.
        MotorUnten.doSteps( -500 );
        qty -= set; // reset counted part quantity
        lcd.setCursor(14, 1);
        lcd.print("   "); // write LCD qty zero
        if (qty < set) {
        delay(2000);
        MotorOben.setSpeed( 300 );
        MotorOben.rotate( 1 );
        state = 8;
     break;
     case 8:
        switchState = analogRead(signalPin);
        if (switchState > 600) { // if photointerrupt detects a part
        qty = qty + 1; // increment part count by one
        delay(50); // debounce
        }
        if (qty == set) {
        delay(0); // delay to clear ramp of counted pieces before stopping vibration.
        MotorOben.stop(  );
        }
        if (qty == set) {
        delay(100); // delay to clear ramp of counted pieces before stopping vibration.
        MotorUnten.doSteps( -500 );
        qty -= set; // reset counted part quantity
        lcd.setCursor(14, 1);
        lcd.print("   "); // write LCD qty zero
        if (qty < set) {
        delay(2000);
        MotorOben.setSpeed( 300 );
        MotorOben.rotate( 1 );
        state = 9;
     break;
     case 9:
        switchState = analogRead(signalPin);
        if (switchState > 600) { // if photointerrupt detects a part
        qty = qty + 1; // increment part count by one
        delay(50); // debounce
        }
        if (qty == set) {
        delay(0); // delay to clear ramp of counted pieces before stopping vibration.
        MotorOben.stop(  );
        }
        if (qty == set) {
        delay(100); // delay to clear ramp of counted pieces before stopping vibration.
        MotorUnten.doSteps( -500 );
        qty -= set; // reset counted part quantity
        lcd.setCursor(14, 1);
        lcd.print("   "); // write LCD qty zero
        if (qty < set) {
        delay(2000);
        MotorOben.setSpeed( 300 );
        MotorOben.rotate( 1 );
        state = 10;
     break;
     case 10:
        switchState = analogRead(signalPin);
        if (switchState > 600) { // if photointerrupt detects a part
        qty = qty + 1; // increment part count by one
        delay(50); // debounce
        }
        if (qty == set) {
        delay(0); // delay to clear ramp of counted pieces before stopping vibration.
        MotorOben.stop(  );
        }
        if (qty == set) {
        delay(100); // delay to clear ramp of counted pieces before stopping vibration.
        MotorUnten.doSteps( -500 );
        qty -= set; // reset counted part quantity
        lcd.setCursor(14, 1);
        lcd.print("   "); // write LCD qty zero
        if (qty < set) {
        delay(2000);
        MotorOben.setSpeed( 300 );
        MotorOben.rotate( 1 );
        state = 11;
     break;
     case 11:
        switchState = analogRead(signalPin);
        if (switchState > 600) { // if photointerrupt detects a part
        qty = qty + 1; // increment part count by one
        delay(50); // debounce
        }
        if (qty == set) {
        delay(0); // delay to clear ramp of counted pieces before stopping vibration.
        MotorOben.stop(  );
        }
        if (qty == set) {
        delay(100); // delay to clear ramp of counted pieces before stopping vibration.
        MotorUnten.doSteps( -500 );
        qty -= set; // reset counted part quantity
        lcd.setCursor(14, 1);
        lcd.print("   "); // write LCD qty zero
        if (qty < set) {
        delay(2000);
        MotorOben.setSpeed( 300 );
        MotorOben.rotate( 1 );
        state = 12;
     break;
     case 12:
        switchState = analogRead(signalPin);
        if (switchState > 600) { // if photointerrupt detects a part
        qty = qty + 1; // increment part count by one
        delay(50); // debounce
        }
        if (qty == set) {
        delay(0); // delay to clear ramp of counted pieces before stopping vibration.
        MotorOben.stop(  );
        }
        if (qty == set) {
        delay(100); // delay to clear ramp of counted pieces before stopping vibration.
        MotorUnten.doSteps( -500 );
        qty -= set; // reset counted part quantity
        lcd.setCursor(14, 1);
        lcd.print("   "); // write LCD qty zero
        break;
      }
    }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }
  }

Ne nicht die schliessenden Klammern am Ende.
Drück mal in der IDE STRG-T.
Dir fehlen alle Klammern im Code.

Code läuft ja, wenn ich automatisch formatieren, wird nur der Einzug verändert, Klammern bleiben gleich.