Aller au contenu

LEDBox : Boîte interactive à LED – Effet Sable et FlappyBird

Dans le cadre du module Makers, nous avons choisi de réaliser une boîte interactive constituée d’une matrice de LEDs interactive.

I. Introduction

1 – Présentation du sujet

Ce projet a pour objectif de créer une boîte dotée d’une matrice de LED 32×16, capable de fonctionner dans deux modes différents grâce à un interrupteur :

  • Un mode « Sable » où les LEDs simulent des grains de sable qui réagissent à l’inclinaison de la boîte, grâce à un gyroscope,
  • Un mode « FlappyBird », où l’utilisateur peut appuyer sur la matrice de LEDs à la manière d’un écran tactile et dont l’appui permet de contrôler la position de l’oiseau dans ce jeu, grâce à des cellules d’effort.

Ce projet combine électronique, programmation Arduino et fabrication makers de composants.

Nous avons choisi de travailler sur ce sujet à partir d’une vidéo sur laquelle nous sommes tombés sur Instagram, et qui nous a beaucoup plu :

Projet de @david_proyectos (Instagram)

2 – Liste des composants

  • 2 matrices de LED RGB 16×16 WS2812B (écran 32×16 LEDs)
  • Microcontrôleur ESP32
  • Gyroscope 3 axes MPU6050
  • 4 capteurs de poids HX711
  • Interrupteur 2 positions
  • Boîtier en bois en MDF 3mm, réalisé à la découpeuse laser
  • Plaque en plexiglass transparent PMMA 3mm, réalisé à la découpeuse laser
  • Pile 9V et régulateur
  • Câblage, breadboard

II. Fonctionnalités

Comme expliqué en introduction nous avons choisi de développer deux modes de jeu afin d’exploiter cet écran-matrice de LEDs.

1 – 1er mode : effet Sable

a) Fonctionnement du mode

Lorsque le mode « sable » est activé, les LEDs représentent des grains qui tombent en fonction de l’inclinaison de la boîte. On simule ainsi un comportement d’écoulement et d’écrasement le long des parois de l’écran, des LEDs allumées.

b) Utilisation du gyroscope

Nous avons choisi d’utiliser un gyroscope MPU6050 afin de fournir les données d’accélération sur les axes X et Y de notre matrice de LEDs. Ces données sont utilisées pour calculer l’inclinaison et adapter le mouvement des LEDs en conséquence.

En effet, idéalement dans un objet statique l’accélération sur l’axe Z est égale à la force gravitationnelle, et elle doit être nulle sur les axes X et Y. En utilisant les valeurs de l’accéléromètre, il est possible de calculer les angles de roulis et de tangage.

Pour exploiter ces données, nous avons d’abord effectué une calibration du capteur MPU6050 au démarrage. Cette étape consiste à mesurer plusieurs fois l’accélération sur les axes X et Y alors que la matrice est posée à plat et immobile, afin de déterminer un offset moyen sur chaque axe. Ce décalage est ensuite soustrait aux valeurs lues en temps réel, pour corriger les petites erreurs ou biais du capteur.

À chaque boucle du programme, nous lisons les valeurs d’accélération actuelles de l’axe X et Y (respectivement ax et ay), que nous corrigeons à l’aide de ces offsets. Ces accélérations corrigées sont divisées par un facteur (ici 350.0) pour les ramener à une plage de valeurs adaptée, ce qui nous donne les accélérations accelX et accelY que nous utilisons pour influencer le mouvement des grains.

Ces valeurs accelX et accelY servent à modifier la vitesse de chaque grain.

Elles traduisent l’inclinaison de la carte : par exemple, si on incline vers la droite, accelX augmente. À chaque boucle, on ajoute ces valeurs à la vitesse actuelle de chaque grain.

Cela veut dire que plus on incline la carte, plus les vitesses velX et velY vont changer rapidement, ce qui pousse les grains dans la direction de l’inclinaison. Ensuite, on applique un coefficient de frottement. Cela réduit légèrement la vitesse à chaque tour, comme si les grains glissaient sur une surface avec résistance. Puis on limite leur vitesse pour éviter qu’ils ne deviennent trop rapides.

velX[i] += (int8_t)accelX;
velY[i] += (int8_t)accelY;
// Application de la "friction"
velX[i] = (velX[i] * friction[i]) / 100;
velY[i] = (velY[i] * friction[i]) / 100;
// Limite de vitesse
velX[i] = constrain(velX[i], -1, 1);
velY[i] = constrain(velY[i], -1, 1);

Ensuite, on calcule la nouvelle position en ajoutant cette vitesse à la position actuelle: chaque grain est déplacé d’un pixel au maximum par boucle, dans la direction de l’accélération détectée. On vérifie ensuite si la case est libre avant de déplacer réellement le grain.

En cas de collision, la direction est inversée (rebond simple) :

int newX = constrain((int)posX[i] + velX[i], 0, MATRIX_WIDTH - 1);
int newY = constrain((int)posY[i] + velY[i], 0, MATRIX_HEIGHT - 1);
if (!isOccupied(newX, newY, i)) {
  posX[i] = newX;
  posY[i] = newY;
} else {
  velX[i] = -velX[i] / 2;
  velY[i] = -velY[i] / 2;
}

Finalement, chaque grain est affiché en couleur sur la matrice :

uint16_t color = matrix.Color(120, 0, 180); // Violet
matrix.drawPixel(posX[i], posY[i], color);

Ce mécanisme permet de simuler une physique simple et interactive, où les grains « tombent » et « glissent » dans la direction de l’inclinaison.

c) Câblage, intégration au boîtier et programmation

Le gyroscope est relié au microcontrôleur via le bus I²C. Il est positionné au centre du boîtier pour une mesure équilibrée des mouvements. On câble comme ceci ce module :

Pin du gyroscopeCorrespondanceESP32
VCCAlimentation du capteur (3,3V)Pin 21
GNDMasseGND
SCLBroche SCL pour communication I2CPin GPIO22
SDABroche SDA pour communication I2CPin GPIO22
d) Matrice de LED

La matrice de LEDs utilisée dans le projet est une grille de 32 colonnes sur 16 lignes de LEDs RGB adressables, contrôlée par la bibliothèque Adafruit_NeoMatrix. Elle fonctionne en envoyant les données d’affichage à une seule broche (ici la broche 5), les LEDs étant connectées en série. Chaque LED peut être allumée individuellement selon sa position (x, y) et une couleur définie en RGB. L’affichage est d’abord mis en mémoire, puis affiché sur la matrice avec la commande matrix.show(). À chaque boucle du programme, l’écran est vidé, les nouvelles positions des particules sont dessinées, puis l’affichage est mis à jour.

On banche la matrice de LEDs de la façon suivante :

Câble de la matriceCorrespondanceESP32
Fil rougeAlimentation de la matrice (5V)Alimentation 5V grâce à une pile 9V et un régulateur
Fil blancMasseGND
Fil vertSignal de donnéesPin GPIO5

Il est également possible d’interconnecter plusieurs matrices entre elles afin d’en agrandir la taille. C’est ce que nous avons fait avec deux matrices 16×16.

e) Processus

Nous avions initialement développé notre projet sur une carte Arduino Uno. Le système de particules fonctionnait correctement avec une petite matrice de 16×16 LEDs et un nombre réduit de grains (autour d’une quarantaine). Cependant, lorsque nous avons tenté d’augmenter la taille de la matrice à 32×16 afin d’obtenir un affichage plus large et plus fluide, la mémoire disponible sur l’Arduino Uno s’est révélée insuffisante. L’augmentation du nombre de LEDs et de particules à gérer entraînait une surcharge de la RAM, provoquant des comportements instables. Pour surmonter cette limitation, nous avons migré le projet vers une carte ESP32, qui offre une capacité mémoire bien plus importante ainsi qu’un processeur plus rapide. Grâce à cette transition, nous avons pu gérer l’ensemble des 512 LEDs de la matrice 32×16, tout en conservant un nombre élevé de particules (jusqu’à 160) avec une animation fluide. Cette nouvelle plateforme nous permet désormais d’exploiter pleinement le potentiel visuel du sable animé en temps réel, tout en intégrant des capteurs comme le MPU6050.

Voici une vidéo de démonstration :

2 – 2e mode : FlappyBird sur « écran tactile »

a) Fonctionnement du mode

Dans ce mode, l’utilisateur peut appuyer sur « l’écran », c’est-à-dire la plaque en Plexiglass, afin de donner une direction à l’oiseau du jeu FlappyBird. En effet, on place des quatre côtés de la matrice de LEDs des capteurs d’effort afin de pouvoir localiser, lorsque ces capteurs sont correctement calibrés, l’endroit sur cette plaque sur lequel l’utilisateur appuie avec son doigt.

Les enjeux de cet ajout ont été l’intégration des capteurs à l’écran, le traitement des informations fournies par les quatre capteurs, ainsi que la calibration de ces cellules de force.

b) Utilisation des capteurs de pression

Nous avons choisi d’utiliser les cellules de charge à jauge de contrainte HX711 qui sont, semble-t-il, assez classiques pour ce type d’usage.

Concernant leur fonctionnement, une cellule de charge convertit une force en un signal électrique qui peut être mesuré.

Cette cellule est constituée d’un pont de Wheatstone. Lorsqu’elle subie une torsion, les résistances du pont changent et la tension V+ − V− est proportionnelle à la pression qui s’exerce sur la barre. Le module HX711 sert à amplifier et mesurer cette tension.

La résistance des jauges de contrainte varie lorsqu’une force externe est appliquée à un objet, ce qui entraîne une déformation de la forme de l’objet (dans ce cas, la barre métallique). La variation de la résistance est proportionnelle à la charge appliquée, ce qui nous permet de calculer le poids des objets, ou ici dans notre cas localiser le point d’appui de l’utilisateur sur la plaque de Plexiglass.

Les capteurs de pression sont répartis sous la plaque. Les quatre cellules mesurent en continu le poids appliqué sur chacune d’entre elle, et calcule (développer) le barycentre afin de localiser l’endroit de l’appui.

c) Câblage et intégration au boîtier

On relie la cellule de charge et l’amplificateur de la cellule de charge comme ceci :

Cellule de chargeHX711 (entrée)HX711 (sortie)ESP32
Fil rougeE+VCC5 V
Fil noirE-GNDGND
Fil vert (V+)A+DTData – Pin GPIO…
Fil blanc (V-)A-SCKClock – Pin GPIO…
d) Démonstration

Nous avons dans un premier temps essayé de calculer la position XY de l’appui de l’utilisateur :

On remarque bien que la position varie correctement avec les appuis de l’utilisateur à différentes coordonnées. Cependant, les mesures restent trop peu précises pour arriver à obtenir des coordonnées au pixel près.

Ensuite, nous avons utilisé un programme afin de lier le calcul des coordonnées grâce aux efforts mesurés sur chaque HX711, et un affichage sur la matrice de LEDs. On constate bien que la boule de LEDs bouge, mais cela reste trop peu précis pour arriver à jouer au Jeu FlappyBird.

Voici une vidéo de démonstration :

Nous avons tout de même réalisé une animation reproduisant le décor de FlappyBird :


III. Réalisation du boîtier

1 – Modélisation de la boîte

Le boîtier a été modélisé en 3D sur Onshape.

2 – Optimisation de la position des capteurs de pression

Nous avons ajouté une pièce intermédiaire (en gris) permettant de faire un appui pour les capteurs de pression. En effet, il est nécessaire d’avoir un appui stable sur leur face inférieure, et un appui mobile (Plexiglass) sur leur face supérieure, afin de détecter les poids correctement.

3 – Découpe laser

Les faces du boîtier ont été découpées au laser dans du bois MDF de 3 mm, et la plaque transparente en PMMA de 3 mm.


IV. Alimentation du système

Pour alimenter notre système, nous avons choisi une pile 9V, principalement pour sa simplicité d’intégration et sa disponibilité. Toutefois, cette tension n’est pas directement compatible avec les composants de notre montage, qui nécessitent des tensions plus basses et surtout stables. C’est pourquoi nous utilisons un régulateur LM2596, un module buck (abaisseur de tension) capable de convertir efficacement les 9V d’entrée en 5V, tout en fournissant un courant suffisant pour alimenter la matrice LED et l’ESP32.

La matrice NeoPixel fonctionne en 5V, tandis que l’ESP32, plus sensible, fonctionne en 3.3V. Le LM2596 fournit une sortie 5V stabilisée, que nous utilisons pour alimenter directement la matrice, et que nous injectons sur l’entrée VIN de l’ESP32. Cette dernière intègre son propre régulateur linéaire interne, qui abaisse les 5V à 3.3V pour les besoins de son cœur de calcul. Ainsi, les deux composants sont correctement alimentés à partir d’une seule source régulée. De plus les deux capteurs (gyroscope et de pressions) sont aussi alimentés en 3.3V.

Ce choix nous permet de sécuriser le fonctionnement du système en évitant les surtensions, tout en assurant une alimentation suffisante pour une matrice 32×16, même avec plusieurs LEDs allumées simultanément. Néanmoins, les limites en capacité de courant de la pile 9V nous ont poussés à réduire la luminosité globale des LEDs afin d’éviter les chutes de tension et garantir une autonomie correcte.


V. Conclusion

Ce projet propose deux interactions originales avec une matrice LED : un mode Sable qui permet de combiner utilisation d’un gyroscope et d’une matrice de LEDs, et un mode FlappyBird certes non abouti, mais qui nous a tout de même permis de nous initier à l’utilisation de jauges de contraintes et manipuler les machines disponibles au FabLab. Nous n’avions aucune expérience Makers avant ce module, et ce projet nous a permis de nous initier à Arduino et aux machines du FabLab.

Pistes de développement

  • Ajouter un écran OLED pour afficher un score
  • Intégrer des effets sonores pour chaque action
  • Créer d’autres modes afin de jouer à des jeux avec l’écran tactile
  • Permettre un mode multi-joueurs dans d’autres jeux à implémenter.

Sources

Cours d’électronique des projets Makers – Adrien Boussicault, EirLab

http://electroniqueamateur.blogspot.com/2020/05/matrice-de-leds-rgb-16-x-16-ws2812b-et.html

https://www.instructables.com/How-to-Interface-HX711-Balance-Module-With-Load-Ce

https://randomnerdtutorials.com/esp32-load-cell-hx711

https://github.com/bogde/HX711