Debouncing the KY-040 Gray-Code Encoder (Gewicht springt auf Werte ausserhalb der 5 g-Schritte)

Ich hätte noch eine kleine weitere Herausforderung mit der Bitte um kurze Bewertung:

Wenn ich im Setup-Füllmenge ein Glas umdefiniere, habe ich das Problem, dass ich sehr oft die gewünschte Füllmenge nicht exakt “eindrehen” kann, zB anstelle 500g entweder 499g oder 504g. Mir ist schon klar, dass Füllmengen im 5g-Raster sinnvoll sind, aber hier hapert es ein wenig an der Umsetzung bzw. ausreichender Würdigung von möglichen Störquellen (Prellen etc.).
(Info: In meinem HaniMandl ist der hier verbreitete Drehwinkelgeber mit Taster KY-040 verbaut)

Meine Lösungsgedanken waren/sind:

  1. Störungsursache finden und abstellen

  2. Workaround: Füllmengenwerte auf 0 oder 5 auf- bzw. abrunden

  3. Workaround: Steuerung der Schrittweite in Abhängigkeit der Drehgeschwindigkeit des Encoders, zB
    schnell: 10g-Sprünge
    langsam: 1g-Schritte

  4. Workaround: Eingaberoutine der Füllmengenwerte ändern auf stellenweise Eingabe, Tausender -> Hunderter -> Zehner -> Einer mit allen erlaubten Ziffern, Quittierung per QuadEncoderTaster

Ich persönlich würde die Lösung #4 favorisieren und #1 nicht vernachlässigen.
Was meinen hier die Entwickler?

1 Like

Danke @RoSch für den bug report, könntest du testweise einmal das Release Version 0.2.8 · ClemensGruber/hani-mandl · GitHub ausprobieren. Bei mir springt die Anzeige beim Drehen des rotary auch auf z.B. 203 g, dann wird aber sofort das Gewicht auf 205 g korrigiert, d.h. immer auch die nächsten vollen x5 oder x0 g gerundet. Ich vermute, dass da an irgendeiner Position beim Runde was nicht passt.

Vielleicht kannst du auch nochmal exakt beschreiben wie du zu einem “schiefen” Wert im Display kommst, damit ich das nachvollziehen kann. Nur durch Drehen des encoders?

[edit] @aholzhammer Konnte es jetzt auch mit der oben verlinkten Code-Version reproduzieren, bei mir springt das Gewicht auf x2 bzw. x7 und bleibt dann in 5 g-Schritten dort. Ist aufgetreten also ich den rotary testweise sehr schnell bewegt habe. Vermutlich erfolgt ein refres / Runden des Wertes und gleichzeitig kommt ein neuer Impuls des rotarys rein. So in etwa meine Vermutung ohne in den code geschaut zu haben.

Ja, der KY-040 liefert pro Rastung zwei Impulse. Merkt man, wenn man ihn im Manuell-Modus langsam zwischen zwei Rastungen bewegt, dann hängt der Winkel auch auf x2 bzw. x7 bevor er umspringt.
Das wird über die ROTARY_SCALE angepasst, aber vermutlich verliert er beim schnellen Drehen ab und an einen Interrupt und hängt dann auf Halbmast.

Als Fixes gehen mit vertretbarem Aufwand an sich nur #1 oder #2.

2 Likes

@clemens
Ja, habe ich gerade getestet, das Fehlerbild gibt es auch dort.
Vor Wechsel von der dev-Version auf 2.0.8 hatte ich folgende Füllmengen definiert:
30g DIB
250g DIB
499g DIB
500g TOF
500g DIB
Ich habe nach Releasewechsel versucht, den 3. Listeneintrag zu korrigieren und den 4. abzuändern, Ergebnis nach diversen Drehtast"spielereien":
30g DIB
250g DIB
504g DIB
317g TOF
500g DIB

Wie bin ich dahin gekommen? Na, ich wollte einfach alle Setup-Funktionen mal ausprobieren und praxisnahe Definitionen hinterlegen, so wie ich es zB in meiner Imkerei bräuchte. So auch bei Füllmenge. Ich arbeite normalerweise mit DIB-Gläsern, seit Ende letzten Jahres auch mit 30g-Gläsern, und wollte einfach die von mir genutzten Glastypen als erste Listeneinträge definieren.
So ist es zu dem “verunglückten” 3. Eintrag gekommen.

Und ja, es hängt zusammen mit der Geschwindigkeit der Bedienung des Drehwinkelgebers. Ich dachte aber zunächst, es wäre eine defekter Geber, nach Tausch blieb aber das Problem, also entweder Serienfehler bei der Herstellung oder Softwareproblem beim Abfangen des Prellens, oder oder …

Das Phänomen des Springens habe ich auch beim einfachen Wechseln der Menüpunkte im Setup, da kommt es auch vor, dass eine gewünschte Auswahl übersprungen wird …

Rührt also von der gleichen Baustelle her.
Meine Workaround-Vorschläge würden also nur die Füllmengenabweichung korrigieren, wesentlicher scheint mir daher die Störungsursachenanalyse und -beseitigung zu sein …

Ich helfe da mit meinen kleinen Möglichkeiten gerne mit …

Euer Roland

2 Likes

Das ist ein guter Hinweis, ich muss mir mal das Datenblatt und die Funktionsweise von dem KY-040 genauer anschauen, also vlt. doch nur ein Timing-Problem.

Wir müssen ja nicht gleich mit Kanonen auf Spatzen schießen: Ggf. könnte sich aber langfristig eine Bibliothek um den rotary kümmern, mal als erste Sammlung:

Infos und Doku Funktionsweise Rotary Encoder und Arduino-Libs



Libs für den ESP32


1 Like

Danke Clemens. Bei Bisherige ESP32Servo-Bibliothek mit der im Arduino-Bibliotheksverwalter ersetzen haben wir gesehen, dass Kevin Harrington die ESP32Servo-Bibliothek qualitativ hochwertig vorantreibt und pflegt.

Genauso verhaelt es sich auch bei der Bibliothek GitHub - madhephaestus/ESP32Encoder: A Quadrature and half quadrature PCNT peripheral driven encoder library supporting 10 encoders, sie ist ebenfalls auf Platform.IO bei ESP32Encoder by Kevin Harrington verfuegbar.

Ich wuerde dieser Bibliothek also tendenziell den Vorzug geben, auch ohne die anderen Module vorher speziell unter die Lupe genommen zu haben.

@clemens @RoSch Ich kann das bei mir auch (mit Gewalt) nachstellen. Wenn ich heftig am Rad drehe, verpasst der Rotary ab und an einen Tick und bleibt auf einer nicht durch 5 teilbaren Zahl stehen. Beim nächsten Dreh nach rechts/links wird das aber korrigiert.
Ist das bei euch anders?

@Andreas Die ESP32Encoder habe ich in einem Test-Code, die ist gut. Alle anderen 4-12 Libraries, die ich ausprobiert habe, waren Mist. Daher auch die “eigene” Implementierung.

Das Problem mit dem ESP32Encoder ist, dass er nicht im Hintergrund verschiedene virtuelle Regler mit verschiedenen Schrittweiten zählt, so wie es der Hanimandl macht. Da ist der Portierungsaufwand höher als initial gedacht.

1 Like

So heftig, wie Du schreibst, brauche ich nicht am Rotary zu drehen, um den unerwünschten Effekt beobachten zu können, insbesondere feststellbar schon bei der Auswahl der 1. Ebene im Setup-Modus …
Am Wochenende habe ich wieder Zeit, mir das auch im Programmcode genauer ansehen zu können und werde dann berichten.

Hast du das mit unterschiedlichen Encodern getestet? Du bist der Erste, der das meldet.

Bei mir ist das anders, wenn der mal “verrutscht” ist bleibt die Abweichung bestehen. Drehen nach links / rechts änder nichts, sondern erhöht oder reduziert das Gewicht nur um 5 g im “falschen” Raster. Als workaround muss ich auf das Minimum 30 g zurückdrehen, da wird der Wert dann korrigiert und wieder bis 500 g raufdrehen.

Dass in der Anzeige mal ein nicht x0 / x5-Wert stehn bleibt und beim nächsten Drehen korrigiert wird habe ich gerade 1x beim Testen gesehen, ist mir bisher allerdings nicht aufgefallen, ggf. ein anderes Problem oder Teilproblem, das seltener auftritt?

Unschöne Erkenntnis nach längeren Tests:

Die ESP32Encoder ist für Quadrature Encoder, unser KY-040 ist ein Gray-Code Encoder. Das funktioniert also nur bedingt, jede Drehung führt zu zwei Sprüngen. Das beschreibt der Entwickler auch genau so: Double count in example · Issue #28 · madhephaestus/ESP32Encoder · GitHub
Prinzipiell geht das, aber jede Änderung an der Library könnte sich anders verhalten. Das scheint mir keine Option.

Der Encoder selbst ist vermutlich ein PEC11L Rotary Encoder. Der ist nur spezifiziert bis 60rpm!


Bei der Geschwindigkeit dürfte nix passieren :slight_smile:

Ich habe keine Gray Code Library für den ESP32 gefunden, die nicht auf Interrupts setzt.

3 Likes

Im oben verlinkten PEC11L datasheet steht:

Quadrature Output Table

Doch ein Quadrature Encoder? Kenn mich bisher bei Encodern gar nicht aus und weiß nicht, was die Elektronik auf “unserem” KY-040 macht. [edit] nicht der KY-040, ggf. aber ähnlich: Ollie's Workshops: Rotary Encoder with Switch da sind auf dem Platinchen nur ein paar Widerstände und eine (LE)Diode.

There are a large number of mechanical rotary encoders available on Amazon, eBay, and Aliexpress. Some of them are plain encoder switches and some of them have the pull-up resistors on a small breakout board. The pull-up resistors are not required because most MCUs can be configured to use internal pull-up resistors.

Bist du sicher, dass beim KY-040 ein PEC11L verbaut ist oder wie ist da die Quellenlage?

Unter GitHub - Billwilliams1952/KY-040-Encoder-Library---Arduino: Arduino library for the KY-040 Encoder wird für den KY-040 ein cap auf der clock line empfohlen:

The KY-040 encoder library uses interrupts on the clock line. Because of switch bounces, a 470 nF (0.47 uF) capacitor is required on each encoder clock (CLK) pin to ground.

Falls du @RoSch einen Kondensator im Bereich 470 nF rumliegen hast wäre es prima, wenn du testen könntest, ob das Problem damit immer noch auftritt.

Noch etwas in Richtung Hardware von Ollie's Workshops: Rotary Encoder with Switch :

In case of a metal shaft and a metal knob, the static charge can cause additional problems.

Verwendest du den Rotary mit knob oder drehst du momentan direkt an der Achse? Falls ja und du einen Knopf da hast, versuche dem mal zu verwenden. Der auf der Teileliste verlinkte KY-040 hat einen Metall-Knopf, ist innen aber aus Konststoff, d.h. mit dem Knopf sollte statische Aufladung weniger ein Problem sein.

Vermutlich variiert das auch je nach Hersteller… Der Bug-Report hier beschreibt aber genau das Verhalten: Double count in example · Issue #28 · madhephaestus/ESP32Encoder · GitHub
Ich hab auch keinen Plan von Binary, Quadruple oder Gray Code Encodern und glaube dem Autor einfach.

Lässt sich auch gerne mit dem Beispiel aus der Library nachstellen.

Der wesentliche Vorteil der ESP32Encoder Library ist übrigens, dass sie genau nicht mit Interrupts arbeitet sondern den Hardware Pulse Counter nutzt. Bisher habe ich keine andere Library gefunden, die das so macht.

1 Like

Der Grund ist wahrscheinlich, dass nur der ESP32 eine solche Einheit besitzt?

Mit Interrupts wird aber dennoch gearbeitet, nicht? Nur muss man halt im Userspace nicht mehr jeden Rotary-Impuls per Interrupt auswerten sondern der Pulse Counter stellt Highlevel-Events zur Verfuegung, die dann per Interrupts signalisiert werden?

Die Doku der NodeMCU Firmware beschreibt das besser:

Kevin Harrington empfiehlt das ebenfalls:

Was der Autor hier anspricht ist ein Feature, das die Pulse Counter Einheit des ESP32 bereits ab Werk ermoeglicht (siehe filtering pulses) und der Treiber bereits entsprechend ansteuert.

Ob das in der Praxis jedoch wirklich ausreichend gut klappt, kann wahrscheinlich @weef besser bewerten.

vielleicht mal diese lib hier ansehen, die könnte mehrere Probleme auf einmal erledigen und dabei sogar noch gesuchte features mitbringen:

This is an adaptation of Ben Buxton’s excellent rotary library and implements additional features for encoder rotation speed.

Features

  • Debounce handling with support for high rotation speeds
  • Correctly handles direction changes mid-step
  • Checks for valid state changes for more robust counting and noise immunity
  • Interrupt based or polling in loop()
  • Counts full-steps (default) or half-steps
  • Calculates speed of rotation
1 Like