Forum: Mikrocontroller und Digitale Elektronik Arduino UNO - Drehzahlmessung Propeller


von Tbd (ids2001)


Lesenswert?

Hallo Forum,


ich komme bei folgender Auflösung einfach nicht auf die Ursache des 
Problems.
Ich möchte die Drehzahl eines Elektromotors ( Brushless Motor ) welcher 
direkt einen Propeller antreibt via IR Lichtschranke ( IR Senderdiode + 
Fototransistor ) und OPV Komperatorschaltung ( TTL Komperator ) auf 
einem digital Port von meinem Arduino UNO ermitteln.

Nachfolgend die Function bzgl Drehzahlmessung
Drehzahlmessung() rufe ich im Hauptprogramm auf.

Umdrehung, negFlanke 3 und negFlanke1 sind double.

Die Ausgabe der Umdrehungen pro Minute erfolgt dann auf einem Display 
bzw über die COM Schnittstelle.
Leider stimmen die Werte nicht, denn fühlbar steigender Motordrehzahl 
sinkt mein Ergebnis am Display bzw scheint es einfach nicht richtig zu 
sein :-(

nach dem Quellcode schildere ich noch meine Gedanken zur 
Flankenerkennung des Signals vom Drehzahlsensor ( Ausgang TTL Komperator 
)
1
int Drehzahlmessung (){
2
  timeStart = micros();               // Variable bei functionsaufruf mit Zeitwert versehen für Schleifenbedingung 
3
  time = micros();                // Variable bei functionsaufruf mit Zeitwert versehen für Schleifenbedingung  
4
  StartMessung = 0;
5
  posFlanke = 0;
6
  negFlanke = 0;
7
     
8
9
   while((time - timeStart) <= 2000000)            //Schleife wird 2sec durchlaufen --- HAUPTSCHLEIFE IN FUNCTION ---
10
   {
11
     time = micros();
12
   
13
     
14
   if(digitalRead(nRPM) == HIGH )            // bei steigender Flanke oder beim einstieg während eines positiven Signales wird Merker StartMessung auf 1 gesetzt
15
    {
16
      StartMessung = 1;
17
      
18
    } 
19
    
20
   if (digitalRead(nRPM) == LOW && StartMessung == 1 )         // bei erster fallender Flanke innerhalb der 2sec wird Merker negFlanke auf 1 gesetzt
21
    {
22
       negFlanke = 1;
23
       negFlanke1 = micros();              // hier beginnt nun die Periodendauermessung für die Ermittlung der Propellerdrehzahl
24
       
25
    }
26
   
27
    if (StartMessung == 1 && negFlanke == 1 )          // erste pos Flanke und erste neg Flanke bereits passiert 
28
    {
29
    while(negFlanke <= 3)              //Schleife wird so lange durchlaufen bis 3 fallende Flanken erkannt worden sind. Dies bedeutet eine volle Umdrehung ist abgeschlossen
30
       {
31
         
32
         if ( digitalRead(nRPM)==HIGH && StartMessung == 1 && negFlanke == 1 ) // 2. pos Flanke wird abgefragt und Merker gesetzt
33
           {
34
            posFlanke = 1;
35
           
36
           // posFlanke1 = micros();
37
           }
38
         if (digitalRead(nRPM) == LOW && StartMessung == 1 && posFlanke == 1 ) // 2. neg Flanke wird abgefragt und Merker gesetzt
39
           {
40
            negFlanke = 2;
41
            //negFlanke2 = micros();
42
            
43
           }
44
         if ( digitalRead(nRPM)==HIGH && StartMessung == 1 && negFlanke == 2 )  // 3. pos Flanke wird abgefragt und Merker gesetzt
45
           {
46
             posFlanke = 2;
47
             //posFlanke2 = micros();
48
             
49
           }
50
         if (digitalRead(nRPM) == LOW && StartMessung == 1 && posFlanke == 2 )  // 3. neg Flanke wird abgefragt und Merker gesetzt
51
           {
52
            negFlanke = 3;
53
            negFlanke3 = micros();
54
            
55
           }
56
         if ( digitalRead(nRPM)==HIGH && StartMessung == 1 && negFlanke == 3 )  // 4. pos Flanke wird abgefragt und Merker gesetzt
57
           {
58
             posFlanke = 3;
59
           }
60
         if (digitalRead(nRPM) == LOW && StartMessung == 1 && posFlanke == 3 )  // 4. neg Flanke wird abgefragt und Merker gesetzt ==> Ausstiegsbedingung aus Schleife weil < 3 
61
           {
62
            negFlanke = 4;
63
           }
64
65
       }                   // Ende der while Schleife neg Flankenerkennung
66
      }
67
     if ( negFlanke == 4 )               // bei voller Umdrehung werden Merker wieder auf 0 gesetzt
68
        {
69
         StartMessung = 0;
70
         posFlanke = 0;
71
        } 
72
          
73
    }                    // Ende der Hauptschleife - nach 2 Sekunden durchlauf                                       
74
            Umdrehungen = 60/((negFlanke3 - negFlanke1)/1000000);    // Berechnung der Umdrehungen pro Minute | upm = Frequenz * 60 = 1 / T * 60
75
            negFlanke = 0;               // Merker 0 setzen nach Ende Hauptschleife und vor Ausstief aus function Drehzahlmessung ()
76
77
   return Umdrehungen;
78
}


Hinweis zur Flankenerkennung.

Ich verwende einen 2 Blatt Propeller und wenn die IR Lichtschranke vom 
Propeller aktiviert wird, liefert sie log 1 zurück.
D.h ein Zweiblattpropeller hat bei einer vollen Umdrehung 3 neg. Flanken 
im Signalausgang.

Im Hauptprogramm void loop () wird die Function Drehzahlmessung() 
aufgerufen.
Nachdem man sich nun in Drehzahlmessung() befindet betritt man zuerst 
eine While Schleife die 2sec lang durchlaufen wird. ( Hauptschleife )

Hier wird nun auf die erste pos Flanke gewartet.
Passiert man diese setze ich den Merker StartMessung auf 1.
Danach wird auf die erste fallende Flanke gewartet.
Hier folgt dann die Merkersetzung negFlanke = 1.
Hier wird dann über die Zeile negFlanke1 = micros(); der aktuelle 
Zeitwert abgespeichert.

Nun kommt man in die nächste While Schleife welche für die Erkennung von 
3 fallenden Flanken für eine volle Umdrehung des Propellers zuständig 
ist.
Hat man die 3. fallende Flanke passiert, wird negFlanke3 = micros(); mit 
dem entsprechenden Zeitwert versehen.

Die Schleife endet mit der 4. fallenden Flanken welche besagt, dass eine 
volle Umdrehung des Propellers nun durchgeführt worden ist.

Ausserhalb der Schleife errechne ich mir nun die Umdrehungen.

Die Umdrehungen pro Minute kann man mit Frequenz * 60 bestimmen.
Ich ermittelte mir ja oben die Dauer für eine Umdrehung also die 
Periodendauer T.
F = 1 / T => 60 / T wobei T von µs auf sec umgewandelt werden muss.




Wisst ihr wo ich den Wurm drinnen habe?
Ich hoffe der Fred ist nicht zu lange lol

danke für eure Hilfe

lg

Dieter

von Kan a. (Firma: Basta) (kanasta)


Lesenswert?

probier vlt. mal den arrrrrduino duo.

von Tbd (ids2001)


Lesenswert?

funktioniert das Programm nicht auf den UNO oder wieso soll ich den DUO 
verwenden?

Gruß
Dieter

von Karl H. (kbuchegg)


Lesenswert?

Dein Code kommt mir .... extrem kompliziert vor.

Im Prinzip ist das eine Statemaschine, nur ist die so unübersichtlich, 
dass es nicht leicht ist da durchzublicken, wo das Problem liegt.

von Tbd (ids2001)


Lesenswert?

naja wie würdet ihr ein TTL Rechtecksignal von einer IR Lichtschranke 
auswerten um auf die Drehzahl des Propellers zu kommen.
Eine volle Propellerumdrehung bedeutet mindst 3 neg Flanken also ein 
Rechtecksignal mit 3 Höckern g

Ich lasse mich ja gerne eines besseren belehren und will ja was lernen, 
letztendlich bin ich ja hier im Forum.


Aber am Arduino UNO liegt es nicht oder?

von Karl H. (kbuchegg)


Lesenswert?

Dieter Sch schrieb:

> Aber am Arduino UNO liegt es nicht oder?

Kann ich mir nicht vorstellen. Zu 99% sitzt das Problem immer vor dem 
Bildschirm :-)


Eine Statemaschine baut man sollvollerweise so:

Es gibt eine Variable, die den State (=den Zustand) der Maschine 
enthält. Weiters gibt es einen großen switch-case, der je nach Zustand 
einen anderen case anspringt. Den Zuständen gibt man sinnvolle Namen 
(per #define). In jedem Zustands-case wird dann die Logik abgearbeitet, 
die zu diesem Zustand gehört.

Bei dir dann etwa so (weil du ja auch noch ein maximales 2 Sekunden 
Intervall haben willst.
1
#define WARTE_ERSTE_FLANKE  0
2
#define WARTE_DRITTE_FLANKE 1
3
#define MESSUNG_FERTIG      2
4
5
int Messung()
6
{
7
  uint8_t state;
8
  uint8_t prevPegel, pegelNow;
9
  uint8_t nrFlanken;
10
  uint16_t startTime;
11
  uint16_t endTime;
12
  
13
  state = WARTE_ERSTE_FLANKE;
14
  prevPegel = digitalRead(nRPM);
15
  nrFlanken = 0;
16
17
  timeStart = micros();
18
  timeNow   = timeStart;
19
20
  //
21
  // Schleife endet bei
22
  //   Zeitüberschreitung (keine Pulse am Eingang)
23
  //   wenn eine entsprechende Anzahl Pulse detektiert wurde
24
  //
25
  while( timeNow - timeStart < 2000 &&
26
         state != MESSUNG_FERTIG )
27
  {
28
    timeNow = micros();
29
    pegelNow = digitalRead(nRPM);
30
31
    switch( state )
32
    {
33
      case WARTE_ERSTE_FLANKE:
34
        //
35
        // Warten auf die erste steigende Flanke
36
        // ist die erkannt, dann beginnt das Messintervall
37
        //
38
        if( prevPegel != pegelNow && pegelNow == HIGH )
39
        {
40
          startTime = timeNow;
41
          state = WARTE_DRITTE_FLANKE;
42
        }
43
        break;
44
45
      case WARTE_DRITTE_FLANKE:
46
        //
47
        // Messung läuft gerade
48
        // Nach der 3.ten erkannten steigenden Flanke wird abgebrochen
49
        // die 3.te steigende Flanke nach der ersten ist die hier:
50
        //
51
        //   +---+    +---+    +----+    +----+    +----+
52
        //   |   |    |   |    |    |    |    |    |    |
53
        // --+   +----+   +----+    +----+    +----+    +----
54
        //          ^ ^        1         2         3
55
        //          | |                            |
56
        //          | |                            Ende der Messung
57
        //          | Beginn der Messung
58
        //          |
59
        //          Einstieg in die Funktion
60
        //
61
        // Die 3.te steigende Flanke kennzeichnet den Begin des
62
        // 4.ten Pulses. Ein 2 Blatt Prop hat daher 2 Umdrehungen
63
        // gemacht.
64
        //
65
        if( prevPegel != pegelNow && pegelNow == HIGH )
66
        {
67
          nrFlanken++;
68
          if( nrFlanken == 3 )
69
          {
70
            endTime = timeNow;
71
            state = MESSUNG_FERTIG;
72
          }
73
        }
74
        break;
75
    }
76
77
    prevPegel = pegelNow;
78
  }
79
80
  if( state == MESSUNG_FERTIG )
81
  {
82
    Drehzahl = ......;  // aus endTime und startTime die Drehzahl
83
                        // errechnen
84
  }
85
  else
86
    Drehzahl = 0;      // wegen Zeitüberschreitung
87
}


Eine (steigende) Flanke wird detektiert, wenn bei 2 mal hintereinander 
nachsehen feststellt dass:
a) sich der Eingangspegel verändert hat
b) der jetzige Eingangspegel high ist. Denn dann muss er aufgrund von a)
   vorher low gewesen sein. Ein Übergang low->high ist aber genau eine
   steigende Flanke.


(Ich geh mal davon aus, dass die Funktion micros() auch zuverlässig 
irgendwelche Zeiten [Mikrosekunden?] liefert)

von Verwirrter Anfänger (Gast)


Lesenswert?

Dieter Sch schrieb:
> naja wie würdet ihr ein TTL Rechtecksignal von einer IR Lichtschranke
> auswerten um auf die Drehzahl des Propellers zu kommen.

Wie genau muss dass den zeitlich aufgelöst sein?

Als ersten simplen Ansatz würde ich einfach zählen, wie viele negative 
Flanken pro 1 (10,100,...) Sekunden auftauchen, und die Zahl dann durch 
3 Teilen. Damit hab ich die Anzahl der Umdrehungen in 1er (10, 100, ...) 
Sekunden und kann dann die RPM ausrechnen.

von Kan a. (Firma: Basta) (kanasta)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Zu 99% sitzt das Problem immer vor dem Bildschirm :-)

arrrrr.

von Tbd (ids2001)


Lesenswert?

Verwirrter Anfänger schrieb:
> Wie genau muss dass den zeitlich aufgelöst sein?

naja die Anwendung ist halt im Hobbybereich also sollte richtige Werte 
liefern aber muss nicht 100% genau sein.
Jedoch schadet es nicht meiner Meinung wenn ich nebenbei auch noch einen 
solch tolle Programmierkünste wie von Karl Heinz mir angeigen.

Aja, gibt es ein Programm was sowas generiert oder muss man es händisch 
eintippen?
 //
        //   +---+    +---+    +----+    +----+    +----+
        //   |   |    |   |    |    |    |    |    |    |
        // --+   +----+   +----+    +----+    +----+    +----
        //          ^ ^        1         2         3

von Karl H. (kbuchegg)


Lesenswert?

Dieter Sch schrieb:

> Aja, gibt es ein Programm was sowas generiert oder muss man es händisch
> eintippen?
>  //
>         //   +---+    +---+    +----+    +----+    +----+
>         //   |   |    |   |    |    |    |    |    |    |
>         // --+   +----+   +----+    +----+    +----+    +----
>         //          ^ ^        1         2         3

Das hast du mit der Hand schneller eingetippt als dein Windows eine 
externe Applikation gestartet hat :-)

Ach eines noch:
Der Code hier ist 'kalt getippt', nach besten Wissen und Gewissen. Da 
mögen noch Fehler drinn sein.

von Tbd (ids2001)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Der Code hier ist 'kalt getippt', nach besten Wissen und Gewissen. Da
> mögen noch Fehler drinn sein.

dann werd ich sie suchen ;-)
Danke für die tolle Unterstützung

von h_ (Gast)


Lesenswert?

Warum legst du dein Signal nicht auf einen Countereingang? Ein zweiter 
Counter, der auf fester Frequenz läuft, ist dabei die Referenz. Mit 
diesen zwei Countern hast du jetzt mehrere Möglichkeiten zu messen. Zum 
Beispiel kannst du warten, bis der Periodenzähler bei 0xff (Überlauf 
eines 8-Bit Counters) angekommen ist, oder bei einem beliebig anderen 
Wert, den man über ein Compare-Register einstellen kann. Egal welche 
Methode du benutzt, in einer ISR kannst du nun auf den Zählerstand 
deines Referenztimers zugreifen  (Overflows beachten!) und die gezählten 
Perioden mit der tatsächlich vergangenen Zeit in Beziehung bringen. 
Ausgabe über Display oder UART wie gehabt.

von Tbd (ids2001)


Lesenswert?

Karl Heinz Buchegger schrieb:
> uint16_t startTime;
>   uint16_t endTime;

Hallo,

musste hier das Ganze nur auf uint32_t ändern weil micros() ja eine µs 
Wert ausgibt und dieser bei 2Sec auf 2000000 ansteigt und somit vom 
16bit Int Wert überlaufen wird.

Der nächste Schritt wird der Abgleich im Betrieb, also bei laufenden 
Motor mit einem handelsüblichen Drehzahlmesser sein, damit ich 
feststellen kann ob die Software richtig rechnet.

Vielen Dank für die tolle Unterstützung

lg
Dieter

von Niang (Gast)


Angehängte Dateien:

Lesenswert?

so sieht es aus  ,
nach 60 impuls  gibt das programme die drehzahl aus

von Thomas F. (igel)


Lesenswert?

Niang schrieb:
> nach 60 impuls  gibt das programme die drehzahl aus

Du bist 5 Jahre zu spät dran.

Edit: Und du bist im falschen Fred gelandet.

: Bearbeitet durch User
von Chefkoch (Gast)


Lesenswert?

Tritt der Effekt IMMER auf, dass bei steigender Drehzahl eine fallende 
Drehzahl angezeigt wird?

>Die Ausgabe der Umdrehungen pro Minute erfolgt dann auf einem Display
>bzw über die COM Schnittstelle

Mir scheint, dass deine Flankenerkennung mittels Polling des von dir 
ausgesuchten Pins erfolgt. Wenn der Controller z.B. gerade mit dem 
Bedienen des Displays oder des COM Treibers beschäftigt ist, würde er 
die Flanke verpassen. Daher meine Eingangsfrage - für mich klingt das 
auf den ersten Blick nach einem Nyquistproblem.

Solche Aufgaben löst man z.B. mit Pins, die einen externen Interrupt 
zulassen zusammen mit einem Timer. Da weiß ich nicht, ob es Arduino 
Bibliotheken gibt, die einem diese externen Interrupts zugänglich 
machen.

von Einer K. (Gast)


Lesenswert?

auch wenn der Thread steinalt ist...

Chefkoch schrieb:
> Da weiß ich nicht, ob es Arduino
> Bibliotheken gibt,

Arduino kennt die Funktion pulseIn().
Damit lässt sich das Problem vermutlich schon erfolgreich erschlagen.
Hat man die Zeit(en), ist es trivial, die Drehzahl zu berechnen.
Die Geometrie des Propellers ist ja hoffentlich Drehzahlunabhängig, und 
kann damit als konstanter Parametersatz einfließen.


Auch gibts genug Libs, welche sich mit Frequenzmessungen beschäftigen.
Dafür dann Timer und Interrupts nutzen.
vielleicht sind diese ja ein Quell der Inspiration.

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Ich hänge mich Mal an diesen betagten Thread an - dieses Mal war mir das 
Alter schon in den ersten drei Posts aufgefallen :)
stolz auf mich bin

Ok, das Problem ist wohl schon lange Keines mehr - aber warum muß ich 
die Luftschraube erfassen, wenn ich doch ein zur Luftschraubendrehzahl 
proportionales Motor-Ansteuersignal habe?
Gerade bei einem BLDC sollte Das gegeben sein.
Einfach das Signal anzapfen, auf Arduino verdauliche Spannungswerte 
begrenzen und zählen/Zeit messen, was dem Motor vorgeworfen wird.
Mit dem Datenblatt des Motor oder ein/zwei Messungen von Hand zu den vom 
Arduino ausgegebenen Werten kann ich den Faktor Drehfeld->Drehzahl 
bestimmen und schon sind wir fertig.

Es sei, es kommt darauf an, daß die Luftschraube detektiert wird - aus 
der Motordrehzahl kann ich noch nicht ableiten, ob die Schraube 
überhaupt noch an Ihrem Platz ist.

MfG

Edit
Oh oh - jetzt wird der Thread nicht mehr als steinalt per roter Schrift 
markiert - tschuldigung :/

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.