Mallika Yedla, Julie Hoover, Rosie Murphy ESE 111 Final Project Final Report Due: 12/15/2017

Project Title: Bottle Buddy

Abstract:

For our final project, we created a “smart” water bottle (with WiFi connectivity). Our bottle enables the user to achieve healthy levels of hydration throughout the day, no matter busy and hectic the user’s daily life may be. We have found that we each tend to get busy with work, classes, or other activities throughout the day, and we often forget to drink water as regularly as we should in order to function at our best, given the active lifestyles that we each lead.

Our water bottle uses a pressure sensor and an accelerometer (detailed information below) with Arduino to determine how much water is in the bottle and how often the user is drinking from the bottle. When the user’s water consumption hits pre-programmed thresholds that indicate a particular hydration level (threshold would theoretically programmed based on the user’s particular physiological characteristics and lifestyle habits), the product sends the user alerts and encouraging messages via text messages.

The Process:

1) Our initial idea was to have a waterproof bag inside the hard plastic bottle, and to have the pressure sensor attached to the bottom of the bag, because we were not sure if the pressure sensor would work if it were directly attached to the bottom of the hard plastic bottle. We had also planned to use the combination of a pressure sensor below the water bottle and LEDs attached to the side of the bottle at multiple points with photoresistors/light sensors directly across (so that when the light was hitting the sensor, we would know that the water level had below that certain point and was not blocking the path of the light beam).

2) Then, we found out that our light sensor idea would not be feasible because of its lack of accuracy. Our idea of using the light sensor was inspired by another project that someone had done for another class, but they had used milk as the liquid, and the opacity of milk made that method more viable for milk than for water (due to light refraction). However, our pressure sensor idea seemed to be working. At this point we were also still sticking with our bag-inside-a-bottle method.

3) The next step was to find another sensor to use in our product, due to the assignment’s requirement of using at least two sensors. After considering a liquid level sensor and a ping sensor (ultrasonic distance sensor), we settled on using an accelerometer (attached to the lid of the bottle to tell us when the bottle was being opened). The accelerometer we used provided x, y, and z-axis data.

4) The issue with the accelerometer was that we did not know how to program it in such a way that we would be able to tell when the bottle’s lid was being unscrewed for the user to drink from it. Then we figured out that we could manipulate the x, y, and z axis data in our code and use the time vector’s derivative to determine when the bottle’s lid was being unscrewed and when it was not.

5) Throughout this process, we went through several pressure (FSR) sensors as they were extremely delicate and we had trouble keeping them intact while manipulating them. We had a lot of issues with breakage of sensors and inaccuracy while attaching the sensors to the bottom of the waterproof bag, so we decided to completely change the design of our product two days before demo day. We ended up attaching the square pressure sensor directly to the bottom of our hard plastic water bottle, and that had the best results (it also looked much cleaner than our initial approach).

The main issues that we encountered were: debugging, soldering delicate parts, and figuring out the software side of things.

~~Debugging and Soldering Issues: when our pressure sensors would break, it was often difficult to tell what was causing the problem. We had to test every other part of our product before looking at the pressure sensor as the cause of an issue, because we had put heat-shrink on the soldered joints of the pressure sensor, and removing the heat-shrink had previously caused us issues with breakage of the fragile sensor. We also had trouble soldering wires to our accelerometer without having excess solder touching components that it should not have been touching. Also, when our breadboard short-circuited, it took a great deal of scrutiny to determine what the issue was, because the issue was usually small and difficult to locate. We struggled with debugging as late as an hour into demo day. Our product had been working well on Saturday night, but Monday evening, we could not get any part of it to work. After spending 1.5-2 hours debugging, we finally determined that our Arduino wifi shield board was malfunctioning and we were able to replace it and demo our fully-functioning product. It was a bit stressful, but definitely satisfying to see our problem-solving skills locate the source of our difficulties.

~~Software: the biggest issue going into demo day was that while we had written all of the code that was necessary for our product to send text message alerts to the user (using Twilio and Temboo with Arduino), the libraries needed to use the Temboo part of our code with Arduino exceeded the maximum storage capacity of our Uno board. Since the ESE lab was out of Arduino Mega boards (which had more storage space), we had to run our code directly from the Temboo website instead of being able to incorporate it into our Arduino code (the text message code is commented out in the code that we have submitted on devpost). We also struggled with getting the accelerometer code going, because we did not know what mathematical calculations to incorporate into our code in order to know specifically when the bottle lid was being unscrewed, but Max helped us fill in our knowledge gaps with that.

Technical Specs/Details

As mentioned above, our final product used the following materials: -Nalgene clear plastic water bottle (32oz) -FSR square pressure sensor -ADXL337 triple axis accelerometer -Arduino Uno WiFi Board -Breadboard -Wires -Solder, hot glue, duct tape, electrical tape, cardboard

***The accelerometer was attached using hot glue to the top of our water bottle’s lid, and was programmed in Arduino to allow us to determine when the bottle’s lid was being unscrewed. We used calculations in Arduino to determine the thresholds for data values that would accompany motion of the accelerometer indicative of the bottle’s lid being unscrewed.

***With this information, we were able to determine how many times per day a user was opening the bottle and drinking from it, which contributed to our data collection and informed us with regard to the timing of water consumption by the user. This information could be used to come up with helpful strategies of making sure the user drinks water at the correct times for maximum efficacy.

***The FSR pressure sensor was placed below the bottle, and allowed us to detect “physical pressure, squeezing, and weight” (Adafruit). This essentially means that as more water was added to or removed from the bottle the bottle, the pressure sensor below the bottle would sense the change in weight above it, and it would send those data values to our Arduino. The sensor’s dimensions were 38 mm Square x 83 mm.

***We used the Arduino WiFi board and we were hoping to use the WiFi Shield to achieve connectivity to the internet and send text messages. Unfortunately, we were not able to do that due to the storage issues that were outlined above. The other materials that we used (listed above) were fairly standard (water bottle, wires, etc.)

Marketability Aspects of Our Project:

As mentioned above and in our video, Bottle Buddy is perfect for students, professionals, parents, athletes, and just anyone who leads a busy life. Busy people have an unhealthy habit of getting caught up in their work or other activities and neglecting to drink as much water as they need to, in order to sustain their active lifestyle. The Bottle Buddy allows the user to be conscious of their hydration levels and to stay healthy (with regard to their hydration) without a great deal of extra effort (thanks to text alerts and convenient reminders and encouragement). The Bottle Buddy is also customizable. A marathon-running teacher, who goes on long runs and who is on their feet all day at school, will require a great deal more water than a mostly sedentary 9-to-5 desk worker who rarely exercises. The Bottle Buddy is capable of accounting for this difference and adjusting accordingly. Dehydration can be extremely dangerous to one’s health, or at the very least, one’s productivity levels and athletic ability. Fortunately, dehydration is an easy issue to solve with Bottle Buddy. The advantages of hydration cannot be overstated, and Bottle Buddy capitalizes on the need for a product that make adequate hydration an easily achievable objective.

What We Have Learned:

--Debugging is challenging, and it can be stressful when a major component silently begins to malfunction right as one is preparing to demo their product. However, it is very satisfying when the source of the issue is located. --Soldering sometimes requires a practiced hand, if the goal is to be precise and have your part still function after having soldered other components to it. --In order to create the best possible product in a given time period, one must be willing to accept the risks associated with pivoting from one design to a completely different one, even as close as a day and a half to their demo day. --Pressure sensors are quite delicate. --Small, easily-implementable adjustments in writing code can make a world of difference in the outcome of a final product. --Water and electronics do not really ever mix. This is why we did not use a ping sensor. --Having a well-functioning team is a great asset to any project.

Code:

//Analog read pins for accelerometer const int xPin = 1; const int yPin = 2; const int zPin = 3;

int fsrPin = 0; // the FSR and 10K pulldown are connected to a0 int fsrReading; // the analog reading from the FSR resistor divider

//The minimum and maximum values that came from //the accelerometer while standing still //You very well may need to change these int minVal[3] = {200, 200, 200}; int maxVal[3] = {400, 400, 400}; double prev =0; double starttime = 0;

/* *#include

include

include

include

include "TembooAccount.h" // Contains Temboo account information

WiFiSSLClient client;

int calls = 1; // Execution count, so this doesn't run forever int maxCalls = 10; // Maximum number of times the Choreo should be executed #include

include

include

include

include "TembooAccount.h" // Contains Temboo account information

WiFiSSLClient client;

int calls = 1; // Execution count, so this doesn't run forever int maxCalls = 10; // Maximum number of times the Choreo should be executed FSR simple testing sketch.

Connect one end of FSR to power, the other end to Analog 0. Then connect one end of a 10K resistor from Analog 0 to ground

For more information see www.ladyada.net/learn/sensors/fsr.html

int fsrPin = 0; // the FSR and 10K pulldown are connected to a0 int fsrReading; // the analog reading from the FSR resistor divider */

void setup(){ Serial.begin(9600); /*

  • int wifiStatus = WL_IDLE_STATUS;

// Determine if the WiFi Shield is present Serial.print("\n\nShield:"); if (WiFi.status() == WL_NO_SHIELD) { Serial.println("FAIL");

// If there's no WiFi shield, stop here while(true); } Serial.println("OK");

// Try to connect to the local WiFi network while(wifiStatus != WL_CONNECTED) { Serial.print("WiFi:"); wifiStatus = WiFi.begin(WIFI_SSID); if (wifiStatus == WL_CONNECTED) { Serial.println("OK"); } else { Serial.println("FAIL"); } delay(5000); }

Serial.println("Setup complete.\n"); }

  • // For debugging, wait until the serial console is connected delay(4000); while(!Serial);

int wifiStatus = WL_IDLE_STATUS;

// Determine if the WiFi Shield is present Serial.print("\n\nShield:"); if (WiFi.status() == WL_NO_SHIELD) { Serial.println("FAIL");

// If there's no WiFi shield, stop here while(true); }

Serial.println("OK");

// Try to connect to the local WiFi network while(wifiStatus != WL_CONNECTED) { Serial.print("WiFi:"); wifiStatus = WiFi.begin(WIFI_SSID); if (wifiStatus == WL_CONNECTED) { Serial.println("OK"); } else { Serial.println("FAIL"); } delay(5000); }

Serial.println("Setup complete.\n"); } */

double prev =0; } void loop(){ double currenttime = millis(); //read the analog values from the accelerometer int xRead = analogRead(xPin); int yRead = analogRead(yPin); int zRead = analogRead(zPin); double totalacceleration = sqrt(pow(xRead,2) + pow(yRead,2) +pow(zRead,2));

double derivative = (totalacceleration - prev)/(currenttime-starttime); prev = totalacceleration; fsrReading = analogRead(fsrPin);

//Output read values to Serial monitor Serial.print("x: "); Serial.print(xRead); Serial.print(" | y: "); Serial.print(yRead); Serial.print(" | z: "); Serial.print(zRead); Serial.print(" | a: "); Serial.print(totalacceleration); Serial.print(" | d: "); Serial.println(derivative); Serial.print("Analog reading = "); Serial.print(fsrReading);

int counter = 0; if (fsrReading < 2) {
counter++; Serial.println(counter); } if (fsrReading < 20) { Serial.println(" - No Water"); } else if (fsrReading < 150) { Serial.println(" - Little Water"); } else if (fsrReading < 220) { Serial.println(" - Medium Filled Bottle"); } else if (fsrReading < 350) { Serial.println(" - Almost Filled Bottle"); } else { Serial.println(" - Full Bottle"); } //delay(1000);

if (derivative > .04) { Serial.println("Bottle has been opened"); }

starttime = currenttime;

//The analogWrite takes a range from 0-255 //map function converts a given range int red = map(xRead, minVal[0], maxVal[0], 0, 255); int green = map(yRead, minVal[1], maxVal[1], 0, 255); int blue = map(zRead, minVal[2], maxVal[2], 0, 255);

delay(100); //slow down the serial display to be able to read easier*/

/*

  • if (calls <= maxCalls) { Serial.println("Running SendSMS - Run #" + String(calls++));

TembooChoreoSSL SendSMSChoreo(client);

// Invoke the Temboo client SendSMSChoreo.begin();

// Set Temboo account credentials SendSMSChoreo.setAccountName(TEMBOO_ACCOUNT); SendSMSChoreo.setAppKeyName(TEMBOO_APP_KEY_NAME); SendSMSChoreo.setAppKey(TEMBOO_APP_KEY); SendSMSChoreo.setDeviceType(TEMBOO_DEVICE_TYPE);

// Set Choreo inputs String AuthTokenValue = "8c8c616707c6b5b746f72818f886f369"; SendSMSChoreo.addInput("AuthToken", AuthTokenValue); String AccountSIDValue = "AC451270608b444ea355a2deaea32f9a70"; SendSMSChoreo.addInput("AccountSID", AccountSIDValue);

// Identify the Choreo to run SendSMSChoreo.setChoreo("/Library/Twilio/SMSMessages/SendSMS");

// Run the Choreo; when results are available, print them to serial SendSMSChoreo.run();

while(SendSMSChoreo.available()) { char c = SendSMSChoreo.read(); Serial.print(c); } SendSMSChoreo.close(); }

Serial.println("\nWaiting...\n"); delay(30000); // wait 30 seconds between SendSMS calls if (calls <= maxCalls) { Serial.println("Running SendSMS - Run #" + String(calls++));

TembooChoreoSSL SendSMSChoreo(client);

// Invoke the Temboo client SendSMSChoreo.begin();

// Set Temboo account credentials SendSMSChoreo.setAccountName(TEMBOO_ACCOUNT); SendSMSChoreo.setAppKeyName(TEMBOO_APP_KEY_NAME); SendSMSChoreo.setAppKey(TEMBOO_APP_KEY); SendSMSChoreo.setDeviceType(TEMBOO_DEVICE_TYPE);

// Set Choreo inputs String AuthTokenValue = "8c8c616707c6b5b746f72818f886f369"; SendSMSChoreo.addInput("AuthToken", AuthTokenValue); String AccountSIDValue = "AC451270608b444ea355a2deaea32f9a70"; SendSMSChoreo.addInput("AccountSID", AccountSIDValue);

// Identify the Choreo to run SendSMSChoreo.setChoreo("/Library/Twilio/SMSMessages/SendSMS");

// Run the Choreo; when results are available, print them to serial SendSMSChoreo.run();

while(SendSMSChoreo.available()) { char c = SendSMSChoreo.read(); Serial.print(c); } SendSMSChoreo.close(); }

Serial.println("\nWaiting...\n"); delay(30000); // wait 30 seconds between SendSMS calls

fsrReading = analogRead(fsrPin);

Serial.print("Analog reading = "); Serial.print(fsrReading); // the raw analog reading

int counter = 0; if (fsrReading < 2) { counter++; Serial.println(counter);

} if (fsrReading < 20) { Serial.println(" - No Water"); } else if (fsrReading < 150) { Serial.println(" - Little Water"); } else if (fsrReading < 220) { Serial.println(" - Medium Filled Bottle"); } else if (fsrReading < 350) { Serial.println(" - Almost Filled Bottle"); } else { Serial.println(" - Full Bottle"); } delay(1000); }

Share this project:

Updates