Skip to content

Commit 75affc8

Browse files
Add EyeLights googly rings Arduino code
1 parent 0f8deec commit 75affc8

1 file changed

Lines changed: 109 additions & 0 deletions

File tree

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
GOOGLY EYES for Adafruit EyeLight LED glasses + driver. Pendulum physics
3+
simulation using accelerometer and math. This uses only the rings, not the
4+
matrix portion. Adapted from Bill Earl's STEAM-Punk Goggles project:
5+
https://learn.adafruit.com/steam-punk-goggles
6+
*/
7+
8+
#include <Adafruit_IS31FL3741.h> // For LED driver
9+
#include <Adafruit_LIS3DH.h> // For accelerometer
10+
#include <Adafruit_Sensor.h> // For m/s^2 accel units
11+
12+
Adafruit_LIS3DH accel;
13+
Adafruit_EyeLights_buffered glasses; // Buffered for smooth animation
14+
15+
// A small class for our pendulum simulation.
16+
class Pendulum {
17+
public:
18+
// Constructor. Pass pointer to EyeLights ring, and a 3-byte color array.
19+
Pendulum(Adafruit_EyeLights_Ring_buffered *r, uint8_t *c) {
20+
ring = r;
21+
color = c;
22+
// Initial pendulum position, plus axle friction, are randomized
23+
// so rings don't spin in perfect lockstep.
24+
angle = random(1000);
25+
momentum = 0.0;
26+
friction = 0.9 + random(500) * 0.0001; // Inverse friction, really
27+
}
28+
29+
// Given a pixel index (0-23) and a scaling factor (0.0-1.0),
30+
// interpolate between LED "off" color (at 0.0) and this item's fully-
31+
// lit color (at 1.0) and set pixel to the result.
32+
void interp(uint8_t pixel, float scale) {
33+
// Convert separate red, green, blue to "packed" 24-bit RGB value
34+
ring->setPixelColor(pixel,
35+
(int(color[0] * scale) << 16) |
36+
(int(color[1] * scale) << 8) |
37+
int(color[2] * scale));
38+
}
39+
40+
// Given an accelerometer reading, run one cycle of the pendulum
41+
// physics simulation and render the corresponding LED ring.
42+
void iterate(sensors_event_t &event) {
43+
// Minus here is because LED pixel indices run clockwise vs. trigwise.
44+
// 0.004 is just an empirically-derived scaling fudge factor that looks
45+
// good; smaller values for more sluggish rings, higher = more twitch.
46+
momentum = momentum * friction - 0.004 *
47+
(cos(angle) * event.acceleration.z +
48+
sin(angle) * event.acceleration.x);
49+
angle += momentum;
50+
51+
// Scale pendulum angle into pixel space
52+
float midpoint = fmodf(angle * 12.0 / M_PI, 24.0);
53+
54+
// Go around the whole ring, setting each pixel based on proximity
55+
// (this is also to erase the prior position)...
56+
for (uint8_t i=0; i<24; i++) {
57+
float dist = fabs(midpoint - (float)i); // Pixel to pendulum distance...
58+
if (dist > 12.0) // If it crosses the "seam" at top,
59+
dist = 24.0 - dist; // take the shorter path.
60+
if (dist > 5.0) // Not close to pendulum,
61+
ring->setPixelColor(i, 0); // erase pixel.
62+
else if (dist < 2.0) // Close to pendulum,
63+
interp(i, 1.0); // solid color
64+
else // Anything in-between,
65+
interp(i, (5.0 - dist) / 3.0); // interpolate
66+
}
67+
}
68+
private:
69+
Adafruit_EyeLights_Ring_buffered *ring; // -> glasses ring
70+
uint8_t *color; // -> array of 3 uint8_t's [R,G,B]
71+
float angle; // Current position around ring
72+
float momentum; // Current 'oomph'
73+
float friction; // A scaling constant to dampen motion
74+
};
75+
76+
Pendulum pendulums[] = {
77+
Pendulum(&glasses.left_ring, (uint8_t[3]){0, 20, 50}), // Cerulean blue,
78+
Pendulum(&glasses.right_ring, (uint8_t[3]){0, 20, 50}), // 50 is plenty bright!
79+
};
80+
#define N_PENDULUMS (sizeof pendulums / sizeof pendulums[0])
81+
82+
// Crude error handler, prints message to Serial console, flashes LED
83+
void err(char *str, uint8_t hz) {
84+
Serial.println(str);
85+
pinMode(LED_BUILTIN, OUTPUT);
86+
for (;;) digitalWrite(LED_BUILTIN, (millis() * hz / 500) & 1);
87+
}
88+
89+
void setup() { // Runs once at program start...
90+
91+
// Initialize hardware
92+
Serial.begin(115200);
93+
if (! accel.begin()) err("LIS3DH not found", 5);
94+
if (! glasses.begin()) err("IS3741 not found", 2);
95+
96+
// Configure glasses for max brightness, enable output
97+
glasses.setLEDscaling(0xFF);
98+
glasses.setGlobalCurrent(0xFF);
99+
glasses.enable(true);
100+
}
101+
102+
void loop() { // Repeat forever...
103+
sensors_event_t event;
104+
accel.getEvent(&event); // Read accelerometer once
105+
for (uint8_t i=0; i<N_PENDULUMS; i++) { // For each pendulum...
106+
pendulums[i].iterate(event); // Do math with accel data
107+
}
108+
glasses.show();
109+
}

0 commit comments

Comments
 (0)