Actualités

Photobooth – La machine à selfies

Photobooth : la machine à selfies
Photobooth : la machine à selfies

Une soirée à thème très prochainement ? Un mariage se profile dans quelques mois ? Le photobooth est la machine idéale pour animer vos évènements festifs. L’idée est la suivante…

Vous célébrez un évènement avec vos invités dans un espace de convivialité. A l’écart, dans une pièce isolée, le photobooth est disposé autour d’une décoration à thème. Avec les accessoires de déguisement mis à disposition au sein de cet espace intime, les conditions sont ainsi réunies pour favoriser la créativité des protagonistes et les inciter à se mettre en scène.

En s’affranchissant du tarif abordable de 0.10€, l’utilisateur de cette machine à « selfies » à l’ancienne repart avec une photo instantanément imprimée sur papier thermique… mais ce n’est pas tout !

Les photos prises par le photobooth seront exportées vers un autre Raspberry chargé de les projeter sur écran afin de partager les clichés (en couleur et haute résolution) avec l’ensemble des convives !

C’est un projet ambitieux mais très enrichissant : les notions impliquées sont denses et les difficultés à surmonter sont assez complexes. Le challenge technique est de taille : de nombreuses lignes de code Python nous attendent alors démarrez le Raspberry et ouvrez le terminal en grand : il va y avoir du pulse sur les GPIOs !

Avant de se lancer, voici un aperçu des photos imprimées :

Photos imprimées sur papier thermique
Photos imprimées sur papier thermique

Eu égard au coût de revient de l’imprimante et du papier thermique, la qualité d’impression est tout à fait acceptable.

Fonctionnement

Afin de percevoir le fonctionnement du photobooth, le tableau ci-dessous fournit une description des différents écrans affichés sur l’écran HDMI au fil de l’utilisation de la machine.

Enchainement des écrans du Photobooth
Enchainement des écrans du Photobooth

Le matériel

Le Photobooth vu de l'intérieur
Le Photobooth vu de l’intérieur

La photo ci-contre illustre l’agencement des composants à l’intérieur du photobooth.

Le matériel à mettre en œuvre est le suivant :

  • Un monnayeur CH-926 ;
  • Un écran LCD 800×480 HDMI ;
  • Un écran LCD HD44780 20×04 avec interface I2C ;
  • Une PiCaméra ;
  • Un ruban CSI de 30 cm (plus long que celui fourni en standard avec la RaspiCam) ;
  • Une imprimante thermique liaison série ;
  • Un gros bouton ;
  • Un relais ;
  • Une alimentation 5V 10A ;
  • Un convertisseur USB 5V-12V ;
  • Un convertisseur HDMI-VGA ;
  • Des câbles dupont, une multiprise, visserie,…
  • Des pièces imprimées en 3D :
  • Un support pour fixer le Raspberry à l’intérieur du photobooth ;
  • Un support pour loger le module camera en façade.
  • Du bois MDF, des vis, des boulons et des écrous,…

Commençons par le monnayeur.

Le monnayeur

Monnayeur CH-928
Cette photo présente le modèle JY-323 qui ne sait reconnaître que 3 pièces différentes mais c’est bien le modèle CH-928 (jusqu’à 6 pièces différentes) qui a été utilisé pour le projet qui nous intéresse dans cet article.

Le modèle utilisé (CH-928) permet de reconnaître jusqu’à 8 pièces différentes. D’après la documentation, le périphérique se base sur le matériau, le poids et la taille de la pièce pour la reconnaître. Avec un taux d’identification annoncé à 99.5%, le monnayeur est a priori précis, précision qui dépendra de l’échantillon utilisé lors de la programmation… Oui, le monnayeur doit « apprendre » à discerner les pièces pour les reconnaître. Cet apprentissage est réalisé en insérant un échantillon de pièces.

Pour configurer les pièces à reconnaître, le monnayeur doit être programmé par un « entrainement » de reconnaissance avec un échantillon d’au moins 15 samples distincts. Par exemple, pour lui apprendre les pièces de 2 euros, il est recommandé d’utiliser 15 pièces de 2 euros différentes.
La programmation du monnayeur est réalisée à l’aide des boutons « Add » et « Minus » et de l’écran LED à deux digits présent sur le monnayeur. Le tableau ci-dessous détaille les paramètres à configurer lors du processus de programmation

IDPIECESECHANTILLON
(nb pieces)
PULSES
(nb_pulses)
PRECISIONCONVERSION
PULSES-CREDIT €
01 à 8 types de piècesPréco.* : 15 à 30 samplesDe 1 à 50.1 à 30
Préco.** : entre 5 et 10
Opération dans le code Python
10.10 €1517credit = nb_pulses/10
20.20 €1527credit = nb_pulses/10
30.50 €1557credit = nb_pulses/10
41.00 €15107credit = nb_pulses/10
52.00 €15207credit = nb_pulses/10
* La quantité de pièces de chaque type influe sur la précision du monnayeur
** La précision 1 est la plus précise

L’échantillon indique le nombre de pièces distinctes utilisées pour programmer le monnayeur. Le nombre de fronts montants envoyés sur la ligne COIN du monnayeur est comptabilisé et stocké dans la variable nb_pulses. Le monnayeur ainsi programmé, la conversion nb_pulses/credit est réalisée avec une simple division par 10 (credit = nb_pulses/10).

La quantité de l’échantillon est importante. Lors des premiers essais, je ne disposais que de 4 pièces de 2 euros distinctes. Avec un échantillon aussi réduit, l’apprentissage n’est pas optimal et il peut parfois arriver qu’une même pièce de 2 euros ne soit pas reconnue et donc rejetée à l’avant du monnayeur.

Algorithme de traitement des séquences de pulses sur la ligne coin

Tout d’abord, précisons que le switch NO/NC permet de définir l’état par défaut de la ligne COIN (fil blanc) :

  • NO (Normally Opened) : ligne COIN est maintenu à l’état HIGH (5V) et passe nb_pulses fois à LOW (0V) si une pièce est reconnue, puis retour à HIGH ;
  • NC (Normally Closed) : ligne COIN est maintenue à l’état LOW (0V) et passe nb_pulses fois à HIGH (5V) si une pièce est reconnue, puis retour à LOW.

Le bouton SPEED à 3 positions permet quant à lui d’influer sur le « output signal » d’après la documentation succincte fournie.

Je n’ai pas su trouvé s’il s’agissait de faire varier la longueur des pulses envoyés sur la ligne COIN ou le laps entre chaque pulse (ou même les deux). Si quelqu’un sait, merci de laisser un petit commentaire pour partager l’info…

Quoi qu’il en soit, les 3 vitesses disponibles sont les suivantes :

  1. SLOW : longueur de pulse = 100ms ;
  2. MEDIUM : longueur de pulse = 50ms ;
  3. FAST : longueur de pulse = 30ms.

Le schéma ci-dessous illustre la variation de tension sur la ligne COIN du monnayeur.

Pulses sur la ligne COIN du monnayeur
Pulses sur la ligne COIN du monnayeur

Lors des premiers essais dans le développement de la librairie COINSELECTOR.py, j’avais envisagé de reconnaître chaque pièce insérée à l’aide de l’algorithme suivant :

  1. A chaque pulse détecté :
    • Incrémentation de la variable nb_pulses ;
    • Stockage de du timestamp du dernier pulse dans last_pulse ;
  2. Dans une boucle infinie test des deux conditions suivantes :
    • nb_pulse > 0 ?
    • laps de temps écoulé depuis le précédent pulse supérieur à 100ms (configuration du swich output signal du monnayeur sur la vitesse SLOW) ?
    • Les deux conditions vérifiées alors identification de la pièce : coin = nb_pulse /10 puis nb_pulses = 0

Techniquement, cet algorithme fonctionne. Mais d’un point de vue fonctionnel, des résultats inattendus se produiront si l’utilisateur insère trop rapidement deux pièces consécutives. En effet, comme le montre le schéma ci-dessus, si la pièce de 0.20 € est insérée immédiatement après la pièce de 0.10 €, alors le temps tx sera suffisamment court pour que le traitement d’identification de la pièce ne soit pas déclenché après l’insertion de la première pièce mais seulement une fois la seconde insérée. Dans ce cas, l’algorithme conduira à nb_pulses = 3 et le code nous indiquera qu’une pièce de 0.30 € a été insérée !

Malgré une série de tests, je ne suis pas parvenu à identifier le seuil (le laps de temps écoulé entre 2 pulses) adéquat pour discerner à coup sur les séquences de pulses. A nouveau, si un lecteur peut apporter ses lumières…

Après réflexion, je réalise que faire la différence entre deux pièces de 0.10 € et une pièce de 0.20 € n’a pas de réel intérêt pour le projet. L’essentiel est d’incrémenter le crédit accumulé selon chaque pièce insérée et l’algorithme s’en trouve d’autant simplifié : il suffit d’ajouter la valeur 0.10 à la variable credit à chaque pulse détecté sur la ligne COIN ! Voici donc l’algorithme retenu :

A chaque pulse détecté : Incrémentation de la variable credit de 0.10.

Alimentation du monnayeur et tension du signal COIN

Alimentation : fournir l’énergie nécessaire…

Le monnayeur fonctionne en 12V. Il sera alimenté à l’aide d’un transformateur 5V (USB) – 12V (DC Jack) présenté dans la photo ci-dessous.

Convertisseur de tension 5V vers 12V USB
Convertisseur de tension 5V vers 12V USB

Il est possible de connecter l’extrémité USB sur le Raspberry mais un éclair apparaîtra sur l’écran (même avec un condensateur 1000μF) à l’insertion d’une pièce dans le monnayeur. Cela signifie une instabilité de la puissance électrique attendue par le Raspberry lorsque le monnayeur est actionné. Il est donc préférable d’utiliser une alimentation plus puissante type un chargeur de téléphone de 2A. Mes premiers essais ont montré que 1 A ne suffisait pas : en cas de sous-alimentation, même une pièce normalement reconnue par le monnayeur sera rejetée en façade en émettant 3 bips.

Signal COIN : abaisser les 5V à 3.3V pour les GPIOs du Raspberry

Pont diviseur de tension pour abaisser les 5V de la ligne COIN du monnayeur à 3.3V pour la GPIO en INPUT du Raspberry
Pont diviseur de tension pour abaisser les 5V de la ligne COIN du monnayeur à 3.3V pour la GPIO en INPUT du Raspberry

En plaçant le switch NO/NC sur NO, on découvre à l’aide d’un multimètre que la ligne COIN envoie du 5V.

Or, le Raspberry attend du 3.3v sur les GPIO en INPUT : il est donc nécessaire de créer un pont diviseur de tension pour abaisser les 5V à 3.3V.

La formule permettant de définir la valeur des résistances est Vout = (Vin x R2) / (R1 + R2).

Avec Vout = 3.3v et Vin = 5v, on arrive à déterminer que les valeurs 5 kΩ et 10kΩ respectivement pour R1 et R2 conviennent parfaitement. Pour abaisser le signal du monnayeur à 3.3V sur la GPIO 21, le câblage à réaliser est illustré par le schéma ci-dessus.

Pour réaliser le pont diviseur de tension ainsi que toutes les connexions des GPIOs, nous allons utiliser un module de prototypage qui s’enfiche sur les GPIO du Raspberry : le prototype HAT

HAT est un acronyme pour Hardware Attached on the Top.

Le Prototype HAT

La quantité de connexions à réaliser justifie l’ajout d’un module de prototypage.

De gauche à droite : le prototype HAT avec le fils soudés et deux momentary switch, le Raspberry Pi 3 et un support pour Raspberry imprimée en 3D
De gauche à droite : le prototype HAT avec le fils soudés et deux momentary switch, le Raspberry Pi 3 et un support pour Raspberry imprimée en 3D

Le prototype HAT (carte rouge à gauche sur la photo ci-dessus) est une simple plaque PCB facilitant la soudure de composants.

PCB est un acronyme pour Printed Circuit Board

Une fois les fils soudés, j’ai sécurisant l’ensemble avec de la colle à chaud. L’élément noir (à droite sur la photo ci-dessus) est la partie inférieure d’un boitier pour Raspberry que j’ai imprimé en 3D pour faciliter l’intégration de l’ensemble dans la partie supérieure du photobooth, comme l’illustre la photo suivante :

Raspberry surmonté du prototype HAT, le tout fixé dans la partie supérieure du photobooth à l'aide du support imprimé en 3D
Raspberry surmonté du prototype HAT, le tout fixé dans la partie supérieure du photobooth à l’aide du support imprimé en 3D

Le modèle .stl du boitier Raspberry est téléchargeable à l’adresse suivante : https://www.thingiverse.com/thing:922740

On distingue par ailleurs sur le HAT deux boutons (jaune et bleu). Ces deux interrupteurs momentanés ont été ajoutés pour faciliter des opérations de maintenance sur le Raspberry, sans qu’un clavier ne soit nécessaire :

  • Bouton JAUNE : sortie du script Python photobooth.py pour pouvoir reprendre la main sur le terminal ;
  • Bouton BLEU : arrêt du Raspberry.

Pour ces deux opérations, le code Python prévoit que l’action demandée soit confirmée par un appui sur le gros bouton rouge dans un délai de 5s. Sans confirmation, le script revient à son fil d’exécution nominal une fois le délai écoulé. Voyons dès à présent le gros bouton rouge…

Le bouton rouge

Gros bouton rouge
Gros bouton rouge

Les cas d’utilisation

Le gros bouton rouge type buzzer est un « momentary switch » c’est-à-dire que le changement d’état est actif uniquement le temps de l’appui sur le bouton. Il est doté d’une LED qui permet d’allumer le bouton. Pour suggérer à l’utilisateur d’appuyer sur le bouton rouge, le clignotement de sa LED sera activé. L’utilisateur sera invité à actionner le buzzer dans les 3 situations suivantes :

IDCONTEXTEBLINK LEDDELAITRAITEMENT EN CAS D’APPUITRAITEMENT SANS APPUI ET DELAI ECOULE
1Crédit inséré ≥ 0.10 € (prix fixé)OUI15 sCrédit retranché de 0.10 €
Mise à jour du l’affichage LCD 20x04
Démarrage d’une session photo…
Crédit retranché de 0.10 €
Mise à jour du l’affichage LCD 20x04
Démarrage automatique d’une session photo…
2Affichage à l’écran de la photo prise avec un bandeau invitant à appuyer sur le bouton rouge NON5sImpression de la photo sur l’imprimante thermiqueRetour fil d’exécution nominal du script
3Bouton jaune actionnéOUI5 sSortie du script et retour au terminalRetour fil d’exécution nominal du script
4Bouton bleu actionnéOUI5 sArrêt du RaspberryRetour fil d’exécution nominal du script

Côté Python, c’est la fonction récursive waitForRedButtonPush() qui est appelée pour gérer l’attente d’un éventuel appui sur le bouton rouge.

Comme vous pourrez le comprendre à la lecture des instructions de la fonction waitForRedButtonPush(delai), le traitement est prévu pour éliminer les faux-positifs. En effet, dans la première version de la fonction, j’observais un phénomène inattendu : le crédit de la machine était parfois incrémenté à l’allumage/extinction de la lumière de la pièce dans laquelle se trouvait le photobooth ! Cela signifie que la ligne COIN du monnayeur était pulsée sans qu’aucune pièce ne soit insérée ! Ce bug est évidemment inacceptable ! Comment faire fortune avec une telle machine !?

En reprenant un montage et un code simpliste destiné à afficher « PULSE DETECTE » à chaque front montant envoyé sur une GPIO, je suis parvenu à comprendre qu’il s’agissait de très courtes interférences électriques induites par le changement d’état de l’interrupteur de la pièce.

Ainsi, il faut réaliser un déparasitage logicielle pour être en mesurer de définir si le pulse est généré par :

  • une interférence : dans ce cas, il sera très court (inférieur à 100 ms) ;
  • un réel signal issu du monnayeur suite à l’insertion d’une pièce.

La fonction waitForRedButtonPush(delai) est donc nécessairement récursive pour pouvoir, à chaque faux-positif écarté, se rappeler elle-même en décrémentant le délai. Le délai doit être décrémenté car en cas de perturbations fréquentes, la fonction récursive pourrait se rappeler constamment avec un délai de 20 s sans que le timeout ne soit jamais atteint, ce qui conduirait, au cas où l’utilisateur n’appuierait pas sur le bouton rouge à une boucle infinie.

Alimentation de la LED

Une LED devient passante à partir d’un certain seuil de tension. Au-delà de ce seuil, la LED laisse passer tout le courant qui lui parvient : il est donc nécessaire de la protéger par une résistance pour ne pas être endommagée. Une résistance de protection est déjà présente sur la LED, on pourra donc l’alimenter directement. Cette LED fonctionne en 12v : les GPIO n’envoient que du 3.3v, on ne pourra donc pas les utiliser directement pour faire clignoter la LED. Il faudra donc utiliser la source 12v obtenue depuis le rehausseur de tension 5v->12v. Et pour le clignotement, nous allons devoir utiliser un interrupteur dont l’ouverture/fermeture peut être commandée à l’aide d’un signal envoyé depuis la GPIO 18. C’est justement le rôle d’un relais…

Le relais

Le relais est un interrupteur dont on commande l’état à l’aide d’un signal.

Connexion du relais pour commander la LED 12V du bouton rouge
Connexion du relais pour commander la LED 12V du bouton rouge

Par défaut, quand la broche Signal est à l’état LOW, la fiche Common de l’interrupteur est en contact avec la fiche NO. Lorsque la broche SIGNAL passe à l’état HIGH, la fiche Common est mise en contact avec la fiche NC.

Remarque : si le câblage Vcc et GND inversé, alors seule le LED du module relais s’allume lors du changement d’état du signal de commande sur la GPIO 18 mais le relais ne switch pas.

Problème d’alimentation du Raspberry

Au départ, j’envisageais d’alimenter la Raspberry avec l’alimentation 5V 10A à l’aide de câbles Dupont soudés sur le Prototype HAT. Ainsi alimenté, je constatais ponctuellement l’affichage d’un éclair jaune en haut à droite de l’écran signalant un problème d’énergie (notamment lorsque l’alimentation est instable) sur le Raspberry. Cet éclair apparaissait notamment au démarrage ou à l’exécution de la commande iwlist dont l’exécution exige de l’énergie pour scanner les hotspots wifis disponibles. En comparant la tension entre la sortie de l’alimentation, la sortie des fils dupont et la sortie aux broches +5V et GND du Prototype HAT, en constate une diminution de la tension au fur et à mesure que l’on s’éloigne de l’alimentation.

L’explication est la suivante : que ce soit les câbles Dupont ou le prototype HAT, les conducteurs sont fins et de fait, imposent une forte résistance entrainant une baisse de tension. Pour rappel, la relation entre la tension, la résistance et l’intensité est régie par la formule U = R x I. L’idée peut être vulgarisée à l’aide de la métaphore suivante : « peu de cuivre donc peu « d’espace » pour faire circuler les électrons qui se gênent mutuellement pour circuler ».

Remarques :

  • Chaque câble branché en série ajoute sa résistance au total, c’est-à-dire que ce n’est pas le plus petit qui fait goulot, c’est bien une addition ;
  • Plus le câble est fin, plus il est résistant. Plus le câble est long, plus il est résistant ;
  • Pour pouvoir déceler ces chutes de tensions, les tensions doivent être mesurées à l’aide d’un voltmètre lorsqu’un courant circule effectivement (Raspberry en fonctionnement), c’est-à-dire qu’un composant appelle des électrons (comme le dit la formule U = R x I). Dans le cas contraire, les électrons ne circulent pas et ne se « gênent » pas et les atténuations de tensions ne pourront donc pas être mises en évidence.

Face à ce problème, je me résous à utiliser un chargeur mini USB classique 5v 2.5A.

L’écran HDMI pourra quant à lui être alimenté directement depuis l’alimentation 5V 10A via des câbles dupont sans aucun problème.

La gestion des INPUTS sur les GPIOs

Les résistances Pull-up/Pull-down

Si une GPIO configurée en entrée n’est connectée à rien, alors elle sera « flottante ». Cela signifie que l’état de la GPIO est instable puisqu’elle n’est connectée à rien jusqu’à l’appui d’un switch réalisant le contact à la masse ou au +3.3v. Dans cet état instable, les interférences électriques induites par l’alimentation secteur influent fortement la valeur de la GPIO.

Pour éviter que la GPIO ne « flotte », il est nécessaire de la fixer à une valeur stable. Pour cela, on utilise une résistance (10Kohms est couramment utilisée) et deux options sont envisageables :

  1. Résistance pull-down : connectée à la masse par l’intermédiaire de la résistance, la GPIO est maintenue à l’état bas ;
  2. Résistance pull-up : connectée au +3.3v par l’intermédiaire de la résistance, la GPIO est maintenue à l’état haut.
Résistance pull-up et résistance pull-down permettant de maintenir une GPIO en INPUT à un état stable
Résistance pull-up et résistance pull-down permettant de maintenir une GPIO en INPUT à un état stable

Il est également possible de mettre en place une résistance pull-up/pull-down de manière logicielle puisque le module RPi.GPIO permet de configurer les GPIO du Raspberry à l’aide des instructions suivantes :

La méthode (basique) du polling

Si vous avez lu l’article sur la machine à blagues Chuck NORRIS, pour lire l’état des GPIOs en entrée, nous avions utilisé la méthode de polling qui consiste à tester à intervalles réguliers, l’état du GPIO à un instant précis. Dans le script Python, les instructions afférentes sont les suivantes :

Cette méthode est perfectible car un changement d’état sur la GPIO peut potentiellement échapper au test si le script Python sonde l’état de la broche au « mauvais moment », c’est-à-dire juste avant ou juste après le pulse électrique. Par ailleurs, lorsque l’on souhaite attendre l’appui sur un switch, le polling s’inscrit dans une boucle infinie.

Malgré l’instruction time.sleep(0.01), la méthode de polling peut s’avérer lourde pour la ressource CPU.

La méthode des interruptions

L’autre méthode, plus élégante et surtout plus efficace consiste à utiliser les interruptions, déclenchées à la détection des fronts (edge) sur le GPIO. Plutôt que de mesurer la valeur de la GPIO, nous allons ici nous intéresser aux changements d’états, appelés évènements. Ces évènements désignant le passage d’un état à l’autre, deux cas de figure se distinguent :

  1. De HIGH vers LOW : falling edge ;
  2. De LOW vers HIGH : rising edge.

Pour ne pas manquer un appui sur le bouton pendant que le script est occupé à exécuter un autre traitement, 3 fonctions sont à notre disposition :

  1. wait_for_edge() ;
  2. event_detected() ;
  3. une fonction de « callback », exécutée dans un thread parallèle au script principal lorsqu’un front est détecté.
La fonction wait_for_edge()

La fonction wait_for_edge() permet de bloquer l’exécution du script jusqu’à ce qu’un edge soit détecté. Nous avons eu recours à cette fonction au sein de la fonction waitForRedButtonPush(delai) (voir paragraphe sur le Bouton rouge ci-dessus) pour attendre l’appui :

On en conviendra, c’est nettement plus élégant que la boucle while de la méthode de polling évoquée ci-dessus et surtout la ressource CPU est épargnée.

Remarques :

  1. La méthode permet de détecter :
    • Les fronts montants : GPIO.RISING ;
    • Les fronts descendants : GPIO.FALLING ;
    • Les fronts montants ET descendants : GPIO.BOTH.
  2. Le paramètre timeout permet de fixer un délai (en ms) au bout duquel le script passera à l’instruction suivante : dans ce cas, le retour de la fonction wait_for_edge() est None ;
  3. Le paramètre bouncetime permet d’éviter le phénomène de rebond : à la détection d’un edge, les fronts suivants seront ignorés pendant le délai spécifié pour éviter le parasitage.

Le phénomène de rebond est parasitage lié à la génération de plusieurs edge alors que le switch n’est appuyé qu’une seule fois. Il est également possible d’utiliser un condensateur pour déparasiter les rebonds.

La fonction event_detected()

La fonction add_event_detected() joue le même rôle que la boucle while de polling mais elle apporte la garantie de détection de chaque évènement, même à un moment où le CPU serait occupé.

Les fonctions Threaded callback

La librairie RPi.GPIO permet de déclencher l’exécution de fonctions callback en parallèle du script principal (dans un nouveau thread), immédiatement après la détection d’un front sur la GPIO en input. Les lignes suivantes extraites du script photobooth.py permettent de définir les fonctions (stopPhotobooth() et haltPhotobooth()) à appeler sur détection de fronts montants sur les GPIO connectées aux switchs jaune et bleu :

En dupliquant les lignes ci-dessus, il est possible d’ajouter plusieurs fonctions de callback sur une même GPIO. Un seul thread étant créé pour l’exécution des fonctions de callback, celles-ci s’exécuteront séquentiellement (et non pas de manière concurrente) dans l’ordre de où elles sont ajoutées.

Enfin, il est possible de désactiver la détection de front sur une GPIO à l’aide de l’instruction :

Quelle que soit l’issue de la fonction waitForRedButtonPush(delai), cette instruction est exécutée pour libérer la GPIO RED_BUTTON et éviter les erreurs du type :

En effet, la fonction waitForRedButtonPush(delai) commence par activer la détection des edges sur le GPIO RED_BUTTON avec l’instruction :

Lorsque que cette fonction s’appelle récursivement, la nouvelle instance de la fonction active également la détection de front alors que l’instance appelante l’avait déjà activé sur le même GPIO.

Enfin, précisons que la fonction add_event_detect est également utilisée dans la librairie COINSELECTOR.py pour capter les pulses sur la ligne COIN du monnayeur. Exécutée dans un thread concurrent, la fonction de callback coinEventHandler(self, pin_number) (voir extrait de code ci-dessous) permet de gérer l’insertion de pièce par un utilisateur à n’importe quel instant, parallèlement à l’exécution du script principal.

 

L’écran LCD HD44780 20×04 et l’interface I2C

Nous avons déjà abordé le fonctionnement de l’écran LCD HD44780 dans un précédent article (voir la machine à blagues Chuck NORRIS), nous ne nous y attarderons donc pas davantage pour se concentrer sur l’interface I2C. En effet, l’écran peut être interfacé de deux manières pour la transmission de données (indépendamment de l’alimentation et du contraste de l’écran) :

  1. en reliant directement les broches Data sur les GPIOs du Raspberry, ce qui suppose d’hypothéquer 4 GPIOs en mode 4 bits voire 8 GPIOs en mode 8 bits ;
  2. par l’intermédiaire d’un module I2C n’exigeant que deux lignes pour les données : SDL et SDA.

Pour ce projet, les connexions sont déjà nombreuses sur les GPIOs et nous retenons l’utilisation d’un module I2C pour simplifier l’interfaçage de l’écran LCD HD44780 20×04 (20 colonnes, 4 lignes).

Ecran LCD HD44780 avec module I2C
Ecran LCD HD44780 avec module I2C

Un bus

Puisqu’il s’agit d’utiliser le bus I2C, commençons par rappeler ce que signifie ce mot galvaudé. Un bus est un dispositif de transmission de données partagé entre plusieurs composants par l’intermédiaire d’un canal de transmission commun. Le concept englobe donc à la fois :

  • le matériel sur lequel repose la communication ;
  • le protocole qui régit les échanges.

On distingue généralement un bus d’une part d’une liaison point à point, qui ne concerne que deux composants qui en ont l’usage exclusif, et d’autre part d’un réseau, qui implique des participants indépendants entre eux, c’est-à-dire pouvant fonctionner de manière autonome, et qui comprend plusieurs canaux permettant des communications simultanées.

Comme l’illustre le schéma ci-dessous, un bus comporte 3 sous-ensembles :

  1. Les lignes de données pour envoyer les données à transmettre ;
  2. Les lignes d’adresse pour indiquer quel composant doit émettre ou recevoir l’information présente sur le bus de données ;
  3. Les lignes de contrôle pour indiquer l’opération à effectuer.
Bus d'échanges de données
Bus d’échanges de données

Maintenant que l’on sait à peu près de quoi on parle, revenons aux GPIOs. Sur certaines d’entre elles, le Raspberry propose l’activation de bus/protocole de communication, à savoir :

  • I2C (Inter-Integrated Circuit) : il s’agit d’un bus série synchrone bidirectionnel half-duplex. Plusieurs équipements (master/slave) peuvent être connectés au bus, à l’aide de 2 lignes :
    • SDA (Serial Data Line) : données bidirectionnelles (GPIO n°3) ;
    • SCL (Serial Clock Line) : horloge de synchronisation bidirectionnelle (GPIO n°5) ;
  • SPI (Serial Peripheral Interface) : bus série synchrone full-duplex. La communication entre plusieurs équipements (schéma master/slaves) est réalisée à l’aide de 4 signaux logiques :
    • SCLK : Serial Clock (GPIO n°23) ;
    • MOSI : Master Output, Slave Input (GPIO n°19) ;
    • MISO : Master Input, Slave Output (GPIO n°21) ;
    • SS : Slave Select.

Parmi ces deux des bus série fonctionnant selon le schéma maitre/esclave, nous allons utiliser le bus I2C. Commençons tout d’abord par l’activer à l’aide de l’utilitaire raspi-config dans le menu « 5 Interfacing Options » puis redémarrer le Raspberry. Pour la transmission des données, le protocole de communication I2C s’appuie sur l’adresse des composants connectés au bus. Nous devons donc déterminer l’adresse de l’écran. Une fois l’ensemble d’outil I2C installé à l’aide de la commande sudo apt-get install i2c-tools, nous disposons de l’utilitaire i2cdetect permettant de détecter les esclaves présents sur le bus I2C :

Scan du bus I2C pour déterminer les adresses des périphériques présents sur le bus
Scan du bus I2C pour déterminer les adresses des périphériques présents sur le bus

L’adresse I2C du LCD est donc dans notre cas : 3F. Cette adresse sera utilisée dans la librairie Python RPi_I2C_driver.py destinée à piloter l’écran, dans laquelle on adaptera la ligne suivante :

La librairie RPi_I2C_driver.py

Commençons par télécharger la libraire RPi_I2C_driver.py (disponible à l’adresse https://github.com/emcniece/rpi-lcd). L’exemple fourni (example.py) permet de comprendre sans grande difficulté comment exploiter les fonctionnalités de la librairie.

Cette librairie s’appuyant sur le module smbus (import smbus), il devra être installé à l’aide de la commande :

L’affichage à obtenir est le suivant :

Informations affichées sur l'écran LCD HD44780 20x04
Informations affichées sur l’écran LCD HD44780 20×04

L’extrait de code ci-dessous illustre ainsi comment afficher les chaines sur les différentes lignes, charger en mémoire un « custom symbol » (ici, le symbole €) pour ensuite l’afficher sur les digits adéquats.

L’utilisateur pouvant introduire des pièces à n’importe quel moment, l’affichage de la dernière ligne CREDIT sera prise en charge par un thread destiné à actualiser en continu le crédit courant. Un zoom sur le code afférent est fourni ci-dessous.

Les variables moneybox et mylcd étant initialement créées dans le script principal, il est nécessaire de les déclarer avec le préfixe global dans la classe checkAndUpdateCredit(threading.Thread) afin qu’elles puissent être manipulées par le thread.

L’IMPRESSION THERMIQUE

Rappels sur la connexion et résolution des problèmes électriques

Comme nous l’avions déjà fait avec la machine à blagues Chuck NORRIS (voir le numéro 2 du magazine « L’officiel PC »), l’impression des photos sera réalisée à l’aide d’une imprimante série. La distribution Raspbian ayant évolué depuis, l’interfaçage est nettement plus simple : la désactivation du login shell et des messages du noyau envoyés sur le port série est désormais possible via l’outil raspi-config.

Pour « libérer » le port série, lancer l’utilitaire à l’aide de la commande sudo raspi-config, puis naviguer dans les menus 5 Interfacing options > P6 serial.

Pour tester le bon fonctionnement de l’imprimante, il est possible d’imprimer un « self-test ticket » sur lequel sera renseigné la table de caractère ainsi qu’un certain nombre d’informations techniques relatives au périphérique. Pour cela, il suffit de maintenir le bouton « feed paper » enfoncé à la mise sous tension. Lors du tout premier test, l’imprimante était provisoirement reliée à l’alimentation 5V à l’aide de câbles Dupont.

Comparés à ceux fournis avec l’imprimante, les câbles Dupont sont nettement plus fins et leur résistance électrique de facto, plus importante (voir détails précédemment évoqués dans le chapitre « Problème d’alimentation du raspberry »). Comme le montre l’image ci-dessous (partie gauche), la capacité de chauffe du périphérique ainsi alimenté est atténuée et le résultat dégradé.

Capacité de chauffe de l'imprimante réduite avec des câbles d'alimentation trop fins
Capacité de chauffe de l’imprimante réduite avec des câbles d’alimentation trop fins

Heureusement, la connectique fournie avec l’imprimante permet d’obtenir un qualité d’impression satisfaisante (à droite sur la photo ci-dessus) et le problème est rapidement résolu.

En revanche, il est possible qu’un autre phénomène vienne perturber l’impression selon le matériel que vous utilisez… Plutôt que de formuler de longues phrases sibyllines, je vous propose d’observer l’image ci-dessous…

Perturbations de la ligne TX par des interférences induites par l'alimentation low-cost de Raspberry
Perturbations de la ligne TX par des interférences induites par l’alimentation low-cost de Raspberry

Sur cette photo se trouvent les impressions obtenues à l’aide de la librairie py-thermal-printer (disponible à l’adresse https://github.com/luopio/py-thermal-printer) dans deux contextes différents :

  • A gauche : le raspberry était alimenté avec l’alimentation noire sans marque ;
  • A droite : le raspberry était alimenté avec l’alimentation blanche de marque SAMSUNG.

Identifier l’origine du phénomène n’étant pas nécessairement triviale, je vous livre l’explication sans détour… Si l’impression est dégradée (caractères inattendus et image décalée) cela signifie que la transmission des données (à imprimer) sur la ligne TX (entre le Raspberry et l’imprimante) n’est pas fiable. Et si la transmission n’est pas fiable, c’est parce qu’elle subit des perturbations (sur la ligne TX et GND) dues aux interférences émises… par l’alimentation (sans marque et de qualité moyenne) du Raspberry !

Remarque : éloigner l’imprimante de l’alimentation du Raspberry suffit à supprimer les interférences, c’est d’ailleurs pour cela que le problème n’était pas survenu sur la machine à blague Chuck NORRIS. Mais pour ce projet, tout doit être intégré à l’intérieur du photobooth et nous sommes contraints de recourir à une alimentation de qualité (tel qu’un chargeur SAMSUNG) pour résoudre le problème.

Utiliser une librairie Python 2 depuis un script Python 3 : le module PRINT.py

Pour exploiter le potentiel de l’imprimante série depuis le script Python, nous allons installer les librairies suivantes :

Téléchargeons la librairie mise à disposition par Adafruit à l’aide de la commande :

Parmi les fichiers présents dans le répertoire Python-Thermal-Printer créé à l’issue de la commande précédente, nous allons plus particulièrement nous intéresser au fichier Adafruit_Thermal.py. C’est ce fichier que nous allons utiliser depuis notre script photobooth.py. Cette bibliothèque est développée en Python 2 et l’absence de shebang indique que c’est l’interpréteur /usr/bin/python (sous-entendu, version 2). Le script photobooth.py est codé quant à lui avec la version 3 du langage et son exécution fait appel fait appel à l’interpréteur en version 3 comme le précise le shebang # !/usr/bin/python3.

Remarque : Le shebang est l’information placée sur la toute première ligne du fichier (exemple : # !/usr/bin/python) permettant d’indiquer le chemin de l’interpréteur à utiliser pour exécuter les instructions.

Ainsi, si l’on importe directement la librairie Adafruit_Thermal.py dans le script photobooth.py, le code de la librairie sera également parsé avec l’interpréteur version 3, ce qui conduira naturellement à la levée d’erreurs puisque du code Python 2 ne se conformes pas se conforme pas aux exigences de syntaxe introduites par Python 3. L’instruction import Adafruit_Thermal.py en début du script photobooth.py ne peut donc pas être envisagée. Pour s’affranchir d’un laborieux travail d’évolution de la librairie vers la version 3 du langage, nous allons contourner ce problème en créant un module PRINT.py écrit en Python 2 dans lequel sera importé le fichier Adafruit_Thermal.py. Le code chargé de l’impression (en utilisant les fonctionnalités de la librairie) sera déporté dans ce module. Enfin, il suffira d’appeler le script PRINT.py depuis photobooth.py avec l’interpréteur Python 2 à l’aide de l’instruction :

L’instruction subprocess.call (contrairement à subprocess.popen(), subprocess.call() bloque l’exécution du script appelant jusqu’au la fin du processus appelé) permet de créer un nouveau processus chargé d’exécuter la commande passée en paramètres : ici, il s’agit de lancer l’interpréteur Python auquel on fournit en argument le script PRINT.py, auquel on fournit en argument, le nom du fichier à imprimer.

Lancer le script photobooth.py au démarrage

Editer le fichier /etc/rc.local à l’aide de la commande :

Et ajouter (avant la ligne exit 0) la ligne suivante :

Le caractère « & » permet de lancer le script autostartphotobooth.sh en tâche de fond. Editons dès à présent le script autostartphotobooth.sh (nano autostartphotobooth.sh) et ajoutons les lignes suivantes :

Dans cet ultime chapitre, nous allons passer en revue un certain nombre de notions relatives à l’affichage et à la manipulation des images. Tout d’abord, pour un affichage sur l’écran HDMI, les modifications suivantes seront apportées dans le fichier /boot/config.txt :

La gestion des images

Dans cet ultime chapitre, nous allons passer en revue un certain nombre de notions relatives à l’affichage et à la manipulation des images. Tout d’abord, pour un affichage sur l’écran HDMI, les modifications suivantes seront apportées dans le fichier /boot/config.txt :

L’affichage graphique est réalisé à l’aide de la bibliothèque Pygame qui sera installée à l’aide de la commande suivante :

Assez simple à aborder, nous ne nous attarderons pas sur l’utilisation de Pygame. La lecture des deux premiers cours OpenClassroom sur le sujet vous suffira pour mettre en place rapidement l’affichage rudimentaire utilisé dans le photobooth. Intéressons-nous tout de même rapidement aux lignes suivantes extraites du script photobooth.py :

Une fois la fenêtre Pygame (il s’agit d’un objet de classe Surface) affichée en plein écran, le terminal sera masqué et les messages affichés sur la sortie standard ne seront plus visibles. Passée en paramètre au script photobooth.py, l’option –debug permettra de désactiver l’affichage de la fenêtre Pygame sans occulter les messages affichés par les instructions print() au fil de l’exécution du script. Cette option se révèlera bien utile pour débuguer le code.

Côté camera, la capture d’image fera l’objet d’ajustements au fil de l’exécution d’une session photo pour améliorer l’expérience utilisateur. Lorsque la caméra est à sa résolution maximum (s’agissant de ma PiCamera v2 : 2592×1944), le ratio largeur/hauteur (≈ 1.3) ne correspond pas à celui de l’écran (≈ 1.6) et l’affichage du flux vidéo laissent apparaître des bandes noires assez peu esthétiques.

Les ajustements opérés chronologiquement sont les suivants :

  1. la prévisualisation de la camera sera réalisée :
    • à la résolution de l’écran (800×480) afin que le flux vidéo utilise la totalité de l’écran ;
    • avec un « horizontal flip », permettant de réaliser l’affichage en reproduisant l’effet d’un miroir, plus naturel à l’utilisation du photobooth ;
  2. les clichés seront capturés avec la résolution maximum de la caméra pour des photos de qualité (l’adaptation est réalisée juste avant la capture, pendant l’affichage de l’écran SMILE ;
  3. un copie miniature de l’image capturée sera réalisée à la résolution 800×480 pour affichage à l’écran ;
  4. pour finir, l’image haute résolution est envoyée au script PRINT.py pour impression une fois les manipulations effectuées :
    • redimensionnement de l’image à 384×288 (384 étant la largeur maximum d’impression) ;
    • éclaircissement de l’image pour un meilleur rendu sur le papier thermique.

Extrait de la fonction shooting() du script photobooth.py :

Extrait du script PRINT.py :

Voilà pour la première partie de ce projet qui claque sa mère ! Rendez-vous dans quelques semaines pour la phase 2 où il sera question d’afficher un slideshow des photos prises par le photobooth.

L’Officiel PC Volume 3 et 4 : La Shopping List Machine et Le Media Center Kodi

C’est avec un peu de retard que je fais à nouveau la promotion du magazine « L’Officiel PC ». En effet, un peu plus de 3 mois se sont déjà écoulés depuis la parution du volume 2 : les numéros 3 et 4 sont déjà sortis ! Retrouvez un article dédié à la Shopping List Machine dans le numéro 3. Publié il y a quelques jours, le volume 4 comporte 10 pages détaillant l’installation de l’alpha à l’omega, du media center Kodi adossé à un espace de stockage LVM.

Bien entendu, l’ensemble des sujets abordés dans les pages de ces numéros sont très intéressants. A la lecture des différentes rubriques (matériels, astuces, dossiers techniques, projets complets,…), on en apprend toujours un peu plus sur le Raspberry Pi et le contenu constitue une remarquable source d’idées pour réaliser de nouveaux projets.

Couverture du magazine L'officiel PC volume 3
Couverture du magazine L’officiel PC volume 3

 

Couverture du magazine L'officiel PC volume 4
Couverture du magazine L’officiel PC volume 4

Shopping List Machine : Python, Code-barres EAN13, SQLite et imprimante thermique

A l’ère du « drive », l’intérêt de cette Shopping List Machine peut laisser dubitatif mais une chose est sûre : au travers de la réalisation de ce projet, vous en apprendrez beaucoup sur des notions variées. Les concepts impliqués sont denses et ne pourront être que survolés mais l’essentiel nécessaire pour se lancer est ici synthétisé.

La machine Shopping List composée d’un Raspberry, d’un scanner sans fil, d’une enceinte et d’une imprimante thermique

Mais avant d’entrer dans les détails techniques, formulons les exigences de la Shopping List Machine…

Continuer la lecture de « Shopping List Machine : Python, Code-barres EAN13, SQLite et imprimante thermique »

L’officiel PC volume 2 : un article dédié à la machine Chuck NORRIS

L’officiel PC volume 2 : un article dédié à la machine Chuck NORRIS

Retrouvez le projet « CHUCK NORRIS MACHINE » dans le deuxième numéro du magazine L’officiel PC RASPBERRY PI.

Couverture L'officiel PC Raspberry Pi Volume 2
Couverture L’officiel PC Raspberry Pi Volume 2

En réponse à l’appel à contribution figurant à la page 82 du premier numéro du magazine « L’officiel PC », j’ai soumis ma proposition d’article à l’équipe de rédaction (raspberry@idpresse.com).

A mon sens, le projet « Chuck NORRIS » s’inscrit dans l’esprit du magazine et constitue un excellent candidat pour y figurer. En effet, ce projet implique de nombreuses connaissances afférentes au Raspberry Pi, les GPIOs, le développement Python, l’électronique ou encore l’utilisation de périphérique avec le port UART. Et c’est ainsi que la machine à blagues Chuck NORRIS fait aujourd’hui l’objet d’un article au sein du volume 2, paru début avril 2017 !

Je remercie Benoît BAILLEUL (ainsi que son équipe de rédaction) pour avoir accepté ma proposition d’article au sein de cette édition qui lui consacre pas moins de 8 pages !

Caractère EOF des fichiers textes : \n pour Unix et \r\n pour Windows

Caractère de fin de ligne EOF (« End Of Line »)

J’ai une précision technique à apporter au sujet du caractère EOF. En effet, dans l’article concernant les aspects logiciels de la machine à blague Chuck Norris, j’indiquais que :

« Ici, le seul moyen que j’ai trouvé pour créer un fichier source valide, c’est par le biais d’un copier-coller de l’ensemble du texte à travers l’utilitaire PuTTY. »

C’est vrai que cette technique peu élégante fonctionne. Néanmoins, je n’ai compris que récemment pourquoi la commande strfile ne générait pas de fichier .dat valide depuis le fichier .txt copié depuis mon PC Windows… explications techniques. Revenons tout d’abord à ce qui se produit lorsqu’on applique la commande strfile sur un fichier .txt crée sur un environnement Microsoft. Voici « l’erreur » qui se produit :

Erreur de la commande strfile sur un fichier utilisant le caractère \r\n comme EOF
Erreur de la commande strfile sur un fichier utilisant le caractère \r\n comme EOF

Le retour de la commande indique qu’il n’y a qu’un seul string dans le fichier .dat généré. Ce qui est faux puisque le gisement de blagues Chuck Norris en contient près de 10 000 ! Quoi qu’il en soit, le fichier ainsi généré ne permettra pas à la commande fortune de fonctionner.

Caractère EOF différent selon l’environnement

Ceci s’explique par le caractère EOF. En effet, les fichiers textes n’utilisent pas le même caractère de fin de ligne selon qu’ils sont créés sur un système Windows (\r\n) ou Unix (\n).

Pour s’en convaincre, on pourra lancer la commande :

permet d’afficher le contenu du fichier en octal en faisant apparaître le caractère EOL. La solution consiste donc à supprimer les caractères \r du fichier créé sous Windows pour qu’il soit exploitable sur le Raspberry.

Pour cela, on pourra utiliser la commande sed (Stream Editor) :

qui permet de substituer le caractère \r par rien (en prenant soin auparavant de faire une sauvegarde chucky.txt.old du fichier original avec l’option –i.old). On remarquera ici qu’on remplace ‘\r’ par rien. On aurait pu essayer de remplacer ‘\r\n’ par ‘\n’… mais cela ne fonctionne pas. Pourquoi ? Ceci est lié au fonctionnement de la commande sed qui travaille ligne par ligne :

  1. elle parcourt le Stream jusqu’au caractère ‘\n’ ;
  2. charge tous les caractères avant le caractère ‘\n’ dans une zone de travail, le caractère EOF exclus ;
  3. effectue le traitement de substitution ;
  4. si l’option -i n’est pas précisée, la commande affiche le résultat sur stdout (l’écran) et aucune modification n’est faite sur le fichier passé en paramètre.

Une fois la commande exécutée, si on relance la commande :

on s’aperçoit que la substitution a fonctionner et que le caractère EOL est désormais \n. La commande strfile génère désormais un fichier .dat correct :

Commande strfile sur un fichier utilisant le caractère \n comme caractère EOF
Commande strfile sur un fichier utilisant le caractère \n comme caractère EOF

Le fichier .dat ainsi généré contient cette fois-ci 9692 strings ! En effet, les fichiers textes n’utilisent pas le même caractère de fin de ligne selon qu’ils sont créés sur un système Windows (\r\n) ou Unix (\n). Un simple copier-coller de l’ensemble du texte à travers l’utilitaire PuTTY réalisera la conversion automatiquement.

Ambilight sur Raspberry avec Hyperion

Ambilight avec Hyperion

Vous connaissez certainement le système « Ambilight » inventé par Philips qui prolonge l’image de la TV sur le mur par éclairage de couleurs cohérentes avec l’image courante grâce à un ensemble de LED. Pour améliorer l’expérience Kodi, il est possible d’équiper le Raspberry d’un tel système à moindre frais : un ruban de LED commandé par le logiciel Hyperion.

Avant d’en dire davantage, je vous propose de découvrir l’effet à obtenir en image :

Test de l'ambilight rainbow
Test de l’ambilight rainbow

Il s’agit ici de l’effet « Rainbow » lancé depuis l’application Android Hypérion Free. Bien entendu, l’utilisation principale reste l’amélioration de l’expérience visuelle pour visionner des films, mais il est également possible d’appliquer une couleur unie en continue ou encore des effets dynamiques prédéfinis sur l’ambilight, c’est ce que nous verrons avec l’application Android une fois que tout sera en place.

Liste du matériel pour l’ambilight maison

Je vous énumère ci-dessous le matériel nécessaire, avec un lien direct sur aliexpress :

Sans compter le coût du Raspberry, le système Ambilight en lui-même revient à 49.86€. C’est quand même un prix assez contenu et tout à fait abordable. D’autant que si l’on dispose déjà d’une alimentation, on économisera 1/3 du prix. Justement, puisqu’on parle de l’alimentation, comment définir l’ampérage nécessaire et suffisant ?

Calcul de l’ampérage

Pour définir la taille (ampérage) du bloc d’alimentation, il suffit de lire les caractéristiques du ruban de LED. Pour le modèle utilisé ici, le vendeur indique un « courant de travail » de 12A par 5m. Selon la taille de la TV à équiper, on définit le métrage nécessaire : pour ma part, je ne dépasse pas 4 mètres. En faisant un produit en croix, on obtient donc (4×12)/5=9.6. Ayant pris des mesures larges et ne souhaitant pas alimenter le Raspberry (le modèle 3 demande jusqu’à 2.5A pour son simple fonctionnement), une alimentation 10A est le bon calibrage.

D’une manière générale, pour calculer l’intensité à fournir par l’alimentation, il suffit de faire l’opération suivante (P = U x I) :

(Longueur ruban x Nombre de LED par mètre x Puissance d’une LED) /  5v = Intensité nécessaire en A.

Fonctionnement du ruban WS2801

Sur le ruban de LED WS2801, chacune des LED est adressable individuellement et peut donc être allumée (ou éteinte) indépendamment de toutes les autres. Comment ça marche ?

Le bus SPI : Serial Peripheral Interface.

Le Raspberry échange avec l’ensemble de LED au travers du bus SPI (Serial Peripheral Interface) disponible sur les GPIO. La liaison SPI est un bus série synchrone full-duplex permettant la transmission de données entre plusieurs équipements selon le schéma master/slaves à l’aide de 2 lignes de signal et 2 lignes de données :

  1. SCLK : Serial Clock ;
  2. MOSI : Master Output, Slave Input ;
  3. MISO : Master Input, Slave Output ;
  4. SS : Slave Select.

Toutes ces lignes sont unidirectionnelles. Le maître génère l’horloge et initialise une transmission de données en sélectionnant l’esclave avec qui il souhaite communiquer. Pour cela, chaque esclave est adressé par le maître par une ligne individuelle SS (Slave Select) et n’est actif que lorsqu’il est sélectionné par la mise à l’état haut de la ligne SS. Une fois l’esclave sélectionné, le maître envoie les données à transmettre sur la ligne MOSI.

Schéma Master-Slave(s) d'une liaison SPI
Schéma Master-Slave(s) d’une liaison SPI

Comme l’indique l’image ci dessus, il y a autant de lignes SS que d’esclaves. Le maitre sélectionne l’esclave à qui il souhaite s’adresser en mettant la ligne SS correspondante à l’état haut et envoie sur la ligne MOSI les données à transmettre. Plus il y a d’esclaves et plus il y a de lignes Slave Select, ce qui peut parfois rendre le montage rapidement complexe quand les slaves sont nombreux, comme c’est le cas d’un ruban de LED.

Il existe une alternative plus souple : le montage « daisy chain » selon lequel :

  • les slaves sont connectés en cascade : le MISO du slave N est connecté au MOSI du slave N+1 ;
  • il n’y a qu’une seule ligne SS pour tous les slaves.
SPI daisy chained
SPI daisy chained

Seul le premier slave reçoit les données directement depuis le maître.

Tant que la ligne CS reste à l’état LOW, à chaque cycle de commande (nombre de pulse sur l’horloge pour transmettre une commande), chaque slave reçoit des données/une commande venant du composant précédent (un slave également, sauf pour le slave 1 qui reçoit les données directement depuis le maître). En effet, si la ligne CS n’est pas activée, les slaves ignorent la commande reçue et la transmettront sur leur sortie MISO lors du cycle. A chaque cycle, les commandes viennent écraser la précédente dans chaque slave,… et c’est ainsi que les données sont propagées à travers la chaîne jusqu’à ce que chaque composant ait reçu la commande appropriée. Le passage à l’état HIGH de la ligne SS donne l’ordre à l’ensemble des composants de la chaine d’exécuter la commande qui leur est parvenue.

Le maître est ainsi en mesure de faire exécuter une commande différente à chaque slave avec seulement 3 lignes : SS, CLK et MOSI.

SPI et WS2801

Dans notre cas, c’est encore particulier. Aucune donnée n’est attendue en retour des LED vers le Raspberry, on n’a pas besoin de la ligne MISO. Et l’on constate que le ruban n’utilise que 2 lignes : Data IN et Clock (en plus de l’alimentation).

Sans aucune certitude au moment de la rédaction de ce paragraphe, j’imagine que cela revient à ce que la ligne SS soit constamment à l’état LOW, ce qui permet de propager les commandes de LED en LED. Et alors pour donner l’ordre d’exécution de la commande, j’imagine que l’ordre est donné au niveau logiciel, puisque le nombre de LED présentes sur le ruban est défini dans le fichier de configuration évoqué plus loin.

Installation matérielle

Le ruban de LED WS2801 ressemble à ça :

LED stripe WS2801
LED stripe WS2801

Comme l’indique une flèche présente sur le ruban, les données ne peuvent circuler que dans un sens (indiqué par une flèche). En revanche, le courant peut être fourni sur une extrémité ou sur l’autre. Parmi les lignes décrites ci-dessus dans la paragraphe SPI, on retrouve de haut en bas :

  • 5V ;
  • CK = Clock ;
  • SI = Data IN ;
  • GND.

ATTENTION : les fils du connecteur JST ne respectent pas le code couleur conventionnel des fils : le +5V est noir et le GND est bleu ! Il est prudent de vérifier ses branchements avant de mettre sous tension.

Pour couvrir le périmètre de la TV, il est nécessaire de couper le ruban sur les traits prévus à cet effet, de les juxtaposer perpendiculairement dans les angles de l’écran puis de les raccorder en soudant 4 fils :

Soudure des lignes 5V, CK, SI et GND.
Soudure des lignes 5V, CK, SI et GND.

Un adhésif se trouve au dos du ruban de LED et facilite l’installation sur la TV sans avoir à fabriquer un support supplémentaire. Une fois placé au dos de la TV, cela donne ça :

Ruban de LED relié perpendiculairement à l'aide de fils soudés
Ruban de LED relié perpendiculairement à l’aide de fils soudés

Le schéma de câblage est le suivant (numération BOARD utilisée) :

Schéma de câblage LED Strip WS2801
Schéma de câblage LED Strip WS2801
  1. CK -> SPI0_CLK = broche 23 ;
  2. SI -> SPI0_MOSI = broche 19.

Une fois le montage réalisé, on obtient :

Connexion du ruban de LED sur les GPIO du Raspberry
Connexion du ruban de LED sur les GPIO du Raspberry

Et puisque les détails sont essentiels pour des réalisations abouties :

Kodi Box
Kodi Box

Installation logicielle

Commençons par mettre à jour le Raspberry :

Puisque le Raspberry échangera avec le ruban de l’aide au travers du bus SPI implémenté sur les GPIOs vues plus haut, il est nécessaire d’activer ce bus SPI. Pour cela, il y a deux possibilités. Editer le fichier /boot/config.txt et décommentez la ligne suivante :

Ou bien passer par l’utilitaire de configuration raspi-config > 5 Interfacing Options > P4 SPI > Activer SPI.

Installons les paquets nécessaires :

Télécharger et installer l’outil hyperion :

Hyperion est un logiciel qui va fonctionner en tant que serveur au sens software, c’est à dire service, qu’une fois le service démarré sur le Raspberry, un nouveau port sera en écoute des requêtes à destination d’Hyperion. Par défaut, ce port est 19445.

A ce stade, le serveur Hyperion n’est pas démarré et ne peut pas l’être :

Comme le suggère le retour de la commande ci-dessus, pour pouvoir démarrer, le serveur Hypérion a besoin d’un fichier de configuration : le fichier /etc/hyperion/hyperion.config.json que nous allons générer à l’aide de l’outil hypercon…

Création du fichier de configuration Hyperion.json

Télécharger l’outil Hypercon : https://hyperion-project.org/wiki/HyperCon-Information. L’utilitaire HyperCon se présente sous la forme d’un .jar (HyperCon.jar). S’agissant d’une application Java, vous aurez nécessairement besoin d’un JRE installé sur votre PC pour pouvoir l’exécuter. Une fois lancé, l’outil se présente de la manière suivante :

Configuration d'Hyperion avec HyperCon
Configuration d’Hyperion avec HyperCon

Il s’agit ici de renseigner les champs avec les paramètres correspondants à l’installation physique des LEDs derrière la TV. Pour cela, on configure le nombre de LED horizontales, à gauche et à droite. Il est possible que le pied de la TV vous contraigne à ne pas couvrir une portion centrale sur le bas de l’écran, dans ce cas, il faudra préciser le Bottom Gap en nombre de LED.

Une fois le fichier généré à l’aide du bouton « Create Hyperion Configuration » en bas à gauche, on le place donc dans le répertoire /etc/hyperion. On peut maintenant démarrer le service :

Et contrôler qu’il est correctement démarré :

On peut également s’apercevoir que le port 19445 est à l’écoute :

Testons dès à présent l’allumage de toutes les LEDS en rouge pendant 5s avec une priorité de 50 (plus prioritaire que par défaut fixé à 100) :

 

Selon le ruban, certaines couleurs RGB peuvent être inversées.

Après avoir généré un premier fichier, j’ai constaté que Hyperion affichait du bleu au lieu du vert et inversement. J’ai donc configurer le paramètre RGB Bytes Order à RBG plutôt que RGB. Par défaut configuré à RGB, ce paramètre devra être adapté selon le ruban de LED utilisé.

Voici l’ambilight en fonctionnement, avec l’activation dynamique des LED pour prolonger de manière lumineuse, l’image sur le mur :

LED lighting
LED lighting

l’application Hypérion Free pour smartphone

Et pour finir, la cerise sur le gâteau ! Téléchargez l’application Hypérion Free sur votre smartphone et vous serez en mesure de télécommander le système ambilight :

L'application Hyperion Free vous permet de commander les LEDs depuis votre smartphone
L’application Hyperion Free vous permet de commander les LEDs depuis votre smartphone

En plus du cercle chromatique, un ensemble d’effets dynamiques est disponible pour tester l’ambilight.

Maintenant, on allume l’ambilight et on fait chauffer les pop-corn !