Ablauf-/Fehlerzeit in Sketch ?

Hallo Gemeinde

Wie löst man elegant eine Ablauf-/Fehlerzeit im Sketch?

Bsp. switch und case. Im nächsten Schritt wird auf die Positionierung des Stepper gewartet, nach 3s soll es einen Fehler geben und der move gestoppt werden.

Wenn man die Durchlaufzeit nimmt; iFehlerzeit--; ist das keine definitive Zeit die man wartet richtig?

Danke! BG

millis() bzw für schnelle sachen micros()

Hallo,

zunächst mal kannst Du die tarsächliche Position des Steppermotors ja nicht wirklich abfragen. Der Motor hat ja keine Positionsrückmeldung.

Wenn Die die accelStepper lib verwendest kannst du zwar eine aktuelle Position abfragen, aber die enspricht dem aktuellen Positionssollwert. Du kannst also für den Ablauf deiner Schrittkette diesen Wert benutzen. Die accelStepper lib hat eine gute Beschreibung und viele Beispiele zum üben. Parallel dazu kannst natürlich mit millis() eine "Zeitüberwachung" realisieren , nach der z.B ein Endschalter angefahren sein muss.

Um die tatsächliche Position abzufragen müsste man einen inkremental Geber anbauen, das macht man eigendlich bei DC Motoren. Oder industriell auch bei AC, AC-Servo Motoren. Bei Steppermotoren geht man eigendlich davon aus das er die vorgegebene Schrittanzahl auch tatsächlich dreht. Solange das Drehmoment des Motors groß genug ist tut er das ja auch. Wenn man davon ausgehen muss das es auch mal blokieren kann, oder man tatsächlich sehr grösse Drehmomente benötigt, verwendet man einen DC, AC, mit angebautem inkremental Geber als Positions-istwert.

in Verbindung mit einem Positionsregelkreis entsteht ein sogenannter Schleppfehler, wird dieser zu groß kann der Antrieb nicht folgen und es liegt eine "Störung vor"

Heinz

Hallo,

du suchst nach einem Timeout. Ganz simpel. Beim starten der Motorbewegung die Zeit merken. Ab diesem Zeitpunkt musst du 2 Dinge abfragen. Ist Motor in Position oder ist die Wartezeit abgelaufen? Wenn Zeit vorher um > TimeOut. Ist Motor innerhalb des Timeouts in Position > Timeout zurücksetzen/deaktivieren.

Hallo!

ich habe die schnelle Lösung von Doc_Arduino probiert und sie funktioniert für mich.

case 2: iErrorTime = millis(); case 3: (millis() > (iErrorTime + iFaultTime))

aufgefallen ist mir eine "inkonsistente Situation". Der Sketch verlief sich bei einer Abfrage eines Eingangs (am Uno ist dzt. nichts angehängt). Dieser meinte ein Eingang sei HIGH. Dem ist aber nicht so, ziemlich beharrlich. Das kann einen Anfänger wie mich schon mal aus der Spur bringen, aber mit "Kodierung und neu hochladen" war der Spuk vorbei. Was genau ist das und wer kanns mir erklären?

Wie ist der Eingang beschaltet bzw. wie ist er bei setPinMode eingestellt?

Gruß Tommy

case 3: (millis() > (iErrorTime + iFaultTime))

Das soll funktionieren?
Immer?
Ich befürchte, dass da ein Fehler vorliegt.

hier mal der Code von mir:

/*
 * CONTROL-MASHINE
 * Es werden entzünderte und kalibrierte 9mm Hülsen kontrolliert. Falsche Kaliber aussortiert.
 * 1. Höhe, 3 Sensoren 
 * - 1. Sensor: 15mm, Erkennung der Hülse
 * - 2. Sensor: 19mm, korrekte Höhe
 * - 3. Sensor: 21mm, falsche Höhe
 * 
 * weitere Entwicklungen:
 * A) Lichtschranke, Erkennung des ZH Loches
 * 
 * ABLAUF:
 * 1) Kalibrierung der Maschine, Schalter = Ref & Einwurfstellung
 * 2) LOOP - Positionierung des Selektierarms zur Einwurfstelle
 * 3) nach Einwurfzeit mit Sensor 1, Abfrage der Sensoren und weiteren Schritt bestimmen
 * 3.1) Hülsenhöhe == OK, Selekierarm zum Auswurf guter Hülsen (ZH später)
 * 3.2) Hülsenhöhe != OK, Selektierarm zum Auswurf falscher Hülsen
 * 4) LOOP END
 */
 // GLOBALE KONSTANTEN ---------------------------------
  const unsigned int iStepsGoodCase = 350; // Steps zum Auswurf guter Hülsen
  const bool iDirectionGoodCase = LOW; // Richtung für die Drehbewegung
  const unsigned int iStepsBadCase = 200; // Steps zum Auswurf falscher Hülsen
  const bool iDirBadCase = HIGH; // Richtung für die Drehbewegung
  const unsigned int iStepsOfRefSwitchUp = 1000; // Steps zum Auffahren des Referenzschalter
  const unsigned int iStepsOfRefSwitchDown = 100; // Steps zum Abfahren des Referenzschalter
  const unsigned int iSpeedRefUp = 200; // Speed zum Auffahren des Refschalter
  const unsigned int iAccRefUp = 200; // Dynamik zum Auffahren des Refschalter
  const unsigned int iSpeedRefDown = 50; // Speed zum Auffahren des Refschalter
  const unsigned int iAccRefDown = 50; // Dynamik zum Auffahren des Refschalter
  const unsigned int iFaultTime = 5000; // Fehlerzeit [ms]
  const unsigned int iDelayTime = 500; // Verzögerungszeit
// GLOBALE I/O
  const unsigned int I_Sensor1 = 3; // Eingang vom Sensor 1 = Erkennung der Hülse
  const unsigned int I_Sensor2 = 4; // Eingang vom Sensor 2 = korrekte Höhe
  const unsigned int I_Sensor3 = 5; // Eingang vom Sensor 3 = falsche Höhe
  const unsigned int I_PosSensorEmptyBadCase = 6; // Position Auswurf falscher Hülsen
  const unsigned int I_PosSensorInputCase = 7; // Position Einwurf neuer Hülsen
  const unsigned int I_PosSensorCheckGoodCase = 8; // Position Überprüfung ZH
  const unsigned int I_PosSensorEmptyGoodCase = 9; // Position Auswurf guter Hülsen
  const unsigned int O_StepperENA = 11; // Enable Signal zum Treiber
  const unsigned int O_StepperDIR = 12; // Direction Signal zum Treiber
  const unsigned int O_StepperPUL = 13; // Puls Signal zum Treiber
// GLOBALE MERKER -------------------------------------      
  bool bRefMerker = LOW; // Merker ob referenziert wurde
  bool bSensor1 = LOW; // Merker für den das Sensorsignal
  bool bSensor2 = LOW; // Merker für den das Sensorsignal
  bool bSensor3 = LOW; // Merker für den das Sensorsignal
  bool bPosSensorEmptyBadCase = LOW; // Merker für Sensorsingal
  bool bPosSensorInputCase = LOW; // Merker für Sensorsingal
  bool bPosSensorCheckGoodCase = LOW; // Merker für Sensorsingal
  bool bPosSensorEmptyGoodCase = LOW; // Merker für Sensorsingal
  bool bError = LOW; // Merker für Fehlerausgabe
  unsigned int iRefState = 0; // Schrittindikator
  unsigned int iError = 0; // Error
  unsigned int iErrorTime = 0; // Startzeit für Zeitabfragen
// Bibliotheken --------------------------------------.
  #include <AccelStepper.h>
  AccelStepper stepper(AccelStepper::DRIVER,O_StepperPUL,O_StepperDIR); 
// ----------------------------------------------------
// INIT -----------------------------------------------
// ----------------------------------------------------
 void setup() {
  // Define I/O
  pinMode (I_Sensor1, INPUT); 
  pinMode (I_Sensor2, INPUT); 
  pinMode (I_Sensor3, INPUT); 
  pinMode (I_PosSensorEmptyBadCase, INPUT); 
  pinMode (I_PosSensorInputCase, INPUT); 
  pinMode (I_PosSensorCheckGoodCase, INPUT); 
  pinMode (I_PosSensorEmptyGoodCase, INPUT); 
  pinMode (O_StepperENA, OUTPUT); 
  pinMode (O_StepperDIR, OUTPUT); 
  pinMode (O_StepperPUL, OUTPUT); 
  // Define Serial Output to display machine status
  Serial.begin (9600); // Datenrate 9600 bps
}
// ----------------------------------------------------
// CODE - REF -----------------------------------------
// ----------------------------------------------------
void Referenz() // Refschalter = bPosSensorEmptyBadCase
{ switch (iRefState) {
    // ------------------------------------------------
    case 0: // ist der Selektierarm leer ?
      Serial.println("Referenzierung Start --------------");
      if (bSensor1 == LOW)
       { iRefState = 1; 
         Serial.println("R0/ Selektorarm ist leer -> R1");
       }
      else 
       { iError = 1000; 
       } break;
    // ------------------------------------------------
    case 1: // Entscheidung ob der Ref-Sensor belegt ist
      if (bPosSensorEmptyBadCase == LOW)
       { iRefState = 2; 
         Serial.println("R1/ CalSensor ist LOW -> R2");
       }
      else if (bPosSensorEmptyBadCase == HIGH)
       { iRefState = 10; 
         Serial.println("R1/ CalSensor ist HIGH -> R10");
       }
      else 
       { iError = 1001; 
       } break;
    // ------------------------------------------------
    case 2: // Richtung Refschalter fahren
      stepper.setAcceleration (iAccRefUp);
      stepper.setSpeed (iSpeedRefUp);
      digitalWrite(O_StepperENA,HIGH);
      digitalWrite(O_StepperDIR,HIGH);
      stepper.move (iStepsOfRefSwitchUp);
      iRefState = 3;
      iErrorTime = millis();
      Serial.println("R2/ Move to PosEmptyBadCase started -> R3");
      break;
    // ------------------------------------------------
    case 3: // am Refschalter angekommen ?
      if (bPosSensorEmptyBadCase == HIGH)
      { stepper.stop ();
        iRefState = 10;
        Serial.println("R3/ PosSensorBadCase aktiviert, Move Stop -> R10");
        delay(iDelayTime);
      }
      else if (millis() > (iErrorTime + iFaultTime))
      { stepper.stop ();
        iError = 1003;
      } break;
    // ------------------------------------------------
    case 10: // vom Refschalter langsam runterfahren
      stepper.setAcceleration (iAccRefDown);
      stepper.setSpeed (iSpeedRefDown);
      digitalWrite(O_StepperENA,HIGH);
      stepper.move (iStepsOfRefSwitchDown);
      iRefState = 11;
      iErrorTime = millis();
      break;
    // ------------------------------------------------
    case 11: // vom Schalter herunten?
      if (digitalRead (I_PosSensorEmptyBadCase) == LOW)
      { stepper.stop ();
        stepper.setCurrentPosition (0);
        iRefState = 12;
        delay(iDelayTime);
      }
      else if (millis() > (iErrorTime + iFaultTime))
      { stepper.stop ();
        iError = 1011;
      } break;
    // ------------------------------------------------
    case 12: // Finish
      bRefMerker == HIGH;
      Serial.println("R12/ RefMerker HIGH");
      Serial.println("R12/ Referenzierung ENDE ----------");
      break;
    // ------------------------------------------------
    default:
      iError = 1099; 
      break;
    // ------------------------------------------------
  }
}
// ----------------------------------------------------
// MAIN - CODE ----------------------------------------
// ----------------------------------------------------
void loop() 
{ // Local Merker -------------------------------------
  // poll Inputs --------------------------------------
    bSensor1 = digitalRead (I_Sensor1);
    bSensor2 = digitalRead (I_Sensor2);
    bSensor3 = digitalRead (I_Sensor3);
    bPosSensorEmptyBadCase = digitalRead (I_PosSensorEmptyBadCase);
    bPosSensorInputCase = digitalRead (I_PosSensorInputCase);
    bPosSensorCheckGoodCase = digitalRead (I_PosSensorCheckGoodCase);
    bPosSensorEmptyGoodCase = digitalRead (I_PosSensorEmptyGoodCase);

…musste ihn kürzen, ist nicht soviel erlaubt hier…

in Referenz werden nun die 5s Fehlerzeit abgewartet bis der Error angezeigt wird
der bSensor1 war HIGH, obwohl am UNO nichts angeschlossen ist, erst mit dem Kodierung korrigieren ging der Ablauf wieder.
Fehlt mir der setPinMode ?

Das kommt darauf an, wie der Taster beschaltet ist. Deshalb hatte ich danach gefragt. Offene Eingänge wirken wie Antennen und haben wechselnde und zufällige Werte.

Gruß Tommy

Tommy56: Das kommt darauf an, wie der Taster beschaltet ist. Deshalb hatte ich danach gefragt. Offene Eingänge wirken wie Antennen und haben wechselnde und zufällige Werte.

Gruß Tommy

OK, damit ist der Testaufbau Unsafe. Das ist dann ok für mich zu wissen.

Schön für Dich. Nur keine Fragen beantworten. Hilfe für Dich macht richtig "Freude".

Gruß Tommy

Tommy56: Wie ist der Eingang beschaltet bzw. wie ist er bei setPinMode eingestellt?

Tommy56: Schön für Dich. Nur keine Fragen beantworten. Hilfe für Dich macht richtig "Freude".

Verstehe nicht, hatte doch geschrieben, dass nichts am UNO angehängt ist. setPinMode findet im Google noch keinen Treffer, im Sketch nicht vorhanden. Was meinst du nun?

"Nichts angehängt" muss bei diesen Beschreibungen nicht bedeuten keinen PullUp/PullDown.

Dann ist Dein Google defekt, wenn es für setPinMode nichts findet. Meins findet ca. 28.400 Treffer.

Gruß Tommy

Die Funktion heißt pinMode(...). https://www.arduino.cc/reference/en/language/functions/digital-io/pinmode/ Entscheidend sind die Parameter auf die Tommy anspricht.

Um es zu verstehen, setPinMode ist eine selbst gestrickte Funktion?

PinMode habe ich drin, allerdings ohne Pull-Up Definition. Und es ist nichts angeschlossen, d.h. es befindet sich kein Draht am UNO. Kein Widerstand, kein … nichts.
Ich bin ja noch kompletter Anfänger, möchtet ihr mir erklären wie das nun schlau gemacht wird. Danke!

in meinem Sketch habe ich nun den Pull-Up eingestellt und die Zuweisung zum Merker !=

habe mal diesen Artikel dazu gefunden: LINK

ist das der Weg?

Ich verwende Näherungsschalter +/-/S NPN, ist es sauber mit Pull-Up diese direkt am UNO anzuschließen?

Ok, setPinMode war mein Fehler, pinMode ist richtig. Das wird auch bei der Google-Suchen nach setPinMode angezeigt. Nein, dieser Link ist nicht Dein Weg.

und die Zuweisung zum Merker !=

soll was bedeuten? Ein paar Worte mehr steigern oft die Verständlichkeit enorm. Das ist sparen an der falschen Stelle.

Das mit dem PullUp kann funktionieren, das hängt vom Sensor ab (Link).

Gruß Tommy

Sorry.

Sensor

  const unsigned int I_Sensor1 = 3; // Eingang vom Sensor 1
  bool bSensor1 = LOW; // Merker für den das Sensorsignal

void setup() {
  pinMode (I_Sensor1, INPUT_PULLUP); 
}

void loop(){
   bSensor1 != digitalRead (I_Sensor1);
}

!= ist ein Vergleich zwischen 2 Werten, keine Zuweisung.

So wird ein Schuh draus (LOW-aktiver Sensor)

bSensor1 = !digitalRead (I_Sensor1);

Die Beschreibung beim Händler ist zwar auch grottig, man kann aus mehreren Beiträgen zum gleichen Sensor herauslesen, dass es wohl ein NPN-Open Collector ist, der bei Annäherung das Signal gegen LOW zieht (HIGH bringt der Kollektorwiderstand) und damit gegen den PuulUp gefahren werden kann.

Gruß Tommy

OK, danke!

d.h. der NPN, bei Erkennung eines Objekts = LOW, sollte dann am UNO mit Pull-Up ein High auf bSensor1 bringen, verstehe ich das richtig?

digitalRead(I_Sensor1) ergibt bei LOW am Eingang LOW
!digitalRead(I_Sensor1) ergibt bei LOW am Eingang HIGH

Gruß Tommy