Skip to content

Commit 2b421e4

Browse files
authored
Add files via upload
1 parent 8f086fb commit 2b421e4

File tree

1 file changed

+172
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)