Introduction: 3D Printed NeoPixel Ring Butterfly With Tinkercad
Combine the rainbow lights of NeoPixels with 3D printing to program, design, and assemble a groovy, illuminated butterfly!
This is a great project to dive into basic electronics and programming using Arduino and NeoPixels, and to combine electronics with 3D design using Tinkercad and 3D printing.
This project uses the following electronic parts:
- Arduino Uno with USB cable
- 24 NeoPixel Ring
- Jumper wires (you only need 3 from this set)
We've also created wishlists on Sparkfun and Adafruit for these components.
You'll also need the following tools:
- Soldering iron and solder (also available from Adafruit and Sparkfun)
- Wire strippers (also available from Adafruit and Sparkfun)
- Wire cutters/snips (also available from Adafruit and Sparkfun)
- Helping hands (optional but handy for holding your parts in place when you solder - also available from Adafruit and Sparkfun)
For more info on getting started and leveling up with 3D printing, check out one of the free Instructables classes on 3D printing. This is an intermediate level Arduino project, so if you're an ultra-beginner or a bit rusty, brush up with the free Instructables Arduino Class or the earlier Arduino Tinkercad lessons.
First, you'll first learn how NeoPixels work by programming a NeoPixel ring to light up every color of the rainbow in the Tinkercad Circuit simulator:
After that, you'll customize a 3D butterfly design in Tinkercad that attaches to a special holder for securing your design and a Neopixel ring to an Arduino Uno.
Finally, you'll assemble your circuit and 3D printed parts to create a butterfly light show.
Let's get started!
This lesson was written in collaboration with Tiffany Tseng and Erik Nauman
Step 1: What's a NeoPixel Ring?
You may have experimented with RGB LEDs before. Each RGB LED has 3 LEDs (one red, one green, and one blue) that can be mixed together in different brightnesses to create millions of possible colors. Well, NeoPixels are "smart" RGB LEDs, controllable easily using few Arduino pins and a little more complex code than for plain LEDs.
A NeoPixel ring is a ring-shaped circuit board with NeoPixels placed around it.
When programming in Arduino, we use values from 0-255 to represent the brightness of each red, green, and blue LED. As an example, this is the Arduino code for red:
Color(255, 0, 0);
The syntax for specifying color is Color(RedValue, GreenValue, BlueValue). So, with a RedValue of 255, and 0 for both the GreenValue and BlueValue, the color specified is pure bright red.
Step 2: Open Tinkercad Circuits
We'll begin by learning about programming a NeoPixel using Circuits on Tinkercad.
Tinkercad Circuits is a free website for building and simulating circuits. To get started, head over to the Tinkercad site and log in or create an account if you're new.
One you've logged in, start building in Circuits by clicking on the Circuits category on your dashboard and then click the "Create New Circuit" button.
Step 3: Create a New Circuit With an Arduino Uno and NeoPixel Ring
To build this simulated circuit, the only two components you will need are an Arduino Uno and a 24-LED NeoPixel ring.
Find the Arduino Uno under basic components and drag it out into the editor.
Search for "NeoPixel Ring 24" in the search box and drag out the NeoPixel Ring 24 component into the editor.
The 5V pin on the Arduino is the pin that provides a positive voltage charge to the NeoPixel ring. The GND pin on the Arduino is the ground pin, or the negative charge. Pin 9 on the Arduino will connect to the IN pin on the far side of the NeoPixel ring. This “data” pin will carry programming instructions to the NeoPixel ring, so it knows which pixel to light up what color.
You can create a wire in Tinkercad Circuits by clicking on a pin of a component and clicking again on the pin you want to connect to. Hovering over pins on a component will reveal the pin name. A handy tip is that after placing a wire, you can double clicking anywhere on the wire to create a bend point. Clicking and dragging bend points lets you shape you wire, which keeps your circuit design nice and tidy.
Connect the 5V pin on the Arduino (located under the POWER section of the Arduino) to the PWR pin on the NeoPixel ring (located by default in the top left of the NeoPixel).
Change the color of the wire to red in the Color dropdown or by hitting 2 on your keyboard.
Connect the GND pin on the Arduino to the G pin on the NeoPixel ring. Change the color of this wire to black.
Connect pin 9 on the Arduino to the IN pin on the NeoPixel ring. Change its color to green.
To recap, your circuit should now have the following connections:
- Arduino 5V pin to the NeoPixel ring PWR pin
- Arduino ground (GND) pin to the NeoPixel ring G pin
- Arduino pin 9 to the NeoPixel ring IN pin
In case you're curious, you might have noticed that the NeoPixel ring also has an OUT pin. The OUT pin is for chaining together multiple NeoPixel components. With the data OUT pin of one NeoPixel component connected to the data IN pin of another, you can control multiple NeoPixel components with a single Data IN connection—pretty cool!
Step 4: Start Coding: Add the NeoPixel Library
Now let's get started with programming your Arduino to control the NeoPixel LEDs!
Here's the whole starter program, so you can easily copy and paste into your own Circuits simulation. We'll go over each part in detail:
#include <Adafruit_NeoPixel.h> #define PIN 9 #define NUMPIXELS 24 int delayval = 50; int currentColor = 0; Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); void setup() { pixels.begin(); // This initializes the NeoPixel library. pixels.setBrightness(100); // 100/255 brightness (about 40%) pixels.show(); // Initialize all pixels to 'off' } void loop() { pixels.setPixelColor(0, pixels.Color(0,150,0)); pixels.show(); }
First, we'll add the NeoPixel library, which opens up a new set of commands we for controlling our NeoPixel ring.
Click the "Code" button to open the code editor.
Click on the dropdown that says "Blocks" to switch the mode to "Text". A warning will appear, telling you the blocks program will be deleted. Click "Continue".
Remove any of the code leftover in the setup()
and loop()
functions.
Add the following to the first line in the editor (copy/paste or type it in):
#include <Adafruit_NeoPixel.h>
You can also add this include statement by clicking on the Library button, which is shaped like a paper file folder drawer, and clicking Include for the NeoPixel library. Note that there are many other libraries you can add to your Tinkercad Circuit projects.
Step 5: Writing the Code: NeoPixel Basics
Next, we'll add a few variables that won't change during the course of the program, also know as constants. Add these constants right below the include statement you added in the previous step.
#define PIN 9 #define NUMPIXELS 24
Here, our first constant's name is PIN, and its value is 9, representing the pin number connected to the data IN on the NeoPixel ring. The second constant is named NUMPIXELS and its value is 24, the number of NeoPixels in our ring.
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
In order to use the NeoPixel library to control your pixels, you need to first create a NeoPixel object in your code. Add this line next. This creates an object called “pixels” that will be used to represent our NeoPixel ring when we use functions from the NeoPixel library.
Notice that the constants you created for the data pin (PIN
) and number of NeoPixels in the ring (NUMPIXELS
) are used to create the pixels object, so the object knows how many LEDs are connected and to which pin.
Add the following line underneath your pixel object definition, before the setup()
:
int delayval = 100; int currentColor = 0;
Add in two variable declarations before the code's setup()
. The delay value (delayval
) of 100 refers to milliseconds. This variable will be used to determine when we change the next NeoPixel's color.
The currentColor
variable starts counting at 0. This value will change throughout the program refer to different colors of the rainbow to send to the NeoPixels. Computer programs usually start counting things from 0.
void setup() { pixels.begin(); // This initializes the NeoPixel library. pixels.setBrightness(100); // 100/255 brightness (about 40%) pixels.show(); // Initialize all pixels to 'off' }
Inside the setup()
, we will initialize our NeoPixel object with pixels.begin();
. This statement uses a syntax that may be new to you, called “dot notation.” We can’t just say begin()
—the compiler needs to know what should begin. We created the pixels object so we could tell the compiler we want the NeoPixel object "pixel" to begin.
By default, the NeoPixels will be full brightness, which is really, uncomfortably bright. So let's take the option to reduce the overall brightness by using setBrightness()
, which takes a value from 0-255.
pixels.show();
is called whenever you want to update the pixels to the latest state, so we'll call it once in the setup()
to make sure they're all off.
void loop() { pixels.setPixelColor(0, pixels.Color(0,150,0)); pixels.show(); }
Now that we've done all the setup, we're ready to start assigning colors to the NeoPixels in the loop()
! First we'll light up one NeoPixel. We'll use dot notation again to set the first NeoPixel on the ring to the color green, then a second statement to push the color to the ring and make it show.
The function setPixelColor()
takes two arguments, separated by a comma. The first is the index, or address, of the NeoPixel you want to light up. Remember that computers start counting from zero, so the number 0 refers to the first NeoPixel, the number 4 refers to the 5th Neopixel, etc.
The argument in setPixelColor()
is the color you want it to set the NeoPixel. Notice how we set the color with Color(0, 150, 0)
. The three arguments (0, 150, and 0) describe how much red, green, and blue to use, each in a range from 0-255.
pixels.show()
is needed to update the NeoPixels to display the latest commands/colors.
Let’s try out what we have so far. Click the Start Simulation button and watch your NeoPixel light up!
Now try lighting up another pixel in the ring by by changing the first argument in setPixelColor. Can you light up the last LED in our 24-pixel ring?
Try modifying the color by adjusting the second argument in setPixelColor. Remember, the color is set by the red, green, and blue parameters you provide, each from a scale from 0 to 255.
Step 6: Writing the Code: Ramping Up to Rainbow
You now know how to light up a single pixel in the ring, but what if we want the colors to animate around the ring instead? A for loop will let us do exactly that by lighting up each NeoPixel one at a time, one after one another. For another basic introduction to for loops with plain LEDs, check out our lesson about fading LEDs with for loops.
Let's look at this example of a for loop and break down each part:
for(int i=0; i<NUMPIXELS; i++){ }
The three parts, separated by semi-colons, define what number to start counting from (int i=0
), when to stop (i < NUMPIXELS
), and what number to count by (i++
). In the for loop above, we start counting at 0, stop as soon as we reach the NUMPIXELS
value, and count up by one until we get there (i++
is shorthand for “add 1 each time”).
Notice that we created a variable i
that is used as a counter for each time we go through the for loop. We can use this variable within our for loop to reference where we are in the loop—for example, as a way to keep track of which NeoPixel we are lighting up. Everything contained by the for loop's curly braces { }
will be executed each time the program goes through the loop.
Remove the statements you had to light up a single NeoPixel (everything inside the loop()
), and replace them with the following loop()
content so it now looks like this:
void loop() { for(int i=0; i<NUMPIXELS; i++){ pixels.setPixelColor(i, pixels.Color(0,150,0)); pixels.show(); delay(delayval); } }
Notice that setPixelColor(0, pixels.Color(0,150,0))
has changed to setPixelColor(i, pixels.Color(0,150,0))
?. That is because as the variable i
adds 1 each repeat, the NeoPixel we are lighting up within the ring is changing.
Click Start Simulation to run your code again, and watch the light step around the NeoPixel ring! Note that once it makes it all the way around, the ring will remain green. Let's remedy that...
Our NeoPixel ring will look even better with more colors, but to change colors while lighting up each NeoPixel, we'll first need to store our color values in variables. Our colors can’t be stored in simple integers because they are made up of three values (one for each red, green, and blue). We will store them in 32-bit variables to hold that information.
uint32_t red = pixels.Color(255, 0, 0); //red
Add this color right above your for loop()
, and change your second setPixelColor argument to red. Your loop()
should now look like this (feel free to copy and paste):
void loop() { uint32_t red = pixels.Color(255, 0, 0); //red for(int i=0; i<NUMPIXELS; i++){ pixels.setPixelColor(i, red); pixels.show(); delay(delayval); } }
Click Start Simulation to check that your NeoPixels now light up red. Similar to before, once each LED is set to red, the entire ring will stay red.
Let’s now add all the colors of the rainbow! Add eight more colors to the list under the red color variable and before your for loop.
uint32_t orange = pixels.Color(255, 100, 10); //orange uint32_t yellow = pixels.Color(255, 255, 0); //yellow uint32_t green = pixels.Color(0, 255, 0);//green uint32_t dkgreen = pixels.Color(0, 115, 0);//dark green uint32_t cyan = pixels.Color(0, 255, 255); //cyan uint32_t blue = pixels.Color(0, 0, 255); //blue uint32_t magenta = pixels.Color(255, 0, 255); //magenta uint32_t purple = pixels.Color(50, 0, 50); //purple
To make it easier to cycle through our rainbow colors, let's store the variables you just defined into an array. An array is a collection of variables, like students in a line. The array keeps the variables in a certain order so they don’t get mixed up.
Remember that variable currentColor
we created earlier on? We'll use it here to cycle through each color of our array.
Underneath your definition for the color purple, add the following line to create an array of rainbow colors:
uint32_t colors [9] = {red, orange, yellow, green, dkgreen, cyan, blue, magenta, purple};
The first part of the statement (uint32_t
) states the type of the variables in the array.
The name colors [9]
creates an array named colors containing nine objects (colors) in it.
Now in your for loop, change the color we use in setPixelColor
to refer to the color array:
pixels.setPixelColor(i, colors[currentColor]);
We want to change the color of each pixel in the ring, so we'll need to change the currentColor each time we go through the for loop. After the delay statement, within the for loop, increase the currentColor variable by one:
currentColor++;
Click Start Simulation. You should see rainbow colors moving part of the way around the ring!
Did you notice there is a problem? The colors stop after the first rainbow without continuing through the entire ring.
For each new light on the ring, the variable currentColor
adds one so the next color from the colors array can be displayed. But when currentColor
gets to 9 the array has ended but the counting keeps going! There is no color to display. Remember, the array starts counting at 0 so the 9th color is actually number 8 in the array
We will use an if/then condition to make the number go back to 0 when it reaches 9.
After the currentColor++;
statement, add this condition, called a test:
if (currentColor >= 9) currentColor = 0;
This states that if the value of currentColor
is greater than or equal to 9, it should reset to 0. Then the colors can start their cycle over again and keep going around the ring.
void loop() { uint32_t red = pixels.Color(255, 0, 0); //red uint32_t orange = pixels.Color(255, 100, 10); //orange uint32_t yellow = pixels.Color(255, 255, 0); //yellow uint32_t green = pixels.Color(0, 255, 0);//green uint32_t dkgreen = pixels.Color(0, 115, 0);//dark green uint32_t cyan = pixels.Color(0, 255, 255); //cyan uint32_t blue = pixels.Color(0, 0, 255); //blue uint32_t magenta = pixels.Color(255, 0, 255); //magenta uint32_t purple = pixels.Color(50, 0, 50); //purple //put the colors in an array uint32_t colors [9] = {red, orange, yellow, green, dkgreen, cyan, blue, magenta, purple}; for (int i = 0; i < NUMPIXELS; i++) { pixels.setPixelColor(i, colors[currentColor]); delay(delayval); pixels.show(); currentColor++; if (currentColor >= 9) currentColor = 0; } }
Click Start Simulation to test your program and enjoy your animating rainbow!
Step 7: Download Your Code From Tinkercad Circuits
To program your physical Arduino Uno, you'll need to bring your code into the Arduino IDE software— here's how.
With the Code Editor open, click the button shaped like a downward facing arrow, which will export a file that you can open in your Arduino software. You can also copy and paste the code into a blank Arduino program window.
Step 8: Duplicate and Tinker
Now we're ready to create a 3D design that incorporates our Arduino and NeoPixel 24 ring. Here's a design you can customize that contains all the parts you'll need.
You can find this design on Tinkercad, where you can click the "Duplicate and Tinker" button to create a copy you can edit. If you're not logged in, you will see a "Sign up to Copy" button instead of "Duplicate and Tinker". We recommend you log in first so you can easily remix the project!
There are a few different parts in this design:
- Arduino Uno
- NeoPixel 24 ring (in yellow)
- Butterfly shape
- Holder (in red) used to attach your butterfly and NeoPixel ring easily to the Arduino.
- "Cutout" (the transparent hole shape) which is used to create a feature at the base of the butterfly so that the part can snap onto the holder when 3D printed.
If you zoom in on the holder, you'll see a few key design elements. First, there are three holes that you'll use to wire the NeoPixel ring to the Arduino. You'll also find a snap at the center of the holder. You'll attach your butterfly to this snap with the help of the cutout.
Step 9: Prepare the Parts
In this step, we'll align the holder and cutout before grouping our cutout with the butterfly design.
Select both the cutout and the holder (shift-click or draw a box containing both) and click the Align button. Center both on the workplane by clicking on the two middle dots along the workplane.
Let's make the Butterfly transparent to make it easier to see how the cutout and circuit assembly fit inside. Select the Butterfly, click on the Solid color in the inspector, and check the transparent box.
At this stage, we're going to hide the cutout so we can better align the butterfly with the Rainbow Glow holder. Don't worry—we'll bring it back in just a bit! Click on the Cutout and click the Hide button in the inspector (it looks like a lightbulb).
Step 10: Apply the Cutout
Now we're ready to position the butterfly and apply the cutout to it, adding a socket to its base. We'll use a workplane to make sure that the base of the butterfly is aligned with the holder.
Click the Workplane button or press "W" on your keyboard to begin defining a new workplane. Place the workplane on the flat surface of the holder in which the snap sits upon. You'll notice now that there is an orange plane placed at this location.
Select the Butterfly and press "D" on your keyboard to drop the Butterfly on your newly-created workplane. This ensures that the Butterfly is placed at the right height.
Click on the "Show All" button in the toolbar to reveal the Cutout.
Click on the Top side of the View Cube to make it easier to position the Butterfly over the cutout.
Now drag the butterfly so that its cylinder base is centered with the socket of the cutout.
Select the butterfly and the Cutout and click the Group button (or press "ctrl+G" on your keyboard) to group them together and add the socket to the Butterfly base. Do not select the circuit assembly at this step—just the Cutout!
Rotate the camera to check how the cutout has created a cavity in the Butterfly so it can fit onto the snap of the Rainbow Glow holder.
Feel free to modify the design of the butterfly to add any additional details if you'd like before printing.
Step 11: 3D Print Your Design
When exporting your circuit assembly, you will want to export it separately from your design. In this step, we'll export the holder and butterfly separately. Select one of the shapes and click the Export button. Ensure that "The selected shape" is selected and click .STL to export the circuit assembly for 3D printing. Exporting the holder circuit assembly will only export the 3D-printable components (the holder) in the assembly. The electronic components will not be included. Repeat to export the other part. Print both files on your 3D printer of choice! If you're new to 3D printing, check out Jonathan Odom's excellent free Instructables Easy 3D Printing Class to get you up to speed.
For the holder, we recommend printing right-side up with support material at 100% infill. This will ensure that it fits well over the Arduino. Use flush snips to trim away the support material.
For the butterfly, we recommend printing the part in translucent or white filament and upside-down to eliminate the need for support material, also at 100% infill. However even if you don't have clear or white plastic to print with, the light will shine through the details on the butterfly wings.
Step 12: Gather Your Components and Tools
After 3D printing your parts, gather all your additional parts and tools to assembly your Rainbow Glow butterfly. As a reminder, you'll want to have these parts on hand:
- Arduino Uno with USB cable
- 24 NeoPixel Ring
- Jumper wires (you only need 3 from this set)
We've also created wishlists on Sparkfun and Adafruit for these components.
You'll also need the following tools:
- Soldering iron and solder (also available from Adafruit and Sparkfun)
- Wire strippers (also available from Adafruit and Sparkfun)
- Wire cutters/snips (also available from Adafruit and Sparkfun)
- Helping hands (optional but handy for holding your parts in place when you solder - also available from Adafruit and Sparkfun)
Step 13: Assemble the Sandwich
The first step towards putting together your circuit and 3D printing sandwich is to add the holder to the top of the Arduino. The holder should fit snugly around the black headers of the Arduino Uno, where you usually plug in wires.
The NeoPixel Ring should fit around the holder with the PWR and GND pins of the NeoPixel facing the bottom of the holder, close to the + and - indicators on the holder.
Step 14: Plug in Jumpers
Notice how your holder has three holes for connecting the NeoPixel ring to the Arduino. On one side, there are two holes for connecting power and ground, and on the other side is a hole for a data connection to Arduino pin 9. In this step, you'll add jumper wires to each of these holes that will then be soldered to the NeoPixel ring.
Wire colors can be useful for distinguishing between different pins. We recommend you use one red jumper wire for the power connection, one black jumper wire for the ground connection, and one colored wire (anything other than red!) for your data connection. In this example, we'll use a green jumper for our data connection.
Insert one end of a red jumper wire into the + hole of the holder. Make sure it's fully inserted so that it makes a connection with the Arduino Uno 5V pin.
Insert one end of a black jumper wire into the - hole of the holder. Make sure it's fully inserted so that it makes a connection with the GND (Ground) pin of the Arduino.
Take the last jumper cable (green or color of your choice) and insert one end into the 9 hole of the holder. Make sure it's fully inserted so that it makes a connection with pin 9 of the Arduino.
Step 15: Strip the Wire Ends
In order to solder to our Neopixel ring, we'll snip and strip one end of each of the jumper cables.
Using wire cutters or the cutting part of the wire strippers, snip the ends of each of the jumper cables (the loose end that is currently not connected to anything) to remove the plastic end.
Now use the wire strippers to remove the insulation from the exposed end of each of the jumper cables. These are the ends that we'll solder directly to the contacts on NeoPixel ring.
Step 16: Solder Your Connections
Now let's connect the wires to the NeoPixel pins. Twist and tin the wires at the exposed ends of the jumper to make it easier to insert into the NeoPixel holes. Learn more about soldering in Randy's free Instructables Electronics Class.
Take the stripped and tinned and of the red jumper wire (connected to 5V pin of the Arduino) and thread it through a hole marked PWR the NeoPixel ring. Thread the wire through the hole from top to bottom. After threading the wire through the hole, bend the end to help hold the wire in place.
Repeat with the black jumper wire (connected to the GND pin of the Arduino): thread it through one of the holes marked G on the NeoPixel ring, inserting the wire from the top of the NeoPixel ring to the bottom, bending the end after inserting.
Repeat the same process for the last jumper wire (connected to Arduino pin 9) to wire it to the hole marked IN on the NeoPixel ring.
Next up, use a soldering iron to solder strong connections between the jumper cables and the NeoPixel ring! Soldering irons can get very hot, so make sure you learn how to use a soldering iron safely before proceeding!
Flip the entire assembly upside down and use the helping hand tool to hold it in place as you solder each wire to the corresponding NeoPixel pin. After the joints cool, trim the excess wire with your flush wire snips.
Step 17: Program the Arduino
Now we're ready to program the Arduino with the rainbow code! Remember the .ino file you exported from the Circuits editor? We'll be using that here to upload the code you created onto your Arduino.
Open up the Arduino IDE on your computer. (Follow the instructions on this page if you haven't downloaded the software before).
You'll need to install the NeoPixel library if you don't already have it. Go to Sketch > Include Library > Manage Libraries... From there, search for "Adafruit NeoPixel" and click the Install button. Once it's installed, the library will now be available to use. For more detailed instruction on installing libraries using the Arduino Library Manager, check out this lesson of the free Instructables Arduino Class.
Open up your Arduino sketch (check your downloads folder for a file ending in .ino).
Plug in the Arduino to your computer using the USB cable.
Under Tools > Board, select the Arduino/Genuino Uno from the list.
Under Tools > Port, select the port for your Arduino.
Click the Upload button (the right arrow) to upload your code to your Arduino. If you've wired everything successfully, your NeoPixel should now light up!
You may need to debug your circuit if it is not lighting up as you expected. Double check that your jumper cables are fully connected to the Arduino and that you have strong solder connections to the NeoPixel ring.
Step 18: Attach the Butterfly and Enjoy!
We can finally attach the Butterfly to our holder! Your butterfly should snap directly to the holder. Press the butterfly lightly into place!
Congratulations—you've built a solid foundation in programming for NeoPixels, solder connections, and construct a 3D design with a beautiful rainbow glow! Try using the cutout from your Tinkercad 3D design to create a different model to attach to the NeoPixel holder.
If you make this project, post an "I made it" below to share your design!