Geschwindigkeitsmessung mit Interrupts

Hallo liebes Forum,

ich möchte mittels einer Gabellichtschranke die stationär positioniert ist die aktuelle Geschwindigkeit einer sich bewegenden Zahnstange bestimmen. Testverläufe haben ohne Probleme ein HIGH/LOW Signal angezeigt, der Sensor funktioniert also.
Nun zu meinem Problem:

Mein Code bisher:

#define black 2 //

volatile float t0, t1;
volatile float delta, speedval;

//Für Interrupt
const float p = 1.57;   //Teilung = Pi * Modul der Zahnstange (0.5) gerundet auf zwei Nachkommastellen

void setup() {
Serial.begin(9600);
pinMode(black, OUTPUT);

//**********************************************************************************
////Lets interrupt this shiat
//Bei freier Lichtschranke ist der Ausgabewert 1
attachInterrupt(0, getTime, LOW); //0 corresponds to D2 (Arduino Mega), FALLING ->Immer wenn ein Zahn die Schranke blockiert soll die Geschwindigkeit gemessen werden
attachInterrupt(0, calcSpeed, HIGH); 
//**********************************************************************************

              }

void loop() {
    Serial.println(t0);
      Serial.print("     ");
      Serial.println(t1);
  //Testen
  //Serial.print(digitalRead(black));
  //Serial.print(" ");
  //Serial.println(speedval);

  
//Serial.print("DeltaTime: ");
//Serial.print(delta);
//Serial.print("   ******   ");
//Serial.print("Speed: ");
//Serial.println(speedval);

//Serial.println(blaval);//Gibt ON/OFF aus 1=Kein Objekt, 0=Objekt - in der Lichtschranke                                
//Ausgabewert [0:Objekt in Lichtschranke/1:Freie Lichtschranke]: "); //Nur zum Testen des Gesamtcodes

//**********************************************************************************

//Interrupt Section
void calcSpeed(){
  t1 = millis();
  delta= (t1-t0)/1000;  //Delta in Sec.
  speedval = p/(delta); //Teilung durch deltaTime  
}

void getTime(){
  t0 = millis();
              }
//**********************************************************************************

Meine calcSpeed Function funktioniert nicht und das hat damit zu tun, dass sich der t0 Wert nicht erhöht wie er sollte während das beim t1 Wert kein Problem ist. Wo ist da der Gedankensalat/-fehler bei mir?

  • Gibt es eventuell bessere Möglichkeiten die Geschwindigkeit herauszubekommen, gerade wenn der Code eigentlich länger ist und die Interrupts "dauernd" Kapazitäten beanspruchen?

Marsmann:
Meine calcSpeed Function funktioniert nicht und das hat damit zu tun, dass sich der t0 Wert nicht erhöht wie er sollte während das beim t1 Wert kein Problem ist. Wo ist da der Gedankensalat/-fehler bei mir?

attachInterrupt(0, calcSpeed, HIGH);

Besser wäre es in dem FALLING Interrupt die Geschwindigkeit zu berechenen (jetzt-letztesMal).

Auch ist es sinnvoller micros() statt millis() zu benutzen, ist halt viel genauer.

Vielen Dank für die schnelle Antwort:

Whandall:

attachInterrupt(0, calcSpeed, HIGH);

Besser wäre es in dem FALLING Interrupt die Geschwindigkeit zu berechenen (jetzt-letztesMal).

Auch ist es sinnvoller micros() statt millis() zu benutzen, ist halt viel genauer.

Hab eben ein wenig mit dem Code rumgespielt und dachte, dass es vielleicht daran liegen könnte das zwei Interrupts auf denselben Pin zugreifen und das iwie zu schnell geschieht. Was hältst du hier von?

attachInterrupt(0, calcSpeed, CHANGE); 


//Interrupt Section
void calcSpeed(){
  t0 = micros();
  delta= (t1-t0)/1000000;  //Delta in Sec.
  speedval = p/(delta); //Teilung durch deltaTime
  t1 = micros();  
}

Es kann nur eine (external) Interruptroutine pro Pin aktiv sein.

Ich habe dir beschrieben wie ich es machen würde.

Letzte Dauer (volatile uint32_t) ergibt sich aus dieser Flanke und der vorherigen Flanke, danach wird letzte auf diese gesetzt, eventuelle Floatberechnungen werden via loop erledigt, nachdem man sich bei ausgeschalteten Interrupts eine Kopie von Letzte Dauer verschafft hat.

Dir ist klar, dass du keine Bewegungsrichtung erkennen kannst?

Hab auch versucht den Code so anzupassen wie du es vorgeschlagen hattest :wink:

Ja, das ist mir klar und ist für meine Anwendung auch nicht nötig, aber danke für den TIpp.

  • Also würdest du den Wert speedVal im Loop ausrechnen lassen?
  • Kommt es eigentlich zu Ungenauigkeiten der Zeitmessung wenn der Code länger wird und der Interrupt dauernd den "Main-Code" unterbricht?

Zu Ungenauigkeiten kann es nur kommen, wenn der Hauptcode Interrupts abschaltet.

Mit welcher Geschwindigkeit sind die Zähne unterwegs?

8 bis 18 mm/sec. ALso einigermaßen langsam...