In this tutorial i will show, how i made my own sleep tracking device with Arduino. It will count total sleep time as well as light sleep and deep sleep. You might be wondering how sleep tracking fitness band works. You will get the answer in this video. So lets get started.

For this you will need,

  1. Arduino Nano,
  2. MPU6050 Accelerometer Module,
  3. Bluetooth module (HC-05),
  4. Lipo battery or Bluetooth battery
  5. Jumper wires.

I did lots of experimentation to find out sleep tracking algorithm. I changed algorithm in every experiment. It is just a trial code, before we go to test it for a long hours. In this code I reduced the sleep confirmation time to 10 seconds. Later in this tutorial, I will tell you, where i got this “sleep confirmation time”, “interruption” and “deep sleep time” etc. Within 10 seconds if it detects hand movement then it will make start timer equal to zero.

movement detected within 10 seconds

Movement detected within 10 seconds, Timer start again

If it successfully cross the 10 seconds without any movement. Then it will start counting light sleep.

successfully cross 10 second

Successfully cross the 10 second without any movement

Now it is in sleep mode. If you move your hand it will not start time from zero. It will count interrupt.

light sleep interrupt

Light Sleep Interrupt

If it successfully cross 30 seconds without movement means you are in deep sleep. It will start to count deep sleep.

successfully cross 30 second in light sleep

successfully cross 30 without any movement second in light sleep

If you move your hand in deep sleep. It will kick out from deep sleep and again go to light sleep and also make interrupt equal to 1.

interruption in deep sleep again started light sleep

Interruption in deep sleep again started light sleep

If 10 second you don’t move your hand it will make interrupt equal to zero. And As you are in sleeping mode. It will give you 5 chance, if within 30 second your hand move 5 times. It means your are awake or you are not sleeping. It will comes out of the sleeping mode and stop light sleep timer.  After 5 interruption it will count total light sleep, total deep sleep and total sleep.

5 interruption in light sleep

5 interruption in light sleep

This algorithm is not final. Watch my final code, it was a just trial to see algorithm is correct or not.

Download library for MPU6050 accelerometer from github OR you can download it from here because github library may change by the time or it may not work.

Download MPU6050 library: MPU6050_tockn-master

sleep tracking circuit
Arduino Sleep Tracking Fitness Band Code:
#include <SoftwareSerial.h>
#include <MPU6050_tockn.h>
#include <Wire.h>

MPU6050 mpu6050(Wire);
SoftwareSerial MySerial(7, 8); // pin 7 connects to TX of HC-05 | pin 8 connects to RX of HC-05

long timer = 0;
long sleep_timer_start, sleep_timer_end,sleep_timer_end2;
float x,y,z;
int activate, interrupt,stage_sleep_time, interrupt_sleep_timer,interrupt_for_deep_sleep, total_sleep, total_deep_sleep, total_light_sleep, deep_sleep, light_sleep, interrupt_timer=0;
void setup() {
MySerial.begin(9600);
Wire.begin();
mpu6050.begin();
//mpu6050.calcGyroOffsets(true);

}

void loop() {
mpu6050.update();

if(millis() - timer > 1000){ 
x = mpu6050.getGyroX();
y = mpu6050.getGyroY();
z = mpu6050.getGyroZ();

if (activate == 0){ // first sleep confirmation
if ((x<=20 || x>=-20) && (y<=20 || y>=-20) && (z<=20 || z>=-20)) {
sleep_timer_start = millis()/1000-sleep_timer_end;
if (sleep_timer_start == 300){
activate = 1;}
}
if ((x>=20 || x<=-20) || (y>=20 || y<=-20) || (z>=20 || z<=-20)){
sleep_timer_end =(millis()/1000); }
}

if (activate == 1){ // sleeping mode
light_sleep = (millis()/1000)-sleep_timer_end;

if (interrupt == 0){
if (light_sleep >= 4200){
if (interrupt_for_deep_sleep > 4200){
if (light_sleep - interrupt_sleep_timer >= 600){
deep_sleep = light_sleep - interrupt_for_deep_sleep;
}
}
}
}
light_sleep = light_sleep - deep_sleep;

if ((x>=20 || x<=-20) || (y>=20 || y<=-20) || (z>=20 || z<=-20)){
interrupt_sleep_timer = (millis()/1000)-sleep_timer_end; 
interrupt_for_deep_sleep = light_sleep;
interrupt =interrupt+1;
delay(8000);}



if ((millis()/1000)- sleep_timer_end -interrupt_sleep_timer > 300) {
interrupt =0; 
}

if ((millis()/1000)- sleep_timer_end - interrupt_sleep_timer <= 300){
if (interrupt >=5){
sleep_timer_end =(millis()/1000);
if (light_sleep >= 900){ // second sleep confirmation
total_light_sleep = total_light_sleep + light_sleep;
total_deep_sleep = total_deep_sleep + deep_sleep;
total_sleep = total_light_sleep + total_deep_sleep; }
activate =0;
interrupt =0;
deep_sleep= 0;
light_sleep= 0;
interrupt_sleep_timer=0;
interrupt_for_deep_sleep=0;
}
}

}
stage_sleep_time = light_sleep + deep_sleep; 
if (stage_sleep_time >= 5400){
sleep_timer_end =(millis()/1000);
total_light_sleep = total_light_sleep + light_sleep;
total_deep_sleep = total_deep_sleep + deep_sleep;
total_sleep = total_light_sleep + total_deep_sleep; 
activate =0;
interrupt =0;
deep_sleep= 0;
light_sleep= 0;
interrupt_sleep_timer=0;
interrupt_for_deep_sleep=0; 
}

MySerial.print(sleep_timer_start); // just to know code and sensor working fine
MySerial.print(",");
if (light_sleep >= 900){ 
MySerial.print(light_sleep/60);
MySerial.print(",");
MySerial.print(deep_sleep/60);
MySerial.print(","); 
MySerial.print(total_light_sleep/60);
MySerial.print(",");
MySerial.print(total_deep_sleep/60);
MySerial.print(",");
MySerial.print(total_sleep/60);
MySerial.print(";"); }
else {
MySerial.print(0);
MySerial.print(",");
MySerial.print(0);
MySerial.print(","); 
MySerial.print(total_light_sleep/60);
MySerial.print(",");
MySerial.print(total_deep_sleep/60);
MySerial.print(",");
MySerial.print(total_sleep/60);
MySerial.print(";");
} 
timer = millis();
}

}

I wore my honor fitness band and this sleeping tracking Arduino band on same hand. To see how it performs compare to Honor fitness band.

arduino sleep tracking and fitness band

Experiment 1:

I was not expecting this result. It is really good. Even experiment 1 algorithm was not that good, compare to my final algorithm. But I got few bugs in my code with this experiment. And I corrected it for second experiment.

Experiment 1

Experiment 2:

You can see total sleep time is somewhat match with my honor band. But deep sleep is really deep. So i need to do some adjustment in my algorithm for deep sleep.

Experiment 2

Experiment 3:

It is working better and better with the experiment. But i will make more powerful algorithm and update the video. Make sure you subscribe to the channel.

Experiment 3

I didn’t use it to track whole night sleep. Because my battery would die and i will lose my sensor data too.

How this algorithm is working?

I am using my Honor Band A2 for around 2 years. So i know how it is working. To know more about their algorithm. I slept for 2 hours with camera on, which is recording my whole body movement. Especially hand movement. From this video I got my “sleep confirmation time”, “deep sleep”, “interruptions” require to confirm you are not sleeping or awake. I have read somewhere our body doesn’t move much in deep sleep. So that part also can be utilize in counting deep sleep.

Code Explanation:

Lets see the final code.

Store gyro values for x, y and z direction in x, y and z.

x = mpu6050.getGyroX();
y = mpu6050.getGyroY();
z = mpu6050.getGyroZ();

By default activate equal to zero. And it will check condition, If our hand is not moving or in rest. This condition will be true. It will start sleep timer.

if (activate == 0){ 
if ((x<=20 || x>=-20) && (y<=20 || y>=-20) && (z<=20 || z>=-20)) {
sleep_timer_start = millis()/1000-sleep_timer_end;
if (sleep_timer_start == 300){
activate = 1;}

I used two confirmation for sleep. This is first confirmation for sleep. If our hand is not moving for 300 second i.e 5 minutes. It will make activate equal to one and start counting light sleep.

If within 5 minutes our hand move then it will gain start the timer.

if ((x>=20 || x<=-20) || (y>=20 || y<=-20) || (z>=20 || z<=-20)){
sleep_timer_end =(millis()/1000); }
}

If activate is 1 then we are in sleeping mode. It will start counting light sleep. But it will not print light sleep time in the app. It will wait for second confirmation of sleeping before putting values on mobile phone screen. It will check if light sleep is more than 15 minutes then it will count that time as a light sleep. If it is less than 15 minutes it will not be counted.

if (light_sleep >= 900){
total_light_sleep = total_light_sleep + light_sleep;
total_deep_sleep = total_deep_sleep + deep_sleep;
total_sleep = total_light_sleep + total_deep_sleep; }
activate =0;
interrupt =0;
deep_sleep= 0;
light_sleep= 0;
interrupt_sleep_timer=0;
interrupt_for_deep_sleep=0;
}

if you are in sleeping mode then your hand movement doesn’t make light sleep equal to zero. Whenever your hand move it will count interrupt.

if ((x>=20 || x<=-20) || (y>=20 || y<=-20) || (z>=20 || z<=-20)){
interrupt_sleep_timer = (millis()/1000)-sleep_timer_end; 
interrupt_for_deep_sleep = light_sleep;
interrupt =interrupt+1;
delay(8000);}

If within 5 minutes 5 interruption is done. It means you are awake and it will make activate equal to zero. And sum up the light sleep and deep sleep time in total sleep time.

if ((millis()/1000)- sleep_timer_end - interrupt_sleep_timer <= 300){
if (interrupt >=5){
sleep_timer_end =(millis()/1000);
if (light_sleep >= 900){ // second sleep confirmation
total_light_sleep = total_light_sleep + light_sleep;
total_deep_sleep = total_deep_sleep + deep_sleep;
total_sleep = total_light_sleep + total_deep_sleep; }
activate =0;
interrupt =0;
deep_sleep= 0;
light_sleep= 0;
interrupt_sleep_timer=0;
interrupt_for_deep_sleep=0;
}
}

if your last interruption was 5 minutes ago then it will make interrupt is equal to zero.

if ((millis()/1000)- sleep_timer_end -interrupt_sleep_timer > 300) {
interrupt =0; 
}

When sleep cycle starts after 70 minutes, we go to deep sleep. It will see if light sleep is greater than 70 minutes and body doesn’t move for 10 minutes then it will start counting time for deep sleep.

if (interrupt == 0){
if (light_sleep >= 4200){
if (interrupt_for_deep_sleep > 4200){
if (light_sleep - interrupt_sleep_timer >= 600){
deep_sleep = light_sleep - interrupt_for_deep_sleep;
}
}
}

Most of adults have 90 minutes sleep cycle time. So I have added 90 minutes sleep stage time. When it reaches to 90 minutes. It will again start the light sleep but before starting it again it will sum up the values in total sleep values.

stage_sleep_time = light_sleep + deep_sleep; 
if (stage_sleep_time >= 5400){
sleep_timer_end =(millis()/1000);
total_light_sleep = total_light_sleep + light_sleep;
total_deep_sleep = total_deep_sleep + deep_sleep;
total_sleep = total_light_sleep + total_deep_sleep; 
activate =0;
interrupt =0;
deep_sleep= 0;
light_sleep= 0;
interrupt_sleep_timer=0;
interrupt_for_deep_sleep=0; 
}

I am adding “code is working” here in the code. Because when we connect the app to the bluetooth, there is no way to find it. It is working or not, especially in this case. If we see it showing values to “code is working” and move sensor little bit then again it start time from zero. It means sensor etc working fine. If you want you can add directly sensor value.

This code will print the values to the mobile phone via Bluetooth.

MySerial.print(sleep_timer_start); // just to know code and sensor working fine
MySerial.print(",");
if (light_sleep >= 900){ 
MySerial.print(light_sleep/60);
MySerial.print(",");
MySerial.print(deep_sleep/60);
MySerial.print(","); 
MySerial.print(total_light_sleep/60);
MySerial.print(",");
MySerial.print(total_deep_sleep/60);
MySerial.print(",");
MySerial.print(total_sleep/60);
MySerial.print(";"); }
else {
MySerial.print(0);
MySerial.print(",");
MySerial.print(0);
MySerial.print(","); 
MySerial.print(total_light_sleep/60);
MySerial.print(",");
MySerial.print(total_deep_sleep/60);
MySerial.print(",");
MySerial.print(total_sleep/60);
MySerial.print(";");
}

I am thinking to make an updated videos for pedometer and this sleep tracking band with much more powerful algorithm. So make sure you subscribe to the channel. I hope you will like my effort. Let me know how this is going for you.

Till then keep learning keep making.