IoT that allows you to clink glasses with your drinking buddy no matter where you two are.

Created: March 7th, 2017

0

Problem Statement

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.

0

Goal

The goal of this product is to bridge the physical distance between loved ones so they can share a drink with that special someone in real time and even signal a cheers, or a Clink!

0

Process

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.

0
Diagram of Interaction (cont.)
17105706 1570055896357750 363614215 n.thumb
0
Diagram of Interaction
17101643 1570055886357751 944931363 n.thumb
0
Early Accelerometer Circuit
17036550 10208840869446702 91458756 o.thumb
0
Early Solenoid Circuit
17092190 1570055863024420 1473247808 n.thumb
0
CAD Handle Model
17035921 10212823597330960 802227805 o.thumb
0
Inside of the handle
Img 1092 2.jpg.thumb
0
Final Wiring
17036747 10212827669152753 46758986 o.thumb
0

Software

Accelerometer - The main goal when initially coding with the accelerometer was to determine a good range to map the readings in order to get a clearer signal. To do this, we calculated the maximum and minimum reading from the accelerometer giving tapping movements and clinking movements.

0
Setting Accelerometer Range
// 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);
}
(2017) Click to Expand
0

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.

0
int sPin = D0;

void setup() {
    pinMode(sPin, OUTPUT);
}

void loop() {
    //Small Clinks
    for(int i = 0; i < 5; i++) {
        analogWrite(sPin, 130);
        delay(100);
        analogWrite(sPin, 0);
        delay(100);
    }
    //Big Clink
    analogWrite(sPin,220);
    delay(500);
    analogWrite(sPin, 0);
    delay(500);
}
Click to Expand
0

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.

0
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
0

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

0

Outcome

The final product looks like this:

0

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).

0
Clink IoT
Brian Yang - https://youtu.be/xKav21jDY_A
0

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.  

0

Reflection

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.

x
Share this Project


About

IoT that allows you to clink glasses with your drinking buddy no matter where you two are.