Entries Tagged 'C' ↓

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.

Radioshack Infrared Receiver <--> Arduino

I just posted up an article on the Gumbolabs blog explaining how to use the Radioshack infrared receiver module. It contains Arduino code along with the explanations.

Aruduino ethernet shield and Rails

I just wrote an article on the GumboLabs blog about using the Arduino Ethernet shield. Be sure to check it out.

Parallax RFID reader <--> Arduino

Parallax RFID reader

Parallax RFID reader

I just recently wrote an article at the Gumbo Labs blog on interfacing to the Parallax RFID reader. Here is the final code if you are only looking for that:

/**
 * author Benjamin Eckel
 * date 10-17-2009
 *
 */
#define RFID_ENABLE 2   //to RFID ENABLE
#define CODE_LEN 10      //Max length of RFID tag
#define VALIDATE_TAG 1  //should we validate tag?
#define VALIDATE_LENGTH  200 //maximum reads b/w tag read and validate
#define ITERATION_LENGTH 2000 //time, in ms, given to the user to move hand away
#define START_BYTE 0x0A
#define STOP_BYTE 0x0D

char tag[CODE_LEN];  

void setup() {
  Serial.begin(2400);
  pinMode(RFID_ENABLE,OUTPUT);
}

void loop() {
  enableRFID();
  getRFIDTag();
  if(isCodeValid()) {
    disableRFID();
    sendCode();
    delay(ITERATION_LENGTH);
  } else {
    disableRFID();
    Serial.println("Got some noise");
  }
  Serial.flush();
  clearCode();
} 

/**
 * Clears out the memory space for the tag to 0s.
 */
void clearCode() {
  for(int i=0; i<CODE_LEN; i++) {
    tag[i] = 0;
  }
}

/**
 * Sends the tag to the computer.
 */
void sendCode() {
    Serial.print("TAG:");
    //Serial.println(tag);
    for(int i=0; i<CODE_LEN; i++) {
      Serial.print(tag[i]);
    }
}

/**************************************************************/
/********************   RFID Functions  ***********************/
/**************************************************************/

void enableRFID() {
   digitalWrite(RFID_ENABLE, LOW);
}

void disableRFID() {
   digitalWrite(RFID_ENABLE, HIGH);
}

/**
 * Blocking function, waits for and gets the RFID tag.
 */
void getRFIDTag() {
  byte next_byte;
  while(Serial.available() <= 0) {}
  if((next_byte = Serial.read()) == START_BYTE) {
    byte bytesread = 0;
    while(bytesread < CODE_LEN) {
      if(Serial.available() > 0) { //wait for the next byte
          if((next_byte = Serial.read()) == STOP_BYTE) break;
          tag[bytesread++] = next_byte;
      }
    }
  }
}

/**
 * Waits for the next incoming tag to see if it matches
 * the current tag.
 */
boolean isCodeValid() {
  byte next_byte;
  int count = 0;
  while (Serial.available() < 2) {  //there is already a STOP_BYTE in buffer
    delay(1); //probably not a very pure millisecond
    if(count++ > VALIDATE_LENGTH) return false;
  }
  Serial.read(); //throw away extra STOP_BYTE
  if ((next_byte = Serial.read()) == START_BYTE) {
    byte bytes_read = 0;
    while (bytes_read < CODE_LEN) {
      if (Serial.available() > 0) { //wait for the next byte
          if ((next_byte = Serial.read()) == STOP_BYTE) break;
          if (tag[bytes_read++] != next_byte) return false;
      }
    }
  }
  return true;
}

Facebook Bombing (aka F-bombing)

A while back, in the good ole days of sticking it to Mark Zuckerberg, I came up with a concept I now call Facebook bombing (aka F-bombing). Basically, Facebook has it’s own little markup language in which you can use the ‘p’ tag to create a line break. I haven’t tried it yet, but I think you can insert this anywhere on your page. I originally started doing this in posts to people’s walls to make my messages look special and pretty. But then, I started thinking, how many of these can you fit in a post. Facebook posts have a character limit, but this tag doesn’t count as a character, so you can fit about 1000 of them. Thus the idea was born and I created the Longest Facebook Page group (which was actually a front competition to find a new way to insert iframes into pages). It was a huge disaster. Anyway, it still works, so if you want to do it, follow these instructions:

  1. Choose a victim.
  2. Go to this link and copy all the p’s by going to [ Edit - Select All ] on your browser’s menu and hitting ctrl+c (or apple+c).
  3. Paste into the post box with ctrl+v (or apple+v).
  4. Hit post.
  5. Laugh at your friend’s expense.

Like I said, I could only fit 1000 of them but if you want to do some bounds testing yourself, here is the source C program to generate as many tags as you want. Keep in mind that this is harmless and they can easily delete your post but for the time it is there, it is funny. One more thing, if you do this to my page, prepare to be Facebook H-bombed.

**Update : This no longer works :(**