Introduction: Fiber-Optic Lights in Canvas Print

This project adds a unique spin on a standard canvas print. I programed in 4 different lighting modes but you could easily add more. The mode is changed each time you turn it off and back on instead of having a separate button to minimize damage to the frame. The batteries should last for 50+ hours of use - I'm not really sure, but I made a similar project for a friend and it used 5x as many lights and has lasted 20+ hours on a single set of batteries.

Materials

  • Canvas print with workable space - I ordered mine from https://www.easycanvasprints.com because they had good prices and an open back. The thicker 1.5" frame was perfect and gave me a lot of space to bend the fiber optic strands. Additionally you want a picture that gives you 3" by 8" of workable space for the battery pack and microcontroller and LED strips
  • LED strip lights - I used addressable WS2812 LED strips. Don't be intimidated, they're really easy to use with the FastLED or Neopixel libraries! You could also use any standard LED strip, you just won't be able to control each light section individually without a lot more wiring.
  • Microcontroller - I used an Arduino Uno but you can use just about anything for this project.
  • Battery pack - I ordered this one from eBay (from China) and it was titled "6 x 1.5V AA 2A CELL Battery Batteries Holder"
  • Fiber optic strands - once again, ordered from China on eBay - "PMMA Plastic Fiber Optic Cable End Grow Led Light DIY Decor" or "PMMA End Glow Fiber Optic Cable for Star Ceiling Light Kit". I used sizes 1mm and 1.5mm, I actually recommend using smaller than that.
  • On/Off switch - "SPDT On/On 2 Position Miniature Toggle Switches"
  • Wire organization clips - These help keep the fiber optic strands nice and tidy. https://smile.amazon.com/gp/product/B07CL2HVPV/
  • Foam board, solid core connector wire, heat shrink tubing

Tools

  • Dremel - used to nest the on/off switch in the picture frame. This could maybe be accomplished with a drill and a really big bit, but I don't recommend that.
  • Soldering iron - attaching wires to the LED strip
  • Hot glue gun - literally every step of this project
  • Large sewing needle - for poking holes through the canvas and foam board for the lights

Step 1: Foam Board, Battery Pack and On/off Switch

Before anything else you need to attach a piece of foam board to the back of the canvas print. This gives us a nice solid surface to attach everything else to and helps hold the fiber optic strands in place. Just use an exacto knife or box cutter to cut a piece of foam board to the right size and hot glue it in at a lot of places. I recommend using black foam board so that it doesn't allow as much light to bleed through.

I used the dremel bit that looks like a normal drill bit but is actually great for removing material. It's one of the bits that should come with any dremel. Use a can of compressed air to get rid of any sawdust from the dremel.

Hot glue everything in place. Make sure the battery pack is attached very well because it requires a good bit of force to insert/remove a battery and you don't want the battery holder to go anywhere.

Step 2: Microcontroller and Circuit

I put the power switch before the Arduino UNO so that when you toggle the switch then nothing is using power from the battery packs. This should help the batteries last as long as possible when the project isn't turned on. Arduino boards are notoriously bad at power management - they use a lot of current if they're turned on even if they aren't actively doing anything.

Plug the positive end of the battery pack into VIN (voltage input) of the microcontroller so that it uses the controller's built-in voltage regulator to get the voltage down to the 5V it needs. If we were powering more lights we might need to use our own voltage regulator for them, but the UNO should be able to handle 5 LEDs.

I used a resistor between the data output and the LED strip to smooth out the signal - without the resistor you might get random flashing of pixels. The size of the resistor doesn't really matter, anything between 50Ω and 400Ω should work.

Step 3: Fiber-optic Lights

After some trial and error I eventually found a good way to get the fiber optic strands through the canvas.

  1. Use the largest sewing needle you have to poke a hole through the front of the canvas and foam board. I recommend poking every hole you want at the very beginning so you can flip it over and see where you can/can't put your cable organization clips
  2. Take a pair of needle-nosed pliers and grab the fiber optic strand less than a centimeter from the end
  3. Poke the fiber optic strand through the hole you made with a needle
  4. Route the strand through various plastic clips to where it is slightly longer than necessary - we'll cut it later
  5. With your hot glue gun on the LOW temperature setting (if it has that option) put a drop of hot glue on the fiber optic strand where it pokes through the foam board. Alternately you could use that blue tacky stuff. The hot glue does deform the strand a little bit but it doesn't seem to mess with the optical qualities too much
  6. Cut the strand a little bit away from the canvas using wire cutters.

To speed up the process you can poke through many fibers in a row before doing the hot glue. They should generally stay in place on your own.

Be careful not to break or squish the fiber optic strands on the table - they'll break and if it makes the strand too short then you'll be sad and have to redo it. Use the battery pack as a counterweight so you can have the picture frame less than half on the desk.

Because I used white foam board instead of black there was a lot of light shining through when the LEDs were on. As a fix I taped in some aluminum foil between the lights and the canvas.

Use heat shrink tubing to keep each bundle of fiber optic strands together.

  1. Cut the strands for the bundle to approximately the same length
  2. Put the section through heat shrink tubing
  3. Use a heat gun or soldering iron to shrink it. If you're using a soldering iron, just let the side of the iron lightly touch the tubing and it will shrink. It shouldn't melt the tubing because it's designed for a little heat.

Eventually I used hot glue to attach the end of the bundle to each LED light. I used a lot of hot glue so that the fibers actually got light from each red/green/blue diode in the light - when the fibers are really close to the light a "white" color (which is actually red and green and blue) then some fibers will just be red and some will be green, instead of all being white. This could be improved by using a piece of paper or something else to diffuse it, but hot glue worked well enough for me.

Step 4: Programming

In programming this I used threelibraries

FastLED - a great library for controlling WS2812 LED strips (and many other addressable LED strips) - https://github.com/FastLED/FastLED

Arduino Low Power - I don't know how much power this actually saves, but it was super easy to implement and should help save a tiny bit of power on the function that is just white lights and then delaying forever. https://github.com/rocketscream/Low-Power

EEPROM - Used to read/store the current mode of the project. This allows the project to increment the color mode each time you turn it off and back on, which eliminates the need of a separate button to change the mode. The EEPROM library is installed whenever you install the Arduino IDE.

I also used a sketch for twinkling the lights that someone else set up. It randomly lights up a pixel from a base color to a peak color and then back down. https://gist.github.com/kriegsman/88954aae22b03a66... (it uses the FastLED library as well)

I also used the vMicro plugin for Visual Studio - this is an amped up version of the Arduino IDE. It has a ton of helpful autocomplete functions and highlights problems in your code without having to compile it. It costs $15 but is so worth it if you're going to make more than one Arduino project, and it will force you to learn about Visual Studio which is a super powerful program. https://www.visualmicro.com/

(I'm also attaching the code .ino file because the Instructable hosting of a Github Gist destroys a lot of the blank spaces in the file)

The Arduino code running 4 color modes on an Arduino UNO for some WS2812B LED strip lights using the FastLED library

#include<FastLED.h>
#include<LowPower.h>
#include<EEPROM.h>
//FastLED setup
#defineNUM_LEDS4
#definePIN3//Data pin for LED strip
CRGB leds[NUM_LEDS];
//Twinkle setup
#defineBASE_COLORCRGB(2,2,2) //Base background color
#definePEAK_COLORCRGB(255,255,255) //Peak color to twinkle up to
// Amount to increment the color by each loop as it gets brighter:
#defineDELTA_COLOR_UPCRGB(4,4,4)
// Amount to decrement the color by each loop as it gets dimmer:
#defineDELTA_COLOR_DOWNCRGB(4,4,4)
// Chance of each pixel starting to brighten up.
// 1 or 2 = a few brightening pixels at a time.
// 10 = lots of pixels brightening at a time.
#defineCHANCE_OF_TWINKLE2
enum { SteadyDim, GettingBrighter, GettingDimmerAgain };
uint8_t PixelState[NUM_LEDS];
byte runMode;
byte globalBright = 150;
byte globalDelay = 20; //Delay speed for twinkling
byte address = 35; //Address to store the run mode
voidsetup()
{
FastLED.addLeds(leds, NUM_LEDS);
FastLED.setCorrection(TypicalLEDStrip);
//FastLED.setMaxPowerInVoltsAndMilliamps(5,maxMilliamps);
FastLED.setBrightness(globalBright);
//Get the mode to run
runMode = EEPROM.read(address);
//Increment the runmode by 1
EEPROM.write(address, runMode + 1);
}
voidloop()
{
switch (runMode)
{
//Solid white
case1: fill_solid(leds, NUM_LEDS, CRGB::White);
FastLED.show();
DelayForever();
break;
//Twinkle kinda slowly
case2: FastLED.setBrightness(255);
globalDelay = 10;
TwinkleMapPixels();
break;
//Twinkle quickly
case3: FastLED.setBrightness(150);
globalDelay = 2;
TwinkleMapPixels();
break;
//Rainbow
case4:
RunRainbow();
break;
//Index out of range, reset it to 2 and then run mode 1.
//When the arduino restarts it will run mode 2, but for now run mode 1
default:
EEPROM.write(address, 2);
runMode = 1;
break;
}
}
voidRunRainbow()
{
byte *c;
uint16_t i, j;
while (true)
{
for (j = 0; j < 256; j++) { // 1 cycle of all colors on wheel
for (i = 0; i < NUM_LEDS; i++) {
c = Wheel(((i * 256 / NUM_LEDS) + j) & 255);
setPixel(i, *c, *(c + 1), *(c + 2));
}
FastLED.show();
delay(globalDelay);
}
}
}
byte * Wheel(byte WheelPos) {
static byte c[3];
if (WheelPos < 85) {
c[0] = WheelPos * 3;
c[1] = 255 - WheelPos * 3;
c[2] = 0;
}
elseif (WheelPos < 170) {
WheelPos -= 85;
c[0] = 255 - WheelPos * 3;
c[1] = 0;
c[2] = WheelPos * 3;
}
else {
WheelPos -= 170;
c[0] = 0;
c[1] = WheelPos * 3;
c[2] = 255 - WheelPos * 3;
}
return c;
}
voidTwinkleMapPixels()
{
InitPixelStates();
while (true)
{
for (uint16_t i = 0; i < NUM_LEDS; i++) {
if (PixelState[i] == SteadyDim) {
// this pixels is currently: SteadyDim
// so we randomly consider making it start getting brighter
if (random8() < CHANCE_OF_TWINKLE) {
PixelState[i] = GettingBrighter;
}
}
elseif (PixelState[i] == GettingBrighter) {
// this pixels is currently: GettingBrighter
// so if it's at peak color, switch it to getting dimmer again
if (leds[i] >= PEAK_COLOR) {
PixelState[i] = GettingDimmerAgain;
}
else {
// otherwise, just keep brightening it:
leds[i] += DELTA_COLOR_UP;
}
}
else { // getting dimmer again
// this pixels is currently: GettingDimmerAgain
// so if it's back to base color, switch it to steady dim
if (leds[i] <= BASE_COLOR) {
leds[i] = BASE_COLOR; // reset to exact base color, in case we overshot
PixelState[i] = SteadyDim;
}
else {
// otherwise, just keep dimming it down:
leds[i] -= DELTA_COLOR_DOWN;
}
}
}
FastLED.show();
FastLED.delay(globalDelay);
}
}
voidInitPixelStates()
{
memset(PixelState, sizeof(PixelState), SteadyDim); // initialize all the pixels to SteadyDim.
fill_solid(leds, NUM_LEDS, BASE_COLOR);
}
voidDelayForever()
{
while (true)
{
delay(100);
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
}
}
voidshowStrip() {
FastLED.show();
}
voidsetPixel(int Pixel, byte red, byte green, byte blue) {
// FastLED
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
}

Step 5: Final Product

Ta-da! I hope this Instructable inspires someone else to make their own similar project. It really wasn't hard to do and I was surprised that no one had done it and written a thorough instructable about it yet.

Check out my website for other projects that I've made and some pictures I've taken - www.jacobathompson.com/projects