Mit Drehreglern ist es möglich die Anzahl der bewegten „Schritte“ zu erkennen. Anders als übliche Potentiometer, welche in verschiedenen analogen Modulen wie z.B. Joysticks verbaut sind, wird beim KY040 eine Drehung in beide Richtung erkannt. Solche Drehregler sind üblicherweise in Radios und anderen drehbaren Einstellungsmöglichkeiten verbaut.
In diesem Tutorial bauen wir aus einem solchen KY040 einen Lautsärkeregler für unseren Raspberry Pi. So können wir bspw. auch einfach per Hardware die Lautstärke unseres Live-Radios oder unserer Jukebox regeln.
Natürlich kann das Tutorial (in abgewandter Form) auch für andere Projekte verwendet werden. Helligkeitsregelung, Zeiten einstellen, etc. sind Optionen die mir spontan einfallen, allerdings kann so ziemlich alles, was per Drehknopf eingestellt werden soll, damit umgesetzt werden.
Zubehör
Neben einem Raspberry Pi wird ein Drehregler mit 5 Pins benötigt. Zum Anschluss an den Pi werden außerdem Female-Female Jumper Kabel (ebay) gebraucht.
Wer einen 3D Drucker besitzt, kann sich auch noch dazu einen aufsteckbaren Drehknopf drucken.
In dem Video habe ich zusätzlich die Daten auf einem 20×04 Zeichen Display anzeigen lassen (hier geht es zur Anleitung).
Raspberry Pi KY040 Verbindung
Der Drehregler hat insgesamt 5 Anschlüsse – davon zwei Spannungspole (VCC, GND) und einen zum Erfassen des Tastendrucks (SW). Mit Hilfe der restlichen zwei Pins (DT, CLK), kann die Richtung der Drehung festgestellt werden. Dabei wird beim Drehen eine Flanke erzeugt. Je nachdem, ob nach rechts oder links gedreht wird, ist die Spannung des anderen Pins digital 0 oder 1. Der SW Pin liefert hingegen solange eine Spannung, die der Knopf gedrückt wird.
Meine Pinbelegung sieht folgendermaßen aus:
Raspberry Pi | KY040 |
---|---|
GPIO 5 (Pin 29) | CLK |
GPIO 6 (Pin 31) | DT |
GPIO 13 (Pin 33) | SW |
3.3V (Pin 1) | + |
GND (Pin 6) | GND |
Um den Drehregler verwenden zu können, laden wir der Einfachheit halber eine Bibliothek, welche auf Github verfügbar ist.
git clone https://github.com/conradstorz/KY040
Die enthaltene „KY040.py“ Datei können wir in anderen Skripten importieren.
Drehregler Anwendungsbeispiel: Lautstärke ändern
Im folgenden Video habe ich den Drehregler KY040 als Drehknopf für die Lautstärke am Raspberry Pi genommen. Das Drücken des Knopfes lässt den Sound stumm schalten (Mute).
Um auch einen solchen Lautstärkeregler nach zu bauen, habe ich ein Skript geschrieben, welches Systemaufrufe zum Ändern der Lautstärke aufruft. Die Basis bildet die eben geladene Klasse, welche im selben Verzeichnis wie das nachfolgende Skript vorhanden sein muss.
Dazu können wir z.B. einfach in den Ordner wechseln und eine neue Datei erstellen:
cd KY040 sudo nano volume_regulator.py
Folgender Inhalt wird eingefügt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
import RPi.GPIO as GPIO from KY040 import KY040 import os, time def readVolume(): value = os.popen("amixer get PCM|grep -o [0-9]*%|sed 's/%//'").read() return int(value) def rotaryChange(direction): volume_step = 5 volume = readVolume() if direction == 1: os.system("sudo amixer set PCM -- "+str(min(100,max(0,volume + volume_step)))+"%") else: os.system("sudo amixer set PCM -- "+str(min(100,max(0,volume - volume_step)))+"%") def switchPressed(): print "button pressed" if __name__ == "__main__": CLOCKPIN = 5 DATAPIN = 6 SWITCHPIN = 13 GPIO.setmode(GPIO.BCM) ky040 = KY040(CLOCKPIN, DATAPIN, SWITCHPIN, rotaryChange, switchPressed) ky040.start() try: while True: time.sleep(0.05) finally: ky040.stop() GPIO.cleanup() |
Gespeichert wird mit STRG+O und mit STRG+X wird der Nano-Editor geschlossen.
Das Skript leitet im Grunde genommen nur die jeweiligen Bewegungen weiter. Dazu lesen wir zuerst die aktuelle Lautstärke aus und erhöhen bzw. verringern diese um 5%. Den Wert kannst du natürlich nach Belieben anpassen. Wer mehr über den Alsa-Mixer erfahren möchte, kann einen Blick in die Dokumentation werfen. Hiermit können alle Sound-relevanten Daten (Lautstärke, Einstellungen, etc.) ausgelesen werden und auch in anderen Projekten verwendet werden (Car-PC als Beispiel).
Wie im Video zu sehen ist, ist die Erkennung leider nicht immer absolut genau. Hier kann die bouncetime
geändert werden, um eine Variabilität zu gewährleisten. Ist der Wert allerdings zu groß, kann es sein, dass manche Drehungen gar nicht erkannt werden.
48 Kommentare
Was wäre denn der Code für Up/Down/Enter?
Ich überlege, so einen Regler als Steuerung für einen Squeezebox-Client zu verwenden.
Der Beispielcode ist doch unten dabei?
1.2.2017
An interesting tutorial. This has given me an idea.
Volume control using the potentiometer as volume limit, but including
with a digital potentiometer such as http://cdn-reichelt.de/documents/datenblatt/A200/DATASHEET_AD_8400.pdf (the data sheet is in English).
The idea being that when the device is switched on the volume to be increased
until equal to the analogue poti. This is to avoid the problen caused by cranking
the volume poti up to max ,switching off, then later switching on to get a large
scale dose of tinnitus.
When I get enough time free I’ll try that out and let you know, I have a bit of a problem with my right arm, it is difficult to build alone – I need help.
Perhaps someone has all ready done it,
My first thought was using a potentiometer as you said. But the problem ist, if you are near to the maximum (e.g. 9k from 10k) and you rotate again to the right: Then you will reach e.g. 1k and the volume is changing from 90% to 10%. This is why I decided to use use a rotary switch instead of a potentiometer. But if you have a better solution, I would be happy if you would share it with us.
Für die Genauigkeit einfach 2 Kondensatoren ( steht auch im Datasheet drin ) benutzen.
Eine gute Erklärung siehe hier:
Ich habe je einen 100nF Kondensatoren zwischen CLK und GND und zwischen DT und GND geschaltet – und es läuft tatsächlich viel besser!
hallo! das habe ich auch vor, habe diese https://www.conrad.at/de/keramik-kondensator-radial-bedrahtet-100-nf-50-vdc-10-holystone-rdcx104k050dka-1-st-531855.html Kondensatoren gekauft. Wie kann ich die zwischenschalten? danke
Hey Klaus
Kommt etwas drauf an, für welche Anwendung du den Drehregler verwendest. Ich habe die Verbindungskabel getrennt, den Kondensator dazwischen gelötet und das ganze mit einem Schrumpfschlauch eingepackt.
Lieber Gruss
Simon
Wie genau würde dann der Schaltplan aussehen? Ich habe jetzt einen Kondensator zwischen CLK und GND und zwischen DT und GND. CLK und DT gehen nachdem sie auf der einen Seite des Kondensators verbunden wurden wie oben gezeigt weiter und dann habe ich das andere Ende der beiden Kondensatoren mit GND verbunden, das ich an einer Stelle unterbrochen habe. Mein Problem ist jetzt, dass egal in welche Richtung ich drehe die Lautstärke runter geht, ansonsten macht der Kondensator seinen Job gut, der Regler ist viel flüssiger und gleichmäßiger.
Könntest du bitte konkret aufzeigen wie du das Display zum Lautstärke anzeigen programmiert hast? Bin daran fast am verzweifeln. Vielen lieben Dank!
Der Teil ist in diesem Tutorial gezeigt: HD44780 LCD Display per I2C mit dem Raspberry Pi ansteuern
Vielen Dank für das Toutorial
Sieht so aus, als dass auch ich als Newbie damit mein Ziel erreichen könnte. Ich habe dazu noch ein – zwei Fragen und bin sehr dankbar, wenn mir jeman weiterhelfen kann.
1. Muss ich die Bibliothek KY040 irgendwie einbinden, damit sie beim Start des Raspy gelesen wird?
2. Ich betreibe mein PI mit einer externen Soundkarte, fundktioniert das oben beschreibene Vorgehen trotzdem?
3. Ich habe Kodi 17 in einem Raspbian Jessie installiert, denkt Ihr, dass ich den Sound so trotzdem regeln kann?
Vielen Dank für eure Hilfe
Simon
1. Nein
2. Sollte trotzdem gehen. Ansonsten kannst du die zu regelnde Quelle auch angeben.
3. Ja, sollte möglich sein.
Vielen Dank Felix für deine rasche Antwort! Das stimmt mich sehr optimistisch auszuprobieren!
Weisst du wie ich die Quelle meiner Soundkarte auslesen- und welchen Pfad ich danach im Skript eingeben oder ersetzen muss?
Am besten du ließt dich ein bisschen in den amixer ein. Das Python Skript ruft ja lediglich den Shell Befehl dessen auf.
Soundkarte funktioniert leider nicht und ich habe nicht herausgefunden, wo ich die zu regelnde Quelle angeben kann.
Aber ich glaube dem Rätsel ein Schritt näher gekommen zu sein und zwar habe ich in der alsa.conf die Werte:
defaults.ctl.card
defaults.pcm.card
defaults.pcm.device
alle auf 1 (USB AUDIO Codec) gestellt. Beim Reboot wird nun die USB Soundkarte als default erkannt. Wenn ich jetzt aber das Skript „volume_regulator.py“ starte kommt beim Bedienen des Drehreglers folgende Fehlermeldung:
Traceback (most recent call last):
File „/home/pi/KY040/KY040.py“, line 43, in _clockCallback
self.rotaryCallback(GPIO.input(self.dataPin))
File „volume_regulator.py“, line 11, in rotaryChange
volume = readVolume()
File „volume_regulator.py“, line 8, in readVolume
return int(value)
ValueError: invalid literal for int() with base 10: ’84n84n‘
Weiss jemand von euch wie ich diesen Fehler beheben, bzw ich den USB AUDIO Codec in KY040.py integrieren kann? Oder gibt es einen anderen Weg die zu regelnde Quelle anzugeben?
Moin,
könnte ich mit dem Programmcode auch die Geschwindigkeit eines Motors steuen?
Wenn du einen DC Motor und PWM nutzt, dann ja.
Analog geht, aber die USB Soundkarte kann man damit nicht steuern.
Ich weiß nicht wie, wurde hier ja schon beschrieben.
Meine USB Soundkarte funktioniert einwandfrei.
Analog mit der int. Soundkarte macht keinen Sinn. Da kann man sich das Geld für den Drehschalter sparen. Oder hat noch jemand eine Lösung, falls nicht spart euch das Geld.
Hi,
ich habe alles so gemacht, wie es in dem Tutorial steht, allerdings habe ich damit leider keinen Erfolg.
Vllt kann mir ja jemand weiter helfen. Vielen Dank!
Grüße
P.S.: Ich weiss jetzt nicht welche Angaben noch notwendig sind, von dem her bitte fragen….
EIn bisschen präizer wäre vorteilhaft… Fehlermeldungen, etc, ..?
So sieht die Ausgabe aus:
pi@CarPi:/var/mail/KY040 $ sudo ./volume_regulator.py
./volume_regulator.py: 1: ./volume_regulator.py: import: not found
./volume_regulator.py: 3: ./volume_regulator.py: import: not found
./volume_regulator.py: 6: ./volume_regulator.py: Syntax error: „(“ unexpected
Entweder sudo python oder dem Skript einen Python Header geben.
Hat sich erledigt. War einfach nur mein blöder Fehler, das Script nicht mir python zu starten….
Grüße
P.S.: Vielen Dank für das Tutorial! Sehr leicht verständlich!
Hallo Felix,
vielen Dank für dieses TuT 🙂 Das hat mich erst auf die Idee gebracht, den KY040 zu verwenden!
Ein Problem habe ich noch, an dem ich seit gestern bastel.
In der Variable wird ja die aktuelle Lautstärke gespeichert, was bei dem analogen Ausgang des Rai kein Problem ist. Ich nutze jedoch eine USB Soundkarte und dort muss ich in der Variable (oder in zwei?) die Lautstärke je Kanal speichern. dies bekomme ich nicht eingebaut.
Auslesen und Ausgeben geht ja mit: amixer sget Speaker | grep ‚Right:‘ | awk -F'[][]‘ ‚{ print $2 }‘
Vielleicht kann mir jemand erklären, wie ich dies je als Variable speichere um es in Deinem Code zu verwenden.???
Vielen Dank und Grüße
Sören
Hallo!
Danke für das TuT. Hab es auch mit einer USB Soundkarte zum laufen gebracht. Das Problem hierbei war, dass beim Lautstärke auslesen der linken und rechte Kanal ausgegeben wurde. Hab ich recht einfach gelöst indem ich in Zeile 8 einfach [:-4] in den int Befehl eigegeben habe
return int(value[:-4])
Damit kommt jetzt bei der Ausgabe z.B. nur 67
Vorher war es
67
67
und Pyhton hat damit nichts anfangen können.
Ein Problem habe ich aber noch. Ich würde gerne, wie im Video zu sehen, mit einem Druck auf den Taster die Lautstärke stumm schalten. Bin noch absoluter Python Anfänger und habe es selbst leider nicht zum laufen gebracht. Wäre nett wenn mir wer helfen könnte.
Die Lösung ist mit
return int(value[:-4])
nicht wirklich optimal.
Sobald die Lautstärke einzeilig wird gibt Pyhton nur noch Fehler aus.
Habe aber jetzt eine Lösung gefunden. Beim Auslesen der Lautstärke einfach ein „uniq“ dranhängen. Damit werden Dupletten gelöscht und man hat nur noch z.B. 45 als Ausgabe.
value = os.popen(„amixer get PCM|grep -o [0-9]*%|sed ’s/%//’|uniq“).read()
Bei mir kommt der Fehler
TypeError: switchPressed() takes no arguments (1 given)
wenn ich an dem Drehregler drehe. Was kann ich da machen?
Und das wenn ich drücke
Simple mixer control ‚PCM‘,0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback -10239 – 400
Mono: Playback 400 [100%] [4.00dB] [on]
Ich denke du hast bei der Verkabelung etwas vertauscht und prüfe mal ob SW wirklich am richtigen Pin hängt. Denn die Meldung „TypeError: switchPressed() takes no arguments (1 given)“ sollte eigentlich kommen wenn man den Button drückt und nicht beim drehen. Und genauso sollte beim drehen die Meldung kommen, die bei dir kommt wenn du drückst. Bei dieser Meldung zeigt die letzte Zeile „Mono: Playback 400 [100%] [4.00dB] [on]“ an, dass die Lautstärke auf 100% eingestellt ist.
Den TypeError beim Drücken des Buttons hatte ich auch und ich hab in der volume_regulator.py einfach noch ein Argument bei der Funktion switchPressed() ergänzt. Sieht dann so aus (letzte beiden Zeilen der volume_regulator.py):
def switchPressed(tmp):
print „button pressed“
Hallo und erstmal danke für das tut.
es tut auch das was es soll, nur bin ich zu dumm den code zu ändern.
ich habe ein hifiberry amp2 am laufen den anlogen ausgang also der vom pi lässst sich steuern.
was muss ich denn wo ändern damit die lautsträke auch vom hifiberry sich ändernt ?
Den HifiBerry Amp2 zu steuern habe ich leider auch noch nicht hinbekommen und würde mich über Hilfe hier im Forum sehr freuen.
Hallo!
Würdet ihr auch den rotary Encoder verwenden um zwischen zB vier unterschiedlichen Getränken wählen zu können?
Wenn ja, wüsstet ihr eine Seite wo ich so einen Code finden könnte. Bin nämlich Python Anfänger.
Hallo
sehe ich das richtig das im o.g. Script die „mute“ funktion fehlt?
Zumindest funktioniert es bei mir nicht .
Es kommt nur die Meldung „button pressed“
Wie kann ich die Mutefunktion noch aktivieren.
Danke und Gruß Nico
Haha, das gleiche Problem hatte ich auch. Hab mir so geholfen, sicher eher pfusch, nachdem ich keine Ahnung hab, aber es tut exakt, was es soll:
def switchPressed(pin):
volume = readVolume()
print(„button connected to pin:{} pressed“.format(pin))
if pin == 13:
os.system(„sudo amixer set PCM — „+str(min(100,max(0,0)))+“%“)
print(volume)
if… bräuchte es eigentlich nicht, aber ist „in die Zukunft gedacht“
print… hab ich zweimal nur zur Erfolgskontrolle drin, kann man auch weglassen.
Schöne Grüße
Hallo!
Ich habe die Anleitung aufs -kleinste befolgt und weiß nicht warum, aber sobald ich den Regler drehe, wird die Stromzufuhr unterbrochen und der Pi startet von neuem.
Was habe ich falsch gemacht?
Basis meiner Installation ist Raspberry Buster, Phoniebox von Miczflor, GPIO.Buttons und das Ky040-script.
Danke!
Hallo,
genau das gleiche Problem habe ich auch. Jedoch habe ich auch einen HifiBerry AMP2 dazwischen hängen. Hab die Verkabelung mehrfach geprüft und ist in Ordnung.
Habe den Fehler gefunden: War doch die Verdrahtung. Ich hatte nicht aufgepasst und CLK an 3.3V laufen. Habe dann + auf 3.3V und CLK richtig angeschlossen, dann ging es. 😉
Hi, ich möchte das in Verbindung mit dem piCorePlayer machen. Leider akzeptiert das Image schon den Befehl „git clone https://github.com/conradstorz/KY040“ nicht.
Hat jemand eine Lösung, wie das mit dem piCorePlayer klappt?
Hallo, weißt du wie man einfach nur die Systemlautstärke verändern kann (also ohne das Potentiometer). Also, dass eben im Skript steht, dass das Volumen auf 25 gestellt werden soll, sobald das Skript gestartet wird.
Hallo, ich versuche das ganze auf dem Raspberrypi4 bekomme aber nur diesen Fehler als output
„`
Traceback (most recent call last):
File „/home/pi/KY040/KY040.py“, line 43, in _clockCallback
self.rotaryCallback(GPIO.input(self.dataPin))
File „volume_regulator.py“, line 11, in rotaryChange
volume = readVolume()
File „volume_regulator.py“, line 8, in readVolume
return int(value)
ValueError: invalid literal for int() with base 10: “
„`
Irgendwelche Ideen wie ich hier weiterkommen kann?
Tausend dank!
hallo hast du eine Lösung gefunden? Ich habe genau die gleiche Fehlermeldung
Vielen Dank
Bei mir das gleiche. Komme hier leider auch nicht mehr weiter…
Hi.
Lösung hat Thomas am 03.05.2018 schon geposted.
value = os.popen(„amixer get Master|grep -o [0-9]*%|sed ’s/%//’|uniq“).read()
Gruß
Hallo,
Danke schon einmal für das tolle Tutorial, leider klappt es bei mir nicht.
Ich habe den Ordner von Github gezogen und in dem Ordner ein .py File erzeugt (radio_volume.py) , mit dem obenstehenden Quellcode. Wenn ich es ausführen möchte, bekomme ich folgende Fehlermeldeung:
Traceback (most recent call last):
File „radio_volume.py“, line 29, in
ky040 = KY040(CLOCKPIN, DATAPIN, SWITCHPIN, rotaryChange, switchPressed)
NameError: name ’switchPressed‘ is not defined
Was habe ich falsch gemacht?
Danke im Voraus!
hi
geht das auch, wenn zusätzlich zum hifiberry noch ein 3.5″ display oben drauf ist?
pins sind ja so nicht frei
Hallo ich bekomme den Regler einfach nicht zum funktionieren und weiß nicht mehr was ich noch ändern muß.
ich habe die Klammern bei den Print Kommandos bereits gesetzt, aber das scheint nicht das Problem zu sein.
pi@rp4:~ $ python3 /home/pi/KY040/volume_regulator.py
Traceback (most recent call last):
File „/home/pi/KY040/volume_regulator.py“, line 32, in
ky040.start()
File „/home/pi/KY040/KY040.py“, line 34, in start
GPIO.add_event_detect(self.clockPin, GPIO.FALLING, callback=self._clockCallback, bouncetime=self.DEBOUNCE)
RuntimeError: Failed to add edge detection
pi@rp4:~ $
Kann Mir hier jemand helfen?