Skip to content

Commit 0f8deec

Browse files
Add Arduino version of EyeLights_Accelerometer_Tap
1 parent 242135b commit 0f8deec

1 file changed

Lines changed: 132 additions & 0 deletions

File tree

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
ACCELEROMETER INPUT DEMO: while the LED Glasses Driver has a perfectly
3+
good clicky button for input, this code shows how one might instead use
4+
the onboard accelerometer for interactions*.
5+
6+
Worn normally, the LED rings are simply lit a solid color.
7+
TAP the eyeglass frames to cycle among a list of available colors.
8+
LOOK DOWN to light the LED rings bright white -- for navigating steps
9+
or finding the right key. LOOK BACK UP to return to solid color.
10+
This uses only the rings, not the matrix portion.
11+
12+
* Like, if you have big ol' monster hands, that little button can be
13+
hard to click, y'know?
14+
*/
15+
16+
#include <Adafruit_IS31FL3741.h> // For LED driver
17+
#include <Adafruit_LIS3DH.h> // For accelerometer
18+
#include <Adafruit_Sensor.h> // For m/s^2 accel units
19+
20+
Adafruit_LIS3DH accel;
21+
Adafruit_EyeLights_buffered glasses; // Buffered for smooth animation
22+
23+
// Here's a list of colors that we cycle through when tapped, specified
24+
// as {R,G,B} values from 0-255. These are intentionally a bit dim --
25+
// both to save battery and to make the "ground light" mode more dramatic.
26+
// Rather than primary color red/green/blue sequence which is just so
27+
// over-done at this point, let's use some HALLOWEEN colors!
28+
uint8_t colors[][3] = {
29+
{27, 9, 0}, // Orange
30+
{12, 0, 24}, // Purple
31+
{5, 31, 0}, // Green
32+
};
33+
#define NUM_COLORS (sizeof colors / sizeof colors[0]) // List length
34+
uint8_t looking_down_color[] = {255, 255, 255}; // Max white
35+
36+
uint8_t color_index = 0; // Begin at first color in list
37+
uint8_t *target_color; // Pointer to color we're aiming for
38+
float interpolated_color[] = {0.0, 0.0, 0.0}; // Current color along the way
39+
float filtered_y; // De-noised accelerometer reading
40+
bool looking_down; // Set true when glasses are oriented downward
41+
sensors_event_t event; // For accelerometer conversion
42+
uint32_t last_tap_time = 0; // For accelerometer tap de-noising
43+
44+
// Crude error handler, prints message to Serial console, flashes LED
45+
void err(char *str, uint8_t hz) {
46+
Serial.println(str);
47+
pinMode(LED_BUILTIN, OUTPUT);
48+
for (;;) digitalWrite(LED_BUILTIN, (millis() * hz / 500) & 1);
49+
}
50+
51+
void setup() { // Runs once at program start...
52+
53+
// Initialize hardware
54+
Serial.begin(115200);
55+
if (! accel.begin()) err("LIS3DH not found", 5);
56+
if (! glasses.begin()) err("IS3741 not found", 2);
57+
58+
// Configure accelerometer and get initial state
59+
accel.setClick(1, 100); // Set threshold for single tap
60+
accel.getEvent(&event); // Current accel in m/s^2
61+
// Check accelerometer to see if we've started in the looking-down state,
62+
// set the target color (what we're aiming for) appropriately. Only the
63+
// Y axis is needed for this.
64+
filtered_y = event.acceleration.y;
65+
looking_down = (filtered_y > 5.0);
66+
// If initially looking down, aim for the look-down color,
67+
// else aim for the first item in the color list.
68+
target_color = looking_down ? looking_down_color : colors[color_index];
69+
70+
// Configure glasses for max brightness, enable output
71+
glasses.setLEDscaling(0xFF);
72+
glasses.setGlobalCurrent(0xFF);
73+
glasses.enable(true);
74+
}
75+
76+
void loop() { // Repeat forever...
77+
78+
// interpolated_color blends from the prior to the next ("target")
79+
// LED ring colors, with a pleasant ease-out effect.
80+
for(uint8_t i=0; i<3; i++) { // R, G, B
81+
interpolated_color[i] = interpolated_color[i] * 0.97 + target_color[i] * 0.03;
82+
}
83+
// Convert separate red, green, blue to "packed" 24-bit RGB value
84+
uint32_t rgb = ((int)interpolated_color[0] << 16) |
85+
((int)interpolated_color[1] << 8) |
86+
(int)interpolated_color[2];
87+
// Fill both rings with packed color, then refresh the LEDs.
88+
glasses.left_ring.fill(rgb);
89+
glasses.right_ring.fill(rgb);
90+
glasses.show();
91+
92+
// The look-down detection only needs the accelerometer's Y axis.
93+
// This works with the Glasses Driver mounted on either temple,
94+
// with the glasses arms "open" (as when worn).
95+
accel.getEvent(&event);
96+
// Smooth the accelerometer reading the same way RGB colors are
97+
// interpolated. This avoids false triggers from jostling around.
98+
filtered_y = filtered_y * 0.97 + event.acceleration.y * 0.03;
99+
100+
// The threshold between "looking down" and "looking up" depends
101+
// on which of those states we're currently in. This is an example
102+
// of hysteresis in software...a change of direction requires a
103+
// little extra push before it takes, which avoids oscillating if
104+
// there was just a single threshold both ways.
105+
if (looking_down) { // Currently in the looking-down state...
106+
(void)accel.getClick(); // Discard any taps while looking down
107+
if (filtered_y < 3.5) { // Have we crossed the look-up threshold?
108+
target_color = colors[color_index]; // Back to list color
109+
looking_down = false; // We're looking up now!
110+
}
111+
} else { // Currently in the looking-up state...
112+
if (filtered_y > 5.0) { // Crossed the look-down threshold?
113+
target_color = looking_down_color; // Aim for white
114+
looking_down = true; // We're looking down now!
115+
} else if (accel.getClick()) {
116+
// No look up/down change, but the accelerometer registered
117+
// a tap. Compare this against the last time we sensed one,
118+
// and only do things if it's been more than half a second.
119+
// This avoids spurious double-taps that can occur no matter
120+
// how carefully the tap threshold was set.
121+
uint32_t now = millis();
122+
uint32_t elapsed = now - last_tap_time;
123+
if (elapsed > 500) {
124+
// A good tap was detected. Cycle to the next color in
125+
// the list and note the time of this tap.
126+
color_index = (color_index + 1) % NUM_COLORS;
127+
target_color = colors[color_index];
128+
last_tap_time = now;
129+
}
130+
}
131+
}
132+
}

0 commit comments

Comments
 (0)