まこと の ブログ

MaKoTo no burogu — Journal de bord…

Aller au contenu | Aller au menu | Aller à la recherche

Mini Game Center -3-

Suite de l'étude précédente :
Bien ! Maintenant que le système est installé, il nous faut un programme pour exploiter la mini-borne, et ainsi automatiser l'affichage des vidéos.

1 - Playlist de vidéos et pilotage par GPIO :

  • Il faut voir mes petites bornes comme des judebox à jeux vidéos, qui jouent une vidéo en boucle.

- Sur la carte SD sont stockées plusieurs vidéos de démo de jeux ou de parties enregistrées.
- Les vidéos sont jouées par un script Python, et il est alors possible d'interagir avec la vidéo qui joue. Ainsi on va pouvoir :

- augmenter/diminuer le volume sonore, à l'aide de deux boutons poussoir.
- augmenter/diminuer la luminosité de l'écran, à l'aide de ces même deux boutons, avec un appuie long (> 2s).
- sauter de 30 secondes en avant/arrière, à l'aide de deux autres boutons poussoir.
- jouer la vidéo suivante/précédente, à l'aide de ces même de deux autres boutons, avec un appuie long (> 2s).
- faire une pause/relancer la lecture de la vidéo, à l'aide du bouton dédié.


  • Voici dores et déjà une petite vidéo de démonstration pour bien comprendre l'idée :


  • Et donc, pour ce faire, voici le schéma de câblage des boutons aux GPIO :


C'est le dessin du RaspberryPi Zero qui est représenté, mais les câbles (cf. la vidéo) sont bien raccordés sur le Pi HAT (cf. le schéma structurel). Les condensateurs d'anti-rebond font 100nF.
Il ne reste plus qu'a programmer…

  • On a donc besoin de Python3 avec la librairie RPI.GPIO, et de la librairie omxcontrol de Douglas6 qui fonctionne avec dbus :
sudo apt-get install python3-rpi.gpio python3-dbus
cd /home/pi
git clone https://github.com/Douglas6/omxcontrol.git
cd omxcontrol
sudo python setup.py install

On a donc un dossier /home/pi/omxcontrol dans lequel on va placer notre programme Python pompeusement appelé « VideoOMXcontrol_GPIO_Multionctions_Playlist.py ».

#!/usr/bin/env python2.7
# coding: utf-8
# Compatible Python3

# Programme pour RaspberryPi
# Joue une playliste de vidéos avec omxplayer
# Pilotage des vidéos et de la playliste avec 5 boutons GPIO

##################################
# Import des modules nécessaires #
##################################
from omxcontrol import *
import subprocess
import RPi.GPIO as GPIO
import time

#############
# Init GPIO #
#############
PIN_PLAY = 31           # GPIO06, Play/Pause/Stop  [Appuie court et long]
PIN_VOLMOINS = 35       # GPIO19, Volume -
PIN_VOLPLUS = 37        # GPIO26, Volume +
PIN_PRECEDENT = 38      # GPIO20, Précédent [Appuie court et long]
PIN_SUIVANT = 36        # GPIO16, Suivant [Appuie court et long]
PIN_BRIGHTNESS = 12	# GPIO18, PWM de réglage de la luminosité

GPIO.setmode(GPIO.BOARD) ## Use board pin numbering
GPIO.setup(PIN_PLAY, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(PIN_VOLMOINS, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(PIN_VOLPLUS, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(PIN_PRECEDENT, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(PIN_SUIVANT, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(PIN_BRIGHTNESS, GPIO.OUT)

#####################
# Ressources Vidéos #
#####################
def Selection(i):
    switcher={
        0:'/home/pi/deathsml_15-07-2015_1cc_h264-21.mp4',
        1:'/home/pi/dodonpachi_23-02-2014_montage.mp4',
        2:'/home/pi/espgal_26-02-2015_1cc_x264_crf23.mp4',
        3:'/home/pi/galaxian.mp4',
        }
    return switcher.get(i,"Séléction Invalide")

#############
# Variables #
#############
vid = 0
long_press = 1
very_long_press = 3
start = 0
end = 0
brightness = 100
pwm = GPIO.PWM(PIN_BRIGHTNESS, 130) # channel et frequence en Hz, meilleur résultat à 120 et 130Hz

#############
# Démarrage #
#############
os.system('sudo pkill omxplayer')       # S'assure qu'aucune instance omxplayer ne tourne encore, en cas de plantage
# omxplayer /home/pi/deathsml_15-07-2015_1cc_h264-21.mp4 --aspect-mode stretch -o local
pwm.start(brightness)	# Démarrage de la PWM du rétroéclairage LCD au max (100)


# fonction qui sera appelée quand on appuiera sur le bouton : PIN_VOLMOINS
def bouton_PIN_VOLMOINS(channel):
    global brightness
    global start
    global end
    if GPIO.input(channel) == GPIO.LOW:
        print("GPIO.LOW")
        start = time.time()
    if GPIO.input(channel) == GPIO.HIGH:
        print("GPIO.HIGH")
        end = time.time()
        elapsed = end - start
        print(elapsed)
        if (elapsed > very_long_press):
            print("very_long_press: ",very_long_press)
            # À DÉFINIR
            print('Fonction à définir')
        elif (elapsed > long_press):
            print("long_press :",long_press)
            # Baisser la luminosité de l'écran LCD
            brightness = brightness - 10
            if brightness <= 10:
                brightness = 10
                print("Luminosité baissée au max")
            print("Baisse la luminosite :", brightness)
            pwm.ChangeDutyCycle(brightness)
        elif (elapsed > 0):
            print("short_press")
            # Baisser le Volume du son
            print("Button Volume - pressé")
            omx.action(OmxControl.ACTION_DECREASE_VOLUME)


def bouton_PIN_VOLPLUS(channel):
    global brightness
    global start
    global end
    if GPIO.input(channel) == GPIO.LOW:
        print("GPIO.LOW")
        start = time.time()
    if GPIO.input(channel) == GPIO.HIGH:
        print("GPIO.HIGH")
        end = time.time()
        elapsed = end - start
        print(elapsed)
        if (elapsed > very_long_press):
            print("very_long_press: ",very_long_press)
            # À DÉFINIR
            print('Fonction à définir')
        elif (elapsed > long_press):
            print("long_press :",long_press)
            # Augmenter la luminosité de l'écran LCD
            brightness = brightness + 10
            if brightness >= 100:
                brightness = 100
                print("Luminosité augmentée au max")
            print("Augmente la luminosite :", brightness)
            pwm.ChangeDutyCycle(brightness)
        elif (elapsed > 0):
            print("short_press")
            # Monter le Volume du son
            print("Button Volume + pressé")
            omx.action(OmxControl.ACTION_INCREASE_VOLUME)


def bouton_PIN_PRECEDENT(channel):
    global vid
    global start
    global end
    if GPIO.input(channel) == GPIO.LOW:
        print("GPIO.LOW")
        start = time.time()
    if GPIO.input(channel) == GPIO.HIGH:
        print("GPIO.HIGH")
        end = time.time()
        elapsed = end - start
        print(elapsed)
        if (elapsed > very_long_press):
            print("very_long_press: ",very_long_press)
            # À DÉFINIR
            print('Fonction à définir')
        elif (elapsed > long_press):
            print("long_press :",long_press)
            # Stopper la lecture et tombe donc en erreur via Try > Except de la boucle principale
            print('Vidéo Précédente')
            omx.action(OmxControl.ACTION_EXIT)
            vid = vid - 1       # pour lire la vidéo précédente
            if vid == -1:
                vid = 3
            print('vid : ',vid)
        elif (elapsed > 0):
            print("short_press")
            # un petit saut un arriére dans la vidéo
            print('<<')
            omx.action(OmxControl.ACTION_SEEK_BACK_SMALL)


def bouton_PIN_SUIVANT(channel):
    global vid
    global start
    global end
    if GPIO.input(channel) == GPIO.LOW:
        print("GPIO.LOW")
        start = time.time()
    if GPIO.input(channel) == GPIO.HIGH:
        print("GPIO.HIGH")
        end = time.time()
        elapsed = end - start
        print(elapsed)
        if (elapsed > very_long_press):
            print("very_long_press: ",very_long_press)
            # À DÉFINIR
            print('Fonction à définir')
        elif (elapsed > long_press):
            print("long_press :",long_press)
            # Stopper la lecture et tombe donc en erreur via Try > Except de la boucle principale
            print('Vidéo Suivante')
            omx.action(OmxControl.ACTION_EXIT)
            vid = vid + 1       # pour lire la vidéo suivante
            if vid == 4:
                vid = 0
            print('vid : ',vid)
        elif (elapsed > 0):
            print("short_press")
            # un petit saut en avant dans la vidéo
            print('>>')
            omx.action(OmxControl.ACTION_SEEK_FORWARD_SMALL)


def bouton_PIN_PLAY(channel):
    global start
    global end
    if GPIO.input(channel) == GPIO.LOW:
        print("GPIO.LOW")
        start = time.time()
    if GPIO.input(channel) == GPIO.HIGH:
        print("GPIO.HIGH")
        end = time.time()
        elapsed = end - start
        print(elapsed)
        if (elapsed > very_long_press):
            print("very_long_press: ",very_long_press)
            # À DÉFINIR
            print('Fonction à définir')
        elif (elapsed > long_press):
            print("long_press :",long_press)
            # Stoppe la vidéo
            print('Stop')
            omx.action(OmxControl.ACTION_EXIT)	 # SORTIR DE LA BOUCLE PRINCIPALE sinon la vidéo se relancera
        elif (elapsed > 0):
            print("short_press")
            # Pause/Play la vidéo
            print('Pause/Play')
            omx.action(OmxControl.ACTION_PAUSE)


GPIO.add_event_detect(PIN_VOLMOINS, GPIO.BOTH, callback=bouton_PIN_VOLMOINS, bouncetime=100)
GPIO.add_event_detect(PIN_VOLPLUS, GPIO.BOTH, callback=bouton_PIN_VOLPLUS, bouncetime=100)
GPIO.add_event_detect(PIN_PRECEDENT, GPIO.BOTH, callback=bouton_PIN_PRECEDENT, bouncetime=100)
GPIO.add_event_detect(PIN_SUIVANT, GPIO.BOTH, callback=bouton_PIN_SUIVANT, bouncetime=100)
GPIO.add_event_detect(PIN_PLAY, GPIO.BOTH, callback=bouton_PIN_PLAY, bouncetime=100)

#####################
# Boucle Principale #
#####################
while True:
    try:
        omx = OmxControl()      # appel librairie OmxControl

    except OmxControlError as ex:       # si le controle ne voit plus D-Bus, relance la vidéo
        print("ERREUR de contrôle D-Bus, relance de la vidéo")
        print('Selection : ',Selection(vid))
        subprocess.Popen(['omxplayer','--aspect-mode', 'stretch', '-o', 'local', Selection(vid)], stdin=subprocess.PIPE)
        time.sleep(3)   # tempo pour laisser le temps au player vidéo de démarrer
        omx = OmxControl()      # appel librairie OmxControl
        omx.action(OmxControl.ACTION_DECREASE_VOLUME)
        omx.action(OmxControl.ACTION_DECREASE_VOLUME)
        omx.action(OmxControl.ACTION_DECREASE_VOLUME)
        omx.action(OmxControl.ACTION_DECREASE_VOLUME)
        omx.action(OmxControl.ACTION_DECREASE_VOLUME)
        omx.action(OmxControl.ACTION_DECREASE_VOLUME)	# -18 db

# on réinitialise les ports GPIO en sortie de script
GPIO.cleanup()


#####################################################
# Fonctions disponible dans la librairie OmxControl #
#####################################################
#ACTION_DECREASE_SPEED
#ACTION_INCREASE_SPEED
#ACTION_REWIND
#ACTION_FAST_FORWARD
#ACTION_SHOW_INFO
#ACTION_PREVIOUS_AUDIO
#ACTION_NEXT_AUDIO
#ACTION_PREVIOUS_CHAPTER
#ACTION_NEXT_CHAPTER
#ACTION_PREVIOUS_SUBTITLE
#ACTION_NEXT_SUBTITLE
#ACTION_TOGGLE_SUBTITLE
#ACTION_DECREASE_SUBTITLE_DELAY
#ACTION_INCREASE_SUBTITLE_DELAY
#ACTION_EXIT
#ACTION_PAUSE
#ACTION_DECREASE_VOLUME
#ACTION_INCREASE_VOLUME
#ACTION_SEEK_BACK_SMALL
#ACTION_SEEK_FORWARD_SMALL
#ACTION_SEEK_BACK_LARGE
#ACTION_SEEK_FORWARD_LARGE
#ACTION_SEEK_RELATIVE
#ACTION_SEEK_ABSOLUTE
#ACTION_STEP
#ACTION_BLANK
#ACTION_MOVE_VIDEO
#ACTION_HIDE_VIDEO
#ACTION_UNHIDE_VIDEO
#ACTION_HIDE_SUBTITLES


2 - Automatisation :

  • Pour démarrer automatiquement le programme python dés le démarrage du Raspberry, on utilise un script bash :
nano /home/pi/arcade.sh

Avec dedans :

#!/bin/bash

/usr/local/bin/fbcp &
/usr/bin/python3 /home/pi/omxcontrol/VideoOMXcontrol_GPIO_Multifonctions_Playlist.py
  • Et puis on ajoute simplement le script dans le .bashrc de l'utilisateur courant[1].
sudo nano /home/pi/.bashrc

À la fin du fichier, renseigner :

echo Lancement du script arcade après le login de l utilisateur pi
/bin/bash /home/pi/arcade.sh



C'est terminé pour l'électronique et l'informatique ! Du moins pour le pilotage d'une seule borne.
Plus tard je ferais en sorte de pouvoir piloter chaque borne du Game Center depuis un seul pupitre.
La prochaine fois nous verrons comment intégrer l'écran dans la maquette et nous auront terminé cette Sega Astro City.

Ressources :
https://www.dexterindustries.com/howto/run-a-program-on-your-raspberry-pi-at-startup/
https://stackoverflow.com/questions/36073640/time-between-button-press-and-release-in-python

Note

[1] Pas possible d'utiliser la méthode désormais classique via systemd, car le programme refusait de se lancer à cause d'erreurs avec dbus. Cependant ce n'est pas plus mal, car le programme est lancé par la console loguée sur l'écran LCD, on le voit démarrer à l'allumage du pi.

Ajouter un commentaire

Les commentaires peuvent être formatés en utilisant une syntaxe wiki simplifiée.

Fil des commentaires de ce billet