Bonjour et bienvenue dans la dernière partie de notre gamme Disco Glasses.
Dans la partie d’aujourd’hui, nous allons une fois de plus résumer toutes les informations pertinentes pour la construction des lunettes, montrer quelques photos des séquences d’animation et bien sûr faire don d’une mise à niveau fonctionnelle de nos lunettes. La mise à niveau fonctionnelle de la partie d’aujourd’hui se compose d’un capteur de vibration, qui est activé par vos mouvements de danse dans la discothèque et donne ainsi à notre micro contrôleur des informations sur votre "comportement de danse" sur la piste de danse. A partir de cette information, les séquences lumineuses des lunettes sont contrôlées.
En d’autres termes, vos lunettes répondent à vos mouvements de danse rythmique! Comment ça marche techniquement ?
En tant qu’élément central, nous avons d’abord besoin d’un capteur de vibration. Cela peut être trouvé dans notre boutique en plusieurs versions. Chacun des capteurs mentionnés réagit légèrement différemment aux mouvements. Ainsi, le résultat final dépendra bien sûr également du capteur utilisé. Je recommande le Module de capteur KY-002n comme capteur de vibration. J’ai aussi fait cela dans ma propre configuration de testTet lors de l’élaboration du code. Il est important que le capteur passe activement au sol. Cela signifie qu’en cas de « choc », le capteur utilisé ferme brièvement le contact après GND.
Pointe: Essayez différents capteurs si nécessaire pour obtenir votre meilleur résultat. Une sélection de capteurs alternatifs se trouve à la fin de ce blog !
Le deuxième nouveau composant matériel est un commutateur plus simple. Ce commutateur est utilisé pour passer de l’ancien mode autosuffisant connu de la partie 2 au nouveau mode qui réagit aux mouvements. Le passage d’un mode à l’autre peut avoir lieu à tout moment. Aussi, par exemple, lors d’un programme en cours!
Mais passons au câblage des deux nouveaux composants de nos lunettes.
Comme on peut le voir sur le schéma, le capteur de vibration se trouve entre GND et le port 10 et le commutateur entre GND et le port 11 du processeur. Le câblage du bouton, d’autre part, n’a pas changé:
Aussi le câblage des deux anneaux WS2812 n’a pas changé par rapport à la partie précédente de la série:
Veuillez télécharger le code mis à jour par les fonctionnalités suivant sur vos lunettes après la mise à jour matérielle :
#include <Adafruit_NeoPixel.H (en)> #define BUTTON_CHANGEANIMATION 12 Épingle IO numérique connectée au bouton. Ce sera conduit avec une résistance pull-up de sorte que le commutateur devrait Tirez la broche au sol momentanément. Sur un haut - bas transition de la logique de bouton appuyez sur s’exécutera. #define PIXEL_PIN 6 Épingle IO numérique connectée aux NeoPixels. #define SHOCK_SENSOR 10 Choc / Capteur de vibration attaché #define MODE_SWITCH 11 Mode Opération #define PIXEL_COUNT 24 Tous les pixels sur bande #define MaxAninmationsAvail 4 Adafruit_NeoPixel Bande = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_RGB + NEO_KHZ800); Const Int hueRedLow = 0; Const Int hueRedHigh = 255; Const Int hueBlue = 170; Const Int angleMin = 0; Const Int angleSector = 60; Const Int angleMax = 360; Const Int brightMin = 0; Const Int brightMax (en) = 255; Octet Teinte, "Je ne suis pas; La saturation est fixée à 255 (plein) pour enlever le blead-through de différents "Je ne suis pas Octet Saturation = 255; Contrôle interrut Bool A60telSecInterruptOccured = Vrai; Bool FunctionMode = Faux; Octet A60telSecondes24 = 0; Octet A4telSecondes24 = 0; Variables de minuterie Int TimerSeconds TimerSeconds = 0; Counter Int TimerAlarmSet (en anglais) = 15; 15 Deuxième minuterie Bool TimerStartFlagFlagFlag = Faux; Bool Timerstop = Vrai; Opérations manuelles Bool ButtonAPress (en) = Faux; AnimationControl Int DevraitAnimation = 0; Int IsAnimation = 0; Int OLDLightBorder (en) = 0; Bool GetONOFFStatus GetONOFFStatus = Faux; Bool OLDONOFFStatus = Faux; Bool PlayIntro = Faux; Jouer Intro Bool PlayOutro PlayOutro = Faux; Jouer Outro Bool ChangementAnimation = Faux; Bool RunOnce (RunOnce) = Vrai; Animation Power Off - Anmation 0 variables universelles Octet Un, C, D, E, F; Unsigned Int R, G, B; Interrompre les routines ISR (ISR)(TIMER1_COMPA_vect) { Bool LEDChange (en), PressedZ (pressedZ); PressedZ (pressedZ) = digitalRead (en)(BUTTON_CHANGEANIMATION); Lire bouton Push FunctionMode = digitalRead (en)(MODE_SWITCH); Si ((PressedZ (pressedZ) == Faible) Et (ButtonAPress (en) == Faux)) { ButtonAPress (en) = Vrai; } TCNT1 (en) = 0; Enregistrement de l’initialisation } Interrompre la fin Commence programme principal Vide Configuration() { Bande.Commencer(); Bande.Montrer(); Initialiser tous les pixels à 'off' pinMode(BUTTON_CHANGEANIMATION, INPUT_PULLUP); pinMode(SHOCK_SENSOR, INPUT_PULLUP); pinMode(MODE_SWITCH, INPUT_PULLUP); randomSeed(analogRead (en)(0)); noInterrupts(); Désactiver tous les Interrrupts TCCR1A (EN) = 0x00; TCCR1B (EN) = 0x02; TCNT1 (en) = 0; Enregistrement de l’initialisation OCR1A = 33353; Charge de sortie Comparer registre TIMSK1 (en) |= (1 << OCIE1A); Activer la minuterie Comparer l’interruption Interrompt(); Activer toutes les interruptions } Fonctions d’aide Vide HSBToRGB ( Unsigned Int inHue, Unsigned Int inSaturation, Unsigned Int inBrightness, Unsigned Int *Ou, Unsigned Int *Og, Unsigned Int *Ob ) { Si (inSaturation == 0) { achromatique (gris) *Ou = *Og = *Ob = inBrightness; } Autre { Unsigned Int scaledHue = (inHue * 6); Unsigned Int Secteur = scaledHue >> 8; secteur 0 à 5 autour de la roue de couleur Unsigned Int offsetInSector = scaledHue - (Secteur << 8); position au sein du secteur Unsigned Int P = (inBrightness * ( 255 - inSaturation )) >> 8; Unsigned Int Q = (inBrightness * ( 255 - ((inSaturation * offsetInSector) >> 8) )) >> 8; Unsigned Int T = (inBrightness * ( 255 - ((inSaturation * ( 255 - offsetInSector )) >> 8) )) >> 8; Interrupteur ( Secteur ) { Cas 0: *Ou = inBrightness; *Og = T; *Ob = P; Pause; Cas 1: *Ou = Q; *Og = inBrightness; *Ob = P; Pause; Cas 2: *Ou = P; *Og = inBrightness; *Ob = T; Pause; Cas 3: *Ou = P; *Og = Q; *Ob = inBrightness; Pause; Cas 4: *Ou = T; *Og = P; *Ob = inBrightness; Pause; Par défaut: cas 5: *Ou = inBrightness; *Og = P; *Ob = Q; Pause; } } } Vide CheckConfigButtons () InterruptRoutine { Bool PressedZ (pressedZ); Si (ButtonAPress (en) == Vrai) { Si (DevraitAnimation < MaxAninmationsAvail ) { DevraitAnimation++; } Autre { DevraitAnimation = 0; } Retard(400); ButtonAPress (en) = Faux; } } Vide AnimationControl () { Int GetSelAnimation (en) = 0; Si (GetONOFFStatus GetONOFFStatus != OLDONOFFStatus) { OLDONOFFStatus = GetONOFFStatus GetONOFFStatus; Si (GetONOFFStatus GetONOFFStatus) { DevraitAnimation = 1; } Autre { DevraitAnimation = 0; } } } ----------------------------------------------------------------------- de la boucle principale Vide Boucle() { AnimationControl(); RunAnimations(); CheckConfigButtons(); } Boucle principale ----------------------------------------------------------------------- fin Intros Vide Intro_CountUp (Octet R, Octet G, Octet B, Int retard, Bool Dir) { Si (Dir) { Pour ( Int Ⅰ = 0; Ⅰ < Bande.numPixels (numPixels)(); Ⅰ++) { Bande.setPixelColor(Ⅰ, R, G, B); Valeurs Calulate RGB pour Pixel Bande.Montrer(); Afficher les résultats :) Retard(retard); } } Autre { Pour ( Int Ⅰ = 0; Ⅰ < Bande.numPixels (numPixels)() + 1; Ⅰ++) { Octet Pos = Bande.numPixels (numPixels)() - Ⅰ; Bande.setPixelColor(Pos, R, G, B); Valeurs Calulate RGB pour Pixel Bande.Montrer(); Afficher les résultats :) Retard(retard); } } } Vide Intro_RaiseRainbow(Bool hausse) { Luminosité = 255; Int Rainbowcolor (Rainbowcolor) = 0; Si (hausse) { Pour (Int Ⅰ = 0; Ⅰ < Bande.numPixels (numPixels)(); Ⅰ++) { Teinte = Carte(Ⅰ + Rainbowcolor (Rainbowcolor), angleMin, 60, hueRedLow, hueRedHigh); Définir la couleur HSBToRGB(Teinte, Saturation, Luminosité, &R, &G, &B); Définir la couleur Bande.setPixelColor(Ⅰ, R, G, B); Valeurs Calulate RGB pour Pixel Bande.Montrer(); Retard(40); } } Autre { Pour (Int Ⅰ = 0; Ⅰ < Bande.numPixels (numPixels)(); Ⅰ++) { Bande.setPixelColor(Ⅰ, 0, 0, 0); Bande.Montrer(); Retard(40); } } } Animations Outtros Vide Ani_AllOff () { Pour ( Int Ⅰ = 0; Ⅰ < Bande.numPixels (numPixels)(); Ⅰ++) { Bande.setPixelColor(Ⅰ, 0, 0, 0); tous hors tension } Bande.Montrer(); } Vide Ani_AllOn (Octet R, Octet G, Octet B) { Pour ( Int Ⅰ = 0; Ⅰ < Bande.numPixels (numPixels)(); Ⅰ++) { Bande.setPixelColor(Ⅰ, R, G, B); tous sur } Bande.Montrer(); } Vide Ani_Starshower () { Int Array[10] ; Bool chocValue = Vrai; Bool Pressé = Vrai; Pour ( Int Ⅰ = 0; Ⅰ < Bande.numPixels (numPixels)(); Ⅰ++) { Bande.setPixelColor(Ⅰ, 0, 0, 15); tous bleus à base } Pour (Int Ⅰ = 0; Ⅰ < 10; Ⅰ++) { Int Sélectionné = Aléatoire(Bande.numPixels (numPixels)()); Bande.setPixelColor(Sélectionné, 255, 255, 255); Blanc } Bande.Montrer(); Retard(100); Pour ( Int Ⅰ = 0; Ⅰ < Bande.numPixels (numPixels)(); Ⅰ++) { Bande.setPixelColor(Ⅰ, 0, 0, 15); tous bleus à base } Bande.Montrer(); Si (FunctionMode) { Retard(500); } Autre { faire { chocValue = digitalRead (en)(SHOCK_SENSOR); Pressé = digitalRead (en)(BUTTON_CHANGEANIMATION); FunctionMode = digitalRead (en)(MODE_SWITCH); } Tandis que ((chocValue) && (!FunctionMode) && ( Pressé)) ; } } Vide Ani_Rainbow(Octet retard) { Luminosité = 100; Int Rainbowcolor (Rainbowcolor) = 0; Bool chocValue = Vrai; Bool Pressé = Vrai; faire { Pour (Int Ⅰ = 0; Ⅰ < Bande.numPixels (numPixels)(); Ⅰ++) { Teinte = Carte(Ⅰ + Rainbowcolor (Rainbowcolor), angleMin, 60, hueRedLow, hueRedHigh); HSBToRGB(Teinte, Saturation, Luminosité, &R, &G, &B); Bande.setPixelColor(Ⅰ, R, G, B); } Bande.Montrer(); Afficher les résultats :) Si (FunctionMode) { Retard(retard); } Autre { faire { chocValue = digitalRead (en)(SHOCK_SENSOR); Pressé = digitalRead (en)(BUTTON_CHANGEANIMATION); FunctionMode = digitalRead (en)(MODE_SWITCH); } Tandis que ((chocValue) && (!FunctionMode) && ( Pressé)) ; } Rainbowcolor (Rainbowcolor)++ ; } Tandis que (Rainbowcolor (Rainbowcolor) < 61); } Vide Ani_Two_Color () { Bool chocValue = Vrai; Bool Pressé = Vrai; Octet Diviseur = Aléatoire (1, 10); Bool Couleur; Int X = 1; B = 0; Pour (Int s = 0; s > -1; s = s + X) { Couleur = Faux; Pour ( Int Ⅰ = 0; Ⅰ < Bande.numPixels (numPixels)(); Ⅰ++) { Un = Ⅰ / Diviseur; Si (!(Un == B)) { B = Un; Couleur = !Couleur; } Si (Couleur) { Bande.setPixelColor(Ⅰ, 0, s, 0); Grün } Si (!(Couleur)) { Bande.setPixelColor(Ⅰ, s, 0, 0); Pourrir } } Bande.Montrer(); Si (s == 255) { Si (FunctionMode) { X = -1; Retard(200); } Autre { faire { chocValue = digitalRead (en)(SHOCK_SENSOR); Pressé = digitalRead (en)(BUTTON_CHANGEANIMATION); FunctionMode = digitalRead (en)(MODE_SWITCH); } Tandis que ((chocValue) && (!FunctionMode) && ( Pressé)) ; X = -1; } } Retard(10); } Bande.Montrer(); } Vide Ani_Halloween() { Bool chocValue = Vrai; Bool Pressé = Vrai; Un = -10; Pour (Int Ⅰ = 0; Ⅰ < Bande.numPixels (numPixels)(); Ⅰ++) { Bande.setPixelColor(Ⅰ, Aléatoire(1, 254), Aléatoire(1, 204), Aléatoire(1, 254)); E = E + Un; F = F + Un; Si (F <= 0) { Un = +10; } Si (F >= 60) { Un = -10; } } Bande.Montrer(); Afficher les résultats :) Si (FunctionMode) { Retard(300); } Autre { faire { chocValue = digitalRead (en)(SHOCK_SENSOR); Pressé = digitalRead (en)(BUTTON_CHANGEANIMATION); FunctionMode = digitalRead (en)(MODE_SWITCH); } Tandis que ((chocValue) && (!FunctionMode) && ( Pressé)) ; } } Vide FadeColor (FadeColor) () { Octet Luminosité = 0; Octet Saturation = 0; Int Colori = 49 ; faire { Pour (Int Ⅰ = 0; Ⅰ < Bande.numPixels (numPixels)(); Ⅰ++) { HSBToRGB(Colori, Saturation, Luminosité, &R, &G, &B); Définir la couleur Bande.setPixelColor(Ⅰ, R, G, B); Valeurs Calulate RGB pour Pixel } Luminosité ++; Bande.Montrer(); Afficher les résultats :) Retard(40); } Tandis que (Luminosité < 50); } Vide RunAnimations() { Si (!(DevraitAnimation == IsAnimation)) { PlayOutro PlayOutro = Vrai; ChangementAnimation = Vrai; } Interrupteur (IsAnimation) { Cas 0: tous LedsOFF Si (PlayIntro) { PlayIntro = Faux; Runonce (Runonce) = Vrai; } Si ((!(PlayIntro)) && (!(PlayOutro PlayOutro))) { Si (Runonce (Runonce)) { Ani_AllOff (); } Runonce (Runonce) = Faux; } Si (PlayOutro PlayOutro) { PlayOutro PlayOutro = Faux; PlayIntro = Vrai; Runonce (Runonce) = Vrai; IsAnimation = DevraitAnimation; } Pause; Cas 1: Si (PlayIntro) { Intro_CountUp (0, 0, 15, 100, Vrai); PlayIntro = Faux; } Si ((!(PlayIntro)) && (!(PlayOutro PlayOutro))) { Ani_Starshower(); } Si (PlayOutro PlayOutro) { Intro_CountUp (0, 0, 0, 100, Faux); PlayOutro PlayOutro = Faux; PlayIntro = Vrai; IsAnimation = DevraitAnimation; } Pause; Cas 2: Si (PlayIntro) { Intro_RaiseRainbow(Vrai); PlayIntro = Faux; } Si ((!(PlayIntro)) && (!(PlayOutro PlayOutro))) { Ani_Rainbow(20); } Si (PlayOutro PlayOutro) { Intro_RaiseRainbow(Faux); PlayOutro PlayOutro = Faux; PlayIntro = Vrai; IsAnimation = DevraitAnimation; } Pause; Cas 3: Si (PlayIntro) { Ani_AllOff (); PlayIntro = Faux; } Si ((!(PlayIntro)) && (!(PlayOutro PlayOutro))) { Ani_Two_Color (); Ani_Two_Color (tote hue, byte tail,byte brightness,byte delaytime) } Si (PlayOutro PlayOutro) { PlayOutro PlayOutro = Faux; PlayIntro = Vrai; IsAnimation = DevraitAnimation; } Pause; Cas 4: Si (PlayIntro) { Ani_AllOff (); PlayIntro = Faux; } Si ((!(PlayIntro)) && (!(PlayOutro PlayOutro))) { Ani_Halloween (); // } Si (PlayOutro PlayOutro) { PlayOutro PlayOutro = Faux; PlayIntro = Vrai; IsAnimation = DevraitAnimation; } Pause; } }
En appuyant sur le bouton, les animations peuvent maintenant être appelées l’une après l’autre. Ce qui est nouveau, c’est qu’il peut maintenant être commuté entre les modes de fonction autonome et de rétroaction en appuyant simplement sur le commutateur.
Tout le monde réagit ! des quatre animations légèrement différentes sur le capteur de vibration si le mode "Feedback" est sélectionné.
En tant que petite aide à la performance, j’ai déjà photographié les 4 animations différentes :
Starshower:
Arc-en-ciel:
Mouvement de deux couleurs:
Halloween:
S’il vous plaît noter que dans les deux! Ne passe pas les animations à l’animation suivante immédiatement, mais toujours sortir de la séquence en cours avant le début de la prochaine animation.
Je vous souhaite beaucoup de plaisir à recréer les lunettes disco. Peut-être que vous voulez programmer plus de séquences d’animation si les 4 existantes ne sont pas assez pour vous?
Essayez d’autres capteurs, tels que :
Ou vous pouvez essayer d’utiliser un capteur des différents
Écrivez vos idées ou vos questions dans les commentaires.