BBC micro:bit
MPRLS Pressure Sensor
Introduction
The Adafruit MPRLS Ported Pressure Sensor Breakout is a pressure sensor that has a little port that you can connect a tube to. The board costs around £14 and needs you to solder on some headers. The board works at 3V with the micro:bit over i2c and spits out numbers for you with far less work than some other pressure sensors need. The port is 2.5mm in diameter and it is easy to get some silicone tubing that will fit snugly over the port. This allows you to blow or sip air in or from the tube and get a reading on the sensor.
In the image, I have the micro:bit in an Elecfreaks 'sensor:bit'. This board has a built-in buzzer on pin 0, which was used for one of the experimental programs on this page.
Programming
In this first program I was just trying to see what kind of readings I was going to get from the sensor. Using the REPL in Mu, I echoed them to the screen whilst I copied, converted and trimmed from the Arduino library that Adafruit have published.
from microbit import * def _status(): buf = i2c.read(0x18, 1) return buf[0] def _raw(): i2c.write(0x18,b'\xaa\x00\x00') a = _status() & 0x20 while a: sleep(10) a = _status() & 0x20 buf = i2c.read(0x18,4) a = buf[0] if a & 0x01 or a & 0x04: return 0xFFFFFFFF return (buf[1]<<16) + (buf[2]<<8) + buf[3] def read_pressure(): raw = _raw() if raw==0xFFFFFFFF: return -1 psi = ((raw-0x19999A) * 25)/0xCCCCCC return psi def hpa(p): return p * 68.947572932 while True: p = read_pressure() print(p,"PSI.",hpa(p),"hPA") sleep(50)
This second program was about detecting the sip and puff. I took a handful of readings to get a base from which to detect upward and downward changes in pressure.
from microbit import * def _status(): buf = i2c.read(0x18, 1) return buf[0] def _raw(): i2c.write(0x18,b'\xaa\x00\x00') a = _status() & 0x20 while a: sleep(10) a = _status() & 0x20 buf = i2c.read(0x18,4) a = buf[0] if a & 0x01 or a & 0x04: return 0xFFFFFFFF return (buf[1]<<16) + (buf[2]<<8) + buf[3] def read_pressure(): raw = _raw() if raw==0xFFFFFFFF: return -1 psi = ((raw-0x19999A) * 25)/0xCCCCCC return psi def hpa(p): return p * 68.947572932 def sip_puff(m,o): p = hpa(read_pressure()) if p<(m-o): return -1 elif p>(m+o): return 1 else: return 0 display.show(Image.SURPRISED) sleep(1000) # average of 10 readings mid = 0 for i in range(10): mid += hpa(read_pressure()) sleep(100) mid = mid / 10.0 print(mid) display.show(Image.HAPPY) sleep(1000) last = 0 sp = ["Sip", "None", "Puff"] while True: current = sip_puff(mid,30) if last!=current: print(sp[current+1]) last = current sleep(50)
Although the offset is fairly small, I found that I could comfortably trigger the sip and puff messages.
My final experiment was to see if performance was good enough to allow the sensor to be used for musical instrument purposes. The following program plays a note if the user puffs down the tube. Holding down the A button means you get a different note.
from microbit import * import music def _status(): buf = i2c.read(0x18, 1) return buf[0] def _raw(): i2c.write(0x18,b'\xaa\x00\x00') a = _status() & 0x20 while a: sleep(10) a = _status() & 0x20 buf = i2c.read(0x18,4) a = buf[0] if a & 0x01 or a & 0x04: return 0xFFFFFFFF return (buf[1]<<16) + (buf[2]<<8) + buf[3] def read_pressure(): raw = _raw() if raw==0xFFFFFFFF: return -1 psi = ((raw-0x19999A) * 25)/0xCCCCCC return psi def hpa(p): return p * 68.947572932 def sip_puff(m,o): p = hpa(read_pressure()) if p<(m-o): return -1 elif p>(m+o): return 1 else: return 0 display.show(Image.SURPRISED) sleep(1000) # average of 10 readings mid = 0 for i in range(10): mid += hpa(read_pressure()) sleep(100) mid = mid / 10.0 print(mid) display.show(Image.HAPPY) sleep(1000) while True: current = sip_puff(mid,30) if current==1: if button_a.is_pressed(): music.pitch(440,-1) else: music.pitch(494,-1) else: music.stop() sleep(20)
This last program worked a lot better than I thought. I was using the pressure sensor as a straight on/off switch and it proved pretty easy to start, stop and sustain the notes. The use of the button made the experience a little like covering up finger holes whilst blowing into a whistle. The sensor works well enough to make more projects like this possible.
Review
It's not a cheap sensor but it does its job really well. Getting clear readings that make sense is a lot easier than I have found with other pressure sensors and the code I have written could be trimmed a lot more. The reading of the status register is not as essential to the process as I thought it might be.
With the setup that I had for these projects, I could comfortably vary the reading by around 100 - 120 hectopascals, sipping as well as puffing. I have not yet established the extent to which a user can feel completely in control of that pressure though. For a project where that mattered, it might be worth looking more carefully at the range of the sensor and trying to find one that gives more resolution around the pressures that a user can generate.