Clink!
Made by monishag, Travis Chambers, Brian Yang and Shaan
Made by monishag, Travis Chambers, Brian Yang and Shaan
IoT that allows you to clink glasses with your drinking buddy no matter where you two are.
Created: March 7th, 2017
We hit a wall when started to explore product ideas that could make long-distance relationships more intimate. In a changing world where technology has brought loved ones closer through cheap travel and Facetime, technology has also torn loved ones apart, as we witness social interactions being replaced by screens that people spend too much time on. Instead of creating a device that would simply be another screen, we decided to capitalize on an already intimate interaction that is special in all relationships (family and friends)... sharing a drink! We chose this interaction because it is personal to all of us, whether it be wine nights with friends that we wouldn’t be able to experience with friends once we graduated, gunning down beers, or drinking tea with family. This device is aimed at loved ones who would like to share a drink together in virtual proximity.
After deciding to focus on the experience of sharing a drink, we brainstormed some different forms that our product could take. Ideas ranged from building the whole drinking cup from scratch to building just a handle (all with embedded components). In the end, we decided to go with a handle that could be attached to any cup that was tall enough.
Then we detailed our interaction scenario. We wanted a person to be able to turn on their device, know if the other person was available, tap their glass to signal to the other person that they wanted to clink glasses, and to ultimately "clink" glasses.
This interaction boiled down to the following 5 main states: device signals that other person is on, device is waiting for the other person to tap their glass, device signals when other person has tapped, device is waiting for other person to clink their glass, and finally, device clinks.
The main physical components that we used per handle were an accelerometer, a solenoid, and an LED. The accelerometer would measure when a person has tapped or made the clinking motion. The solenoid would emulate physical taps and clinks. The LED would be used as a signaling device.
The remainder of the process was split between software and hardware.
// Setting Accelerometer range
int xPin = A1;
int yPin = A2;
int zPin = A3;
int xReading, yReading, zReading;
// Initial settings
int maxX = 0;
int minX = 5000;
int maxY = 0;
int minY = 5000;
int maxZ = 0;
int minZ = 5000;
void setup()
{
Serial.begin(9600);
xReading = analogRead(xPin);
yReading = analogRead(yPin);
zReading = analogRead(zPin);
}
void loop()
{
xReading = analogRead(xPin);
if(xReading > maxX) maxX = xReading;
if(xReading < minX) minX = xReading;
yReading = analogRead(yPin);
if(yReading > maxY) maxY = yReading;
if(yReading < minY) minY = yReading;
zReading = analogRead(zPin);
if(zReading > maxZ) maxZ = zReading;
if(zReading < minZ) minZ = zReading;
String outputOld = "";
String output = outputOld.format("xR: %d, yR: %d, zR: %d", xReading, yReading, zReading);
String outputOld2 = "";
String output2 = outputOld2.format("xMax: %d, xMin: %d, yMax: %d, yMin: %d, zMax: %d, zMin: %d", maxX, minX, maxY, minY, maxZ, minZ);
delay(100);
}
Solenoid - The solenoid was used to create the clinking of the glasses. We used the solenoid in two different spots, the first was 5 quick smaller clinks that indicated your partner had requested a clink. The second was one bigger clink and this was used to mimic an actual clinking of two glasses.
Putting it all together - Finally we combined the two scripts so that when a user tapped three times, which is picked up by the accelerometer, they would emit an event to the other device saying the Person A wanted to clink. The receiving of this event would trigger the small taps of the solenoid for Person B and when Person B tapped their glasses three times the device would emit an event to Person A saying both parties were ready to clink. When both people raised their glasses the bigger solenoid clink would be triggered.
int i = 0;
int xPin = A1;
int yPin = A2;
int zPin = A3;
int sPin = D0;
int ledPin = D1;
int wentUp = 0;
//Led pulsing variables
int brightness = 0;
int fade = 5;
int xReading, yReading, zReading;
int x, y, z; // Readings
int xBase, yBase, zBase;
int clinkThreshold = 1; // 30% of the range of values is half the threshold
int tapThreshold = 5; // 50% of the range of values is half the threshold
int xLowThC, yLowThC, zLowThC;
int xHighThC, yHighThC, zHighThC;
int zLowThT;
int zHighThT;
int timerTapCount, timerStartTap, timerStartClink;
int timerLimitTapCount = 5;
int timerLimitTap = 20;
int timerLimitClink = 10;
// OUR DEVICE'S STATE
bool tapped, clinked;
int numTaps;
// OTHER PERSON'S STATE
bool otherTapped, otherClinked;
// LIGHTS
bool clinkingLights, tappingLights;
int maxX = 0;
int minX = 5000;
int maxY = 0;
int minY = 5000;
int maxZ = 0;
int minZ = 5000;
void tapClinkHandler(const char *event, const char *data)
{
i++;
Serial.print(i);
Serial.print(" ");
Serial.print(event);
Serial.print(", data: ");
// So data could be either NULL, tap, or clink
if(data) {
Serial.println(data);
if(strcmp(data, "tap")==0)
{
// SOLENOID TAPPING CODE
otherTapped = 1;
Particle.publish("In SOleniod");
// Have we also tapped?
if(tapped == 1)
{
// Clink state activated: CLINKING LEDs
// Clink timer starts
Serial.println("WE ARE IN CLINK MODE");
clinkingLights = 1;
tappingLights = 0;
timerStartClink = Time.now();
fade = 0;
brightness = 0;
} else {
Serial.println("THE OTHER PERSON HAS CLINKED IT'S TIME FOR ME TO CLINK");
tappingLights = 1;
timerStartTap = Time.now();
for(int i = 0; i < 5; i++){
analogWrite(sPin, 220);
delay(100);
analogWrite(sPin, 0);
delay(100);
}
// Tap state activated: TAPPING LEDs
}
} else if (strcmp(data, "clink") == 0)
{
// This should only be sent when both are in tapping State
if(tapped == 0)
{
// This is invalid, this state shouldn't be entered
Serial.println("The other person has clinked but we haven't tapped.");
return;
}
if(clinked == 1)
{
Serial.println("WE BOTH CLINKED SUCCESS");
// SOLENOID CLINKS CODE
// reset all states
tapped = 0;
clinked = 0;
otherTapped = 0;
otherClinked = 0;
clinkingLights = 0;
tappingLights = 0;
analogWrite(sPin,255);
delay(500);
analogWrite(sPin, 0);
} else {
Serial.println("The other person has clinked but I haven't");
// Set a variable for the other person being in a clink state
otherClinked = 1;
timerStartClink = Time.now();
// So that when we clink finally, the solenoid clinks
}
} else {
Serial.println("What is this state?");
}
} else {
Serial.println("Null");
}
}
void setup()
{
Serial.begin(9600);
xReading = analogRead(xPin);
xBase = map(xReading, 1954, 2184, 0, 10);
yReading = analogRead(yPin);
yBase = map(yReading, 1557, 2214, 0, 10);
zReading = analogRead(zPin);
zBase = map(zReading, 2329, 2486, 0, 10);
xLowThC = xBase - clinkThreshold;
xHighThC = xBase + clinkThreshold;
yLowThC = yBase - clinkThreshold;
yHighThC = yBase + clinkThreshold;
zLowThC = zBase - clinkThreshold;
zHighThC = zBase + clinkThreshold;
zLowThT = zBase - tapThreshold;
zHighThT = zBase + tapThreshold;
Particle.subscribe("TAP_CLINK_CMU_IOT1", tapClinkHandler);
pinMode(ledPin, OUTPUT);
pinMode(sPin, OUTPUT);
Serial.print("ZHigh: ");
Serial.println(zHighThT);
Serial.print("ZLow: ");
Serial.println(zLowThT);
}
// Idea: get maximum and minimum range of motion and
// then map the values into that range from 0 to 100
void loop()
{
xReading = analogRead(xPin);
x = map(xReading, 1954, 2184, 0, 10);
if(xReading > maxX) maxX = xReading;
if(xReading < minX) minX = xReading;
yReading = analogRead(yPin);
y = map(yReading, 1557, 2214, 0, 10);
if(yReading > maxY) maxY = yReading;
if(yReading < minY) minY = yReading;
zReading = analogRead(zPin);
z = map(zReading, 2329, 2486, 0, 10);
if(zReading > maxZ) maxZ = zReading;
if(zReading < minZ) minZ = zReading;
// For taps, we need to have a time limit for when each successive tap can
// be counted, if it exceed like 5 seconds? then it resets the number of taps
if(numTaps > 0 and numTaps < 3)
{
if((Time.now() - timerTapCount) >= timerLimitTapCount)
{
// If taps aren't done successively, then reset the number of taps
Serial.println("Your taps have been reset");
numTaps = 0;
}
}
if(tappingLights == 1)
{
if((Time.now() - timerStartTap) <= timerLimitTap)
{
// LED LIGHT CODE maybe fade up one second
// And fade down one second
} else {
// Reset all states
Serial.println(timerStartTap - Time.now());
Serial.println(timerLimitTap);
tapped = 0;
clinked = 0;
otherTapped = 0;
otherClinked = 0;
tappingLights = 0;
clinkingLights = 0;
numTaps = 0;
}
} else if (clinkingLights == 1)
{
if((Time.now() - timerStartClink) <= timerLimitClink)
{
// LED LIGHT CODE FOR CLINK
} else {
// Time's up - reset all states
tapped = 0;
clinked = 0;
otherTapped = 0;
otherClinked = 0;
tappingLights = 0;
clinkingLights = 0;
numTaps = 0;
}
}
if(clinked == 0 and tapped == 1 and otherTapped == 1)
{
if(otherClinked == 1)
{
if(z <= zLowThC and (y <= yLowThC or x <= xLowThC))
{
//Time.now() - timerStart) >= timerLimit
Serial.println("WE BOTH CLINKED SUCCESS");
Particle.publish("TAP_CLINK_CMU_IOT2", "clink");
// SOLENOID CLINK CODE
// Reset all states
analogWrite(sPin,255);
delay(500);
analogWrite(sPin, 0);
tapped = 0;
clinked = 0;
otherTapped = 0;
otherClinked = 0;
clinkingLights = 0;
tappingLights = 0;
numTaps = 0;
}
} else {
if(z <= zLowThC and (y <= yLowThC or x <= xLowThC))
{
clinked = 1;
Serial.println("You clinked!");
Particle.publish("TAP_CLINK_CMU_IOT2", "clink");
}
}
} else if(tapped == 0)
{
// We only want to publish to particle once
if(otherTapped == 1)
{
if (z >= zHighThT or z <= zLowThT)
{
numTaps++;
timerTapCount = Time.now();
Serial.println("Tap1");
Serial.println(numTaps);
if(numTaps == 3)
{
tapped = 1;
Serial.println("You tapped and the other person tapped!");
Particle.publish("TAP_CLINK_CMU_IOT2", "tap");
// Now we need to start the clinking lights
clinkingLights = 1;
tappingLights = 0;
// Reset numTaps
numTaps = 0;
timerStartTap = Time.now();
timerStartClink = Time.now();
}
}
} else {
//Serial.println("13");
if (z >= zHighThT or z <= zLowThT)
{
numTaps++;
Serial.println("Tap2");
Serial.println(numTaps);
timerTapCount = Time.now();
if(numTaps == 3)
{
tapped = 1;
Serial.println("You tapped and the other person did not tap!");
Particle.publish("TAP_CLINK_CMU_IOT2", "tap");
tappingLights = 1;
// Reset numTaps
numTaps = 0;
timerStartTap = Time.now();
}
}
}
}
}
Click to Expand
Hardware
The following is a list of hardware used for the building of one cup:
1x Photo Particle
1x Accelerometer
1x Solenoid
1x MOSFET
1x Diode
1x Resister (10k)
1x Resister (320)
1x LED
1x 9v Battery
1x Pololu 5V Step-Down Voltage Regulator {VERY IMPORTANT, unlike an arduino, the particle can only take up to 6v while the arduino can take up to 12v. We kill a few particles ;( }
1x SPDT Switch
A Tall Gall
Custom 3D Printed Housing
Zip Ties
Wires
Here is a photo of a fully assembled cup with out electronic cover
The final interaction scenario is as follows:
Person A is sitting at home, taking a drink using a cup with a Clink! handle. Their LED light turns on which means that their friend, Person B, is also taking a drink at the same time. Person A decides that they want to do a cheers, so they tap their glass on the table (their LED starts slowly pulsing) and wait. Person B's solenoid taps on their glass. That lets them know Person A wants to clink.
But, first, they have to let Person A know they're ready. So Person B taps their glass on the table. Person A's solenoid taps on their glass, and now both Person A's and Person B's LED is strobe-lighting. This means it's time to clink!
Person A raises their glass and Person B raises their glass, and CLINK! The solenoids on their glass make one resounding clink, and everything resets back to normal.
-----
To help visualize this better, we made the following video: (BELOW).
The prototype is mostly complete. To improve the device, one thing we could do is add a contact microphone to the glass to better detect table taps. Currently the accelerator doesn't seem to be sensitive enough to table taps; this could be because of where it's situated in the handle or how people end up moving the handle.
Monisha: Through this process, I learned more about storyboarding and detailing an interaction scenario. I also learned about different aspects to consider when designing a physical product such as tactile feedback. If I could re-do this project, I would work on making sure all the hardware components were wired together as soon as possible before calibrating settings for any of the sensors. That way, it'd be easier to determine if a sensor was a good pick or not for a particular instance.
Brian: The process of this made me learn about how group dynamics work in a relativity small, and short project while working in a larger team. I personally think four people was a bit much for this project since there were times when team members had nothing to do while waiting on others as many task can only be completed by one person.
Travis: The biggest lesson I learned from this project is to try to integrate all parts as soon as possible. We spent a lot of time getting the individual parts of the project to work correctly but when we went to combine all the different parts we ran into problems that we had not foreseen. A little more time spent on working with the parts all together would have been very helpful for this project.
Shaan: I learned a lot doing this project with a team. 3D printing the handle was difficult because the design took so long to print. And I learned the importance of recognizing the different data sets that we needed to collect as well. Because of the small time frame, we were not able to have all the components as connected as we would have liked, thus leading to a few technical difficulties on Thursday. If I had to add one thing about this product it would be a smaller handle which we could achieve if we used smaller parts and had a little extra time.
IoT that allows you to clink glasses with your drinking buddy no matter where you two are.