Skip to content

The Making of Breathless

December 16, 2010

To get to this:

I needed sensors to measure my breath, a microprocessor to convert the analog voltage sensor values into a byte meaningful to a computer, a serial connection, and a program to visualize the breathing.  Each step required tools and design.

Breath Measurement

Right off the bat, how does one measure breath?  Meter the air flowing through your mouth or nostrils?  Is that really measuring the exchange of oxygen and carbon dioxide in the alveoli?  What if you want something less invasive?  I settled on simply measuring the change in diameter of my chest and belly, modeling diaphragmatic and belly breathing.  My solar plexus seems to be the approximate height at which diaphragmatic breathing makes the most visible difference to chest diameter, and my belly button likewise to belly diameter, but I emphasize that the data now being taken off these sensors is an approximation of the actual act of breathing, with the aim of conveying some information about the nature of that breath back to the user.

Selection of the sensor is critical.  There are a number of conductive fabrics and threads out there, but I needed something that changed resistance values as it stretched.  Some fabrics do this, but it is more due to the warp and weave of the fabric than any stretching of the thread itself.  Images Scientific Instruments makes a great polymer sensor that develops very predictable resistance values as it is stretched axially (http://www.imagesco.com/sensors/stretch-sensor.html):

At rest it has a nominal resistance of 1000 ohms per inch, and when stretched 50%, the resistance doubles to 2000 ohms per inch.

I created two straps of canvas webbing with quick release mechanisms to gird myself at those locations, and then cut them at the sensor location to allow it to expand and contract as I breathed.  I reinforced the sensor with elastic so that all of the stress would not be on the sensor itself.

I cut the sensor material into 2″ lengths and crimped terminals onto the ends:

The safety pins were a temporary strategy, and I was planning to sew the terminals to the canvas, but they are working just fine for the time being:

Here were the trial connections to the breadboard:

The initial board looked like this:

Ignore the Op-Amp in the center.  That was part of another project described earlier where I was trying to filter signals with galvanic skin response.  To the right you can see two pairs of red and green wires coming off the board: they go to the two ends of the stretch sensors.  There’s a voltage divider circuit there for each of them, with green and yellow wires going into the AnalogIn pins, and resistors going to ground.  The XBee radio is there for wireless serial communication.

The final breadboard is a lot neater, and looks like this:

Note the quick-release spade terminals have replaced the alligator clips.  Handling it this way instead of just hard-wiring allows me to hide the board in my jacket pocket and run the wires up my sleeve to the belts.  I used stranded wire.  It’s much more flexible, with less likelihood of cracking as I’m moving around.

Soldering to the terminals is kind of ugly though.  They heat up much more slowly than the wire:

Here’s the setup from the back, and some close-ups:

Microprocessor

Obviously, I used the Arduino to convert the analog voltage sensor values to bytes.  The code is quite simple:


/*
Respiration Sensor Sketch
With Handshaking

10/24/2010
modified 11/14/10: added handshaking

M. Fleisig

Based on DanO's MultiSensor Send: http://itp.nyu.edu/~dbo3/roy/?p=25

This sketch requires two analog sensors.
*/

int diaphragm;
int belly;

void setup() {
Serial.begin(9600);
Serial.write(10);
}

void loop() {

if (Serial.available() > 0) //Only send out if something has come in
//In this case, anything received will trigger a send
{
Serial.read();

belly = analogRead(4);
Serial.print(belly);
Serial.print(",");

diaphragm = analogRead(5);
Serial.print(diaphragm);
Serial.print(",");

Serial.write(10);

}
}

 

A Serial Connection

This would work just fine hardwired to a computer with a USB cable, but I want to be able to walk around with it, sleep with it, and be able to get up and pour myself a cup of coffee without pulling everything off the table.  To really be free, a bluetooth connection to my phone would be nice, but I’ve got an iPhone, and they’re not super friendly about developing that portion of their hardware–at least not right now.  I’ve got some experience with XBee’s, so I decided to go with them, although it will limit the distance I can range from my laptop.  There’s always something to say about working with them, and once I got the hang of them, they’re quite friendly, but I’m going to save that for another day.  Be sure to disconnect the TX/RX pins (the blue and yellow wires at digital pins 0 and 1) if you need to connect via USB.  Note that I’m using the XBee in perhaps its most basic configuration, so I only have power, ground, TX and RX.  I just realized looking at these pictures that I am supplying the XBee with 5 volts in the final board, and 3.3 V in the prototype.  This would certainly account for why I had to modify the mapped values.  I need to figure out whether this is a problem, in which case I need to fix it asap.

…………………………………………………………………………………………..

UPDATE: Yeah, fubar.  Tom confirmed it would be wise to correct the voltage, and that I could eventually fry the XBee; I’m glad I caught it.  I dropped the voltage for the entire project to 3.3V and remapped my max and min values.  See my Processing code below.

Moral: Document, document, document!
…………………………………………………………………………………………..

Here’s the final board on battery power, and the XBee Explorer connected to my laptop:

A Program to Visualize the Breathing

Finally, here is the Processing Code.  The handshaking is critical to keeping Processing and the Arduino synchronized.
…………………………………………………………………………………………..

UPDATE: With the project voltage dropped to 3.3V, I remapped the sensor values as follows:

 

int minDiaph = 575; // Min Sensor Value
int maxDiaph = 605; // Max Sensor Value
int minBelly = 580; // Min Sensor Value
int maxBelly = 600; // Max Sensor Value

 

These hard max and min’s are inelegant, though, and I am going to try to implement Chris Allick’s suggestion that Processing dynamically reset those values based on what’s next in Serial. I’ve also got to work on the smoothing.  It looks like I’m currently averaging every two, but I’m not really: the previous value is actually the midpoint of the range, so this could be causing problems.  It’s possible as well that in adding and subtracting the tiny percentage of the range, depending on inhalation and exhalation, it is contributing to the jitter.  I’m doing that to model the growing staleness of air held in the lungs, and the accelerating freshness of air rushing in.  Possible options to deal with the jitter are to play with that percentage, the range, or take a true average of every three or more readings.
…………………………………………………………………………………………..


/*
Respiration Sketch
With Handshaking

First modified 24 Oct 2010
Subsequent modification: 25 Oct 2010
by Morgen Fleisig

Modified from:

Serial String Reader
Language: Processing

Reads in a string of characters from a serial port until
it gets a linefeed (ASCII 10). Then splits the string into
sections separated by commas. Then converts the sections to ints,
and prints them out.

created 2 Jun 2005
modified 6 Aug 2008
by Tom Igoe
*/

import processing.serial.*; // import the Processing serial library
Serial myPort; // The serial port

float percent = 0.135; //Percentage of range to test
//(e.g., considered to be an inhalation or exhalation)

float bgcolor; // Background color

float rRED = 224; //Randomly from Fisk Mississippi map RED
float gRED = 69;
float bRED = 63;

float rBLUE = 153; //Randomly from Fisk Mississippi map BLUE
float gBLUE = 204;
float bBLUE = 204;

float fcolorDiaphR = 188; // Diapragm fill color value
float fcolorDiaphG = 136; // Diapragm fill color value
float fcolorDiaphB = 133; // Diapragm fill color value

float fcolorBellyR = 188; // Belly fill color value
float fcolorBellyG = 136; // Belly fill color value
float fcolorBellyB = 133; // Belly fill color value

float colorIncrementer = 1.6;

float incrR = colorIncrementer*percent * (71); //HARD-CODED COLOR RANGE VALUES--SHOULD BE EXTERNALIZED
float incrG = colorIncrementer*percent * (135);
float incrB = colorIncrementer*percent * (141);

float diaDiaph; // Diaphragm ball Diameter
float diaBelly; // Belly ball Diameter

int minValue = 0; // Min analogRead Value
int maxValue = 1024; // Max analogRead Value

int minDiaph = 885; // Min Sensor Value
int maxDiaph = 925; // Max Sensor Value
int minBelly = 865; // Min Sensor Value
int maxBelly = 908; // Max Sensor Value

int nowDiaph; // Current Sensor Value
int nowBelly;
int prevDiaph = (minDiaph + maxDiaph)/2; // Previous Sensor Value set to MIDWAY
int prevBelly = (minBelly + maxBelly)/2;

int rangeDiaph = maxDiaph - minDiaph; //Range of Sensor Values
int rangeBelly = maxBelly - minBelly;
float rangeDiaphPC = percent*rangeDiaph;
float rangeBellyPC = percent*rangeBelly;

void setup() {
size(440,700);

// List all the available serial ports
println(Serial.list());

// I know that the first port in the serial list on my mac
// is always my Arduino module, so I open Serial.list()[0].
// Change the 0 to the appropriate number of the serial port
// that your microcontroller is attached to.
myPort = new Serial(this, Serial.list()[0], 9600);

myPort.write(65); //request a value

// read bytes into a buffer until you get a linefeed (ASCII 10):
myPort.bufferUntil('\n');
} //setup

void draw() {
background(bgcolor);
smooth();

fill(fcolorDiaphR, fcolorDiaphG, fcolorDiaphB);
ellipse(width/2, height/4, diaDiaph, diaDiaph);

fill(fcolorBellyR, fcolorBellyG, fcolorBellyB);
ellipse(width/2, 3*height/4, diaBelly, diaBelly);
} //draw

// serialEvent method is run automatically by the Processing applet
// whenever the buffer reaches the byte value set in the bufferUntil()
// method in the setup():

void serialEvent(Serial myPort) {
// read the serial buffer:
String myString = myPort.readStringUntil('\n');
// if you got any bytes other than the linefeed:
if (myString != null) {

myString = trim(myString);

// split the string at the commas
// and convert the sections into integers:
int sensors[] = int(split(myString, ','));

// print out the values you got:
for (int sensorNum = 0; sensorNum 1) {
diaBelly = map(sensors[0], minBelly, maxBelly, height/2, height/6);
diaDiaph = map(sensors[1], minDiaph, maxDiaph, height/2, height/6);

nowBelly = sensors[0];
nowDiaph = sensors[1];

if (nowBelly > prevBelly + rangeBellyPC)
{
bellyExhale();
}
else if (nowBelly prevDiaph + rangeDiaphPC)
{
diaphragmExhale();
}
else if (nowDiaph rBLUE )
{
fcolorBellyR -= incrR;
}

if ( fcolorBellyG < gBLUE + 1 )
{
fcolorBellyG += incrG;
}

if ( fcolorBellyB < bBLUE + 1 )
{
fcolorBellyB += incrB;
}

prevBelly = nowBelly;
} //bellyInhale

void bellyExhale()
{
if ( fcolorBellyR gRED )
{
fcolorBellyG -= incrG;
}

if ( fcolorBellyB > bRED )
{
fcolorBellyB -= incrB;
}

prevBelly = nowBelly;
} //bellyExhale

void diaphragmInhale()
{
if ( fcolorDiaphR > rBLUE )
{
fcolorDiaphR -= incrR;
}

if ( fcolorDiaphG < gBLUE + 1 )
{
fcolorDiaphG += incrG;
}

if ( fcolorDiaphB < bBLUE + 1 )
{
fcolorDiaphB += incrB;
}

prevDiaph = nowDiaph;
} //diaphragmInhale

void diaphragmExhale()
{
if ( fcolorDiaphR gRED )
{
fcolorDiaphG -= incrG;
}

if ( fcolorDiaphB > bRED )
{
fcolorDiaphB -= incrB;
}

prevDiaph = nowDiaph;
} //diaphragmExhale

 

Advertisements

From → Rest of You

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: