Probleme beim Rotation Count

Hallo Liebes Forum :slight_smile: Ich bin neu hier und hoffe Ihr könnt mir vielleicht einen Tipp geben, wie ich mein Arduino Projekt fertigstellen kann.

Hier ein paar kurze Infos zum Projekt:

Ich möchte einen automatischen Spulenwickler bauen. Ich benutze einen Arduino Uno und ein Motorshield mit 4 Anschlüsssen, um zwei Motoren zu steuern. Einmal einen 9v DC Motor, der über Anschluss M3 des Motor Shields angesteuert wird und dann noch einen 9v Steppemotor, der mit anschluss M1 und M2 des Motor Shields verbunden ist.

Dieser Steppermotor treibt eine kleine Traverse an. Im void setup home ich die Stepper-traverse mit Hilfe einer z-limit switch von meinem Ender 3. Nachdem die Traverse erfolgreich die home position erreicht hat, startet der DC-Motor und der Code geht in den void loop über.

Im void loop möchte ich zwei dinge machen: zum einen möchte ich die Traverse ausgehend vom Nullpunkt nach links und rechts bewegen. Zum anderen möchte ich mit Hilfe eines Reed Kontaktes die Umdrehungen des Motors zählen, sodass dc motor und stepper motor automatisch abgeschaltet werden, sobald eine bestimmte maximale Umdrehungszahl erreicht ist. Hier liegt mein Problem!

Ich möchte, dass mir der serielle monitor aller 3 millisekunden den wert des reed kontaktes ausgibt und gleichzeitig die traverse bewegt. Jedoch scheint dies nicht möglich zu sein. Entweder liest der serielle monitor den reed wert zwar korrekt, aber der code bleibt im ersten loop stecken.

Oder aber der stepper bewegt sich genau so wie gewollt, aber ich kriege nur einmal pro loop einen wert für den reed pin ausgegeben, was dazu führt, dass die umdrehungen nicht korrekt gezählt weren. Alles andere funktioniert bereits perfekt!

KANN MIR BITTE BITTE IRGENDJEMAND HELFEN???

Hier ist mein code:

#include <AccelStepper.h>
#include <AFMotor.h>

#define LIMIT_SWITCH_PIN 2
#define HOMING_SPEED -150    // Geschwindigkeit für die Rückwärtsbewegung beim Homing
#define STEPS_PER_MM 80 // 80 Schritte pro Millimeter

#define HOMING_DISTANCE_MM -20.0 // Distanz in mm, die sich die Traverse vom Limit Switch zurück bewegen soll
#define TRAVERSE_LOOP_DISTANCE_MM 10.0 // Traverse Loop Distanz in mm
#define DC_MOTOR_SPEED_PERCENT 100 // Geschwindigkeit des DC Motors in Prozent
#define TRAVERSE_SPEED_MM_PER_S 10 // Geschwindigkeit der Traverse in mm/s

AF_Stepper motor1(200, 1);
AF_Stepper motor2(200, 2);
AF_DCMotor motor(3); // Initialisiere das Motor Shield

const int reedPin = A0; // Definiere den Pin für den Reed-Kontakt
int rotationCount = 0; // Zähler für die Umdrehungen
const int targetRotationCount = 100; // Zielanzahl von Umdrehungen

int previousReedState = LOW; // Vorheriger Reed-Zustand

unsigned long previousTime = 0; // Vorherige Zeit für die Reed-Zustandsüberprüfung

void forwardstep1() {  
  motor1.onestep(FORWARD, INTERLEAVE);
}
void backwardstep1() {  
  motor1.onestep(BACKWARD, INTERLEAVE);
}
void forwardstep2() {  
  motor2.onestep(FORWARD, INTERLEAVE);
}
void backwardstep2() {  
  motor2.onestep(BACKWARD, INTERLEAVE);
}

AccelStepper stepper1(forwardstep1, backwardstep1);

void setup() {  
  pinMode(LIMIT_SWITCH_PIN, INPUT_PULLUP); // Konfiguriere den Limit-Switch als INPUT mit Pull-Up-Widerstand
  stepper1.setMaxSpeed(200.0);
  stepper1.setAcceleration(100.0);

  // Starte die Homing-Funktion
  while (digitalRead(LIMIT_SWITCH_PIN) != LOW) {
    stepper1.setSpeed(HOMING_SPEED);
    stepper1.runSpeed();
  }
  
  // Berechne die Anzahl der Schritte basierend auf der angegebenen Distanz
  float homing_steps = HOMING_DISTANCE_MM * STEPS_PER_MM;

  // Bewege die Traverse in die entgegengesetzte Richtung um die angegebene Distanz
  stepper1.setSpeed(HOMING_SPEED);
  stepper1.move(-homing_steps); // Negatives Vorzeichen für die entgegengesetzte Richtung
  while (stepper1.distanceToGo() != 0) {
    stepper1.run();
  }
  stepper1.setCurrentPosition(0);

  // Warte 5 Sekunden
  delay(5000);

  Serial.begin(9600);

  // Starte den Motor auf Stufe 200/255
  motor.setSpeed(map(DC_MOTOR_SPEED_PERCENT, 0, 100, 0, 255));
  motor.run(BACKWARD);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////

void loop() {
  unsigned long currentTime = millis(); // Aktuelle Zeit in Millisekunden
  // Setze Geschwindigkeit und Beschleunigung für die Bewegung
  stepper1.setMaxSpeed(TRAVERSE_SPEED_MM_PER_S * STEPS_PER_MM);
  stepper1.setAcceleration(100000.0);
  
  // Berechne die Anzahl der Schritte basierend auf der Traverse Loop Distance
  float traverse_loop_steps = TRAVERSE_LOOP_DISTANCE_MM * STEPS_PER_MM;
  
  // Bewegung vorwärts um die angegebene Distanz
  stepper1.moveTo(traverse_loop_steps); 
  stepper1.runToPosition();
  
  // Bewegung rückwärts um die gleiche Distanz zur Ausgangsposition (Punkt 0)
  stepper1.moveTo(0); 
  stepper1.runToPosition();

  // Überprüfe den Reed-Zustand alle 3 Millisekunden
  if (currentTime - previousTime >= 3) {
    previousTime = currentTime; // Aktualisiere die Zeit für die nächste Überprüfung

    // Lese den Zustand des Reed-Kontakts
    int reedState = digitalRead(reedPin);

    // Gib den Zustand des Reed-Kontakts im seriellen Monitor aus
    Serial.print("Reed-Zustand: ");
    Serial.println(reedState);

    // Überprüfe, ob der Reed-Zustand von 0 auf 1 gewechselt hat (steigende Flanke)
    if (reedState == HIGH && previousReedState == LOW) {
      rotationCount++; // Erhöhe den Zähler für die Umdrehungen
      Serial.print("Umdrehung ");
      Serial.println(rotationCount);
      
      // Überprüfe, ob die Zielanzahl an Umdrehungen erreicht wurde
      if (rotationCount >= targetRotationCount) {
        // Stoppe den DC-Motor
        motor.run(RELEASE);
        Serial.println("DC-Motor gestoppt");
        
        // Stoppe den Schrittmotor
        stepper1.stop();
        Serial.println("Schrittmotor gestoppt");
      }
    }
    // Speichere den aktuellen Reed-Zustand für den nächsten Durchlauf
    previousReedState = reedState;
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Das ist der erste
ganz große Fehler bei 3ms. Setze das mal auf 115200 hoch.

1 Like

alle 3 Millisekunden also 1000 / 3 = 333 mal pro Sekunde kannst du wirklich so schnell lesen?
Welche maximalen Drehzahlen treten da auf?

Wenn die Drehzahlen höher als ca. 30 Umdrehungen pro Minute sind dann sollte man das Zählen über einen Interrupt machen. Aaaber ein Reed-Kontakt wird ordentlich prellen. Das bedeutet pro Schaltvorgang nicht nur einen Impuls sonden 2 bis 10 Impulse.

Da ist ein Reedkontakt einfach schlecht geeignet.

Viel einfachere Lösung:
Welche Kräfte treten beim Spulen wickeln auf?
Wenn die Kräfte nicht so groß sind dann bietet sich an als Motor der das Spule drehen auch einen Schrittmotor zu verwenden.

Dann brauchst du überhaupt keinen Reed-Kontakt mehr

1 Like

okay, danke dir! ich nehme an das ist, um eine schnellere kommunikation zu ermöglichen? ich habe es ausprobiert, leider hat dies mein problem aber nicht gelöst

[quote="daniel-123456, post:4, topic:1227695, full:true"]
es muss diese so schnell abfragen, da sich der motor sehr schnell dreht. Jedesmal, wenn der Reed kontakt geschlossen ist, soll der monitor den wert 1 ausgeben (0 im offenen zustand) jedes mal wenn der reed pin wert sich von 0 auf 1 ändert, soll eine umdrehung gezählt werden.

Ich danke dir für den Tipp, ich denke aber, dass das eher schwierig wird, der dc motor dreht mit ca. 1300 rpm. Ich dachte eigentlich, dass sich die der reed status entprellen lässt, indem man nur eine umdrehung zählt, wenn der reed status von 0 auf 1 wechselt, sodass doppelzählungen vermieden werden. Ist meine Logik so richtig oder mache ich da einen fehler?

1300 rpm sind für einen Schrittmotor schon machbar. Bei höheren Drehzahlen nimmt das Drehmoment ab. Daher die Frage nach dem auftretenden Dremoment.

Spätestens wenn du einen Servomotor nimmst funktioniert das tadellos.
Ein Servomotor hat schon einen Encoder auf der Motorachse drauf.
Du gibst eine Zielposition vor und dann dreht sich der Servomotor bis zum erreichen der Zielposition

Das ist aufwendigere Technik deswegen kostet die auch mehr.
Also was für eine Größe so rein mechanisch hat der bisher verwendete DC-Motor?
Welche Spannung? welchen Strom?
Wie dick sind die Drähte die du da wickelst.
Ist das 2,5 mm² massives Kupfer oder sind das 0,X mm dünne Drähtchen?

das ist ein winziger 9v motor (24mm x 40mm so in der drehe) betreibe aktuell beide motoren über den arduino mit einem 7,5V 1A Netzteil. Die drähte sind ebenfalls sehr dünn, so um die 0,063mm^2

Dann dürfte so ein Servomotor ganz locker reichen

1 Like

Ich danke dir! mein komplettes projekt kostet keine hundert euro also werd ich erstmal weiter probieren, das problem so zu lösen. Aber gut zu wissen dass es diese option gibt als letzten ausweg ^^

Also wenn es extrem preiswert sein soll

optischer Encoder
https://www.reichelt.de/entwicklerboards-speed-sensor-lm393-debo-speed-sens-p226726.html

Die Impulse werden über eine interrupt service routine gezählt.
Bei magnetischen oder optischen Encodern gibt es keine Probleme mit prellen.

Ich verstehe immer noch nicht warum du auf dem Bildschirm 333 Ausgaben pro Sekunde durchsausen lässt. Da kannst du doch gar nicht mitlesen.

Und wenn es dir darum geht den Wechsel zwischen 0 und 1 anzeigen zu lassen
Das kann man viel eleganter programmieren das wirklich nur beim Wechsel eine Ausgabe erfolgt

      Serial.print("Umdrehung ");
      Serial.println(rotationCount);
// 1234567890123456
// Umdrehung 123456

16 Zeichen mal 10 bit = 160 bit
bei 9600 bits pro Sekunde dauert die Ausgabe
160 / 9600 = 16,7 Millisekunden

du möchtest aber alle 3 Millisekunden den encoder lesen
geht bei der niedrigen Baudrate einfach nicht

7 stellige Zahl ausgeben bei 115200 baud

70 / 115200 = 0,6 Millisekunden

1 Like

okay also vielleicht habe ich hier einen denkfehler. ich möchte die werte des seriellen monitors nicht selber lesen, ich möchte nur, dass der zustand des reed pins aller 3 millisekunden abgefragt wird, damit der arduino genau erkennt, wann der wert des reed kontaktes von 0 auf 1 wechselt. wenn das in irgendeinen form anders und einfacher geht, dann bin ich damit auch super zufrieden :smiley: mein problem ist halt, dass es im aktuellen code nur ein mal pro loop einen wert raus schmeißt und nur ab und zu mal zufällig registriert, dass der reed kontakt geschlossen wird.

also mein eigentliches problem ist, dass der reed zustand nicht wiederholt im selben loop ausgelesen wird. Ich würde gerne im selben loop einmal die traverse ein stück nach rechts bewegen und dann zurück, und zeitgleich parallel aller 3 millisekunden den reed schalter zustand lesen, um die udrehungen zu zählen. das beides scheint aber unvereinbar zu sein

was meinst du mit "loop" ??
mach erst mal das mit deinem Code im ersten Posting

Und dann markiere das im code was du mit "loop" meinst

1 Like

danke für den tipp! Habe das jetzt gemacht und den void loop optisch vom rest getrennt

supi gemacht mit der Code-Section
Dein Reed-Kontakt prellt. Englisch bouncing
Auf dem Oscilloscop sieht das so aus:

Wie willst du da alle 3 Millisekunden sicher erfassen ob ein neuer Impuls da ist?

1 Like

Hier in Zeitlupe

1 Like

okay, jetzt verstehe ich das problem, danke dir. Also habe ich noch ein zusätzliche problem zu meinem eigentlichen problem -.-

Doch es gibt ganz verschiedene. Man kann das auch in hardware machen.
oder in Software bei 1300 rpm sind das
1300 / 60 = 21.7 Impulse pro Sekunde

1 / 21.7 = 0.046 Sekunden = 46 Millisekunden der nächste Impuls
also könnte man es mit 20 Millisekunden debounce-Zeit probieren ob das ausreicht

Man könnte das mit einer Interruptroutine probieren
Der interrupt wird durch die steigende Flanke ausgelöst
in der interrupt-routine wird geprüft ob es schon eine steigende Flanke gab
wenn nein

  • Merker "erste steigende Flanke" setzen
  • den aktuellen Wert von millis() in einer Variable speichern
  • Zähler um eins erhöhen

wenn der Reedkontakt jetzt prellt löst er den nächsten Interrupt aus aber es wird ja sofort geprüft ob der Merker "erste steigende Flanke" schon gesetzt wurde.
wenn ja prüfe im Hauptprogramm ob schon 20 Millisekunden vergangen sind.
wenn weniger als 20 millisekunden vergangen sind mache einfach nichts
wen 20 Millisekunden vergangen sind setze den Merker zurück
weil gemäß der Theorie der Reed-Kontakt nach 20 Millisekunden aufgehört hat zu prellen

Wenn nach dieser Zeit eine steigende Flanke auftritt dann ist es ein neuer Impuls.

Das steht und fällt mit der Zeit wie lange der Reedkontakt prellt.

Deshalb empfehle ich den Umstieg auf einen optischen oder magnetischen Sensor
die prellen nicht.

1 Like