In the meantime, Sophie had figured out how we're going to get our water bottle working. It turns out Camelbak water bottles have breathable lids that allow air in while letting water out. This way, when we drink out of the container the amount of air in the pack won't change. We bought a Nalgene water pack that has a regular water bottle lid on it, switched it with a Camelbak lid, and connected it to a long tube to drink through. We also cut a hole in the side of the pack and inserted our water level sensor. The whole system seemed to be working when we used our test code! :)
Next, Sophie and I walked through how we wanted the programming side of the system to work. She had a rather complicated suggestion that involved using different classes for different sensors but I was convinced we could come up with something quite simple and elegant that would hopefully work just as well. I definitely understand now why Takis always told us it's better to spend hours planning out code and only thirty minutes actually writing it because if we had just written our first idea it would have been a huge headache to debug the code and figure out what was wrong. Instead, Sophie and I brainstormed how the program should run, wrote and re-wrote pseudocode on the board, and walked through every line of the pseudocode until we felt confident it would work. Once I actually sat down to write the code it took less than thirty minutes to write and it worked the first time I compiled and uploaded it! I'm quite proud of myself for that one.
I came up with a relatively simple way of tracking how much water had been drunk. I decided we should have keep track of the initial water level and then check every five minutes if the water level has dropped. If the water level has dropped, the amount it has fallen is added to a cupsdrunk integer and the new water level is saved to be compared to next time. Every five minutes, when the water level is tested, the program checks if the water level changes a significant amount over a five second interval to determine whether the value is a reliable datapoint or if the wearer is likely just moving around a lot and causing the water level to rise and fall. It has been proven that drinking eight cups of water a day is considered healthy and we want the wearer to have a grace-period for when they have to drink all their water so, every six hours, the program subtracts the liquid level sensor's equivalent of two cups of water from the cupsdrunk variable. If the cupsdrunk integer is negative, that means the wearer has not drunk two cups of water in the last two hours and the LED changes from blue to pink. If at anytime the integer is positive, the LED will change back from pink to blue.
Something I really like about this implementation is that it can easily be transferred from the water bottle to measuring exercise and sleep. It also allows the wearer to drink an excess amount of water and not be reminded to drink water until much later. The way I think of it, the program almost works like a bank. If you are in water-intake debt you will need to drink extra in order to make up for it. If, however, you drink a lot of water all at once, you will have a surplus and will not have to worry about drinking water again until your savings run out. Below is the code for the water intake sensor and LEDs:
#define LSR 0
#define blueLED 11
#define redLED 2
#define SliSwi 0
#include <Time.h>
#define TIME_MSG_LEN 11 // time sync to PC is HEADER followed by Unix time_t as ten ASCII digits
#define TIME_HEADER 'T' // Header tag for serial time sync message
#define TIME_REQUEST 7 // ASCII bell character requests a time sync message
int lsrReading;
int lastWaterLevel;
int cupsdrunk;
int fivmin;
int sixhrs;
void setup(void)
{
Serial.begin(9600);
pinMode(LSR, INPUT);
pinMode(blueLED, OUTPUT);
pinMode(redLED, OUTPUT);
pinMode(SliSwi, INPUT);
lastWaterLevel = analogRead(LSR);
cupsdrunk = 0;
fivmin = 0;
sixhrs = 0;
}
void loop(void)
{
lsrReading = analogRead(LSR);
if (second()==0)
{
fivmin++;
sixhrs++;
}
if (fivmin==5)
{
getLiquidChange();
}
if (sixhrs == 360)
{
cupsdrunk = (cupsdrunk - 90);
sixhrs = 0;
if (cupsdrunk >= 0)
{
digitalWrite(blueLED, HIGH);
digitalWrite(redLED, LOW);
} else {
digitalWrite(blueLED, LOW);
digitalWrite(redLED, HIGH);
}
}
if (cupsdrunk >= 0)
{
digitalWrite(blueLED, HIGH);
digitalWrite(redLED, LOW);
}
/* if (lsrReading > 500)
{
digitalWrite(blueLED, HIGH);
digitalWrite(redLED, LOW);
} else if (lsrReading < 500)
{
digitalWrite(blueLED, LOW);
digitalWrite(redLED, HIGH);
}*/
Serial.print("Analog reading = ");
Serial.println(lsrReading);
digitalClockDisplay();
Serial.println(second());
Serial.print("cupsdrunk = ");
Serial.println(cupsdrunk);
Serial.print("lastWaterLevel = ");
Serial.println(lastWaterLevel);
Serial.print("fivmin = ");
Serial.println(fivmin);
Serial.print("sixhrs = ");
Serial.println(sixhrs);
delay(950);
}
void getLiquidChange()
{
int level1 = analogRead(LSR);
int lwrbnd = (level1 - 10);
int uprbnd = (level1 + 10);
delay(4000);
int level2 = analogRead(LSR);
if (level2 >= lwrbnd && level2 <= uprbnd)
{
if (level2 < lastWaterLevel)
{
Serial.print("level2 = ");
Serial.println(level2);
cupsdrunk = cupsdrunk + (lastWaterLevel - level2);
}
lastWaterLevel = level2;
}
fivmin = 0;
}
void digitalClockDisplay(){
// digital clock display of the time
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.print(" ");
Serial.print(day());
Serial.println();
}
void printDigits(int digits){
// utility function for digital clock display: prints preceding colon and leading 0
Serial.print(":");
if(digits < 10)
Serial.print('0');
Serial.print(digits);
}
Unfortunately, in the middle of the night after Sophie and I had finally gotten everything to work, we watched tragically as the input from the water level sensor suddenly dropped from its normal reading down to zero. Whenever we tried to adjust anything, the sensor simply gives in completely random data that doesn't make any sense given the thresholds we calculated while it was still working. It was extremely discouraging for both of us, especially because we had just gotten it to work and we had no idea what went wrong.
The next morning I talked with Orit and she explained to me the difference between working with hardware and programming only on the computer. When working with the computer, it is fairly predictable and you can debug and know when it doesn't work it is likely something you have done wrong. When working with hardware, however, you spend a lot of your time troubleshooting and trying to determine whether you've made the error or whether your hardware is simply malfunctioning. In our case, it seems fairly clear the problem lies with the hardware, especially since it was working perfectly and then all of a sudden it stopped right before our eyes even though we didn't make any changes to it. We will be ordering a new water level sensor and implementing that as soon as we can.
In the meantime, I installed a flex sensor instead in order to give a demo to our class of reading input and getting feedback using the blue and pink LEDs. I only had to change a few thresholds in the code and it was good to go. Whenever I hold the flex sensor so that the reading is below the last reading, the program thinks I've drunk water. But if the flex sensor stays at the same level or gets higher for too long the LEDs turn pink and I need to drink some more water in order for them to turn blue. Here is a picture of me wearing the feasibility prototype that we presented during class. One person in the hallway asked me if I was a human time bomb. Hehe.
No comments:
Post a Comment