3D Printed Arc Reactor

Last year I designed a 3D-printable Arc reactor prop, controlled by an Adafruit Gemma microcontroller and using a NeoPixel Ring for illumination. I shared this on Thingiverse at the time – now I’m finally following up with the details.

Introduction

I originally intended to publish a wiring diagram & assembly guide along with the files on Thingiverse, but as with many projects that didn’t happen.

I’ve had a few requests for info like that since then – so, today I plan to explain the inner workings of my Arc reactor prop for those that wish to replicate it.

Note that when you’re doing the wiring, you have to take care to wire things so that they’ll fit inside the printed Arc Reactor – make wires the right length, route some wires around printed parts, and so on. I recommend getting the reactor printed first, then sitting down with the components and printed parts while going through this.

Hardware

Let’s start with a list of components:

Here’s a Fritzing diagram of roughly how the wiring goes together:

gemmaArcReactor

Because not all the parts I used are in the Fritzing library, a few of the parts in the above image are not exactly right – the LiPo charger is bigger than the one I used, and the single NeoPixel is a Flora instead of a PCB version (although the Flora NeoPixel might work, I didn’t try it).

Here’s a schematic showing how Gemma connects to the two NeoPixel modules:

gemmaArcReactor_schem

I can’t do a diagram for the battery/charger/Gemma, because Fritzing doesn’t have power connections on the Gemma board or the right LiPo charger – so here’s a rundown on how the battery is wired in.

The JST plug on the battery should plug directly into the LiPo charger board. Check the polarity first, as it’s not guaranteed that the battery will have the JST plug the same way around as the charger.

The LiPo charger should have pads to access the battery – on the board I used (linked above), these were marked BAT and GND. These pads should be a direct pass through to your battery, which means there will be 4.2-3.7V across them depending on how charged your battery is.

Now, we need to connect these wires to the JST battery-in connection on the Gemma board. I soldered a spare JST plug onto some wires and connected it to BAT and GND, so that I could plug it directly into the board. Gemma doesn’t have any pads for battery input, so the only other option would be to try and solder onto the pins inside the JST connector, or the leads where the JST plug is soldered onto the Gemma board.

Halfway through the positive lead going from the charger board to Gemma, install the power switch. If you’re using a switch with 3 legs on the bottom (like I did), solder the wire to two adjacent legs and leave the furthest leg free.

This switch will let you turn the arc-reactor on and off, while still being able to charge it in either state.

Firmware

Now that everything there is done, it’s time to test things! Here’s a quick Arduino test sketch that should light up all the NeoPixels:

#include <Adafruit_NeoPixel.h>

#define PIN 1

Adafruit_NeoPixel strip = Adafruit_NeoPixel(25, PIN, NEO_GRB + NEO_KHZ800);


void setup() {
 strip.begin();
 strip.show(); // Initialize all pixels to 'off'
}

void loop() {
 // Some example procedures showing how to display to the pixels:
 colorWipe(strip.Color(255, 0, 0), 50); // Red
 colorWipe(strip.Color(0, 255, 0), 50); // Green
 colorWipe(strip.Color(0, 0, 255), 50); // Blue
 // Send a theater pixel chase in...
 theaterChase(strip.Color(127, 127, 127), 50); // White
 theaterChase(strip.Color(127, 0, 0), 50); // Red
 theaterChase(strip.Color( 0, 0, 127), 50); // Blue

 rainbow(20);
 rainbowCycle(20);
 theaterChaseRainbow(50);
}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
 for(uint16_t i=0; i<strip.numPixels(); i++) {
 strip.setPixelColor(i, c);
 strip.show();
 delay(wait);
 }
}

void rainbow(uint8_t wait) {
 uint16_t i, j;

 for(j=0; j<256; j++) {
 for(i=0; i<strip.numPixels(); i++) {
 strip.setPixelColor(i, Wheel((i+j) & 255));
 }
 strip.show();
 delay(wait);
 }
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
 uint16_t i, j;

 for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
 for(i=0; i< strip.numPixels(); i++) {
 strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
 }
 strip.show();
 delay(wait);
 }
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
 for (int j=0; j<10; j++) { //do 10 cycles of chasing
 for (int q=0; q < 3; q++) {
 for (int i=0; i < strip.numPixels(); i=i+3) {
 strip.setPixelColor(i+q, c); //turn every third pixel on
 }
 strip.show();
 
 delay(wait);
 
 for (int i=0; i < strip.numPixels(); i=i+3) {
 strip.setPixelColor(i+q, 0); //turn every third pixel off
 }
 }
 }
}

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
 for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel
 for (int q=0; q < 3; q++) {
 for (int i=0; i < strip.numPixels(); i=i+3) {
 strip.setPixelColor(i+q, Wheel( (i+j) % 255)); //turn every third pixel on
 }
 strip.show();
 
 delay(wait);
 
 for (int i=0; i < strip.numPixels(); i=i+3) {
 strip.setPixelColor(i+q, 0); //turn every third pixel off
 }
 }
 }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
 WheelPos = 255 - WheelPos;
 if(WheelPos < 85) {
 return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
 } else if(WheelPos < 170) {
 WheelPos -= 85;
 return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
 } else {
 WheelPos -= 170;
 return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
 }
}

This example is Adafruits “Strand Test” example, with the pin and number of NeoPixels preset to match the Arc Reactor design. Put that code in your Arduino IDE, make sure to set Gemma as the board and upload it. You should see both the NeoPixel ring and the single NeoPixel light up a dazzling variety of colours!

I’ve put together a quick sketch that should be a bit more arc-reactor appropriate (untested):

//Basic demo sketch showing a few basic 'Arc Reactor Appropriate' animations
//Chris Barr, 2015

#include <Adafruit_NeoPixel.h>

#define PIN 1
#define NUM_PIXELS 25

int mode = 1; //change this number to see different effects
int num_modes = 3;
boolean automatically_change_mode = true; //disable this to lock to the one effect
unsigned long last_changed_mode_time = 0;
unsigned long effect_duration = 10000; //when changing automatically, each effect lasts for minimum 10s

int brightness = 200;
int mean_brightness = 200;
int flicker_range = 4;
int spin_rate = 50;
int fade_rate = 5;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIXELS, PIN, NEO_GRB + NEO_KHZ800);

uint32_t c_blue = strip.Color(10,10,255);

void setup() {
 strip.begin();
 strip.show(); // Initialize all pixels to 'off'
}

void loop() {
 
 if(mode==1)
 {
 //sets all NeoPixels to be blue
 setAll(c_blue);
 strip.show();
 }
 else if(mode==2)
 {
 //sets all NeoPixels to be blue with flicker
 brightness += random(flicker_range)-round(flicker_range/2);
 brightness = constrain(brightness, min(mean_brightness + flicker_range*5, 255), max(mean_brightness - flicker_range*5,0));
 setAll(strip.Color(10, 10, brightness));
 strip.show();
 }
 else if(mode==3)
 {
 //swirls around outer ring
 for(int i = 0; i < 24; i ++)
 {
 //fade change
 for(int j = 0; j < 50; j++)
 {
 //set previous pixel back to being dim
 if(i>0)
 strip.setPixelColor(i-1,strip.Color(10,10,200-j));
 else
 strip.setPixelColor(24,strip.Color(10,10,200-j));
 //set current pixel to be brighter
 strip.setPixelColor(i,strip.Color(10,10,150+j));
 
 //set center pixel to constant colour
 strip.setPixelColor(25,c_blue);
 
 //update changes
 strip.show();
 
 //wait before repeating
 delay(fade_rate);
 }
 delay(spin_rate);
 }
 
 }
 
 if(automatically_change_mode)
 {
 if(millis()-last_changed_mode_time > effect_duration)
 {
 last_changed_mode_time = millis();
 mode++;
 if(mode>num_modes)
 mode = 1;
 }
 }
 
}

void setAll(uint32_t color)
{
 for(int i = 0; i < NUM_PIXELS; i++)
 {
 strip.setPixelColor(i,color);
 }
}


That should be enough to get you up and running! If you have any questions, feel free to leave a comment below asking.

4 comments

    1. Hi Iris! I didn’t keep track precisely, because I already had some of the components on hand – I’d say less than USD 50 for everything excluding the printed parts.

  1. i am a complete newbie to this and having trouble with the code is there a cut and paste version of the code so all i need to do is copy and paste

    1. Hi David! I’ve added two code examples – one that is just a simple test, and one with an ‘arc reactor’-style effect. Assuming all wiring is the same as in the post, they should be cut-and-paste ready!

Comments are closed.