Datum:
Hallo Leute, habe ein kleines Problem: Ich habe hier einen Encoder, der über einen STM32 angesprochen wird. Der uC beschreibt automatisch ein Counter Register, je nach Zählrichtung. Das Register habe ich auf 20000 Werte begrenzt. Eine Umdrehung des Encoders bedeutet ebenfalls 20000 Counts. Ich möchte nun die absolute Anzahl der Counts anzeigen, dafür benötige ich eine Überlauferkennung. Wenn ich das so nach dem Motto mache...
if(abs(naechsterWert - vorigerWert) > xxx)) ueberlauf(); |
...benötige ich aber eine Schwelle. Ich bin mir nicht im klaren, wie groß diese sein sollte. Wähle ich sie zu groß, erkennt sie keine Überläufe, zu klein werden welche dazugedichtet... Der Encoder wird mit max 50u/s angetrieben, ein Timer, der das Counterregister ausließt hat eine Periodendauer von 6ms. Das bedeutet pro Timerintervall können max 6000 Counts entstanden sein. Angenommen meine Werte befinden sich bei 10000 und 6ms später bei 16000 Counts, dann ist alles gut, die Differenz beträgt 6000. Kurz darauf kommt der Überlauf: 1. Wert bei 15k, der 2. 6ms später bei 1k. Die Differenz beträgt jetzt |-4000|=4000. Wähle ich also 6000 als untere Grenze (darunter ist ein Überlauf), würde es hinkommen. Dreht der Encoder aber langsamer, so werden natürlich auch die Counts zwischen zwei Abtastpunkten (6ms) weniger. Z.B. nur noch 1000 steps bei 500rpm. Also wäre alles ein Überlauf :D Das blöde: Es sollen sowohl positive als auch negative Überläufe erkannt werden. Versteht ihr mein Problem? Wenn ja, wie löst man so etwas? Danke & schöne Grüße!
Datum:
Ich nochmal: Werde es jetzt erst einmal per Overflow Interrupt lösen, der eine Flag setzt. Aber wie geht es ohne Interrupt?
Datum:
stm32 schrieb: > Aber wie geht es ohne Interrupt? Du kennst die 'Richtung' in die sich der Zählerstand entwickeln müsste? (zb wegen bekannter Drehrichtung eines Motor an dem der Encoder hängt) Wenn der Counter eigentlich größer werden müsste. Wenn der neue Wert kleiner als der vorhergehende ist, gab es einen Überlauf. 19998 + 4 -> 2 vorher: 19998 jetzt: 2 -> Überlauf, indem 4 Ticks aufgelaufen sind Wenn der Counter eigentlich kleiner werden müsste Wenn der neue Wert größer als der vorhergehende ist, gab es einen Unterlauf. 2 - 4 -> 19998 vorher: 2 jetzt: 19998 -> Unterlauf, indem 4 Ticks in der anderen Richtung aufgelaufen sind Du kennst die Drehrichtung nicht: zb. du weisst nur dass sich der Wert von 15k auf 1k verändert hat. dazu gibt es 2 Möglichkeiten entweder der Counter ist immer größer geworden und hat irgendwann mit einem Überlauf die 1k erreicht oder der Counter ist in der anderen Richtung sukzessive kleiner geworden, hat also tatsächlich 15000, 14999, 14998, ..., 1002, 1001, 1000 gezählt. Welche ist die richtige Lösung? Ist der Counter größer (+Überlauf) geworden, dann hat er 1k - 15k (und weil das Ergebnis negtiv ist: + 20k): 6k Ticks zurückgelegt. -> Ergebnis A Ist der Counter regulär kleiner geworden, dann hat er 15k - 1k: 14k Ticks zurückgelegt -> Ergebnis B Da du aber weißt, das von einer Abfrage zur nächsten, der Counter sich maximal um 6k Einheiten verändern kann, KANN daher Ergebnis B nicht richtig sein. Der Counter kann sich physikalisch im betrachteten Zeitraum nicht um 14k Ticks verändert haben. Ergebnis A hingegen liegt mit 6k im Bereich des Möglichen. -> Strategie: rechne dir die Werte für beide Möglichkeiten aus und mach einen Plausibilitätscheck um zu entscheiden welcher von beiden der richtige ist. Note: Da Ergebnis A + Ergebnis B in Summe wieder die 20k ergeben müssen, und die 6k Schwelle kleiner als die Hälfte davon (10k) ist, ist es immer eindeutig welcher Fall vorliegt und man braucht auch nur einen der beiden Fälle durchrechnen. Ist der durchgerechnete Fall nicht möglich, kann es nur der andere sein.
Datum:
stm32 schrieb: >Kurz darauf kommt der Überlauf: 1. Wert bei 15k, der 2. 6ms später bei >1k. Die Differenz beträgt jetzt |-4000|=4000 Das ist ja wohl komplett falsch gerechnet. Auch ist der Überlauf nicht durch einen Wert kleiner als irgendwas gekennzeichnet, sondern größer als irgendwas.
Datum:
Danke für deine Antwort! Karl Heinz Buchegger schrieb: > Du kennst die 'Richtung' in die sich der Zählerstand entwickeln müsste? > (zb wegen bekannter Drehrichtung eines Motor an dem der Encoder hängt) Leider nein, da schnelle Änderungen, fällt somit raus. Es gibt zwar ein direction Bit, aber ich habe Angst das zu benutzen, weil der Encoder sehr hochauflösend ist und die Richtungsänderung ziemlich schnell sein kann. Karl Heinz Buchegger schrieb: > Du kennst die Drehrichtung nicht: > zb. du weisst nur dass sich der Wert von 15k auf 1k verändert hat. Das schon eher (wenn man z.B. von 3000rpm ausgeht) Karl Heinz Buchegger schrieb: > -> Strategie: rechne dir die Werte für beide Möglichkeiten aus > und mach einen Plausibilitätscheck. So in der Richtung wollte ich das ja ausprobieren, kam aber auf keinen grünen Ast ;) Dein Beispiel klingt aber logisch. Ich muss das nur noch in Befehle verpacken, werde ich morgen machen. Dankeschön =)
Datum:
chick schrieb: > Das ist ja wohl komplett falsch gerechnet. > > > Auch ist der Überlauf nicht durch einen Wert kleiner als irgendwas > gekennzeichnet, sondern größer als irgendwas. Aber das is das, was ich oben stehen hatte ;) Schlicht und ergreifend die Differenz. Dass die nicht stimmt ist ja mehr oder weniger das Problem ;)
Datum:
stm32 schrieb: > Dein Beispiel klingt aber logisch. Sowas (Überlauf/Unterlauf) kann man sich oft ganz leicht mit einer Uhr und einem Sekundenzeiger klar machen. erste Zeit: Sekundenzeiger auf 56 zweite Zeit: Sekundenzeiger auf 2 Du weisst nicht, ob es sich um eine normale Uhr oder um eine rückwärtslaufende Eieruhr handelt. Aber du weißt, dass der Vorgang (Gewicht, das vom Dach fällt) nicht länger als 10 Sekunden gedauert haben kann. Also wird es wohl eine normale Uhr gewesen sein, bei der der Zeiger über 60 drüber gelaufen ist. Denn im anderen Fall hätte der Sekundenzeiger 54 Sekunden gebraucht um von der 56 auf die 2 zu kommen. Und das widerspricht dem Grundwissen, dass der Vorgang spätestens nach 10 Sekunden vorbei ist. Dein Glück ist diese Aussage > Der Encoder wird mit max 50u/s angetrieben, ein Timer, der > das Counterregister ausließt hat eine Periodendauer von 6ms. > Das bedeutet pro Timerintervall können max 6000 Counts entstanden > sein. Die ist der Schlüssel zur Lösung des Gordischen Knotens.
Datum:
stm32 schrieb: > chick schrieb: >> Das ist ja wohl komplett falsch gerechnet. >> >> >> Auch ist der Überlauf nicht durch einen Wert kleiner als irgendwas >> gekennzeichnet, sondern größer als irgendwas. > > Aber das is das, was ich oben stehen hatte ;) Schlicht und ergreifend > die Differenz. Dass die nicht stimmt ist ja mehr oder weniger das > Problem ;) Das Problem ist, dass du dich von den Zahlenwerten hast täuschen lassen. Eine Differenz errechnet sich immer aus Ende minus Anfang. Immer! 1k - 15k und da kommt ganz sicher nicht -4k raus. Schon eher -14k. UNd weil es sich um unsigned Arithmetik handelt, kann das nicht negativ sein, sondern muss mit +20k beaufchlagt werden um wieder im erlaubten Bereich 0 bis 20k zu sein. Wieder: einfach mal mit einer Uhr und einem Sekundenzeiger klarmachen. Oder auch mit Winkeln am Winkelmesser. 20° minus 40° ergeben -20°. Um in den erlaubten Bereich 0 bis 360 zu kommen, müssen da noch 360 dazu. -20 plus 360 macht 340. Also: 20° minus 40° ergeben 340°. Und natürlich auch umgekehrt: 340° plus 40° ergeben 20° Ein Absolutwert hingegen hat da nichts verloren.
Datum:
Ist mir vollkommen klar, habe mir den Sachverhalt hier per Sägezahnfunktion dargestellt. Das Problem war es bisher das in Anweisungen zu verpacken :-( Trotzdem natürlich danke für die weitere Ausführung! Mir kommt gerade noch eine Frage hoch: Ist es überhaupt sinnvoll, den absoluten Winkel benutzen zu wollen? Unter Umständen braucht es dafür große Variablen, die auch überlaufen können. Mit einem int32 z.B. kann ich ca 30 Min auf voller Drehzahl den Winkel loggen (pos + neg). Ich möchte eigentlich eine Positionsregelung machen. Ist es da möglicherweise sinniger, die Anzahl der Überläufe zu zählen und dann per modulo Operation den Winkel herauszufinden? Kam mir gerade nur so in den Kopf ;) Und dann noch was zur Laufzeit: Eine Flag im Interrupt setzen geht schnell denke ich mal. Eine verschachtelte If-Konstruktion ist bestimmt länger. Aber ein Interrupt "stört" auch gleichzeitig die anderen Abläufe. Ich habe z.B. einen wichtigen Timer, der das Counter register abtastet. Diesen habe ich natürlich hoch priorisiert. Dann sollte das kein Problem sein oder? Die selbe Frage bezüglich der Modulo Operation: Wie viel langsamer ist die im Vergleich zum einfachen addieren der Winkel? Danke euch!
Datum:
Oh, da kam schon wieder was neues.. Karl Heinz Buchegger schrieb: > Dein Glück ist diese Aussage >> Der Encoder wird mit max 50u/s angetrieben, ein Timer, der >> das Counterregister ausließt hat eine Periodendauer von 6ms. >> Das bedeutet pro Timerintervall können max 6000 Counts entstanden >> sein. > Die ist der Schlüssel zur Lösung des Gordischen Knotens. Das hab' ich so festgelegt, sonst käme mir auch der Herr Shannon in die Quere ;) Karl Heinz Buchegger schrieb: > Das Problem ist, dass du dich von den Zahlenwerten hast täuschen lassen. > Eine Differenz errechnet sich immer aus Ende minus Anfang. Immer! > > 1k - 15k > > und da kommt ganz sicher nicht -4k raus. Schon eher -14k. UNd weil es > sich um unsigned Arithmetik handelt, kann das nicht negativ sein, > sondern muss mit +20k beaufchlagt werden um wieder im erlaubten Bereich > 0 bis 20k zu sein. Oh man. Damit muss ich meine Aussage von oben revidieren, hatte noch nicht klick gemacht beim Sägezahn ;) Habe in der Tat die falschen Werte verwendet. Statt 15k nämlich 5k, was die Differenz von 15k zu 20k ist. Dankeschön
Datum:
stm32 schrieb: > verschachtelte If-Konstruktion ist bestimmt länger. Programmiers aus. Das hört sich jetzt nur kompliziert an. Im Code ist das dann viel einfacher.
Datum:
So, heute nochmal drüber geguckt. Fand' die Interrupt Lösung eigentlich cool, aber habe dann festgestellt, dass sich mei einem Ripple in 0° das übliche Problem ergibt. Daher also 6000 als Schwelle verwendet und läuft. Hab' ich übrigens vorher auch schon ausprobiert; Es lief nur nicht, weil ich Idiot den falschen Header für die abs() Funktion includiert habe. Jetzt läufts, besten Dank!
Datum:
Edit: Falscher Benutzername; wird Zeit sich anzumelden ;)
Datum:
> Ich möchte nun die absolute Anzahl der Counts anzeigen, dafür > benötige ich eine Überlauferkennung. Wenn ich mich jetzt gedanklich nicht zu sehr verfranst habe, dann ist das hier ....
....
diff = naechsterWert - vorigerWert;
if( diff < 0 )
diff += 20000;
if( diff < 10000 )
total += diff
else
total -= 20000 - diff;
vorigerWert = naechsterWert;
....
|
.... die komplette Aufsummierung der Tick Counts auf eine laufende
Summe.
Komplett ohne Interrupts oder auch nur die Anzahl der Overflows kennen
zu müssen. Ich sagte doch: Es erklärt sich nur schlecht, der Code selbst
ist ganz simpel.
Fall 1: Drehrichtung positiv, ohne Überlauf
vorigerWert sei 8000
naechsterWert sei 12000
-> also sollten 4000 Ticks addiert werden. Schaun ma mal
diff = naechsterWert - vorigerWert; +4000 (12 - 8)
if( diff < 0 ) nein
diff += 20000;
if( diff < 10000 ) Ja
total += diff 4000 addieren
else
total -= 20000 - diff;
|
*** Passt ***
Fall 2: Drehrichtung positiv, mit Überlauf
vorigerWert sei 18000
naechsterWert sei 2000
-> also sollten 4000 Ticks addiert werden. Schaun ma mal
diff = naechsterWert - vorigerWert; -16000 (2 - 18)
if( diff < 0 ) ja
diff += 20000; 4000
if( diff < 10000 ) Ja
total += diff 4000 addieren
else
total -= 20000 - diff;
|
*** Passt ***
Fall 3: Drehrichtung negativ, ohne Unterlauf
vorigerWert sei 12000
naechsterWert sei 8000
-> also sollten 4000 Ticks subtrahiert werden. Schaun ma mal
diff = naechsterWert - vorigerWert; -4000 (8 - 12)
if( diff < 0 ) ja
diff += 20000; 16000
if( diff < 10000 ) Nein
total += diff
else
total -= 20000 - diff; 4000 subtrahieren (20 - 16)
|
*** Passt ***
Fall 4: Drehrichtung negativ, mit Unterlauf
vorigerWert sei 2000
naechsterWert sei 18000
-> also sollten 4000 Ticks subtrahiert werden. Schaun ma mal
diff = naechsterWert - vorigerWert; +16000 (18 - 2)
if( diff < 0 ) Nein
diff += 20000;
if( diff < 10000 ) Nein
total += diff
else
total -= 20000 - diff; 4000 subtrahieren (20 - 16)
|
*** Passt ***
Datum:
Wow, so eine ausführliche Antwort hatte ich gar nicht mehr erwartet, ich hatte es folgendermaßen gelöst (oder hab' ich da was vergessen?):
if(abs(actualPositionCount - lastPositionCount) > sprungSchwelle) // überlauf erkannt,z.B.: 1.Wert=15k, 2.Wert=1k -> 1-15=-14. überlauf -> Oder: 1.=10k, 2.=16k -> 2.-1.=6k -> passt
{ // Am Sägezahn vorstellen, oder an Uhr, oder am Winkel
if (actualPositionCount > lastPositionCount) // 6000 kommt von 6ms Timer @ 3000rpm und 10k steps/u
{
actualPosition+=(actualPositionCount-lastPositionCount-20000); // echte Winkelposition aus Counter Value berechnen, underflow
}
else if (actualPositionCount < lastPositionCount)
{
actualPosition+=(actualPositionCount-lastPositionCount+20000); // overflow
}
}
else
actualPosition+=(actualPositionCount-lastPositionCount);
lastPositionCount = actualPositionCount;
|
Habe ich da Möglichkeiten nicht mit abgedeckt?
Datum:
pwm schrieb: > Habe ich da Möglichkeiten nicht mit abgedeckt? Probiers aus. Es gibt 4 Fälle, spiel sie durch (Oder schreib dir schnell am PC ein Programm, welches das für dich tut)