Moinmoin, ich hätte da mal wieder ein kleines Problem und hoffe auf eure Hilfe ;) ich habe momentan ein Bastelprojekt mit diesem Motor: https://www.amazon.de/gp/product/B07N2KL4JQ?psc=1. Dieser soll einen Seilzug (naja, Seil ist ein großes Wort, eher eine Schnur, aber das nur am Rande) erst auf- und später wieder abrollen und dabei am Ende an der gleichen Stelle, also "bei Null", landen. Dafür würde ich gerne den verbauten Encoder nutzen. Das Ganze läuft auf einem ESP32, die beiden Hall-Sensoren des Encoders liegen auf Interrupt-Pins. Am Getriebeabgang nominelle 20 Umdrehungen bei einer Untersetzung von 340:1 macht 6800 U/min an der Motorwelle, oder etwa 113 Hz. Mit zwei Sensoren also 226 Hz. Das sollte doch eigentlich machbar sein - denkste. Ich habe meine Versuche für die Interrupts mal auf Pastebin gelegt: https://pastebin.com/fcf8Cizi. Dabei gibt es drei Versionen, die ich bisher ausprobiert habe. Die erste nutzt die gleiche Funktion für beide Sensoren - mit den ganzen If-Abgleichen scheint sie aber zu langsam zu sein, da der Counter nur um sehr wenige Ticks pro Zeit hochgeht. Zudem ist sie sehr unzuverlässig, ich habe mal ein Stück Schnur auf- und wieder abgerollt, mit dem Ergebnis dass ich nach 30cm Schnur aufrollen bei etwa 30 Ticks im Plus war, nach dem Abrollen allerdings bei -50 statt wieder bei 0. Also sowohl zu wenig als auch unzuverlässige Ticks. Version 2 spaltet die Funktion auf, um die Interrupts schneller abzuarbeiten. Das funktioniert zwar etwas besser, allerdings bekomme ich dabei zig Tausend Ticks in sehr kurzer Zeit, und sie zählen eigentlich immer ins Positive, unabhängig von der Drehrichtung des Motors. Also auch nicht die richtige Lösung. Die dritte Version sollte nur zeigen, ob beide Sensoren funktionieren und grob die gleiche Empfindlichkeit haben, und das haut ziemlich gut hin. Der ESP32 hat an dieser Stelle übrigens nicht viel mehr zu tun als den Motor laufen zu lassen und den Encoder auszuwerten, das sollte also eigentlich bzgl. Rechenleistung auch kein großes Problem darstellen. Ich vermute an dieser Stelle langsam, dass mein kompletter Ansatz einen Fehler hat. Liege ich damit richtig? Wie kann ich dieses Problem sinnvoller angehen und lösen? Ich habe in anderen Threads zu Motorencodern von Timer-Bausteinen gelesen, würde aber schätzen dass das bei <1kHz mit Kanonen auf Spatzen geschossen wäre? So, das erst mal von meiner Seite. Sollten weitere Fragen bestehen, stellt sie natürlich gerne. Ich hoffe ich trete auf niemandes Schlips mit diesem Problem, das ich sicher nicht als erster habe, aber ich habe weder hier noch in den Weiten des Internets wirklich eine Lösung gefunden, die zu meiner Konfiguration passt...
:
Bearbeitet durch User
Andreas B. schrieb: > Das Ganze läuft auf einem ESP32, die beiden > Hall-Sensoren des Encoders liegen auf Interrupt-Pins. Warum über Interrupt? Frage die Pins im festen Zeittakt ab? Statt IF-Abgleich kannst du besser eine einfache Tabelle für die Auswertung benutzen. Eingangswert sind vier Bits, zwei von der vorherigen Ablesung und zwei von der aktuellen.
Hallo Wolfgang, danke für den Input. Interrupt habe ich gewählt, um bei der doch "relativ" hohen Frequenz definitiv jede Umdrehung mitzuzählen. Wenn ich eine fest getaktete Abfrage mache, mein Hall-Durchgang aber zwischen zwei Takten liegt, "rutscht" dieser doch durch, oder nicht? Ich könnte natürlich einen der zwei Kerne nur auf diese Aufgabe ansetzen und im Millisekundentakt abfragen, aber ist das eine sinnvolle Herangehensweise? Meinst du mit Tabelle eine switch-case-Staffelung? Und mit bitweisem Schreiben habe ich noch nie gearbeitet, da muss ich mich erstmal einarbeiten. Gegenüber dem Schreiben auf normal deklarierte Variablen vermute ich einen Geschwindigkeitsvorteil, richtig?
Wolfgang schrieb: > Warum über Interrupt? Das ist bei Hallgebern optimal: maximale Geschwindigkeit, minimale ISR-Grundlast. Ansonsten ist die Auswertung nahezu gleich. Andreas B. schrieb: > Ich habe meine Versuche für die Interrupts mal auf Pastebin gelegt: Du mußt den Zustand der beiden Eingänge am Anfang der ISR einlesen und nur noch diesen auswerten.
Andreas B. schrieb: > - mit den ganzen > If-Abgleichen scheint sie aber zu langsam zu sein, da der Counter nur um > sehr wenige Ticks pro Zeit hochgeht. Du sagst also, daß der Prozessor drei boolsche Vergleiche, eine Zuweisung und ein Inkrement nicht mit 226Hz abarbeiten kann. Wenn das so ist, dann solltest du die Taktfrequenz von dem Ding mal auf etwas mehr als nur 1000Hz einstellen. Dein Problem liegt nicht an den paar Zeilen in der ISR, das liegt woanders. Wo, musst du rausfinden. Oliver
Andreas B. schrieb: > Ich könnte natürlich einen der zwei Kerne nur auf diese Aufgabe ansetzen > und im Millisekundentakt abfragen, aber ist das eine sinnvolle > Herangehensweise? Ja, genau so macht man das: https://www.mikrocontroller.net/articles/Drehgeber
m.n. schrieb: > Du mußt den Zustand der beiden Eingänge am Anfang der ISR einlesen und > nur noch diesen auswerten. Beziehst du dich auf eine der Versionen, die ich auf Pastebin geposted habe? Falls ja: in der ersten mache ich genau das, in der zweiten geschieht meine Auswertung ja quasi über den ISR-Aufruf - sprich, wenn eine der Funktionen aufgerufen wird, ist ja klar, dass gerade das zugehörige Signal eine Änderung erfahren hat. Oder ist das zu menschlich-instinktiv und nicht computer-logisch gedacht? Oliver S. schrieb: > Du sagst also, daß der Prozessor drei boolsche Vergleiche, eine > Zuweisung und ein Inkrement nicht mit 226Hz abarbeiten kann. Das war lediglich eine Vermutung aufgrund des für mich (!) unlogisch erscheinenden Verhaltens und der Tatsache, dass sich das Verhalten drastisch ändert, wenn ich die ISR-Aufrufe splitte und kürzer gestalte. > Dein Problem liegt nicht an den paar Zeilen in der ISR, das liegt > woanders. Wo, musst du rausfinden. Darf ich das so verstehen, dass du der Meinung bist, dass beide Versionen, sofern der gesamte restliche Code sauber läuft und hardwareseitig alles stimmt, eine korrekte Zählung der Umdrehungen liefern müssten? Das wäre auf jeden Fall schon mal eine interessante Information, da ich meine Fehlersuche dann auf andere Bereiche fokussieren könnte. Wenn ich in den nächsten Tagen dazu komme, werde ich auf jeden Fall mal ein komplettes Minimalbeispiel schreiben, vielleicht gibt das besser Aufschluss.
:
Bearbeitet durch User
Sind die Signale der Sensoren eigentlich ausreichend entprellt? Oder schalten die wirklich 100%ig prellfrei, sodaß sich das Problem nicht stellt?
Andreas B. schrieb: > Darf ich das so verstehen, dass du der Meinung bist, dass beide > Versionen, sofern der gesamte restliche Code sauber läuft und > hardwareseitig alles stimmt, eine korrekte Zählung der Umdrehungen > liefern müssten? Keine Ahnung, da ich nicht weiß, was der Rest des Programms alles anstellt. Was ich sage, ist, daß die paar Zeilen Code auch bei mehreren kHz ISR-Frequenz problemlos abgearbeitet werden sollten. Bei 226Hz stirbt der Prozessor höchstens an Langeweile. Oliver
Hermann Kokoschka schrieb: > Sind die Signale der Sensoren eigentlich ausreichend entprellt? > Oder schalten die wirklich 100%ig prellfrei, sodaß sich das Problem > nicht stellt? Hallo Hermann, da es sich um einen "professionellen" Encoder handelt und kein von mir zusammengeschustertes Teil, würde ich erstmal davon ausgehen. Sicher sagen kann ich es allerdings leider nicht, da ich kein Oszilloskop besitze. Zumindest ein kleines wird allerdings wohl in den nächsten Wochen kommen, da genau solche Fragen immer weider ein Problem darstellen. Oliver S. schrieb: > Keine Ahnung, da ich nicht weiß, was der Rest des Programms alles > anstellt. Was ich sage, ist, daß die paar Zeilen Code auch bei mehreren > kHz ISR-Frequenz problemlos abgearbeitet werden sollten. Bei 226Hz > stirbt der Prozessor höchstens an Langeweile. Deswegen die Formulierung "sofern der restliche Code sauber läuft". Aber gut, ich glaube, ich verstehe dich richtig, und es liegt nicht an der Arbeitsgeschwindigkeit. Also auf in die weitere Fehlersuche. Mir ist allerdings vorhin noch etwas anderes aufgefallen: meine Definition der Möglichkeiten ist fehlerbehaftet. Ich bin bislang davon ausgegangen, dass der Encoder immer nur entweder-oder triggert. Wäre dies der Fall, hätte der "Auslösemechanismus" (also der Magnet) die Möglichkeit, in den 270° oder in den 90° zwischen den beiden Hall-Sensoren stehen zu bleiben. Dadurch ergäbe sich nach meinem Code die Möglichkeit der Richtungsumkehr des Signals bzw. meiner Interpretation davon. Daher habe ich gerade mal noch ein anderes "Experiment" durchgeführt und einfach mal während des Motorbetriebs alle 3ms den Status der Signale ausgelesen - und diese können auch beide gleichzeitig HIGH sein. Wäre es insofern nicht eine Möglichkeit, nur einen Interrupt zu feuern und mit diesem zu prüfen, ob das andere Signal gerade HIGH oder LOW ist, sprich, ob das Interrupt-Signal als erstes (anderes Signal LOW) oder als zweites (anderes HIGH) angesprochen wird? ... zwo, eins, Risiko. Gleich mal ausprobieren. /edit: mit diesem Code, per Interrupt auf EncPin1 gestartet, habe ich jetzt ein relativ gutes Ergebnis erzielt:
1 | void Encoder() |
2 | {
|
3 | bool Enc2Val = digitalRead(EncPin2); |
4 | #define DebounceVal 2
|
5 | static unsigned long localTimer = 0; |
6 | |
7 | if (labs(millis() - localTimer) > DebounceVal) |
8 | {
|
9 | if (Enc2Val == HIGH) |
10 | {
|
11 | EncoderCounter++; |
12 | }
|
13 | else
|
14 | {
|
15 | EncoderCounter--; |
16 | }
|
17 | localTimer = millis(); |
18 | }
|
19 | }
|
Ich muss noch ein bisschen mit dem DebounceVal spielen, aber das könnte klappen... /edit2: nein, wohl doch nicht. Ich habe testweise eine Schnur auf- und wieder abgerollt, um die "gefahrene Strecke" zu messen, und habe immer noch Abweichungen von 10-20%. So langsam fuchst mich das.
:
Bearbeitet durch User
Andreas B. schrieb: > Mir ist allerdings vorhin noch etwas anderes aufgefallen: meine > Definition der Möglichkeiten ist fehlerbehaftet. so kann das passieren, wenn man es mit unterschiedlichen flankengesteuerten ISR behandeln will, die sich gegenseitig die Enc?Triggered Signale wegschalten - man merkt, dass man leider doch nicht alle möglichen Fälle berücksichtigt hat. Das soll nicht bedeuten, dass sich dein Encoder nicht auch mit flankengetriggerten ISR korrekt auswerten ließe. Aber bevor die Knoten in deinem Kopf zu groß werden, schau dir stattdessen diese Implementierung an, die einfach nur in einem festen Zeitraster (1ms) die Eingänge abfragt: https://www.mikrocontroller.net/articles/Drehgeber#Solide_L%C3%B6sung:_Beispielcode_in_C (In dem Artikel werden auch die möglichen Fallstricke der Lösungsansätze behandelt, durch die du dich gerade durchkämpfst). Falls dein Drehgeber die Flanken sehr "ungünstig" ausgeben sollte (z.B. Signal A wechselt direkt nach Signal B) lohnt es sich ggf. den Timerinterrupt noch etwas schneller aufzurufen, um wirklich sicher jeden Pegelwechsel zu detektieren. Die Belastung des Controllers durch diese Auswertung ist aber auch dann noch gering, wenn die Timer-ISR z.B. alle 300µs abläuft. Wenn du es auch damit nicht zum zuverlässigen Funktionieren bringen solltest, ist es endgültig Zeit für das Oszi, mit dem du nachprüfen kannst, ob nicht doch eins der Signale "krank" ist.
Hallo Achim, "aus Fehlern wird man klug, drum ist einer nicht genug" ;) ich lerne definitiv mal wieder viel aufgrund meiner Unzulänglichkeiten, da ich das ganze Elektro-Thema bis vor zwei Jahren für ein Buch mit sieben Siegeln gehalten habe. Und wenn ich eben doch mal wieder hängen bleibe, bin ich immer wieder froh, hier Antworten zu bekommen :) Nachdem du jetzt der zweite bist, der mir versichert, dass es mit einer festen Abtastrate funktionieren wird, werde ich mich mal an den Drehgeber-Artikel setzen. Das wird dann allerdings wohl eine Weile dauern, da ich so einiges, was dort gemacht wird, nicht verstehe und ich ein bisschen das "Wikipedia-Phänomen" kommen sehe, dass man mit einem Artikel anfängt, aber bald 20 Tabs offen hat. Zudem fahre ich bereits morgen in den Weihnachtsurlaub, da weiß ich nicht wie viel ich tatsächlich geschafft bekomme. Ich wusste bislang auch noch nicht, dass man - wenn ich das kurze Überfliegen des Artikels richtig verstehe - Interrupts auch programmiert, also eben etwa jede Millisekunde, triggern kann. Das war bislang meine größte "Sorge" bei der Implementierung eines festen Taktes. Aber wie gesagt, ich lese mich da ein und versuche mich dann mal daran. Und zu guter Letzt: ich glaube, ein kleines Oszilloskop könnte ein Weihnachtsgeschenk an mich selbst werden. Man kann es ja doch immer wieder mal brauchen, und so lange man es nicht braucht, frisst es kein Heu. ;)
Wenn du als Neuling auf dem Gebiet versuchst, deinen eigenen Algorithmus zu entwickeln, liegen die Chancen bei mindestens 99%, dass du dabei in irgendeine Falle tappst. Das liegt nicht an dir, sondern in der Natur der Sache :) Wenn du schnell zum Ziel kommen willst, nimmst du einen der im Artikel Drehgeber vorgestellten Routinen. Diese arbeiten alle mittels periodischer Abtastung, die typischerweise von einem Timer-Interrupt getriggert wird. Die Abtastrate muss dabei so hoch gewählt werden, dass bei sauberen Signalen zwischen den Signalflanken immer mindestens ein Abtastpunkt liegt. Prellen bzw. Schwingungen im Bereich der Flanken müssen nicht im Detail abgetastet werden können und dürfen deswegen auch höherfrequent sein. Der durch sie verursachte Fehler beträgt maximal ±1 Inkremente und nicht akkumulierend. Auch kurze Peaks in den Signalen schaden nicht, solange sie nicht in beiden Signalen gleichzeitig auftreten. Man kann die Auswertung mit einem Fehler von ±1 Inkrement prinzipiell auch mit Interrupts realisieren, muss dann aber genau wissen, was man tut. Das Verfahren wird – richtig umgesetzt – auch ziemlich kompliziert, so dass man mit hoher Wahrscheinlichkeit irgendeinen selten auftretenden Fall übersieht und der ermittelte Zählerstand deswegen längerfristig immer mehr von dem erwarteten Wert abweicht. Da die Interrupt- gegenüber den Abtastverfahren keine relevanten Vorteile aufweisen, sind letztere der Standard. Auch in Hardware implementierte Encoderzähler (die ganz sicher nicht von Laien entwickelt wurden) arbeiten mit periodischer Abtastung und nicht auf Flankenauswertung, was man leicht daran erkennen kann, dass sie eine Taktquelle benötigen. Wenn es dir weniger um eine schnelle Lösung, sondern mehr um den Erkenntnisgewinn geht, kannst du natürlich gerne deine eigenen Ideen ausprobieren. Dann solltest du deine Verfahren aber erst einmal auf dem Papier auf Zuverlässigkeit prüfen, bevor du sie in der Praxis testest. Denn nur auf dem Papier kannst du auch die pathologischen Fälle erfassen, die in der Praxis vielleicht nur einmal in mehreren Stunden oder noch seltener auftreten. Hierzu ist es wichtig, sämtliche mögliche Zustandswechsel der beiden Signale durchzuspielen und zwar insbesondere auch hochfrequente Wechsel im Bereich der eigentlichen Signalflanken, wie sie bspw. beim Prellen oder Vibrieren auf einer Flankenposition auftreten können. Betrachte dabei mindestens die folgende Fälle: 1. Encoder dreht sich längere Zeit nur vorwärts oder nur rückwärts. 2. Encoder steht an einer Flanke, wackelt dort aber ganz leicht hin und her, so dass von den beiden Signalen eins konstant bleibt und das andere ständig zwischen low und high wechselt. 3. Wie (2), nur dass die low-high-Wechsel des einen Signals schneller erfolgen, als sie vom Interruptsystem des Controllers verarbeitet werden können. Wenn du diese Überprüfungen auf deinen zuletzt geposteten Ansatz anwendest, wirst du feststellen, dass dieser bereits bei Punkt 2 versagt, weswegen du Punkt 3 du gar nicht nachzuprüfen brauchst.
:
Bearbeitet durch Moderator
Hallo Yalu, hui, so viel Text - danke dir (und natürlich auch allen anderen!) für die Zeit, die du dir da genommen hast :) Tatsächlich versuche ich bei vielen Sachen erstmal, eine eigene Lösung zu entwickeln, bevor ich zu Bibliotheken oder anderweitig vorgefertigten Lösungen greife - ist nicht immer optimal, wie man hier sieht, aber an vielen Stellen kann man dabei viel lernen, wie man auch hier sieht ;) gerade bei so etwas sensiblem wie dieser Encoder-Geschichte ist es dann aber wohl doch sinnvoll, auf etablierte Lösungen zu bauen, aus Gründen, die du ja genannt hast. Das Ding ist, ich will zwar schnell zum Ziel kommen, um mit meinem Projekt voranzukommen, aber ich möchte auch verstehen, WIE ich zum Ziel komme. Also werde ich zwar letztlich eine der vorgefertigten Lösungen nutzen, aber eben erst wenn ich sie (zu großen Teilen) verstanden habe. Es könnte also durchaus sein, dass ich hier noch ein-, zweimal nachfragen werde O:) Mit der eineindeutigen Definition von und dem Erkennen jeglicher möglicher Betriebszustände tue ich mich immer noch schwer. Das Durchspielen verschiedener Szenarien, wie du es beschreibst, ist da sehr hilfreich, aber man muss natürlich auch die "Fallen" erkennen, die sich dabei ergeben können. Ich denke, da fehlt mir einfach noch viel Erfahrung, aber das wird :)
:
Bearbeitet durch User
Das Abtasten mit einem Timer interrupt von zb 1ms ist einfach, weil es nur 4 Zustaende gibt. Low-low, low-high, high-high, high-low. Dann nimmt man den vorherigen Zustand welcher auch wieder aus Low-low, low-high, high-high, high-low ist. Wenn die beiden gleich sind, hat sich nichts geaendert. Und sonst aendert sich jeweils der eine oder andere pin, je nachdem ob nach links oder rechts gedreht wurde.
Heute muß ich doch einmal wiedersprechen. Yalu X. schrieb: > Man kann die Auswertung mit einem Fehler von ±1 Inkrement prinzipiell > auch mit Interrupts realisieren, muss dann aber genau wissen, was man > tut. Das Verfahren wird – richtig umgesetzt – auch ziemlich kompliziert, > so dass man mit hoher Wahrscheinlichkeit irgendeinen selten auftretenden > Fall übersieht und der ermittelte Zählerstand deswegen längerfristig > immer mehr von dem erwarteten Wert abweicht. Da die Interrupt- gegenüber > den Abtastverfahren keine relevanten Vorteile aufweisen, sind letztere > der Standard. Bei der Dekodierung wird immer der neue mit dem alten Zustand verglichen und darauf reagiert. Diesen Vergleich kann man nun zyklisch per Timer aufrufen oder eben per Interrupt nur, wenn tatsächlich Pegeländerungen vorliegen. Bei hoher Impulsfolge wird bei Interrupts weniger Grundlast des Prozessors benötigt, da nur die Impulse verarbeitet werden müüsen, die auch auftreten. Schnelle Inkrementalgebersignale bis in den 3-stelligen kHz-Bereich auszuwerten, ist per Interrupt wesentlich geschickter. Für noch höhere Frequenzen werden dann Hardwaredekoder+Zähler benötigt. > Auch in Hardware implementierte Encoderzähler (die ganz > sicher nicht von Laien entwickelt wurden) arbeiten mit periodischer > Abtastung und nicht auf Flankenauswertung, was man leicht daran erkennen > kann, dass sie eine Taktquelle benötigen. Hardwaredekoder brauchen einen Takt, um +/- Flanken überhaupt erkennen zu können. Dieser liegt üblicherweise im MHz-Bereich. Beim µC, der per Interrupt auswertet, ist diese Hardware als Flankenerkennung am Eingang ebenfalls vorhanden. So, jetzt habe ich es Dir aber gezeigt ;-)
m.n. schrieb: > Bei hoher Impulsfolge wird bei Interrupts weniger Grundlast des > Prozessors benötigt, da nur die Impulse verarbeitet werden müüsen, die > auch auftreten. Schnelle Inkrementalgebersignale bis in den 3-stelligen > kHz-Bereich auszuwerten, ist per Interrupt wesentlich geschickter. Für > noch höhere Frequenzen werden dann Hardwaredekoder+Zähler benötigt. Das stimmt so nicht. Beim Abtastverfahren ist die benötigte Rechenleistung unabhängig von der Impulsfrequenz immer gleich. Beim Interruptverfahren ist die benötigte Rechenleistung proportional zur Impulsfrequenz. Bei niedrigen Frequenzen ist sie niedriger als beim Abtastverfahren. Bei der Maximalfrequenz, auf die das Abtastverfahren ausgelegt ist, ist sie etwa gleich. Kommen bei der Maximalfrequenz noch zusätzliche Impulse durch Prellen oder Schwingungen hinzu, steht das Interruptverfahren rechenzeitmäßig schlechter da. Um zu verhindern, dass bei einem auf Grund eines Fehlers dauerhaft oszillierenden Signals die CPU durch Interrupts komplett blockiert wird, sollte die Interruptrate begrenzt werden, bspw. dadurch, dass am Ende der Interruptroutine die Freigabe der Interruptsperre per Timer verzögert erfolgt. Das macht die ganze Sache aber komplizierter und damit fehleranfälliger. Das Abtastverfahren verschwendet zwar bei langsam drehendem Encoder ein kleines Bisschen Rechenzeit, aber diese Rechenkapazität muss sowieso vorgehalten werden, da sich der Encoder ja irgendwann auch schneller drehen wird. > Hardwaredekoder brauchen einen Takt, um +/- Flanken überhaupt erkennen > zu können. Theoretisch wäre auch ein Verfahren denkbar, das – bspw. unter Verwendung von flankengetriggerten Flipflops – direkt auf die Flanken reagiert. Das macht aber niemand, weil die dadurch entstehenden Schwierigkeiten die potentiellen Vorteile bei weitem überwiegen.
Yalu X. schrieb: > Kommen bei der Maximalfrequenz noch > zusätzliche Impulse durch Prellen oder Schwingungen hinzu, Was soll man bei konstruierten Argumenten noch antworten? Wenn man bei Hallgebern Effekte hat wie Schwingen, Zittern, Prellen, Wabbeln, Zurren und Zappeln, hat man an anderer Stelle etwas grundlegend falsch gemacht. Vielleicht einfach mal die Schrauben festziehen.
Ich habe damals lange damit rumexperimentiert, weil ich auch 2-Spur Encoder hatte. Mein Fazit war, das IRQ gesteuerte Auswertung immer Probleme mit verlorenenen Schritten hatte, wenn man die Drehrichtung ändert, unabhängig von Prellen oder Nichtprellen. Die Timermethode hingegen kann schrittgenau vor und zurückzählen, wenn man sich für die richtige Auswertung (1 Schritt, 2 Schritt, 4 Schritt) entscheidet.
Ich bin auch von Meinung das die A/B Signale erst ueberpruft werden mussen das die Fehlerfrei sein ! Damit meine ich steile Flanken, A/B um die 90° (+/- 30°) verschoben, Pegel richtig und keine falsches schalten. Wen das so ist, sind alle methoden IO ! Da gibt auch µ-controller, wo die A/B Signale gleich in hardware auf eine Timer/Counter kommen ! Da ist dan die µ-auslastung 0 ! (fast alle 32-bit von STM konnen das).
Matthias S. schrieb: > Ich habe damals lange damit rumexperimentiert, weil ich auch 2-Spur > Encoder hatte. Mein Fazit war, das IRQ gesteuerte Auswertung immer > Probleme mit verlorenenen Schritten hatte, wenn man die Drehrichtung > ändert, unabhängig von Prellen oder Nichtprellen. Was natürlich am IRQ liegen muß, und nicht an dir. Bei sauberen prellfreien Signalen gibt es keinen Grund, warum das mit IRQ-Auswertung nicht funktionieren sollte, und komplizierter als eine Abfrage der Pins im festen Timertakt ist das aus Prinzip auch nicht. Der IRQ muß natürlich auf jeden Flankenwechsel triggern, sonst klappt das nicht. Oliver
Matthias S. schrieb: > Mein Fazit war, das IRQ gesteuerte Auswertung immer > Probleme mit verlorenenen Schritten hatte Man muß natürlich den Interrupt auf alle 4 Flanken auslösen und den Unterschied zum vorher gemerkten Stand auswerten. Also genau so, wie man es im Timerinterrupt machen würden. Auch muß man immer zuerst die Pending-Flags löschen und danach die beiden Pins einlesen. Dann kann keine Änderung durchrutschen.
Peter D. schrieb: > Man muß natürlich den Interrupt auf alle 4 Flanken auslösen und den > Unterschied zum vorher gemerkten Stand auswerten. Es reichen die +/- Flanken eines Kanals. Aus dem 2. Kanal wird die Richtungsinformation gewonnen.
m.n. schrieb: > Es reichen die +/- Flanken eines Kanals. Aus dem 2. Kanal wird die > Richtungsinformation gewonnen. Und damit sind wir bei dem üblichen Konsumerschrott, wo man am liebsten mit dem 10-Pfünder auf den Drehgeber dreinschlagen will. Der Witz ist, daß der Interrupthandler eben nicht exakt synchron zur Flanke den 2. Kanal einlesen kann. D.h. jeder Preller und beliebige Richtungswechsel durch den Benutzer zählen falsch. Die Interrupts sind nur dazu tauglich, um festzustellen, es erfolgte eine Änderung. Die Auswertung selber muß immer anhand des Graycodes erfolgen.
:
Bearbeitet durch User
m.n. schrieb: > Yalu X. schrieb: >> Kommen bei der Maximalfrequenz noch >> zusätzliche Impulse durch Prellen oder Schwingungen hinzu, > > Was soll man bei konstruierten Argumenten noch antworten? > > Wenn man bei Hallgebern Effekte hat wie Schwingen, Zittern, Prellen, > Wabbeln, Zurren und Zappeln, hat man an anderer Stelle etwas grundlegend > falsch gemacht. Vielleicht einfach mal die Schrauben festziehen. Kann man machen. Wenn alles so fixiert wird, dass sich der Encoder gar nicht mehr drehen kann, sind auch alle Messfehler beseitigt ;-) Nein, mit den Schwingungen meine ich nicht solche, die auf Grund einer wackeligen Konstruktion entstehen. Es gibt da noch viele andere Möglichkeiten. Stell dir vor, der TE möchte damit eine digitale Positionsregelung realisieren. Dann entstehen selbst bei perfekt ausgelegtem Regler durch Quantisierungfehler immer leichte Regelschwingungen. Es kann aber auch sein, dass das von dem Motor angetriebene Objekt selber etwas vibriert bzw. von extern zu Vibrationen angeregt wird. Das schlägt sich auf die Motorwelle und damit auf den Encoder nieder. Mag sein, dass beim TE genau diese Effekte nicht auftreten. Wenn du aber immer alle Effekte, die evtl. Schwierigkeiten machen könnten, schon von vornherein ausschließt und dann auch noch gezielt auf das am schwersten zu beherrschende Auswerteverfahren setzt, wirst du nie ein zuverlässig arbeitendes System hinbekommen. Beim Abtastverfahren hat man all diese Probleme nicht. Warum sollte man sich das Leben also unnötig schwer machen?
m.n. schrieb: > Es reichen die +/- Flanken eines Kanals. Aus dem 2. Kanal wird die > Richtungsinformation gewonnen. Bei Drehgebern, die sowieso nur alle zwei Flanken eine Rastung haben, kann man das vielleicht so machen. Auf einer Motorwelle möchte man eigentlich keine Information verschwenden und wertet alle vier Zustände eines 2-Bit-Gray-Codes aus. Die Kanäle sind bzgl. ihres Informationsgehalts völlig gleichberechtigt. Da ist nicht einer für Richtung und einer für Takt o.ä. zuständig. https://de.wikipedia.org/wiki/Gray-Code#L%C3%B6sung_mit_Gray-Code https://de.wikipedia.org/wiki/Inkrementalgeber#Signalauswertung
Wolfgang schrieb: > Auf einer Motorwelle möchte man eigentlich keine Information > verschwenden und wertet alle vier Zustände eines 2-Bit-Gray-Codes aus. Kann man gerne machen, muß man aber nicht. Green-Code reicht aus ;-) Peter D. schrieb: > D.h. jeder Preller und beliebige > Richtungswechsel durch den Benutzer zählen falsch. Kontaktprellen bei Hallsensoren? Zum Problem des TOs: Er kann im Grunde machen, was er will. Nur wenn seine ISRs nicht richtig arbeiten, liegt es nicht an dem Verfahren selbst. Alle Jahre wieder!
m.n. schrieb: > Kontaktprellen bei Hallsensoren? Ich mache da keinen Unterschied zwischen Prellen und Störungen, es wird beides auf die gleiche Art gefiltert.
>Wie kann ich dieses Problem sinnvoller angehen und lösen?
Starte mit einem Minimalprogramm. Darin konfigurierst Du einen
Hardware-Timer so, dass er genau jede 1 ms einen Interrupt auslöst. In
der ISR liest Du die (digitalen) Zustände beider Sensoren ein und
vereinigst die beiden Bits zu einem Byte-Wert 0...3. Addition von 48
macht daraus einen ASCII-Char "0"..."3" und den sendest Du über die UART
z. B. mit 38400 Baud auf Deinen PC. Ein darauf laufendes
Terminalprogramm loggt den Stream und schreibt ihn in eine Datei. Wenn
Du den Motor zehn Sekunden laufen lässt (für ein oder zweimal
vor-stop-zurück-stop-vor wird das reichen) wird die Datei am Schluss
genau 10000 Zeichen enthalten. Soviel kannst Du mit jedem ordentlichen
Texteditor noch locker handeln.
Und dann schaust Du Dir in diesem Editor erstmal ganz entspannt an, was
die Sensoren da während des Motorlaufs abgeliefert haben: Störungen?
Prellen? Andere komische Effekte? Oder nichts davon, d. h. alles ist
plausibel und OK?
Anschließend kannst Du Dir - am besten in der Sprache, mit der Du auch
Deinen µC programmierst - eine Zustandsmaschine schreiben, welche diese
Datei einliest, und daras den gewünschten Zustand, also die
Motorposition, berechnet. Den Algorithmus optimierst Du solange, bis er
zu Deiner Zufriedenheit funktioniert, also alle 10000 berechneten
Motorpositionen korrekt oder zumindet akzeptabel genau sind.
Der Rest ist klar. So oder so ähnlich würde ich die Sache angehen.
Moinmoin, der TE ist zurück, Weihnachten war anstrengend, aber jetzt darf ich weiterbasteln. Ich bin noch nicht fertig, aber wollte mich hier mal wieder zwischenmelden. Ich habe den zu Anfang verlinkten Eintrag zum Drehgeber gelesen und die Theorie verstanden. Die Praxis umzusetzen fiel mir anhand des Beispiels etwas schwer, aber mit genug Google fragen ließen sich alle Begriffe und Befehle klären ;) Da der Code am Ende auf einem ESP32 läuft, habe ich die Initialisierung des Timers anhand des Tutorials hier aufgebaut: https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/. Bezüglich der Präzision bin ich vollauf zufrieden: nach einer Minute Laufzeit gab es im Minimalcode eine Abweichung um eine Mikrosekunde, das ist bei Weitem genug. Ich habe den aktuellen Stand mal wieder bei Pastebin abgelegt, falls jemand drüberschauen und eventuell Dinge anmerken möchte: https://pastebin.com/piK6XGmT. Ich muss allerdings dazu sagen, dass der Code momentan auf händischen Betrieb mit zwei Knöpfen ausgelegt ist, damit ich verstehe, was da wann passiert und eventuelle Bugs fixen kann (aus diesem Grund sind auch die Serial.println im Interrupt, die kommen da wieder raus). Im händischen Betrieb macht es bislang einen sehr soliden Eindruck. Morgen werde ich mal den Motor dranhängen und sehen, was dann passiert. Sofern Interesse besteht, werde ich weiter berichten. Ich danke euch aber auf jeden Fall soweit für die Hilfe - wie bereits am Anfang geschrieben, habe ich doch mal wieder einiges gelernt ;)
m.n. schrieb: > Green-Code reicht aus ;-) Du solltest ganz dringend an deinen Sprachkenntnissen arbeiten: Gray ≠ Grey Der Code ist nach dem Physiker Frank Gray benannt. https://de.wikipedia.org/wiki/Gray-Code
Wolfgang schrieb: > Du solltest ganz dringend an deinen Sprachkenntnissen arbeiten: Meinst Du? Kennst Du denn Peter Green nicht? https://de.wikipedia.org/wiki/Peter_Green Mit dem Gray-Code bei zwei phasenverschobenen Signalen ist es so wie mit dem Mann mit dem Hammer. Der kennt auch keinen Unterschied zwischen Nutz- und Störsignal. Hau drauf und fertig - das machen wir immer so!
m.n., also hilfreich sind deine Beiträge nicht unbedingt. Welchen Nutzen ziehst du aus diesem Geschwätz? Kleines Update: ich habe gerade mal den Encoder drangehängt und getestet. Irgendwo hängt aber noch ein Fehler drin, bei gleichbleibender Drehrichtung zählt der Encoder mit meinem Code je nach Motorgeschwindigkeit auf- oder abwärts. Um meine Logik nochmal zu überprüfen: ich habe eine Getriebeabtriebsgeschwindigkeit von 20 RPM bei einer Untersetzung von 340:1, also eine Motordrehzahl von 6800 Umdrehungen pro Minute, sprich 113,33 Hertz. Da die Hallgeber 90° versetzt sind, ergibt sich eine maximale Signaländerungsrate von 453,33 Hz, soweit korrekt? Nyquist-Shannon sagt mindestens doppelte Abtastrate, zur Sicherheit vierfach, macht 1813,33 Hz, und zum einfacheren Rechnen machen wir da 2 kHz draus. Sprich, wenn ich den Interrupt alle 500 Mikrosekunden laufen lasse, müsste ich eigentlich ein sauberes Signal bekommen, so weit korrekt? Vom Prellen mal abgesehen, was dem ein oder anderen User zufolge bei Hall-Sensoren nicht oder nur in geringem Maße stattfinden sollte, was kann es sein, das mir das Ergebnis dermaßen zerschießt? Dem Vorschlag von LostInMusic folgend werde ich wohl mal Elektronik und Code so weit umbauen, dass ich den Motor auch über den Mikrocontroller steuern kann (wurde für den Test bislang über die eigentliche Motorsteuerung betrieben), und schauen was da genau passiert. Vielleicht wird es langsam auch einfach wirklich mal Zeit für ein Oszi, das man mit rein hängen kann...
Wolfgang schrieb: > Falsches Genre Sag das nicht. Man muß weder Frank Gray noch Peter Green kennen, um einen Drehencoder auszuwerten. Andreas B. schrieb: > Kleines Update: ich habe gerade mal den Encoder drangehängt und > getestet. Irgendwo hängt aber noch ein Fehler drin, bei gleichbleibender > Drehrichtung zählt der Encoder mit meinem Code je nach > Motorgeschwindigkeit auf- oder abwärts. Das kommt dabei raus, wenn man sich durch Aussagen wie: "Das geht nur so" einläßt und nicht den eigenen Kopf gebraucht. Wie gesagt, den Namen Gray muß man dabei garnicht kennen.
Andreas B. schrieb: > Dieser soll einen > Seilzug (naja, Seil ist ein großes Wort, eher eine Schnur, aber das nur > am Rande) erst auf- und später wieder abrollen und dabei am Ende an der > gleichen Stelle, also "bei Null", landen. Das wird nicht zufällig eine Hühnertür? Ich habe Magnetschalter als Endschalter oben und unten verbaut - und lasse die Steuerung ordentlich blinken, wenn ein erwarteter Zustand nicht eintritt (das Seil kann ja auch mal schlaff werden, weil die "Falltür" sich verkantet / etwas drinsteckt ...). Das bekommst Du bei der Encoder-Methode nicht mit.
m.n. schrieb: > Das kommt dabei raus, wenn man sich durch Aussagen wie: "Das geht nur > so" einläßt und nicht den eigenen Kopf gebraucht. Genau. Deshalb habe ich auch erstmal eine ganze Weile meine eigenen Herangehensweise versucht zum Laufen zu kriegen und erst, als ich mit meinem Latein am Ende war, hier nachgefragt und nachfolgend einen gut erklärten und begründeten Alternativvorschlag ausprobiert. So macht man das, ohne eigenen Kopf. Wie gesagt, deine Beiträge sind nicht besonders hilfreich, und solang nichts konstruktives kommt, werde ich sie in Zukunft ignorieren. Hugo H. schrieb: > Das wird nicht zufällig eine Hühnertür? Hehe, nein, aber rein von der Mechanik her wird es grob vergleichbar. An einem Ende kann (und werde) ich einen Endschalter verbauen, am anderen aber soll es frei einstellbare oder vorgespeicherte (Zwischen)zustände geben. Um bei deiner Anwendung zu bleiben: es wird einen Endschalter für "Tür ist ganz offen" geben, ich will aber "Tür zu" und "Tür halb zu" über den Verfahrweg steuern.
:
Bearbeitet durch User
Andreas B. schrieb: > es wird einen Endschalter für > "Tür ist ganz offen" geben, ich will aber "Tür zu" und "Tür halb zu" > über den Verfahrweg steuern. Na ja - das Problem, dass Du nicht weißt was am anderen Ende des Seils passiert, bleibt ...
:
Bearbeitet durch User
Hugo H. schrieb: > Na ja - das Problem, dass Du nicht weißt was am anderen Ende des Seils > passiert, bleibt ... Das ist zwar korrekt, in meiner Anwendung aber kein Problem, da die Seilführung im Betrieb immer unter Beobachtung steht
Andreas B. schrieb: > Wie gesagt, deine Beiträge sind nicht besonders hilfreich, und solang > nichts konstruktives kommt, So, wie Deine Misserfolge aussehen, kannst Du doch garnicht beurteilen, was konstruktiv ist oder nicht. Bei mir funktionieren die Drehgeber, ob langsam oder schnell. Einen kleinen Beispielcode hätte ich Dir auch gezeigt. Gut, belassen wir es dabei.
Welchen Zweck sollen die Variable "interruptCounter" und die Funktion "encode_read" erfüllen?
m.n. schrieb: > Kann man gerne machen, muß man aber nicht. Green-Code reicht aus ;-) > Er kann im Grunde machen, was er will. Nur wenn seine ISRs nicht richtig > arbeiten, liegt es nicht an dem Verfahren selbst. m.n. schrieb: > Alle Jahre wieder! m.n. schrieb: > Mit dem Gray-Code bei zwei phasenverschobenen Signalen ist es so wie mit > dem Mann mit dem Hammer. Der kennt auch keinen Unterschied zwischen > Nutz- und Störsignal. Hau drauf und fertig - das machen wir immer so! m.n. schrieb: > Das kommt dabei raus, wenn man sich durch Aussagen wie: "Das geht nur > so" einläßt und nicht den eigenen Kopf gebraucht. m.n. schrieb: > So, wie Deine Misserfolge aussehen... ... doch, doch. Ich bin mir ziemlich sicher beurteilen zu können, dass das weder konstruktiv noch hilfreich, sondern einfach nur unnötige Polemik ist. m.n. schrieb: > Einen kleinen Beispielcode hätte ich Dir auch > gezeigt. Tja, schade dass du stattdessen so damit beschäftigt warst, unser aller Zeit zu verschwenden, während andere User versucht haben zu helfen und dabei auch noch Erfolg hatten. Jetzt werden wir deine Lösung wohl nie erfahren. LostInMusic schrieb: > Welchen Zweck sollen die Variable "interruptCounter" und die Funktion > "encode_read" erfüllen? Das habe ich mich ehrlich gesagt auch schon gefragt. Den Part habe ich größtenteils aus dem Drehgeber-Beispielcode übernommen, da mein anfänglicher Versuch, den EncoderCounter direkt im Interrupt zu schreiben, nicht so recht funktioniert hat. Der Fehler lag letztlich allerdings an anderer Stelle und das ist ein Relikt, das noch beseitigt werden möchte. Ich hoffe, dass ich heute Abend noch dazu komme.
Andreas B. schrieb: > Ich hoffe, dass ich heute Abend noch dazu komme. So, habe es geschafft und die Zeit gefunden, mich nochmal ranzusetzen. Der Fehler, den ich mit der encode_read-Funktion umgangen habe, war doch noch da, ich habe ihn aber durch einiges Suchen finden können. Wenn ich direkt im Interrupt
1 | EncoderCounter += pgm_read_byte(&table[last]); |
schreibe, liest pgm_read_byte() den Wert aus der Tabelle unsigned aus, addiert also fröhlich 255, statt 1 abzuziehen. Insbesondere beim Rückwärtslauf hat das natürlich sehr schnell zu absurden Werten (und mich letztlich auf die richtige Spur) geführt. Mit
1 | EncoderCounter += (int8_t) pgm_read_byte(&table[last]); |
dagegen zeigt er jetzt auch im Interrupt das erwartete Verhalten. Der Umweg über die encode_read()-Funktion scheint das gleiche zu machen, ohne dass ich es bisher verstanden habe. Ein paar kurze Tests (10-30 Sekunden Vorwärtslauf, dann Rückwärtslauf bis EncoderCounter <= 0) zeigen eine Präzision, die für mich in der Praxis absolut tauglich wäre. Ich werde das morgen mal noch weitergehend testen (Testlauf über mehrere Minuten, mehrere Wiederholungen von kurzen Vor-Zurück-Wechseln etc.), aber gerade bin ich guter Dinge, dass ich mein Ziel an dieser Stelle so langsam erreiche. ... schon schlimm, diese Misserfolge, die mir so sehr meine Urteilskraft rauben.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.