Sniff is a "Scratch-like" programming language that's designed to help Scratchers move gently from Scratch to more conventional languages. They can start writing programs, without having to learn a new language because Sniff is based on Scratch. They learn a little more about variables, compiling, syntax errors (!), and they can have fun controlling real hardware while they're doing it.

Wednesday, 12 March 2014

The 20 cent Heart Monitor

We all love quick, and cheap science projects, so when I saw a "heart rate sensor for Arduino" on Ebay I almost grabbed one instantly... but then I looked a bit closer and realised that it looked a bit shoddy... Was I really getting value for money from my hard earned $2?

Reading the description and looking at the picture it appeared this thing was just and IR led, and photo-transistor soldered onto a PCB. The LED shines into your fingertip, the photo-resistor measures how much is reflected back (or transmitted - either should work). It turns out this is a perfectly reasonable way to measure blood flow. More blood means more (or maybe less?) reflection, means a changing voltage we can measure, and plot!

However I didn't feel like blowing a whole $2 on this - times are tight, and anyway I bought a whole bunch of IR emitter/photo-transistor packages last week to do proximity sensing! They're called TCRT5000's and for $2 you'll get a bag of ten. Wiring them up just needs a couple of resistors, and we can start measuring with them.


make pulseSensor analog input A5

when start
.forever
..say [ pulseSensor ]
..wait 0.1 secs

We need analog input so this isn't going to run on a Pi, but hooking this into an Arduino Uno I started getting measurements: about 0.9 when the sensor was clear, and about 0.03 when I put my thumb over it. The reading of 0.03 is a bit small, but importantly, it did seem to be changing in time with my pulse. I adjusted the resistor value on the photo-transistor, and got a reading of somewhere between 0.17 and 0.19 which was clearly indicating that I definitely have a pulse.

The coffee cup measurements from last week worked so well I thought that the tft screen might be worth another run out, and I could use the same two script approach:

when start
.set displayColor to 000
.tell tft to "clear"
.broadcast startMeasuring
.broadcast startDrawing

For the measuring thread I decided to include some averaging, so that the several readings are combined. With a bit of tweaking I ended up with:

make currentVal number
when startMeasuring
.forever
..set currentVal to 0.8 *currentVal +0.2 * pulseSensor
..wait 0.02secs

For drawing I wrote:
when startDrawing
.forever
..set displayY to (40*timer) mod 320
..
..set displayColor to 777
..set displayX to 0
..tell tft to "move"
..set displayX to 239
..tell tft to "hfill"
..
..set displayColor to 700
..set displayX to (currentVal)*50*200
..tell tft to "setPixel"

the tft device has an "hfill" command that makes it quick to blank out an individual line - there's no equivalent vfill (perhaps there should be?) so it was easiest to plot the graph from bottom to top, and then turn the screen around when it was finished. We pick a row based on time (40 samples per second was perfectly manageable with this hardware and looked about right), and assign that to displayY so all drawing takes place on that line.
We then use hfill to blank the line, and set a single pixel based on the current reading of the sensor. The result is a graph of my pulse! (sorry for the photo - it's hard to get a good picture of the screen when you've got to keep you thumb on the sensor!)

One minor problem was that depending on how hard I pressed and what part of my thumb I used the values could change substantially - the trace would disappear completely if I moved my thumb a little too much. We're only interested in the variation with a period of about 0.5 seconds, so the final refinement was to add an averageValue variable which is the average of the reading over several seconds. By removing the, we still get the the nice pulse, but the graph automatically centres itself on screen if you keep your finger still for a few seconds.

Here's the final code:

make pulseSensor analog input A5

make tft device
make displayX number
make displayY number
make displayColor number
make message string

when start
.set displayColor to 000
.tell tft to "clear"
.broadcast startMeasuring
.broadcast startDrawing

make currentVal number
make averageVal number

when startMeasuring
.forever
..set currentVal to 0.8 *currentVal +0.2 * pulseSensor
..set averageVal to 0.01*currentVal + 0.99*averageVal
..wait 0.02secs

when startDrawing
.forever
..set displayY to (40*timer) mod 320
..
..set displayColor to 777
..set displayX to 0
..tell tft to "move"
..set displayX to 239
..tell tft to "hfill"
..
..set displayColor to 700
..set displayX to (currentVal-averageVal)*50*200+120
..tell tft to "setPixel"

Isn't that the best $0.20 you ever spent?


No comments:

Post a Comment