Hallo allerseits,
zwar habe ich das folgende mit einem Cubietruck und nicht mit einem Raspberry Pi gemacht, aber weil hier mehr Leute reinschauen und ich eigentlich vor keinem hardwarespezifisches Problem stehe, erlaube ich mir einfach hier ein Thema aufzumachen.
Ich habe an die GPIO Pins ein paar Taster und LEDs angeschlossen und ein Skript mit einer Endlosschleife geschrieben, das über das sysfs die Taster abfragt und die LEDs steuert, damit ich einen mpd zumindest rudimentär am Gerät selbst bedienen kann, was zwar nicht sehr elegant ist und dank sysfs sehr viel Rechenleistung verbraucht, aber zumindest zuverlässig funktioniert.
Jetzt will ich aber etwas mehr und steuere zusätzlich über I²C ein Display an und werte außerdem 2 Drehimpulsgeber aus.
Dank eines Ports von WiringPi auf den Cubietruck kann ich mit einem von den Hardwarechecks befreiten py-gaugette Drehimpulsgeber auslesen. Also habe ich mir basierend darauf meine eigenen Workerthreads gebastelt, die nur die ganze Zeit Taster und Drehimpulsgeber abfrage und mit Callbackfunktionen etwas im Hauptprogramm auslösen sollen und genau dabei stoße ich immer wieder auf Probleme.
In das python-Forum, in dem auch schon einen Thread eröffnet habe, traue ich mich vorläufig noch nicht wieder, weil ich das Gefühl habe zu weit daneben zu stehen um dort sinnvolle Fragen stellen zu können.
Also poste ich einmal mein Testprogramm, das schon nicht richtig funktioniert.
import math
import threading
import time
import random
import mpd
import wiringpi2
#1 und 2 fuer Pull-up und -down sind beim Cubietruck vertauscht
PUD_UP=1
PUD_DOWN=2
PUD_OFF=0
wiringpi2.wiringPiSetup()
class RotaryEncoder(threading.Thread):
def __init__(self, a_pin, b_pin, pin_pud, callback):
[…]
class SimpleSwitch(threading.Thread):
def __init__(self, pin, pin_pud, debounce, callback):
[…]
localmpd = mpd.MPDClient()
localmpd.connect("localhost", 6600)
def rotary_a_event(event):
if event == -1:
print "rotate-"
elif event == 1:
print "rotate+"
return
def rotary_b_event(event):
if event == -1:
localmpd.previous()
elif event == 1:
localmpd.next()
return
def reset_playlist(event):
if event == -1:
localmpd.clear()
def play(event):
if event == -1:
localmpd.clear()
if localmpd.status()['state'] == 'play':
localmpd.pause()
else:
if localmpd.status()['playlistlength'] == '0':
albums = localmpd.list("album")
localmpd.findadd("album", albums[random.randint(0, len(albums)-1)])
localmpd.play()
encoder_a = RotaryEncoder(28, 29, PUD_DOWN, rotary_a_event)
encoder_a.start()
encoder_b = RotaryEncoder(26, 27, PUD_DOWN, rotary_b_event)
encoder_b.start()
switch_a = SimpleSwitch(20, PUD_UP, 0.001, reset_playlist)
switch_a.start()
switch_b = SimpleSwitch(20, PUD_UP, 0.001, play)
switch_b.start()
while True:
time.sleep(1)
Alles anzeigen
Ich hoffe es ist einigermaßen klar, was das passieren soll:
- der erste Drehimpulsgeber encoder_a soll nur die Meldungen "rotate-" und "rotate+" ausgeben, wenn daran gedreht wird und das funktioniert auch soweit.
- der zweite Drehimpulsgeber encoder_b soll zum nächsten oder vorigen Stück springen, was er aber nur tut, wenn man nicht zu schnell daran dreht. Hier ist mir schon so viel unklar, dass weh tut...
Blockieren die Callbackfunktion den Workerthread oder laufen schon mehrere Callbackfunktionen paralell, wenn ich einigermaßen schnell drehe?
- der Taster switch_a soll die Playlist leeren und funktioniert für sich gnommen einigermaßen problemlos nur in Verbindung mit
- dem anderen Taster switch_b kommt es zu merkwürdigen Problemen. Der sollte zwischen Play/Pause umschalten und wenn die Playlist leer ist, ein zufälliges Album auswählen und zur Wiedergabeliste hinzufügen.
Die Anweisungen stammen übrigens aus meinem ersten uneleganten Skript mit der Endlosschleife, das aber wie gesagt problemlos funktioniert hat.
Außerdem ist beim Testen dieser für mich endgültig unerklärliche Fehler aufgetreten
$ python test2.py
Exception in thread Thread-4:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
self.run()
File "test2.py", line 75, in run
self.callback(delta)
File "test2.py", line 115, in play
if localmpd.status()['state'] == 'play':
KeyError: 'state'
Exception in thread Thread-3:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
self.run()
File "test2.py", line 75, in run
self.callback(delta)
File "test2.py", line 110, in reset_playlist
localmpd.clear()
File "/usr/local/lib/python2.7/dist-packages/python_mpd2-0.5.4-py2.7.egg/mpd.py", line 600, in decorator
return wrapper(self, name, args, bound_decorator(self, returnValue))
File "/usr/local/lib/python2.7/dist-packages/python_mpd2-0.5.4-py2.7.egg/mpd.py", line 238, in _execute
return retval()
File "/usr/local/lib/python2.7/dist-packages/python_mpd2-0.5.4-py2.7.egg/mpd.py", line 595, in decorator
return function(self, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/python_mpd2-0.5.4-py2.7.egg/mpd.py", line 365, in _fetch_nothing
raise ProtocolError("Got unexpected return value: '%s'" % line)
ProtocolError: Got unexpected return value: 'volume: 100'
Alles anzeigen
Kann das vielleicht (auch) daran liegen, dass ich parallel zu meinem Skript mpdlcd laufen lasse, um das Display über lcdproc anzusteuern?
Die Workerthreads habe ich der Übersichtlichkeit wegen nicht gepostet, sie scheinen aber zu funktionieren. Wenn es für die Fehlersuche wichtig ist oder sie jemand aus anderen Gründen gerne sehen würde, poste ich sie selbstverständlich gerne - ich habe sie mir aber hautpsächlich mithilfe des verlinkten py-gaugette zusammengebastelt.
Es wäre toll, wenn sich das jemand ansehen und mir weiterhelfen könnte... aber ich muss euch vorwarnen, in dem Fall kommen noch einige weitere Fragen auf euch (und eventuell das python-Forum) zu.
viele Grüße,
smutbert