Posted by kantch
The FSR is placed so that it senses the level of water in a glass. I used cotton in between so that the force gets more directed towards the center of the sensor (the most sensitive part). The computer displays a physical simulation of falling drops of water under gravity force alone. The program updates object's positions based on their previous location, mass (proportional to the cube of their scale on the display) and gravity force, which is directly read from the Arduino's serial output.
Language & packages used: Python; PySerial for reading data from the arduino's serial port; Pyglet for the animation (using sprites); Numpy for misc math functions.
The tricky part is that the serial port's speed and the animation speed are different (Arduino is faster than 2D rendering, at least when used at 11500 bauds), and one really wants to use the "last" Arduino's reading instead of the last "not yet" read. In my implementation, this is done by using a background thread (receiving) which continually updates the sensor's value, and a parallel thread (refresh) which uses this value to draw the animation.
Also, a little method takes care of auto-calibrating the measures (auto_calibration) between 0 and 1
*********************************************************************
from __future__ import print_function, division
import pyglet
from numpy.random import normal, uniform
from numpy import sqrt, array
import serial
from threading import Thread
window = pyglet.window.Window(1024,512)
pyglet.gl.glClearColor(1,1,1,1)
dropimage = pyglet.resource.image('droplet.png')
NDROPS = 50
drops=[]
for i in range(NDROPS):
drop = pyglet.sprite.Sprite(dropimage)
drop.scale = normal(0.08,0.02)
drop.position = uniform(0, 1024), uniform(0, 512)
drops.append(drop)
DT = 0.01
last_received = 0
PMIN=1024
PMAX=0
def auto_calibrate(x):
global PMIN
global PMAX
if x<PMIN:
PMIN=x
if x>PMAX:
PMAX=x
if PMAX == PMIN:
return 0
return (x-PMIN)/(PMAX-PMIN)
with serial.Serial('/dev/tty.usbmodemfa141', 115200, timeout = 1) as ser:
def refresh(t):
window.clear()
#read last pressure
G = (1-auto_calibrate(last_received))*30
for drop in drops:
drop.draw()
x, y=drop.position[0], 512-drop.position[1]
if y>600:
x, y=uniform(0, 1024) , 1
drop.position = array([x, 512-y]) + diff_pos(x, y, 5*drop.scale**3, G, DT)
def diff_pos(x, y, m, g, dt):
return array([0, -dt*sqrt(2*y*g/m)])
def receiving(ser):
global last_received
buffer = ''
while True:
buffer = buffer + ser.read(ser.inWaiting())
if '\n' in buffer:
lines = buffer.split('\n')
try:
last_received = int(lines[-2])
except:
last_received = last_received
print(last_received)
buffer = lines[-1]
Thread(target=receiving, args=(ser,)).start()
pyglet.clock.schedule_interval(refresh, 0.001)
pyglet.app.run()