Set colors, animation speed, choose your animation and more - all from an onboard menu system.
This guide shows how to make a five-input helper-gadget for designing animations on NeoPixels. A digital readout shows RGB values and other data. It allows you to select from a collection of animations and fine tune them for color, speed, direction or any other variable you program for.
Techniques for repurposing and decorating a scavenged case are also shown. The basics of coding a simple menu-driven selection system is demonstrated. And the advantages of a modular, tabbed approach to coding in the Arduino IDE are discussed.
Who Is This For
This is an advanced beginners project. The provided sample code should be ready to load-and-run. But to modify it you should be familiar with for-loops, functions, the case-statement and controlling NeoPixels with Adafruits library.
If you have several breadboards filled with switches and pots always sitting around, and you swap them between test projects, you might benefit by making this permanent version.
If you are a visual designer and crafter, you might find this useful for determining colors and patterns before embedding the NeoPixels into your final project.
Do you hate to wait for your code to upload? Sure, coding animations for NeoPixels is easy. And it is fun learning how even minor tweaks can yield vastly different effects.
But sometimes I get frustrated and impatient compiling and uploading the code over and over again for every minor change. This seems to be true for most new programmers. Now there's a knob for that.
Wouldn't it be cool to have one more button, a button that sent the current values into memory so that on the next start-up, each animation used our favorite settings automatically. Well there are plenty of input pins still available - and what a perfect time to learn about writing to memory.
Or create external ports so you could hook up any sized NeoPixel object for experimentation.
Step 1: Tools and Materials
- Arduino - I used Adafruit's Pro Trinket 5v because of its small size and low cost. But a standard Uno, Leonardo or any other full size Arduino will work. This particular configuration needs serial communication capabilities and five analog inputs, so some of the other mini-Arduino compatibles boards do not have enough inputs.
- Display - I used the Serial RGB 16x2 LCD display from Adafruit, mostly because my other displays were in use on other projects and the display fit into an existing opening in the scavenged case. But an SPI or I2C version would work fine. An OLED or color LCD graphics screen would work well also, but would require slightly more sophisticated programming.
- Neopixel - This project uses the 12 pixel NeoPixel ring because it fit the existing opening in the scavenged case. But the 16 or 24, or any other size of NeoPixels would work fine
- Perf-Board - I used the half-size PermaProto board form Adafruit because it has the same "routing" as the breadboard that I developed the circuit on. But any perf-board will work if you know how to modify the schematic. You can even use a breadboard, the circuit just won't be as durable.
- Wire - After struggling with scavenged wire and even jumper wires, I used the silicon sheathed wire from Adafruit. It's super flexible and easy to work with. Now I wish I had used it from the beginning.
- Potentiometers (qty 5) - I chose the 10k linear-taper potentiometers from Sparkfun (COM-09288) because they have the long shaft that would protrude out of the deep case. Most similar potentiometers will work, but 10k and linear (not audio taper) work best for me. You could even add more pots, there are three analog pins left on the ProTrinket.
- Button - You need a "normally open" momentary push button. The one used here is a reset button scavenged from a scrapped power supply.
- Capacitor - I used the 4700 uF 10v capacitor from Adafruit (1589).
- Resistor - I used a 330 ohm resistor
- USB Cable - Since this project was originally intended to be left at a Maker Space, I wanted the USB cable to be permanently attached so patrons didn't need to find a cable each time. You could leave access to the USB port and not attach the cable.
- Case - Not totally necessary, but it really helps keep your electronics safe. I used the shell of an old alarm clock because it had just the right number of holes and brackets for the project. But there are lots of old electronics cases waiting for a new life.
- Knobs - Just for decoration really, but I tell myself that it "Clarifies the functionality of the interface."
- Decorations - The decorations were originally meant to make the project fun for some kids in our local Makers Club. But after getting disassembled and transported, stored and generally knocked about, most of the decorations have been removed - and the project still gets used.
- Paint - Totally optional
- Support Material - You may also need some Sugru, Instamorph or at least some hot-glue to make components fit and secire them to the case
- Soldering Iron - Any fine tipped soldering iron will do.
- Multimeter - Test your connections and troubleshoot.
- Third-Hand - Really helpful, but not essential.
- Shaping Tools - You may need a pocketknife, files or a rotary tool to modify the case
You will also need a computer with the Arduino IDE installed. You will also need the NeoPixels library.
Step 2: Hooking It Up
It looks complicated, but don't freak out. If you can hook up one potentiometer, you can hook up five.
What a neat little board. It is a full blown Arduino-compatible board in a tiny package. But don't let the small size fool you. It is as powerful as the full sized boards and even has some extras. I normally like the 3v version because it simplifies working with the NeoPixels, but this LCD needs 5v, so I opted for the regular 5v board. Check out the introductory tutorial from Adafruit to learn more.
The PermaProto boards have power and ground rails just like a breadboard. And the center runs mimic a breadboard also. You can easily scratch through these runs, however, and customize the layout for a more compact design. But the breadboard-like layout makes it really simple to transfer your breadboarded prototype to a finished, soldered project. Because of this mimicry, you can use the included diagram of the breadboard and the connections will be exactly the same on the PermaProto. (You can also get several different sizes of the PermaProtos)
If you are using another type of prototyping board you will need to run power and ground plus make connections between components.
Power and Ground
I chose to pull the power for the PermaProto board from the BUS pin on the Pro-Trinket. Connect the BUS pin to one of the power rails on the PermaProto, then bridge the rail over to other power rail. This power supply runs all the components except the LCD display. The LCD display pulls power from the pin labeled 5v on the ProTrinket.
NOTE: Even with the LCD drawing power from another pin, I have seen some computers that cannot supply enough power. Everything still runs, but the LCD display gets dim or even blanks out. If you know how, providing a separate 5v supply to the LCD display would solve the problem.
If you know how to hook a up one potentiometer, you can hook up five. Just run the power for each of the five pots to a power rail, and all five grounds to a ground rail. Then connect the third pin on each to an analog pin on the Arduino.
You can use any analog pin, but I chose to keep the I2C pins (A4 and A5) open just in case I decided to expand the project later on.
The sample code expects:
- * the "MENU" knob to be on A0
- * the RED value to be on A1
- * the GREEN value to come from A2
- * the BLUE value is from A3
- * the "VARIABLE" knob is assigned to pin A7
The NeoPixel ring uses the standard hookup. Power and ground come from the PermaProto rails (with the appropriate capacitor in place).
The sample code expects:
- * the digital data to come from pin 9.
We run the data line through a resistor on the PermaProto board just before the .
(Capacitor and Resistor)
Please read the Uber Guide for NeoPixels for full details. Basically, you need to put the capacitor across the positive and negative lines of the power supply. Place the cap as close to the first NeoPixel as possible. The resistor goes in the data line as close to the first NeoPixel as possible. The Uber Guide explains the why and where in detail, so be sure to read and understand it.
LCD Display and Serial Communication
The LCD display needs power and ground connections plus a serial communications line. The LCD only receives data, it does not send data, so the RX line can be used for other purposes if needed.
The sample code expects:
- * to use the hardware defined pin 1 (one) as the serial transmission (TX) line.
This project used a normally-open momentary switch. Just connect one lead to the reset pin on the board and the other lead to the ground rail. When the button is pushed, the reset pin is pulled to ground and the Arduino resets itself.
If you want to, you can make the USB cable a permanent part of the project.
Step 3: Code
This project uses "Tabs" to help organize the code inside the Arduino IDE. This is really the only unusual coding practice in the entire project. Tabs are not used much, or maybe I just learned about them. But they remind me of techniques and mechanisms used in more sophisticated programming environments.
I use them more as bookmarks in this project. Their main function here is to break the code into chunks so that I can navigate easily without so much scrolling. This has an important added benefit. I am a very lazy programmer, and if I don't think anyone will see my code, then I will avoid scrolling and will slap code snippets into random places until the whole program becomes an unreadable mess. It executes fine, but if I come back a month later I can't even read my own code, much less modify it. Using tabs, my code usually stays more readable because I can quickly get to the tab that contains related code snippets. So the entire program stays better organized. Tabs almost force me to think more modularly.
This also helps when I need to modify the program for use with other components. In this project, all the code for driving the display is in a couple of tabs. It was easy when I ported it to an SPI display. I knew where all the related code was, and it was easy for me to substitute the new code into the program without tracking it down in a single spaghetti tangle of code.
Tabs can be created using the small down-arrow at the upper right of the IDE interface. Note that the load order of the tabs is important, just like a in single-file program.
How To Use
Download all the sample files and place them all in a directory inside you Arduino folder. Call the new folder/directory "Loop_Trainer" so that it matches the name of your main .ino file. Load the Loop_Trainer file, then compile and upload to your hardware.
The code is well commented (some would say over commented), so hopefully even beginners will be able to understand how it works.
Basically, the code reads the values from the potentiometers, maps the values if needed, then passes the value to an animation function. The values are also displayed on the screen. Simple, right? Well it is, don't let the tabbed format confuse things.
- Loop_Trainer: This the main file. It has all the usual initialization, the setup and main loop. The code sets the pin numbers and variable names, loads the NeoPixel library and starts the serial communication. The main loop is very simple, it just calls a function to read the values on the potentiometers and execute the menu.
- LCD_baseCommands: The LCD display used in this project uses start and stop codes to pass it commands. It is simple to understand, but repeating the codes gets tedious and bloats the file. So I created a series of functions so the codes can be called simply. Check out Adafruit's guide for a full list of commands.
- LCD_setup: Now that all the base commands have been turned into functions, we can use them to setup the screen for use. You will need to modify this tab and the LCD_baseCommand tab if you use a different display.
- Menu_functions: This is a simple case statement. Depending on what the mapped value of the menu pot is, we call a function (in the NeoPixel_Functions tab) to animate the NeoPixels. I have left some blank slots for you to populate with your own animations.
- NeoPixel_Functions: This is the fun part. This file contains the actual animation code. These animations are functions called from within the Menu_functions tab. The animations acquire the RGB and variable values from data set by the Read_pots tab. The animations also send data to the display screen using the functions in the LCD_baseCommands tab. When you create your own new animations, just call them from the Menu_functions tab. These are basic animations, but I have left a two-parter and a couple of other oddball routines for you to play with.
- Read_Pots: These functions read the potentiometers and map their values to fit their standard purpose. For example, the menu only needs 10-20 steps, so we map to that value. The RGB value needs to be 0-255. But the "variable" input is used in so many different ways that We send the raw value and map it to the current need while inside the calling function. You can always do a direct analogRead if you want poll a value differently.
IMPORTANT NOTE: Somewhere. somehow, I will have left "stubs" of abandoned experiments and other errors in this sample code. The code runs, but if you find dead-ends, they are probably left over from ports to different displays or from "banks" of animations not intended to be provided in the sample code.
Step 4: Control Interface
There are five potentiometers in the physical control interface. The scavenged case had pre-made holes laid out nearly perfectly for this interface. The slot for the seven-segment display fit the LCD display almost perfectly with room left over for the reset button. And the hole that used to house the all-important snooze button fit the 12 pixel ring perfectly.
- Menu Selection - Upper Left
The value from this potentiometer controls which animation is active.
- Variable. - Lower Left
This knob is used to adjust a value such as speed, amount of fade, randomness etc., whatever you program the value to affect.
- R-G-BColors - Three knobs at top right side
The three knobs across the upper right are used primarily to control the Red, Blue and Green (RGB) color values of the LEDs. (Although I don't demonstrate it in this guide, you can also create a two-step control structure where these buttons set the color in part-one, then control three more values in part-two.)
The project uses two sizes of knobs (one for the menu-select and another larger knob for the variable-adjuster) while leaving three RGB potentiometers bare. This seems to work well for new users. It differentiates the three separate functions by look and feel.
Display and Readout
The display is a standard 16x2 alphanumeric display with an RGB backlight.
The top line usually displays (from left to right)
- * the "Menu Step" aka the selected animation, (ex: m1 or m23)
- * the Red, Green and Blue values in 0-255 format (r255g123b231)
- The sample code puts the display in "left justified" mode. This means that the display expands and contracts based on the values - it could use as few as the first nine slots, or all 16.
The bottom line displays hints and prompts for the user. They should help the user understand how to run the gadget. Usually, this prompt explains now turning the "variable" knob will affect the animation.
In more complex scenarios (not shown in the provided sample code), these rules can be broken and extended. When I program for my own use this is not really an issue. But when other people have used the gadget, I find it very important to maintain a consistent structure to the interface across all animations,
Step 5: Case and Decoration
You can leave the board exposed, put it inside a cardboard box or a Tupperware container and the project will still work great. But I am always trying to find ways to bring our club's coders and crafters closer together. So I tried to generate some interest in decorating the case to make it an entertaining and enticing toy - I failed miserably.
The look started as "weathered-industrial" but trended more towards SteamPunk as time went on. Eventually it became what I lovingly call "Blobby Rococo." I am not happy with the look, but the gadget is so useful I decided to share it anyway.
This case was from an old alarm clock. Originally, I scavenged it for the LED display and the control board. Neither of those ever made it into a finished project, but they were both great learning experiences. Everyone needs to know how to determine the pinout of a four-digit, seven-segment display... fun, fun, fun.
You, however, will need to find a case that appeals to you. That's not too hard though, with so many electronics sent to the landfill every day. In fact, designing an interface is good practice and fitting your interface into.an existing shell is a great exercise.
To-Do Next Time
If I was designing this from scratch I would put the Neopixels on a flat surface with no obstructions. I can usually get a good idea of what the lights will look like with a given material, but having the LEDs stuck in a corner does make it more difficult.
I would also put the NeoPixels flush with the surface. I recessed them too much because I wanted some protection when the lights are at full brightness. But I find that I wish I could put items directly onto the NeoPixels quite often, and since I'm testing diffusers, the blinding light is usually blocked anyway.
Holes and Mountings
Luckily, all the holes and openings on this case were almost perfectly sized. I used a pocketknife to scrape open the holes for the potentiometer a millimeter more, and scraped down one edge of the display opening so the LCD readout fit snugly (it stays put with no screws or glue). Your case might need to be modified more. But if you look around, you are likely to find a case that will work with minimal modifications. Most electronics cases are failry soft plastic, so any rotary tool can drill, grind or sand the openings to size.
I mostly used Instamorph plastic to form any mounting brackets needed. It is simple to work with, non-toxic and very cheap. You could also use hot-glue or Sugru.
I cleaned the surface and hit the top half with some red Krylon Fusion spray paint. I added some industrial yellow and gold metallic accents. But I am finding that the red paint tends to absorb and overpower other colors after a week or two. The gold and yellow are barely visible now.
Ah, the decorations. Let's just say this isn't my best work and leave it at that. You can certainly do better.
I tried to make a lens hood from air-dry clay. I could not get the smooth, commercial look I wanted. So I went in the opposite direction and began pressing gears and brackets into the soft clay to give it that SteamPunk look. It sort of worked, so I painted the hood with metallic acrylic paint.
The rim around the NeoPixel is a plumbing part. It fit and it hid the LEDs to prevent getting blinded when then are at full brightness. I usually remove it when testing materials for their light diffusing properties.
There were even more gears and brackets at one time, but they mercifully started falling off during transport (and a couple of drops to the floor) so I left them. trust ne, no great loss to the design world.
The knobs shown here are from Adafruit. Using two different sizes and leaving the three RGB shafts bare does really help new users remember which potentiometers do what. And they are nice, metal knobs with a luxuriant feel. They make the project feel finished.
Step 6: Using It
Given the amount of time I had spent creating and recreating similar interfaces, I knew a more permanent version like this would be helpful, but I find myself using it more than I imagined and in ways I didn't anticipate.
As I expand my exploration of decorative wearables, I usually test materials for their interaction with light and color by holding them up to the NeoPixels. I can explore a wide range of effects to quickly find a look that works well with that particular material. Cloth, plastics, stones and anything else that is semi-translucent gets tested. By now, I have "banks" of favorite animations that I can load and test.
It has also turned out to be a great teaching tool. I can load a series of slightly different loops and use them to demonstrate how minor changes in the code can yield a totally different animation - or how totally different coding techniques can provide the exact same visual output.
Plus, it's just a fun toy for anyone to play with. So have fun making it and making it your own. Let me know if you create anything new with it.
Thanks for reading, and enjoy.