SmartKegerator v2 Installation Guide

Project source here
This project has been heavily modified to take advantage of the raspberry pi 2’s additional horsepower. If you are looking for the raspberry pi v1 code, look around version 62 in the repository. Version 70 and on are unlikely to work on the original pi, although I have not tried.

[Updated 10/4/2016: These instructions have been updated and now work with a clean raspbianPIXEL image]

Installation:

Install a new copy of raspbian onto an sd card.

On your first boot, configure these:
Expand Filesystem
Boot to Desktop
Enable Camera
Configure keyboard (if not in UK) and timezone
Finish > Reboot

1) Update raspbian

sudo apt-get update
sudo apt-get upgrade
sudo rpi-update

2) Install requisites

sudo apt-get install qtcreator cmake libopencv-dev mplayer subversion qt4-dev-tools libqt4-dev libqt4-dev-bin qt4-qmake

3) Configure QtCreator

Launch QtCreator from start menu > Programming > QT Creator

Once in QT Creator:
Tools > Options > Build & Run > Qt Versions > Add > navigate to or paste: /usr/bin/qmake-qt4
Tools > Options > Build & Run > Compilers > Add > pick GCC
Then set compiler path : /usr/bin/arm-linux-gnueabihf-gcc-4.9
Click OK

Qt Creator seems to think that we are going to deploy on a remote target, to fix this :
Help > About Plugins
Uncheck Device Support > Remote Linux
Click Close and reopen Qt Creator

Tools > Options > Build & Run > Kits > Desktop-Qt4 4.8.6 (qt4)
Compiler: GCC
Debugger : /usr/bin/gdb

4) Compile facial recognition libraries

cd ~
git clone https://github.com/bytefish/libfacerec
cd libfacerec
sudo cmake .
sudo make

5) Compile QWT

cd ~
mkdir qwt
cd qwt
svn co svn://svn.code.sf.net/p/qwt/code/branches/qwt-6.1 ./
qmake qwt.pro
sudo make
sudo make install
cd lib/
sudo cp * /usr/lib/

6) Compile WiringPi

cd ~
git clone git://git.drogon.net/wiringPi
cd wiringPi/
./build

7) Get SmartKegerator source

cd ~
mkdir qt
cd qt/
mkdir SmartKegerator
cd SmartKegerator/
svn co https://subversion.assembla.com/svn/smartkegerator/trunk ./

8) Edit config files

sudo nano ~/qt/SmartKegerator/config.txt

Make sure all of the paths are correct for your system. If you’re using a fresh copy of raspbian and followed each step here, you shouldn’t need to edit anything.

9) Run it!

Open QTCreator and File > Open Project > /home/pi/qt/SmartKegerator/SmartKegerator.pro

Click Yes when it asks about environment settings.

Click the green arrow on the bottom-left to start building. The first build will take a while. If everything worked you should see the application open! If you get errors, try google or come back here and post a comment.

9) Disable the screen saver

sudo nano /etc/lightdm/lightdm.conf

scroll down until you see

[SeatDefaults]
#xserver-command=X

Remove the starting ‘#’ from ‘#xserver-command=X” and add ” -s 0 -dpms” to the end so you have:

[SeatDefaults]
xserver-command=X -s 0 -dpms

ctrl-x, y, enter to save

To use the Mimo-720S

See this post about configuring the touchscreen and kernel

Advertisement

Smart Kegerator

Discovery Channel Canada’s “Daily Planet” segment: https://www.youtube.com/watch?v=ENPVkKDqYiE (very similar to the walkthrough above)

Update 7/31/2015:

New installation guide has been posted here:
https://philsprojects.wordpress.com/2015/07/31/smartkegerator-v2-installation-guide/

 

The purpose of this project was to allow my roommates and friends to be able to drink as much beer from the kegerator as they’d like, without guesstimating who owes what when it comes time to refill the kegs. The system uses two flow meters in the beer lines to detect when beer is poured, and once a pour has started, the raspi camera module turns on to run facial recognition (disabled when I shot this video) and charge the appropriate user for their beer. I wanted the system to be as passive as possible, requiring zero human interaction (no RFID cards, no selecting the user every time) but to record all pours and how much was poured. So far the system is running great, minus that accidental spill because my tap handles are too close together 🙂

Eventually I’d like to use weight sensors under each keg to get a better estimation of keg volume, and use a liquid probe thermometer to better estimate the temperature of the beer instead of the air. I’m also moving to a NOIR pi camera module after finding it had much better low light performance, and I’ll probably add some IR lamps to help illuminate the face for recognition when the lights are off. I also need to mount the camera a bit better, ideally higher and a littler further behind the tower, but the flex arm tripod worked great for this first implementation.

I’m also working on a new UI that will probably look something like this:

Mock up UI v2

Mock up UI v2

The source is currently avilable at https://www.assembla.com/code/smartkegerator/subversion/nodes/ but it’s certainly not finished or polished.

The UI is written in QT and C++, using python scripts for the gpio flow interrupts (the c++ interrupts seemed unreliable,but python’s implementation worked perfectly) and the C loldht script found on these forums to read the temp from the temp/humidity sensor.

I’ve made a quick and dirty fritzing image to illustrate the connections, but I’m not very good with frizing so I’ve included text as well.
KegeratorSchematic
On each flow meter, I connected the red to the pi’s 3.3v, black to ground, and the yellow pin to GPIO #23 and GPIO #24 for left and right sides respectively.
The temperature sensor, looking at the front of it (the side with the holes) the pins go left to right 1-4. Pin 1 to GPIO #17, so that I can turn it on/off by writing power out on pin 17. Pin 2 to GPIO #4. Pin 3 to ground. And lastly put a 4.7k ohm resistor between pins 1 and 2.

Parts:
Rasperry pi
http://www.amazon.com/RASPBERRY-MODEL-756-8308-Raspberry-Pi/dp/B009SQQF9C/ref=sr_1_1?ie=UTF8&qid=1394450356&sr=8-1&keywords=raspberry+pi

Mimo 720S display
http://www.amazon.com/Powered-Slide-out-Touch-Screen-Monitor/dp/B002QFP4Z8/ref=sr_1_1?ie=UTF8&qid=1394450430&sr=8-1&keywords=mimo+720s

Powered USB Hub
http://www.amazon.com/gp/product/B005A0B3FG/ref=oh_details_o05_s01_i00?ie=UTF8&psc=1

DHT22 temp/humidity sensor
https://www.adafruit.com/products/385

Flow meters
http://www.adafruit.com/products/828

Pi Camera module (NOIR seems ideal for low light)
http://www.amazon.com/Raspberry-Pi-Camera-Filter-Vision/dp/B00G76YEU8/ref=sr_1_1?ie=UTF8&qid=1394450401&sr=8-1&keywords=raspberry+pi+noir

100cm SPI cable (raspi camera cable)
http://www.ebay.com/itm/141129552486?var=440222309796&ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l2649

Camera housing
http://www.amazon.com/gp/product/B00E1UOXMQ/ref=oh_details_o06_s00_i00?ie=UTF8&psc=1

Wide-angle lens
http://www.amazon.com/gp/product/B009NED5E2/ref=oh_details_o00_s00_i00?ie=UTF8&psc=1

Techflex cable sleeve(I think it makes the raspi camera cable better looking)
http://www.amazon.com/gp/product/B007VT6HSC/ref=oh_details_o02_s00_i00?ie=UTF8&psc=1

For the gpio breakout:
10 pin ribbon cable
http://www.ebay.com/itm/281152427395?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l2649

10 pin connectors
http://www.ebay.com/itm/171047381713?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l2649

protoboard from radioshack
http://www.radioshack.com/product/index.jsp?productId=2104052

References:
Mimo 720S solution – http://www.raspberrypi.org/phpBB3/viewtopic.php?t=27781
Raspberry pi camera to opencv/facial recognition – http://thinkrpi.wordpress.com/opencv-and-pi-camera-board/

More info coming soon!

Kegerator Flow Meter Test

The first step along the road to getting the kegerator monitor up and running

Flow meter used available from adafruit: http://www.adafruit.com/products/828

Based on the code from: https://github.com/adafruit/Adafruit-Flow-Meter/blob/master/Adafruit_FlowMeter.pde

Source:

#include

#define lcdPin 6

SoftwareSerial LCD = SoftwareSerial(0, lcdPin);
// since the LCD does not send data back to the Arduino, we should only define the txPin
const int LCDdelay = 10; // conservative, 2 actually works

// which pin to use for reading the sensor? can use any pin!
#define FLOWSENSORPINLEFT 2
#define FLOWSENSORPINRIGHT 3

// count how many pulses!
volatile uint16_t pulsesLeft = 0;
volatile uint16_t pulsesRight = 0;

volatile uint16_t lastPulses = 0;

// track the state of the pulse pin
volatile uint8_t lastFlowPinStateLeft;
volatile uint8_t lastFlowPinStateRight;

volatile int32_t lastFlowTimer = 0;

float litersPerTank = 18.9;
float pricePerTank = 78;

bool clearNextTick = true;

// Interrupt is called once a millisecond, looks for any pulses from the sensor!
SIGNAL(TIMER0_COMPA_vect)
{
uint8_t left = digitalRead(FLOWSENSORPINLEFT);
uint8_t right = digitalRead(FLOWSENSORPINRIGHT);

if (left != lastFlowPinStateLeft && left == HIGH) {
//low to high transition!
pulsesLeft++;
}

if (right != lastFlowPinStateRight && right == HIGH) {
//low to high transition!
pulsesRight++;
}

lastFlowPinStateLeft = left;
lastFlowPinStateRight = right;

uint16_t pulses = pulsesLeft = pulsesRight;

if (pulses == lastPulses)
{
if (lastFlowTimer > -1)
lastFlowTimer++;
}
else
{
if (lastPulses == 0)
clearNextTick = true;
lastFlowTimer = 0;
}

lastPulses = pulses;
}

void useInterrupt(boolean v)
{
if (v) {
// Timer0 is already used for millis() - we'll just interrupt somewhere
// in the middle and call the "Compare A" function above
OCR0A = 0xAF;
TIMSK0 |= _BV(OCIE0A);
}
else {
// do not call the interrupt function COMPA anymore
TIMSK0 &= ~_BV(OCIE0A);
}
}

void setup()
{
Serial.begin(9600);
Serial.print("Flow sensor test!");

pinMode(FLOWSENSORPINLEFT, INPUT);
digitalWrite(FLOWSENSORPINLEFT, HIGH);
lastFlowPinStateLeft = digitalRead(FLOWSENSORPINLEFT);

pinMode(FLOWSENSORPINRIGHT, INPUT);
digitalWrite(FLOWSENSORPINRIGHT, HIGH);
lastFlowPinStateRight = digitalRead(FLOWSENSORPINRIGHT);

useInterrupt(true);

pinMode(lcdPin, OUTPUT);
LCD.begin(9600);
clearLCD();
lcdPosition(0, 0);
LCD.print("Starting Up");

lastFlowTimer = -1;
clearNextTick = true;
pulsesLeft = 0;
pulsesRight = 0;
}

void loop() // run over and over again
{
uint16_t pulses = pulsesLeft = pulsesRight;

if (clearNextTick)
clearLCD();
clearNextTick = false;

if (pulses == 0)
{
if (lastPulses > 0)
clearLCD();

lcdPosition(0, 4);
LCD.print("Welcome!");
lcdPosition(1, 1);
LCD.print("Begin pouring!");
}
else
{
float liters = pulses;
liters /= 7.5;
liters /= 60.0;
liters /= 1.4; //weird const

float ounces = liters * 33.8;

float price = liters / litersPerTank * pricePerTank;

if (pulsesRight > 0)
LCD.print("right");
else
LCD.print("left");
lcdPosition(1, 0);
LCD.print("Oz: ");
LCD.print(ounces);
lcdPosition(1, 9);
LCD.print(" $:");
LCD.print(price);

// Reset
if (lastFlowTimer > 1000)
{
lastFlowTimer = -1;
clearNextTick = true;
pulsesLeft = 0;
pulsesRight = 0;
}
}

delay(100);
}

// wbp: goto with row & column
void lcdPosition(int row, int col) {
LCD.write(0xFE); //command flag
LCD.write((col + row * 64 + 128)); //position
delay(LCDdelay);
}
void clearLCD(){
LCD.write(0xFE); //command flag
LCD.write(0x01); //clear command.
delay(LCDdelay);
}