LED Octopus Hat

A lightup octopus hat I coded, 3D model designed, printed, and made!
Table of Contents

Basic overview

Octopus hat

This hat was a labor of love, and taught me so much about LED programming, electrical wiring, better 3d-modelling, and more! It's made from 3d-printed ball-jointed tentacles that are hollow inside, containing programmable LED strips and a wire to make them positionable. The hat itself is a felt hat, hollowed out to fit the controller and batteries and wiring, with holes for the light-up eyes. It lasts for about 4-6 hours on the built-in batteries alone and cycles through a variety of patterns I programmed in. To learn how I did it and more, read on!

Lessons Learned

  • How to wire LED strips, code a microcontroller, and assemble a Li Ion battery pack.
  • How to design and print a large-scale project, meant to work with LEDs.
  • Always check the polarity of connectors (esp JST connectors), and swap as needed. (Apparently pcb/arduino usage is different than rc car ones, whatever)
  • Batteries in PARALLEL add amperage, in SERIES add voltage! Also, connecting a bunch of wires together is ALWAYS in parallel!
  • Use a resistor to emulate amp load (and desired voltage draw).
  • Gel nail polish is BS
  • Painting/general cleanup of 3d printed segments can take longer than expected; the less post-processing needed, the MUCH better.

Modelling the tentacles

All the modelling was done in Blender. Using pre-existing assets of ball joints from Thingiverse, I twisted and sculpted tentacles to fit with the joints. I hollowed out the tentacles to leave room for the LEDs, while also optimizing how the tentacles looked for best layers when 3D printing. When printing the actual tentacles, I used minimum shell/wall thickness for maximum light output.

Octopus hat
Initial sketch of what I wanted the hat to look like
Octopus hat
Modeling the tentacle ball joints in Blender
Octopus hat
Slicer program for previewing a 3D print of a tentacle

Programming the LEDs

The controller used for this hat is the Teensy 3.2, with the OctoWS2811 Adaptor for handling LEDs. Definitely overkill for a project with barely hundreds of LEDs, instead of thousands, but it's what was first recommended to me so it's what I used! I learned a lot about programming microcontrollers, including how the Arduino framework works and various LED libraries. I didn't use the FastLED library as is usually standard, but rather the very similar OctoWS2811 LED Library which is tailor-made for the controller I used. Both the FastLED and OctoWS2811 operate similarly on the Arduino framework for programming a microcontroller, namely that there has to be a loop() function in the .ino file that is the main entryway into the file.

As a programmer I felt confident in my ability to program these LEDs, but there was definitely a lot to learn about the way microcontroller programming works; namely, that though it uses C++ code syntax and file structure, the execution of the code is done differently from standard cpus -- it's single threaded and all code is blocking. Other issues cropped up due to the number of clock cycles and how LED instructions are sent, all of which was very interesting to go through! To see the code for the LED patterns I whipped up, see below; the OctopusHat.ino file is the main entryway with the other files defining patterns that (hopefully) I get a chance to re-use in future work. I'll upload the project to Github if you ask me to ;)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 #include <OctoWS2811.h> #include "ledStripPatterns.h" // Max num of LEDs per a strip const int ledsPerStrip = 30; // Seems excessive to have *6 but w/e DMAMEM int displayMemory[ledsPerStrip*6]; int drawingMemory[ledsPerStrip*6]; // Strip I'm currently using is GRB const int config = WS2811_GRB | WS2811_800kHz; // Indices for the octopus LEDs (arms are uneven lengths) const int LEDStarts[8] = {0,ledsPerStrip*1, ledsPerStrip*2, ledsPerStrip*3, ledsPerStrip*4, ledsPerStrip*5, ledsPerStrip*6, ledsPerStrip*7}; const int LEDEnds[8] = {7,ledsPerStrip*1 + 14, ledsPerStrip*2 + 9, ledsPerStrip*3 + 15, ledsPerStrip*4 + 19, ledsPerStrip*5 + 22, ledsPerStrip*6 + 29, ledsPerStrip*7 + 9}; // Octopus eyes indices, are on pin/strip #1 const int eyesStart = 8; const int eyesEnd = 13; // Predefined colors for bouncing ball animation int ballColors[8][2]; //rgb color from bright to dark // const int oceanColors[4] = { 0x4c738f, 0x9ec6d0, 0x2c8fa3, 0x003136 }; const int oceanColors[4] = { BLUE, PURPLE, PINK, RED }; // Main call that creates the leds object to use with OctoWS2811 OctoWS2811 leds(ledsPerStrip, displayMemory, drawingMemory, config); // Init the strip patterns class StripPatterns patterns(LibraryUsed::OCTO_LIB); void setup() { for (int i = 0; i < 8; i++) { ballColors[i][0] = patterns.rainbowColors[(i+1)*24 % 180]; ballColors[i][1] = patterns.rainbowColors[(i+1)*26 % 180]; } leds.begin(); Serial.begin(38400); } const int loopTimeSecs = 30; const int rainbowDelay = 1100; int NumFunctions = 4; void loop() { static int currInd = 0; static int lastMillis = millis(); int i; switch (currInd) { case 0: for (i = 0; i < 8; i++) patterns.MeteorRain(patterns.rainbowColors[(i+12)*7 % 180], LEDStarts[i], LEDEnds[i], i, 128, 60); break; case 1: for (i = 0; i < 8; i++) patterns.Fire(45, 120, 40, LEDStarts[i], LEDEnds[i]); break; case 2: for (i = 0; i < 8; i++) patterns.BouncingColoredBalls(2, ballColors[i], LEDStarts[i], LEDEnds[i], i); break; case 3: for (i = 0; i < 8; i++) patterns.RainbowIndividual(rainbowDelay, LEDStarts[i], LEDEnds[i]); break; } // Rainbow eyes!! patterns.RainbowIndividual(rainbowDelay, eyesStart, eyesEnd); // Loop thru all designs if (lastMillis + (loopTimeSecs * 1000) < millis()) { lastMillis = millis(); currInd = ++currInd % NumFunctions; } // Only show rainbow once if (lastMillis / (loopTimeSecs * 1000) > NumFunctions ) { NumFunctions = 3; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 #include <Arduino.h> #include <OctoWS2811.h> #include <FastLED.h> #include "ledStripPatterns.h" #include "ledUtilities.h" StripPatterns::StripPatterns(LibraryUsed library) { LibraryUsed _library = library; // pre-compute the 180 rainbow colors for (int i=0; i<180; i++) { int hue = i * 2; int saturation = 100; int lightness = 50; rainbowColors[i] = makeColor(hue, saturation, lightness); } } /** * Adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects * meteorSize – the number of LEDs that represent the meteor, not counting the tail of the meteor * meteorTrailDecay - how fast the meteor tail decays/ disappears. A larger number makes the tail short and/or disappear faster. * Theoretically a value of 64 should reduce the brightness by 25% for each time the meteor gets drawn. * speedDelay - how many milliseconds (1000 milliseconds in a second) the drawing will be delayed */ void StripPatterns::MeteorRain(int color, int startInd, int endInd, int strip, byte meteorTrailDecay, int speedDelay) { static int stripInds[STRIPS]; // Delay code static int lastMillis = millis(); static int lastStart = 0; // Delay without actually pausing the whole teensy, allowing for other delays on other pixel rows in a single loop if (millis() - lastMillis < speedDelay) return; // Update the delay time once per loop ASSUMING that a loop INCREMENTS through the pixels (++)!!! if (lastStart > startInd) lastMillis = millis(); lastStart = startInd; // Set the starting ind to not be zero, but the actual starting ind if (stripInds[strip] < startInd) stripInds[strip] = startInd; // fade brightness all LEDs one step for (int j = startInd; j < endInd + 1; j++) { if (random(10)>5) { fadeToBlack(j, meteorTrailDecay ); } } // draw meteor int meteorSize = max((endInd - startInd + 1) / 10, 1); for(int j = 0; j < meteorSize; j++) { if( (stripInds[strip] - j < endInd+1) && (stripInds[strip]-j >= startInd) ) { setPixel(stripInds[strip]-j, color); } } showStrip(); // Emulate a loop through startInd < i < endInd*2, aka all leds twice (for decay niceness) stripInds[strip] = (stripInds[strip] + 1) % (endInd*2 - startInd); } /** * Adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects * * Max num of balls = 4 * Max num of strips/legs = 8 */ void StripPatterns::BouncingColoredBalls(int BallCount, int colors[], int startInd, int endInd, int leg, bool reverse) { const float Gravity = -9.81; const int StartHeight = 1; const float ImpactVelocityStart = sqrt( -2 * Gravity * StartHeight ); const int MaxBalls = 4; // Max 4 balls, per each strip / static float Height[STRIPS][MaxBalls]; static float ImpactVelocity[STRIPS][MaxBalls]; static float TimeSinceLastBounce[STRIPS][MaxBalls]; static int Position[STRIPS][MaxBalls]; static long ClockTimeSinceLastBounce[STRIPS][MaxBalls]; static float Dampening[STRIPS][MaxBalls]; static bool init[STRIPS] = {true, true, true, true, true, true, true, true}; if (init[leg]) for (int i = 0 ; i < BallCount ; i++) { ClockTimeSinceLastBounce[leg][i] = millis() - leg*1000; Height[leg][i] = StartHeight; Position[leg][i] = 0; ImpactVelocity[leg][i] = ImpactVelocityStart; TimeSinceLastBounce[leg][i] = 0; Dampening[leg][i] = 0.90 - float(i)/pow(BallCount,2); init[leg] = false; } for (int i = 0 ; i < BallCount ; i++) { TimeSinceLastBounce[leg][i] = millis() - ClockTimeSinceLastBounce[leg][i]; Height[leg][i] = 0.5 * Gravity * pow( TimeSinceLastBounce[leg][i]/1000 , 2.0 ) + ImpactVelocity[leg][i] * TimeSinceLastBounce[leg][i]/1000; if ( Height[leg][i] < 0 ) { Height[leg][i] = 0; ImpactVelocity[leg][i] = Dampening[leg][i] * ImpactVelocity[leg][i]; ClockTimeSinceLastBounce[leg][i] = millis(); if ( ImpactVelocity[leg][i] < 0.01 ) { ImpactVelocity[leg][i] = ImpactVelocityStart; } } Position[leg][i] = round( Height[leg][i] * (endInd - startInd) / StartHeight); } // Clear trails for (int i=startInd; i < endInd+1; i++) { setPixel(i, 0); } if (reverse) { for (int i = 0 ; i < BallCount ; i++) { setPixel(endInd - Position[leg][i], colors[i]); } } else { for (int i = 0 ; i < BallCount ; i++) { setPixel(Position[leg][i] + startInd, colors[i]); } } showStrip(); } /** * Set a row of pixels to a color, cycling through colors at rainbowWait rate */ void StripPatterns::RainbowIndividual(int rainbowWait, int startInd, int endInd) { static int timeRainbowMillis = millis(); static int colorInd = 0; // Delay without actually pausing the whole teensy, allowing for other delays on other pixel rows in a single loop if (millis() - timeRainbowMillis >= rainbowWait / LEDS_PER_STRIP) { // Only one gloabal var set per loop timeRainbowMillis = millis(); colorInd = ++colorInd % 180; } for (int x=startInd; x < endInd+1; x++) { int index = (colorInd + x) % 180; setPixel(x, rainbowColors[index]); } showStrip(); } /** Adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectFire The first one (Cooling) indicates how fast a flame cools down. More cooling means shorter flames, and the recommended values are between 20 and 100. 50 seems the nicest. The Second parameter (Sparking), indicates the chance (out of 255) that a spark will ignite. A higher value makes the fire more active. Suggested values lay between 50 and 200, with my personal preference being 120. The last parameter (SpeedDelay) allows you to slow down the fire activity … a higher value makes the flame appear slower. You’ll have to play a little with that, but personally I like a value between 0 and 20. */ void StripPatterns::Fire(int Cooling, int Sparking, int SpeedDelay, int startInd, int endInd) { static int timeFireMillis = millis(); static int lastStart = 0; // One array for all pixels static byte heat[LEDS_PER_STRIP*STRIPS]; // Delay without actually pausing the whole teensy, allowing for other delays on other pixel rows in a single loop if (millis() - timeFireMillis < SpeedDelay) return; // Update the delay time once per loop ASSUMING that a loop INCREMENTS through the pixels (++)!!! if (lastStart > startInd) timeFireMillis = millis(); lastStart = startInd; int numLeds = endInd-startInd + 1; int cooldown; // Step 1. Cool down every cell a little for (int i = startInd; i < endInd + 1; i++) { cooldown = random(0, ((Cooling * 10) / numLeds) + 2); if(cooldown>heat[i]) { heat[i]=0; } else { heat[i]=heat[i]-cooldown; } } // Step 2. Heat from each cell drifts 'up' and diffuses a little for( int k= endInd; k >= startInd+2; k--) { heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3; } // Step 3. Randomly ignite new 'sparks' near the bottom if( random(255) < Sparking ) { // Spark in the bottom 20% int y = random(0, numLeds / 5) + startInd; heat[y] = heat[y] + random(160,255); } // Step 4. Convert heat to LED colors for(int j = startInd; j < endInd + 1; j++) { setPixelHeatColor(j, heat[j] ); } showStrip(); } void StripPatterns::setPixelHeatColor (int Pixel, byte temperature) { // Scale 'heat' down from 0-255 to 0-191 byte t192 = round((temperature/255.0)*191); // calculate ramp up from byte heatramp = t192 & 0x3F; // 0..63 heatramp <<= 2; // scale up to 0..252 // figure out which third of the spectrum we're in: if( t192 > 0x80) { // hottest setPixel(Pixel, 255, 255, heatramp); } else if( t192 > 0x40 ) { // middle setPixel(Pixel, 255, heatramp, 0); } else { // coolest setPixel(Pixel, heatramp, 0, 0); } } // For setting entire strip to one color void StripPatterns::setColorStrip(int color, int startInd, int endInd) { for (int i=startInd; i < endInd+1; i++) { setPixel(i, color); } // ledsOcto.setPixel(endInd, WHITE); showStrip(); } void StripPatterns::fadeToBlack(int ledNo, byte fadeValue) { uint32_t oldColor; uint8_t r, g, b; int value; switch (_library) { case LibraryUsed::OCTO_LIB: oldColor = ledsOcto.getPixel(ledNo); break; case LibraryUsed::FAST_LED_LIB: oldColor = ledsFast[ledNo]; break; } r = (oldColor & 0x00ff0000UL) >> 16; g = (oldColor & 0x0000ff00UL) >> 8; b = (oldColor & 0x000000ffUL); r=(r<=10)? 0 : (int) r-(r*fadeValue/256); g=(g<=10)? 0 : (int) g-(g*fadeValue/256); b=(b<=10)? 0 : (int) b-(b*fadeValue/256); setPixel(ledNo, r,g,b); } void StripPatterns::showStrip() { switch (_library) { case LibraryUsed::OCTO_LIB: ledsOcto.show(); break; case LibraryUsed::FAST_LED_LIB: FastLED.show(); break; } } void StripPatterns::setPixel(uint32_t num, int color) { switch (_library) { case LibraryUsed::OCTO_LIB: ledsOcto.setPixel(num, color); break; case LibraryUsed::FAST_LED_LIB: ledsFast[num] = CRGB(color); break; } } void StripPatterns::setPixel(uint32_t num, uint8_t red, uint8_t green, uint8_t blue) { switch (_library) { case LibraryUsed::OCTO_LIB: ledsOcto.setPixel(num, red, green, blue); break; case LibraryUsed::FAST_LED_LIB: ledsFast[num] = CRGB(red, green, blue); break; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include <Arduino.h> #include <OctoWS2811.h> #include <FastLED.h> #ifndef STRIP_PATTERNS #define STRIP_PATTERNS #define RED 0xFF0000 #define GREEN 0x00FF00 #define BLUE 0x0000FF #define LIGHTBLUE 0x00FFFF #define YELLOW 0xFFFF00 #define PINK 0xFF1088 #define ORANGE 0xE05800 #define WHITE 0xFFFFFF #define PURPLE 0x8100FF #define ENDCOL 0x62FF00 // Change for each project compiled #define LEDS_PER_STRIP 30 // Change for each project compiled #define STRIPS 8 enum class LibraryUsed { OCTO_LIB, FAST_LED_LIB }; // Set if using the OctoWS2811 library extern OctoWS2811 ledsOcto; // Set if using FastLED library extern CRGB ledsFast[LEDS_PER_STRIP * STRIPS]; class StripPatterns { public: StripPatterns(LibraryUsed library); void MulticolorSineWave(int colors[4], int startInd, int endInd, int leg); void BouncingColoredBalls(int BallCount, int colors[], int startInd, int endInd, int leg, bool reverse = true); void Fire(int Cooling, int Sparking, int SpeedDelay, int startInd, int endInd); void RainbowIndividual(int rainbowWait, int startInd, int endInd); void MeteorRain(int color, int startInd, int endInd, int strip, byte meteorTrailDecay, int speedDelay); void setColorStrip(int color, int startInd, int endInd); // Predefined colors of rainbow int rainbowColors[180]; private: LibraryUsed _library; void setPixelHeatColor (int Pixel, byte temperature); void fadeToBlack(int ledNo, byte fadeValue); void showStrip(); void setPixel(uint32_t num, int color); void setPixel(uint32_t num, uint8_t red, uint8_t green, uint8_t blue); }; #endif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include <Arduino.h> unsigned int h2rgb(unsigned int v1, unsigned int v2, unsigned int hue) { if (hue < 60) return v1 * 60 + (v2 - v1) * hue; if (hue < 180) return v2 * 60; if (hue < 240) return v1 * 60 + (v2 - v1) * (240 - hue); return v1 * 60; } // Convert HSL (Hue, Saturation, Lightness) to RGB (Red, Green, Blue) // // hue: 0 to 359 - position on the color wheel, 0=red, 60=orange, // 120=yellow, 180=green, 240=blue, 300=violet // // saturation: 0 to 100 - how bright or dull the color, 100=full, 0=gray // // lightness: 0 to 100 - how light the color is, 100=white, 50=color, 0=black // int makeColor(unsigned int hue, unsigned int saturation, unsigned int lightness) { unsigned int red, green, blue; unsigned int var1, var2; if (hue > 359) hue = hue % 360; if (saturation > 100) saturation = 100; if (lightness > 100) lightness = 100; // algorithm from: http://www.easyrgb.com/index.php?X=MATH&H=19#text19 if (saturation == 0) { red = green = blue = lightness * 255 / 100; } else { if (lightness < 50) { var2 = lightness * (100 + saturation); } else { var2 = ((lightness + saturation) * 100) - (saturation * lightness); } var1 = lightness * 200 - var2; red = h2rgb(var1, var2, (hue < 240) ? hue + 120 : hue - 240) * 255 / 600000; green = h2rgb(var1, var2, hue) * 255 / 600000; blue = h2rgb(var1, var2, (hue >= 120) ? hue - 120 : hue + 240) * 255 / 600000; } return (red << 16) | (green << 8) | blue; } // alternate code: // http://forum.pjrc.com/threads/16469-looking-for-ideas-on-generating-RGB-colors-from-accelerometer-gyroscope?p=37170&viewfull=1#post37170
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 unsigned int h2rgb(unsigned int v1, unsigned int v2, unsigned int hue) { if (hue < 60) return v1 * 60 + (v2 - v1) * hue; if (hue < 180) return v2 * 60; if (hue < 240) return v1 * 60 + (v2 - v1) * (240 - hue); return v1 * 60; } // Convert HSL (Hue, Saturation, Lightness) to RGB (Red, Green, Blue) // // hue: 0 to 359 - position on the color wheel, 0=red, 60=orange, // 120=yellow, 180=green, 240=blue, 300=violet // // saturation: 0 to 100 - how bright or dull the color, 100=full, 0=gray // // lightness: 0 to 100 - how light the color is, 100=white, 50=color, 0=black // int makeColor(unsigned int hue, unsigned int saturation, unsigned int lightness) { unsigned int red, green, blue; unsigned int var1, var2; if (hue > 359) hue = hue % 360; if (saturation > 100) saturation = 100; if (lightness > 100) lightness = 100; // algorithm from: http://www.easyrgb.com/index.php?X=MATH&H=19#text19 if (saturation == 0) { red = green = blue = lightness * 255 / 100; } else { if (lightness < 50) { var2 = lightness * (100 + saturation); } else { var2 = ((lightness + saturation) * 100) - (saturation * lightness); } var1 = lightness * 200 - var2; red = h2rgb(var1, var2, (hue < 240) ? hue + 120 : hue - 240) * 255 / 600000; green = h2rgb(var1, var2, hue) * 255 / 600000; blue = h2rgb(var1, var2, (hue >= 120) ? hue - 120 : hue + 240) * 255 / 600000; } return (red << 16) | (green << 8) | blue; }

Some LED patterns

Rainbow pattern on the version 1 hat

Wiring: SO MUCH soldering

Octopus hat
Internals of the hat, along with the 3d-printed custom cases I made for the microcontroller and battery pack

This was my first time EVER soldering, and man was it a doozy! 8 LED strips, each with Data In, Data Out, Power, and Gnd wires, each going to its own path.... it was a LOT lemme tell yea especially with the shitty $20 soldering beginner's kit I bought from Amazon. But the end result is the beautiful wiring you see here! All solder points are heat-shrink wrap protected or have silicon gel, or both, to protect them.

Upgrading to 2.0

When I initially made the hat, not only did it have the worst wiring (not pictured lol) but it also had pretty ugly/robotic looking tentacles. When I did version 2.0, I fixed BOTH problems along with adding an internal lithium ion battery pack to go with the ability to run off of an external pack!

Octopus hat
Initial Version
Octopus hat
Initial Version lit up
Octopus hat
Version 2.0
Octopus hat
Version 2.0 lit up

Final Assembly and Look!

Octopus Hat

Materials used

NameCostNotes
Manpower $0.00So many hours.... more than 80+ for doing version 1 + version 2....
New Hat $17.00 https://www.amazon.com/dp/B07XGCVNNG
Filament $45.00Approx usage, probably
Silicone conformal coating pen $13.00Make the board more resilient
Heat Shrink Wire Electrical Connectors Kit - Butt, Ring, Spade $11.00Fore better connecting/splitters/wiring and such I guess? Without soldering?
Wire stripper/crimper tool $7.00 About time anyways
3.7v 1100mAh lipo rechargeable batteries x4$41.00Should be plenty of power
Buck converter down step x$11.00In order to have 5v output from 3.7v batteries in series
USB LiPoly charger$14.00Charging back up the batteries
USB mini b cable$1.50for charger lol
More jst connectors$10.00Fucking didn't realize there's multiple types of 2 pin jst connectors and got the wrong one initially...
WS2812B Addressable LED Strip$36.005V, 60pixel/m, IP67, 5 meters, RGB order: GRB (Not RGB)
Teensy 3.2 + header$20.00https://www.adafruit.com/product/2756
OctoWS2811 Adapter for Teensy 3.1 - Control tons of NeoPixels!$12.50
2-Way 2.1mm DC Barrel Jack Splitter Squid$3.00
Tactile Button switch (6mm) x 20 pack$2.50
Adafruit Perma-Proto Half-sized Breadboard PCB - Single$4.00
Soldering kit$20.00https://www.amazon.com/gp/product/B07S61WT16/ref=ppx_od_dt_b_asin_title_s02?ie=UTF8&psc=1
Ethernet cable$3.50
2 Pack Black 1 Female to 4 Male 5.5mm X 2.1mm CCTV DC Power Supply Splitter Cable$8.50
Mini top hat$11.00Too small ultimately.... https://www.amazon.com/gp/product/B07D4JZ6KM/ref=ppx_od_dt_b_asin_title_s02?ie=UTF8&psc=1
10 Female 12v DC Power Jack Adapter Connector for Led Strip$5.00
30 Pcs 40 Pin 2.54mm Male and Female Pin Headers$5.50Would have BEEN NICE to know I NEEDED this beforehand!!!