Using an Arduino + acceleromter to monitor sleep

I have heard that a trip to a sleep doctor entails hooking up a bunch of sensors to you and they tell you things like how many times you woke up in the night. I don’t have a bunch of sweet EEG nodes, but I realized that I could easily create something that measures my relative movement throughout the night. Looking at an over-arching chart would probably give me a good idea of how I was really sleeping.

The Parts

I am currently working on a system which involves control theory and I purchased one of these IMUs from Sparkfun.

6DOF IMU

Sparkfun Razor 6DOF IMU

This is a 6 degree of freedom inertial measurement unit. It uses 2 gyroscopes and an accelerometer to give you information about your hardware’s orientation. I am waiting for some parts to come in so I just had it hooked up to one of my development boards just hanging out. I realized I could just use the accelerometer chip to relatively measure “how much” I was moving.

Accelerometers are really simple devices and they have become completely ubiquitous. If you are reading this on a mac or an iphone, then you are using one right now. A 3 axis accelerometer, such as the one on this board, can measure the orientation of the chip in relation to the earth’s magnetic field. Due to it’s sensitivity, it is also really good at measuring general vibration.

The Build

Hooking up to the accelerometer is pretty simple. You only need 5 pins: a 3.3V VCC and GND pin, then 3 analog pins for x, y, and z.

Boarduino + IMU wired

Boarduino + IMU wired

Since most accelerometers run on 3.3V, you will likely need to account for that in some way if you are running your arduino at a higher voltage. The x, y, and z pins output a voltage b/w 0 and 3.3V for each axis. For instance, if you are holding the chip completely level, you may see something like 1.65V on the X pin, as you turn it towards 90 degrees, it will increase. You can measure this using analogRead(int pin); .

The Code

The code for this project was so simple it took me under 1 hour to write the firmware and the client software. First the Arduino code:

#define DEBUG 0 //set to 1 for debug mode
#define AX 0 //accelerometer pin X
#define AY 1 //accelerometer pin Y
#define AZ 2 //accelerometer pin Z
#define DELAY 1000
#define SENSITIVITY 3 //movement required to send a movement event

//storage for x,y,z values
int x, y, z;
//storing the old values to compare relation movement
int old_x, old_y, old_z;
//our 'relative motion'
int movementFactor;

void setup() {
  Serial.begin(9600);
  readSensors();
  saveValues();//initialize
}

void loop() {

   readSensors();
   determineMovementFactor();

   if (movementFactor > SENSITIVITY) { 

      if (DEBUG) {
         Serial.print("x = ");
         Serial.print(x);
         Serial.print(" | y = ");
         Serial.print(y);
         Serial.print(" | z = ");
         Serial.print(z);
         Serial.print(" | movement = ");
         Serial.println(movementFactor);
      } else {
         Serial.println(movementFactor);
      }

      saveValues();
      delay(DELAY);
   }
}

/**
 * All we are doing here is finding the greatest derivative from
 * the 3 axises and choosing that as our relative movement factor
 */
void determineMovementFactor() {
   movementFactor = abs(old_x - x);
   int temp = abs(old_y - y); //due to impl of max(), no inline functions
   movementFactor = max(movementFactor, temp);
   temp = abs(old_z - z);
   movementFactor = max(movementFactor, temp);
}

void readSensors() {
   x = analogRead(AX);
   y = analogRead(AY);
   z = analogRead(AZ);
}

void saveValues() {
   old_x = x;
   old_y = y;
   old_z = z;
}

Assuming you don’t have it in DEBUG mode, it constantly reads the values off the accelerometer and finds the greatest change b/w all the axises. If that is greater than your SENSITIVITY, it sends it to the computer. I chose to do it this way rather than sending the movement factor every second so I could exploit the sparsity of the data and just use a scatter plot to stretch it out over the time domain. Now for the client side…

The client code is just a single python script. To get it working you need to install pyserial of course.

#!/usr/bin/env python
#
# @file: monitor.py
# @author: Benjamin Eckel
#
# To Run -->
#     $python monitor.py > output_file.csv
#                                                                                                              

import serial
import datetime

FTDI_USB = "/dev/tty.usbserial-A3000RBH"

if __name__ == "__main__":
    print "Time,Movement"
    ser = serial.Serial(FTDI_USB, 9600)
    while 1:
        movement = ser.readline()
        print "%s,%s" % (datetime.datetime.now().strftime("%H:%M:%S"), movement.rstrip())

This code is self explanatory, you run it and it prints out a comma-separated file with the hours, minutes, seconds, and the relative motion. You can redirect the output to whatever file or program you choose. Here is an example of some output:

Time,Movement
01:31:47,4
01:31:48,12
01:31:49,15
01:31:50,4
01:31:51,4
01:31:53,4
01:31:54,27
01:31:55,6
01:31:56,12
01:31:57,16
01:31:58,6
01:31:59,5
01:32:00,5
01:32:02,4
01:32:03,4
01:32:06,4
01:32:07,4
01:32:08,4
01:32:09,4

All you need to change is your FTDI_USB location. If you don’t know yours, plug in your arduino and run this command:

ls /dev/usb.tty.usb*

This is assuming you are running OS X or Linux of course. Windows uses COM ports. Refer to pyserial for help.

The Installation

To get good readings, it is best to place the sensor somewhere on your mattress that experiences the maximum displacement of the surface (the anti-node) caused by your movements. You can program it in DEBUG mode and try different locations out. I just wrapped the sensor in a sock and stuck it in one of my pillows.

Sock wrapped sensor

Sock wrapped sensor

The Results

To graph the results, I imported the resulting csv file into excel and created a scatter plot. This is my sleep from June 20 1:30AM to 11:00AM [ took a while to get out of bed :) ]:

Sleep chart thumb

Click to view full chart

From what little I know about the subject, I think I should be seeing spikes separated by intervals of about 90 minutes (the time it takes to get a full cycle of sleep). There are definitely some abnormalities in there. I am going attempt to do this for about a week and maybe send the results to a doctor friend.

1 comment so far ↓

#1 David Duval on 08.08.12 at 3:59 pm

Very cool project. I’m thinking of building something like this to measure my own sleep, and I’ll be interested to hear what your doctor friend says about it.

I think the accelerometer measures orientation relative to Earth’s gravitational field, not magnetic field :)

Leave a Comment