/*
* Destresser by Robert "Zach"arias (rzachari@andrew.cmu.edu)
* version 1.1, 9/15/15
*
* Summary: Arduino with attached mic, which is positioned on a table surface,
* reads the tempo of tapping sounds on that table. If the tapping tempo is slow
* or absent, the indicator shows green. If the tempo is mid-pace, the indicator
* shows yellow. And if the tapping becomes very fast, the indicator shows
* red and triggers a servomotor to swab the user's forehead with a moist sponge.
* (The servo is mounted on the visor of the user's cap.)
*
* Tempo is measured by the gap between taps, which I call opmet (haha),
* smoothed by a simple exponential decay algorithm.
*
* 9V is run into the Arduino's VIN, and 5V at about 1A is run to the small hobby
* servo, with the grounds tied together.
*
* Project for 48-739 "Making Things Interactive" at Carnegie Mellon, taught by
* Jake Marsico.
*
* Released to the public domain by the author.
*/
#include <Servo.h>
Servo myservo;
int micPin = A3; // simple electret with built-in amp, threshold set to trigger when table tapped
int blinker = 13; // for debugging; will light when a tap is detected
int servoPin = 9;
// LEDs
int redLED = 5;
int yellowLED = 6;
int greenLED = 7;
int micThreshold = 800; // cuts out most noise
int minBetweenTaps = 70; // 70 milliseconds between taps, to remove echoes
float weightOfNewData = 0.75; // closer to 1 biases towards old data, closer to 0 biases towards new data
unsigned long tapTime = 0; // will be set to millis() when tap is detected
unsigned long prevTapTime = 0; // stores the prior tap time value
unsigned long diff = 0; // stores the difference between the prior and current tap times
unsigned long runningAvg = 1000; // stores smoothed opmet data in ms, initialized to 1 second
int sleepTimer = 5000; // how long to wait before going into sleep mode, in ms
int longWait = 500; // long gap between taps, in ms
int shortWait = 170; // short gap between taps, in ms
// servo positions
int restPos = 0; // resting position
int middlePos = 70; // in between taps position
int headPos = 95; // tapping forehead position, empirically derived
int counter = 0;
void setup() {
pinMode(micPin, INPUT);
pinMode(blinker, OUTPUT);
pinMode(redLED, OUTPUT);
pinMode(yellowLED, OUTPUT);
pinMode(greenLED, OUTPUT);
myservo.attach(servoPin);
myservo.write(restPos);
Serial.begin(9600);
}
void loop() {
int micRead = analogRead(micPin);
// if "tap" sound, i.e. mic reads high value, record timer value and do math to recalculate opmet
if (micRead >= micThreshold) {
digitalWrite(blinker, HIGH); // board blinks for debugging
tapTime = millis(); // draw line in sand
diff = tapTime - prevTapTime; // calculate distance from last line in sand
prevTapTime = millis(); // make the new line in the sand
// simple exponential decay to calculate running average
runningAvg = (diff * (1 - weightOfNewData)) + (runningAvg * weightOfNewData);
Serial.print("runningAvg = "); Serial.println(runningAvg);
delay(minBetweenTaps); // cuts out hearing the same tap twice or thrice in a row
digitalWrite(blinker, LOW);
}
if (runningAvg > longWait) {
green();
}
else if (runningAvg <= longWait && runningAvg > shortWait) {
yellow();
}
else {
red();
headPad();
}
/*if you don't hear anything for a while, simulate one tap per second
to go back to green and not skew average opmet too far upwards */
if (counter == 100 && millis() - prevTapTime > sleepTimer) {
counter = 0; // reset counter
Serial.println("sleeping");
runningAvg = 1000; // pretend the average opmet is one second
}
counter++; // implemented because sleep procedure was eating up too many cycles
}
void red() {
digitalWrite(redLED, HIGH);
digitalWrite(yellowLED, LOW);
digitalWrite(greenLED, LOW);
}
void yellow() {
digitalWrite(redLED, LOW);
digitalWrite(yellowLED, HIGH);
digitalWrite(greenLED, LOW);
}
void green() {
digitalWrite(redLED, LOW);
digitalWrite(yellowLED, LOW);
digitalWrite(greenLED, HIGH);
}
void headPad() {
// blocking code that swabs the forehead
myservo.write(headPos);
delay(500);
myservo.write(middlePos);
delay(500);
myservo.write(headPos);
delay(500);
myservo.write(middlePos);
delay(500);
myservo.write(headPos);
delay(500);
myservo.write(restPos);
// restore baseline 1000 opmet value
runningAvg = 1000;
}
Click to Expand
Content Rating
Is this a good/useful/informative piece of content to include in the project? Have your say!
You must login before you can post a comment. .