(Sort of) Black Hole Generator (Honest)

(Sort of) Black Hole Generator (Honest)

Ok, let’s be honest, it’s NOT a black hole generator, but it does generate what look like holes in walls and tables that are very black. It’s actually an Infinity Mirror (not an Infinity Gauntlet, that’s from Marvel Comics). Anyway, here’s how I built it.

bh white

The basic premise of an infinity mirror is to use two reflective surfaces facing each other to create the perception of a long tunnel. To achieve this you start with a mirror at the back of a picture frame, mount LEDs in the frame sides (at 90 degrees to the mirror) and finish with a two way mirror in the front (a panel of glass that can be seen through from one side and is a mirror on the other).

bh blue

The rear mirror started out life as part of a larger tiled mirror. I bought a frame from Hobby Craft that is the correct size for the mirror (which surprised me as it included a frame within a frame, which made mounting the lighting easier) and used car window tint on the inside of the front glass to create the two way mirror.

Rather than drill and mount LEDs around the frame I’ve used a strip of common anode RGB LEDs from Banggood.com, which meant either sticking to a single colour or building a controller box. Naturally I built a controller box. Because reasons.

I decided to use an Arduino Nano (clone) as a self contained micro-controller. Now of course an Arduino can’t sink much current, certainly not enough to power 30 or so RGB LEDs (so that’s potentially 90 or so LEDs if all colours are on), so I built a circuit using a MOSFET to control each channel (Red, Green and Blue) which has it’s gate switched direct from the Nano. That way the MOSFETs handle the big current.

bh control

To control the output I bought a 3×4 Matrix key pad. This requires seven digital IO pins on the Nano, plus the 3 already assigned for driving the MOSFETs, that’s most of the pins gone. I wanted some form of LCD display, and seeing as the standard Hitachi interface requires up to 11 digital IO pins, that was looking unlikely. However I found an I2C driven LCD (which was actually just a standard Hitachi style LCD with an I2C daughter-board) which would only require 2 pins. So I bought it. All of the electronics, like the LEDs, came from Banggood.com.

After a bit of soldering, then some wiring, then some tweaking, I finally mounted the controller in a project box from Maplin (after setting about it with a generic-high-speed-multi-tool). Viola, a black hole generator.

bh lcd

 

 

 

 

So here’s the fritzed circuit …

bh circuit

And here’s the code for the Arduino (I may link the libraries if I can dig out the correct links – grab me at the hackspace if I forget!)


#include <Keypad.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address

const byte brightMax = 200;
const byte brightMin = 0;
const int msDelay = 10;

const byte ROWS = 4;
const byte COLS = 3;

int ledR = 9;
int ledG = 10;
int ledB = 11;

int valR = brightMax;
int valG = brightMax;
int valB = brightMax;

bool doLoop = false;

char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'#','0','*'}

};

byte colPins[COLS] = { 4, 3, 2 };
byte rowPins[ROWS] = { 8, 7, 6, 5 };

Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup() {
// define output pins
pinMode(ledR, OUTPUT);
pinMode(ledG, OUTPUT);
pinMode(ledB, OUTPUT);
}

void loop() {
char key=kpd.getKey();

if (key)
{
switch(key)
{
case '#': doLoop = true; break;
case '*': doLoop = true; break;
case '0':
valR = brightMax;
valG = brightMax;
valB = brightMax;
break;
case '1': //RED toggle
if (valR > brightMin)
{
valR = brightMin;
}
else
{
valR = brightMax;
}
break;
case '2': //GREEN toggle
if (valG > brightMin)
{
valG = brightMin;
}
else
{
valG = brightMax;
}
break;
case '3': //BLUE toggle
if (valB > brightMin)
{
valB = brightMin;
}
else
{
valB = brightMax;
}
break;
case '4': //RED up
if (valR < brightMax)
{
valR += 10;
}
else
{
valR = brightMax;
}
break;
case '5': //Green up
if (valG < brightMax)
{
valG += 10;
}
else
{
valG = brightMax;
}
break;
case '6': //Blue up
if (valR < brightMax)
{
valB += 10;
}
else
{
valB = brightMax;
}
break;
case '7': //RED down
if (valR > (brightMin + 10))
{
valR -= 10;
}
else
{
valR = brightMin;
}
break;
case '8': //GREEN down
if (valG > (brightMin + 10))
{
valG -= 10;
}
else
{
valG = brightMin;
}
break;
case '9': //BLUE down
if (valB > (brightMin + 10))
{
valB -= 10;
}
else
{
valB = brightMin;
}
break;
}
}

if (doLoop == true)
{
faderLoop();
}
else
{
analogWrite(ledR, valR);
analogWrite(ledG, valG);
analogWrite(ledB, valB);
}
}

void faderLoop()
{
int i = 0;

//set initial values of LEDs
writeToLEDs();

//white to red (ffffff to ff0000)
for (i = brightMax; i > brightMin - 1; i--)
{
valG = i;
valB = i;
writeToLEDs();
delay(msDelay);
}
//red to yellow (ff0000 to ffff00)
for (i = brightMin; i < brightMax; i++)
{
valG = i;
writeToLEDs();
delay(msDelay);
}

//yellow to green (ffff00 to 00ff00)
for (i = brightMax; i > brightMin - 1; i--)
{
valR = i;
writeToLEDs();
delay(msDelay);
}

//green to cyan (00ff00 to 00ffff)
for (i = brightMin; i < brightMax; i++)
{
valB = i;
writeToLEDs();
delay(msDelay);
}

//cyan to blue (00ffff to 0000ff)
for (i = brightMax; i > brightMin - 1; i--)
{
valG = i;
writeToLEDs();
delay(msDelay);
}

//blue to magenta (0000ff to ff00ff)
for (i = brightMin; i < brightMax; i++)
{
valR = i;
writeToLEDs();
delay(msDelay);
}

//magenta to white (ff00ff to ffffff)
for (i = brightMin; i < brightMax; i++)
{
valG = i;
writeToLEDs();
delay(msDelay);
}
}

void writeToLEDs()
{
lcd.setCursor(0,0);
if (valR > 0)
{
lcd.print("R:" + String(valR, DEC));
}
else
{
lcd.print("R:OFF");
}
analogWrite(ledR, valR);

lcd.setCursor(1,1);
if (valG > 0)
{
lcd.print("G:" + String(valG, DEC));
}
else
{
lcd.print("G:OFF");
}
analogWrite(ledG, valG);

lcd.setCursor(7,0);
if (valB > 0)
{
lcd.print("B:" + String(valB, DEC));
}
else
{
lcd.print("B:OFF");
}
analogWrite(ledB, valB);
}

No Comments

Post A Comment