The Code
// Make Stuff Move | Animate Shield v8.0
// This is the code that comes preloaded on our animate shield/Arduino board combo
int VERSION = 2;
#include <Adafruit_NeoPixel.h>
#include <Servo.h>
#include <EEPROM.h>
// Setup the LED
#define LED_PIN 7
#define LED_COUNT 1
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
#define MIC_PIN A5
int mic_value;
int curr_level = 0;
int prev_level = 0;
int servo_level = 0;
int light_level = 0;
int is_beat = 0;
int mic_cut_default = 180;
int mic_cut = 180;
// min and max values from the sensor
int vol_min = 300;
int vol_max = 600;
// Cabibration of min and max values from analog
#define ANALOG_MAX 1023
#define ANALOG_MIN 0
#define SERVO_MIN 2
#define SERVO_MAX 178
// Delay between reading for recording movement
int frame = 0;
int playSpeed = 50; // in ms, 50ms seems good
#define FRAME_DELAY 50 // in ms, 50ms seems good
#define FRAME_LIMIT 1024 // number of samples to store
// Arduino Pin assignments
int recordButtonPin = 12;
int playButtonPin = 11;
int ledPin = 13;
int ledState = 0;
int servoPinA = 8;
int servoPinB = 9;
int servoPinC = 10;
int knobPinA = A0;
int knobPinB = A1;
int knobPinC = A2;
// Variables for record/play state
int repeat = 1;
int playing = 0;
int recording = 0;
long pressTime = 0;
// Create the servo objects
Servo myServoA;
Servo myServoB;
Servo myServoC;
void setup() {
Serial.begin(9600);
Serial.println("Make Stuff Move | 3 Servo Record and Play");
pinMode(recordButtonPin, INPUT);
digitalWrite(recordButtonPin, HIGH);
pinMode(playButtonPin, INPUT);
digitalWrite(playButtonPin, HIGH);
pinMode(ledPin, OUTPUT);
pinMode(knobPinA, INPUT);
pinMode(knobPinB, INPUT);
pinMode(knobPinC, INPUT);
myServoA.attach(servoPinA);
myServoB.attach(servoPinB);
myServoC.attach(servoPinC);
//Light
strip.begin();
strip.show();
versionBlink(VERSION);
}
void loop() {
// Check for the play button being clicked or held
if (digitalRead(playButtonPin) == LOW) {
pressTime = 0;
while (digitalRead(playButtonPin) == LOW) {
delay(1000);
pressTime = pressTime + 1;
}
if (pressTime < 2) {
Serial.println("PLAY ONLY");
playServos(playButtonPin);
}
else {
Serial.println("PLAY DANCE");
playServosDance(playButtonPin);
}
pressTime = 0;
}
// Check for Record button
else if (! digitalRead(recordButtonPin)) {
delay(10);
// wait for released
while (! digitalRead(recordButtonPin)) {
delay(100);
// OK released!
}
Serial.println("RECORD");
recordServos(recordButtonPin);
}
// Otherwise just read the knobs to move the servos
else {
moveServos();
}
}
// Move Function -------------------------------------------------------------------------
void moveServos() {
// Read the value from the mic
int mic_value = analogRead(MIC_PIN);
//Serial.print("MIC | ");
//Serial.println(mic_value);
curr_level = map(mic_value, vol_min, vol_max, 0, 100);
// If the current level is lower than the previous level fade the pixel and move the meter down
// This provides a smoother movement
if (curr_level < prev_level) {
curr_level = prev_level - 2;
// Don't let the level drop below zero
if (curr_level < 0) {
curr_level = 0;
}
}
// Enable the following to get visual output in the Serial Monitor
// Warning this slows down the servo ...adds lag
/*
for (int i = 0; i <= curr_level/5; i++) {
Serial.print("|");
}
Serial.println("|");
*/
int a = analogRead(knobPinA);
int b = analogRead(knobPinB);
int c = analogRead(knobPinC);
int red = map(a, ANALOG_MIN, ANALOG_MAX, 255, 0);
int green = map(b, ANALOG_MIN, ANALOG_MAX, 255, 0);
int blue = map(c, ANALOG_MIN, ANALOG_MAX, 255, 0);
light_level = map(curr_level, 0, 100, 0, 50);
light_update(red, green, blue, light_level);
a = map(a, ANALOG_MIN, ANALOG_MAX, SERVO_MIN, SERVO_MAX);
myServoA.write(a);
b = map(b, ANALOG_MIN, ANALOG_MAX, SERVO_MIN, SERVO_MAX);
myServoB.write(b);
//c = map(c, ANALOG_MIN, ANALOG_MAX, SERVO_MIN, SERVO_MAX);
//myServoC.write(c);
int servo_meter = map(curr_level, 0, 100, SERVO_MAX, SERVO_MIN);
myServoC.write(servo_meter);
Serial.print("SERVO | ");
Serial.println(servo_meter);
prev_level = curr_level;
}
// Play Function Dance
void playServosDance(int buttonPin) {
Serial.println("Playing and Dancing");
frame = 0;
playing = 1;
digitalWrite(ledPin, HIGH);
while (digitalRead(buttonPin) == HIGH) {
//Allow for beat cut-in value to be adjusted with holding record and knob A
if (digitalRead(recordButtonPin) == LOW) {
mic_cut = analogRead(knobPinA);
mic_cut = map(mic_cut, ANALOG_MIN, ANALOG_MAX, 300, 50);
Serial.print("mic_cut: ");
Serial.println(mic_cut);
}
// Read the value from the mic
int mic_value = analogRead(MIC_PIN);
//Serial.print("MIC: ");
//Serial.println(mic_value);
// Set the cutoff value and if lower, fade the current level for the servo and led
if (mic_value > mic_cut) {
is_beat = 1;
curr_level = 50;
}
else {
is_beat = 0;
curr_level = prev_level - 7;
}
int a = EEPROM.read(frame + 0);
int b = EEPROM.read(frame + 1);
int c = EEPROM.read(frame + 2);
// Check for stop/loop frame
if (a == 255 or b == 255 or c == 255) {
frame = 0;
Serial.println("loop");
continue;
}
if (frame == 0 and is_beat == 0) {
//Serial.println("waiting");
}
else {
if (frame == 0) {
Serial.println("BEAT!!");
}
frame = frame + 3;
}
myServoA.write(a);
myServoB.write(b);
myServoC.write(c);
int red = map(a, 0, 180, 255, 0);
int green = map(b, 0, 180, 255, 0);
int blue = map(c, 0, 180, 255, 0);
light_update(red, green, blue, 50);
delay(playSpeed);
prev_level = curr_level;
}
Serial.println("Stoped Playing");
//reset the mic_cut
mic_cut = mic_cut_default;
delay(200);
digitalWrite(ledPin, LOW);
}
// Play Function Frames -------------------------------------------------
void playServos(int buttonPin) {
Serial.println("Playing");
frame = 0;
playing = 1;
digitalWrite(ledPin, HIGH);
while (digitalRead(buttonPin) == HIGH) {
int a = EEPROM.read(frame + 0);
int b = EEPROM.read(frame + 1);
int c = EEPROM.read(frame + 2);
int red = map(a, 0, 180, 255, 0);
int green = map(b, 0, 180, 255, 05);
int blue = map(c, 0, 180, 255, 0);
light_update(red, green, blue, 50);
// Check for stop/loop frame
if (a == 255 or b == 255 or c == 255) {
frame = 0;
if (repeat == 1) {
Serial.println("loop");
continue;
}
else {
Serial.println("stop");
break;
}
}
myServoA.write(a);
myServoB.write(b);
myServoC.write(c);
// Set speed from first knob A0 while the recordbutton is held down during playback
if (! digitalRead(recordButtonPin)) {
playSpeed = analogRead(knobPinA);
playSpeed = map(playSpeed, ANALOG_MIN, ANALOG_MAX, 100, 0);
}
delay(playSpeed);
frame = frame + 3;
}
Serial.println("Stoped Playing");
delay(200);
digitalWrite(ledPin, LOW);
}
// Record Function -------------------------------------------------
void recordServos(int buttonPin) {
frame = 0;
Serial.println("Recording");
while (digitalRead(buttonPin)) {
//int last_a = a;
int a = analogRead(knobPinA);
// Create a smoothing by looking at the difference between values
// ie if change is not more than say 5 then do not make a change.
a = map(a, ANALOG_MIN, ANALOG_MAX, 0, 180);
myServoA.write(a);
EEPROM.write(frame, a);
int b = analogRead(knobPinB);
b = map(b, ANALOG_MIN, ANALOG_MAX, 0, 180);
myServoB.write(b);
EEPROM.write(frame + 1, b);
int c = analogRead(knobPinC);
c = map(c, ANALOG_MIN, ANALOG_MAX, 0, 180);
myServoC.write(c);
EEPROM.write(frame + 2, c);
Serial.print(frame);
Serial.print(" | ");
Serial.print(a);
Serial.print(",");
Serial.print(b);
Serial.print(",");
Serial.print(c);
Serial.println("");
int red = map(a, 0, 180, 255, 0);
int green = map(b, 0, 180, 255, 0);
int blue = map(c, 0, 180, 255, 0);
light_update(red, green, blue, 50);
if (frame == FRAME_LIMIT) break;
frame = frame + 3;
// Only take a reading every so many miliseconds to store
delay(FRAME_DELAY);
// Blink the light
if (ledState == 0) {
digitalWrite(ledPin, HIGH);
ledState = 1;
}
else {
digitalWrite(ledPin, LOW);
ledState = 0;
}
}
Serial.println("Stopping Rcording");
// If we stop before the end of the storage limit, store 999 so the play funciton will know when to loop.
if (frame != FRAME_LIMIT) {
Serial.println("Adding Loop Frame");
//Set an arbitrary frame number that we will never store ir "999"
EEPROM.write(frame, 255);
}
digitalWrite(ledPin, LOW);
Serial.println("Finished Recording");
delay(500);
}
void light_update(int red, int green, int blue, int brightness) {
uint32_t color = strip.Color(red, green, blue);
strip.setBrightness(brightness);
strip.fill(color, 0, LED_COUNT);
strip.show();
}
void versionBlink(int codeVersion) {
int ledBlink = 0;
for (int i = 0; i < codeVersion * 2; i++ ) {
if (ledBlink == 0) {
light_update(50, 255, 0, 0);
ledBlink = 1;
delay(200);
}
else {
light_update(50, 255, 0, 50);
ledBlink = 0;
delay(300);
}
}
}