Drehinkrementalgeber |
FunktionsweiseFast alle Drehinkrementalgeber (auch Drehgeber, Drehimpulsgeber oder Encoder genannt) übermitteln Drehbewegungen mittels phasenverschobener Zustandsänderungen zweier Signale, A und B. Neben der Positionsänderung werden so auch Richtung und im weiteren Sinne sogar Geschwindigkeit nach Außen getragen. Das hört sich komplizierter an als es ist. Im Zeitdiagramm sieht das Ganze so aus:![]() Einmal formal ...Das Verhalten eines Drehinkrementalgeber lässt sich formal in Form eines einfachen Mealy-Automaten beschreiben:![]() M besteht aus 5 Elementen:
![]() Los
geht's im Zustand S0. Eine Drehbewegung nach rechts
bewirkt eine
Zustandsänderung via S2, S3,
S1 usw. Bei entgegengesetzter Bewegung
ist die Reihenfolge entsprechend umgekehrt. Zwecks besserer Nachvollziehbarkeit wurden im
Diagramm die Übergänge zwischen S0/S3
bzw. S1/S2 weggelassen.
Sie sind für die in der Theorie kontinuierlich ablaufenden
Automaten unerheblich, können jedoch im realen Umfeld durchaus auftreten. Eine gute Darstellung der Funktion ζ ist die Wertetabelle:
![]() Einmal real ...Die Abfrage des Drehinkrementalgeber gestaltet sich im Grunde ganz einfach. Hauptaufgabe dabei ist die Umsetzung der Zustandsübergangsfunktion ζ, bzw. ihrer o.g. Wertetabelle. Da sich hier die Folgezustände unmittelbar aus den Eingabewerten ableiten (ab → Sab), halbiert sich die Größe des 2D-Feldes auf 16 Werte. Trotzdem sollte auf Systemen mit Harvard-Architektur die Wertetablle natürlich im Programmspeicherbereich abgelegt sein. Ausgaben L, N und R sind durch die Werte -1, 0 und +1 vertreten.Wichtig ist, dass die Software möglichst jede Änderung des AB-Signals und damit jede Drehbewegung mitbekommt. Um diese Echtzeitanforderung erfüllen zu können, sollte der folgende Programmteil innerhalb eines Zeitinterrupts abgearbeitet werden. Wenn man das menschliche "Drehvermögen" als Grundlage nimmt, reichen IRQ-Aufrufe im Intervall von 1ms aus. Hier nun der Beispielcode in C: static const SInt08
zeta[][4] = { { 0, -1, +1, 0 },
{ +1, 0, 0, -1 }, { -1, 0, 0, +1 }, { 0, +1, -1, 0 } }; static const UInt08 encRaster = 2; // Rasterstopps: 1,2 oder 4 static UInt08 encState = 0; // Aktueller Zustand static SInt08 encDelta = 0; // Positionsveränderung SInt08 encAB // Eingabe aus A und B encAB = (!GetPin(ENC_A) << 1) + !GetPin(ENC_B); encDelta += zeta[encState][encAB]; encState = encAB; if( encDelta == encRaster || encDelta == -encRaster ) { encDelta > 0 ? encPosition++ : encPosition--; encDelta = 0; } Die Signale A und B werden durch die Pins ENC_A und ENC_B eingelesen. Da die Pegel häufig "low-active" sind, werden beide vor der Zusammenstellung des Eingabewertes encAB invertiert. Unterschiede gibt es bei den Haltepunkten. Manche Inkrementgeber vollziehen 4 Zustandswechsel, bevor sie in der Folgeposition einrasten, andere kommen mit der halben Phase aus. Theoretisch würde bereits ein einzelner Wechsel ausreichen um eine Positionsänderungen festzustellen, jedoch wären Fehler durch Prellen und "flatternde" Signale deutlich häufiger. Die Rastereinteilung ist in der Konstanten encRaster festgelegt. Erreicht die Anzahl Signalwechsel (der gleichen Richtung) den Wert in encRaster, hat das eine Veränderung des Wertes in encPosition um ±1 zur Folge. Den Wert in encPosition kann man nun asynchron, z.B. im Bereich der Applikations-Hauptschleife, abfragen: SInt08
GetRotEntPos(void)
{ SInt08 value = 0; Atomic { value = encPosition; encPosition = 0; } return value; } Dabei sollte sich der Aufrufer nicht zu viel Zeit lassen. encPosition hat mit seinen 8 Bits einen Wertebereich von -128 bis +127. Wird dieser aufgrund zu langsamer Abfrage über- bzw. unterschritten, ist der Wert des Drehgebers verloren. Grob gesagt: Mit einer 2er Rasterung ist man mit fünfmal pro Sekunde auf jeden Fall auf der sicheren Seite. Jetzt gibt es eine gute und eine schlecht Nachricht. Die Schlechte ist: Es gibt Inkrementalgeber, die haben ihren Rasterpunkt genau an der Stelle liegen, wo auch ein Signalwechsel stattfindet. Das hat zur Folge, dass der Wechsel von einer Rasterposition zur Nächsten mal über 3, mal über 4 Signalwechsel geht. Je nach Bauart kann es also sein, dass AB z.B. 00→10→11→01→00 durchlaufen (4 Wechsel) oder eben dass AB kurz vor dem letzten Wechsel bei 01 verbleiben. Man kann sich also bei dieser Sorte Drehgebern nicht darauf verlassen, immer wieder in 00 einzurasten. Die gute Nachricht ist aber, dass man solches Verhalten ebenso mit dem oben gezeigten Automaten abbilden kann. Dazu ist lediglich eine Anpassung von ζ nötig. Genauer gesagt reicht es, die Wertetabelle ein wenig auszudünnen. Ist beispielsweise Signal B der "Wackelkandidat", sollten alle Zustandswechsel, die das Signal B betreffen, neutralisiert werden. Im Automaten bedeutet das, dass alle Wechsel zwischen S0/S1 und S2/S3 neutralisiert werden (N): ![]() static const SInt08
zeta[][4] = { { 0, 0, +1, 0 }, { 0, 0, 0, -1 }, { -1, 0, 0, 0 }, { 0, +1, 0, 0 } }; Weiterführende Informationen zum Thema Inkrementalgebern findet man jede Menge auf dem Netz. |
© 2013 Reimar Grasbon ![]() |