Abfrage der Laufzeit entfernen und weiteres

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Frank R.
User
Beiträge: 38
Registriert: Montag 23. September 2019, 10:10

und nochmal angepasst

Code: Alles auswählen

import gpiozero
import time
import random

def play_leds(leds):
    repetition_count = 20 * len(leds)  # Muster wird repetition_count mal wiederholt
    on_time = 0.1  # Leuchtdauer der LED
    
    for i in range(repetition_count):
        led = random.choice(leds)
        led.on()
        time.sleep(on_time)
        if i < repetition_count-1:
            led.off()
        else:
            time.sleep(5)
            led.off()

def main():
    leds = gpiozero.LEDBoard(17, 18, 27, 22, 23, 24, 25, 4, 12)
    button = gpiozero.Button(16)
    while True:
        button.wait_for_press()
        play_leds(leds)

if __name__ == '__main__':
    main()
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Du hast Code mehrfach kopiert. Dabei geht es nur darum, eine Schleife zu programmieren, die 179mal kurz und einmal lang pausiert.

Code: Alles auswählen

import gpiozero
import time
import random
from itertools import repeat, chain

def play_leds(leds):
    on_time = 0.1  # Leuchtdauer der LED
    delays = chain(repeat(on_time, 20 * len(leds) - 1), [5])
    for delay in delays:
        led = random.choice(leds)
        led.on()
        time.sleep(delay)
        led.off()

def main():
    leds = gpiozero.LEDBoard(17, 18, 27, 22, 23, 24, 25, 4, 12)
    button = gpiozero.Button(16)
    while True:
        button.wait_for_press()
        play_leds(leds)

if __name__ == '__main__':
    main()
Frank R.
User
Beiträge: 38
Registriert: Montag 23. September 2019, 10:10

Oh jeh.. da hab ich mich wohl in den Schleifen verrannt. Habe deinen Code eben mal getestet, sieht ja schon anders aus. Vielen lieben Dank erstmal, Sirius3.
Ich versuche mal, den Code nachzuvollziehen:

Aus den itertools werden, vereinfacht gesagt, repeat für die Wiederholungen und chain für den Ablauf der Iterationen importiert. delays definiert eine chain, also Kette von Abläufen, welche 20 mal die Anzahl der LEDs durchläuft, wobei jede LED für 0.1 Sekunden leuchtet, ausgeschaltet wird, und die letzte LED (- 1) für [5] Sekunden aktiviert bleibt. delay wird durch [5] bestimmt, wenn ich dort eine andere Zahl eintrage bleibt die LED länger an.

Hoffe ich habe das halbwegs verständlich erklärt, wie ich den Code verstehe?
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Es gibt verschiedene Arten, solche Probleme zu lösen. Einen Index zu nehmen, um zu wissen, ob man am letzten Durchgang angekommen ist, ist indirekter, als mit einer Schleife über die Pausen direkt. Index versucht man deshalb in Python zu vermeiden, weil man Don schön einfach andere Reihen binden kann, als nur aufsteigende Zahlen.
Frank R.
User
Beiträge: 38
Registriert: Montag 23. September 2019, 10:10

Kann ich denn, basierend auf diesem Code, einen Sound abspielen? Also bei jedem Aufleuchten einer LED einen Sound (immer der selbe) mit der entsprechenden on_time? Für das Abspielen dachte ich an pygame, scheint wohl die einfachste Möglichkeit zu sein. Wie man einen Sound an sich abspielt ist ja gut dokumentiert. Wäre hier ein eigener Abschnitt (wie z.B. def main():) notwendig bzw. sinnvoll, oder kann das in den vorhandenen (def play.....) integriert werden?
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das muss schon mit der bestehenden Logik verbaut werden. Und es kann sein, dass du den Pygame Event Loop treiben musst. Also gelegentlich mal aufrufen.
Frank R.
User
Beiträge: 38
Registriert: Montag 23. September 2019, 10:10

Hallo,

bin jetzt etwas weiter mit dem Sound, allerdings funktioniert es noch nicht so richtig. Momentan sieht der Code folgendermaßen aus:

Code: Alles auswählen

import gpiozero
import time
import random
import pygame
from itertools import repeat, chain
pygame.init()
sound = pygame.mixer.Sound('/home/pi/Documents/test.wav')

def play_leds(leds):
    on_time = 0.1  # Leuchtdauer der LED
    delays = chain(repeat(on_time, 20 * len(leds) - 1), [5])
    for delay in delays:
        led = random.choice(leds)
        led.on()
        sound.play()
        time.sleep(delay)
        led.off()

def main():
    leds = gpiozero.LEDBoard(17, 18, 27, 22, 23, 24, 25, 4, 12)
    button = gpiozero.Button(16)
    while True:
        button.wait_for_press()
        play_leds(leds)

if __name__ == '__main__':
    main()
Ich vermute mal, dass das nicht optimal ist :?: Ich habe das Problem, dass der Sound, wenn er nicht genau so lang bzw. kurz ist wie das Aufblinken, völlig falsch abgespielt wird. d.h. wenn ich den Sound nicht auf 0.1 Sekunden kürze, funktioniert die Wiedergabe nicht richtig. Und am Ende soll ein ANDERER Sound entsprechend des delays, also hier 5 Sekunden lang abgespielt werden.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn Du in 18 sekunde 180 mal einen Sound abspielen willst, dann rate mal, wie lange ein Ton sein kann ...
Was soll man sonst noch sagen? Du mußt das was Du willst programmieren. Das passiert nicht von alleine.
Frank R.
User
Beiträge: 38
Registriert: Montag 23. September 2019, 10:10

Natürlich nur 0.1 Sekunden, wie oben geschrieben. Mich interessiert eher, ob denn der Code an sich so ok ist, oder ob der Einbau des sound.play() anders gelöst werden sollte.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Man könnte natürlich auch parallel dazu einen Sound abspielen, der halt so lang ist, wie die ganze Würfelei.
Frank R.
User
Beiträge: 38
Registriert: Montag 23. September 2019, 10:10

Ja, die Idee hatte ich auch. Da könnte ich wohl was basteln. Ich muss den Code sowieso noch anpassen, die Würfelei sollte höchstens 10 bis 15 Sekunden dauern. Also entsprechend weniger Durchläufe.
Frank R.
User
Beiträge: 38
Registriert: Montag 23. September 2019, 10:10

Moin Forum, kleines Update hierzu. Ich habe den Code erweitert, um insgesamt 5 verschiedene Sounds abzuspielen. Jetzt gibt es nur ein Problem. Obwohl die Sounds vorhanden sind, können sie nicht abgespielt werden. Hier mal der aktuelle Code:

Code: Alles auswählen

import gpiozero
import time
import random
import pygame.mixer
import glob
from itertools import repeat, chain

pygame.mixer.init()
soundfiles = glob.glob("/home/pi/Documents/*.mp3")

def play_leds(leds):
    pygame.mixer.Sound(random.choice(soundfiles)).play()
    on_time = 0.1  # Leuchtdauer der LED
    delays = chain(repeat(on_time, 11 * len(leds) - 1), [5])
    for delay in delays:
        led = random.choice(leds)
        led.on()
        time.sleep(delay)
        led.off()

def main():
    leds = gpiozero.LEDBoard(17, 18, 27, 22, 23, 24, 25, 4, 12)
    button = gpiozero.Button(16)
    while True:
        button.wait_for_press()
        play_leds(leds)

if __name__ == '__main__':
    main()

Sobald das Skript gestartet wurde, und ich den Taster drücke, erscheint folgende Fehlermeldung:

pygame.error: Unable to open file '/home/pi/Documents/versuch5.mp3'

Wobei die Nummer hinter "versuch" immer anders ist, also z.B. versuch3, versuch2 usw. Die "glob" scheint also zu funktionieren, aber warum kann die MP3 nicht geöffnet werden?
Frank R.
User
Beiträge: 38
Registriert: Montag 23. September 2019, 10:10

Update: Ich habe jetzt probeweise statt MP3 Dateien Wave Dateien verwendet (die selben MP3 in .wav) umgewandelt, und siehe da: Die Sounds werden tatsächlich OHNE Fehlermeldung abgespielt, auch zufällig. Aber warum klappt das mit MP3 nicht?
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Frank R.: Kann Pygame (unter Linux) überhaupt MP3? Ist ja ein nicht-freier Codec.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Frank R.
User
Beiträge: 38
Registriert: Montag 23. September 2019, 10:10

Habe eben mal nachgeschaut, pygame kann MP3 abspielen, aber der Code muss dann anders aussehen. Wenn man nur Sounds in Form von .ogg oder .wav Dateien abspielen möchte, sieht der Code so aus wie oben geschrieben. Wenn man aber MP3 Dateien abspielen will, muss es "pygame.mixer.music.play()" heißen, so habe ich das jedenfalls verstanden. Werde ich bei Gelegenheit mal testen.
Frank R.
User
Beiträge: 38
Registriert: Montag 23. September 2019, 10:10

Habe noch eine Frage: Ist es möglich, die Zufallswiedergabe der Sounds so zu coden, dass ein und derselbe Sound NICHT zweimal nacheinander abgespielt wird? Also z.B. test1.wav wird abgespielt, dann folgt zufällig test2.wav bis test5.wav, und erst nach diesem Durchlauf darf test1.wav wieder aufgerufen werden.
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Klar ist das moeglich. Du musst eine Kopie der moeglichen Sounds machen, und bei jeder Auswahl (random.choice(copy_of_available_sounds)) den gewaehlten einfach entfernen. Sobald die Liste dann leer ist, erzeugst du wieder eine Kopie aller Moeglichkeiten.
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

So zB

Code: Alles auswählen

import time
import random

SONGS = ["a", "b", "c"]


def random_song_generator(songs):
    while True:
        selection = list(songs)
        random.shuffle(selection)
        yield from selection


def main():
    rsg = random_song_generator(SONGS)
    while True:
        for _ in SONGS:
            print(next(rsg))
        print("-" * 20)
        time.sleep(.2)


if __name__ == '__main__':
    main()
Frank R.
User
Beiträge: 38
Registriert: Montag 23. September 2019, 10:10

Ok, aber wie binde ich diese Funktion in meinen Code ein? So wie ich das verstanden habe muss die Zeile "rsg = random_song_generator(SONGS)" , zusätzlich in "def main():" rein. Nur wie binde ich den Abschnitt "def random_song_generator(songs):" ein? Und was ist mit den pygame.mixer Angaben? Was kann/muss davon weg bzw. geändert werden?
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

`play_leds` braucht als zusätzliches Argument den Sound, der gespielt werden soll.
Und aus der while-True-Schleife machst Du einfach eine for-Schleife über die Sounds, die rsg liefert.
Antworten