Disco goggles with ws2812b RGB LED rings

Disco goggles with the WS2812b RGB LED Ring


Hello and welcome to another blog series about our WS2812b RGB LED Ring. Once again, it's all about the current topic of "upcycling". After all, no one should be able to say that the maker :) not also think about the environment.
This time we "upcycle" an old sunglasses to a stylish "disco goggles" for the next disco visit. Although I am no longer one of the disco-goers, I think that there should also be a project for our younger makers among the readers. I hope you like the idea of Disco LED glasses for the next disco visit! With that you will certainly really catch up in the (dance) mass. The WS2812b LED rings act as "glasses". The frame around the two eye rings can be assembled from an old sunglasses. As mc we use the Arduino Nano again for reasons of space, as a power supply a USB power bank from the mobile phone. For the wiring, I recommend offloading the electronics and power supply from the glasses, so it is sufficient to have a thin, 3 adrige cable disappear from the left or right ear handle over the top into an electronic box in the shirt pocket or trouser pocket. In this electronic box you install the pushbutton and other sensors (in the upcoming parts) to control the glasses. For our blog today, we need the following hardware setup:

As parts you don't need much:

1 xAZ-Delivery Nano V 3

2 x RGB LED Ring WS2812b with 12 RGB LEDs 5V for Arduino 50 mm outer diameter

1x Pushbutton

1x Usb power bank and USB cable suitable for Arduino Nano

 

When we have finished the circuit, we now have to include the Adafruit Neopixel library so that we can easily control the LED's of the ring.
The required library can be added to our IDE in 2 ways:
1.) Download the library on the URL https://github.com/adafruit/Adafruit_NeoPixel. Then in the IDE in the menu item Sketch -> Include Library ->Add Zip Library manually.
2.) Enter "Adafruit Neopixel" in the library manager as a search term, click on the library and then select "Install". Please select at least version 1.2.4.

If everything worked out up to this point, please upload the following code to the nano:

 

#include <Adafruit_NeoPixel.H>

#define BUTTON_CHANGEANIMATION  12    Digital IO pin connected to the button.  This will be                                       driven with a pull-up resistor so the switch should                                       Pull the pin to ground momentarily.  On a high -> low                                       transition the button press logic will execute.
#define PIXEL_PIN    6    Digital IO pin connected to the NeoPixels.
#define PIXEL_COUNT 24   All Pixels on Umbrella
#define MaxAninmationsAvail 1
#define STATUS_PIN 13 Animation Control Button
Adafruit_NeoPixel Strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_RGB + NEO_KHZ800);

Const Int hueRedLow = 0;
Const Int hueRedHigh = 255;
Const Int hueBlue = 170;
The size of the angle of one sector (1/6 of a color wheel), and of a complete
cycle of the color wheel.
Const Int angleMin = 0;
Const Int angleSector = 60;
Const Int angleMax = 360;
Const Int brightMin = 0;
Const Int brightMax = 255;

Byte Hue, "I'm not;
The saturation is fixed at 255 (full) to remove blead-through of different
"I'm not
It could be linked to another potentiometer if a demonstration of hue
Is desired.
Byte saturation = 255;

Timer Variables
Int TimerSeconds = 0;  Counter
Int TimerAlarmSet = 15; 15 seconds timer
Bool TimerStartFlagFlag = False;
Bool Timerstop = True;

Manual Operations
Bool ButtonAPress  = False;
Byte LedMode = 2;

AnimationControl
Int ShouldAnimation  = 0;
Int IsAnimation  = 0;
Int OLDLightBorder = 0;
bool GetONOFFStatus = false;

bool OLDONOFFStatus = false;
bool PlayIntro = false; // Intro
bool PlayOutro = false; // Outro
bool ChangeAnimation = false;
bool RunOnce = true;   //universal variables
byte a,c,d,e,f;
unsigned int r, g, b;

//Interrupt Routines

ISR(TIMER1_COMPA_vect)         {
 bool LEDChange,PressedZ; 
 //Switch Abfrage
 PressedZ= digitalRead(BUTTON_CHANGEANIMATION);
 if ((PressedZ == LOW) and (ButtonAPress == false))     {       ButtonAPress = true;            }     TCNT1 = 0;      // Register initializing
}

//Interrupts end

// begin Program
void setup()    {          strip.begin();     strip.show();   // Initialize all pixels to 'off'         pinMode(BUTTON_CHANGEANIMATION, INPUT_PULLUP);     pinMode(STATUS_PIN,OUTPUT);     digitalWrite(STATUS_PIN, HIGH);     randomSeed(analogRead(0));     noInterrupts(); // All Interrupts disable     TCCR1A = 0x00;       TCCR1B =  0x02;     TCNT1 = 0;      // Register initalization     OCR1A =  33353;      // Load Output Compare Register       TIMSK1 |= (1 << OCIE1A);  // Activate Timer Compare Interrupt      interrupts();   // Activate all Interrupts     Serial.begin(9600);     Serial.flush();    }

// Help Functions
void HSBToRGB(     unsigned int inHue, unsigned int inSaturation, unsigned int inBrightness,     unsigned int *oR, unsigned int *oG, unsigned int *oB )
{     if (inSaturation == 0)     {         // achromatic (grey)         *oR = *oG = *oB = inBrightness;     }     else     {         unsigned int scaledHue = (inHue * 6);         unsigned int sector = scaledHue >> 8; // sector 0 to 5 around the color wheel         unsigned int offsetInSector = scaledHue - (sector << 8);  // position within the sector                  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;         switch( sector ) {         case 0:             *oR = inBrightness;             *oG = t;             *oB = p;             break;         case 1:             *oR = q;             *oG = inBrightness;             *oB = p;             break;         case 2:             *oR = p;             *oG = inBrightness;             *oB = t;             break;         case 3:             *oR = p;             *oG = q;             *oB = inBrightness;             break;         case 4:             *oR = t;             *oG = p;             *oB = inBrightness;             break;         default:    // case 5:             *oR = inBrightness;             *oG = p;             *oB = q;             break;         }     }
}

void CheckConfigButtons ()    // InterruptRoutine
{
bool PressedZ;

if (ButtonAPress == true)    {     ShouldAnimation = !ShouldAnimation;     delay(250);     ButtonAPress = false;    }
} 

void AnimationControl ()
{   int GetSelAnimation = 0;       if (GetONOFFStatus != OLDONOFFStatus)     {     OLDONOFFStatus = GetONOFFStatus;     if (GetONOFFStatus)        {       randomSeed(analogRead(3));            GetSelAnimation = 1;       ShouldAnimation = GetSelAnimation;       Serial.print ("System ON. Selected: ");       Serial.println (ShouldAnimation);       } else       {       Serial.print ("System OFF. Seconds:");       TimerStartFlagFlag = false;       Serial.println (TimerSeconds);       ShouldAnimation = 0;       }   }    }

// Main Loop  -----------------------------------------------------------------------

void loop()    {     AnimationControl();     RunAnimations();     CheckConfigButtons();   }

// Main Loop  ----------------------------------------------------------------------- Ende


//Intros
void Intro_RaiseRainbow(bool risefall)
{   brightness = 255;   int Rainbowcolor = 0;
 if (risefall)
 {   for (int i=0; i < strip.numPixels(); i++)      {      //   wdt_reset();       hue = map(i + Rainbowcolor, angleMin, 60, hueRedLow, hueRedHigh); //Set Minute Color           HSBToRGB(hue, saturation, brightness, &r, &g, &b); //Set Hour Color       strip.setPixelColor(i, r, g, b);     //Calulate RGB Values for  Hour Pixel       strip.show();       delay(40);     }
 } else
 {      for (int i=0; i < strip.numPixels(); i++)      {      //   wdt_reset();       strip.setPixelColor(i, 0, 0, 0);       strip.show();       delay(40);     }
 } 
}
//Animations
void Ani_AllOff ()
{
for ( int i = 0; i < strip.numPixels(); i++)      {               strip.setPixelColor(i,0, 0, 0);      // all off      }
strip.show();
}

void Ani_Rainbow(byte delaytime)
{   brightness = 100;   int Rainbowcolor = 0;   do   {   for (int i=0; i < strip.numPixels(); i++)      {        hue = map(i + Rainbowcolor, angleMin, 60, hueRedLow, hueRedHigh);            HSBToRGB(hue, saturation, brightness, &r, &g, &b);        strip.setPixelColor(i, r, g, b);        }   strip.show();   // Show results :)   delay(delaytime);   Rainbowcolor++ ;   } while (Rainbowcolor < 61);
}

void RunAnimations()
{   if (!(ShouldAnimation == IsAnimation))   {     PlayOutro = true;     ChangeAnimation = true;   }
switch (IsAnimation)    {      case 0:                                    // all LedsOFF       if (PlayIntro)          {                  PlayIntro = false;         RunOnce = true;         }        if   ((!(PlayIntro)) &&  (!(PlayOutro)))        {           if (RunOnce) {  Ani_AllOff (); }          RunOnce = false;        }        if  (PlayOutro)          {                PlayOutro  = false;         PlayIntro = true;         RunOnce = true;         IsAnimation = ShouldAnimation;         }               break;       case 1:            if (PlayIntro)          {         Intro_RaiseRainbow(true);            PlayIntro = false;         }         if  ((!(PlayIntro)) && (!(PlayOutro)))         {           Ani_Rainbow(20);         }        if  (PlayOutro)          {         Intro_RaiseRainbow(false);                      PlayOutro  = false;         PlayIntro = true;         IsAnimation =  ShouldAnimation;         }              break;    }    }

 

Jetzt einfach kurz den Taster betätigen und das Schauspiel genießen :) . Ein weiterer Tastendruck schaltet die Brille wieder aus.

Ich wünsche viel Spaß beim Nachbauen und wie immer bis zum nächsten Mal.

For arduinoProjects for beginners

4 comments

Tobias

Tobias

In der Tat hat sich ein kleiner Fehler in das Fritzing Bild eingeschlichen. Natürlich müssen die Ringmassen auch mit GND verbunden werden. Für die Verbindung der Ringe ist folgendes zu beachten :
D6 > DI (Ring1) DO (Ring1) → DI (Ring2)

Sascha

Sascha

Moin
Von der Idee her, finde ich es gut, aber mir stellt sich die Frage ob es funktioniert wenn die Ringe keinen Null bekommen.

Geht dir nichts an

Geht dir nichts an

Die Fritzing funktioniert so nicht, Masse (gnd) ist zwar zwischen den einzelnen Ringen verbunden, aber nicht zum Breadboard … dafür aber 2 mal die 5V Verbindung.
P.S.: Wenn ihr nächstes mal das Bild mit halb so vielen Pixeln veröffentlicht, dann sieht man auch solche Fehler nicht mehr. (Oder in anderen Worten: Bitte einen link zu einem Fritzing Bild mit höherer Auflösung damit die Leute auch erkennen können was wohin geht, denn hier sind die Beschriftungen nicht mehr zu erkennnen)

Bernd

Bernd

Der Schaltplan sieht ja ganz nett aus, aber die zwei RGB LED Ringe brauchen nicht nur die GND Verbindung untereinander sondern auch noch die GND Verbindung zum Breadboard, oder nur zwei schwarze Verbindungen von den Ringen zum Breadboard auf GND. Etwa so wie bei zwei den roten +5V Verbindungen.

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. Install ESP32 now from the board manager
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA - Over the Air - ESP programming via WLAN