Pressure Coaster

Assignment: Sensing PART II: Force Sensitive Resistors and Photocells

Collaborators:

Assignment: Sensing PART II: Force Sensitive Resistors and Photocells
Collaborators:

Assignment: Sensing PART II: Force Sensitive Resistors and Photocells
Collaborators:

Overview:

I combined the mechanical and programming sections into a single project - a pressure-sensitive coaster that allows me to visualize consuming a cup of tea.

Description:

The user twists a potentiometer to manipulate the colors of three LEDs. The circle of the potentiometer corresponds to the perimeter of an RGB color wheel - the colors of the LEDs change according to the position. A diffuser on top blends the colors together.

A force sensor on a separate circuit is attached to a beverage coaster. Software on the arduino board detects whenever a cup is lifted off of the coaster via the large change in the force sensor reading. When this happens, arduino transmits the current RGB values of the LED lights over the serial cable.

Processing software on the computer listens for RGB triplets. Whenever a new RGB triplet is received, the software adds a moving circle to an existing field with a corresponding color. The moving circle code is based off of the 'Bounce' example.

As the user takes sips from their cup (lifting and replacing the mug), the number of circles grows. Twisting the potentiometer gradually with time can result in a pleasing variety of colorful bouncing circles. Photos of the board and a screenshot are at the end.

 

Materials:

Arduino

LEDs X 3

Resistors

Potentiometer

Force Sensor

Diffuser

Coaster

Bubble wrap (to make the coaster more squishy)

A dime (to provide a firm back for the force sensor)

Tape

Lots of wires

Code

Arduino:

/*

* use one pot to fade between colors

*/
int coffeePin = 1; // set the input pin for the coaster
int potPin = 2;   // set the input pin for the potentiometer
int ledPin = 9;   // green
int ledPin2 = 6; // blue
int ledPin3 = 11; // red
int val = 0;      // initialize variable to store the value coming from the sensor
int red = 0; //initilaize variables to store the different color values
int blue = 0;
int green = 0;
int mugThere = 255; // initialize a variable that for detecting the presence of a mug
int lastMugReading = 255; // initialize a variable for remembering the last mug reading

void setup() {
Serial.begin(9600); // Turn on the serial
}

void loop() {

/* we're mapping values to a color wheel
0 is full red
170 is half red, half blue
341 is full blue
511 is half blue, half green
682 is full green
852 is half green, half red

A note on the math:
For the purpose of this assignment, I've divided the sensor input into thirds, each of size 341 (technically 342 for the first and last third)
Dividing 255 (an LED range) by 341 (the the span of a sensor range) we get a multiplier we can use against the pot value to normalize output based on the range
*/

val = analogRead(potPin);    // read the value from the pot, between 0 - 1024
if (val < 341) { //we're in the first third of the sensor range
red = 255 - val*(255.0/341); //red's total brightness is based on the distance from zero (further from zero is less bright)
blue = val*(255.0/341); //blue's total brightness is also based on the distance from zero (further form zero is more bright)
//blue = 50;
green= 000; //each step only covers a fade between two colors (the third color is off)
}

else if (val < 682) { // we're in the middle third of the sensor range
red = 0000; //red is off now
blue = 255 - (val-341)*(255.0/341); //blue gets fainter as we get away from the bottom of this range
//blue = 000;
green = (val-341)*(255.0/341);//green gets brighter as we get away from the bottom of this range.
}

else  { //we're in the last third of the sensor range
red = (val-682)*(255.0/341); // red grows as it gets further from bottom fo this range
blue = 000; // blue is off
green = 255 - (255.0/341)*(val-682); //green fades
}
analogWrite(ledPin, green); // write the red value
analogWrite(ledPin2, blue); // write the blue value
analogWrite(ledPin3, red); // write the green value

mugThere = analogRead(coffeePin); // read the value of the potentiometer

if(mugThere + 250 < lastMugReading) { // a 'mugThere' reading significantly lower than the 'lastMugReading' indicates that the cup has recently been lifted.
//We add 250 to the 'mugThere' reading to help false positives caused by small shifts in weight.
//if we detect a mug lift, we want to print out a comma delimited list of RGB values to be read by the processing software.
Serial.print(red);
Serial.print(',');
Serial.print(blue);
Serial.print(',');
Serial.print(green);
Serial.println();
lastMugReading = mugThere; //we now need to update the lastMugReading to reflect the fact that the cup has been lifted. Failure to do so will cause the serial to fire continuously.
}

if (mugThere > 350) { //If the mugThere value is higher than 350, the mug is back on the coaster
lastMugReading = mugThere; //Callibrate the lastMugReading based on the current weight of the mug.
}
}

 

Processing:

/**
* Bounce.
*
* When the shape hits the edge of the window, it reverses its direction.
*/
import processing.serial.*;
String portname = "/dev/cu.usbserial-A9007LR8";
Serial port;
float[] black = {0,0,0};
class Circle { // Define a circle class
float size; // Define size property
float xpos, ypos;    // Define position properites  
float xspeed;  // Define shape speed properties
float yspeed; 
int xdirection;  // Define direction properties
int ydirection;
float[] colors = {0,0,0}; // Define a color array

Circle(float[] tempc, int tsize) { //Constructor function
size = tsize;  //circle size is passed in
xspeed = 2.8;  // Speed of the shape
yspeed = 2.2;  // Speed of the shape
xdirection = 1;  // Left or Right
ydirection = 1;  // Top to Bottom
colors[0] = tempc[0]; //set colors based on the colors passed in
colors[1] = tempc[1];
colors[2] = tempc[2];
xpos = width/2;
ypos = height/2;
}

void display()
{
// Update the position of the shape
xpos = xpos + ( xspeed * xdirection );
ypos = ypos + ( yspeed * ydirection );

// Test to see if the shape exceeds the boundaries of the screen
// If it does, reverse its direction by multiplying by -1
if (xpos > width-size || xpos < 0) {
xdirection *= -1;
}
if (ypos > height-size || ypos < 0) {
ydirection *= -1;
}
fill(colors[0],colors[2],colors[1]);
// Draw the shape
ellipse(xpos+size/2, ypos+size/2, size, size);
}

}

java.util.ArrayList someCircles;

void setup()
{
port = new Serial(this, portname, 9600);
size(640, 400); // define the display size
noStroke(); // set stroke to none
frameRate(30);
smooth();
someCircles = new ArrayList(); // Initialize an array to hold our circles.
// Set the starting position of the shape
}
void draw()
{
background(255); // Recolor the background to white (failure to do this causes circles to streak
for (int i = someCircles.size()-1; i >= 0; i--) { //For each circle (starting with last)
Circle tcircle = (Circle) someCircles.get(i); // Retrieve the circle
tcircle.display(); //Draw the circle
}
}

void serialEvent(Serial p) { //Detect serial events
String inString = port.readStringUntil('\n'); //Get our commands by reading whole lines from the serial
if (inString != null) {
// trim off any whitespace:
inString = trim(inString);
// split the string on the commas and convert the
// resulting substrings into an integer array:
float[] colors = float(split(inString, ","));
// if the array has at least three elements, you know
// you got the whole thing. 
if (colors.length >=3) {
someCircles.add(new Circle(colors, 30));
//create a new circle with the colors passed in on the serial
//someCircles.add(new Circle(black,10)); // This is a cute black circle. I've turned it off for now.
}
}
}

Pictures:

Complete circuit and all parts

Complete circuit, potentiometer, force sensing coaster, and tea mug

Closeup of circuit

Close-up view of circuit.

Detail of bottom of coaster

Underside of coaster. Notice bubble wrap on corners and center (to make it "squishier"), and the dime taped to the underside of the FSR to improve sensitivity.

Screenshot of circles after drinking a cup of tea

This is what my screen looked like after I drank a cup of tea on the coaster, turning the pot dial every few minutes. Reds were the start of the cup, blues were the middle, and greens/greenish reds were the end. Note that these balls are animated; they bounce around the screen on a normal run.