(→Auslegen der Lochscheibe) |
(→Messen der Drehzahl durch zählen der Impulse) |
||
(35 dazwischenliegende Versionen von 4 Benutzern werden nicht angezeigt) | |||
Zeile 4: | Zeile 4: | ||
− | + | Ermitteln der Drehzahl und Wegstrecke in Abhängigkeit einer Winkeländerung oder Impulsfolge in einer Abgelaufenen Zeit | |
− | * Messen der Drehzahl nach jedem Impuls, also in Abhängigkeit einer | + | * Messen der Drehzahl nach jedem Impuls, also in Abhängigkeit einer Winkeländerung. |
− | * Messen der Drehzahl durch | + | * Messen der Drehzahl durch Zählen der Impulse nach Ablauf einer bestimmten Zeit. |
+ | * Richtung, Geschwindigkeit und Position mit Doppellichtschranke ermitteln | ||
{{Ausbauwunsch|Mehr Grundlagen und vor allem mal praktische Programmbeispiele / Algorithmen etc.}} | {{Ausbauwunsch|Mehr Grundlagen und vor allem mal praktische Programmbeispiele / Algorithmen etc.}} | ||
= Messen der Drehzahl nach jedem Impuls = | = Messen der Drehzahl nach jedem Impuls = | ||
− | Dieser Teil beschäftigt sich mit der Optischen Drehzahlmessung mit Hilfe einer Lochscheibe und [[Gabellichtschranke]] berechnet über die Periodendauer ohne Drehrichtungserkennung. | + | Dieser Teil beschäftigt sich vor allem mit der Optischen Drehzahlmessung mit Hilfe einer Lochscheibe und [[Gabellichtschranke]] berechnet über die Periodendauer ohne Drehrichtungserkennung. |
[[Bild:GP1S23 Testaufbau.JPG|thumb| Testaufbau mit einer 32er Lochscheibe ]] | [[Bild:GP1S23 Testaufbau.JPG|thumb| Testaufbau mit einer 32er Lochscheibe ]] | ||
[[Bild:183015_LB_00_FB.EPS_250.jpg|thumb|GP1S23 Gabellichtschranke Bild: Conrad Electronic ]] | [[Bild:183015_LB_00_FB.EPS_250.jpg|thumb|GP1S23 Gabellichtschranke Bild: Conrad Electronic ]] | ||
Zeile 17: | Zeile 18: | ||
== Einführung == | == Einführung == | ||
+ | |||
+ | Am einfachsten ist Impulse direkt an einer Bürste eines Motors zu zählen. Siehe dazu: http://www.roboternetz.de/community/...einem-DC-Motor . | ||
Die [http://de.wikipedia.org/wiki/Winkelgeschwindigkeit Winkelgeschwindigkeit] ist die Winkeländerung pro Zeiteinheit. Mit der Lichtschranke und den geometrischen Daten der Lochscheibe kann man nun relativ einfach die Zeit für eine bestimmte Winkeländerung messen. | Die [http://de.wikipedia.org/wiki/Winkelgeschwindigkeit Winkelgeschwindigkeit] ist die Winkeländerung pro Zeiteinheit. Mit der Lichtschranke und den geometrischen Daten der Lochscheibe kann man nun relativ einfach die Zeit für eine bestimmte Winkeländerung messen. | ||
Zeile 30: | Zeile 33: | ||
== Auslegen der Lochscheibe == | == Auslegen der Lochscheibe == | ||
− | In den meisten | + | In den meisten Fällen definieren der mechanische Aufbau den Durchmesser der Lochscheibe und die Drehzahl die Teilung (Anzahl der Löcher). Der µContoller und die Gabellichtschranke müssen die Impulse auch erfassen und verarbeiten können. Wenn man das Drehzahlband abschätzen kann ist es hilfreich, sich schon Gedanken um die Programmierung zu machen, denn bei hohen Drehzahlen springt der µC jedes mal in die Interrupt Service Routine rein, sofern man es so programmiert wie im Beispiel. Bei hohen Drehzahlen sollte die Teilung somit gröber, bei niedriger Drehzahl die Teilung feiner sein. |
[[Bild:Drehscheibe20mm.png|400px|thumb|left|Lochscheibe abgerollt mit idealisiertem Signal ]] | [[Bild:Drehscheibe20mm.png|400px|thumb|left|Lochscheibe abgerollt mit idealisiertem Signal ]] | ||
Zeile 38: | Zeile 41: | ||
Hier folgt nun die Berechnung über die Periodendauer, beachten sollte man das im [http://de.wikipedia.org/wiki/Bogenma%C3%9F Bogenmaß] gerechnet wird, ein Winkel mit dem Bogenmaß 1 rad hat ein Gradmaß von ca. 57,3°. 11.25° sind also ca. 0,196 rad, das führt später natürlich zu unschönen Rechenoperationen im µC, Stichwort [http://www.mikrocontroller.net/articles/Festkommaarithmetik Festkommaarithmetik]. | Hier folgt nun die Berechnung über die Periodendauer, beachten sollte man das im [http://de.wikipedia.org/wiki/Bogenma%C3%9F Bogenmaß] gerechnet wird, ein Winkel mit dem Bogenmaß 1 rad hat ein Gradmaß von ca. 57,3°. 11.25° sind also ca. 0,196 rad, das führt später natürlich zu unschönen Rechenoperationen im µC, Stichwort [http://www.mikrocontroller.net/articles/Festkommaarithmetik Festkommaarithmetik]. | ||
− | Nach dem | + | Nach dem Umstellen kommt man aber auf eine recht handliche Formel <math>n = \frac{\varphi }{dt \cdot 360}</math> |
− | Es ist auch eine Überlegung wert ob man die Drehzahl nicht umrechnet sondern mit der Periodendauer arbeitet | + | Es ist auch eine Überlegung wert, ob man die Drehzahl nicht umrechnet sondern mit der Periodendauer arbeitet. Das ist zwar nicht so geläufig aber das stört den µController nicht. Mit einem Kalkulationsprogramm kann man die Umrechnung von Periodendauer in Drehzahl auch extern vornehmen. |
+ | Man sollte sich auch klar machen, das zumindest ein 8-Bit Prozessor am besten mit '''Ganzzahlen''' zwischen 0 und 255 oder 0 und 65535 zurechtkommt. Für die Teilung der Lochscheibe bieten sich deshalb Werte wie 90, 72, 45, 36, 30, 24, 20, 18, 15, 12, 10 und 8 an. Verwendet man an Stelle der dargestellten 32er Lochscheibe eine 30er oder 36er Scheibe, kann man zumindest mit ganzzahligen Gradzahlen rechnen. "Krumme Werte" wie [http://de.wikipedia.org/wiki/Kreiszahl Pi = 3,1415...], [http://de.wikipedia.org/wiki/Radiant_%28Einheit%29 Radiant = 57,29577...°] usw. sollten eine seltene Ausnahme in der Programmierung sein. | ||
+ | = Messen der Drehzahl durch zählen der Impulse = | ||
+ | Dieser Teil beschäftigt sich mit der Optischen Drehzahlmessung mit Hilfe einer Lochscheibe und [[Gabellichtschranke]] berechnet über die die Anzahl der Impulse in einer gewissen Zeit. | ||
+ | Die meisten µC bieten die Möglichkeit über einen Eingang direkt mit der Hardware externe Pulse zu zählen (z.B. beim AVR der Eingang T1). Über eine vorgegeben Zeit von z.B. 1 Sekunde wird über den externen Eingang die Zahl der Pulse gezählt. Die Drehzahl ergibt sich dann einfach auch der Zahl der Impulse geteilt durch die Zahl der Löcher in der Scheibe und die Zeit für die Messung. Da die Zahl der Löcher und die Zeit konstant sind, erhält man direkt einen Wert proportional zur Drehzahl. Auch ist bei geeigneter Hardware die Belastung für die CPU gering, es werden aber i.A. 2 Timer benötigt: der eine für das Zählen der Impulse und der andere für die Festlegung des Zeitintervalls. Das Zeitintervall muss als Kompromiss zwischen Aktualisierungsfrequenz und Auflösung gewählt werden: mit einer Scheibe mit 32 Löchern erhält man in einer Sekunde ein Auflösung von 1/32 Umdrehungen pro Sekunde oder bei 1/32 Sekunde nur noch 1 Umdrehung pro Sekunde als Auflösung. Geeignet ist diese Methode vor allem für schnell kommende Pulse, also hohe Drehzahlen bzw. Lochscheiben mit vielen Löchern, da so in der Messzeit genügend Pulse für eine ausreichende Auflösung kommen. | ||
+ | = Richtung, Geschwindigkeit und Position mit Doppellichtschranke ermitteln = | ||
+ | Dieser Teil beschäftigt sich mit der Optischen Drehzahl- und Geschwindigkeitsmessung sowie der Erfassung von Drehrichtung und zurückgelegter Position mit Hilfe einer Lochscheibe und 2 Gabellichtschranken. Hierfür werden Quadratursignale in definierten Zeitabständen ausgewertet. | ||
+ | |||
+ | == Einführung == | ||
− | + | Für kontrollierte Bewegungen ist es mitunter wichtig, auch die Drehrichtung/Richtungswechsel und Position auszuwerten. Eine Lochscheibe mit einer Gabellichtschranke liefert lediglich Rechteckimpulse, egal wie rum sich die Lochscheibe bewegt. Bringt man eine zweite Gabellichtschranke an der gleichen Lochscheibe leicht versetzt an, bekommt man auch die Drehrichtung mit. Diese Methode ist altbekannt, simpel und leicht nachzubauen. Wenn man die Drehrichtung kennt, ist auch die Position kein Problem mehr. Ausgehend von einer Kalibrierposition können bei Vorwärtsbewegung Inkremente hochgezählt oder bei Rückwärtsbewegung runtergezählt werden. | |
− | + | Interessierte nehmen dazu mal eine PC-Maus mit Kugelantrieb zur Hand. Darin findet man zwei kleine Lochscheiben, die für die X- und Y-Richtung die Impulse erzeugen. Durch spezielle Gabellichtschranken mit 2 phasenversetzten Ausgängen wird auch die Drehrichtung erkannt. | |
− | == | + | Das selbe Prinzip ist in linearer Form auch in PC-Druckern zu finden: Entlang des Wagenrücklaufes ist ein transparentes Kunsstoffband gespannt, auf dem winzig kleine Streifenmuster aufgebracht sind. Diese werden von einer Gabellichtschranke mit 2 Ausgängen erkannt und so die Wagenposition gesteuert. |
+ | |||
+ | Aber es geht natürlich noch einfacher... | ||
+ | |||
+ | == Zwei Lichtschranken liefern vier Zustände == | ||
+ | |||
+ | [[Bild:vorwaerts_.jpg|thumb|Zustandsfolge bei Vorwärtsbewegung]] | ||
+ | [[Bild:rueckwaerts_.jpg|thumb|Zustandsfolge bei Rückwärtsbewegung]] | ||
+ | [[Bild:2LSZustand.jpg|thumb|2 Lichtschranken (LSA und LSB) liefern phasenversetzte Rechtecksignale. In Vorwärts- und Rückwärtsrichtung ergeben sich unterschiedliche Zustandsfolgen]] | ||
+ | |||
+ | Man nimmt 2 normale Gabellichtschranken und bringt sie so an, das sie im 1,5 fachen Lochabstand die Lochscheibe durchleuchten. Wenn sich Lichtschranke A in der Mitte des Lichtstreifens befindet, ist Lichtschranke B an der Grenze des Schattenstreifens. Nebenstehende Skizzen zeigen die möglichen Zustände beider Lichtschranken bei Vorwärts- und Rückwärtsbewegung der Lochscheibe. Wichtig ist hierbei, das die Lochscheibe in etwa gleich breite Licht- und Schattensegmente eingeteilt ist und die Lichtschranke(n) einen möglichst haarfeinen Lichtstrahl besitzt. Die Signale der Fototransistoren sollten verstärkt und gegebenenfalls mit TTL-Bausteinen zu korrekten High- und Low-Pegeln aufbereitet werden. | ||
+ | |||
+ | |||
+ | Es ergeben sich nun folgende Kombinationen: | ||
+ | |||
+ | * Zustand 1: LSA = hell und LSB = hell | ||
+ | * Zustand 2: LSA = hell und LSB = dunkel | ||
+ | * Zustand 3: LSA = dunkel und LSB = dunkel | ||
+ | * Zustand 4: LSA = dunkel und LSB = hell | ||
+ | |||
+ | Dreht man die Lochscheibe weiter, wiederholt sich der Vorgang. Die Zustandsfolge ist 1 > 2 > 3 > 4 > 1 > 2 > 3 > 4 > usw. | ||
+ | |||
+ | |||
+ | |||
+ | Bei entgegengesetzter Drehrichtung ändert sich diese Reihenfolge. Betrachtet man wieder vom Zustand 1 ausgehend die Gegenrichtung, ergeben sich nun diese Kombinationen: | ||
+ | |||
+ | * Zustand 1: LSA = hell und LSB = hell | ||
+ | * Zustand 4: LSA = dunkel und LSB = hell | ||
+ | * Zustand 3: LSA = dunkel und LSB = dunkel | ||
+ | * Zustand 2: LSA = hell und LSB = dunkel | ||
+ | |||
+ | Die Zustandsfolge in Gegenrichtung lautet dann: 1 < 4 < 3 < 2 < 1 < 4 < 3 < 2 < usw. | ||
+ | |||
+ | |||
+ | Mit diesem Wissen ist es nun ein Kinderspiel, auch die Änderung der Drehrichtung festzustellen. Dazu muss der letzte Zustand in einer Variable gespeichert und mit dem neu erkannten Zustand verglichen werden. Folgt nach Zustand 1 der Zustand 2, so ist es eine Vorwärtsbewegung. Folgt dem Zustand 1 der Zustand 4, so ist es eine Rückwärtsbewegung. Gleiches Prinzip gilt auch für die restlichen Zustände 2, 3 und 4. | ||
+ | |||
+ | == Positionsüberwachung == | ||
+ | |||
+ | Von jedem der 4 Zustände gibt es also zwei zu unterscheidende Fälle: Vorwärts und Rückwärts. Insgesamt müssen demzufolge 8 Bedingungen zyklisch abgetastet und ein Positionszähler entsprechend inkrementiert oder dekrementiert werden und schon hat man eine exakte Streckeninformation. In Worte gefasst ergibt sich folgende Logik: | ||
+ | |||
+ | Ausgangszustand: Beide Lichtschranken sind aus (A=0 UND B=0) und Zustand =1 | ||
+ | |||
+ | * WENN (Zustand=1 UND A=0 UND B=1) DANN: Setze Zustand=2, Position inkrementieren, Vor | ||
+ | * WENN (Zustand=1 UND A=1 UND B=0) DANN: Setze Zustand=4, Position dekrementieren, Rück | ||
+ | * WENN (Zustand=2 UND A=1 UND B=1) DANN: Setze Zustand=3, Position inkrementieren, Vor | ||
+ | * WENN (Zustand=2 UND A=0 UND B=0) DANN: Setze Zustand=1, Position dekrementieren, Rück | ||
+ | * WENN (Zustand=3 UND A=1 UND B=0) DANN: Setze Zustand=4, Position inkrementieren, Vor | ||
+ | * WENN (Zustand=3 UND A=0 UND B=1) DANN: Setze Zustand=2, Position dekrementieren, Rück | ||
+ | * WENN (Zustand=4 UND A=0 UND B=0) DANN: Setze Zustand=1, Position inkrementieren, Vor | ||
+ | * WENN (Zustand=4 UND A=1 UND B=1) DANN: Setze Zustand=3, Position dekrementieren, Rück | ||
+ | [[Bild:Lochscheibe8.jpg|thumb|Lochscheibe 8 ]] | ||
+ | [[Bild:Lochscheibe10.jpg|thumb|Lochscheibe 10 ]] | ||
+ | [[Bild:Lochscheibe12.jpg|thumb|Lochscheibe 12 ]] | ||
+ | [[Bild:Lochscheibe15.jpg|thumb|Lochscheibe 15 ]] | ||
+ | [[Bild:Lochscheibe18.jpg|thumb|Lochscheibe 18 ]] | ||
+ | [[Bild:Lochscheibe20.jpg|thumb|Lochscheibe 20 ]] | ||
+ | |||
+ | |||
+ | Diese Prüfung muss ständig wiederholt werden, damit alle Pegelwechsel der beiden Lichtschranken erfasst werden. Nur so ist es möglich, die exakte Position zu verfolgen. Dafür bieten sich 2 Möglichkeiten: Entweder die Prüfung wird im Hauptprogramm ständig durchlaufen bzw. ein Timer-Interrupt tastet regelmäßig die Lichtschranken ab oder ein Interrupt reagiert auf eine Änderung der Leichtschranken und die Auswertung erfolgt nach jeder Änderung. Die Art der Auswertung kann in allen Fällen gleich sein - lediglich wann und wie oft sie aufgerufen wird ist verschieden. Hier soll nur die Interruptvariante betrachtet werden, weil sie mehr Vorteile bringt. Weiter unten im Artikel ist dazu ein Beispiel in Sprache C zu finden. | ||
+ | |||
+ | Zuvor muss aber eine sinnvolle Auslegung von Lochscheibe, Drehzahl und Positionsbereich gefunden und in Einklang mit den Ressourcen des verwendeten µControlles gebracht werden. Dazu folgende Betrachtungen: | ||
+ | |||
+ | Wenn 2 phasenversetzte Lichtschranken je Hell-/ Dunkelzyklus bereits 4 Positionen liefern, benötigt die Lochscheibe nur halb so viel "Löcher" wie eine Lochscheibe bei Verwendung nur einer Lichtschranke. Eine 15er Lochscheibe liefert demzufolge 15x4 = 60 Positionen auf 360°, das sind 6° je erfasster Position. Entscheidend ist, an welchem Antriebsteil die Lochscheibe montiert ist und mit welcher Untersetzung zwischen Motor und Abtriebswelle(Rad) gearbeitet wird. Ist die Lochscheibe an der Motorwelle angebracht, würde bei einer angenommenen Untersetzung von 10:1 eine erfasste Position nur 0,6° an der Abtriebswelle ausmachen. | ||
+ | |||
+ | Man muss sich klar machen, welche '''Positioniergenauigkeit''' nötig ist. Dabei gilt: Auslegung so genau wie nötig, nicht wie möglich. Weiter muss geklärt werden, wo man die Lochscheibe sinnvoll anbringt. Sie darf im Betrieb weder verschmutzt oder beschädigt werden. Fahrmodelle ziehen Staub, Haare etc. gern an, gut beraten ist man mit einer '''verkapselten Optomechanik'''. Ein weiterer Faktor ist die '''Drehzahl''' (im Leerlauf am höchsten) des Motors, weil diese die Frequenz der abzutastenden Signale beeinflusst. Zwischen Drehzahl n [U/min], Frequenz f [Hz] und Teilung T besteht folgender Zusammenhang: | ||
+ | |||
+ | '''f = n * T / 60 s''' | ||
+ | |||
+ | Beispiel: Ein Motor dreht im Leerlauf mit 2370 U/min und hat eine Lochscheibe mit Teilung = 12 an der Motorwelle. Die Frequenz der abzutastenden Signale einer Lichtschranke soll ermittelt werden. (oben im Osszillogramm dargestellt) | ||
+ | |||
+ | '''f = 2370 * 12 / 60 s''' | ||
+ | |||
+ | '''f = 474 Hz''' | ||
+ | |||
+ | Eine Lichtschranke liefert also ein Rechtecksignal mit f = 474 Hz. Jetzt muss noch das Signal der zweiten Lichtschranke um 90° versetzt darübergelegt werden. Bei idealen Pegeln sind in einer Periode 4 Schaltzustände abzutasten, also muss die Abtastfrequenz mindestens 4-fach über der Grundfrequenz liegen. Da es in der Praxis aber keine idealen Pegel gibt, muss die Abtastfrequenz noch höher ausgelegt werden. Betrachten wir noch mal das Oszillogrammm weiter oben: | ||
+ | |||
+ | Es fällt auf, das die Zeiten nicht exakt gleich sind, die Zustandszeiten 1 und 3 sind etwas länger als 2 und 4. Das liegt an der Einstellung des Abstandes beider Lichtschranken zueinander, die Phasenlage ist hier nicht genau 90°. Außerdem sind Lochscheibe und Lichtschranken mit kleinen Unregelmäßikeiten, Streuungen, Anstiegs- und Abfallzeiten behaftet, so dass es in einer Periode auch Zeiten gibt, die nicht eindeutig einem der 4 genannten Zustände entsprechen. Für eine sichere Abtastung ist deshalb von der kürzesten (= ungünstigsten) Schaltzeit auszugehen, hier sind es ca. 0,4 Millisekunden, das entspricht 2,5 kHz. Jeder Zustand sollte vom µController sicherheitshalber schon 3 bis 4 mal abgetastet werden, so das wir für das Beispiel mindestens ca. 10 kHz Abtastfrequenz einplanen müssen. Als Orientierungshilfe gilt: | ||
+ | |||
+ | '''Abtastfrequenz >= 20 * Frequenz Lichtschranke''' | ||
+ | |||
+ | Entsprechend der gewünschten Positioniergenauigkeit und Drehzahl kann nun die Teilung der Lochscheibe so gewählt werden, das die Lichtschrankensignale vom µController abgetastet werden können. Da Kaufteile aus dem Industriebereich oft eine recht hohe Teilung vorgeben, ist es manchmal besser, mit kleineren Teilungen anzufangen. Rechts sind Vorlagen, die man sich auf Folien ausdrucken kann.(Nähere Beschreibung im Praxis-Teil) | ||
+ | |||
+ | Die Abtastung muss sicher sein, auch wenn das Hauptprogramm gerade mit anderen Dingen als der Lochscheibenauswertung beschäftigt ist. Man kann zwar die Lochscheibe vom Hauptprogramm durchaus mit abfragen lassen, aber dann sollten keine anderen zeitraubenden Prozeduren darin enthalten sein. Ist nur ein Zustandswechsel übersehen und ausgelassen wurden, geht es erst an der nachfolgenden gleichen Hell-/Dunkel-Kombination weiter und der Contoller verzählt sich um 4 Inkremente! Deshalb sollte die TimerInterrupt-Variante vorgezogen oder die Abtastung in einen separaten µController ausgelagert werden. | ||
+ | |||
+ | Der Positionsbereich muss schließlich auch in einer Variablen dargestellt werden. Im Beispiel mit Teilung =12 wird der Positionzähler bei einer Motorumdrehung um 48 Inkremente hochgezählt. Bei 2370 U/min wäre eine 16Bit-Variable nach ca. 34 Sekunden übergelaufen. Demzufolge ist auch das Speichervolumen der Positionsvariablen dem tatsächlichen Fahrbereich anzupassen. Man kann auch Ober-/ Untergrenzen definieren, die bei Erreichen den Antrieb anhalten. Somit wird ein mechanisches Überfahren von Endlagen oder ein logisches Überlaufen von Variablen verhindert. | ||
+ | |||
+ | |||
+ | '''Zusammenfassung:''' | ||
+ | {| {{Blauetabelle}} | ||
+ | | | ||
+ | # Welche Positionsgenauigkeit brauch ich? | ||
+ | # Sind Lochscheibe und Optik vor Störeinflüssen geschützt? | ||
+ | # Welche maximale Drehzahl muss noch sicher abgetastet werden? | ||
+ | # Frequenz Lichtschranke anpassen: Hohe Drehzahl mit kleiner Teilung / geringe Drehzahl mit großer Teilung | ||
+ | # Phasenlage richtig eingestellt? Optimal sind 90° | ||
+ | # Positionsvariable mit genügend Speichervolumen? | ||
+ | |} | ||
+ | |||
+ | == Kalibrierung == | ||
+ | |||
+ | Im einfachsten Fall fährt man seinem Antrieb auf eine Referenzmarke (Nonius, Paßstift o.ä.) und setzt dort den Positionszähler zurück. | ||
+ | |||
+ | Wer es noch genauer will, muß auch noch die Lochscheibe in eine definierte Ausgangsstellung bringen. Dazu kann man die Lichtschrankensignale mit 2 LEDs optisch anzeigen. In der Kalibrierstellung müssen dann der Antrieb auf der Refernzmarke stehen und beide LEDs leuchten. Als Referenzmarke kann natürlich auch eine zusätzliche Lichtschranke dienen, die eine kleine Bohrung am Antrieb erkennt. Wichtig ist, dass die Referenzmarke nur einmal und eindeutig am Antrieb angebracht ist. | ||
+ | |||
+ | == Geschwindigkeit und Beschleunigung == | ||
+ | |||
+ | Geschwindigkeit wird meist in [m/s], [km/h] oder [mph] ausgedrückt, also der Wegstrecke je Zeiteinheit. Im µController interessieren uns diese Einheiten erst mal nicht, hier werden Inkremente je Zeiteinheit gezählt. Die Zeitintervalle, in denen die Inkremente ausgewertet werden, liefert wieder ein TimerInterrupt. Dieser ist mit deutlich längeren Zyklen auszulegen, damit auch genügend Inkremente je Zyklus gezählt werden können. Im Code-Beispiel unten werden bei 16Mhz CPU-Takt die Vorteiler 1 und 1024 für die TimerInterrupt´s verwendet: Timer 0 mit Prescaler =1024 für die Geschwindigkeitsberechnung mit ca. 61 Hz und Timer 2 mit Prescaler =1 für die Abtastung der Lichtschranken mit 62,5 kHz. Die Geschwindigkeitsmessung wurde mit 12er, 15er und 18er Teilung getestet. In der ISR des Timer_0 Overflow wird die Differenz aus aktueller Position und der Position des vergangenen Zyklus gebildet. Da diese Wegdifferenz in definierten Zeitabständen ermittelt wird, hat man hier bereits die Geschwindigkeit in n Inkremente je 0,01638 Sekunden. Mit dieser etwas abstrakten Geschwindigkeitseinheit wird im Hauptprogramm der Motor gesteuert. | ||
+ | |||
+ | Das gleiche Verfahren ist auch für die Beschleunigung anwendbar. Die Beschleunigung ist die Geschwindigkeitsänderung je Zeiteinheit. In der ISR des Timer_0 Overflow kann die Differenz aus aktueller Geschwindigkeit und der Geschwindigkeit des vergangenen Zyklus gebildet werden, um so die Beschleunigung zu erhalten. Die Einheit ist wieder etwas ungewohnt: Inkremente je 0,01638 Sekunden in 0,01638 Sekunden, also Inkremente/Quadratsekunden. Voraussetzung für eine vernünftige Beschleunigungsermittlung ist, das eine genügend hohe Auflösung der Geschwindigkeit vorliegt(=hohe Teilung der Lochscheibe). Ansonsten sind die ermittelten Werte zu klein und liegen, je nach Trägheit des Motors, fast immer bei 0, 1, 2 oder maximal 3. | ||
+ | |||
+ | Vorteil der Differenzmethode ist, man kann die Geschwindigkeit in einer 8Bit-Variable mit Vorzeichen ausdrücken. Die Werte des Beispieles lagen je nach Teilung zwischen -50 und +50 und sind für die Motorsteuerung ausreichend. Bessere Auflösung erfordert höhere Teilung, höhere Abtastrate, höhere CPU-Frequenz. | ||
+ | |||
+ | == Praxis== | ||
+ | |||
+ | === Herstellung der Lochscheibe === | ||
+ | Für eigene Projekte ist es mitunter schwer, Lochscheiben in passender Größe und Teilung zu finden. Oft müssen dann Kompromisse in der Drehzahlsteuerung oder Positionierung gemacht werden, weil die vielleicht günstigere Teilung nicht zu beschaffen ist. | ||
+ | |||
+ | Hier wird deshalb ein Selbstbau von preiswerten Lochscheiben vorgestellt: Man trägt in einer Excel-Tabelle z.B. 18 mal die Zahl 20 ein und markiert diesen Zellbereich. Anschließend erstellt man mit dem Diagramm-Assistent ein Ring-Diagramm. Darin muss man nun jeden Datenpunkt einzeln formatieren und abwechslend die Farbe schwarz und weiß zuordnen. Markiert man die komplette Datenreihe, kann man unter 'Formatieren'>'Optionen' auch die Innenringgröße einstellen. Dieses Ring-Diagramm kann nun beliebig kopiert und vergößert oder verkleinert werden, auch die Datenreihe kann auf z.B. 24x15 oder 30x12 angepasst werden. So lassen sich auf einer A4-Seite einige Dutzend Lochscheiben in allen Größen und Teilungen herstellen. Das fertige Arbeitsblatt muss nun noch mit geeigneter Tinte auf Folie ausgedruckt werden. Den Drucker muss man möglichst auf satte Farbe und kräftgen Kontrast einstellen. Zum Schluß wird die ausgedruckte Folie mit A4- Laminierfolie verstärkt, wer kein Laminiergerät hat, geht in einen Copy-Shop o.ä. | ||
+ | |||
+ | Die so gewonnenen Lochscheiben werden nun ausgeschnitten und bei Bedarf mit einem Heißluftgerät noch etwas "nachgebacken", bevor sie im eigenen Projekt mit Kraftkleber auf ein kleines Rad aufgeklebt werden. Hierbei auf gute Zentrierung achten, damit die Lochscheibe möglichst rund läuft. Sekundenkleber ist deshalb ungeeignet, weil kaum Zeit für Korrektur und Einstellung bleibt. | ||
+ | |||
+ | === Anpassen der Lichtschranke === | ||
+ | |||
+ | Baustelle: | ||
+ | |||
+ | Fotos, Anregungen zum Nachbau, Beschaffung, Erfahrungen | ||
+ | |||
+ | weiterführende Informationen: | ||
+ | [http://de.wikipedia.org/wiki/Inkrementalgeber Inkrementalgeber] | ||
+ | |||
+ | === Quellcode === | ||
+ | |||
+ | <pre> | ||
+ | |||
+ | //Deklaration global | ||
+ | volatile uint8_t Zust_Li; //Zustandsmerker Position linker Motor | ||
+ | volatile uint16_t Li_Inkr; //aktuelle Position linker Motor | ||
+ | volatile uint16_t old_Li_Inkr; //Position im vorangegangenen Takt | ||
+ | volatile int8_t Speed_Li_Ist; //Wegänderung je Takt, in ISR Timer 0 | ||
+ | |||
+ | ... | ||
+ | |||
+ | // Interrupt-Service-Routine Timer_0 Overflow | ||
+ | SIGNAL (SIG_OVERFLOW0) | ||
+ | { | ||
+ | // ISR-Code 61,035 Pro Sekunde | ||
+ | Timeout++; | ||
+ | Speed_Li_Ist = Li_Inkr - old_Li_Inkr; | ||
+ | old_Li_Inkr = Li_Inkr; | ||
+ | } | ||
+ | |||
+ | |||
+ | // Interrupt-Service-Routine Timer_2 Overflow | ||
+ | SIGNAL (SIG_OVERFLOW2) | ||
+ | { | ||
+ | // ISR-Code 62.5 kHz | ||
+ | // 4 Zustaende durch jeweils 1 Bit repräsentiert (1,2,4,8) | ||
+ | // Lichtschranke A liegt an Port A.0 | ||
+ | // Lichtschranke B liegt an Port A.1 | ||
+ | |||
+ | if ( (Zust_Li == 1) && ( !(PINA & (1<<PINA0)) )&& ( PINA & (1<<PINA1) ) ){ | ||
+ | Li_Inkr = Li_Inkr + 1; | ||
+ | Zust_Li = 2; | ||
+ | } /* end if */ | ||
+ | |||
+ | if ( (Zust_Li == 1) && (PINA & (1<<PINA0) )&& ( !( PINA & (1<<PINA1)) ) ){ | ||
+ | Li_Inkr = Li_Inkr - 1; | ||
+ | Zust_Li = 8; | ||
+ | } /* end if */ | ||
+ | |||
+ | if ( (Zust_Li == 2) && (PINA & (1<<PINA0) )&& ( PINA & (1<<PINA1) ) ){ | ||
+ | Li_Inkr = Li_Inkr + 1; | ||
+ | Zust_Li = 4; | ||
+ | } /* end if */ | ||
+ | |||
+ | if ( (Zust_Li == 2) && ( !(PINA & (1<<PINA0)) )&& ( !( PINA & (1<<PINA1)) ) ){ | ||
+ | Li_Inkr = Li_Inkr - 1; | ||
+ | Zust_Li = 1; | ||
+ | } /* end if */ | ||
+ | |||
+ | if ( (Zust_Li == 4) && (PINA & (1<<PINA0) )&& ( !( PINA & (1<<PINA1)) ) ){ | ||
+ | Li_Inkr = Li_Inkr + 1; | ||
+ | Zust_Li = 8; | ||
+ | } /* end if */ | ||
+ | |||
+ | if ( (Zust_Li == 4) && ( !(PINA & (1<<PINA0)) )&& ( PINA & (1<<PINA1) ) ){ | ||
+ | Li_Inkr = Li_Inkr - 1; | ||
+ | Zust_Li = 2; | ||
+ | } /* end if */ | ||
+ | |||
+ | if ( (Zust_Li == 8) && ( !(PINA & (1<<PINA0)) )&& ( !( PINA & (1<<PINA1)) ) ){ | ||
+ | Li_Inkr = Li_Inkr + 1; | ||
+ | Zust_Li = 1; | ||
+ | } /* end if */ | ||
+ | |||
+ | if ( (Zust_Li == 8) && (PINA & (1<<PINA0) )&& ( PINA & (1<<PINA1) ) ){ | ||
+ | Li_Inkr = Li_Inkr - 1; | ||
+ | Zust_Li = 4; | ||
+ | } /* end if */ | ||
+ | |||
+ | } | ||
+ | |||
+ | ... | ||
+ | |||
+ | int main (void) | ||
+ | { | ||
+ | |||
+ | //Init | ||
+ | TCCR2 |= (1<<CS20); //Prescaler = 1 (16MHz/1 = 16000000) -> | ||
+ | //16000000/256 -> 62500 Interrupts je Sekunde | ||
+ | |||
+ | TCCR0 |= (1<<CS02)|(1<<CS00); //Prescaler = 1024 (16000000 / 1024 = 15625) -> | ||
+ | //15625/256 = 61,035 -> 61 Interrupts je Sekunde | ||
+ | |||
+ | TIMSK |= (1<<TOIE0)|(1<<TOIE2); //Timer Overflow Interrupt Enablae für Timer 0 und 2 | ||
+ | |||
+ | |||
+ | Li_Inkr = 32000;Zust_Li = 1; // Kalibrierstellung bei 32000 | ||
+ | sei(); // Interrupts aktivieren | ||
+ | |||
+ | |||
+ | while(1) | ||
+ | { | ||
+ | |||
+ | // hier kann Position und Geschwindigkeit ausgewertet werden | ||
+ | } | ||
+ | } | ||
− | + | </pre> | |
= Vor und Nachteile der Messmethoden= | = Vor und Nachteile der Messmethoden= |
Aktuelle Version vom 29. Juni 2013, 22:51 Uhr
Ermitteln der Drehzahl und Wegstrecke in Abhängigkeit einer Winkeländerung oder Impulsfolge in einer Abgelaufenen Zeit
- Messen der Drehzahl nach jedem Impuls, also in Abhängigkeit einer Winkeländerung.
- Messen der Drehzahl durch Zählen der Impulse nach Ablauf einer bestimmten Zeit.
- Richtung, Geschwindigkeit und Position mit Doppellichtschranke ermitteln
Dieser Artikel ist noch lange nicht vollständig. Der Auto/Initiator hofft das sich weitere User am Ausbau des Artikels beteiligen.
Das Ergänzen ist also ausdrücklich gewünscht! Besonders folgende Dinge würden noch fehlen: Mehr Grundlagen und vor allem mal praktische Programmbeispiele / Algorithmen etc. |
Inhaltsverzeichnis
Messen der Drehzahl nach jedem Impuls
Dieser Teil beschäftigt sich vor allem mit der Optischen Drehzahlmessung mit Hilfe einer Lochscheibe und Gabellichtschranke berechnet über die Periodendauer ohne Drehrichtungserkennung.
Einführung
Am einfachsten ist Impulse direkt an einer Bürste eines Motors zu zählen. Siehe dazu: http://www.roboternetz.de/community/...einem-DC-Motor .
Die Winkelgeschwindigkeit ist die Winkeländerung pro Zeiteinheit. Mit der Lichtschranke und den geometrischen Daten der Lochscheibe kann man nun relativ einfach die Zeit für eine bestimmte Winkeländerung messen. Die Lochscheibe gibt uns die Winkeländerung bei einer Periode vor, bei einer 32er Lochscheibe wären das 11,25° pro Periode , wie in den Bildern vom Oszilloskop zu sehen ändert sich natürlich bei Änderung der Drehzahl die Periodendauer, die Winkeländerung pro Periode ist aber konstant da diese durch die Lochscheibe vor gegeben ist.
Um die Periodendauer zu messen verwende ich den ICP1 (Input Capture Pin) eines Atmega8 der bei steigender Flanke den Timer1 ausliest und in das ICR1 Register schreibt. Läuft der Mikrocontroller auf 8Mhz und wir stellen den Vorteiler des Timers auf 8 so bekommen wir die Periodendauer in µs als Wert.
Auslegen der Lochscheibe
In den meisten Fällen definieren der mechanische Aufbau den Durchmesser der Lochscheibe und die Drehzahl die Teilung (Anzahl der Löcher). Der µContoller und die Gabellichtschranke müssen die Impulse auch erfassen und verarbeiten können. Wenn man das Drehzahlband abschätzen kann ist es hilfreich, sich schon Gedanken um die Programmierung zu machen, denn bei hohen Drehzahlen springt der µC jedes mal in die Interrupt Service Routine rein, sofern man es so programmiert wie im Beispiel. Bei hohen Drehzahlen sollte die Teilung somit gröber, bei niedriger Drehzahl die Teilung feiner sein.
Berechnungen
Hier folgt nun die Berechnung über die Periodendauer, beachten sollte man das im Bogenmaß gerechnet wird, ein Winkel mit dem Bogenmaß 1 rad hat ein Gradmaß von ca. 57,3°. 11.25° sind also ca. 0,196 rad, das führt später natürlich zu unschönen Rechenoperationen im µC, Stichwort Festkommaarithmetik.
Nach dem Umstellen kommt man aber auf eine recht handliche Formel [math]n = \frac{\varphi }{dt \cdot 360}[/math]
Es ist auch eine Überlegung wert, ob man die Drehzahl nicht umrechnet sondern mit der Periodendauer arbeitet. Das ist zwar nicht so geläufig aber das stört den µController nicht. Mit einem Kalkulationsprogramm kann man die Umrechnung von Periodendauer in Drehzahl auch extern vornehmen.
Man sollte sich auch klar machen, das zumindest ein 8-Bit Prozessor am besten mit Ganzzahlen zwischen 0 und 255 oder 0 und 65535 zurechtkommt. Für die Teilung der Lochscheibe bieten sich deshalb Werte wie 90, 72, 45, 36, 30, 24, 20, 18, 15, 12, 10 und 8 an. Verwendet man an Stelle der dargestellten 32er Lochscheibe eine 30er oder 36er Scheibe, kann man zumindest mit ganzzahligen Gradzahlen rechnen. "Krumme Werte" wie Pi = 3,1415..., Radiant = 57,29577...° usw. sollten eine seltene Ausnahme in der Programmierung sein.
Messen der Drehzahl durch zählen der Impulse
Dieser Teil beschäftigt sich mit der Optischen Drehzahlmessung mit Hilfe einer Lochscheibe und Gabellichtschranke berechnet über die die Anzahl der Impulse in einer gewissen Zeit.
Die meisten µC bieten die Möglichkeit über einen Eingang direkt mit der Hardware externe Pulse zu zählen (z.B. beim AVR der Eingang T1). Über eine vorgegeben Zeit von z.B. 1 Sekunde wird über den externen Eingang die Zahl der Pulse gezählt. Die Drehzahl ergibt sich dann einfach auch der Zahl der Impulse geteilt durch die Zahl der Löcher in der Scheibe und die Zeit für die Messung. Da die Zahl der Löcher und die Zeit konstant sind, erhält man direkt einen Wert proportional zur Drehzahl. Auch ist bei geeigneter Hardware die Belastung für die CPU gering, es werden aber i.A. 2 Timer benötigt: der eine für das Zählen der Impulse und der andere für die Festlegung des Zeitintervalls. Das Zeitintervall muss als Kompromiss zwischen Aktualisierungsfrequenz und Auflösung gewählt werden: mit einer Scheibe mit 32 Löchern erhält man in einer Sekunde ein Auflösung von 1/32 Umdrehungen pro Sekunde oder bei 1/32 Sekunde nur noch 1 Umdrehung pro Sekunde als Auflösung. Geeignet ist diese Methode vor allem für schnell kommende Pulse, also hohe Drehzahlen bzw. Lochscheiben mit vielen Löchern, da so in der Messzeit genügend Pulse für eine ausreichende Auflösung kommen.
Richtung, Geschwindigkeit und Position mit Doppellichtschranke ermitteln
Dieser Teil beschäftigt sich mit der Optischen Drehzahl- und Geschwindigkeitsmessung sowie der Erfassung von Drehrichtung und zurückgelegter Position mit Hilfe einer Lochscheibe und 2 Gabellichtschranken. Hierfür werden Quadratursignale in definierten Zeitabständen ausgewertet.
Einführung
Für kontrollierte Bewegungen ist es mitunter wichtig, auch die Drehrichtung/Richtungswechsel und Position auszuwerten. Eine Lochscheibe mit einer Gabellichtschranke liefert lediglich Rechteckimpulse, egal wie rum sich die Lochscheibe bewegt. Bringt man eine zweite Gabellichtschranke an der gleichen Lochscheibe leicht versetzt an, bekommt man auch die Drehrichtung mit. Diese Methode ist altbekannt, simpel und leicht nachzubauen. Wenn man die Drehrichtung kennt, ist auch die Position kein Problem mehr. Ausgehend von einer Kalibrierposition können bei Vorwärtsbewegung Inkremente hochgezählt oder bei Rückwärtsbewegung runtergezählt werden.
Interessierte nehmen dazu mal eine PC-Maus mit Kugelantrieb zur Hand. Darin findet man zwei kleine Lochscheiben, die für die X- und Y-Richtung die Impulse erzeugen. Durch spezielle Gabellichtschranken mit 2 phasenversetzten Ausgängen wird auch die Drehrichtung erkannt.
Das selbe Prinzip ist in linearer Form auch in PC-Druckern zu finden: Entlang des Wagenrücklaufes ist ein transparentes Kunsstoffband gespannt, auf dem winzig kleine Streifenmuster aufgebracht sind. Diese werden von einer Gabellichtschranke mit 2 Ausgängen erkannt und so die Wagenposition gesteuert.
Aber es geht natürlich noch einfacher...
Zwei Lichtschranken liefern vier Zustände
Man nimmt 2 normale Gabellichtschranken und bringt sie so an, das sie im 1,5 fachen Lochabstand die Lochscheibe durchleuchten. Wenn sich Lichtschranke A in der Mitte des Lichtstreifens befindet, ist Lichtschranke B an der Grenze des Schattenstreifens. Nebenstehende Skizzen zeigen die möglichen Zustände beider Lichtschranken bei Vorwärts- und Rückwärtsbewegung der Lochscheibe. Wichtig ist hierbei, das die Lochscheibe in etwa gleich breite Licht- und Schattensegmente eingeteilt ist und die Lichtschranke(n) einen möglichst haarfeinen Lichtstrahl besitzt. Die Signale der Fototransistoren sollten verstärkt und gegebenenfalls mit TTL-Bausteinen zu korrekten High- und Low-Pegeln aufbereitet werden.
Es ergeben sich nun folgende Kombinationen:
- Zustand 1: LSA = hell und LSB = hell
- Zustand 2: LSA = hell und LSB = dunkel
- Zustand 3: LSA = dunkel und LSB = dunkel
- Zustand 4: LSA = dunkel und LSB = hell
Dreht man die Lochscheibe weiter, wiederholt sich der Vorgang. Die Zustandsfolge ist 1 > 2 > 3 > 4 > 1 > 2 > 3 > 4 > usw.
Bei entgegengesetzter Drehrichtung ändert sich diese Reihenfolge. Betrachtet man wieder vom Zustand 1 ausgehend die Gegenrichtung, ergeben sich nun diese Kombinationen:
- Zustand 1: LSA = hell und LSB = hell
- Zustand 4: LSA = dunkel und LSB = hell
- Zustand 3: LSA = dunkel und LSB = dunkel
- Zustand 2: LSA = hell und LSB = dunkel
Die Zustandsfolge in Gegenrichtung lautet dann: 1 < 4 < 3 < 2 < 1 < 4 < 3 < 2 < usw.
Mit diesem Wissen ist es nun ein Kinderspiel, auch die Änderung der Drehrichtung festzustellen. Dazu muss der letzte Zustand in einer Variable gespeichert und mit dem neu erkannten Zustand verglichen werden. Folgt nach Zustand 1 der Zustand 2, so ist es eine Vorwärtsbewegung. Folgt dem Zustand 1 der Zustand 4, so ist es eine Rückwärtsbewegung. Gleiches Prinzip gilt auch für die restlichen Zustände 2, 3 und 4.
Positionsüberwachung
Von jedem der 4 Zustände gibt es also zwei zu unterscheidende Fälle: Vorwärts und Rückwärts. Insgesamt müssen demzufolge 8 Bedingungen zyklisch abgetastet und ein Positionszähler entsprechend inkrementiert oder dekrementiert werden und schon hat man eine exakte Streckeninformation. In Worte gefasst ergibt sich folgende Logik:
Ausgangszustand: Beide Lichtschranken sind aus (A=0 UND B=0) und Zustand =1
- WENN (Zustand=1 UND A=0 UND B=1) DANN: Setze Zustand=2, Position inkrementieren, Vor
- WENN (Zustand=1 UND A=1 UND B=0) DANN: Setze Zustand=4, Position dekrementieren, Rück
- WENN (Zustand=2 UND A=1 UND B=1) DANN: Setze Zustand=3, Position inkrementieren, Vor
- WENN (Zustand=2 UND A=0 UND B=0) DANN: Setze Zustand=1, Position dekrementieren, Rück
- WENN (Zustand=3 UND A=1 UND B=0) DANN: Setze Zustand=4, Position inkrementieren, Vor
- WENN (Zustand=3 UND A=0 UND B=1) DANN: Setze Zustand=2, Position dekrementieren, Rück
- WENN (Zustand=4 UND A=0 UND B=0) DANN: Setze Zustand=1, Position inkrementieren, Vor
- WENN (Zustand=4 UND A=1 UND B=1) DANN: Setze Zustand=3, Position dekrementieren, Rück
Diese Prüfung muss ständig wiederholt werden, damit alle Pegelwechsel der beiden Lichtschranken erfasst werden. Nur so ist es möglich, die exakte Position zu verfolgen. Dafür bieten sich 2 Möglichkeiten: Entweder die Prüfung wird im Hauptprogramm ständig durchlaufen bzw. ein Timer-Interrupt tastet regelmäßig die Lichtschranken ab oder ein Interrupt reagiert auf eine Änderung der Leichtschranken und die Auswertung erfolgt nach jeder Änderung. Die Art der Auswertung kann in allen Fällen gleich sein - lediglich wann und wie oft sie aufgerufen wird ist verschieden. Hier soll nur die Interruptvariante betrachtet werden, weil sie mehr Vorteile bringt. Weiter unten im Artikel ist dazu ein Beispiel in Sprache C zu finden.
Zuvor muss aber eine sinnvolle Auslegung von Lochscheibe, Drehzahl und Positionsbereich gefunden und in Einklang mit den Ressourcen des verwendeten µControlles gebracht werden. Dazu folgende Betrachtungen:
Wenn 2 phasenversetzte Lichtschranken je Hell-/ Dunkelzyklus bereits 4 Positionen liefern, benötigt die Lochscheibe nur halb so viel "Löcher" wie eine Lochscheibe bei Verwendung nur einer Lichtschranke. Eine 15er Lochscheibe liefert demzufolge 15x4 = 60 Positionen auf 360°, das sind 6° je erfasster Position. Entscheidend ist, an welchem Antriebsteil die Lochscheibe montiert ist und mit welcher Untersetzung zwischen Motor und Abtriebswelle(Rad) gearbeitet wird. Ist die Lochscheibe an der Motorwelle angebracht, würde bei einer angenommenen Untersetzung von 10:1 eine erfasste Position nur 0,6° an der Abtriebswelle ausmachen.
Man muss sich klar machen, welche Positioniergenauigkeit nötig ist. Dabei gilt: Auslegung so genau wie nötig, nicht wie möglich. Weiter muss geklärt werden, wo man die Lochscheibe sinnvoll anbringt. Sie darf im Betrieb weder verschmutzt oder beschädigt werden. Fahrmodelle ziehen Staub, Haare etc. gern an, gut beraten ist man mit einer verkapselten Optomechanik. Ein weiterer Faktor ist die Drehzahl (im Leerlauf am höchsten) des Motors, weil diese die Frequenz der abzutastenden Signale beeinflusst. Zwischen Drehzahl n [U/min], Frequenz f [Hz] und Teilung T besteht folgender Zusammenhang:
f = n * T / 60 s
Beispiel: Ein Motor dreht im Leerlauf mit 2370 U/min und hat eine Lochscheibe mit Teilung = 12 an der Motorwelle. Die Frequenz der abzutastenden Signale einer Lichtschranke soll ermittelt werden. (oben im Osszillogramm dargestellt)
f = 2370 * 12 / 60 s
f = 474 Hz
Eine Lichtschranke liefert also ein Rechtecksignal mit f = 474 Hz. Jetzt muss noch das Signal der zweiten Lichtschranke um 90° versetzt darübergelegt werden. Bei idealen Pegeln sind in einer Periode 4 Schaltzustände abzutasten, also muss die Abtastfrequenz mindestens 4-fach über der Grundfrequenz liegen. Da es in der Praxis aber keine idealen Pegel gibt, muss die Abtastfrequenz noch höher ausgelegt werden. Betrachten wir noch mal das Oszillogrammm weiter oben:
Es fällt auf, das die Zeiten nicht exakt gleich sind, die Zustandszeiten 1 und 3 sind etwas länger als 2 und 4. Das liegt an der Einstellung des Abstandes beider Lichtschranken zueinander, die Phasenlage ist hier nicht genau 90°. Außerdem sind Lochscheibe und Lichtschranken mit kleinen Unregelmäßikeiten, Streuungen, Anstiegs- und Abfallzeiten behaftet, so dass es in einer Periode auch Zeiten gibt, die nicht eindeutig einem der 4 genannten Zustände entsprechen. Für eine sichere Abtastung ist deshalb von der kürzesten (= ungünstigsten) Schaltzeit auszugehen, hier sind es ca. 0,4 Millisekunden, das entspricht 2,5 kHz. Jeder Zustand sollte vom µController sicherheitshalber schon 3 bis 4 mal abgetastet werden, so das wir für das Beispiel mindestens ca. 10 kHz Abtastfrequenz einplanen müssen. Als Orientierungshilfe gilt:
Abtastfrequenz >= 20 * Frequenz Lichtschranke
Entsprechend der gewünschten Positioniergenauigkeit und Drehzahl kann nun die Teilung der Lochscheibe so gewählt werden, das die Lichtschrankensignale vom µController abgetastet werden können. Da Kaufteile aus dem Industriebereich oft eine recht hohe Teilung vorgeben, ist es manchmal besser, mit kleineren Teilungen anzufangen. Rechts sind Vorlagen, die man sich auf Folien ausdrucken kann.(Nähere Beschreibung im Praxis-Teil)
Die Abtastung muss sicher sein, auch wenn das Hauptprogramm gerade mit anderen Dingen als der Lochscheibenauswertung beschäftigt ist. Man kann zwar die Lochscheibe vom Hauptprogramm durchaus mit abfragen lassen, aber dann sollten keine anderen zeitraubenden Prozeduren darin enthalten sein. Ist nur ein Zustandswechsel übersehen und ausgelassen wurden, geht es erst an der nachfolgenden gleichen Hell-/Dunkel-Kombination weiter und der Contoller verzählt sich um 4 Inkremente! Deshalb sollte die TimerInterrupt-Variante vorgezogen oder die Abtastung in einen separaten µController ausgelagert werden.
Der Positionsbereich muss schließlich auch in einer Variablen dargestellt werden. Im Beispiel mit Teilung =12 wird der Positionzähler bei einer Motorumdrehung um 48 Inkremente hochgezählt. Bei 2370 U/min wäre eine 16Bit-Variable nach ca. 34 Sekunden übergelaufen. Demzufolge ist auch das Speichervolumen der Positionsvariablen dem tatsächlichen Fahrbereich anzupassen. Man kann auch Ober-/ Untergrenzen definieren, die bei Erreichen den Antrieb anhalten. Somit wird ein mechanisches Überfahren von Endlagen oder ein logisches Überlaufen von Variablen verhindert.
Zusammenfassung:
|
Kalibrierung
Im einfachsten Fall fährt man seinem Antrieb auf eine Referenzmarke (Nonius, Paßstift o.ä.) und setzt dort den Positionszähler zurück.
Wer es noch genauer will, muß auch noch die Lochscheibe in eine definierte Ausgangsstellung bringen. Dazu kann man die Lichtschrankensignale mit 2 LEDs optisch anzeigen. In der Kalibrierstellung müssen dann der Antrieb auf der Refernzmarke stehen und beide LEDs leuchten. Als Referenzmarke kann natürlich auch eine zusätzliche Lichtschranke dienen, die eine kleine Bohrung am Antrieb erkennt. Wichtig ist, dass die Referenzmarke nur einmal und eindeutig am Antrieb angebracht ist.
Geschwindigkeit und Beschleunigung
Geschwindigkeit wird meist in [m/s], [km/h] oder [mph] ausgedrückt, also der Wegstrecke je Zeiteinheit. Im µController interessieren uns diese Einheiten erst mal nicht, hier werden Inkremente je Zeiteinheit gezählt. Die Zeitintervalle, in denen die Inkremente ausgewertet werden, liefert wieder ein TimerInterrupt. Dieser ist mit deutlich längeren Zyklen auszulegen, damit auch genügend Inkremente je Zyklus gezählt werden können. Im Code-Beispiel unten werden bei 16Mhz CPU-Takt die Vorteiler 1 und 1024 für die TimerInterrupt´s verwendet: Timer 0 mit Prescaler =1024 für die Geschwindigkeitsberechnung mit ca. 61 Hz und Timer 2 mit Prescaler =1 für die Abtastung der Lichtschranken mit 62,5 kHz. Die Geschwindigkeitsmessung wurde mit 12er, 15er und 18er Teilung getestet. In der ISR des Timer_0 Overflow wird die Differenz aus aktueller Position und der Position des vergangenen Zyklus gebildet. Da diese Wegdifferenz in definierten Zeitabständen ermittelt wird, hat man hier bereits die Geschwindigkeit in n Inkremente je 0,01638 Sekunden. Mit dieser etwas abstrakten Geschwindigkeitseinheit wird im Hauptprogramm der Motor gesteuert.
Das gleiche Verfahren ist auch für die Beschleunigung anwendbar. Die Beschleunigung ist die Geschwindigkeitsänderung je Zeiteinheit. In der ISR des Timer_0 Overflow kann die Differenz aus aktueller Geschwindigkeit und der Geschwindigkeit des vergangenen Zyklus gebildet werden, um so die Beschleunigung zu erhalten. Die Einheit ist wieder etwas ungewohnt: Inkremente je 0,01638 Sekunden in 0,01638 Sekunden, also Inkremente/Quadratsekunden. Voraussetzung für eine vernünftige Beschleunigungsermittlung ist, das eine genügend hohe Auflösung der Geschwindigkeit vorliegt(=hohe Teilung der Lochscheibe). Ansonsten sind die ermittelten Werte zu klein und liegen, je nach Trägheit des Motors, fast immer bei 0, 1, 2 oder maximal 3.
Vorteil der Differenzmethode ist, man kann die Geschwindigkeit in einer 8Bit-Variable mit Vorzeichen ausdrücken. Die Werte des Beispieles lagen je nach Teilung zwischen -50 und +50 und sind für die Motorsteuerung ausreichend. Bessere Auflösung erfordert höhere Teilung, höhere Abtastrate, höhere CPU-Frequenz.
Praxis
Herstellung der Lochscheibe
Für eigene Projekte ist es mitunter schwer, Lochscheiben in passender Größe und Teilung zu finden. Oft müssen dann Kompromisse in der Drehzahlsteuerung oder Positionierung gemacht werden, weil die vielleicht günstigere Teilung nicht zu beschaffen ist.
Hier wird deshalb ein Selbstbau von preiswerten Lochscheiben vorgestellt: Man trägt in einer Excel-Tabelle z.B. 18 mal die Zahl 20 ein und markiert diesen Zellbereich. Anschließend erstellt man mit dem Diagramm-Assistent ein Ring-Diagramm. Darin muss man nun jeden Datenpunkt einzeln formatieren und abwechslend die Farbe schwarz und weiß zuordnen. Markiert man die komplette Datenreihe, kann man unter 'Formatieren'>'Optionen' auch die Innenringgröße einstellen. Dieses Ring-Diagramm kann nun beliebig kopiert und vergößert oder verkleinert werden, auch die Datenreihe kann auf z.B. 24x15 oder 30x12 angepasst werden. So lassen sich auf einer A4-Seite einige Dutzend Lochscheiben in allen Größen und Teilungen herstellen. Das fertige Arbeitsblatt muss nun noch mit geeigneter Tinte auf Folie ausgedruckt werden. Den Drucker muss man möglichst auf satte Farbe und kräftgen Kontrast einstellen. Zum Schluß wird die ausgedruckte Folie mit A4- Laminierfolie verstärkt, wer kein Laminiergerät hat, geht in einen Copy-Shop o.ä.
Die so gewonnenen Lochscheiben werden nun ausgeschnitten und bei Bedarf mit einem Heißluftgerät noch etwas "nachgebacken", bevor sie im eigenen Projekt mit Kraftkleber auf ein kleines Rad aufgeklebt werden. Hierbei auf gute Zentrierung achten, damit die Lochscheibe möglichst rund läuft. Sekundenkleber ist deshalb ungeeignet, weil kaum Zeit für Korrektur und Einstellung bleibt.
Anpassen der Lichtschranke
Baustelle:
Fotos, Anregungen zum Nachbau, Beschaffung, Erfahrungen
weiterführende Informationen: Inkrementalgeber
Quellcode
//Deklaration global volatile uint8_t Zust_Li; //Zustandsmerker Position linker Motor volatile uint16_t Li_Inkr; //aktuelle Position linker Motor volatile uint16_t old_Li_Inkr; //Position im vorangegangenen Takt volatile int8_t Speed_Li_Ist; //Wegänderung je Takt, in ISR Timer 0 ... // Interrupt-Service-Routine Timer_0 Overflow SIGNAL (SIG_OVERFLOW0) { // ISR-Code 61,035 Pro Sekunde Timeout++; Speed_Li_Ist = Li_Inkr - old_Li_Inkr; old_Li_Inkr = Li_Inkr; } // Interrupt-Service-Routine Timer_2 Overflow SIGNAL (SIG_OVERFLOW2) { // ISR-Code 62.5 kHz // 4 Zustaende durch jeweils 1 Bit repräsentiert (1,2,4,8) // Lichtschranke A liegt an Port A.0 // Lichtschranke B liegt an Port A.1 if ( (Zust_Li == 1) && ( !(PINA & (1<<PINA0)) )&& ( PINA & (1<<PINA1) ) ){ Li_Inkr = Li_Inkr + 1; Zust_Li = 2; } /* end if */ if ( (Zust_Li == 1) && (PINA & (1<<PINA0) )&& ( !( PINA & (1<<PINA1)) ) ){ Li_Inkr = Li_Inkr - 1; Zust_Li = 8; } /* end if */ if ( (Zust_Li == 2) && (PINA & (1<<PINA0) )&& ( PINA & (1<<PINA1) ) ){ Li_Inkr = Li_Inkr + 1; Zust_Li = 4; } /* end if */ if ( (Zust_Li == 2) && ( !(PINA & (1<<PINA0)) )&& ( !( PINA & (1<<PINA1)) ) ){ Li_Inkr = Li_Inkr - 1; Zust_Li = 1; } /* end if */ if ( (Zust_Li == 4) && (PINA & (1<<PINA0) )&& ( !( PINA & (1<<PINA1)) ) ){ Li_Inkr = Li_Inkr + 1; Zust_Li = 8; } /* end if */ if ( (Zust_Li == 4) && ( !(PINA & (1<<PINA0)) )&& ( PINA & (1<<PINA1) ) ){ Li_Inkr = Li_Inkr - 1; Zust_Li = 2; } /* end if */ if ( (Zust_Li == 8) && ( !(PINA & (1<<PINA0)) )&& ( !( PINA & (1<<PINA1)) ) ){ Li_Inkr = Li_Inkr + 1; Zust_Li = 1; } /* end if */ if ( (Zust_Li == 8) && (PINA & (1<<PINA0) )&& ( PINA & (1<<PINA1) ) ){ Li_Inkr = Li_Inkr - 1; Zust_Li = 4; } /* end if */ } ... int main (void) { //Init TCCR2 |= (1<<CS20); //Prescaler = 1 (16MHz/1 = 16000000) -> //16000000/256 -> 62500 Interrupts je Sekunde TCCR0 |= (1<<CS02)|(1<<CS00); //Prescaler = 1024 (16000000 / 1024 = 15625) -> //15625/256 = 61,035 -> 61 Interrupts je Sekunde TIMSK |= (1<<TOIE0)|(1<<TOIE2); //Timer Overflow Interrupt Enablae für Timer 0 und 2 Li_Inkr = 32000;Zust_Li = 1; // Kalibrierstellung bei 32000 sei(); // Interrupts aktivieren while(1) { // hier kann Position und Geschwindigkeit ausgewertet werden } }