Module 8x8 LEDS pour un eCube 8x8x8 - 1/2

image principale Module 8x8 LEDS pour un eCube 8x8x8 - 1/2

Difficulté:

Les tutos de réalisation d'un cube de 8x8x8 LEDs ne manquent pas sur Internet.
Je leur trouve 3 inconvénients :
  1/ le câblage est lourd et complexe (souvent à cause de l'utilisation de registres à décalage)
  2/ ils ne sont pas accessibles par une page Web de contrôle
  3/ les animations sont figées dans le programme

L'idée est donc d'utiliser un ATmega 328p (Arduino UNO) pour un module de 8X8 LEDs (16 broches), de multiplier le module par 8 et de contrôler chaque module par un Raspberry Pi, qui offrira le serveur HTTP/PHP/JS nécessaire au pilotage WEB ou par shell BASH/Python.
La quantité de fils va être drastiquement réduite. Les animations pourront être chargées via le Raspberry Pi.

" Un A[rdui]no pour contrôler les Hommes, les Nains, les Elfes, ..., Un [RPi] pour les contrôler TOUS"

Ce 1er tuto va présenter la réalisation d'un unique module 8x8.
Suivra un 2ème tuto, pour réaliser le eCube 8x8x8 qui nécessitera 8 modules 8x8 et peut-être la réalisation d'une page Web pour piloter le cube depuis un navigateur.

ÉQUIPEMENTS

Pour commencer, tous mes documents sont sur mon cloud ici.
En matériel il vous faudra :
Un PC (très basique) sous Linux de préférence, Un Raspbberry Pi, 2 Arduino, dont un avec ATmega extractible comme celui-ci

RÊVE !

Je ne vous cache pas que je serai comblé, si ce projet suscitait de l'intérêt par quelques uns d'entre vous, pour un développement collaboratif. En effet la phase suivante qui consistera à créer le eCube 8x8x8, si elle ne présente pas de difficulté particulière pour la partie électronique, me semble par contre ardue pour ce qui concerne la réalisation d'une page WEB interactive.

Les bonnes volontés sont les (TRÈS !) bienvenues.

Matériel :

Budget : Non défini

Etape 1 : Réalisation du module 8x8

La grille de 64 LEDs est un montage classique qui met en commun 8 anodes sur 8 lignes et 8 cathodes sur 8 colonnes. Des 2N2222 pilotent les cathodes pour ne pas charger les broches de l'Arduino, chaque colonne pouvant recevoir le courant cumulé de 8 anodes soit : 8x20mA.

1ère maquette réalisée sur plaque d'essai et pilotée par un Arduino Uno

J'utilise du fil rigide des cordes à piano de 1mm, pour relier les LEDs. Elles sont fixées au moment de la soudure sur une matrice imprimée :  matrice 8x8 STL .
Les cordes à piano pour être faciles à souder sont passées au décapant.
Si vous ne possédez pas d'imprimante 3D, vous pouvez percer un panneau de bois aggloméré de 20x20cm avec une mèche de 5mm. Le pas entre chaque trou est un multiple de 2,54mm. J'ai choisi 7 x 2,54mm=17,78mm ce qui donnera un cube de ~142mm de côté.
Un fil fin relie chaque ligne (anodes) à la carte du circuit.

Comme je l'ai fait pour ma 1ère maquette, vous pouvez ne câbler que les LEDs et les transistors sur une plaque d'essai et vous connectez le tout à un Arduino Uno. Pour cette 1ère étape, ça suffit très bien pour atteindre l'objectif.
Vous pouvez aussi réaliser l'ensemble du circuit sur une plaque d'essai, ce qui demande un certain travail, ou enfin,  vous pouvez profiter du PCB dessiné à l'occasion sur Fritzing et dont je fournis et le fichier FZZ et la possibilité d'en demander la réalisation chez Aisler pour ~12€/carte. PCB chez Aisler  (je ne suis pas payé pour ça, mais je trouve le procédé facile et professionnel)

liste du matériel
schéma électronique

Etape 2 : Préparation de l'ATmega 328P


Chaque carte reçoit un ATmega 328 chargé d'un "bootloader" pour simplifier le chargement du code écrit avec l'IDE Arduino. Voir le tuto pour charger un bootloader dans un ATmega qui n'en dispose pas.
Pour fonctionner les ATmega 328 ne nécessitent qu'une alimentation 5V et une horloge constituée d'un quartz et de 2 capacités de 22pF, j'ai ajouté une résistance d'1MOhm pour améliorer le fonctionnement.

ATMega 328P + bootloader + quartz = ARDUINO UNO !

Les modules sont programmables directement avec l'IDE Arduino.


Un des modules reçoit le régulateur de tension pour une alimentation entre 5V et 12V.
Les autres modules sont découpés pour laisser la place à un Raspberry Pi dans le socle du futur cube.


Un connecteur [reset, Rx, Tx, GND, 5V] permet la programmation de l'ATmega.
J'utilise pour ma part un Arduino Uno dont l'ATmega est retiré, cela me permet de récupérer l'électronique d'adaptation USB/UART à moindre frais. Le câblage est direct broche à broche.

Une autre solution consiste à se procurer une carte USB/UART spécifique.
Pour fonctionner il faut ajouter un condensateur de 100nF en série entre la sortie DTR de l'UART et le reset de la carte.

Cette connexion n'est utile que pour la période d'écriture / débogage du programme de l'Arduino.

La liaison entre le module et le Raspberry Pi se fait en utilisant les 5 broches du connecteur vertical côté module et les broches sda(3), scl(5), GPIO4(7), GPIO14(8) +GND(6) côté RPi.

Pour ouvrir une session sur le Raspberry Pi, j'utilise une connexion SSH qui se fait via le réseau WIFI.

# ssh pi@picube.local

Voilà... Nous sommes prêts à programmer l'ensemble !

Etape 3 : Le programme sur l'Arduino - ATmega 328

Toute la partie qui suit dans ce chapitre, peut être zappée par ceux qui veulent juste utiliser le programme tel quel.
Il faudra juste vérifier les n° des broches utilisées en fonction de votre montage électronique.

ORGANISATION DE LA GRILLE[0]

L'affichage des LEDs est représenté en mémoire par un tableau de 8x8 octets (GRILLE). Un octet représente une colonne de 8 LEDs. Le bit de poids le +faible correspond à La LED la + basse. L'origine de notre grille est donc [0,0] en bas à gauche, la LED en haut à droite est codée [7,7].

TABLEAUX INTERNES AUX ARDUINO

Le module dispose de 3 zones de mémoires :
     1/ Pour l'affichage des LEDs une grille[0] de 8x8 octets est nécessaire, on vient de le voir, celle-ci est accompagnée de 15 autres grilles[1 à15] qui seront affichées en fonction d'un paramètre de sélection de grille.
Il sera possible de charger chacune des 15 grilles et d'en afficher le contenu à la demande.
    2/ Une zone de mémoire de données de 15x32 octets, qui correspond à 15 cellules de 32 octets. Ceci sera détaillé +loin.
    3/ Une zone tampon (FIFO) de stockage des instructions reçues. En effet comme le Raspi et les Arduino fonctionnent en mode désynchronisé, il est nécessaire de laisser fonctionner chacun à son rythme. Le tampon fonctionne en mode FIFO (First In, First Out) sur 128x3 octets en mode carroussel.
Comme ce tampon FIFO stocke les instructions, j'en profite pour l'utiliser en mémoire "arrière" pour ré-exécuter des commandes déjà passées.

Format et orientation des motifs
Tableaux internes de l’ATmega
GRILLE[16][8]: 16 x 8x8 octets
DONNEES[488] : 16 x 4x32 octets (CELLULE = 4 GRILLEs | 10 instructions (+2 octets))
FIFO[128]    : 128 x 3 octets (cache)
Format des Instructions : [ level, inst.][ P2, P1 ][ P4, P3 ]
                                           [ 2 x 4 bits ][2x4bits][2x4bits]
                                           [  octet  0   ][ octet 1][ octet 2]

COMMUNICATION INTER-MODULES ET Raspberry Pi

J'ai choisi d'utiliser le bus I2C pour communiquer en sens unique depuis le Raspi vers l'Arduino.
Le bus est simple à utiliser, ne nécessite que 2 fils+gnd et permet d'adresser plusieurs dizaines d'équipements.
Le Raspi est paramétré en maître et les Arduino en esclaves. Chaque environnement dispose de bibliothèque facilitant la programmation.

ADRESSAGE

Chaque module 8x8 va donc recevoir une adresse différente que le Raspi utilisera pour dialoguer individuellement avec ceux-ci.

Afin d'éviter que le programme des Arduino ne soit différent pour chaque module, un adressage physique est mis en place et une lecture de cette adresse est faite après chaque reset. J'utilise pour cela, 3 des 8 broches pilotant les cathodes de la grille de LEDs. La lecture de l'état de ces 3 broches ne doit pas déranger l'utilisation par la suite des broches en sortie. Je positionne donc le temps de la lecture, les 3 broches en INPUT, une résistance de 3,3K est connectée ou non au VCC. J'obtiens un 0 ou un 1 en fonction de la présence ou non de la résistance.
Le 1er module ne reçoit aucune résistance, le dernier en a 3. L'adressage démarre à 0x8 et peut atteindre 0xF si les 3 broches sont à 1, chaque broche ayant un poids = 2^n.

Le code de lecture est simple :

const byte CATHODE[8] = {17,15,11,9,5,1,6,0}; // broches utilisées pour les CATHODEs

const byte OffsetAdd = 2; byte I2Caddress=0x8; void setup() { // la présence des straps ajoutent les poids : 4 + 2 + 1 

for (byte i=0; i<3; i++) { pinMode(CATHODE[i+OffsetAdd], INPUT_PULLUP); // 3 broches des CATHODES sont utilisées en INPUT juste le temps de lire l'@ du module

I2Caddress = I2Caddress + (digitalRead(CATHODE[i+OffsetAdd]) << i); // n décalage.s à gauche = 1*2^n }

SÉLECTION DES DONNÉES / INSTRUCTIONS

Il est pratique de pouvoir différencier le type d'information envoyé aux Arduino, je vais utiliser pour ça la broche libre 2 (INT 0) :
        0 (LOW) ce sont des données
        1 (HIGH) ce sont des instructions
Rappelons à ce stade, que tant que le Raspi est en OUTPUT, il envoie un 3V3 sur l'entrée de l'Arduino, ce qui suffit à définir un état 1(HIGH).

DIALOGUE ENTRE MODULES ET RASPBERRY PI

Le Raspi va pouvoir envoyer aux Arduino des instructions codées sur 3 octets maximum. Ceci va permettre de réduire les temps de communication et surtout la quantité de mémoire utilisée de côté des Arduino.
     a/ le 1er octet contient sur :
           > 4 bits de poids fort, le niveau de grille à afficher
           > 4 bits de poids faible, le code d'instruction
     b/ les 2 autres octets codés eux aussi sur  2x4 bits, contiendront de 1 à 4 paramètres utiles en fonction des besoins de l'instruction.
(v. tableau ci-dessus)

Le programme IDE Arduino est ici : module8x8.2.ino


Etape 4 : Programme côté Raspberry Pi

J'ai choisi de faire le développement du projet sur un Raspberry Pi 0W, mais tout RPi convient et lorsque je passerai au eCube, peut-être devrai-je passer sur un Rpi 3.
Celui-ci est installé sous Raspian lite qui est beaucoup + économe en ressources. Y'a pas d'écran graphique. Et ça suffit pour ce projet !.

Depuis un terminal sur mon PC portable (sous Linux évidemment !) je me connecte au Rpi par :
  pintout@Aspire-ES1:~$ ssh pi@picube.local
On va passer en mode super utilisateur :
  root@picube:/home/pi#  sudo su
On en profite pour faire :
  root@picube:/home/pi#  apt update
  root@picube:/home/pi#  apt upgrade
À l'aide du :
  root@picube:/home/pi# raspi-config
il faut activer le bus I2C, le WIFI et l'accés SSH (v. pages de notre ami François Mocq)
J'y ai installé un serveur Apache + PHP, la bibliothèque WiringPi ainsi que les I2c-Tools et le WiringPi Python-smbus:
  root@picube:/home/pi# apt install apache2 php5 i2c-tools wiringpi python-smbus
Si on désire faire des beaux graphiques sur la page web, je vous suggère d'utiliser la bibliothèque JPGraph en suivant le tuto : Utiliser JPGraph

À ça, j'ajoute pour mon confort personnel : Rsync, Samba, joe, htop et ntp
   root@picube:/home/pi# apt install samba rsync joe htop ntp
NTP est un client d'accès aux serveurs de temps... Le Raspi sera toujours à l'heure
SAMBA va permettre un partage des dossiers pour les PC sous MS Windows.
Je suis sympa, je vous donne une configuration de partage pour Samba :
   root@picube:/home/pi# nano /etc/samba/smbd.conf
       ajoutez ces lignes à la fin du fichier :
       [PI]
             path = /home/pi
             browseable = yes
             read only = no
             force user = pi
             force group = pi
             create mode = 0774
             directory mode = 0774
   
root@picube:/home/pi# smbpasswd -a pi
        donnez un mdp à l'utilisateur samba "pi"
   root@picube:/home/pi# service smbd restart

Sur votre PC MS Windows, vous pouvez connecter le service par : \\picube\PI
Si vous êtes sous Windows 10 et que ça ne fonctionne pas... Démerdez-vous ! je ne suis pas là pour vous aider à utiliser un système de M.... ! Passez sous Linux !
Pour ce qui me concerne, comme je n'utilise QUE du LIBRE, mon PC est sous Linux XUBUNTU et je connecte le dossier du PI par SFTP (v. Gigolo) : sftp://pi@picube.local/
De cette manière je travaille depuis mon PC directement sur les programmes situés sur le Rpi, avec Bluefish comme éditeur de programmes Python et shell Bash. J'utilise un terminal SSH pour lancer et tester mes programmes

Revenons à nos moutons...
Le Raspi est normalement prêt.

Le programme le plus important est celui qui va interpréter et transmettre les instructions aux Arduino. Il est écrit en Python, Je l'appelle "ecube.py". Pour simplifier son utilisation, je crée un "alias" par la commande :
   root@picube:/home/pi# alias e3="python /home/pi/ecube.py"
cette commande peut être insérée dans le fichier /home/pi/.profile pour retrouver l'alias à chaque connexion.
Dans un script l'alias ne fonctionnera pas, il suffit de définir une variable : e3="python /home/pi/ecube.py" par exemple et d'utiliser $e3 à chaque que l'on en a besoin (v. exemple +loin).

ATTENTION, m.à j. 25 mars 18 :
J'ai fait une mise à jour en Python3, voici les changements :
  root@picube:/home/pi# sudo apt install python3 python3.smbus python3-rpi.gpio
il faut redéfinir les alias :
   root@picube:/home/pi# alias e3="python3 /home/pi/ecube.py"
   root@picube:/home/pi# alias e3v="python3 /home/pi/ecube-v.py"
ainsi que dans les scripts : e3="python3 /home/pi/ecube.py"

Etape 5 : LES INSTRUCTIONS DE COMMANDE

MODE COMMANDE

Des ordres directement envoyés par le Raspi sont exécutés par le module concerné. Ces ordres sont des primitives accompagnées de paramètres, exemples :

  1. format des commandes :     e3 N inst [[[[P1] P2] P3] P4]

       Je suppose  "e3" = "python /home/pi/ecube.py"
                            "N" : n° de grille | 'N'=0..15
                            "P(1,2,3,4)" : paramètres dépendants de la fonction | 'P'=0..15.
    il est obligatoire de passer "N", même si non utilisé.

        Instructions :

     e3 x reset : remise à zéro de l'ATmega (x quelconque)

     e3 N efface : efface la GRILLE n° 'N' | 'N'=0..15

     e3 N select : sélectionne la GRILLE n° 'N'et la met à l'affichage

     e3 x delai D : change la valeur de tempo | ‘D’=0..15

     e3 x charge 'fichier' : transfert contenu de 'fichier' dans DONNEES[488] de l'ATmega

     e3 N transf C P  : transfert le contenu de la CELLULE 'C', position 'P' sur la GRILLE 'N' | 'C'=0..15, 'P'=0..3 (note: si P>3 on déborde sur la CELLULE C+n, ce qui n'est pas un inconvénient)
     e3 x envoie 'fichier' : envoie le motif contenu dans 'fichier' qui sera directement transféré dans GRILLE[0] et affiché

     e3 x joueP1 P2 type : joue une série de motifs ou d’instructions | 'Pn'=0..15

         type = grille : sélectionne les GRILLES de ‘P1’ à ‘P2’

         type = motif : affiche les motifs des CELLULES ‘P1’ à ‘P2’

         type = inst : exécute les instructions des CELLULES P1 à P2

         type = cache : ré-exécute les ‘P1’ instructions arrières du cache FIFO.Pour ‘P2’=0 joue en boucle sinon 1 fois (la boucle s’arrête à la 1ère instruction reçue)

     e3 N car C: dessine une caractère alphanumérique ‘C’ (0..9, A..Z) sur la GRILLE ‘N’

     e3 N ligne X Y type dessine une ligne (point, lignes, croix, etc.) passant par ‘X’‘Y’ sur la GRILLE ‘N’ | X & Y=0..15

        type = .  : dessine un point

        type = -  : dessine une ligne horizontale

        type = ‘|’ : dessine une ligne verticale (utilisation de «» ou ‘ ’ ou \ obligatoire)

        type = G  : dessine une diagonale orientée à gauche (le symbole ‘\’ n’est pas utilisable, grrr !)

        type = /  : dessine une diagonale orientée à droite

        type = +  : dessine une croix

        type = X  : dessine une croix en X

        type = ‘*’ : dessine une étoile (utilisation de «» ou ‘’ ou \ obligatoire)

     e3 N carre X Y X1 Y1 : dessine un carré vide depuis ‘X’‘Y’ à ‘X1’’Y1’ sur la GRILLE ‘N’

     e3 N CARRE X Y X1 Y1 : dessine un carré plein depuis ‘X’‘Y’ à ‘X1’’Y1’ sur la GRILLE ‘N’

     e3 N cercle D X Y : dessine un cercle centré en ‘X’‘Y’sur la GRILLE ‘N’

  2. Des animations constituées de motifs ou de suites d'instructions, peuvent être chargées dans une mémoire de 15 cellules de 32 octets (tableau DONNEES[488]. Chacune de ces cellules pouvant stocker 4 motifs de grille (4x8 octets) ou 10 instructions (10x3 (+2 octets perdus)). Ces cellules seront "jouées" avec l'instruction "joue" et les paramètres [cellule de Début] [cellule de Fin] et [Type de cellule].(v. les commandes associées ci-dessus).

  3. Après un pré-remplissage des grilles[1 à 15], grâce à la commande 'transf' la sélection de la grille à l'affichage permet une animation sur 15 motifs différents (la grille[0] est toujours affichée).

EXEMPLE 

Voici un exemple de script possible en Shell Bash pour créer une animation :

   root@picube:/home/pi#  nano animation.sh # (si vous utilisez une connexion réseau au Rpi, vous pouvez éditer le document avec un programme d'édition simple, mais graphique comme "Kate".)

  • #!/bin/bash
  • e3="python /home/pi/ecube.py"   # pour simplifier l'usage du programme Python ecube.py
  • $e3 0 reset                                      # r. à z. du module
  • $e3 0 charge mes_motifs.txt          # chargement du fichier de motifs dans DONNEES[488]
  • for (( i=0; i<15; i++ )) ; do $e3 $[ $i+1 ] transf 0 $i ; done 
    # boucle de transfert des motifs de DONNEES[488] vers les GRILLE[x]
  • $e3 0 joue 1 15 grille                      # lancement 1ère animation 
  • $e3 0 joue 1 0 cache                       # lancement animation en boucle
  • sleep 10                                           # l'animation se joue 10'
  • $e3 0 select                                     # stoppe l'animation et efface la grille en cours
  • exit

   root@picube:/home/pi#  chmod + x animation.sh   # à ne faire qu'une seule fois
   root@picube:/home/pi#  ./animation.sh

MOTIFS

Les motifs sont une succession de 8 octets, le 1er représente la 1ère colonne, etc...
Si j'inscris "255,0,0,0,0,0,0,0" dans un fichier et que je charge le motif, j'obtiendrai une ligne verticale sur la 1ère colonne.
Pour simplifier la création de ces fichiers de motifs, je mets à votre disposition un document "calc" (Libre Office) motifs.ods qui permet de dessiner les grilles et de récupérer les codes correspondants.
Il suffit alors de sélectionner et de copier l'entête de chaque série de 4 cellules puis de les coller dans un fichier de texte avec un éditeur simple (Kate, Wordpad, Notepad, etc...)
Chaque ligne de ce fichier comprend donc 32 caractères et correspond à une cellule.
Il ne faut pas dépasser 15 lignes, soit 15 cellules (sinon gare au débordement de variable que l'IDE Arduino ne gère pas).
 

INSTRUCTIONS

C'est un peu plus compliqué pour les instructions, car il faut les donner au format compressé sous 3 octets, donc 6x4bits.

Je vous redonne le format ici : [ inst , level ][ P2 , P1 ][ P4 , P3 ]

Pour nous aider à déterminer les bonnes successions de codes à inscrire dans un fichier texte, je vous donne une version modifiée du programme "ecube.py"  nommé ecube-v.py ("v" comme verbose) qui affiche dans le terminal le code envoyé aux Arduino.

Ce qui donne par exemple :
  root@picube:/home/pi#  alias e3v="python /home/pi/ecube-v.py"  # à ne faire qu'une fois !
  root@picube:/home/pi#  e3v 0 joue 1 11 grille
    11
    177
    0

Il ne vous suffit plus qu'à inscrire dans le fichier, chaque valeur séparée par une ",".
Vous trouverez sur mon cloud des exemples d'animations.
Attention de vérifier l'@ du module, le mien est en 0xE, à modifier ci nécessaire.

petits films de démonstration 

Etape 6 : CONCLUSIONS

J'espère avoir suscité de l'intérêt avec mon projet .
J'attends avec impatience que des personnes me rejoignent dans le développement de cet eCube 8x8x8, surtout si vous apportez des compétences dans la création de pages WEB interactives. Je ne sais faire que du HTML/PHP et ça ne suffira pas à créer une belle interface ergonomique et dynamique.

Merci de votre attention

nb : l'éditeur du tuto mis à disposition par OuiAreMakers que je remercie au passage, ne me permet plus de joindre aucun fichier. Je vous rappelle donc mon lien vers le cloud du projet :
https://cloud.retzien.fr/index.php/s/V6Pz58GF1YUatuc
Tous les documents mis à disposition sont libres de droit et peuvent être utilisés, modifiés, distribués librement.

Voilà une réalisation d'un bon niveau avec une conception originale et astucieuse.

Le tutoriel est très pédagogique et précisément expliqué, bravo !

Merci pour vos encouragements. J'essaye de faire au mieux de mes capacités.

Très bon tuto mais les liens vidéos ne fonctionnent plus " Fichier non trouvé"

Bonjour Mic2001,
J'ai effectivement fais un ménage un peu trop rapide dans mon Cloud.
J'ai réactivé un lien vers le dossier vidéos : https://cloud.retzien.fr/index.php/s/XLiD3nBSsnjTPT9
Merci de votre intérêt pour mon projet, qui est certes en suspend pour l'heure, mais qui n'attend qu'une étincelle pour redémarrer.
Serge Pintout 

super projet ! merci du partage ! 

Ces tutoriels devraient vous plaire

vignette Connecter un  écran LCD en I2C
Connecter un écran LCD en I2C
vignette Arduino et Porte automatique de poulailler
Arduino et Porte automatique de poulailler
vignette Construire son Bartop Arcade de A à Z
Construire son Bartop Arcade de A à Z
avaatar Pintout Serge

Pintout Serge

Suivre

Vues: 484
Mis en favoris: 15

Découvrez d'autres tutoriels de

Pintout Serge

Un afficheur 4x7 segments pour ma moto

Découvrez tous les tutoriels partagés sur Oui Are Makers

Powered by Oui Are Makers