Very Light Tea
Made by rkandala
Made by rkandala
The design challenge for this project was to find a nonsensical ambient noise and translate that into a digital output (e.g. light, motion, etc.) through signal processing. For my project I chose to listen to tea boiling and translate the noise into patterns on LEDs that was expressive and reflective of the water boiling in a tea kettle.
Created: September 17th, 2015
//***********************
//Audio+Smoothing Stuff
//***********************
const int numReadings = 10;
int readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
int micPin = A0;
int micVal;
//**************
//NeoPixel Stuff
//**************
#include <Adafruit_NeoPixel.h> //include the neopixel library
//declarations
#define PIXEL_PIN 3
#define NUMPIXELS 12
Adafruit_NeoPixel ring = Adafruit_NeoPixel(NUMPIXELS, PIXEL_PIN, NEO_GRB + NEO_KHZ800); //initialize neopixel object
//colors
uint32_t ringColor;
uint32_t blank = ring.Color(0,0,0);
uint32_t coldBlue = ring.Color(10,10,255);
uint32_t doneGreen = ring.Color(10,255,10);
int r; int g; int b;
//************
//State Logic
//************
int state = 0;
int timer = 0;
#define THRESHOLD 130
int signalTimer =0;
int signalLength = 100;
boolean signalLost = false;
//state 0 - on
int lightState[]={1,0,0,0,0,0,0,0,0,0,0,0};
int minPos=0;
boolean startAnim = false;
int onTimer;
int onDelay=20;
int onEnd = 725; //750-870
//state 1 - build
int buildEnd = 3200;//ends @ 3650; 2850-3200
//int buildEnd = 380;
//state 2 - bubble
int bubbleEnd = 500;//ends @ 4150
//int bubbleEnd = 450;
int bubbleTimer=0;
int bubblePtrn[4][NUMPIXELS] = { {1,0,1,0,1,0,1,0,1,0,1,0},
{0,0,0,1,1,1,1,1,1,0,0,0},
{0,1,0,1,0,1,0,1,0,1,0,1},
{1,1,1,0,0,0,0,0,0,1,1,1} };
int ptrnState=0;
//state 3 - off
int offTimer=0;
//int offDelay = 150;
int resetDelay = 150;
int bright;
int showPixel;
void setup(){
ring.begin();
ring.setBrightness(50);
ring.show();
Serial.begin(9600);
}
void loop(){
//smoothing
micVal = smoothing();
delay(1); // delay in between reads for stability
//state animations
if(state == 0){state0ON();timer++;}
else if(state == 1){state1Build(); timer++;}
else if(state == 2){state2Bubble(); timer++;}
else if(state == 3){state3OFF(); timer++;}
else{checkSignal();timer++;}
debugger();
}
void checkSignal(){
//checking signal frequency
if(micVal<THRESHOLD){signalTimer++;}
else if(micVal>=THRESHOLD){signalTimer=0;signalLost = false;}
if(signalTimer>=signalLength && !signalLost){signalLost=true;}
}
void state0ON(){
if(micVal>=THRESHOLD){startAnim = true;} //check if audio has changed
if(startAnim && onTimer<=onDelay){
minPos = map(onTimer,0,onDelay,0,NUMPIXELS);
//updatePixels
for(int i=0;i<NUMPIXELS;i++)
{
if(i<=minPos){lightState[i]=1;}
else{lightState[i]=0;}
}
//drawPixels
for(int i=0;i<NUMPIXELS;i++)
{
ring.setPixelColor(i,blank);
if(lightState[i]>0){
ring.setPixelColor(i,coldBlue);
}
}
ring.show();
onTimer++;
}
else if(onTimer>onDelay){
lightState[0]=1;
minPos=0;
startAnim=false;
onTimer=0;
}
if(timer>=onEnd){
state=1; timer=0;
resetLED();}
}
void state1Build(){
checkSignal();
// if(timer<=buildEnd){
if(!signalLost){
r = map(timer,0,buildEnd,10,255);
g = map(timer,0,buildEnd,10,0);
b = map(timer,0,buildEnd,255,10);
bright = map(micVal,0,500,10,70);
ringColor = ring.Color(r,g,b);
}
// else if (timer>buildEnd){
else if (signalLost){
ringColor = ring.Color(255,0,0);
state=2; timer=0;
ring.setBrightness(50);
}
for(int i=0;i<NUMPIXELS;i++)
{
ring.setPixelColor(i,ringColor);
}
ring.setBrightness(bright);
ring.show();
}
void state2Bubble(){
if(timer<=bubbleEnd){
if(bubbleTimer%150==0){
ptrnState++;
ptrnState%=4;
r = random(255);
g = random(255);
b = random(255);
ringColor = ring.Color(r,g,b);
}
for(int i =0;i<NUMPIXELS;i++){
if(bubblePtrn[ptrnState][i]>0){ring.setPixelColor(i,ringColor);}
else{ring.setPixelColor(i,blank);}
}
ring.show();
}
else if (timer>bubbleEnd){state=3;bubbleTimer=0;timer=0;}
}
void state3OFF(){
bright = map(offTimer, 0, resetDelay,100,0);
showPixel = map(offTimer, 0, resetDelay,NUMPIXELS,0);
if(offTimer<=resetDelay){
for(int i =0;i<NUMPIXELS;i++){
ring.setBrightness(bright);
if(i<showPixel){ring.setPixelColor(i,doneGreen);}
else{ring.setPixelColor(i,blank);}
}
ring.show();
}
else if(offTimer>resetDelay) {state=0;offTimer=0;timer=0;}
offTimer++;
}
void resetLED(){
for(int i=0;i<NUMPIXELS;i++)
{
ring.setPixelColor(i,blank);
}
ring.show();
}
void debugger(){
Serial.print("raw: ");
Serial.print(analogRead(micPin));
Serial.print("; avg: ");
Serial.print(micVal);
if (state == 1 || state == 4){
Serial.print("; signalT: ");
Serial.print(signalTimer);
Serial.print("; signalS: ");
Serial.print(signalLost);
}
Serial.print("; State: ");
Serial.print(state);
Serial.print("; timer: ");
Serial.println(timer);
}
int smoothing(){
// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = analogRead(micPin);
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;
// calculate the average:
average = total / numReadings;
// send it to the computer as ASCII digits
return average;
}
Click to Expand
When I was exploring the problem space I tried to understand the noise pattern for a range of natural and man-made noises. Ultimately I ended up choosing tea boiling for 2 reasons:
1) Boiling water is a very violent process that is hidden to some degree by the tea kettle but I wanted to make it experienceable somehow.
2) I wanted to create an aesthetic experience that was detached from utility.
For the interactions I coded a few of patterns on the NeoPixel ring to see what patterns had fit the qualities of the water boiling at various stages.
//Early Exploration of LED Patterns
const int numReadings = 10;
int readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
int inputPin = A0;
//neopixel
#include <Adafruit_NeoPixel.h> //include the neopixel library
#define PIXEL_PIN 6
#define NUMPIXELS 12
Adafruit_NeoPixel ring = Adafruit_NeoPixel(NUMPIXELS, PIXEL_PIN, NEO_GRB + NEO_KHZ800); //initialize neopixel object
uint32_t ringColor;
uint32_t blank = ring.Color(0,0,0);
int r=25;
int g=0;
int b=25;
int maxLEDS=0;
int lightState[]={1,0,0,0,0,0,0,0,0,0,0,0};
int minPos=0;
int LEDSpeed = 20;
int timer=0;
void setup(){
// initialize serial communication with computer:
Serial.begin(9600);
// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
//Initialize Ring
ring.begin();
ring.setBrightness(50);
ring.show();
Serial.begin(9600);
}
void loop(){
//Get input signal
int val = cleanSignal();
timer++;
Serial.print("raw: ");
Serial.print(analogRead(inputPin));
Serial.print("; avg: ");
Serial.print(val);
Serial.print("; timer: ");
Serial.println(timer);
delay(1); // delay in between reads for stability
ringPattern(val);
}
void ringPattern(int micVal){
g = map(micVal,33,1023,0,255);
maxLEDS = map(micVal,33,1023,0,NUMPIXELS);
LEDSpeed = map(micVal,33,1023,40,100);
ringColor = ring.Color(r,g,b);
//updatePixels
minPos++;
minPos = minPos%NUMPIXELS;
for(int i=0;i<NUMPIXELS;i++)
{
if(i>=minPos && i<minPos+maxLEDS){lightState[i]=1;}
else{lightState[i]=0;}
}
//drawPixels
for(int i=0;i<NUMPIXELS;i++)
{
ring.setPixelColor(i,blank);
if(lightState[i]>0){
ring.setPixelColor(i,ringColor);
}
}
ring.show();
delay(LEDSpeed);
}
int cleanSignal(){
// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = analogRead(inputPin);
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;
// calculate the average:
average = total / numReadings;
// send it to the computer as ASCII digits
return average;
}
Click to Expand
Making Things Interactive (MTI) is a studio course based on physical prototyping and computing. You will develop novel sensing, interaction and display techniques through projects and short assignm...more
The design challenge for this project was to find a nonsensical ambient noise and translate that into a digital output (e.g. light, motion, etc.) through signal processing. For my project I chose to listen to tea boiling and translate the noise into patterns on LEDs that was expressive and reflective of the water boiling in a tea kettle.