Beer video selector (en)

Logo de Creative Common License    The “Beer Video Selector” is a project that involve recycling of an old laptop screen. The frame is made of raw palette wood. You touch the left and right beer can to select your video and the middle on to launch it. The bars reflect the capacitive signals and turn red when passing a threshold.
This can be a great tool to communicate your activities to the public in a show, a fair or whatever !

probando-la-capacitacion-fablab-santander

Once the frame is cut from a palette wood and fixed we place the screen and block it with small wooden pieces.
We bought the display controller in ebay (yes this is not recycled, working on it…)
The beer cans are fixed by 2 wood screws that go through the frame. A central hole lets go the wire for capacitive sensing through.

detalle-de-construccion-del-proyecto-de-capacitacion

The capacitive sensing is done by an arduino board connected to the raspberry PI (RPI) by usb cable. The RPI runs a python software that basically use serial port to get a permanent flow of 3 capacitive sensors data. python check thresholds , repetitions and all that sort of things. When touching a beer can is detected python use “subprocess” to launch omxplayer:
   arg=str(int(videoIndex+1))+”.mp4″
subprocess.call([“omxplayer”, arg])
    I tried to use the python library pygame but it needs very special video formats. No way.

detalle-del-sistema-de-imagen

The capacitive sensing is done by following this tutorial: http://playground.arduino.cc/Main/CapacitiveSensor?from=Main.CapSense. Use the library CapacitiveSensor.h . It could be done directly by the RPI ( see here) but to avoid problems I preferred to separate sensing and interface software.
We use 1M resitors and no capacitors ( should I ?, yes…)
It’s somehow  rough to adjust the thresholds to make it work quite smoothly. Make a first prototype with the arduino and the beer cans alone. When it’s OK redo debugging with the cans mounted on the final frame because the signals will change and so your adjustments !

The GUI is done in python with the library Tkinter. Quite nice and easy to use.

Voilà. here are the codes for arduino and the python code.

———————————————————————————————————————————–

Arduino:

———————————————————————————————————————————–

#include <CapacitiveSensor.h>

/*
* CapitiveSense Library Demo Sketch
* Paul Badger 2008
* Uses a high value resistor e.g. 10 megohm between send pin and receive pin
* Resistor effects sensitivity, experiment with values, 50 kilohm – 50 megohm. Larger resistor values yield larger sensor values.
* Receive pin is the sensor pin – try different amounts of foil/metal on this pin
* Best results are obtained if sensor foil and wire is covered with an insulator such as paper or plastic sheet
*/

// send pin 8 receive/sensor pin 2 receive/sensor pin 3
// | | |
// | | |
// |_________R10M______|________ foil |
// | |
// | |
// |_________R10M__________________________________|_______ foil

//see http://www.pjrc.com/teensy/td_libs_FrequencyTimer2.html
#define nbSensors 3
CapacitiveSensor* cs[nbSensors];
long threshold=50;

double m[nbSensors];

void setup()
{
Serial.begin(9600);
pinMode(13, OUTPUT);//LED on board
for (int j=0;j<nbSensors;j++) cs[j] = new CapacitiveSensor(5+j,2+j);
}

void loop()
{
long start = millis();
int n=100;

for (int j=0;j<nbSensors;j++) m[j]=0;

for (int j=0;j<nbSensors;j++)
for (int i=0;i<n;i++)  m[j]+= cs[j]->capacitiveSensor(10);

int index=-1;
double max=0;
for (int j=0;j<nbSensors;j++)
{
if (m[j]>max)
{
max=m[j];
index=j;
}
Serial.print(m[j]);
Serial.print(” “);
}
if (max>threshold*n) Serial.println(index);else Serial.println(“nada”);

delay(10); // arbitrary delay to limit data to serial port
}

———————————————————————————————————————————–

Raspberry:

———————————————————————————————————————————–

from Tkinter import *
import time
import serial
import math
import tkFont
import subprocess
w=1280
h=700
r1=50
h0=0
h1=0
h2=0
x0=w/(3+1)*1
x1=w/(3+1)*2
x2=w/(3+1)*3

#thresholds:
t0=15000
t1=10000
t2=600

#corrections:
k0=50
k1=50
k2=4

#index of the selected video
videoIndex=0
lastVideoIndex=-1
counter=0
#selectorSize
ds=15
#selection position:
sy=200
#nb of videos
nbVideos=6

class alien(object):

def __init__(self):
self.root = Tk()
self.canvas = Canvas(self.root, width=w, height = h)
self.canvas.pack()

#filename = PhotoImage(file = “icones.png”)
photo = PhotoImage(file = “icones_videoSelector.gif”)
image = self.canvas.create_image(0, 0, anchor=NW, image=photo)

self.p0 = self.canvas.create_polygon(x0-r1,h,x0+r1,h,x0+r1, h-h0, x0-r1, h-h0,outline=’black’, fill=’red’)
self.p1 = self.canvas.create_polygon(x1-r1,h,x1+r1,h,x1+r1, h-h1, x1-r1, h-h1,outline=’black’, fill=’red’)
self.p2 = self.canvas.create_polygon(x2-r1,h,x2+r1,h,x2+r1, h-h2, x2-r1, h-h2,outline=’black’, fill=’red’)
self.cursor = self.canvas.create_oval(w/nbVideos*(videoIndex+0.5)-ds, sy-ds, w/nbVideos*(videoIndex+0.5)+ds, sy+ds, outline=’red’, fill=’red’)

font1 = tkFont.Font(family=’FreeSans’,size=36, weight=’bold’)
self.t0=self.canvas.create_text(x0,h-30,text=”<-“, fill=’black’,width=100,font=font1);
self.t1=self.canvas.create_text(x1,h-30,text=”OK”, fill=’black’,width=100,font=font1);
self.t2=self.canvas.create_text(x2,h-30,text=”->”, fill=’black’,width=100,font=font1);

self.canvas.pack()
self.root.after(0, self.animation)
self.root.mainloop()

def animation(self):
while True:
global counter
global lastVideoIndex
global videoIndex
global nbVideos
string = ser.readline()
#print string
list=string.split(‘ ‘, 3 )
#print list
v0=0
v1=0
v2=0
if (len(list)==4):
if (is_number(list[0])): v0=float(list[0])
#print v0
if (is_number(list[1])): v1=float(list[1])
#print v1
if (is_number(list[2])): v2=float(list[2])
#print v2
print v0,v1,v2
#v0=math.pow(v0,2)
#v1=math.pow(v1,2)
#v2=math.pow(v2,2)
h0=min(v0/k0,h-170);
h1=min(v1/k1,h-170);
h2=min(v2/k2,h-170);
#print x ,y
time.sleep(0.005)
#self.alien1 = self.canvas.create_oval(v1/10, 260, v1/10+100, 260+100, outline=’white’,fill=’blue’)
#self.canvas.move(self.alien1, dx, 0)

#update the signal bars:
self.canvas.coords(self.p0,x0-r1,h,x0+r1,h,x0+r1, h-h0, x0-r1, h-h0);
self.canvas.coords(self.p1,x1-r1,h,x1+r1,h,x1+r1, h-h1, x1-r1, h-h1);
self.canvas.coords(self.p2,x2-r1,h,x2+r1,h,x2+r1, h-h2, x2-r1, h-h2);
#update the cursor:
self.canvas.coords(self.cursor,w/nbVideos*(videoIndex+0.5)-ds, sy-ds, w/nbVideos*(videoIndex+0.5)+ds, sy+ds);

if (v0>t0):
videoIndex-=1
if (videoIndex<0): videoIndex=nbVideos-1
self.canvas.itemconfigure(self.p0, fill=’red’)
self.canvas.update()
time.sleep(0.2)
else:
self.canvas.itemconfigure(self.p0, fill=’green’)
if (v1>t1):
self.canvas.itemconfigure(self.p1, fill=’red’)
self.canvas.update()
arg=str(int(videoIndex+1))+”.mp4″
print arg
counter=counter+1
if (counter>3):
subprocess.call([“omxplayer”, arg])
#time.sleep(4)
#flush serial entries:
while((v0>t0)|(v1>t1)|(v2>t2)):
string=ser.readline()
print string
list=string.split(‘ ‘, 3 )
if (len(list)==4):
if (is_number(list[0])): v0=float(list[0])
if (is_number(list[1])): v1=float(list[1])
if (is_number(list[2])): v2=float(list[2])
print v0,v1,v2
else:
self.canvas.itemconfigure(self.p1, fill=’green’)
counter=0
if (v2>t2):
videoIndex+=1
if (videoIndex>=nbVideos): videoIndex=0
self.canvas.itemconfigure(self.p2, fill=’red’)
self.canvas.update()
time.sleep(0.2)
else:
self.canvas.itemconfigure(self.p2, fill=’green’)
self.canvas.update()
def is_number(s):
try:
float(s)
return True
except ValueError:
pass

try:
import unicodedata
unicodedata.numeric(s)
return True
except (TypeError, ValueError):
pass

return False
#open serial port:
b=0
while b == 0:
try:
port=”/dev/ttyACM0″
print “open port “+port
ser = serial.Serial(port=port, baudrate=9600, bytesize=8, parity=’N’, stopbits=1, timeout=1)
b=1
except serial.SerialException:
string = “”
print “failed to open arduino port (retry in 10s)”
time.sleep(10)

#flush serial entries:
v0=0
v1=0
v2=0
while((v0>t0)|(v1>t1)|(v2>t2)):
string=ser.readline()
print string
list=string.split(‘ ‘, 3 )
if (len(list)==4):
if (is_number(list[0])): v0=float(list[0])
if (is_number(list[1])): v1=float(list[1])
if (is_number(list[2])): v2=float(list[2])
print v0,v1,v2
alien()

ser.close()

No se admiten más comentarios