The Anatomy:
The device:
Friday Night Tights is wearable technology that addresses the dangers of drunk walking. Many Americans have a false sense of security that, by avoiding driving under the influence, they are safe to walk while intoxicated. Yet fatalities are in fact high among drunk pedestrians who walk into traffic.The system houses an Arduino device inside a fanny pack attached to the tights' hip, and runs wires down to pressure sensors which slip into the wearer's shoes.
When the system detects walking patterns that indicate severe levels of intoxication, it emits a subtle LED light up in the pouch, and syncs wirelessly with an Android phone, to send a text message to a predesignated friend or cab company of the wearer's whereabouts.
The algorithm:
We define an inebriate's type of imbalance as marked by quick, light steps, followed rapidly by long, heavy compensating steps. 2 warnings are allowed before, on the 3rd round, the response is triggered.
When the Arduino has access to video output, it can provide serial monitoring results like:
the device's serial output |
The Code:
// Our algorithm detects drunk walking by tracking sudden shifts of imbalance.
// We define an inebriate's type of imbalance as marked by quick, light steps,
// followed rapidly by long, heavy compensating steps. 2 warnings are allowed
// before, on the 3rd round, the response is triggered.
// LIBRARIES
#include <QueueArray.h> // FIFO stack
// ANALOG DATA: Left Foot
const int analogInPin1 = A0; // Force Pressure Sensor at A0
//const int analogOutPin1 = 9; // LED at variable pin 10
int sensorValue1 = 0; // value from variable sensor
int LeftValue = 0; // value from output to analog out
// ANALOG DATA: Right Foot
const int analogInPin2 = A1; // Force Pressure Sensor at A1
//const int analogOutPin2 = 10; // LED at variable pin 9
int sensorValue2 = 0; // value from variable sensor
int RightValue = 0; // value from output to analog out
// QUEUE: a custom First-In-First-Out array
class QueueNode
{
public:
QueueNode(int val, QueueNode* next)
{
_val = val;
_next = next;
}
int _val;
QueueNode* _next;
};
class Queue
{
public:
Queue()
{
head = NULL;
}
void Append(int val) // ~ QueueArray.push()
{
QueueNode* qn = new QueueNode(val, head);
head = qn;
};
void Clear() // ~ QueueArray.clear()
{
QueueNode* cur = head;
head = NULL;
while (cur != NULL)
{
QueueNode* next = cur->_next;
delete cur;
cur = next;
}
}
QueueNode* Pull() // ~ QueueArray.pop()
{
QueueNode* cur = head;
head = NULL;
QueueNode* next = cur->_next;
cur = next;
delete cur;
return cur;
}
float Average() // return a numerical average
{
int cnt = 0;
int sum = 0;
QueueNode* cur = head;
while (cur != NULL)
{
cnt++;
sum += cur->_val;
cur = cur->_next;
}
if (cnt == 0)
return 0.0;
else
return (float)sum/(float)cnt;
}
int Count() // return the total items in Queue
{
int cnt = 0;
QueueNode* cur = head;
while (cur != NULL)
{
cnt++;
cur = cur->_next;
}
return (int)cnt;
}
private:
QueueNode* head;
};
// GLOBALS
Queue PressureQ = Queue(); // Queue of current step's pressure values
Queue DrunkTrackerQ = Queue(); // Instances of drunk-like behavior before drunk alarm goes off.
float currPressureAvg = 0.00; // float of current step's average pressure
float prevPressureAvg = 0.00; // float of previous step's average pressure
int currPace = 0; // int of current step's pace length
int prevPace = 0; // int of previous step's pace length
int loopNum = 0;
int drunkSteps = 3;
int warnBlinks = 0;
//LED OUTS:
int ledPin1 = 9;
int ledPin2 = 10;
// DETECT: This function collects the pressure and timing of each step. One step is the combination of pressure that is greater than 0 followed by 0 pressure. Pacing is measured as the duration of each step.
void DetectStep(int outputValue)
{
if ( outputValue != 0 ) // Record pressure values during a foot step
{
PressureQ.Append(outputValue);
Serial.print("\tpressure: \t");
Serial.println(outputValue);
}
else // At the end of the footstep, calculate the step's average pressure
{
currPace = PressureQ.Count(); // And record the footstep's length
currPressureAvg = PressureQ.Average();
PressureQ.Clear();
Serial.print("\tpressure average: \t");
Serial.println(currPressureAvg);
Serial.print("\tpace: \t");
Serial.println(currPace);
}
}
// FLAG: Function flags instances of a very short and light step being followed immediately by a long and heavy step
void Flag( float currPressureAvg, int currPace )
{
if ( (prevPace >= (currPace/2)) && ( prevPace != 0 ) )
{
if ( currPressureAvg >= (prevPressureAvg/2) )
{
drunkSteps--; // Give a set number of warnings
warnBlinks++;
Serial.print("you kinda drunk...but we gonna give you ");
Serial.print(drunkSteps);
Serial.println(" more chances.");
// Blink with # blinks = # warnings
for (int i=0; i++; i<warnBlinks){
digitalWrite(ledPin1, HIGH); // Turn the LED on (HIGH is the voltage level)
delay(750); // Wait
digitalWrite(ledPin1, LOW); // Turn the LED off by making the voltage LOW
delay(750); // Wait
}
}
}
}
// RESPOND: This function calls DETECT and FLAG and triggers a response if no warnings are left.
void respond(int outputValue)
{
pinMode(ledPin1, OUTPUT); // LED pins to output
pinMode(ledPin2, OUTPUT);
DetectStep(outputValue); // Detect steps
Flag(currPressureAvg, currPace); // Flag for drunkenness
prevPressureAvg = currPressureAvg; // Step forward on pressure
prevPace = currPace; // Step forward on pace
// RESPONSE NECESSARY
if (drunkSteps == 0)
{
// Just blink like cray
Serial.println("YEAH YOU SHITFACED...LEDs and whatever");
digitalWrite(ledPin1, HIGH); // Turn the LED on (HIGH is the voltage level)
delay(500); // Wait for half a second
digitalWrite(ledPin1, LOW); // Turn the LED off by making the voltage LOW
delay(500); // Wait for half a second
}
}
// SETUP WITH SERIAL MONITORING
void setup(){
Serial.begin(9600);
}
// MAIN LOOP:
void loop()
{
QueueArray <int> LeftRight;
Serial.print("loop: \t");
Serial.println(loopNum);
loopNum++;
// READ: analog values
sensorValue1 = analogRead(analogInPin1); // Read in input from left foot
LeftValue = map(sensorValue1, 0, 256, 0, 50); // Map the lower-bound 0-256 to the range 0-50
//analogWrite(analogOutPin1, LeftValue); // Change the analog out value
sensorValue2 = analogRead(analogInPin2); // Read in input from right foot
RightValue = map(sensorValue2, 0, 256, 0, 50); // Map the lower-bound 0-256 to the range 0-50
//analogWrite(analogOutPin2, RightValue); // Change the analog out value
LeftRight.push(LeftValue);
LeftRight.push(RightValue);
//while ( !LeftRight.isEmpty() )
//{
int outputValue = LeftRight.pop();
respond(LeftRight.pop());
//}
delay (1000); // Half second cycles
}
References:
Traffic Safety Facts 2009 Data. U.S. Department of Transportation, National Highway Traffic Safety Administration
The Perils of Drunk Walking: A New Marketplace Podcast
Freakonomics: What Went Right? Responding to Wrong-Headed Attacks
Flexiforce Sensors Screening Athlete's Feet at the Special Olympics. These are the force pressure sensors we researched and used.
Android Bluetooth to Arduino. For the text messaging response.
Investigator: Breathalyzer found to be inaccurate, unreliable. An investigative article on the inaccuracies of breathalyzers, which contributed to our decision to stay away from using alcohol breath detection.
The Perils of Drunk Walking: A New Marketplace Podcast
Freakonomics: What Went Right? Responding to Wrong-Headed Attacks
Flexiforce Sensors Screening Athlete's Feet at the Special Olympics. These are the force pressure sensors we researched and used.
Android Bluetooth to Arduino. For the text messaging response.
Investigator: Breathalyzer found to be inaccurate, unreliable. An investigative article on the inaccuracies of breathalyzers, which contributed to our decision to stay away from using alcohol breath detection.
Flexiforce Quickstart Guide. For working with flexiforce and Arduino
QueueArray. library for FIFO queue.
C++
Artefact Wearable Tech Movement. The wearable tech movement look and appeal that inspired our attention to chic over kitsch.
No comments:
Post a Comment