Drehzahlmessung per Interrupt und Gabellichtschranke

Moin,
es hängt mal wieder bei mir, soll heissen ich bräuchte Hilfe, mal wieder.

Folgende Problemlösung wird gesucht:
Messen der Drehzahl eines Spindelmotor (Drehbank) um die Leitspindel per Schrittmotor mit der gewünschten Drehzahl anzusteuern. Das ganze soll zum Gewindedrehen dienen daher sollte die Auswertung und Regelung sich möglichst in Echtzeit abspielen.

Derzeitiges Problem ist das Messen der Drehzahl. Mein Lösungsansatz ist folgender:
eine Scheibe mit 90 "Zähnen" sitz auf der Spindelwelle und durchläuft eine Gabellichtschranke.
Die positive Flanke des Signals zähle ich per Interrupt. Nach 100ms lese ich den Zähler aus und kann so die Drehzahl berechnen. Soweit die Theorie. Gemessene Ergebnisse schwanken : z.B.
effektive Drehzahl = 133 U/min.
gemessen Flanken = 60 - 65
Abfrageintervall = 100ms

ergibt bei mir 60 Flanken * 10 => also 600 Impulse/Sekunde // (60 Flanken * 10 *100ms)
/ 90 Zähne = 6,666 U/sek
400 U/min.

Jetzt die große Frage:

  1. wieso schwankt das Ergebnis so stark (60 - 65) ?????
  2. wo ist bei meiner Berechnung der Fehler ????

Oszi nicht vorhanden,

Vielleicht geht es ja anders einfacher und vor allem genauer

Denkanstösse und Tips sind willkommen

#include "Wire.h"

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

#define PIN_DOUT 2
#define lmillis() ((long)millis())

long lastAction;
volatile int count = 0;



void setup()
{
  Serial.begin(115200);
  Wire.begin();
  lcd.init();                                             //LCD 1602 starten 
  lcd.backlight(); 
  lcd.setCursor(1, 0);
  lcd.print("Drehzahl 1.1");
  lcd.setCursor(1, 1);
  lcd.print("V 1.1");
  delay(1000);
  lcd.clear();

  pinMode(PIN_DOUT, INPUT);
  attachInterrupt(digitalPinToInterrupt(PIN_DOUT), isrCount, RISING);
}



void loop()
{
  if (lmillis() - lastAction >= 100) 
    {
      detachInterrupt(digitalPinToInterrupt(PIN_DOUT));
      lastAction = lmillis();
      Serial.println(count);
      count = 0;
      attachInterrupt(digitalPinToInterrupt(PIN_DOUT), isrCount, RISING);
    }
}



void isrCount()
  {
    count++;
  }

Gruß Stefan

Hatten wir doch schon!

Tausche mal die loop() aus:

void loop()
{
  if (lmillis() - lastAction >= 100) 
    {
	  lastAction = lmillis();
      noInterrupts();
      int countRead = count ;
	  count=0;
      interrupts();
	  Serial.println(countRead);
	  
    }
}

Kannst du das mal ins deutsche, für Anfänger übersetzen?

wird auf den counter nur zugegriffen, wenn kein Interrupt aktiv ist

das muss unsigned long sein

was ist das für eine Funktion?

das sind nicht immer 100ms! das kann länger sein.

Hallo
das liegt an Deiner Messmethode, ich weiß nicht wie Du an die 65 Zähne kommst die du misst.

Du hast 133u/min x90 Zähne = 11970 Impulse / Minute

das sind in 100 ms =11970 / 600 = 19.9Impulse
bzw. etwa 199Hz

Nun kannst Du aber keine 0,3 Impulse messen Dein Zähler misst entweder 19 oder 20 Impulse. Das ergibt eine Auflösung von etwa 5%.

Bei kleinen Frequenzen sollte man eine Periodendauer Messung machen. Dabei wird die Zeit zwischen zwei gleichen Flanken gemessen. Das kann man mit micros() gut machen. Du misst in der ISR die Differenz zwischen dem aktuelle und dem letzten Aufruf.

actmicros=micros()
messwert=actmicros-lastmicros;
lastmicros=actmicros;

Außerhalb der ISR berechnest Du die Drehzahl dann als float Wert. Dabei musst Du natürlich beachten das es sich bei Deinem Messwert um Microsekunden handelt. Du kannst auch erst mal als Hilfsgrösse die Frequenz (Hz) ausrechnen.

Frequenz= 1000000.0 / Messwert
Drehzahl = Frequenz x 60 / 90 müsste es dann sein.

Nachtrag.
Berechnung oben geändert hatte die Anzahl der Zähne mit 60 gerechnet.

@ paulpaulson
brachte nicht den erwünschten Erfolg.

@Rentner
die oben beschriebenen 60 - 65 Impulse wurden innerhalb 100ms gezählt.

Bei kleinen Frequenzen (wo fangen hohe an??) leuchtet ein die Zeit zu messen. Ich habe versucht das mal umzustellen. Ich hoffe ich hab nicht wieder ein Fehler drin. Aber das Ergebnis in Mikrosekunden springt zwischen 8588 und 11636 Microsekunden. Allerdings auch nur noch die zwei Werte. Gemessen an einer anderen Zahnscheibe (36 Zähne) mit in etwa gleicher stabilen Drehzahl.


#define PIN_DOUT 2

long actmicros = 0;
long Messwert = 0;
long lastmicros= 0 ;
float Frequenz = 0;

void setup()
{
  Serial.begin(115200);
  Wire.begin();
  
  pinMode(PIN_DOUT, INPUT);
  attachInterrupt(digitalPinToInterrupt(PIN_DOUT), isrCount, RISING);
  attachInterrupt(digitalPinToInterrupt(PIN_DOUT), isrCount, RISING);
}



void loop()
{
  noInterrupts();
  //Frequenz= 1000000 / Messwert;
  Frequenz=  Messwert;
  Serial.println(Frequenz);
  Frequenz = 0;
  interrupts();
}



void isrCount()
{
  actmicros=micros();
  Messwert=actmicros-lastmicros;
  lastmicros=actmicros;
}

Gruß Stefan

im letzten Satz vielleicht unglücklich ausgedrückt. Die Drehzahl ist stabil . Sie beträgt ungefähr 150 U/min

Hallo
ich habe mal in meiner Basterkiste gesucht was gefunden und noch mal kurz getestet.

Der Test erfolgt mit Tone und einer Brücke zum testen.

/*
 * Frequenzmessung mittels Periodendauermessung
 * Test mit Tone Brücke zweischen Pin5 und 2 
 */
#include<util/atomic.h>

const byte messpin = 2;
uint32_t altzeit;
uint32_t i_messwert = 0;
uint32_t messwert = 0;
uint32_t lastmic;
uint32_t actmic;

float frequenz;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
    tone(5, 500);
  attachInterrupt(digitalPinToInterrupt(messpin), messen, FALLING);
}

void loop() {
  // put your main code here, to run repeatedly:

  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    messwert = i_messwert;
  }
  
if (messwert > 100) { // Division mit 0 vermeiden
      frequenz = 1000000.0 / messwert;
    }
    else  frequenz = 0;
  
  if ( millis() - altzeit > 1000) { // Anzeige 
   altzeit=millis();
   Serial.print("Periodendauer ");
    Serial.print(messwert);Serial.print("us\t Frequenz ");
    Serial.print(frequenz);Serial.println("Hz");
  }
}

void messen() {
  actmic = micros();
  i_messwert = actmic - lastmic;
  lastmic = micros();

}

Wenn Du zu keiner konstanten Messung mit dem Motor kommst könnte ich mir noch vorstellen das der Schrittmotor ein bischen ruckelt und eventuell der ein oder andere Zahn doppelt gemessen wird.
In dem Fall hilft sicher ein kleiner Kondensator 100nF parallel zu der Lichtschranke.

Heinz

Hier While Schleife endet nicht - #2 by combie
Und Folgepostings.

2 Likes

Moin,
@Rentner,
"Der Test erfolgt mit Tone und einer Brücke zum testen".
Funktioniert ja geradezu perfekt.
Jetzt hab ich bei meinem Probeaufbau folgendes feststellen müssen, dass das Ergebnis nicht so konstant ausfällt. Da ich ja jetzt die Software ausschließen kann, suche ich die Ursache beim Zahnrad. Es ist aus Sperrholz gelasert und weist trotzdem Toleranzen in den Zahnbreiten und Zahnlücken auf habe ich jetzt nach genauem hinsehen bemerkt. Ich bin jetzt auf der Suche nach einem vernünftigen Drehsensor.

Also derweilen schönen Dank und ich werde weiter berichten.

Gruß Stefan

P.S.
Vielleicht kennt ja jemand einen Sensor bei dem die Teilung auf einer Riemenscheibe aufgeklebt werden kann

Messergebnis von heute morgen mit der Sperrholzscheibe

07:38:58.746 -> Periodendauer 4384us Frequenz 228.10Hz
07:38:59.028 -> Periodendauer 8us Frequenz 0.00Hz
07:38:59.263 -> Periodendauer 4596us Frequenz 217.58Hz
07:38:59.498 -> Periodendauer 12us Frequenz 0.00Hz
07:38:59.781 -> Periodendauer 4580us Frequenz 218.34Hz
07:39:00.017 -> Periodendauer 4544us Frequenz 220.07Hz
07:39:00.252 -> Periodendauer 4600us Frequenz 217.39Hz
07:39:00.534 -> Periodendauer 4496us Frequenz 222.42Hz
07:39:00.769 -> Periodendauer 4400us Frequenz 227.27Hz
07:39:01.004 -> Periodendauer 4672us Frequenz 214.04Hz
07:39:01.239 -> Periodendauer 4760us Frequenz 210.08Hz
07:39:01.522 -> Periodendauer 4600us Frequenz 217.39Hz
07:39:01.757 -> Periodendauer 4668us Frequenz 214.22Hz
07:39:01.992 -> Periodendauer 4716us Frequenz 212.04Hz
07:39:02.275 -> Periodendauer 4564us Frequenz 219.11Hz
07:39:02.511 -> Periodendauer 4572us Frequenz 218.72Hz
07:39:02.746 -> Periodendauer 8us Frequenz 0.00Hz
07:39:03.028 -> Periodendauer 4668us Frequenz 214.22Hz
07:39:03.263 -> Periodendauer 8us Frequenz 0.00Hz
07:39:03.498 -> Periodendauer 4592us Frequenz 217.77Hz
07:39:03.781 -> Periodendauer 8us Frequenz 0.00Hz
07:39:04.017 -> Periodendauer 4492us Frequenz 222.62Hz
07:39:04.252 -> Periodendauer 12us Frequenz 0.00Hz
07:39:04.535 -> Periodendauer 4556us Frequenz 219.49Hz
07:39:04.770 -> Periodendauer 12us Frequenz 0.00Hz

Hallo,
was ist mit der12us Messung ? die fällt ja total aus der Rolle.
ja das ist das Problem bei einer Periodenmessung. Wenn Du eine Torzeitmessung machst und du willst auf 1% auflösen dann benötigst Du eine Messzeit von 500ms bei 200 Hz. <1% ist sicher schon gewünscht.

Beruflich habe ich früher viel Periodenmessung verwendet bei Durchfluss Frequenzen 10-500 Hz, allerdings haben wir über mehrere Perioden gemessen. Das gibt dann einen Mittelwert. Wenn Du 20 Zähne messen würdest das hättest Du bei 200Hz etwa eine Messzeit von 100ms. Kleiner Toleranzen bekommst du damit schon weg. Die einzelne Zahnbreite spielt ja keine Rolle , die Periode muss halt möglichst gleich sein. Eventuell kannst Du den ein oder anderen Zahn noch mal mit der Nagelfeile bearbeiten :wink:

So als Ansatz
Du könntest bei meinem Sketch auch alle 10ms den Wert auslesen. Damit hast Du sicher 10 verschiedene Zähne-Perioden gemessen. aus z.B 10 Messwerten bildest einen Mittelwert. Dann ist deine gesamte Messzeit 100ms bei hoher Auflösung.

oder
In die ISR eine Periodenzähler einbauen , die micros() werden dann gemessen von z.B. 20 bis 0 . Ausserhalb wird der Periodenzähler abgefragt und bei 0 der Werte für micros() übernommen. Anschließend wir der Periodenzähler wieder auf 20 gesetzt.

constexpr byte pin {5};

void setup()
{
  Serial.begin(9600);
  tone(pin, 500);
}

void loop()
{
  Serial.print("Periodendauer ");
  Serial.print(pulseIn(pin,HIGH));
  Serial.println(" µs");
}

Nachdem ich mit neu angefertigten Zahnrädern experimentiert habe gibt es ein kleines Erfolgserlebnis zu berichten, aber erst nachdem ich den Kondensator an Pin2 angeschlossen habe. Guter Tipp

Heute Nachmittag geht es ans bilden des Mittelwertes, ist ja überschaubar :slightly_smiling_face:

Stand der Dinge

10:56:13.488 -> Periodendauer 4920us Frequenz 203.25Hz
10:56:13.726 -> Periodendauer 5064us Frequenz 197.47Hz
10:56:13.966 -> Periodendauer 5012us Frequenz 199.52Hz
10:56:14.253 -> Periodendauer 4848us Frequenz 206.27Hz
10:56:14.492 -> Periodendauer 4904us Frequenz 203.92Hz
10:56:14.731 -> Periodendauer 4796us Frequenz 208.51Hz
10:56:14.970 -> Periodendauer 4876us Frequenz 205.09Hz
10:56:15.259 -> Periodendauer 4808us Frequenz 207.99Hz
10:56:15.496 -> Periodendauer 4964us Frequenz 201.45Hz
10:56:15.736 -> Periodendauer 5012us Frequenz 199.52Hz
10:56:15.973 -> Periodendauer 4872us Frequenz 205.25Hz
10:56:16.260 -> Periodendauer 4924us Frequenz 203.09Hz
10:56:16.496 -> Periodendauer 4976us Frequenz 200.96Hz
10:56:16.735 -> Periodendauer 4956us Frequenz 201.78Hz
10:56:16.975 -> Periodendauer 4936us Frequenz 202.59Hz
10:56:17.260 -> Periodendauer 4956us Frequenz 201.78Hz
10:56:17.499 -> Periodendauer 4876us Frequenz 205.09Hz
10:56:17.738 -> Periodendauer 4976us Frequenz 200.96Hz
10:56:17.977 -> Periodendauer 4820us Frequenz 207.47Hz
10:56:18.216 -> Periodendauer 5012us Frequenz 199.52Hz
10:56:18.502 -> Periodendauer 4884us Frequenz 204.75Hz
10:56:18.740 -> Periodendauer 4964us Frequenz 201.45Hz
10:56:18.978 -> Periodendauer 4920us Frequenz 203.25Hz

Abfragezyklus = 10ms, hatte ich vergessen

Hallo
Sorry, ganz so einfach ist es nicht.
pulsein(Pin ,HIGH) misst die H Zeit. Mann müsste zusätzlich noch die L Zeit messen und das addieren um an die Periodendauer zu kommen. Das Tastverhältnis muss ja nicht 1:1 sein, bei dem Zahnrad.

Zudem blockiert das dann , insbesondere bei kleine Frequenzen würd das dann suboptimal.
.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.