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
intDrehzahlmessung(){
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
returnUmdrehungen;
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
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.
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?
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
intMessung()
6
{
7
uint8_tstate;
8
uint8_tprevPegel,pegelNow;
9
uint8_tnrFlanken;
10
uint16_tstartTime;
11
uint16_tendTime;
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
caseWARTE_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
caseWARTE_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)
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.
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
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.
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
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.
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
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.
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.
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 :/