Skip to content

Commit 35decf1

Browse files
authored
Merge pull request adafruit#1259 from firepixie/master
Firewalker Lite arduino code for Gemma M0
2 parents 24ad4e8 + 0b7ce3e commit 35decf1

File tree

2 files changed

+176
-0
lines changed

2 files changed

+176
-0
lines changed

Diff for: Gemma_Firewalker_AnimLite/.gemma_m0.test.only

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{\rtf1\ansi\ansicpg1252\cocoartf2511
2+
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
3+
{\colortbl;\red255\green255\blue255;}
4+
{\*\expandedcolortbl;;}
5+
\margl1440\margr1440\vieww10800\viewh8400\viewkind0
6+
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
7+
8+
\f0\fs24 \cf0 }
+168
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// 'Firewalker' LED sneakers sketch for Adafruit NeoPixels by Phillip Burgess
2+
3+
#include <Adafruit_NeoPixel.h>
4+
5+
const uint8_t gamma1[] PROGMEM = { // Gamma correction table for LED brightness
6+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
8+
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
9+
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
10+
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
11+
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
12+
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
13+
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
14+
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
15+
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
16+
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
17+
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
18+
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
19+
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
20+
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
21+
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
22+
23+
// LEDs go around the full perimeter of the shoe sole, but the step animation
24+
// is mirrored on both the inside and outside faces, while the strip doesn't
25+
// necessarily start and end at the heel or toe. These constants help configure
26+
// the strip and shoe sizes, and the positions of the front- and rear-most LEDs.
27+
// Becky's shoes: 39 LEDs total, 20 LEDs long, LED #5 at back.
28+
// Phil's shoes: 43 LEDs total, 22 LEDs long, LED #6 at back.
29+
#define N_LEDS 39 // TOTAL number of LEDs in strip
30+
#define SHOE_LEN_LEDS 20 // Number of LEDs down ONE SIDE of shoe
31+
#define SHOE_LED_BACK 5 // Index of REAR-MOST LED on shoe
32+
#define STEP_PIN A2 // Analog input for footstep
33+
#define LED_PIN A0 // NeoPixel strip is connected here
34+
#define MAXSTEPS 3 // Process (up to) this many concurrent steps
35+
36+
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
37+
38+
// The readings from the sensors are usually around 250-350 when not being pressed,
39+
// then dip below 100 when the heel is standing on it (for Phil's shoes; Becky's
40+
// don't dip quite as low because she's smaller).
41+
#define STEP_TRIGGER 150 // Reading must be below this to trigger step
42+
#define STEP_HYSTERESIS 200 // After trigger, must return to this level
43+
44+
int
45+
stepMag[MAXSTEPS], // Magnitude of steps
46+
stepX[MAXSTEPS], // Position of 'step wave' along strip
47+
mag[SHOE_LEN_LEDS], // Brightness buffer (one side of shoe)
48+
stepFiltered, // Current filtered pressure reading
49+
stepCount, // Number of 'frames' current step has lasted
50+
stepMin; // Minimum reading during current step
51+
uint8_t
52+
stepNum = 0, // Current step number in stepMag/stepX tables
53+
dup[SHOE_LEN_LEDS]; // Inside/outside copy indexes
54+
boolean
55+
stepping = false; // If set, step was triggered, waiting to release
56+
57+
58+
void setup() {
59+
pinMode(9, INPUT_PULLUP); // Set internal pullup resistor for sensor pin
60+
// As previously mentioned, the step animation is mirrored on the inside and
61+
// outside faces of the shoe. To avoid a bunch of math and offsets later, the
62+
// 'dup' array indicates where each pixel on the outside face of the shoe should
63+
// be copied on the inside. (255 = don't copy, as on front- or rear-most LEDs).
64+
// Later, the colors for the outside face of the shoe are calculated and then get
65+
// copied to the appropriate positions on the inside face.
66+
memset(dup, 255, sizeof(dup));
67+
int8_t a, b;
68+
for(a=1 , b=SHOE_LED_BACK-1 ; b>=0 ;) dup[a++] = b--;
69+
for(a=SHOE_LEN_LEDS-2, b=SHOE_LED_BACK+SHOE_LEN_LEDS; b<N_LEDS;) dup[a--] = b++;
70+
71+
// Clear step magnitude and position buffers
72+
memset(stepMag, 0, sizeof(stepMag));
73+
memset(stepX , 0, sizeof(stepX));
74+
strip.begin();
75+
stepFiltered = analogRead(STEP_PIN); // Initial input
76+
}
77+
78+
void loop() {
79+
uint8_t i, j;
80+
81+
// Read analog input, with a little noise filtering
82+
//stepFiltered = ((stepFiltered * 3) + analogRead(STEP_PIN)) >> 2;
83+
stepFiltered = (((stepFiltered * 3) - 100) + analogRead(STEP_PIN)) >> 2;
84+
85+
// The strip doesn't simply display the current pressure reading. Instead,
86+
// there's a bit of an animated flourish from heel to toe. This takes time,
87+
// and during quick foot-tapping there could be multiple step animations
88+
// 'in flight,' so a short list is kept.
89+
if(stepping) { // If a step was previously triggered...
90+
if(stepFiltered >= STEP_HYSTERESIS) { // Has step let up?
91+
stepping = false; // Yep! Stop monitoring.
92+
// Add new step to the step list (may be multiple in flight)
93+
stepMag[stepNum] = (STEP_HYSTERESIS - stepMin) * 6; // Step intensity
94+
stepX[stepNum] = -80; // Position starts behind heel, moves forward
95+
if(++stepNum >= MAXSTEPS) stepNum = 0; // If many, overwrite oldest
96+
} else if(stepFiltered < stepMin) stepMin = stepFiltered; // Track min val
97+
} else if(stepFiltered < STEP_TRIGGER) { // No step yet; watch for trigger
98+
stepping = true; // Got one!
99+
stepMin = stepFiltered; // Note initial value
100+
}
101+
102+
// Render a 'brightness map' for all steps in flight. It's like
103+
// a grayscale image; there's no color yet, just intensities.
104+
int mx1, px1, px2, m;
105+
memset(mag, 0, sizeof(mag)); // Clear magnitude buffer
106+
for(i=0; i<MAXSTEPS; i++) { // For each step...
107+
if(stepMag[i] <= 0) continue; // Skip if inactive
108+
for(j=0; j<SHOE_LEN_LEDS; j++) { // For each LED...
109+
// Each step has sort of a 'wave' that's part of the animation,
110+
// moving from heel to toe. The wave position has sub-pixel
111+
// resolution (4X), and is up to 80 units (20 pixels) long.
112+
mx1 = (j << 2) - stepX[i]; // Position of LED along wave
113+
if((mx1 <= 0) || (mx1 >= 80)) continue; // Out of range
114+
if(mx1 > 64) { // Rising edge of wave; ramp up fast (4 px)
115+
m = ((long)stepMag[i] * (long)(80 - mx1)) >> 4;
116+
} else { // Falling edge of wave; fade slow (16 px)
117+
m = ((long)stepMag[i] * (long)mx1) >> 6;
118+
}
119+
mag[j] += m; // Add magnitude to buffered sum
120+
}
121+
stepX[i]++; // Update position of step wave
122+
if(stepX[i] >= (80 + (SHOE_LEN_LEDS << 2)))
123+
stepMag[i] = 0; // Off end; disable step wave
124+
else
125+
stepMag[i] = ((long)stepMag[i] * 127L) >> 7; // Fade
126+
}
127+
128+
// For a little visual interest, some 'sparkle' is added.
129+
// The cumulative step magnitude is added to one pixel at random.
130+
long sum = 0;
131+
for(i=0; i<MAXSTEPS; i++) sum += stepMag[i];
132+
if(sum > 0) {
133+
i = random(SHOE_LEN_LEDS);
134+
mag[i] += sum / 4;
135+
}
136+
137+
// Now the grayscale magnitude buffer is remapped to color for the LEDs.
138+
// The code below uses a blackbody palette, which fades from white to yellow
139+
// to red to black. The goal here was specifically a "walking on fire"
140+
// aesthetic, so the usual ostentatious rainbow of hues seen in most LED
141+
// projects is purposefully skipped in favor of a more plain effect.
142+
uint8_t r, g, b;
143+
int level;
144+
for(i=0; i<SHOE_LEN_LEDS; i++) { // For each LED on one side...
145+
level = mag[i]; // Pixel magnitude (brightness)
146+
if(level < 255) { // 0-254 = black to red-1
147+
r = pgm_read_byte(&gamma1[level]);
148+
g = b = 0;
149+
} else if(level < 510) { // 255-509 = red to yellow-1
150+
r = 255;
151+
g = pgm_read_byte(&gamma1[level - 255]);
152+
b = 0;
153+
} else if(level < 765) { // 510-764 = yellow to white-1
154+
r = g = 255;
155+
b = pgm_read_byte(&gamma1[level - 510]);
156+
} else { // 765+ = white
157+
r = g = b = 255;
158+
}
159+
// Set R/G/B color along outside of shoe
160+
strip.setPixelColor(i+SHOE_LED_BACK, r, g, b);
161+
// Pixels along inside are funny...
162+
j = dup[i];
163+
if(j < 255) strip.setPixelColor(j, r, g, b);
164+
}
165+
166+
strip.show();
167+
delayMicroseconds(1500);
168+
}

0 commit comments

Comments
 (0)