Introduction: Dynamic LED Lighting Controller for Art
Introduction:
Lighting is an important aspect of visual art. And if the lighting can change with time it can become a significant dimension of the art. This project started with attending a light show and experiencing how the lighting could totally change the color of an object. We began to explore this in lighting fabric art. So far we have built dynamic lighting for 8 pieces including a painting and a photograph. The lighting effects have included: simulating dawn and sunset, underwater light through a rippling surface, lightning in clouds, and dramatically changing the perceived colors and mood of the art work. Videos of these effects are included in the programming steps below.
This instructable builds a controller that sets the brightness and color of a string of individually addressable LEDs over time. It also includes an optional input circuit for manually tuning (setting brightness and color) of a segment of the lighting. You will also learn about many problems and improvements we discovered along the way.
We also wrote an associated instructable on building the shadow box and frame. Check it out at: https://www.instructables.com/id/Dynamic-LED-Ligh...
For now we will focus on the electronics and programming.
Step 1: Materials:
- String of WS2812 LEDs https://www.adafruit.com/product/1461
- Arduino Pro Mini 328 - 5V/16 MHz https://www.adafruit.com/product/2378
- FTDI Friend USB Interface https://www.adafruit.com/product/284
- USB A to MiniB cable for FTDI https://www.adafruit.com/product/260
- 4700 μf Capacitor https://www.adafruit.com/product/1589
- 5v Power Supply with 5.5 x 2.1 connector http://www.newark.com/triad-magnetics/wsu050-4000...
- Power Socket 5.5 x 2.1 https://www.adafruit.com/product/373
- Terminal Block https://www.adafruit.com/product/725
- Prototype circuit board https://www.adafruit.com/product/589
- Button https://www.adafruit.com/product/367
- Potentiometer https://www.adafruit.com/product/356
- Indicator LED https://www.adafruit.com/product/298
- Resistors https://www.adafruit.com/product/2892
- Ribbon cable https://www.sparkfun.com/products/10647
- Header male https://www.sparkfun.com/products/116
- Header female https://www.sparkfun.com/products/115
Step 2: Resources:
- Arduino; Interactive Development Environment (IDE) https://www.arduino.cc
- Adafruit NeoPixel Library https://github.com/adafruit/Adafruit_NeoPixel
- NeoPixel Tutorial https://learn.adafruit.com/adafruit-neopixel-uberguide
- Strandtest Example Program https://github.com/adafruit/Adafruit_NeoPixel/tree/master/examples/StrandtestBLE
- FastLED Library https://github.com/FastLED/FastLED
- FastLED Links and Documentation http://fastled.io/docs http://fastled.io
- FastLED Forum https://plus.google.com/communities/109127054924227823508
- Our Lighting Sketches https://github.com/dennisholt/Dynamic_LED_Controller.git
Step 3: Controller Overview:
The schematic looks pretty simple and it is. We built our controllers to be embedded in a picture frame. The dimensions of the circuit pictured is 2.25” x 1.3” x 0.5”. The optional tuner was built on a separate circuit board with a ribbon cable connector. These pictures show our finished project.
We want to fit our controller into the picture frame so we chose the Arduino pro mini 5v for its small size, cost, and 5v output. The size of the 5v power supply you need will depend on how many LEDs and their maximum brightness in your project. Our projects all ran less than 3 amps and some were less than 1 amp. There are several types of addressable color LEDs. We started with the WS2812 sold by Adafruit as one of their “NeoPixel” products. This worked for us and we haven't explored other LEDs. Most of our projects used the 60 LED per meter strip. So far our projects have ranged up to 145 LEDs.
Optional Tuner:
We built a small input circuit “tuner” so we could easily adjust segments of lighting without modifying and uploading the program for each adjustment. It has: an output LED which flashes the input mode; a button that shifts the input mode; and a knob which can be adjusted. The Arduino can then output the values to a connected computer.
Step 4: Building Controller:
The material list does not contain the wire, heatshrink tubing, and other supplies you might need. For the 5v and ground circuit to the LEDs I suggest you use 26 gauge or heavier stranded wire. We used 26 gauge. Also silicone insulation on the wire is better because it doesn't melt near where you are soldering and it is more flexible. I found leaving a little more space between the components made fabrication much easier. For instance, the controller pictured in Step #6 the space between the housing of the power socket (black) and the terminal block (blue) is about 1 inch. Our mounting cover is two layers of wood veneer.
The picture in this step shows the wiring of a six contact female header for the optional tuner. The unused contact between the red and green wire is plugged with a piece of toothpick to prevent reverse connection.
Step 5:
Now, lets put it together so it fits in the shadow box frame. The frame is 3/4" thick so we have a controller height limit of 1/2". We made mounting plates by sticking two pieces of veneer toughener with the grain perpendicular to each other to limit warping. The components arranged so the power jack will be at the center of the frame. The hole for the power jack was cut with a jeweler's saw and filed out to fit. The components are then wired together before mounting. The socket is glued in place with epoxy. Double sided permanent foam mounting squares are used under the screw terminal and arduino. Hot melt glue is also used to hold the arduino in place as well as the capacitor.
Step 6: Building Optional Tuner:
We built a small input circuit “tuner” so we could easily adjust segments of lighting without modifying and uploading the program for each adjustment. It has: an output LED which flashes the input mode; a button that shifts the input mode; and a knob which can be adjusted. The Arduino can then output the values to a connected computer.
These pictures show the fabrication of the tuner. I covered the back with “Gorilla” tape. Which holds the ribbon cable stable and also made a nice handle.
Step 7: Programming Controller Overview:
This is really the hard part of the project. Hopefully you will be able to use some of our code and methods to get a head start.
Adafruit and FastLED have published two great libraries to enable Arduinos to control many kinds of addressable LEDs. We use both of these libraries in different projects. We suggest you also read some of the resource material on these libraries and explore some of their example programs.
The Github repository of our programs is listed in the “Resources” above. Note we are far from proficient at Arduino programming so there is lots of room for improvement. Feel free to point out issues and contribute improvements.
Step 8: Programming Controller Example Ripple:
“Ripple” by Jeanie Holt was our first success. This piece is a fabric art fish in a shadow box frame. The lighting is steady low level blue from below. And from above, up to three shafts of brighter white light moving right to left as if refracted by moving ripples on the water surface. This is a rather simple concept and the program doesn't use the “tuner” inputs. It starts off including the Adafruit library and defining the output control pin and the number of LEDs. Next we do one-time setup of the serial communication and LED strip. Then we define a number of internal variables, such as, the delay between refreshes, the characteristics of a shaft of light (its brightness over time and its motion), then state variables for each shaft of light.
The “changeBright()” function will increase the brightness of a shaft of light during the “attack” time, hold it constant for the “sustain” time, then fade-out over the “decay” time.
The “ripple()” function is called for each of the three shafts of light during each time increment. The temporary brightness is calculated based on fading from maximum brightness at a constant decay over time. Then for each LED to the left of the starting position the brightness is calculated. We can imagine a ripple of light moving to the left. Each LED to the left is at an earlier point in the ripple brightness time curve. When this ripple has zero brightness for all LEDs the done flag is set to 1. If the LED is already brighter (set by one of the other ripples) we leave the value unchanged.
The main loop starts off by turning off the LEDs. Then for each of the three ripples it calls the ripple function and increments its time counter. If the done flag is set it starts the ripple over. Finally the main loop sets a pale blue light across the bottom.
Step 9: Programming Controller Example Dawn to Dusk:
The next project, “Dawn to Dusk” by Jeanie Holt, is another fabric art piece this time a tree with autumn colored foliage. The lighting is a simulation of the day with dawn beginning to brighten on the left progressing to bright mid-day followed by reddish sunset colors and progressing to night. The challenge here is simplifying the description of shifting color and brightness with time over a strip of 66 LEDs. The other challenge is making the light change smoothly. We really struggled with the noticeable shift in light at low light levels. I tried to get smoother lighting transitions using the FastLED library but was not successful. This program description will be less detailed. Again we used Adafruit's NeoPixel library.
We went to a convention of starting our LED strips in the upper left corner. This makes the LED location numbering a bit awkward in this piece. There are 86 LEDs around the frame. Dawn lights up the left side which goes from 62 to 85. Then top left to bottom right is 0 through 43.
This program does not includes the ability to use the “Tuner” input circuit.
This program uses time dithering to reduce flicker. We update every fifth LED then come around shift over one and update every fifth LED and repeat until they are all updated. For this reason we define the length of the LED string a bit longer than it really is.
Now here is how we simplified the description of the lighting pattern. We identified 12 reference LED positions around the frame from lower left to lower right. Then we defined the red, green, and blue (RGB) LED intensity for these reference LED at up to 12 break points through the dawn to dusk time period. For each break point there are 4 bytes, the number of time counts since the last break point, and the one byte value for each of the RGB colors. This array takes up 576 bytes of precious memory.
We now use linear interpolation to find values between breakpoints and again linear interpolation to find values for the LEDs located between reference LEDs. For the interpolation to work well we need to use some floating point intermediate values. The dawn to dusk period is broken into 120 half second time periods.
Step 10: Programming Controller Example Rain Forest:
The next project I will describe is “Rain Forest” by Juli-Ann Gasper. This is a larger fabric art piece with a lot of depth. Here we used a shadow box about 4.4” deep. The lighting concept is background light levels that are dimmer at the bottom with light flickering through the leaves above from time to time. The concept here is similar to Ripple but the shafts of light don't move. And unlike ripple where the brightness changes smoothly, here the flicker brightness needs to fluctuate. We created a 40 byte array called flicker_b2. We found the visual effect was fine if we used the same pattern for all the flicker locations. We established 5 flicker locations. When reviewing the visual effect we found that one of the flickers needed to be much wider than the others. We used the fill_gradient_RGB() function to stretch that flicker out over about 20 LEDs. Each flicker is independent and starting at random. The probability of each flicker can be set.
The background color needs to be set and restored when the flicker is not brighter than the background.
For this piece we used the FastLED library. In this program the #define TUNING is used to indicate if the tuning board is plugged in, it needs to be 0 when the tuner board is not plugged in. Otherwise the controller is sensitive to static electricity and poltergeists. The compiler only includes the program segments that use the “Tuner” when this variable is 1.
Step 11: Programming Controller Example Storm:
Another project was lighting a photograph called “Storm” by Mike Beck. The picture is a storm cloud. We use FastLED library and do not include the tuning capability. The lighting concept here is some background light with lightning flashes appearing randomly at three points around the cloud. The flash at each location is caused by three LEDs. The space between these LEDs is different for each location. The brightness of these three LEDs is defined by three 30 byte arrays. The brightness sequence in the three arrays gives variation and apparent movement across the three LEDs. The direction of perceived movement and overall brightness is selected for each location. The duration of the flash at each location is adjusted by the time delay between updating brightness values. There is a random time delay between 0.2 and 10.4 seconds between lightning strikes. Which of the three strike locations is also random with 19% chance at top of cloud, 45% chance at lower right, and 36% chance along the left side.
Step 12: Programming Controller Examples Macaw and Nordic Tree:
The pieces “Macaw” by Dana Newman and “Nordic Tree” by Jeanie Holt use lighting color to change the perceived color of the piece. And in the case of Dana's painting of a large macaw the mood of the bird changes from joyful to menacing depending on the color of light surrounding the bird. These two programs are almost identical. We use Adafruit NeoPixel library and the tuning board capability is in these programs. These programs are adapted from the theaterChaseRainbow() function in Adafruit_NeoPixel/examples/Strandtest.ino (downloaded 7/29/2015)
The lighting is held at a relatively constant brightness while the color of the light shifts progressing through a color wheel of colors. Progressing around the color wheel is created by starting with 100% red and incrementally decreasing red while increasing green. Once green is at 100% it is then decreased while increasing blue. And finally as blue is decreased and red increased you come full circle.
This provides lighting using two of the primary colors and leaves one out. As we cycle through this lighting color wheel at some point any color in the art piece will be missing in the supplied light. The resulting change in perceived color can be quite dramatic and becomes a part of the art expression. So if red isn't present in the light any red in the painting will appear dark. When the light is pure red then the red really glows and the other colors are muted.
Step 13: Programming Controller Examples Copperhead:
“Copperhead” by Jeanie Holt use lighting variation to enhance the sense of outdoors and variation in the conspicuity of the snake. The programming layers waves of light on top of background lighting.
For this program we used the FastLED library along with our Tuner circuit for development.
The background color is set at 10 points around the frame and the function fill_gradient() is used to smoothly transition between colors.
At the beginning of a viewing cycle the background is dimmed and color shifts to blue using a cosine curve over time and the setBrightness() function.
After a delay three waves of light moving from the upper right to the lower left. The first wave is the brightest with following waves becoming dimmer. The first wave also moves slower.
Step 14: Programming Controller Examples Black Doodle:
“Black Doodle” by Jeanie Holt explores reflections off of black vinyl.
This program also uses the FastLED library and can take input from the tuning circuit.
The lighting consists of up to 5 simultaneous displays of light playing from random points around the frame. Each display progresses through the same 60 brightness values over time. Each display involves 7 adjacent LEDs with the brightness diminishing toward the edges. Before each display starts there is a random delay. The location of the display is random but locations near an active display are inhibited.
The background is a rainbow of colors spread around the frame. This background rainbow slowly turns and randomly reverses direction.
These descriptions are an overview and aid to reading the programs. We hope you find some of these lighting effects interesting enough to incorporate in one of your projects. A link to github.com where the programs are stored is in Step 2 Resources.
Step 15: Programming the Tuning Functions:
In the RainForest program we can turn the tuning function on by “#define TUNING 1” and attach the tuning input board using its ribbon cable. We need to also set parameters for which LED will be effected by the tuning. For example let's adjust LEDs at positions 61 through 73. We use #define START_TUNE 61 and #define END_TUNE 73. We set other segments of the string to background colors in setup() useing fill_gradient_RGB() calls. The rest of your sketch should not set the LEDs in the tuning range or you won't be able to see your adjustments. Now run the sketch and display the serial monitor. The tuning part of the program has 4 states [Hue, Saturation, Value, and Brightness}. Hue is the color wheel with 0=Red and 255 past blue to almost red. The current state should be printed on the serial monitor and the indicator LED on the tuning board will blink to indicate the state (one blink is Hue; two blinks is Saturation and so forth). Value is the light intensity while brightness is a reduction factor that gets applied to all the LEDs intensity values. So for full brightness set Value = 255 and Brightness = 255. Press the button to shift the state. When you are on the state you want to adjust turn the knob. The program ignores the knob until it is turned more than the INHIBIT_LEVEL. This avoids changing values in the other states when you cycle through them. Example you might start with Hue and get the color you want, then shift to value and adjust to find the brightness you want.
The Macaw and Nordic_Tree sketches include tuning but the functions are a little different. In these sketches there are only two modes. One for brightness and one for color wheel position. With these examples you can see how to customize the tuning functions to work with most any parameter in you lighting control.
Included in the repository is a sketch 'Tuning' which takes the tuning functions from RainForest. This sketch is only the tuning functions so you can explore and more easily follow how the sketch works. We use this sketch to control a test lighting frame which we can quickly place over an art piece and explore lighting effects. Later we will use the tuning information to build the custom lighting controller.
Hope you find this instructable helpful in making your project work.
Step 16: The Rest of the Story:
This is one of two instructables on this project. If you haven't already, check out the companion instructable at: https://www.instructables.com/id/Dynamic-LED-Ligh...