That looks perfect! I've tried the following code but its not working. What am I missing?
Code: Select all
// Googly Eye Goggles
// By Bill Earl
// For Adafruit Industries
//
// The googly eye effect is based on a physical model of a pendulum.
// The pendulum motion is driven by accelerations in 2 axis.
// Eye color varies with orientation of the magnetometer
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LSM303_U.h>
#include <Adafruit_NeoPixel.h>
#define PIN 6
// We could do this as 2 16-pixel rings wired in parallel.
// But keeping them separate lets us do the right and left
// eyes separately if we want.
Adafruit_NeoPixel strip = Adafruit_NeoPixel(39, PIN, NEO_GRB + NEO_KHZ800);
int x;
int y;
int z;
int f;
int p;
Adafruit_LSM303_Accel_Unified accel = Adafruit_LSM303_Accel_Unified(54321);
Adafruit_LSM303_Mag_Unified mag = Adafruit_LSM303_Mag_Unified(12345);
float pos = 0; // Starting center position of pupil
float posB = 0; // Starting center position of pupil
float increment = 2 * 3.14159 / 16; // distance between pixels in radians
float incrementB = 2 * 3.14159 / 16; // distance between pixels in radians
float MomentumH = 0; // horizontal component of pupil rotational inertia
float MomentumV = 0; // vertical component of pupil rotational inertia
// Tuning constants. (a.k.a. "Fudge Factors)
// These can be tweaked to adjust the liveliness and sensitivity of the eyes.
const float friction = 0.95; // frictional damping constant. 1.0 is no friction.
const float swing = 60; // arbitrary divisor for gravitational force
const float gravity = 200; // arbitrary divisor for lateral acceleration
const float nod = 7.5; // accelerometer threshold for toggling modes
long nodStart = 0;
long nodTime = 2000;
bool antiGravity = false; // The pendulum will anti-gravitate to the top.
bool mirroredEyes = false; // The left eye will mirror the right.
const float halfWidth = 1.25; // half-width of pupil (in pixels)
// Pi for calculations - not the raspberry type
const float Pi = 3.14159;
void setup(void)
{
Serial.begin(9600);
strip.begin();
strip.show(); // Initialize all pixels to 'off' sensor_t sensor;
// Initialize the sensors
accel.begin();
mag.begin();
resetModes();
}
// main processing loop
void loop(void)
{
// Read the magnetometer and determine the compass heading:
sensors_event_t event;
mag.getEvent(&event);
// Calculate the angle of the vector y,x from magnetic North
float heading = (atan2(event.magnetic.y,event.magnetic.x) * 180) / Pi;
// Normalize to 0-360 for a compass heading
if (heading < 0)
{
heading = 360 + heading;
}
// Now read the accelerometer to control the motion.
accel.getEvent(&event);
x=event.acceleration.x;
y=event.acceleration.y;
z=event.acceleration.z;
f= sqrt(x*x+y*y+z*z);
Serial.print("f: "); Serial.print (f); Serial.print(" ");
Serial.print("Y: "); Serial.print(f); Serial.print(" ");
Serial.print("Z: "); Serial.print(f); Serial.print(" ");Serial.println("m/s^2 ");
delay(0);
// Check for mode change commands
// apply a little frictional damping to keep things in control and prevent perpetual motion
MomentumH *= friction;
MomentumV *= friction;
// Calculate the horizontal and vertical effect on the virtual pendulum
// 'pos' is a pixel address, so we multiply by 'increment' to get radians.
float TorqueH = cos(pos * increment); // peaks at top and bottom of the swing
float TorqueV = sin(pos * incrementB); // peaks when the pendulum is horizontal
// Add the incremental acceleration to the existing momentum
// This code assumes that the accelerometer is mounted upside-down, level
// and with the X-axis pointed forward. So the Y axis reads the horizontal
// acceleration and the inverse of the Z axis is gravity.
// For other orientations of the sensor, just change the axis to match.
MomentumH += TorqueH * event.acceleration.y / swing;
if (antiGravity)
{
MomentumV += TorqueV * event.acceleration.z / gravity;
}
else
{
MomentumV -= TorqueV * event.acceleration.z / gravity;
}
// Calculate the new position
pos += MomentumH + MomentumV;
// handle the wrap-arounds at the top
while (round(pos) < 0) pos += 39.0;
while (round(pos) > 38) pos -= 39.0;
// Now re-compute the display
for (int i = 0; i < 39; i++)
{
// Compute the distance bewteen the pixel and the center
// point of the virtual pendulum.
float diff = i - pos;
// Light up nearby pixels proportional to their proximity to 'pos'
if (fabs(diff) <= halfWidth)
{
uint32_t color;
float proximity = halfWidth - fabs(diff) * 200;
// pick a color based on heading & proximity to 'pos'
color = selectColor(heading, proximity);
// do both eyes
strip.setPixelColor(i, color);
if (mirroredEyes)
{
strip.setPixelColor(38 - i, color);
}
else
{
strip.setPixelColor(38 - i, color);
}
}
else // all others are off
{
strip.setPixelColor(i, 0);
if (mirroredEyes)
{
strip.setPixelColor(38 - i, 0);
}
else
{
strip.setPixelColor(38 - i, 0);
}
}
}
// Now show it!
strip.show();
}
// choose a color based on the compass heading and proximity to "pos".
uint32_t selectColor(float heading, float proximity)
{
uint32_t color;
// Choose eye color based on the compass heading
if (heading < 30)
{
color = strip.Color(255, 0, 0);
}
else if (heading < 60)
{
color = strip.Color(0, 255, 255);
}
else if (heading < 90)
{
color = strip.Color(127, 0, 255);
}
else if (heading < 120)
{
color = strip.Color(128, 255, 0);
}
else if (heading < 150)
{
color = strip.Color(255, 0, 128);
}
else if (heading < 180)
{
color = strip.Color(0, 255, 64);
}
else if (heading < 210)
{
color = strip.Color(0, 21, 255);
}
else if (heading < 240)
{
color = strip.Color(255, 191, 0);
}
else if (heading < 270)
{
color = strip.Color(255, 0, 0);
}
else if (heading < 300)
{
color = strip.Color(0, 255, 255);
}
else if (heading < 330)
{
color = strip.Color(127, 0, 255);
}
else // 300-360
{
color = strip.Color(128, 255, 0);
}
}
// monitor orientation for mode-change 'gestures'
void pattern(sensors_event_t event)
{
accel.getEvent(&event);
x=event.acceleration.x;
y=event.acceleration.y;
z=event.acceleration.z;
f= sqrt(x*x+y*y+z*z);
if (f > 25)
int p = random(2); // choose one of 5 random patterns
switch (p)
{
case 1:
spin(strip.Color(255,0,0), 1, 500);
break;
case 2:
spin(strip.Color(0,0,255), 1, 500);
break;
}
}
// Reset to default
void resetModes()
{
/// spin-up
spin(strip.Color(255,0,0), 1, 500);
spin(strip.Color(0,255,0), 1, 500);
spin(strip.Color(0,0,255), 1, 500);
spinUp();
}
// gradual spin up
void spinUp()
{
for (int i = 300; i > 0; i -= 20)
{
spin(strip.Color(255,0,0), 1, i);
}
pos = 0;
// leave it with some momentum and let it 'coast' to a stop
MomentumH = 3;
}
void spinUpB()
{
for (int i = 150; i > 0; i -= 20)
{
spin(strip.Color(0,255,0), 1, i);
}
pos = 0;
// leave it with some momentum and let it 'coast' to a stop
MomentumH = 3;
}
// Gradual spin down
void spinDown()
{
for (int i = 1; i < 30; i++)
{
spin(strip.Color(255,0,0), 1, i += 20);
}
// Stop it dead at the top and let it swing to the bottom on its own
pos = 0;
MomentumH = MomentumV = 0;
}
void spinDownB()
{
for (int i = 1; i < 30; i++)
{
spin(strip.Color(0,0,255), 1, i += 20);
}
// Stop it dead at the top and let it swing to the bottom on its own
pos = 0;
MomentumH = MomentumV = 0;
}
// utility function for feedback on mode changes.
void spin(uint32_t color, int count, int time)
{
for (int j = 0; j < count; j++)
{
for (int i = 0; i < 39; i++)
{
strip.setPixelColor(i, color);
strip.setPixelColor(38 - i, color);
strip.show();
delay(max(time / 39, 1));
strip.setPixelColor(i, 0);
strip.setPixelColor(38 - i, 0);
strip.show();
}
}
}