Utiliser Adafruit FadeCandy pour le contrôle de LED

Présentation

Source de l'image : Adafruit

La collaboration entre Adafruit et Micah de Scanlime a abouti au lancement de FadeCandy, une carte de circuit d'attaque avec tramage intégré contrôlable par USB. FadeCandy inclut à la fois des éléments matériels et logiciels facilitant la création et le contrôle des projets artistiques à LED adressables WS2811/WS2812, ce qui permet d'obtenir des projets plus esthétiques et moins exigeants quant aux ressources du microcontrôleur. FadeCandy constitue un excellent moyen de démarrer pour les débutants, et fonctionne également comme un outil avancé pour les professionnels.

Le logiciel FadeCandy Server communique avec une ou plusieurs cartes FadeCandy. Il s'exécute sur Windows, Linux, Mac OS ou sur les plateformes embarquées comme Raspberry Pi. Le protocole Open Pixel Control offre un moyen facile de transférer des données de pixels au serveur FadeCandy. Chaque carte de contrôleur prend en charge jusqu'à 512 LED, disposées en 8 rubans de 64, mais les LED RVBB ne sont pas prises en charge. Seules les LED RVB sont prises en charge au moment de la publication de cet article. La programmation de base est abordée plus loin dans cet article.

Le projet étudié ici utilise 52 LED NeoPixel d'Adafruit dans chacune des huit colonnes destinées à inciter les joueurs à utiliser une machine à pince tout en servant de minuterie visuelle pour le compte à rebours. L'utilisation d'un grand nombre de LED adressables et de bibliothèques Arduino traditionnelles avec une connexion directe aux GPIO ralentit le processeur et entraîne des retards dans les fonctions du jeu ainsi que des problèmes de temporisation de l'exécution. Comme un Raspberry Pi 3 est déjà prévu pour les effets sonores de la machine à pince, la communication lumineuse avec la carte FadeCandy sera ajoutée à la liste des tâches du Pi 3.

Déterminer les exigences d'alimentation

La consommation énergétique est un facteur important lorsque vous utilisez des rubans LED. Même si chaque LED de couleur n'utilise que 20 mA de courant, chaque NeoPixel d'Adafruit, à titre d'exemple, dispose de trois couleurs, soit un total de 60 mA si les trois LED sont actives. Multipliez cela par les 52 NeoPixel en parallèle sur chaque ruban, et le courant maximum de chaque ruban dépasse 3 A. En multipliant ce courant par 8 colonnes, on obtient une consommation de courant potentielle de 25 A, sans compter les divers rubans plus petits disposés autour du projet. Mais pourquoi un projet aurait-il besoin d'avoir toutes les LED de chaque NeoPixel allumées simultanément pendant de longues périodes ? La réponse est que cela n'arrivera pas, c'est pourquoi la sélection d'une alimentation se transforme en devinettes. En supposant que 75 % des LED NeoPixel sont allumées à un moment donné et que chacune n'affiche qu'une seule couleur, le courant tombe à environ 6 A. Il n'existe qu'un seul moyen d'en avoir le cœur net : programmer un scénario d'éclairage et tester la consommation de courant avec un appareil de mesure.

Utiliser une carte Breakout pour résoudre les problèmes de conception et de câblage

Avant de commencer la programmation, un circuit imprimé personnalisé est conçu à l'aide de KiCad afin de dériver les connexions FadeCandy sur des blocs de jonction pratiques, ce qui facilite la connexion et l'organisation des sorties. Pour la machine à pince, les LED orientées vers l'arrière se trouvent sur un seul canal, tout comme celles orientées vers la droite, vers la gauche et vers l'avant, afin de préserver les canaux. Les LED supérieures et inférieures du compartiment où tombent les prix sont dérivées séparément, ce qui laisse deux canaux pour d'éventuelles connexions auxiliaires.

La carte Breakout doit comporter des pistes capables de gérer l'appel de courant potentiel du bus d'alimentation. Le choix du cuivre 2 oz pour la carte permet également de prendre en charge de plus grandes quantités de courant. Les Figures 1 et 2 présentent un exemple de circuit imprimé créé à l'aide de KiCad et de l'outil PCB Builder de DigiKey.

Figure 1 : Carte à circuit imprimé nue du fournisseur.

Figure 2 : Pistes du bus d'alimentation à fort courant.

Préparation de l'outil PCB Builder

Une fois entièrement développé, un circuit imprimé personnalisé est exporté en utilisant la fonctionnalité Plot du menu File de l'outil de conception de circuit imprimé dans KiCad. Dans la boîte de dialogue Plot, cliquez sur le bouton Generate Drill File pour enregistrer un fichier de perçage Gerber dans le dossier de votre choix. Cliquez ensuite sur le bouton Plot. KiCad crée alors des fichiers Gerber supplémentaires et les place dans le même dossier que le fichier de perçage. En utilisant le gestionnaire de fichiers Windows, accédez au dossier qui contient les fichiers Gerber. Sélectionnez tous les fichiers relatifs au circuit imprimé, puis faites un clic droit sur l'ensemble de fichiers et sélectionnez Envoyer vers... Dossier compressé. Un nouveau dossier compressé apparaît alors dans le dossier d'origine.

L'outil PCB Builder basé Web de DigiKey facilite la commande de cartes à circuit imprimé personnalisées en proposant un large éventail d'options et de fournisseurs. Une fois l'outil PCB Builder lancé, cliquez sur le bouton Télécharger un fichier Gerber, puis accédez au dossier compressé créé précédemment et sélectionnez-le. Une fenêtre de visualisation de l'outil PCB Builder s'ouvre avec une image de la carte et une liste des fichiers/couches à inclure dans la production, comme illustré à la Figure 3.

Figure 3 : Visionneuse PCB Builder, première étape de l'utilisation de l'outil PCB Builder de DigiKey.

La fenêtre Visionneuse PCB Builder offre de nombreux outils pour examiner la carte à circuit imprimé proposée. La molette de la souris permet d'effectuer des zooms avant et arrière, tandis que le curseur en forme de main permet de déplacer le circuit imprimé dans toutes les directions. Les couches peuvent être visualisées de manière sélective en cliquant sur l'icône en forme d'œil à côté de chaque couche dans la liste des couches.

Cliquez sur le bouton Terminer le téléchargement pour passer à l'étape suivante de la commande. La fenêtre suivante affiche les statistiques pour le circuit imprimé et une liste d'options à sélectionner, comme les couleurs et l'épaisseur du cuivre (voir la Figure 4). Notez que la sélection d'options modifie les prix et la disponibilité des fournisseurs qui peuvent ne pas proposer les options sélectionnées. Commencez par une seule carte, puis faites d'autres sélections selon les besoins.

Figure 4 : Choix des spécifications de circuit imprimé, du fournisseur et de la quantité.

Lorsque vous avez effectué toutes les sélections et déterminé le fournisseur de votre choix, augmentez la quantité de cartes d'une unité à la fois tout en observant le prix. Répétez cette opération jusqu'à ce que le prix augmente. Cette méthode permet de déterminer le nombre maximum de cartes pouvant être produites au prix le plus bas. Cliquez sur le bouton Ajouter au panier lorsque vous êtes prêt à commander.

Assembler la carte Breakout personnalisée

La carte à circuit imprimé terminée inclut des blocs de jonction de rubans LED, des blocs de jonction d'alimentation et une embase à 16 broches. La carte FadeCandy d'Adafruit est équipée de broches d'embase et insérée dans l'embase sur le circuit imprimé avec une entretoise imprimée en 3D pour prendre en charge l'extrémité USB de la carte. Voir la Figure 5.

Figure 5 : Carte Breakout personnalisée entièrement équipée.

Pour mettre en œuvre la carte et commencer la programmation, un banc d'essai composé de 8 colonnes de 26 NeoPixel d'Adafruit est utilisé pour démontrer le concept. Ce nombre sera ensuite porté à 52 NeoPixel dans la machine à pince réelle.

Connectez les rubans LED aux blocs de jonction verts en respectant les branchements d'alimentation et de signal. Une source d'alimentation de 5 V est connectée aux blocs de jonction noirs en respectant les branchements d'alimentation et de mise à la terre. La Figure 6 montre le câblage NeoPixel avant d'utiliser la carte Breakout et la Figure 7 montre les améliorations apportées au câblage.

Figure 6 : Câblage sur banc d'essai avant d'utiliser une carte Breakout.

Figure 7 : Banc d'essai avec carte Breakout.

Une fois le matériel et le câblage en place, connectez un Raspberry Pi 3 à la carte FadeCandy à l'aide du câble USB approprié, puis connectez le Raspberry Pi à un écran, à un clavier et à une souris. Mettez le système sous tension pour commencer la programmation. La carte FadeCandy est configurée en tant que client recevant les données via USB depuis le Pi agissant en tant que serveur. Dans cette configuration, le Pi communique également avec une carte Arduino Mega via une connexion série par USB. La carte Mega gère toutes les entrées et sorties de la machine de jeu et indique simplement au Pi si le jeu est en cours. Le Pi gère les effets sonores et lumineux.

Il existe un large éventail de fonctionnalités et d'applications pour la carte FadeCandy. De nombreux exemples simples et complexes sont disponibles en ligne, et de nouveaux exemples sont régulièrement ajoutés. Le code suivant représente une fonctionnalité multi-thread très basique pour les besoins spécifiques de l'éclairage de ce projet. Le Pi est programmé pour allumer les NeoPixel dans une couleur de base, puis pour ajouter des clignotements aléatoires afin d'accentuer le champ. Lorsqu'une personne joue, deux des rubans sont transformés en compte à rebours visuel. Regardez la Vidéo 1 pour référence. Le code utilisé pour ce projet est inclus ci-dessous (Liste 1).

Copier#Raspberry Pi Game Machine Script
import serial
import threading
import queue
import random
import opc, time
import pygame

#Initialize the sound mixer
pygame.mixer.init(44100, 16, 2)

#Create a game start sound effect object
Start_Sound = pygame.mixer.Sound("glass.wav")
Start_Sound.set_volume(1.0)
Start_Sound.play()

#Create a tick-tock sound object
Tick_Sound = pygame.mixer.Sound("ticktock.wav")
Tick_Sound.set_volume(1.0)
#Tick_Sound.play(maxtime=600)

#Create an end of game sound object
End_Sound = pygame.mixer.Sound("Buzzer-sound-16.wav")
End_Sound.set_volume(1.0)
#End_Sound.play()

#Build queue objects for transfer between threads
game_q = queue.Queue(1)
users_q = queue.Queue(1)
matrix_q = queue.Queue(1)

#State the NeoPixel array for the testbed
numLEDs = 8*26
pixels = [ (0,0,0) ] * numLEDs

#Set FadeCandy meter start pixel
meterStartPix = 130

#Create a serial communication object for the Mega
serMega = serial.Serial('/dev/ttyACM0', 115200)

#Create a client object for the Open Pixel server
client = opc.Client('localhost:7890')

#Define a function for the t1 thread that reads data from the Mega
def MegaData():
        while True:
                if serMega.inWaiting() > 0:
                        GameDuration = int(serMega.readline())
                        PlayFlag = int(serMega.readline())
                        game_q.put((GameDuration, PlayFlag))
                        TotalUsers = int(serMega.readline())
                        if not users_q.full():
                                users_q.put(TotalUsers)
                                
                time.sleep(0.001)
                        
#Define a function for the t2 thread which runs the time meter Neopixels                            
def RunMeter():

        while True:
                GameDuration, PlayFlag = game_q.get()
                matrix_q.put(PlayFlag)
                SleepNum = (float(GameDuration)/100/27)
              
                if PlayFlag == 1:
                        #Quickly fill the meter with green
                        meterPix = meterStartPix
                        Start_Sound.play()
                        for i in range(0, 26):
                                pixels[meterPix] = (0, 200, 0)
                                client.put_pixels(pixels)
                                time.sleep(.02)
                                meterPix = meterPix+1
                                
                        #Fill the meter with red based on game timer
                        meterPix = meterStartPix + 25       
                        for i in range(0, 26):
                                if not game_q.empty():
                                        GameDuration, PlayFlag = game_q.get()
                                if PlayFlag == 1:
                                        pixels[meterPix] = (200, 0, 0)
                                        Tick_Sound.play(maxtime=600)
                                        client.put_pixels(pixels)
                                        time.sleep(SleepNum)
                                        meterPix = meterPix-1
                                else:
                                        break
                                
                        #Wait a tad bit
                        time.sleep(.50)
                        End_Sound.play()
                        time.sleep(.50)
                        
                        #Quickly Clear the meter with soft white
                        meterPix  = meterStartPix
                        for i in range(0, 26):

                                pixels[meterPix] = (30, 30, 30)
                                client.put_pixels(pixels)
                                time.sleep(.01)
                                meterPix = meterPix+1
                                                                
                        time.sleep(2)
                else:
                        
                        #Quickly Clear the meter with soft white
                        meterPix = meterStartPix
                        
                        for i in range(0, 26):

                                pixels[meterPix] = (30, 30, 30)
                                client.put_pixels(pixels)
                                time.sleep(.01)
                                meterPix = meterPix+1
                                
                        time.sleep(2) 
                time.sleep(0.001)
                
#Define a function for the t3 thread that controls the non-meter Neopixels               
def RunMatrix():
       
        numLEDs = 6*26
      
        while True:
                if not matrix_q.empty():
                        play_flag = matrix_q.get()
                        if play_flag == 1:
                                numLEDs = 5*26
                        else:
                                numLEDs = 6*26   

                r = random.randint(25,85)
                g = random.randint(25,85)
                b = random.randint(25,85)
                Bright = 3 
                DotNum = 10 
                              
                for j in range(5):
                        for h in range(10):
                                pixels = [ (r, g, b) ] * numLEDs

                                for g in range(DotNum):
                                        p = random.randint(0,numLEDs-1)
                                        pixels[p] = (r*Bright, g*Bright, b*Bright)
                                
                                client.put_pixels(pixels)
                                
                                if not matrix_q.empty():
                                        play_flag = matrix_q.get()
                                        if play_flag == 1:
                                                numLEDs = 5*26
                                        else:
                                                numLEDs = 6*26 
                                time.sleep(.1)

#Create thread objects                                
t1 = threading.Thread(target = MegaData)
t2 = threading.Thread(target = RunMeter)
t3 = threading.Thread(target = RunMatrix)
t1.start()
t2.start()
t3.start()

Liste 1 : Code utilisé pour contrôler les LED du projet de machine à pince.

Résumé

Travailler avec des LED adressables est enrichissant, mais difficile. Souvent, le code nécessaire pour obtenir l'effet visuel parfait peut interférer avec d'autres opérations du microcontrôleur. La carte FadeCandy et d'autres types de circuits d'attaque LED dédiés sont utilisés pour atténuer ces problèmes et ouvrir la voie à une gamme infinie de scénarios d'éclairage. Avec le circuit d'attaque approprié, les circuits imprimés personnalisés constituent un excellent moyen d'organiser les entrées et sorties et de distribuer l'alimentation.

À propos de l'auteur

Image of Don Johanneck

Don Johanneck, développeur de contenu technique chez DigiKey, travaille dans l'entreprise depuis 2014. Occupant ce poste depuis peu, il est responsable de la rédaction des descriptions vidéo et du contenu produit. Don a obtenu sa licence en sciences appliquées en technologies électroniques et systèmes automatisés du Northland Community & Technical College dans le cadre du programme de bourses de DigiKey. Il aime le radiomodélisme, la restauration de machines anciennes et le bricolage.

More posts by Don Johanneck
 TechForum

Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.

Visit TechForum