Forum: Mikrocontroller und Digitale Elektronik Motor-Encoder auslesen bereitet Probleme


von Andreas B. (firefrog)


Lesenswert?

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
von Wolfgang (Gast)


Lesenswert?

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.

von Andreas B. (firefrog)


Lesenswert?

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?

von m.n. (Gast)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

von Thomas F. (igel)


Lesenswert?

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

von Andreas B. (firefrog)


Lesenswert?

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
von Hermann Kokoschka (Gast)


Lesenswert?

Sind die Signale der Sensoren eigentlich ausreichend entprellt?
Oder schalten die wirklich 100%ig prellfrei, sodaß sich das Problem 
nicht stellt?

von Oliver S. (oliverso)


Lesenswert?

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

von Andreas B. (firefrog)


Lesenswert?

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
von Achim S. (Gast)


Lesenswert?

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.

von Andreas B. (firefrog)


Lesenswert?

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. ;)

von Yalu X. (yalu) (Moderator)


Lesenswert?

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
von Andreas B. (firefrog)


Lesenswert?

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
von Purzel H. (hacky)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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 ;-)

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

von Jan H. (jan_h74) Flattr this


Lesenswert?

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).

von Oliver S. (oliverso)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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
von Yalu X. (yalu) (Moderator)


Lesenswert?

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?

von Wolfgang (Gast)


Lesenswert?

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

von m.n. (Gast)


Lesenswert?

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!

von Peter D. (peda)


Lesenswert?

m.n. schrieb:
> Kontaktprellen bei Hallsensoren?

Ich mache da keinen Unterschied zwischen Prellen und Störungen, es wird 
beides auf die gleiche Art gefiltert.

von LostInMusic (Gast)


Lesenswert?

>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.

von Andreas B. (firefrog)


Lesenswert?

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 ;)

von Wolfgang (Gast)


Lesenswert?

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

von m.n. (Gast)


Lesenswert?

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!

von Wolfgang (Gast)


Lesenswert?

m.n. schrieb:
> Meinst Du? Kennst Du denn Peter Green nicht?

Falsches Genre

von Andreas B. (firefrog)


Lesenswert?

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...

von m.n. (Gast)


Lesenswert?

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.

von Hugo H. (hugo_hu)


Lesenswert?

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.

von Andreas B. (firefrog)


Lesenswert?

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
von Hugo H. (hugo_hu)


Lesenswert?

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
von Andreas B. (firefrog)


Lesenswert?

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

von m.n. (Gast)


Lesenswert?

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.

von LostInMusic (Gast)


Lesenswert?

Welchen Zweck sollen die Variable "interruptCounter" und die Funktion 
"encode_read" erfüllen?

von Andreas B. (firefrog)


Lesenswert?

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.

von Andreas B. (firefrog)


Lesenswert?

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
Noch kein Account? Hier anmelden.