Setup README and INOs
This commit is contained in:
parent
9fda1f1c88
commit
99b899419f
3 changed files with 289 additions and 0 deletions
|
|
@ -0,0 +1,128 @@
|
|||
// Fiery demon horns (rawr!) for Adafruit Trinket/Gemma.
|
||||
// Adafruit invests time and resources providing this open source code,
|
||||
// please support Adafruit and open-source hardware by purchasing
|
||||
// products from Adafruit!
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
#include <avr/power.h>
|
||||
|
||||
#define N_HORNS 1
|
||||
#define N_LEDS 30 // Per horn
|
||||
#define PIN 0
|
||||
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(N_HORNS * N_LEDS, PIN);
|
||||
|
||||
// /\ -> Fire-like effect is the sum of multiple triangle
|
||||
// ____/ \____ waves in motion, with a 'warm' color map applied.
|
||||
#define N_WAVES 6 // Number of simultaneous waves (per horn)
|
||||
// Coordinate space for waves is 16x the pixel spacing,
|
||||
// allowing fixed-point math to be used instead of floats.
|
||||
struct {
|
||||
int16_t lower; // Lower bound of wave
|
||||
int16_t upper; // Upper bound of wave
|
||||
int16_t mid; // Midpoint (peak) ((lower+upper)/2)
|
||||
uint8_t vlower; // Velocity of lower bound
|
||||
uint8_t vupper; // Velocity of upper bound
|
||||
uint16_t intensity; // Brightness at peak
|
||||
} wave[N_HORNS][N_WAVES];
|
||||
long fade; // Decreases brightness as wave moves
|
||||
|
||||
// Gamma correction improves appearance of midrange colors
|
||||
uint8_t gamma[] PROGMEM = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
|
||||
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
|
||||
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
|
||||
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
|
||||
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
|
||||
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
|
||||
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
|
||||
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
|
||||
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
|
||||
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
|
||||
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
|
||||
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
||||
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
||||
|
||||
static void random_wave(uint8_t h,uint8_t w) { // Randomize one wave struct
|
||||
wave[h][w].upper = -1; // Always start just below head of strip
|
||||
wave[h][w].lower = -16 * (3 + random(4)); // Lower end starts ~3-7 pixels back
|
||||
wave[h][w].mid = (wave[h][w].lower + wave[h][w].upper) / 2;
|
||||
wave[h][w].vlower = 3 + random(4); // Lower end moves at ~1/8 to 1/4 pixel/frame
|
||||
wave[h][w].vupper = wave[h][w].vlower + random(4); // Upper end moves a bit faster, spreading wave
|
||||
wave[h][w].intensity = 300 + random(600);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
uint8_t h, w;
|
||||
|
||||
randomSeed(analogRead(1));
|
||||
pixels.begin();
|
||||
for(h=0; h<N_HORNS; h++) {
|
||||
for(w=0; w<N_WAVES; w++) random_wave(h, w);
|
||||
}
|
||||
fade = 234 + N_LEDS / 2;
|
||||
if(fade > 255) fade = 255;
|
||||
|
||||
// A ~100 Hz timer interrupt on Timer/Counter1 makes everything run
|
||||
// at regular intervals, regardless of current amount of motion.
|
||||
#if F_CPU == 16000000L
|
||||
clock_prescale_set(clock_div_1);
|
||||
TCCR1 = _BV(PWM1A) | _BV(CS13) | _BV(CS11) | _BV(CS10); // 1:1024 prescale
|
||||
OCR1C = F_CPU / 1024 / 100 - 1;
|
||||
#else
|
||||
TCCR1 = _BV(PWM1A) | _BV(CS13) | _BV(CS11); // 1:512 prescale
|
||||
OCR1C = F_CPU / 512 / 100 - 1;
|
||||
#endif
|
||||
GTCCR = 0; // No PWM out
|
||||
TIMSK |= _BV(TOIE1); // Enable overflow interrupt
|
||||
}
|
||||
|
||||
void loop() { } // Not used -- everything's in interrupt below
|
||||
|
||||
ISR(TIMER1_OVF_vect) {
|
||||
uint8_t h, w, i, r, g, b;
|
||||
int16_t x;
|
||||
uint16_t sum;
|
||||
|
||||
for(h=0; h<N_HORNS; h++) { // For each horn...
|
||||
for(x=7, i=0; i<N_LEDS; i++, x+=16) { // For each LED along horn...
|
||||
for(sum=w=0; w<N_WAVES; w++) { // For each wave of horn...
|
||||
if((x < wave[h][w].lower) || (x > wave[h][w].upper)) continue; // Out of range
|
||||
if(x <= wave[h][w].mid) { // Lower half of wave (ramping up to peak brightness)
|
||||
sum += wave[h][w].intensity * (x - wave[h][w].lower) / (wave[h][w].mid - wave[h][w].lower);
|
||||
} else { // Upper half of wave (ramping down from peak)
|
||||
sum += wave[h][w].intensity * (wave[h][w].upper - x) / (wave[h][w].upper - wave[h][w].mid);
|
||||
}
|
||||
}
|
||||
// Now the magnitude (sum) is remapped to color for the LEDs.
|
||||
// A blackbody palette is used - fades white-yellow-red-black.
|
||||
if(sum < 255) { // 0-254 = black to red-1
|
||||
r = pgm_read_byte(&gamma[sum]);
|
||||
g = b = 0;
|
||||
} else if(sum < 510) { // 255-509 = red to yellow-1
|
||||
r = 255;
|
||||
g = pgm_read_byte(&gamma[sum - 255]);
|
||||
b = 0;
|
||||
} else if(sum < 765) { // 510-764 = yellow to white-1
|
||||
r = g = 255;
|
||||
b = pgm_read_byte(&gamma[sum - 510]);
|
||||
} else { // 765+ = white
|
||||
r = g = b = 255;
|
||||
}
|
||||
pixels.setPixelColor(h * N_LEDS + i, r, g, b);
|
||||
}
|
||||
|
||||
for(w=0; w<N_WAVES; w++) { // Update wave positions for each horn
|
||||
wave[h][w].lower += wave[h][w].vlower; // Advance lower position
|
||||
if(wave[h][w].lower >= (N_LEDS * 16)) { // Off end of strip?
|
||||
random_wave(h, w); // Yes, 'reboot' wave
|
||||
} else { // No, adjust other values...
|
||||
wave[h][w].upper += wave[h][w].vupper;
|
||||
wave[h][w].mid = (wave[h][w].lower + wave[h][w].upper) / 2;
|
||||
wave[h][w].intensity = (wave[h][w].intensity * fade) / 256; // Dimmer
|
||||
}
|
||||
}
|
||||
}
|
||||
pixels.show();
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
// Adafruit Trinket+NeoPixel animation for Daft Punk-inspired helmet.
|
||||
// Contains some ATtiny85-specific stuff; won't run as-is on Uno, etc.
|
||||
|
||||
// Operates in HSV (hue, saturation, value) colorspace rather than RGB.
|
||||
// Animation is an interference pattern between two waves; one controls
|
||||
// saturation, the other controls value (brightness). The wavelength,
|
||||
// direction, speed and type (square vs triangle wave) for each is randomly
|
||||
// selected every few seconds. Hue is always linear, but other parameters
|
||||
// are similarly randomized.
|
||||
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
#include <avr/power.h>
|
||||
|
||||
// GLOBAL STUFF --------------------------------------------------------------
|
||||
|
||||
#define N_LEDS 29
|
||||
#define PIN 0
|
||||
|
||||
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(N_LEDS, PIN);
|
||||
volatile uint16_t count = 1; // Countdown to next animation change
|
||||
extern const uint8_t gamma[]; // Big table at end of this code
|
||||
|
||||
volatile struct {
|
||||
uint8_t type, // 0 = square wave, 1 = triangle wave
|
||||
value[2]; // 0 = start-of-frame value, 1 = pixel-to-pixel value
|
||||
int8_t inc[2]; // 0 = frame-to-frame increment, 1 = pixel-to-pixel inc
|
||||
} wave[3]; // 0 = Hue, 1 = Saturation, 2 = Value (brightness)
|
||||
|
||||
#define WAVE_H 0 // Array indices for wave[]
|
||||
#define WAVE_S 1
|
||||
#define WAVE_V 2
|
||||
#define FRAME 0 // Array indices for value[] and inc[]
|
||||
#define PIXEL 1
|
||||
|
||||
|
||||
// INITIALIZATION ------------------------------------------------------------
|
||||
|
||||
void setup() {
|
||||
pixels.begin();
|
||||
randomSeed(analogRead(0)); // Seed random() from a floating pin (D2)
|
||||
|
||||
// Timer/Counter 1 is used to generate a steady ~50 Hz frame rate.
|
||||
#if F_CPU == 16000000L
|
||||
clock_prescale_set(clock_div_1);
|
||||
TCCR1 = _BV(PWM1A) | _BV(CS13) | _BV(CS12); // 1:2048 prescale
|
||||
OCR1C = F_CPU / 2048 / 50 - 1;
|
||||
#else
|
||||
TCCR1 = _BV(PWM1A) | _BV(CS13) | _BV(CS11) | _BV(CS10); // 1:1024
|
||||
OCR1C = F_CPU / 1024 / 50 - 1;
|
||||
#endif
|
||||
GTCCR = 0; // No PWM out
|
||||
TIMSK |= _BV(TOIE1); // Enable overflow interrupt
|
||||
}
|
||||
|
||||
void loop() { } // Not used here -- everything's in interrupt below
|
||||
|
||||
|
||||
// 50 HZ LOOP ----------------------------------------------------------------
|
||||
|
||||
ISR(TIMER1_OVF_vect) {
|
||||
uint8_t w, i, n, s, v, r, g, b;
|
||||
uint16_t v1, s1;
|
||||
|
||||
if(!(--count)) { // Time for new animation?
|
||||
count = 250 + random(250); // New effect will run for 5-10 sec.
|
||||
for(w=0; w<3; w++) { // Three waves (H,S,V)...
|
||||
wave[w].type = random(2); // Assign random type (square/triangle)
|
||||
for(i=0; i<2; i++) { // For frame and pixel increments...
|
||||
while(!(wave[w].inc[i] = random(15) - 7)); // Set non-zero random
|
||||
// wave value is never initialized; it's allowed to carry over
|
||||
}
|
||||
wave[w].value[PIXEL] = wave[w].value[FRAME];
|
||||
}
|
||||
wave[WAVE_S].inc[PIXEL] *= 16; // Make saturation & value
|
||||
wave[WAVE_V].inc[PIXEL] *= 16; // blinkier along strip
|
||||
} else { // Continue current animation; update waves
|
||||
for(w=0; w<3; w++) {
|
||||
wave[w].value[FRAME] += wave[w].inc[FRAME]; // OK if this wraps!
|
||||
wave[w].value[PIXEL] = wave[w].value[FRAME];
|
||||
}
|
||||
}
|
||||
|
||||
// Render current animation frame. COGNITIVE HAZARD: fixed point math.
|
||||
|
||||
for(i=0; i<N_LEDS; i++) { // For each LED along strip...
|
||||
|
||||
// Coarse (8-bit) HSV-to-RGB conversion, hue first:
|
||||
n = (wave[WAVE_H].value[PIXEL] % 43) * 6; // Angle within sextant; 0-255
|
||||
switch(wave[WAVE_H].value[PIXEL] / 43) { // Sextant number; 0-5
|
||||
case 0 : r = 255 ; g = n ; b = 0 ; break; // R to Y
|
||||
case 1 : r = 254 - n; g = 255 ; b = 0 ; break; // Y to G
|
||||
case 2 : r = 0 ; g = 255 ; b = n ; break; // G to C
|
||||
case 3 : r = 0 ; g = 254 - n; b = 255 ; break; // C to B
|
||||
case 4 : r = n ; g = 0 ; b = 255 ; break; // B to M
|
||||
default: r = 255 ; g = 0 ; b = 254 - n; break; // M to R
|
||||
}
|
||||
|
||||
// Saturation = 1-256 to allow >>8 instead of /255
|
||||
s = wave[WAVE_S].value[PIXEL];
|
||||
if(wave[WAVE_S].type) { // Triangle wave?
|
||||
if(s & 0x80) { // Downslope
|
||||
s = (s & 0x7F) << 1;
|
||||
s1 = 256 - s;
|
||||
} else { // Upslope
|
||||
s <<= 1;
|
||||
s1 = 1 + s;
|
||||
s = 255 - s;
|
||||
}
|
||||
} else { // Square wave
|
||||
if(s & 0x80) { // 100% saturation
|
||||
s1 = 256;
|
||||
s = 0;
|
||||
} else { // 0% saturation (white)
|
||||
s1 = 1;
|
||||
s = 255;
|
||||
}
|
||||
}
|
||||
|
||||
// Value (brightness) = 1-256 for similar reasons
|
||||
v = wave[WAVE_V].value[PIXEL];
|
||||
v1 = (wave[WAVE_V].type) ? // Triangle wave?
|
||||
((v & 0x80) ? 64 - ((v & 0x7F) << 1) : // Downslope
|
||||
1 + ( v << 1) ) : // Upslope
|
||||
((v & 0x80) ? 256 : 1); // Square wave; on/off
|
||||
|
||||
pixels.setPixelColor(i,
|
||||
pgm_read_byte(&gamma[((((r * s1) >> 8) + s) * v1) >> 8]),
|
||||
pgm_read_byte(&gamma[((((g * s1) >> 8) + s) * v1) >> 8]),
|
||||
pgm_read_byte(&gamma[((((b * s1) >> 8) + s) * v1) >> 8]));
|
||||
|
||||
// Update wave values along length of strip (values may wrap, is OK!)
|
||||
for(w=0; w<3; w++) wave[w].value[PIXEL] += wave[w].inc[PIXEL];
|
||||
}
|
||||
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
// Gamma correction improves appearance of midrange colors.
|
||||
// This table is positioned down here because it's a big annoying
|
||||
// distraction. The 'extern' near the top lets us reference it earlier.
|
||||
const uint8_t gamma[] PROGMEM = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
|
||||
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
|
||||
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
|
||||
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
|
||||
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
|
||||
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
|
||||
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
|
||||
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
|
||||
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
|
||||
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
|
||||
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
|
||||
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
||||
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
||||
4
3D_Printed_Daft_Punk_Helmet/README.md
Normal file
4
3D_Printed_Daft_Punk_Helmet/README.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# 3D Printed Daft Punk Helmet
|
||||
|
||||
Code to accompany this tutorial:
|
||||
https://learn.adafruit.com/3d-printed-daft-punk-helmet
|
||||
Loading…
Reference in a new issue