Erkennung von Abstand zwischen zwei bewegten Teilen mittels IR-Sensor

Du hast das jetzt von 437µs nicht auf 50ms sondern auf 7µs gezogen. :frowning_face:

Änder die Zeilen:

      delayMicroseconds(471);

in

delay(50);    

9600 baud: heute üblich sind 115200 baud.

Wenn du das umstellst dann muss es auch unten rechts im seriellen Monitor auch auf 115200 umgestellt werden
vgs

Am kurzen Step-impuls liegt es nicht
Laut Datenblatt des A4988 ist der chip echt flink mimium 1 µs

Auf was hast du denn die Strombegrenzung eingestellt?

Wie sieht die Motorbewegung aus wenn du den "Dreh nur den Motor"-Sketch aufspielst?
Gibt es eine Masseverbindung zwischen Arduino-GND und A4988 GND?
delay(50) geht dann doch auf die Drehzahl
bei delayMicroSeconds (7) oder auch 471 120 Hz
Bei delay(50) 10 Hz Schrittfrequenz

setze in der function motor() mal die delayMicroseconds() auf 1000
Das ergbit dann eine Schrittfrequenz von ca 500 Hz. Das müsste der Schrittmotor gut können

void motor(){
  if (antrieb == true) {
    digitalWrite(dirPin, LOW);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(1000);
    //delay(50);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(1000);
    //delay(50);
    
    //Serial.println("Laeuft");
  }
  else {
    //digitalWrite(stepPin, LOW);
  }
}

vgs

vgs

Da streiten sich die Geister...
Du verlierst eher einige Ausgaben, weil bei 9600 ist der Puffer schnell mal voll....

Ich mach gerne sowas wie das folgende.
Ersetze ab loop() alles :slight_smile:

void loop()
{
  if (digitalRead(sensorPin) == LOW)         // Sensor detektiert etwas
  {
    isDetect = true;                         // Merken
  }
  if (millis() - detectTime <= mindestZeit)  // letzte detektZeit ist zu kurz? ...
  {
    if (isDetect == true)                    // ... und was detectiert?
      antrieb = false;                       // Antrieb aus
  }
  else                                       // letztes detekt ist lange her
  {
    antrieb = true;                          // Antrieb ein
    if (digitalRead(sensorPin) == HIGH)      // Wenn nichts mehr vor dem Sensor steht
    {
      if (isDetect == true)                  // Merker ist gesetzt? ...
      {
        detectTime = millis();               // ... dann Zeit merken
        isDetect = false;                    // Merker immer löschen
      }
    }
  }
  motor();
  serMon();
}
//
void motor()
{
  if (antrieb == true)
  {
    digitalWrite(dirPin, LOW);
    digitalWrite(stepPin, HIGH);
    delay(15);
    digitalWrite(stepPin, LOW);
   delay(13);
    //Serial.println("Laeuft");
  }
  else
  {
    digitalWrite(stepPin, LOW);
  }
}

void serMon()
{
  static bool oldAntrieb = false;
  static bool oldDetect = false;
  if (antrieb != oldAntrieb)
  {
    Serial.println(F("Zustand Antrieb: "));
    if (antrieb == true)
      Serial.println("ein");
    else
      Serial.println("aus");
    oldAntrieb = antrieb;
  }
  if (isDetect != oldDetect)
  {
    Serial.println(F("Zustand Sensor: "));
    if (isDetect == false)
      Serial.println(F(" da steht was vor"));
    else
      Serial.println(F("ist frei"));
    oldDetect = isDetect;
  }
}

Wenn Du die Ausgbaben nicht mehr brauchst, im loop) einfach serMon() auskommentieren :slight_smile:

Ihr seid echt super nett!
Danke für die schnellen Antworten!

Danke, das habe ich geändert.

Die Spannung an der Strombegrenzung liegt bei 0,7V.
Der Motor läuft flüssig und vibrationsfrei.
Ja, die Massenverbindung entsteht über das CNC V3 Shield.

Vielen Dank, die serielle Ausgabe ist ganz schick!
Nur mein Hauptproblem mit dem Motor besteht leider weiterhin.

... ich stehe völlig auf dem Schlauch wie die Fehlersuche vorangetrieben werden kann.

Dann versuch ich das mal von Grund auf:
Ersetze loop().

void loop()
{
  if (millis() - detectTime > 3000)
  {
    antrieb = !antrieb;
    detectTime = millis();
  }
  motor();
  serMon();
}

Das Ding macht 3 Sekunden Antrieb und 3 Sekunden keinen Antrieb.
Jetzt kannst Du in motor() mit der Zeit spielen.
Wenn das geht, gehts weiter.

Und in serMon() mach mal aus:

    if (isDetect == false)

neu:

    if (isDetect == true)
void motor(){
  if (antrieb == true) {
    digitalWrite(dirPin, LOW);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(1000);
    //delay(50);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(1000);
    //delay(50);
    
    //Serial.println("Laeuft");
  }
  else {
    //digitalWrite(stepPin, LOW);
  }
}

Das ergibt eine Schrittfrequenz von ca 500 Hz
Das sollte der Schritt-Motor gut hinbekommen

Edit:

beschreibe mal möglichst präzise wie der Motor "unrund" läuft.
ungefähre Drehzahl?
Am besten wäre natürlich ein kurzes Video auf Youtube
Welchem Strom entspricht 0,7V auf dem A4988?

EDIT 2:

noch eine Möglichkeit wäre ein halb kaputter A4988.
Wenn man die Leitungen des Schrittmotors während die Versorgungsspannung des Schrittmotors eingeschaltet ist anklemmt oder abklemmt dann gibt das wegen der Induktivität der Motorspulen Spannungsspitzen die den Schrittmotortreiber beschädigen können. Das Phänomen hatte ich mit DRV8825-Treibern auch schon einmal.

Wenn ein neuer Schrittmotortreiber notwendig wird
Die TMC2209 lassen den Schrittmotor sehr leise laufen

oder eben DRV8825

Vielen Dank, dass Ihr mit mir am Ball bleibt

gesagt -> getan -> leider gleiches Ergebnis mit viel Vibration

Bei dem CNC Shield waren vier Treiber dabei und bisher hatte ich nur einen verbaut.
Diesen habe ich nun mal getauscht, aber leider noch immer das gleiche Ergebnis.

Ich habe die Spannung an dem Poti (die Schraube) und der Masse gemessen.
(so habe ich die Anleitung dafür im Netz gefunden, welchen Strom das nun wirklich entspricht bin ich mir unsicher, häufig habe ich gelesen, dass diese Spannung *2 den Strom entspricht, aber ich habe keine ordentliche Quelle dafür)

Auch hier:
gesagt -> getan (deswegen dauerte es, weil ich bisher noch kein Video geschnitten habe und mir dafür ein Programm besorgen musste.

Leider ist die Qualität dadurch runtergerechnet worden.
aber der Code, bei dem es Ruckelt, ist der von XY (nochmals vielen Dank, denn er macht was er soll, nur leider der Motor nicht.)

vielen vielen Dank an Euch!

Also ich würde sagen das liegt schlicht und ergreifend an der Schrittausgabefrequenz von schlappen 35 Hz die bei dieser Code-Variante entsteht:

// Stepper Motor X

const byte stepPin = 2;          //X.STEP
const byte dirPin = 5;           // X.DIR
const byte sensorPin = 9;
const uint32_t mindestZeit = 2000;
uint32_t detectTime;
bool antrieb;
bool isDetect = false;

void setup() {
  Serial.begin(115200);
  pinMode(stepPin, OUTPUT);   // Step Signal fuer Geschw.
  pinMode(dirPin, OUTPUT);    //Dir -> direction
  pinMode(sensorPin, INPUT);        //Sensor eingang
  antrieb = true;
}

void loop()
{
  if (digitalRead(sensorPin) == LOW)         // Sensor detektiert etwas
  {
    isDetect = true;                         // Merken
  }
  if (millis() - detectTime <= mindestZeit)  // letzte detektZeit ist zu kurz? ...
  {
    if (isDetect == true)                    // ... und was detectiert?
      antrieb = false;                       // Antrieb aus
  }
  else                                       // letztes detekt ist lange her
  {
    antrieb = true;                          // Antrieb ein
    if (digitalRead(sensorPin) == HIGH)      // Wenn nichts mehr vor dem Sensor steht
    {
      if (isDetect == true)                  // Merker ist gesetzt? ...
      {
        detectTime = millis();               // ... dann Zeit merken
        isDetect = false;                    // Merker immer löschen
      }
    }
  }
  motor();
  serMon();
}
//
void motor()
{
  if (antrieb == true)
  {
    digitalWrite(dirPin, LOW);
    digitalWrite(stepPin, HIGH);
    delay(15);
    digitalWrite(stepPin, LOW);
    delay(13);
    //Serial.println("Laeuft");
  }
  else
  {
    digitalWrite(stepPin, LOW);
  }
}

void serMon()
{
  static bool oldAntrieb = false;
  static bool oldDetect = false;
  if (antrieb != oldAntrieb)
  {
    Serial.println(F("Zustand Antrieb: "));
    if (antrieb == true)
      Serial.println("ein");
    else
      Serial.println("aus");
    oldAntrieb = antrieb;
  }
  if (isDetect != oldDetect)
  {
    Serial.println(F("Zustand Sensor: "));
    if (isDetect == false)
      Serial.println(F(" da steht was vor"));
    else
      Serial.println(F("ist frei"));
    oldDetect = isDetect;
  }
}

Ändere mal die delays auf delay(1);

// Stepper Motor X

const byte stepPin = 2;          //X.STEP
const byte dirPin = 5;           // X.DIR
const byte sensorPin = 9;
const uint32_t mindestZeit = 2000;
uint32_t detectTime;
bool antrieb;
bool isDetect = false;

void setup() {
  Serial.begin(115200);
  pinMode(stepPin, OUTPUT);   // Step Signal fuer Geschw.
  pinMode(dirPin, OUTPUT);    //Dir -> direction
  pinMode(sensorPin, INPUT);        //Sensor eingang
  antrieb = true;
}

void loop()
{
  if (digitalRead(sensorPin) == LOW)         // Sensor detektiert etwas
  {
    isDetect = true;                         // Merken
  }
  if (millis() - detectTime <= mindestZeit)  // letzte detektZeit ist zu kurz? ...
  {
    if (isDetect == true)                    // ... und was detectiert?
      antrieb = false;                       // Antrieb aus
  }
  else                                       // letztes detekt ist lange her
  {
    antrieb = true;                          // Antrieb ein
    if (digitalRead(sensorPin) == HIGH)      // Wenn nichts mehr vor dem Sensor steht
    {
      if (isDetect == true)                  // Merker ist gesetzt? ...
      {
        detectTime = millis();               // ... dann Zeit merken
        isDetect = false;                    // Merker immer löschen
      }
    }
  }
  motor();
  serMon();
}
//
void motor()
{
  if (antrieb == true)
  {
    digitalWrite(dirPin, LOW);
    digitalWrite(stepPin, HIGH);
    delay(1);
    digitalWrite(stepPin, LOW);
    delay(1);
    //Serial.println("Laeuft");
  }
  else
  {
    digitalWrite(stepPin, LOW);
  }
}

void serMon()
{
  static bool oldAntrieb = false;
  static bool oldDetect = false;
  if (antrieb != oldAntrieb)
  {
    Serial.println(F("Zustand Antrieb: "));
    if (antrieb == true)
      Serial.println("ein");
    else
      Serial.println("aus");
    oldAntrieb = antrieb;
  }
  if (isDetect != oldDetect)
  {
    Serial.println(F("Zustand Sensor: "));
    if (isDetect == false)
      Serial.println(F(" da steht was vor"));
    else
      Serial.println(F("ist frei"));
    oldDetect = isDetect;
  }
}

EDIT:
Ich habe mir jetzt die Step-Pulse-Erzeugung mit dem Oszilloskop angeschaut.
Arduino-Uno-Clon von Keystudio.

Mit dem Anfangscode schwankt der Anstieg des Steppulses um ca 0,5 µsec.
Mit der letzten Programmversion schwappt der Anstieg ca 8 µsec hin und her.
Das sind 0,8% Abweichung. Daran kann es meinem Gefühl nach nicht liegen.
Aber ich habe dazu nie recherchiert.
Ich empfehle auf die MobaTools für die Schrittmotoransteuerung umzusteigen.
Die MobaTools erzeugen die Step-impulse per Hardwaretimer das läuft sehr stabil.
Wenn das eine Randbedingung ist die Schritterzeugung "zu Fuß" zu programmieren
dann kann man sich das per Timerinterrupt auch selber basteln.

vgs

Solltest Du Spaß daran finden, meine Frau schneidet Urlaubsvideos mit Magix Video deLuxe, kombiniert Fotos mit Videos. Erst die Fotos mit einem Assistenten automatisch zu einer Fotoshow formatieren, dann die Videos, Text und zum Schluß Musik ergänzen. Ist nicht in fünf Minuten erledigt, aber "habt Ihr Lust auf dreißig Minuten Urlaubsvideo" wird von unseren Freunden gerne mit "Ja" beantwortet und stimmt auf eine fröhliche Feier ein. Das Programm kommt aus Berlin mit deutscher Qualität und ist in einer älteren Version auch bezahlbar.

Den von Dir verwendeten PowerDirector fand ich vor Jahren, als ich Videoschnittprogramme für uns getestet habe, nicht so prickelnd, kann sich aber geändert haben. Laß Dich also ggf. nicht abschrecken.

Ich beziehe mich auf das zweite Programm in #30.

Ersetze delay(15); durch delayMicroseconds(471); und es schnurrt!

Getestet mit DRV8825, einem anderen Motor und einem UNO.


Jetzt mal mit MobaTools, wobei ich die Programmstruktur bewußt beibehalten habe:

#include <MobaTools.h>
MoToStepper Step(200, STEPDIR);          // Schritte pro Umdrehung

const byte stepPin = 2;          // X.STEP
const byte dirPin = 5;           // X.DIR
const byte sensorPin = 9;
const uint32_t mindestZeit = 2000;
uint32_t detectTime;
bool antrieb;
bool isDetect = false;

void setup() {
  Step.attach( stepPin, dirPin );         // stepPin, dirPin
  Step.setSpeed( 3000 );                  // = 300 U/Min
  Step.setRampLen( 50 );                  // Beschleunigung
  Step.setZero();                         // Referenzpunkt setzen
  Serial.begin(115200);
  pinMode(sensorPin, INPUT_PULLUP);       //Sensor eingang
  antrieb = true;
}

void loop()
{
  if (digitalRead(sensorPin) == LOW)         // Sensor detektiert etwas
  {
    isDetect = true;                         // Merken
  }
  if (millis() - detectTime <= mindestZeit)  // letzte detektZeit ist zu kurz? ...
  {
    if (isDetect == true)                    // ... und was detectiert?
      antrieb = false;                       // Antrieb aus
  }
  else                                       // letztes detekt ist lange her
  {
    antrieb = true;                          // Antrieb ein
    if (digitalRead(sensorPin) == HIGH)      // Wenn nichts mehr vor dem Sensor steht
    {
      if (isDetect == true)                  // Merker ist gesetzt? ...
      {
        detectTime = millis();               // ... dann Zeit merken
        isDetect = false;                    // Merker immer löschen
      }
    }
  }
  motor();
  serMon();
}
//
void motor()
{
  if (antrieb == true)
  {
    Step.rotate( 1 );                        // Richtung ist immer vorwärts
  }
  else
  {
    Step.rotate( 0 );                        // Anhalten mit Rampe
    Step.setZero();                          // Referenzpunkt setzen, wohl nicht benötigt, aber der Positionszähler läuft dann nicht über
  }
}

void serMon()
{
  static bool oldAntrieb = false;
  static bool oldDetect = false;
  if (antrieb != oldAntrieb)
  {
    Serial.println(F("Zustand Antrieb: "));
    if (antrieb == true)
      Serial.println("ein");
    else
      Serial.println("aus");
    oldAntrieb = antrieb;
  }
  if (isDetect != oldDetect)
  {
    Serial.println(F("Zustand Sensor: "));
    if (isDetect == false)
      Serial.println(F(" da steht was vor"));
    else
      Serial.println(F("ist frei"));
    oldDetect = isDetect;
  }
}

Die Geschwindigkeit ist geschätzt.

Nee, das glaube ich nicht. Die Pause ist immer 2 Sekunden lang, unabhängig vom vorherigen Laufweg.

Hallo

und mal wieder ein großes Dankeschön für Euer Feedback.

und

Das stimmt.
Der Motor läuft wieder rund.

Allerdings stimmt auch der kleine Hinweis von @agmue :

Der Motor stoppt bei Änderungen für zwei Sekunden.
und das leider bei beiden Codes bei dem von XY und vom Stefan.

Habt ihr die Muse mir erneut zu Helfen bitte ? :slight_smile:

Ja, das ist bestimmt auch sehr Spaßig, aber bevor ich dieses Projekt starte, sollte ich das Andere erstmal fertigstellen :sweat_smile:

Da musst du am besten den Code posten. Dafür sind ja die Code-Sections extra gemacht.
Geringer Bildschirmplatzverbrauch bei voller Information.

Ich behaupte, dass die Programmskizze die ich ganz am Anfang gepostet habe
nicht grundsätzlich 2 Sekunden wartet sondern nur die Zeit die bis 2 Sekunden fehlt. Zahlenbeispiel:
Zeit 0:03,4 Teil 1 ist zu Ende (Zeitstempel 3400 Millisekunden speichern )
Zeit 0:05,1 Teil 2 wird detektiert (Zeitunterschied 5100 - 3400 = 1700 Millisekunden
Zeit 0:05,4 Teil 2 wird weitertransportiert (Zeitunterschied 2000 Millisekunden) (Zeit in der der Motor steht 2000 - 1700 = 300 Millisekunden.

Es ist beim Programmieren eben nicht damit getan ein funktionierendes Programm auf die schnelle ein bisschen durchzulesen und zu denken "ja verstehe ich" sondern man muss sich schon intensiv damit auseinandersetzen oder sehr gründlich testen.
Wenn es um Zeiten geht geht das Testen durch zusätzliche Variablen in denen man den jeweils aktuellen Wert von millis() speichert und dann die Differenz bildet.

Beispiel:
motorAus = millis();
motor-stop
sonstiger
code ....
motor-EIN
motorEin = millis();

Serial.print("Zeit mit Motoraus=");
Serial.print(motorEin - motorAus);
Serial.println(" Millisekunden");

Edit: Wenn man im seriellen Monitor die Chekcbo "Zeitstempel" aktivieren aktiviert dann bekommt man da auch Zeitstemper mit denen sich dann Zeiten analysieren lassen.
vgs

Nein für drei. :wink: Hab ich geschrieben.

Und das mit dem Spielen der Zeiten war ernst gemeint :wink:
Ok.
Wir haben also einen Motor der dreht.
Ich hab jetzt den Code aus 20 mit dem loop() aus #24 gepaart.
Ein Umlauf im loop() - braucht 12µs Jedenfalls bei mir. Ohne Seriellen Ausgaben.

Schmeiss mal alle Seriellen Ausgaben raus.

Also im loop()
// serMon()
und in Motor()
// Serial.println("Laeuft");

Ich hab mal den Code komplettiert und kommentiert.
Neu sind ein paar Variablen und Code in Zeile 26, 48-50, sowie 53 - 64
Ausgabe auf dem SerMOn - Erste Spalte 16 bzw. 20 zweite Spalte rund 970. Das sind die Zeiten in µs für einen Umlauf.

|15:04:58.927 -> 16|964|
|15:04:58.927 -> 16|968|
|15:04:58.927 -> 20|972|
|15:04:58.927 -> 20|972|
|15:04:58.927 -> 16|968|
|15:04:58.927 -> 16|972|
|15:04:58.927 -> 20|972|

Die erste Zeit ist vor dem Motor, die zweite Zeit nach dem Motor, von der die Zeit für den Motor abgezogen - ist da kein grosser Unterschied zur ersten Zeit.
Wie sieht es bei Dir aus?

// Stepper Motor X

const byte stepPin = 2;          //X.STEP
const byte dirPin = 5;           // X.DIR
const byte sensorPin = 9;
const uint32_t mindestZeit = 2000;
uint32_t detectTime;
bool antrieb;
bool isDetect = false;

const uint16_t anzahlZeiten = 200;   //
uint32_t zeiten[anzahlZeiten] = {0}; // berechnete Laufzeit aufnehmen
uint16_t laufendeZeit;

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  pinMode(stepPin, OUTPUT);   // Step Signal fuer Geschw.
  pinMode(dirPin, OUTPUT);    //Dir -> direction
  pinMode(sensorPin, INPUT);        //Sensor eingang
  antrieb = true;
}
void loop()
{
  uint32_t myMicros = micros();    // Startzeit merken
  if (digitalRead(sensorPin) == LOW)         // Sensor detektiert etwas
  {
    isDetect = true;                         // Merken
  }
  if (millis() - detectTime <= mindestZeit)  // letzte detektZeit ist zu kurz? ...
  {
    if (isDetect == true)                    // ... und was detectiert?
      antrieb = false;                       // Antrieb aus
  }
  else                                       // letztes detekt ist lange her
  {
    antrieb = true;                          // Antrieb ein
    if (digitalRead(sensorPin) == HIGH)      // Wenn nichts mehr vor dem Sensor steht
    {
      if (isDetect == true)                  // Merker ist gesetzt? ...
      {
        detectTime = millis();               // ... dann Zeit merken
        isDetect = false;                    // Merker immer löschen
      }
    }
  }
  // Ab hier Berechnung....
  zeiten[laufendeZeit] = micros() - myMicros; // Von loop() Anfang bis hier
  laufendeZeit++;                             // Nächste Position bestimmen
  motor();
  //serMon();
  zeiten[laufendeZeit] = micros() - myMicros; // Von loop() Anfang nach Motor und SerMon
  laufendeZeit++;                             // nächste Position bestimmen
  if (laufendeZeit >= anzahlZeiten)           // Array ist voll?
  {
    for (uint16_t u = 0; u < anzahlZeiten; u += 2)
    {
      Serial.print(zeiten[u]);                // Erste Zeit
      Serial.print('\t');
      Serial.println(zeiten[u + 1]);          // zweite Zeit
    }
    laufendeZeit = 0;                         // Array von vorn befüllen
  }
}
//

void motor()
{
  if (antrieb == true)
  {
    digitalWrite(dirPin, LOW);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(471);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(471);
    //Serial.println("Laeuft");von 48 bis 64
  }
  else
  {
    digitalWrite(stepPin, LOW);
  }
}
void serMon()
{
  static bool oldAntrieb = false;
  static bool oldDetect = false;
  if (antrieb != oldAntrieb)
  {
    Serial.println(F("Zustand Antrieb: "));
    if (antrieb == true)
      Serial.println("ein");
    else
      Serial.println("aus");
    oldAntrieb = antrieb;
  }
  if (isDetect != oldDetect)
  {
    Serial.println(F("Zustand Sensor: "));
    if (isDetect == false)
      Serial.println(F(" da steht was vor"));
    else
      Serial.println(F("ist frei"));
    oldDetect = isDetect;
  }
}

@StefanL38: Jetzt bin ich wieder in der schon an anderer Stelle beschriebenen Zwickmühle, denn ich habe zur Ordnung meiner Gedanken ein Programm geschrieben, um mich in die Problematik einzudenken. Andere würden Grafiken malen oder Ablaufdiagramme schreiben.

Soll ich dieses Programm geheim halten?

Meine Entscheidung, ich zeige das Programm und überlasse es dem TO, etwas davon zu nehmen oder auch nicht.

Als Fan der MobaTools nutze ich diese und eine Schrittkette (= finite state machine; = endlicher Automat) mit switch/case realisiert. Da kann ich einfacher denken :roll_eyes:

Getestet mit UNO, DRV8825 und einem Schrittmotor:

//#define DEBUGGING                     // Einkommentieren für die Serielle Ausgabe
#ifdef DEBUGGING
#define DEBUG_B(...) Serial.begin(__VA_ARGS__)
#define DEBUG_P(...) Serial.print(__VA_ARGS__)
#define DEBUG_L(...) Serial.println(__VA_ARGS__)
#else
#define DEBUG_B(...)
#define DEBUG_P(...)
#define DEBUG_L(...)
#endif

#include <MobaTools.h>
MoToStepper Step(200, STEPDIR);          // Schritte pro Umdrehung

const byte stepPin = 2;          // X.STEP
const byte dirPin = 5;           // X.DIR
const byte sensorPin = 9;
const uint32_t mindestZeit = 2000;
uint32_t detectTime;
uint32_t jetzt;

void setup() {
  DEBUG_B(115200);
  DEBUG_L(F("Start ..."));
  pinMode(sensorPin, INPUT_PULLUP);       //Sensor eingang
  Step.attach( stepPin, dirPin );         // stepPin, dirPin
  Step.setSpeed( 3000 );                  // = 300 U/Min
  Step.setRampLen( 50 );                  // Beschleunigung
  Step.setZero();                         // Referenzpunkt setzen
  Step.rotate( 1 );                       // Richtung ist immer vorwärts
}

void loop()
{
  jetzt = millis();
  static byte schritt = 0;
  switch ( schritt )
  {
    case 0:
      if (digitalRead(sensorPin) == LOW)         // Sensor detektiert etwas
      {
        serMon( schritt, "Zeit gestartet" );
        detectTime = jetzt;
        schritt++;
      }
      break;
    case 1:
      if (digitalRead(sensorPin) == HIGH)         // Sensor detektiert etwas
      {
        serMon( schritt, "Teil Ende erkannt" );
        schritt++;
      }
      break;
    case 2:
      if (digitalRead(sensorPin) == LOW)         // Sensor detektiert etwas
      {
        serMon( schritt, "Teil Ende erkannt, Zeitdiff: \t", jetzt - detectTime );
        if (jetzt - detectTime >= mindestZeit)  // letzte detektZeit ist zu kurz? ...
        {
          serMon( schritt, "Zeit überschritten, Motor dreht weiter" );
          Step.rotate( 1 );                        // Richtung ist immer vorwärts
          detectTime = jetzt;
          schritt = 1;
        } else {
          serMon( schritt, "Zeit unterschritten, Motor Halt" );
          Step.rotate( 0 );                        // Anhalten mit Rampe
          Step.setZero();                          // Referenzpunkt setzen, wohl nicht benötigt, aber der Positionszähler läuft dann nicht über
          schritt++;
        }
      }
      break;
    case 3:
      if (jetzt - detectTime >= mindestZeit)  // letzte detektZeit ist zu kurz? ...
      {
        serMon( schritt, "Zeit erreicht, Motor Start" );
        Step.rotate( 1 );                        // Richtung ist immer vorwärts
        detectTime = jetzt;
        schritt = 1;
      }
      break;
    default:
      schritt = 0;
  }
}

void serMon(byte s, const char * text)
{
  serMon( s, text, 0 );
}

void serMon(byte s, const char * text, const uint32_t diff)
{
  DEBUG_P(jetzt);
  DEBUG_P(F("\tSchritt: "));
  DEBUG_P(s);
  DEBUG_P('\t');
  DEBUG_P(text);
  if (diff)
  {
    DEBUG_P('\t');
    DEBUG_P(diff);
  }
  DEBUG_L();
}

Bitte ausprobieren, fragen oder verwerfen.

Bei den MobaTools gibt es auch Zeitgeber, die ich wegen der Vergleiichbarkeit nicht genutzt habe.

"Hier stehe ich, ich kann nicht anders." Luthers berühmte Worte, die er wohl nie gesagt hat.

Hallo,

entschuldigt, dass ich mich erst jetzt wieder melde.
Ich wollte das System richtig testen, bevor ich wieder behaupte, dass die Codes nicht funktionieren.

Dabei habe ich nun einen groben Fehler entdeckt:
Ich habe das Program von Null neu aufgebauen wollen um zu schauen wo es hängt.
Dabei ist rausgekommen, dass sobald delay im "IF etwas detektieren" aufkommt, der Motor nicht mehr will. So habe ich den Code komplett gekürzt auf :

// Stepper Motor X

const byte stepPin = 2;          //X.STEP
const byte dirPin = 5;           // X.DIR
const byte sensorPin = 9;
const uint32_t mindestZeit = 2000;
uint32_t detectTime;
bool antrieb;
bool isDetect = false;

const uint16_t anzahlZeiten = 200;   //
uint32_t zeiten[anzahlZeiten] = {0}; // berechnete Laufzeit aufnehmen
uint16_t laufendeZeit;

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  pinMode(stepPin, OUTPUT);   // Step Signal fuer Geschw.
  pinMode(dirPin, OUTPUT);    //Dir -> direction
  pinMode(sensorPin, INPUT);        //Sensor eingang
  antrieb = true;
}

void loop() {

  detect = digitalRead(sen);
  if (detect == 1)
  {
    Serial.println("         an");
     
  }
  else if (detect == 0);
  {
    Serial.println("aus");
   
  }
};

Dabei kommt heraus, dass der Sensor (KY-032) osziliert (habe drei bestellt und bei allen ist es leider so).
16:06:21.230 -> aus
16:06:21.230 -> an
16:06:21.230 -> aus
16:06:21.230 -> an
16:06:21.230 -> aus

Also liegt das Problem nun an der Einstellung der Sensoren und nicht mehr nur am Code.
:frowning:

Ich habe mir bei AZ-delivery das Datenblatt vom AZ-delivery-KY-23 angeschaut.
Durch die Fettschrift will ich zum Ausdruck bringen, wenn du den Sensor woanders gekauft hast könnte die Funktion abweichend sein. Ich halte es für sehr wahrscheinlich dass auch andere KY-23-Sensoren genau gleich arbeiten aber ich weiß es nicht.

In dem Datenblatt steht:
IR-Sende-Diode soll mit 38 kHz Pulse senden damit der Empfänger der auf 38 kHz getrimmt ist ein Signal empfängt. Die beiden Potis stellen Leuchtstärke und Frequenz ein.
Wenn die Frequenz nicht genau 38 kHz ist führt das möglicherweise zum oszillieren.

Am besten einstellen ließe sich das mit einem Oszilloskop.
Nächste Möglichkeit ein Digitalmultimeter mit Frequenzmessung.
Wenn du noch kein Digital Multimeter hast würde ich dir dieses empfehlen.
Saugutes Preisleistungsverhaltnis und vielfältige Messmöglichkeiten
neben den Standardsachen Strom Spannung Widerstand
20A Messbereich
Temperatur (mit mitgeliefertem Sensor)
Kapazität von Kondensatoren
%Duty-cycle
Frequenz bis 10 MHz
Bluetooth und Android App für Messwertanzeige und Datalooging

schlappe 30 Euro

vgs

Im Datenblatt zum IR-Empfänger steht


Das hört sich so an als ob ein dauerhaftes 38 kHz-Signal ohne jede Unterbrechung
mag der Empfänger nicht.
AZ-Delivery schreibt in der seiner Anleitung Enable-Pin kann dauerhaft eingeschaltet sein.
Da habe ich so meine Zweifel wenn ich das lese.
(AZ-delivery hat auch in der DRV8825-Anleitung ein um 180 Grad gedrehtes PINOUT abgebildet. Das führt garantiert zum Sofortausfall des DRV8825-Treibers)

In deinem Video hast du den IR-Sensor nur mit 3 Leitungen angeschlossen. Ich nehme an Plus
Minus
Ausgang
aber kein enable.

Das könnte man mal mit einem Testcode der ca 20 Impulse erzeugt dann Pause macht
20 Pulse erzeugt - Pause machen usw.
testen.

Das könnte man am einfachsten durch ein PWM-Signal mit 50% erreichen

1/38000 = 0,000026315 Sekunden * 20 = 526,1 µs
Also 526 µS lang enable-ein / 526 µS enable-aus heißt zwanzig Pulse senden / zwanzig Puls-längen Pause.

Damit müsste der IR-Empfänger dann zufrieden sein. Man hätte aber das Problem dass der Ausgang dann auch die ganze Zeit hin/und herschaltet.
Deshalb wäre ein Aufruf
enable ein für 20 Impulse
dann enable aus für 20 "Impulse"
Nochmal enable ein 20 pulse
dann prüfen ob Ausgang geschaltet hat eine sichere Methode.
Das dauert dann 1/38000 * 60 = 1,58 Millisekunden. Schritte per MobaTools ausgeben lassen und Sensorabfrage in loop

vgs

Da gibt es auch ein kleines Programm, wie man den Sensor per EN anspricht und auswertet.

EN-Jumper Abziehen nicht vergessen.

Hallo und guten Abend :slight_smile:

Der Sensor ist von AZ, also sollte das genau passen.

Leider habe ich kein Oszilloskop da und mein aktuelles Multimeter hat keine Frequenzmessung.

Du hast richtig angenommen.
Ich hatte im Netz ebenfalls gelesen, dass der Jumper nicht für die Dauernutzung ist, aber da auf der Händlerseite etwas anderes steht, dachte ich, dass ich diesem vertrauen könnte und habe nur 3Kabel verwendet.

Das Programm habe ich mir abgeschrieben und plötzlich, erkennt der Sensor was er erkennen soll.

Also habe ich das mini Programm in das von @agmue eingebunden, nun läuft der Motor und stoppt auch,
aber leider wieder nicht mit dem Abstand sondern, bei Erkennung vom Sensor.

//#define DEBUGGING                     // Einkommentieren für die Serielle Ausgabe
#ifdef DEBUGGING
#define DEBUG_B(...) Serial.begin(__VA_ARGS__)
#define DEBUG_P(...) Serial.print(__VA_ARGS__)
#define DEBUG_L(...) Serial.println(__VA_ARGS__)
#else
#define DEBUG_B(...)
#define DEBUG_P(...)
#define DEBUG_L(...)
#endif

#include <MobaTools.h>
MoToStepper Step(200, STEPDIR);          // Schritte pro Umdrehung

const byte stepPin = 2;          // X.STEP
const byte dirPin = 5;           // X.DIR
const byte sensorPin = 9;
const byte en = 10;
const uint32_t mindestZeit = 2000;
bool isDetect = false;
uint32_t detectTime = 0 ;
uint32_t jetzt;

void setup() {
  DEBUG_B(115200);
  DEBUG_L(F("Start ..."));
  pinMode(en, OUTPUT);
  pinMode(sensorPin, INPUT_PULLUP);       //Sensor eingang
  Step.attach( stepPin, dirPin );         // stepPin, dirPin
  Step.setSpeed( 3000 );                  // = 300 U/Min
  Step.setRampLen( 50 );                  // Beschleunigung
  Step.setZero();                         // Referenzpunkt setzen
  Step.rotate( 1 );                       // Richtung ist immer vorwärts
}

void loop()
{
  jetzt = millis();
  Sensor ();
  static byte schritt = 0;
  switch ( schritt )
  {
    case 0:
      if (isDetect == LOW)         // Sensor detektiert etwas
      {
        serMon( schritt, "Zeit gestartet" );
        detectTime = jetzt;
        schritt++;
      }
      break;
    case 1:
      if (isDetect == HIGH)         // Sensor detektiert etwas
      {
        serMon( schritt, "Teil Ende erkannt" );
        schritt++;
      }
      break;
    case 2:
      if (isDetect == LOW)         // Sensor detektiert etwas
      {
        serMon( schritt, "Teil Ende erkannt, Zeitdiff: \t", jetzt - detectTime );
        if (jetzt - detectTime >= mindestZeit)  // letzte detektZeit ist zu kurz? ...
        {
          serMon( schritt, "Zeit überschritten, Motor dreht weiter" );
          Step.rotate( 1 );                        // Richtung ist immer vorwärts
          detectTime = jetzt;
          schritt = 1;
        } else {
          serMon( schritt, "Zeit unterschritten, Motor Halt" );
          Step.rotate( 0 );                        // Anhalten mit Rampe
          Step.setZero();                          // Referenzpunkt setzen, wohl nicht benötigt, aber der Positionszähler läuft dann nicht über
          schritt++;
        }
      }
      break;
    case 3:
      if (jetzt - detectTime >= mindestZeit)  // letzte detektZeit ist zu kurz? ...
      {
        serMon( schritt, "Zeit erreicht, Motor Start" );
        Step.rotate( 1 );                        // Richtung ist immer vorwärts
        detectTime = jetzt;
        schritt = 1;
      }
      break;
    default:
      schritt = 0;
  }
}

void Sensor (){
    digitalWrite (en, HIGH);
 delayMicroseconds( 210);
  if(digitalRead(sensorPin)){
    isDetect=false;
    //Serial.println("            aus");
  }
  else {
    delayMicroseconds( 395);
    if(digitalRead(sensorPin)){
      isDetect = false;
    }
    else {
          isDetect = true;
    //Serial.println("an");
    }
  }
digitalWrite (en, LOW);
}



void serMon(byte s, const char * text)
{
  serMon( s, text, 0 );
}

void serMon(byte s, const char * text, const uint32_t diff)
{
  DEBUG_P(jetzt);
  DEBUG_P(F("\tSchritt: "));
  DEBUG_P(s);
  DEBUG_P('\t');
  DEBUG_P(text);
  if (diff)
  {
    DEBUG_P('\t');
    DEBUG_P(diff);
  }
  DEBUG_L();
}

naja, auch nicht rosig.
in dem Fall, wenn ich das Miniprogramm hier einbinde, macht der Motor ca. 1 Stepp pro Sekunde, (man hört es) aber läuft wieder nicht rund ...

// Stepper Motor X

const byte stepPin = 2;          //X.STEP
const byte dirPin = 5;           // X.DIR
const byte sen = 9;
const byte en = 10;
const uint32_t mindestZeit = 2000;
uint32_t detectTime;
bool antrieb;
bool isDetect = false;


const uint16_t anzahlZeiten = 200;   //
uint32_t zeiten[anzahlZeiten] = {0}; // berechnete Laufzeit aufnehmen
uint16_t laufendeZeit;

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  pinMode(stepPin, OUTPUT);   // Step Signal fuer Geschw.
  pinMode(dirPin, OUTPUT);    //Dir -> direction
  pinMode(en, OUTPUT);
  pinMode(sen, INPUT);        //Sensor eingang
  antrieb = true;
}
void loop()
{
  Erkennung();
  
  uint32_t myMicros = micros();    // Startzeit merken
  if (isDetect = true)         // Sensor detektiert etwas
  {
    //isDetect = true;                         // Merken
  }
  if (millis() - detectTime <= mindestZeit)  // letzte detektZeit ist zu kurz? ...
  {
    if (isDetect == true)                    // ... und was detectiert?
      antrieb = false;                       // Antrieb aus
  }
  else                                       // letztes detekt ist lange her
  {
    antrieb = true;                          // Antrieb ein
   
      if (isDetect == true)                  // Merker ist gesetzt? ...
      {
        detectTime = millis();               // ... dann Zeit merken
        isDetect = false;                    // Merker immer löschen
      
    }
  }
  // Ab hier Berechnung....
  zeiten[laufendeZeit] = micros() - myMicros; // Von loop() Anfang bis hier
  laufendeZeit++;                             // Nächste Position bestimmen
  motor();
  //serMon();
  zeiten[laufendeZeit] = micros() - myMicros; // Von loop() Anfang nach Motor und SerMon
  laufendeZeit++;                             // nächste Position bestimmen
  if (laufendeZeit >= anzahlZeiten)           // Array ist voll?
  {
    for (uint16_t u = 0; u < anzahlZeiten; u += 2)
    {
      Serial.print(zeiten[u]);                // Erste Zeit
      Serial.print('\t');
      Serial.println(zeiten[u + 1]);          // zweite Zeit
    }
    laufendeZeit = 0;                         // Array von vorn befüllen
  }
}

void motor()
{
  if (antrieb == true)
  {
    digitalWrite(dirPin, LOW);
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(471);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(471);
    //Serial.println("Laeuft");von 48 bis 64
  }
  else
  {
    digitalWrite(stepPin, LOW);
  }
}
void serMon()
{
  static bool oldAntrieb = false;
  static bool oldDetect = false;
  if (antrieb != oldAntrieb)
  {
    Serial.println(F("Zustand Antrieb: "));
    if (antrieb == true)
      Serial.println("ein");
    else
      Serial.println("aus");
    oldAntrieb = antrieb;
  }
  if (isDetect != oldDetect)
  {
    Serial.println(F("Zustand Sensor: "));
    if (isDetect == false)
      Serial.println(F(" da steht was vor"));
    else
      Serial.println(F("ist frei"));
    oldDetect = isDetect;
  }
}
void Erkennung(){
  digitalWrite (en, HIGH);
 delayMicroseconds( 210);
  if(digitalRead(sen)){
    isDetect=false;
    Serial.println("            aus");
  }
  else {
    delayMicroseconds( 395);
    if(digitalRead(sen)){
      isDetect = false;
    }
    else {
          isDetect = true;
    Serial.println("an");
    }
  }
digitalWrite (en, LOW);
}

Ich habe es auch versucht mit einem Neuaufbau mit vielen Ausgaben, aber auch hier funktioniert wieder die ERkennung nicht wie sie es sollte :

int detect;
bool antrieb = true;
bool isDetect = false;
int Zahl = 0;
bool TEIL = false; 

#include <MobaTools.h>
MoToStepper Step(200, STEPDIR);          // Schritte pro Umdrehung

const byte stepPin = 2;          // X.STEP
const byte dirPin = 5;           // X.DIR
const byte sen = 9;
const byte en = 10;
const uint32_t mindestZeit = 2000;
//uint32_t isDetect = false;
uint32_t detectTime = 0 ;
uint32_t jetzt = 0;
uint32_t Zeit = 0;

void setup() {
  //  DEBUG_B(115200);
  //  DEBUG_L(F("Start ..."));
  pinMode(sen, INPUT_PULLUP);             //Sensor eingang
  Step.attach( stepPin, dirPin );         // stepPin, dirPin
  Step.setSpeed( 3000 );                  // = 300 U/Min
  Step.setRampLen( 50 );                  // Beschleunigung
  Step.setZero();                         // Referenzpunkt setzen
  Step.rotate( 1 );                       // Richtung ist immer vorwärts
  Serial.begin(115200);
}

void loop()
{
    Erkennung();

  if (TEIL == true && Zahl != 2 && Zahl != 1)      //Erkennen was Teil ohne vorher was gesehen 
  {
    Serial.println("         Teil A vor Linse");
    Zahl = 1;
    }

  else if ( TEIL == false && Zahl == 1) //TeilA Beendet
  {
    Zeit = millis();
    Zahl = 2;
    Serial.println("         Ende von Teil A");
  }
  else if (TEIL == true && Zahl == 2)
  {
    jetzt = millis() - Zeit;

    if (jetzt <= mindestZeit) {
      Step.rotate( 0 );            // Anhalten mit Rampe
      Step.setZero();              // Referenzpunkt setzen, wohl nicht benötigt, aber der Positionszähler läuft dann nicht über
      delay(3000);
      Step.rotate( 1 );
      Zahl = 0;
      };}
    
  else {
    Zahl=0;
    Serial.println("         anderes Teil genug Abstand");
  }
   Serial.println("Loop Ende/Neustart");
}

void Erkennung() {
  digitalWrite (en, HIGH);
  delayMicroseconds( 210);
  if (digitalRead(sen)) {
    isDetect = false;
    Serial.println("                       nichts erkannt");
  }
  else {
    delayMicroseconds( 395);
    if (digitalRead(sen)) {
      isDetect = false;
      TEIL = false;
    }
    else {
      isDetect = true;
      Serial.println("       etwas detektiert");
      TEIL = true;
    }
  }
  digitalWrite (en, LOW);
}

Ich wünsche Euch eine gute Nacht und tausend Dank für Eure Unterstützung!