Moin,
ich habe schon ein kleines Programm geschrieben, dass beim Eingang einen bestimmten Ton abspielt.
Leider weiß ich nicht ganz wo das Problem liegt, wenn das Programm länger aktiv ist stürzt es einfach ab und es funktioniert nicht mehr.
Findet ihr vielleicht einen Fehler im Programm?
Bin leider echt überfordert was der Fehler sein kann.
Programm:
from RPi import GPIO
from queue import Queue
import time
import vlc
PIN_LEFT_PLAYER = 19
PIN_RIGHT_PLAYER = 21
PIN_Start = 20
def initialize():
queue = Queue()
GPIO.setmode(GPIO.BCM)
for pin in [PIN_LEFT_PLAYER, PIN_RIGHT_PLAYER, PIN_Start]:
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.add_event_detect(pin, GPIO.FALLING, callback=queue.put, bouncetime=3000)
return queue
def main():
try:
queue = initialize()
while True:
pin = queue.get()
#Tor_Links
if pin == (PIN_LEFT_PLAYER):
p = vlc.MediaPlayer("/home/pi/Desktop/Playsound/songs/Air_Horn.mp3")
p.play()
#tor_rechts
elif pin == PIN_RIGHT_PLAYER:
p = vlc.MediaPlayer("/home/pi/Desktop/Playsound/songs/Air_Horn.mp3")
p.play()
#Start
elif pin == PIN_Start:
p = vlc.MediaPlayer("/home/pi/Desktop/Playsound/songs/Boxing Bell Sound Effect.mp3")
p.play()
finally:
GPIO.cleanup()
if __name__ == "__main__":
main()
Song beim PIN Eingang
- __blackjack__
- User
- Beiträge: 13116
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Danoo: Was heisst denn „abstürzen“ und „funktioniert nicht mehr“ genau? Gibt es eine Fehlermeldung beim Absturz? Bis wo hin kommt es beim Neustart?
Am Code direkt fällt mir nichts auf, ich frage mich allerdings wie oft parallel man Sounds starten kann/darf. Kannst Du denn Absturz an der Anzahl der Abspielvorgänge festmachen?
Am Code direkt fällt mir nichts auf, ich frage mich allerdings wie oft parallel man Sounds starten kann/darf. Kannst Du denn Absturz an der Anzahl der Abspielvorgänge festmachen?
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Ich habe sowas bei RPi.GPIO schon öfter erlebt. Keine Ahnung warum. Irgendwas verklemmt da. Ich würde es mal mit pigpio probieren. NICHT (einfach so) mit gpiozero, denn das benutzt defaultmässig RPi.GPIO. Man kann es auf pigpio umlenken.
- noisefloor
- User
- Beiträge: 3856
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
wie startest du das Programm? Wenn du es über eine systemd Service Unit startest solltest du im Log von systemd eine Fehlermeldung finden.
Wenn du es im Terminal im Vorderggrund laufen lässt sollte da eine Fehlermeldung erscheinen.
Gruß, noisefloor
wie startest du das Programm? Wenn du es über eine systemd Service Unit startest solltest du im Log von systemd eine Fehlermeldung finden.
Wenn du es im Terminal im Vorderggrund laufen lässt sollte da eine Fehlermeldung erscheinen.
Gruß, noisefloor
Die Lösung wird ganz einfach sein. Erstelle ausserhalb der Schleife die vlc-Objekte mit verschiedenen Variablen. z.B. left_song = vlc.MediaPlayer("/home/pi/Desktop/Playsound/songs/Air_Horn.mp3")
Dann lässt Du diese mit in dem Fall left_song.play() an der jeweiligen Stelle abspielen.
Dann lässt Du diese mit in dem Fall left_song.play() an der jeweiligen Stelle abspielen.
Alles was wir sind ist Sand im Wind Hoschi.
Einmal die Fehler Meldung, :__blackjack__ hat geschrieben: ↑Sonntag 3. Juli 2022, 08:20 @Danoo: Was heisst denn „abstürzen“ und „funktioniert nicht mehr“ genau? Gibt es eine Fehlermeldung beim Absturz? Bis wo hin kommt es beim Neustart?
Am Code direkt fällt mir nichts auf, ich frage mich allerdings wie oft parallel man Sounds starten kann/darf. Kannst Du denn Absturz an der Anzahl der Abspielvorgänge festmachen?
[00000000149f6040] alsa audio output error: cannot open ALSA device "default": Connection refused
[00000000149f6040] main audio output error: Audio output failed
[00000000149f6040] main audio output error: The audio device "default" could not be used:
Connection refused.
[00000000149f6040] main audio output error: module not functional
[000000798c12c90] main decoder error: failed to create audio output
[0000000014a53b50] vlcpulse audio output error: PulseAudio server connection failure: Connection terminated
ALSA lib pulse.c:242: (pulse_ connect) PulseAudio: Unable to connect: Connection terminated
[0000000014a53b50] alsa audio output error: cannot open ALSA device "default": Connection refused
[0000000014a53b50] main audio output error: Audio output failed
[0000000014a53b50] main audio output error: The audio device "default" could not be used:
Connection refused.
[0000000014a53b50] main audio output error: module not functional
[0000007eecc166d0] main decoder error: failed to create audio output
Wie funktioniert das genau, habe dazu auch im Internet nicht viel gefunden
Okay ich würde das mal morgen ausprobieren da ich meinen PI momentan nicht dabei habe .hyle hat geschrieben: ↑Sonntag 3. Juli 2022, 14:23 Die Lösung wird ganz einfach sein. Erstelle ausserhalb der Schleife die vlc-Objekte mit verschiedenen Variablen. z.B. left_song = vlc.MediaPlayer("/home/pi/Desktop/Playsound/songs/Air_Horn.mp3")
Dann lässt Du diese mit in dem Fall left_song.play() an der jeweiligen Stelle abspielen.
Meinst du das so?
Bin leider noch nicht so lange und bin noch ein kleiner Anfänger
from RPi import GPIO
from queue import Queue
import time
import vlc
PIN_LEFT_PLAYER = 19
PIN_RIGHT_PLAYER = 21
PIN_Start = 20
def initialize():
queue = Queue()
GPIO.setmode(GPIO.BCM)
for pin in [PIN_LEFT_PLAYER, PIN_RIGHT_PLAYER, PIN_Start]:
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.add_event_detect(pin, GPIO.FALLING, callback=queue.put, bouncetime=3000)
return queue
def main():
try:
queue = initialize()
while True:
pin = queue.get()
#Tor_Links
if pin == (PIN_LEFT_PLAYER):
left_song.play()
#tor_rechts
elif pin == PIN_RIGHT_PLAYER:
right_song.play()
#Start
elif pin == PIN_Start:
begin_song.play()
begin_song = vlc.MediaPlayer("/home/pi/Desktop/Playsound/songs/Boxing Bell Sound Effect.mp3")
right_song = vlc.MediaPlayer("/home/pi/Desktop/Playsound/songs/Air_Horn.mp3")
left_song = vlc.MediaPlayer("/home/pi/Desktop/Playsound/songs/Air_Horn.mp3")
finally:
GPIO.cleanup()
if __name__ == "__main__":
main()
Fast! Die drei Zeilen direkt über while True: setzten meinte ich eigentlich, denn unter der Schleife werden diese nie erreicht.
Btw. Poste Code bitte immer in einem Codeblock, sonst gehen die Einrückungen verloren! Verwende dazu den vollständigen Editor und dort den </> Button.
Alles was wir sind ist Sand im Wind Hoschi.
Statt Code zu kopieren benutzt man die passenden Datenstrukturen:
Code: Alles auswählen
from queue import Queue
from pathlib import Path
from RPi import GPIO
import vlc
PIN_LEFT_PLAYER = 19
PIN_RIGHT_PLAYER = 21
PIN_START = 20
SONG_PATH = Path("/home/pi/Desktop/Playsound/songs")
SONGS = {
PIN_START: "Boxing Bell Sound Effect.mp3",
PIN_LEFT_PLAYER: "Air_Horn.mp3",
PIN_RIGHT_PLAYER: "Air_Horn.mp3",
}
def initialize():
queue = Queue()
GPIO.setmode(GPIO.BCM)
for pin in [PIN_LEFT_PLAYER, PIN_RIGHT_PLAYER, PIN_START]:
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.add_event_detect(pin, GPIO.FALLING, callback=queue.put, bouncetime=3000)
return queue
def main():
try:
queue = initialize()
songs = {
pin: vlc.MediaPlayer(SONG_PATH / song)
for pin, song in SONGS.items()
}
while True:
pin = queue.get()
songs[pin].play()
finally:
GPIO.cleanup()
if __name__ == "__main__":
main()
Moin, ich habe mir mal den Code genauer angekuckt und ausprobiert. leider spielt er nur ein mal den Ton ab.
Habt ihr noch einen Lösungsvorschlag?
Habt ihr noch einen Lösungsvorschlag?
Sirius3 hat geschrieben: ↑Montag 4. Juli 2022, 17:46 Statt Code zu kopieren benutzt man die passenden Datenstrukturen:Code: Alles auswählen
from queue import Queue from pathlib import Path from RPi import GPIO import vlc PIN_LEFT_PLAYER = 19 PIN_RIGHT_PLAYER = 21 PIN_START = 20 SONG_PATH = Path("/home/pi/Desktop/Playsound/songs") SONGS = { PIN_START: "Boxing Bell Sound Effect.mp3", PIN_LEFT_PLAYER: "Air_Horn.mp3", PIN_RIGHT_PLAYER: "Air_Horn.mp3", } def initialize(): queue = Queue() GPIO.setmode(GPIO.BCM) for pin in [PIN_LEFT_PLAYER, PIN_RIGHT_PLAYER, PIN_START]: GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) GPIO.add_event_detect(pin, GPIO.FALLING, callback=queue.put, bouncetime=3000) return queue def main(): try: queue = initialize() songs = { pin: vlc.MediaPlayer(SONG_PATH / song) for pin, song in SONGS.items() } while True: pin = queue.get() songs[pin].play() finally: GPIO.cleanup() if __name__ == "__main__": main() [/quote]
- DeaD_EyE
- User
- Beiträge: 1021
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Ich habe mal das Programm in zwei Teile aufgesplittet. vlc_simple kann nur eine Funktion: play(song) und die Logik wann play(song) ausgelöst wird in einer anderen Datei.
vlc_simple.py
event_player.py
Ich höre nur nichts, da ich einen RPi0W2 zum Testen verwendet habe und mein Mini-HDMI-Adapter leider nicht finde.
Beim RPi4 hatte ich jetzt keine Lust, das Gehäuse nur zum Testen auseinander zu bauen.
Kurzes Beispiel mit atexit (für GPIO.cleanup):
Und der Code:
Ich hoffe, dass das ein bisschen weiterhilft. Pfade usw. müssen natürlich angepasst werden, da es nicht mit deinen Daten übereinstimmt.
vlc_simple.py
Code: Alles auswählen
from __future__ import annotations
from pathlib import Path
import vlc
# Nur eine Instanz des MediaPlayer
# Gleichzeitiges abspielen ist dann nicht möglich
_player = vlc.MediaPlayer()
def play(song: str | Path) > bool:
song = Path(song)
if not song.exists():
print(f"Datei existiert nicht: {song}")
return False
# die Methode set_media benötigt eine vlc.Media instanz
_player.set_media(vlc.Media(song))
# Player stoppt nach set_media
# Player mit dem neuen audio starten
_player.play()
return True
event_player.py
Code: Alles auswählen
import time
from pathlib import Path
from RPi import GPIO
from vlc_simple import play
SONG_PATH = Path("/home/deadeye/Musik")
# hier gehe mit Absicht explizit vor
# kann man natürlich in einer Dict-Comprehension machen
SONGS = {
17: SONG_PATH / "南宮嘉駿-回憶總想哭 ft.彭清「回憶總想哭,一個人太孤獨」【動態歌詞版MV】-XN1ubsjTz1U.mp3",
27: SONG_PATH / "Led Zeppelin - Stairway To Heaven ᴴᴰ (Legendado_Tradução PTBR)-D9ioyEvdggk.flac",
22: SONG_PATH / "Magic Sword - In The Face Of Evil-G02wKufX3nw.opus",
}
def song_callback(pin):
# Pin nummer wird übergeben, wenn der Callback durch GPIO aufgerufen wird
# dann wird auf die entsprechende Value der SONGS zugegriffen
# das wird dann der Funktion play übergeben. (im anderen script)
play(SONGS[pin])
def initialize():
GPIO.setmode(GPIO.BCM)
for pin, song in SONGS.items():
print("Init Pin", pin)
GPIO.setup(pin, GPIO.IN, GPIO.PUD_UP)
GPIO.add_event_detect(
pin, GPIO.FALLING, callback=song_callback, bouncetime=3000
)
# bouncetime 3 Sekunden ?
# sobald eine fallende Flanke erkannt wird,
# ruft GPIO die callback-Funktion mit der Pin-Nummer als einziges Argument auf
# das bestimmt dann, welcher Song gespielt wird.
def main():
initialize()
# busy loop um zu verhindern, dass das Programm einfach beendet wird.
# Der main-Thread schläft immer 10 Sekunden lang,
# während der Daemon-Thread von GPIO im Hintergrund aktiv ist
while True:
time.sleep(10)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("Exit")
except Exception as e:
print(e)
# ist nicht so die tolle Art, aber GPIO.cleanup soll ja noch ausgeführt werden
# wenn eine Exception ausgelöst wird, mit der man nicht rechnet und das würde dann
# verhindern das nächste Statement auszuführen
# in diesem Fall GPIO.cleanup()
# andere Möglichkeit:
# import atexit
# atexit.register(GPIO.cleanup)
GPIO.cleanup()
Beim RPi4 hatte ich jetzt keine Lust, das Gehäuse nur zum Testen auseinander zu bauen.
Kurzes Beispiel mit atexit (für GPIO.cleanup):
Code: Alles auswählen
deadeye@rpi0w2:~ $ python fail.py
Auch ein SystemExit lässt atexit noch alle registrierten Funktion aufrufen
Yay, der callback ist ausgeführt worden. Könnte auch ein GPIO.cleanup sein
Code: Alles auswählen
import atexit
atexit.register(lambda: print("Yay, der callback ist ausgeführt worden. Könnte auch ein GPIO.cleanup sein"))
raise SystemExit("Auch ein SystemExit lässt atexit noch alle registrierten Funktion aufrufen")
# Hier endet das Programm und die registrierten Funktionen werden durch
# atexit aufgerufen
# Dises Statement wird nur erreicht, wenn man die vorherige Exception nicht auslöst.
1 / 0 # Hier wird eine Exception ausgelöst, die nicht abgefangen wird.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
@Danoo: der Player kann wohl nur einmal abspielen, da muß man mit Media arbeiten:
@DeaD_EyE: auch wenn vlc intern viel mit globalem Zustand arbeitet, muß man das ja nicht in Python auch machen. Das extra Modul ist dann auch etwas übertrieben für eine Funktion.
Callbacks arbeiten intern mit eigenen Threads, da muß man immer aufpassen und ein externes C-Modul würde ich darin nicht aufrufen, sondern den Callback so einfach halten wie möglich.
Das ist vor allem immer seltsam, wenn im Hauptthread nur geschlafen wird.
GPIO.cleanup sollte in einem finally-Block aufgerufen werden, damit man wirklich sicher ist, dass das ausgeführt wird. Stell Dir vor, jemand drückt Ctrl+C im except-Block.
`atexit` ist da unnötig komplex.
Code: Alles auswählen
from queue import Queue
from pathlib import Path
from RPi import GPIO
import vlc
PIN_LEFT_PLAYER = 19
PIN_RIGHT_PLAYER = 21
PIN_START = 20
SONG_PATH = Path("/home/pi/Desktop/Playsound/songs")
SONGS = {
PIN_START: "Boxing Bell Sound Effect.mp3",
PIN_LEFT_PLAYER: "Air_Horn.mp3",
PIN_RIGHT_PLAYER: "Air_Horn.mp3",
}
def initialize():
queue = Queue()
GPIO.setmode(GPIO.BCM)
for pin in [PIN_LEFT_PLAYER, PIN_RIGHT_PLAYER, PIN_START]:
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.add_event_detect(pin, GPIO.FALLING, callback=queue.put, bouncetime=3000)
return queue
def main():
try:
queue = initialize()
media_player = vlc.MediaPlayer()
songs = {
pin: vlc.Media(SONG_PATH / song)
for pin, song in SONGS.items()
}
while True:
pin = queue.get()
media_player.set_media(songs[pin])
media_player.play()
finally:
GPIO.cleanup()
if __name__ == "__main__":
main()
Callbacks arbeiten intern mit eigenen Threads, da muß man immer aufpassen und ein externes C-Modul würde ich darin nicht aufrufen, sondern den Callback so einfach halten wie möglich.
Das ist vor allem immer seltsam, wenn im Hauptthread nur geschlafen wird.
GPIO.cleanup sollte in einem finally-Block aufgerufen werden, damit man wirklich sicher ist, dass das ausgeführt wird. Stell Dir vor, jemand drückt Ctrl+C im except-Block.
`atexit` ist da unnötig komplex.
- DeaD_EyE
- User
- Beiträge: 1021
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Wenn danach nichts mehr kommt, wird der Interpreter beendet und auch dann werden die registrierten Funktionen aufgerufen. Das passiert nicht, sofern noch non-deamon-Threads laufen.GPIO.cleanup sollte in einem finally-Block aufgerufen werden, damit man wirklich sicher ist, dass das ausgeführt wird. Stell Dir vor, jemand drückt Ctrl+C im except-Block.
`atexit` ist da unnötig komplex.
Das einzige was den Aufruf von atexit verhindert, ist z.B. ein Signal. Da hilft der finally-Block dann auch nicht mehr.
Du meinst sicherlich die Callbacks von RPi.GPIO. Callbacks sollte man kurz halten, aber bei einer Bouncetime von 3 Sekunden ist das egal. Mir gefällt das mit den Queues überhaupt nicht, auch wenn es bei Threads der sichere Standard-Weg ist. Eins ist anzumerken, wenn mal ein Fehler bei einem Callback auftritt, der durch C aufgerufen wird und im Callback ein Bug ist, kann das sogar den Interpreter killen.Callbacks arbeiten intern mit eigenen Threads, da muß man immer aufpassen und ein externes C-Modul würde ich darin nicht aufrufen, sondern den Callback so einfach halten wie möglich.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server