Christian Amato Iteration Assignment


For this assignment, I was inspired by Emilie’s idea that she was going to make a lit-up acrylic sign in layers using neo-pixels and a 3D base. I decided I wanted to go one step further and add an ultrasonic sensor to the front of the base to light up the sign based upon the distance away from you.

This was my nametag, to begin with, and from there I decided I wanted to display the information in sequence, with my hobbies at the front, my information in the middle and my name at the back.

I also kept the same original bear, as that’s my favorite animal but I made it much larger, to approximately 4.5 inches to stay within the realm of the 3D printer base.

This was the overall design I created through Tinkercad with my measurements to scale.

But some of my measurements were not correct and were actually in millimeters instead of centimeters, which led me to have holes that were too small to hold the acrylic, and a cavity that was too narrow to house the ultrasonic sensor and the Arduino.

As you can tell, the dimensions for the acrylic cut-outs were way too small which could have been a big problem if I had not had access to a Dremel to widen the holes.

Thankfully, even with scaling issues, the Neopixel cavity was still wide enough to house the pixels and the perfect length to carry four pixels without any hanging off the edges. This took 8.5 hours to print.

At first, I decided that I wanted to drill out the holes for the Neopixels, but the drill bit and the plastic combination was making it extremely difficult to make consistent cuts without falling into a previous hole.

I have used a Dremel in the past and really did not want to use it, but it was my only option at that point. The Dremel’s friction heated the plastic so hot that I was able to rip out the melted strands of plastic with the needle-nose pliers. It was arduous and honestly a huge waste of my time because it could have so easily been avoided with proper measurements

By widening the holes for the acrylic, it also allowed for larger amounts of light to illuminate the acrylic pieces, which was overall a great thing.

Next, I used a soldering iron and soldered the Neopixels in series. I thought it would be generally easy to do but soldering with such small contacts my first time took a ton of trial and error.

After a failed first attempt after wiring them from the wrong side of the arrow, Brandon generously helped me rewire from the front side.

From that point, I wired up the ultrasonic sensor by drilling two holes in the front, along with the Neopixels and as you can see from the picture, the housing was very snug.

This is how it looked without any illumination.

I think it could have looked much cleaner without the hot glue, but it was necessary to keep it sturdy.

Here is the video of the Neopixels in action without the ultrasonic sensor. I really thought this looked a lot better than the plain colors that I found on the ultrasonic sensor.

Then, I also decided I wanted to use the Ultrasonic sensor to trigger the lights.


I thought this project really used a culmination of all the skills I have developed over this course. I utilized the knowledge I had from the 3D printing unit to create a 3D model that would serve as the base for the entire project using Tinkercad. From there I expanded my knowledge of the Arduino and the code that would end up controlling the entire device. I used the laser cutter again, learned what Neopixels are and the practically unlimited potential for different use. I honed my soldering skills and understood the danger behind lead poisoning. I utilized the drill and the Dremel to cut the housing unit to larger specs. I think this project was great because it allowed me to really use a wide array of devices and in the end it actually functioned.

What went well?

I think the fact that Adafruit has a large array of test codes for Neopixels aided in the overall aesthetic of the design. The coincidence that I was using white 3D printing plastic was also a huge surprise to see how the Neopixels lit up the honeycomb designs on the inside. I thought it really looked great at the end. I think the soldering took a lot of patience but was worth it when it worked on the second try. Brandon was very helpful in showing me how to properly solder, and talking about the importance of cleaning the solder tip to make the solder go down more smoothly.

What could I have done differently?

I think the 3D printing of the base was the hardest part of the project. From the beginning, the dimensions were really not right, and it forced me to rip it apart and use a Dremel to try and accommodate the larger components. I got really lucky with the base cavities somehow being the exact right length for the Arduino and the Neopixels being the exact width to fit in the cavities. But as you can see the base is not flat at all. Its curved on all sides and I noticed this after only 10 minutes of printing. I should have put something that would stick all the plastic to the base of the forge so that it would have been nice and neat. My number one takeaway from this project is to measure twice and cut once. Because of this, I bought a digital caliper for use in my future projects!

Arduino Code-

// Turning NeoPixels on and off using a HC-SRO4 Ping Sensor


This sketch reads a HC-SR04 ultrasonic rangefinder and returns the

distance to the closest object in range. To do this, it sends a pulse

to the sensor to initiate a reading, then listens for a pulse

to return. The length of the returning pulse is proportional to

the distance of the object from the sensor.

The Arduino then takes this information and illuminates a strip of
NeoPixel’s based on the distance of the object from the sensor.

This code was developed partially from Ping))) code found in the public domain
written by David A. Mellis, and adapted to the HC-SRO4 by Tautvidas Sipavicius,
while other portions were written by Charles Gantt and Curtis Gauger from

//Tell the Arduino IDE to include the FastLED library
#include <FastLED.h>

//Setup the variables for the HC-SR04
const int trigPin = 8;
const int echoPin = 7;

//Setup the variables for the NeoPixel Strip
#define NUM_LEDS 12 // How many leds in your strip?
#define DATA_PIN 6 // What pin is the NeoPixel’s data line connected to?
CRGB leds[NUM_LEDS]; // Define the array of leds

void setup() {
// initialize serial communication:

void loop()
// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
long duration, inches, cm;

// The sensor is triggered by a HIGH pulse of 10 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
pinMode(trigPin, OUTPUT);
digitalWrite(trigPin, LOW);
digitalWrite(trigPin, HIGH);
digitalWrite(trigPin, LOW);

// Read the signal from the sensor: a HIGH pulse whose
// duration is the time (in microseconds) from the sending
// of the ping to the reception of its echo off of an object.
pinMode(echoPin, INPUT);
duration = pulseIn(echoPin, HIGH);

// convert the time into a distance
inches = microsecondsToInches(duration);
cm = microsecondsToCentimeters(duration);

Serial.print(“in, “);

if (inches <= 20) {fill_solid( &(leds[0]), NUM_LEDS /*number of leds*/, CRGB::Blue); //{whitestrobe(30);;

else if (inches >= 21) {fill_solid( &(leds[0]), NUM_LEDS /*number of leds*/, CRGB::Black);;


long microsecondsToInches(long microseconds)
// According to Parallax’s datasheet for the PING))), there are
// 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
// second). This gives the distance travelled by the ping, outbound
// and return, so we divide by 2 to get the distance of the obstacle.
// See:
return microseconds / 74 / 2;

long microsecondsToCentimeters(long microseconds)
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return microseconds / 29 / 2;


// NeoPixel test program showing use of the WHITE channel for RGBW
// pixels only (won’t look correct on regular RGB NeoPixel strips).

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket

// Which pin on the Arduino is connected to the NeoPixels?
// On a Trinket or Gemma we suggest changing this to 1:
#define LED_PIN 6

// How many NeoPixels are attached to the Arduino?
#define LED_COUNT 12

// NeoPixel brightness, 0 (min) to 255 (max)
#define BRIGHTNESS 50

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRBW + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic ‘v1’ (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products)

void setup() {
// These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
// Any other board, you can remove this part (but no harm leaving it):
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
// END of Trinket-specific code.

strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED); // Turn OFF all pixels ASAP
strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)

void loop() {
// Fill along the length of the strip in various colors…
colorWipe(strip.Color(255, 0, 0) , 50); // Red
colorWipe(strip.Color( 0, 255, 0) , 50); // Green
colorWipe(strip.Color( 0, 0, 255) , 50); // Blue
colorWipe(strip.Color( 0, 0, 0, 255), 50); // True white (not RGB white)

whiteOverRainbow(75, 5);


rainbowFade2White(3, 3, 1);

// Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single ‘packed’ 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color, int wait) {
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip…
strip.setPixelColor(i, color); // Set pixel’s color (in RAM); // Update strip to match
delay(wait); // Pause for a moment

void whiteOverRainbow(int whiteSpeed, int whiteLength) {

if(whiteLength >= strip.numPixels()) whiteLength = strip.numPixels() – 1;

int head = whiteLength – 1;
int tail = 0;
int loops = 3;
int loopNum = 0;
uint32_t lastTime = millis();
uint32_t firstPixelHue = 0;

for(;;) { // Repeat forever (or until a ‘break’ or ‘return’)
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip…
if(((i >= tail) && (i <= head)) || // If between head & tail…
((tail > head) && ((i >= tail) || (i <= head)))) {
strip.setPixelColor(i, strip.Color(0, 0, 0, 255)); // Set white
} else { // else set rainbow
int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
}; // Update strip with new contents
// There’s no delay here, it just runs full-tilt until the timer and
// counter combination below runs out.

firstPixelHue += 40; // Advance just a little along the color wheel

if((millis() – lastTime) > whiteSpeed) { // Time to update head/tail?
if(++head >= strip.numPixels()) { // Advance head, wrap around
head = 0;
if(++loopNum >= loops) return;
if(++tail >= strip.numPixels()) { // Advance tail, wrap around
tail = 0;
lastTime = millis(); // Save time of last movement

void pulseWhite(uint8_t wait) {
for(int j=0; j<256; j++) { // Ramp up from 0 to 255
// Fill entire strip with white at gamma-corrected brightness level ‘j’:
strip.fill(strip.Color(0, 0, 0, strip.gamma8(j)));;

for(int j=255; j>=0; j–) { // Ramp down from 255 to 0
strip.fill(strip.Color(0, 0, 0, strip.gamma8(j)));;

void rainbowFade2White(int wait, int rainbowLoops, int whiteLoops) {
int fadeVal=0, fadeMax=100;

// Hue of first pixel runs ‘rainbowLoops’ complete loops through the color
// wheel. Color wheel has a range of 65536 but it’s OK if we roll over, so
// just count from 0 to rainbowLoops*65536, using steps of 256 so we
// advance around the wheel at a decent clip.
for(uint32_t firstPixelHue = 0; firstPixelHue < rainbowLoops*65536;
firstPixelHue += 256) {

for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip…

// Offset pixel hue by an amount to make one full revolution of the
// color wheel (range of 65536) along the length of the strip
// (strip.numPixels() steps):
uint32_t pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());

// strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
// optionally add saturation and value (brightness) (each 0 to 255).
// Here we’re using just the three-argument variant, though the
// second value (saturation) is a constant 255.
strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue, 255,
255 * fadeVal / fadeMax)));

if(firstPixelHue < 65536) { // First loop,
if(fadeVal < fadeMax) fadeVal++; // fade in
} else if(firstPixelHue >= ((rainbowLoops-1) * 65536)) { // Last loop,
if(fadeVal > 0) fadeVal–; // fade out
} else {
fadeVal = fadeMax; // Interim loop, make sure fade is at max

for(int k=0; k<whiteLoops; k++) {
for(int j=0; j<256; j++) { // Ramp up 0 to 255
// Fill entire strip with white at gamma-corrected brightness level ‘j’:
strip.fill(strip.Color(0, 0, 0, strip.gamma8(j)));;
delay(1000); // Pause 1 second
for(int j=255; j>=0; j–) { // Ramp down 255 to 0
strip.fill(strip.Color(0, 0, 0, strip.gamma8(j)));;

delay(500); // Pause 1/2 second