Sunday, November 28, 2010

Tweeting Kegerator By Sparkfun- An Inspiring project :)

A pint of beer fresh from the SparkFun kegerator.
Mmmm SparkFun Beer

Follow the SparkFunKeg on Twitter




A Need


When I was first given the duty of making sure the SparkFun kegerator had beer for the SparkFun employees I was excited about getting to choose beer for my colleagues. My excitement quickly waned when I got a knock on my door while in the middle of a panelizing session for BatchPCB. The keg was out. It turns out the SparkFun drinking habits vary and the keg never goes out at a convenient time. People never like going to the break room to grab a cold pint of beer only to get the dreaded fweessssssh of an empty keg. I needed a solution. I wanted something that I could monitor remotely that could tell me when the keg was about to run out.


Kegerator leg with force sensor.
The force sensor sits inside the furniture coaster sandwiched between a scrap PCB and the carriage bolt going up to the kegerator

The most well known method of determining the fullness of a keg is to try to pick it up. If you can pick it up and not feel the mass of the liquid swishing around inside, the keg is out. The more difficult it is to lift the keg, the more full it is. This is just not feasible when it's carefully wedged inside the keg fridge and is not the most accurate method around, plus it shakes up the beer. Weighing the keg would work well and four 100 pound force sensors would work for weighing the whole kegerator. I replaced the casters on the kegerator with carriage bolts that rest on the force sensors that rest on leftover PCBs that rest on furniture coasters. Hot glue was added to give some support that was needed for the lateral forces of moving the keg in and out of the kegerator.


Temperature sensor attached to the kegerator door.
The temperature sensor taped to the inside of the kegerator door

What other useful information would be useful for the keg? Temperature would be great, no need to go get a beer if it was warm for some reason, and would also give some indication of a problem. The Lily Pad Temperature Sensor was then added to the parts list because it was easy to interface with an analog output and did not require anything but three wires leading from the main unit to the sensor.


Talking to the outside world




The Arduino Ethernet Shield used in the keg monitor

So, I have these five sensors and need a way to read their outputs remotely. I wanted to show some cool things one could do with an Arduino. But how do I remotely access the Arduino variables? Connecting the Arduino over USB to a PC sitting next to the kegerator would be massive overkill and a waste of power. I saw that we carried the Arduino Ethernet Shield and I decided to play around with it to see what it could do.

I started by studying some code from the Arduino Ethernet example sketches and code. I decided to leave out the checking for the "GET" that is sent by a web browser asking to display the page. If the Arduino got anything on port 80 (the common port for HTTP), it output the text for the web page. This made it easy to diagnose problems by telneting the Arduino at port 80 and hitting enter at the prompt. I got the Arduino serving up "Hello World!" web pages and moved on to integrating the sensors.


The keg monitor shield on the Arduino stack.
Top to bottom: the Keg Monitor shield, the Arduino Ethernet shield and the Arduino Duemilanove.

The sensors would need to be somewhat more permanent than wires just sticking into the Ethernet Shield's header. I put together a "Keg Shield" that had six Three Pin Screw Terminalseach three pin screw terminal would have a power, ground and analog input that connected to one of the Arduino's analog inputs. Near each terminal, there were empty places for resistors to bias individual analog inputs. This was needed for the force sensors, as they were only two terminal resistive devices. The Keg Shield was designed and sent off through BatchPCB, work could get started on getting the Arduino serving up the analog measurements. Here's what the webpage looks like:


http://www.sparkfun.com/tutorial/kegmonitor/KegPage.jpg

Not too shabby for a 8-bit microcontroller! We would post the live link to the shield, but with all the traffic, we don't want it to go down.

The script below, when called from a computer that has access to the local SparkFun network and an SSH key setup with a remote server would be able to post the keg monitor's web page remotely.

#!/bin/sh
#This script will get a web page and post it to a new site with scp.
#Note: the computer running this must be setup with proper ssh keys
#to access the destination site automatically.
sourcePage=$1
destinationPage=$2

echo Copy: $sourcePage to $destinationPage.

wget $sourcePage -O tempFile
scp tempFile $destinationPage
rm tempFile


Just Add Twitter


One day, I was discussing the Keg Monitor with the IT department, when Prashanta, one of the purchasing people, walked by and suggested I make it update to Twitter. I groaned at the thought of adding more to this project. Yet everyone agreed that we should have a Twitter feed. I jumped on board with the idea and decided it would be fun to see how much stuff we could cram into the little Arduino.

At that time, I was using the Arduino Duemilanove with an ATmega168 instead of the ATmega328 because my distribution of Ubuntu (8.04LTS for AMD 64) had some libraries that needed to be figured out before I could even compile for the ATmega328. Well, adding Twitter to the ATmega168 was rather taxing on its RAM given the amount of strings that had to be handled. I massaged the code as best as I could, I tried to use PROGMEMs and the string library, but to no avail. I could not get the chip to properly work, it would Twitter something unintelligible for a variable that was supposed to represent the fullness of the keg. I gave in, the code for this tutorial needed to be understandable to the common Arduino user and should not be obfuscated because I did not want to upgrade my computer's AVR libraries and compiler. With the help of Google and some luck, I was able to get the ATmega328 compiling and running. You can follow the Twitter feed here.


When to Twitter?


The initial twitter code had the Arduino only twitter every time it was reset. This was nice for debugging or knowing when the power went out, but not really twittering. I added a Reed Switch and some Magnets to sense the pulling of the tap handle. To the code, I added the ability to read from and increment the value of a location in the ATmega's EEPROM. Now, every time the tap handle is pulled, the Arduino twitters and increments a count that will not be erased when the power goes out.

The tap switch schematic.
The schematic for the reed-based tap switch


The reed switch for sensing the presence of the tap handle.
The long blue-green piece of glass is the reed switch which closes when a magnetic field is near by.
The back of the tap handle with the magnets.
When the tap is in the closed position, the group of magnets creates a large enough magnetic field to close the reed switch.
The tap handle pulled and lighting the LEDs. The tap handle not pulled and not lighting the LEDs.
When the tap handle is pulled the reed switch opens, the LEDs are lit and the Arduino twitters its status.

The Gritty Part: Code


The code for this project can be found here and is released as beerware.

I have done my best to attempt to comment the code as best as possible, so below are some parts that are good to see without downloading a zip file.

One of the first things you will notice when you look at the code is:
#include "password.h"
password.h was created so that you do not have to have your Twitter passphrase in your main code. That way you can share your .pde file but not the password.h file. To generate the passphrase, go here and enter your twitter username and password like this:
username:password
Don't trust this site? You can use GNU coreutils' base64 command the same way.

The next thing you will see is:
//Comment out the following line if the device is using a test network configuration
//#define LIVE_NETWORK_CONFIG

This was setup so that I could use multiple Arduino and ethernet shield pairs, just switching out the Arduinos. When the #define line is commented out, the Arduino is using settings for working at my desk. When the line is not commented out, the Arduino uses the live settings. This was useful once I got the code to the point that people could see the monitor's web page and I did not want to discourage them or answer questions when it was not working. If you only have one shield, then you can, but don't have to, get rid of the code that corresponds to the #ifdef and #ifndef of the LIVE_NETWORK_CONFIG definition.

In the line:
byte aryTwitterAddress[] = { 168, 143, 162, 100 };
We make an array that corresponds to the IP address of www.twitter.com. We will use this to send updates to Twitter.

You will notice in these lines that I do not check to see if a valid HTTP GET command was sent.
  //...
  //Get a client
  Client objClient = objServer.available();


  //If there is a cleint connecting, then send the web page
  if (true == objClient)
  {

    //Send the header information
    objServer.println("HTTP/1.0 200 OK");
    objServer.println("Server: arduino");
    objServer.println("Cache-Control: no-store, no-cache");
    objServer.println("Pragma: no-cache\nConnection: close");
    objServer.println("Content-Type: text/html\n");

   //...

We assume that anything connecting to the Arduino is wanting a web page and that is what they are going to get. The five lines starting with "objServer.println" send the HTTP header file information to the assumed web browser. If one were to check for a proper GET, it would be before these five lines.

The twitter code is pretty straight forward. I needed to use the String library to form the Twitter status that was then passed to function Twitter where it was formed it into the tweet. These three sites were very helpful in getting the Arduino to twitter:
http://pratham.name/post/39551949/twitter-php-script-without-curl
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1234028200/1
http://www.mats-vanselow.de/2009/02/08/arduino-lernt-twittern/

Eventually, it became apparent that we would need more than 8 bits to store the pull count in the EEPROM. According to this page, we would overflow an 8 bit counter early into the third keg. There were many ways to store the data, but this way was the easiest and actually worked. When the count is incremented, the EEPROM is read four bytes at a time and pieced together to make a 32 bit number, incremented, broken into individual bytes that are then written back into the EEPROM. The EEPROM will cease to properly write before this counter overflows.


Things to do


The values read from the weight sensors are quite a bit off. This is probably caused by a number of factors such as worn out sensors, the hot glue transmitting too much force around the sensors, the sensors not being directly under the kegerator legs and that the values read from the sensors are not linearly related to the force through the sensors.

The sensors had originally been underneath the keg legs without anything keeping the stack together when a shearing force was applied such as when a full keg is loaded into the kegerator. This allowed the kegerator legs to slide around or off of the force sensors. The force sensors were not changed out when we fixed this problem.

We may have created more of a problem by filling up the furniture coaster cups with hot glue to keep the sensor stack from sliding around. This additional hot glue may be transmitting too much force around the force sensor on each stack and would vary from stack to stack.

The final issue is a known issue with the way the force sensor is read. The resistance of the force sensor is linearly related to the force through the sensor. However the force sensor makes up one half of a voltage divider circuit that creates a voltage readable by the Arduino's ADC. Due to the nature of the voltage divider:

Vout = 5V x R1 / (Rforce + R1)

We will not have a linear relationship between Vout and Rforce. This further complicates things when we just add the voltage measurements together to get a total force reading. We can fix this one of two ways, change the math in the Arduino or we can change the circuit we use to relate the force sensor's resistance to a voltage.


Conclusion


Thanks goes out to Brennen in IT for the assistance with webpages and IP help. This was my final project at SparkFun, and I hope I have left a meaningful and maintainable contribution with this project. I wish you all the best in your lives' journeys.

No comments:

Post a Comment