¡Nuestras gafas de discoteca dan retroalimentación!

Hola y bienvenidos a la última parte de nuestra gama Disco Glasses.

Por parte de hoy volveremos a resumir toda la información relevante para la construcción de las gafas, mostraremos algunas imágenes de las secuencias de animación y, por supuesto, donaremos una actualización funcional a nuestras gafas. La actualización funcional en la parte de hoy consiste en un sensor de vibración, que se activa por sus movimientos de baile en la discoteca y por lo tanto da a nuestro micro controlador información sobre su "comportamiento de baile" en la pista de baile. A partir de esta información, se controlan las secuencias luminosas de las gafas.

En otras palabras, sus gafas responden a sus movimientos de baile rítmico! Bueno, ¿cómo funciona todo técnicamente?

Como elemento central, primero necesitamos un sensor de vibración. Esto se puede encontrar en nuestra tienda en varias versiones. Cada uno de los sensores mencionados reacciona ligeramente diferente a los movimientos. Por lo tanto, el resultado final, por supuesto, también dependerá del sensor utilizado. Recomiendo el Módulo de sensor KY-002n como sensor de vibración. También he hecho esto en mi propia configuración de pruebaTy al desarrollar el código. Es importante que el sensor cambie activamente a tierra. Esto significa que en caso de un "shock", el sensor utilizado cierra brevemente el contacto después de GND.

Propina: Pruebe diferentes sensores si es necesario para obtener su mejor resultado. Una selección de sensores alternativos se puede encontrar al final de este blog!

El segundo nuevo componente de hardware es un conmutador más simple. Este interruptor se utiliza para cambiar entre el antiguo modo autosuficiente conocido de la Parte 2 al nuevo modo que reacciona a los movimientos. El cambio entre modos puede tener lugar en cualquier momento. También, por ejemplo, durante un programa en curso!

Pero pasemos al cableado de los dos nuevos componentes de nuestras gafas.

Como se puede ver en el esquema, el sensor de vibración se encuentra entre GND y el puerto 10 y el conmutador entre GND y el puerto 11 del procesador. El cableado del botón, por otro lado, no ha cambiado:

Parte 3: Fritzing Schematic

 

También el cableado de los dos anillos WS2812 no ha cambiado en comparación con la parte anterior de la serie:

 

Parte 3: Detalle fritzing

 

Cargue el siguiente código actualizado en sus gafas después de la actualización de hardware:

 

 

#include <Adafruit_NeoPixel.H>

#define BUTTON_CHANGEANIMATION  12    Pin de E/S digital conectado al botón.  Esto será
accionado con una resistencia pull-up por lo que el interruptor debe
Tire del pasador al suelo momentáneamente.  En un alto -> bajo
transición de la lógica de pulsación de botón se ejecutará.
#define PIXEL_PIN    6                Pin de E/S digital conectado a los NeoPixels.
#define SHOCK_SENSOR 10               Sensor de choque / vibración conectado
#define MODE_SWITCH 11                Modo de operación
#define PIXEL_COUNT 24                Todos los píxeles en la tira
#define MaxAninmationsAvail 4

Adafruit_NeoPixel Tira = 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 = 255;

Byte Hue, "No soy;
La saturación se fija en 255 (completa) para eliminar el
"No soy
Byte Saturación = 255;
Interrut Control
Bool A60telSecInterruptOccured = Verdad;
Bool FunctionMode = Falso;
Byte A60telSeconds24 = 0;
Byte A4telSeconds24 = 0;
Variables del temporizador
Int TimerSeconds = 0;  Contador
Int TimerAlarmSet = 15; 15 Segundo Temporizador
Bool TimerStartFlagFlag = Falso;
Bool TimerStop = Verdad;
Operaciones manuales
Bool ButtonAPress  = Falso;

AnimationControl
Int ShouldAnimation  = 0;
Int IsAnimation  = 0;
Int OLDLightBorder = 0;
Bool GetONOFFStatus = Falso;

Bool OLDONOFFStatus = Falso;
Bool PlayIntro = Falso; Play Intro
Bool PlayOutro = Falso; Juega Outro
Bool ChangeAnimation = Falso;
Bool Runonce = Verdad;  Animación de apagado - Anmación 0

variables universales
Byte Un, C, D, e, F;
Unsigned Int R, G, B;

Interrumpir rutinas

Isr(TIMER1_COMPA_vect)
{   Bool LEDChange, PressedZ;   PressedZ = digitalRead(BUTTON_CHANGEANIMATION); Leer botón de pulsación   FunctionMode = digitalRead(MODE_SWITCH);   Si ((PressedZ == Bajo) Y (ButtonAPress == Falso))   {     ButtonAPress = Verdad;   }   TCNT1 = 0;      Registrar la inicialización
}

Interrupciones finalizar programa principal
Vacío Configuración()
{   Tira.Comenzar();   Tira.Mostrar();   Inicializar todos los píxeles en 'desactivado'   pinMode(BUTTON_CHANGEANIMATION, INPUT_PULLUP);   pinMode(SHOCK_SENSOR, INPUT_PULLUP);   pinMode(MODE_SWITCH, INPUT_PULLUP);   randomSeed(analogRead(0));   noInterrupts(); Desactivar todos los Interrrupts   TCCR1A = 0x00;   TCCR1B =  0x02;   TCNT1 = 0;      Registrar la inicialización   OCR1A =  33353;      Registro de comparación de salida de carga   TIMSK1 |= (1 << OCIE1A);  Activar interrupción de comparación de temporizador   Interrumpe();   Habilitar todas las interrupciones
}


Funciones auxiliares

Vacío HSBToRGB
(   Unsigned Int inHue, Unsigned Int insaturación, Unsigned Int inBrightness,   Unsigned Int *O, Unsigned Int *Og, Unsigned Int *Ob )
{   Si (insaturación == 0)   {     acromático (gris)     *O = *Og = *Ob = inBrightness;   }   Más   {     Unsigned Int scaledHue = (inHue * 6);     Unsigned Int Sector = scaledHue >> 8; sector 0 a 5 alrededor de la rueda de color     Unsigned Int offsetInSector = scaledHue - (Sector << 8);  posición dentro del sector     Unsigned Int P = (inBrightness * ( 255 - insaturación )) >> 8;     Unsigned Int Q = (inBrightness * ( 255 - ((insaturación * offsetInSector) >> 8) )) >> 8;     Unsigned Int T = (inBrightness * ( 255 - ((insaturación * ( 255 - offsetInSector )) >> 8) )) >> 8;     Interruptor ( Sector ) {       Caso 0:         *O = inBrightness;         *Og = T;         *Ob = P;         Romper;       Caso 1:         *O = Q;         *Og = inBrightness;         *Ob = P;         Romper;       Caso 2:         *O = P;         *Og = inBrightness;         *Ob = T;         Romper;       Caso 3:         *O = P;         *Og = Q;         *Ob = inBrightness;         Romper;       Caso 4:         *O = T;         *Og = P;         *Ob = inBrightness;         Romper;       Predeterminado:    caso 5:         *O = inBrightness;         *Og = P;         *Ob = Q;         Romper;     }   }
}

Vacío CheckConfigButtons ()    InterruptRoutine
{   Bool PressedZ;   Si (ButtonAPress == Verdad)   {     Si (ShouldAnimation < MaxAninmationsAvail )     {       ShouldAnimation++;     } Más     {       ShouldAnimation = 0;     }     Retraso(400);     ButtonAPress = Falso;   }
}

Vacío AnimationControl ()
{   Int GetSelAnimation = 0;   Si (GetONOFFStatus != OLDONOFFStatus)   {     OLDONOFFStatus = GetONOFFStatus;     Si (GetONOFFStatus)     {       ShouldAnimation = 1;     } Más     {       ShouldAnimation = 0;     }   }
}

----------------------------------------------------------------------- de bucle principal

Vacío Bucle()
{   AnimationControl();   RunAnimations();   CheckConfigButtons();
}
Bucle principal ----------------------------------------------------------------------- Final
Intros

Vacío Intro_CountUp (Byte R, Byte G, Byte B, Int retraso, Bool Dir)
{   Si (Dir)   {     Para ( Int  = 0;  < Tira.numPixels(); ++)     {       Tira.setPixelColor(, R, G, B);    Calular valores RGB para píxeles       Tira.Mostrar();   Mostrar resultados :)       Retraso(retraso);     }   } Más   {     Para ( Int  = 0;  < Tira.numPixels() + 1; ++)     {       Byte Pos = Tira.numPixels() - ;       Tira.setPixelColor(Pos, R, G, B);    Calular valores RGB para píxeles       Tira.Mostrar();   Mostrar resultados :)       Retraso(retraso);     }   }
}

Vacío Intro_RaiseRainbow(Bool aumento)
{   Brillo = 255;   Int Rainbowcolor = 0;   Si (aumento)   {     Para (Int  = 0;  < Tira.numPixels(); ++)     {       Hue = Mapa( + Rainbowcolor, angleMin, 60, hueRedLow, hueRedHigh); Establecer color       HSBToRGB(Hue, Saturación, Brillo, &R, &G, &B); Establecer color       Tira.setPixelColor(, R, G, B);     Calular valores RGB para píxeles       Tira.Mostrar();       Retraso(40);     }   } Más   {     Para (Int  = 0;  < Tira.numPixels(); ++)     {       Tira.setPixelColor(, 0, 0, 0);       Tira.Mostrar();       Retraso(40);     }   }
}

Animaciones Outtros
Vacío Ani_AllOff ()
{   Para ( Int  = 0;  < Tira.numPixels(); ++)   {     Tira.setPixelColor(, 0, 0, 0);     todo fuera   }   Tira.Mostrar();
}

Vacío Ani_AllOn (Byte R, Byte G, Byte B)
{   Para ( Int  = 0;  < Tira.numPixels(); ++)   {     Tira.setPixelColor(, R, G, B);     todo en   }   Tira.Mostrar();
}

Vacío Ani_Starshower ()
{   Int Matriz[10] ;   Bool shockValue = Verdad;   Bool PressedT =  Verdad;   Para ( Int  = 0;  < Tira.numPixels(); ++)   {     Tira.setPixelColor(, 0, 0, 15);     todo basado en azul   }   Para (Int  = 0;  < 10; ++)   {     Int Seleccionado = Aleatorio(Tira.numPixels());     Tira.setPixelColor(Seleccionado, 255, 255, 255); Blanco   }   Tira.Mostrar();   Retraso(100);   Para ( Int  = 0;  < Tira.numPixels(); ++)   {     Tira.setPixelColor(, 0, 0, 15);     todo basado en azul   }   Tira.Mostrar();   Si (FunctionMode)   {     Retraso(500);   } Más   {     hacer     {       shockValue = digitalRead(SHOCK_SENSOR);       PressedT = digitalRead(BUTTON_CHANGEANIMATION);       FunctionMode = digitalRead(MODE_SWITCH);     } Mientras ((shockValue) && (!FunctionMode) && ( PressedT))  ;   }
}

Vacío Ani_Rainbow(Byte retraso)
{   Brillo = 100;   Int Rainbowcolor = 0;   Bool shockValue = Verdad;   Bool PressedT =  Verdad;   hacer   {     Para (Int  = 0;  < Tira.numPixels(); ++)     {       Hue = Mapa( + Rainbowcolor, angleMin, 60, hueRedLow, hueRedHigh);       HSBToRGB(Hue, Saturación, Brillo, &R, &G, &B);       Tira.setPixelColor(, R, G, B);     }     Tira.Mostrar();   Mostrar resultados :)     Si (FunctionMode)     {       Retraso(retraso);     } Más     {       hacer       {         shockValue = digitalRead(SHOCK_SENSOR);         PressedT = digitalRead(BUTTON_CHANGEANIMATION);         FunctionMode = digitalRead(MODE_SWITCH);       } Mientras ((shockValue) && (!FunctionMode) && ( PressedT))  ;     }     Rainbowcolor++ ;   } Mientras (Rainbowcolor < 61);
}

Vacío Ani_Two_Color ()
{   Bool shockValue = Verdad;   Bool PressedT =  Verdad;   Byte Divisor = Aleatorio (1, 10);   Bool Color;   Int X = 1;   B = 0;   Para (Int s = 0; s > -1; s = s + X)   {     Color = Falso;     Para ( Int  = 0;  < Tira.numPixels(); ++)     {       Un =  / Divisor;       Si (!(Un == B))       {         B = Un;         Color = !Color;       }       Si (Color) {         Tira.setPixelColor(, 0, s, 0);  Grün       }       Si (!(Color)) {         Tira.setPixelColor(, s, 0, 0);  Putrefacción       }     }     Tira.Mostrar();     Si (s == 255)     {       Si (FunctionMode)       {         X = -1;         Retraso(200);       } Más       {         hacer         {           shockValue = digitalRead(SHOCK_SENSOR);           PressedT = digitalRead(BUTTON_CHANGEANIMATION);           FunctionMode = digitalRead(MODE_SWITCH);         } Mientras ((shockValue) && (!FunctionMode) && ( PressedT)) ;         X = -1;       }     }     Retraso(10);   }   Tira.Mostrar();
}

Vacío Ani_Halloween()
{   Bool shockValue = Verdad;   Bool PressedT =  Verdad;   Un = -10;   Para (Int  = 0;  < Tira.numPixels(); ++)   {     Tira.setPixelColor(, Aleatorio(1, 254), Aleatorio(1, 204), Aleatorio(1, 254));     e = e + Un;     F = F + Un;     Si (F <= 0)     {       Un = +10;     }     Si (F >= 60)     {       Un = -10;     }   }   Tira.Mostrar();   Mostrar resultados :)   Si (FunctionMode)   {     Retraso(300);   } Más   {     hacer     {       shockValue = digitalRead(SHOCK_SENSOR);       PressedT = digitalRead(BUTTON_CHANGEANIMATION);       FunctionMode = digitalRead(MODE_SWITCH);     } Mientras ((shockValue) && (!FunctionMode) && ( PressedT))  ;   }
}

Vacío FadeColor ()
{   Byte Brillo = 0;   Byte Saturación = 0;   Int Colori = 49 ;   hacer   {     Para (Int  = 0;  < Tira.numPixels(); ++)     {       HSBToRGB(Colori, Saturación, Brillo, &R, &G, &B); Establecer color       Tira.setPixelColor(, R, G, B);     Calular valores RGB para píxeles     }     Brillo ++;     Tira.Mostrar();   Mostrar resultados :)     Retraso(40);   } Mientras (Brillo < 50);
}

Vacío RunAnimations()
{   Si (!(ShouldAnimation == IsAnimation))   {     PlayOutro = Verdad;     ChangeAnimation = Verdad;   }   Interruptor (IsAnimation)   {     Caso 0:                                    todos Los LedsOFF       Si (PlayIntro)       {         PlayIntro = Falso;         Runonce = Verdad;       }       Si   ((!(PlayIntro)) &&  (!(PlayOutro)))       {         Si (Runonce) {           Ani_AllOff ();         }         Runonce = Falso;       }       Si  (PlayOutro)       {         PlayOutro  = Falso;         PlayIntro = Verdad;         Runonce = Verdad;         IsAnimation = ShouldAnimation;       }       Romper;     Caso 1:       Si (PlayIntro)       {         Intro_CountUp (0, 0, 15, 100, Verdad);         PlayIntro = Falso;       }       Si  ((!(PlayIntro)) && (!(PlayOutro)))       {         Ani_Starshower();       }       Si  (PlayOutro)       {         Intro_CountUp (0, 0, 0, 100, Falso);         PlayOutro  = Falso;         PlayIntro = Verdad;         IsAnimation =  ShouldAnimation;       }       Romper;     Caso 2:       Si (PlayIntro)       {         Intro_RaiseRainbow(Verdad);         PlayIntro = Falso;       }       Si  ((!(PlayIntro)) && (!(PlayOutro)))       {         Ani_Rainbow(20);       }       Si  (PlayOutro)       {         Intro_RaiseRainbow(Falso);         PlayOutro  = Falso;         PlayIntro = Verdad;         IsAnimation =  ShouldAnimation;       }       Romper;     Caso 3:       Si (PlayIntro)       {         Ani_AllOff ();         PlayIntro = Falso;       }       Si  ((!(PlayIntro)) && (!(PlayOutro)))       {         Ani_Two_Color (); Ani_Two_Color (byte hue, byte tail,byte brightness,byte delaytime)       }       Si  (PlayOutro)       {         PlayOutro  = Falso;         PlayIntro = Verdad;         IsAnimation =  ShouldAnimation;       }       Romper;     Caso 4:       Si (PlayIntro)       {         Ani_AllOff ();         PlayIntro = Falso;       }       Si  ((!(PlayIntro)) && (!(PlayOutro)))       {         Ani_Halloween (); //       }       Si  (PlayOutro)       {         PlayOutro  = Falso;         PlayIntro = Verdad;         IsAnimation =  ShouldAnimation;       }       Romper;   }
}

 

Al pulsar el botón, las animaciones ahora se pueden llamar una tras otra. Lo nuevo es que ahora se puede cambiar entre los modos de función independiente y de retroalimentación simplemente presionando el interruptor.

¡Todos reaccionan! de las cuatro animaciones ligeramente diferentes en el sensor de vibración si se selecciona el modo "Feedback".

Como una pequeña ayuda de rendimiento una vez fotografié las 4 animaciones diferentes:

 

Ducha Estelar:

Efecto: Starshower

Arco iris:

Parte 3 - Efecto Arco Iris

Movimiento de dos colores:

Parte 3: Movimiento de dos colores

 

Víspera de Todos los Santos:

Parte 3 - Efecto Halloween

 

Tenga en cuenta que en ambos! No cambia las animaciones a la siguiente animación inmediatamente, pero siempre sale de la secuencia actual antes de que se inicie la siguiente animación.


Te deseo mucha diversión recreando las gafas de discoteca. Tal vez usted quiere programar más secuencias de animación si los 4 existentes no son suficientes para usted?

Pruebe con otros sensores, como:

O puede intentar usar un sensor de los diversos

 

Escribe tus ideas o preguntas en los comentarios.

 

Para arduinoProyectos para principiantes

Deja un comentario

Todos los comentarios son moderados antes de ser publicados

Artículos de blog

  1. Ahora instalamos el esp32 a través de la administración.
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. Transporte Aéreo - programación de ESP mediante redes locales inalámbricas