Get up, From Your Computer

Project 2: Get Up From Your Computer!

I collaborated with Lauren Chong for this project.

Project

Our project idea was to create a device that notified the user when they have been sitting at their desk for too long. The original idea was to have 3 LEDs that indicated to the user that their time sitting in front of the computer is approaching its limit of around an hour. A green LED would light when 15min are left, a yellow LED lights when 10min are left, and a red LED lights when 5min are left. Once 5min are up, the Arduino would act as a keyboard emulator and log you off your computer. Then, after you move far enough away from your computer the keyboard emulator would unlock your screen.

For this project we needed an Arduino, LEDs, and we used a time of flight I2C sensor.

Schematics

 

Process

 
First, we wired the time of flight sensor and tested that it worked. Then, we wired 3 LEDs to make sure that worked as well. With both working, we combined the two circuits into one.

Next, we worked on getting our code working and this took the most time. Initially, we coded the three LEDs to cycle through with their time delays. Then we tried adding the keyboard emulator element to the code. This took a lot of debugging and also resolving a Windows issue that came up. Lastly, we added the code for the time of flight distance sensor. It took us a while to figure out the various loops to synchronize all the code sections and have all parts work correctly.

Finally, we worked on a small box enclosure that the user could put at the top of their monitor or below. We tried to make this enclosure as least obtrusive as possible.

Documentation

 
 
Here is the circuitry of the time of flight sensor and the 3 LEDs.

Code

Here is the working test of our final iteration.
 
#define OSX 0
#define WINDOWS 1
#define UBUNTU 2

#include "Keyboard.h"
#include "Adafruit_VL53L0X.h"
//#include "Mouse.h"

Adafruit_VL53L0X lox = Adafruit_VL53L0X();

unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;

const unsigned long period1 = 4000;  //the value is a number of milliseconds
const unsigned long period2 = 8000;
const unsigned long period3 = 12000;
const unsigned long period4 = 12100;
//const unsigned long period5 = 12000;

const byte ledPinG = 6;    //Green
const byte ledPinY = 8;    //Yellow
const byte ledPinR = 10;   //Red

//bool lights;

int platform = WINDOWS;

int distance = 0;
Here we are defining all our variables. 
 
void setup() {
  Serial.begin(9600);  //start Serial in case we need to print debugging info
  Keyboard.begin();
  //  lights = TRUE;
  pinMode(ledPinG, OUTPUT);
  pinMode(ledPinY, OUTPUT);
  pinMode(ledPinR, OUTPUT);

  if (!lox.begin()) {
    //    Serial.println(F("Failed to boot VL53L0X"));
    while (1);
  }

  startMillis = millis();  //initial start time
}
Here we are initializing our LEDs, our time of flight I2C distance sensor, and a counter to keep track of time.
 
void loop() {
  currentMillis = millis();
  while (currentMillis - startMillis < period4) {
    currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
    if (currentMillis - startMillis >= period1 && currentMillis - startMillis < period2)  //test whether the period has elapsed
    {
      digitalWrite(ledPinG, HIGH);
      digitalWrite(ledPinR, LOW);

    } if
    (currentMillis - startMillis >= period2 && currentMillis - startMillis < period3)
    {
      digitalWrite(ledPinY, HIGH);
      digitalWrite(ledPinG, LOW);

    } if (currentMillis - startMillis >= period3 && currentMillis - startMillis < period4)
    { digitalWrite(ledPinR, HIGH);
      digitalWrite(ledPinY, LOW);
Here, we are starting the counter and using it to measure time periods. The time periods are used to light a particular color LED once the correct time has passed. The green LED turns on first, then turns off while the yellow LED turns on, then this turns off and the red LED turns on.

We had some initial trouble understanding the currentMillis and startMillis variables in keeping time. We realized that at the end of the cycle, these variables would need to be reinitialized for the next cycle to occur. We also debugged and put in a while loop to get the entire cycle including the keyboard emulator and distance sensor sections to start over again as well.
 
} if (currentMillis - startMillis >= period4) {
      //    lights = !lights;
      switch (platform) {
        case WINDOWS:
          Keyboard.press(KEY_LEFT_CTRL);
          Keyboard.press(KEY_LEFT_ALT);
          Keyboard.press('s');
          delay(10);
          Keyboard.releaseAll();
      }
    }
  }
Here, we are creating a keyboard emulator. It presses the keys to turn the computer to sleep after a certain time period has passed. 

We initially thought about locking the person out of the computer completely but logistically it was easier to obtain the keys for putting the computer to sleep instead. Also, it made more sense from a user standpoint because we did not want our “punishment” for staying in front of the computer too long to be too harsh.
 
if (currentMillis - startMillis >= period4) {

    VL53L0X_RangingMeasurementData_t measure;
    distance = measure.RangeMilliMeter;

    lox.rangingTest(&measure, false); // pass in 'true' to get debug data printout!

    if (measure.RangeStatus != 4) {  // phase failures have incorrect data
      Serial.print("Distance (mm): "); Serial.println(measure.RangeMilliMeter);
      //              //          digitalWrite(ledPinR, HIGH);
      if (distance > 850) {
        delay(1);
        Keyboard.press(KEY_UP_ARROW);
        Keyboard.releaseAll();

        delay(2000);
        startMillis = currentMillis;

      }
    }
  }
  Serial.print(startMillis);
Serial.println(currentMillis);
//  if (currentMillis - startMillis > 
}
Here, the time of flight distance sensor is being initialized. It measures the distance of an object in front of it and once it reaches the noted threshold, the keyboard emulator is used to wake the computer. The counter variables are then reinitialized.

We took time in debugging this section of our code. We weren’t sure if we were getting readings initially and we didn’t know how to take the distance gathered from the sensor and use it in our code to create an action. Also, the computer would wake always even if the distance threshold was not met. This was resolved through debugging and entering an earlier while statement into the code.
 
#define OSX 0
#define WINDOWS 1
#define UBUNTU 2

#include "Keyboard.h"
#include "Adafruit_VL53L0X.h"
//#include "Mouse.h"

Adafruit_VL53L0X lox = Adafruit_VL53L0X();

unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;

const unsigned long period1 = 4000;  //the value is a number of milliseconds
const unsigned long period2 = 8000;
const unsigned long period3 = 12000;
const unsigned long period4 = 12100;
//const unsigned long period5 = 12000;

const byte ledPinG = 6;    //Green
const byte ledPinY = 8;    //Yellow
const byte ledPinR = 10;   //Red

//bool lights;

int platform = WINDOWS;

int distance = 0;

void setup() {
  Serial.begin(9600);  //start Serial in case we need to print debugging info
  Keyboard.begin();
  //  lights = TRUE;
  pinMode(ledPinG, OUTPUT);
  pinMode(ledPinY, OUTPUT);
  pinMode(ledPinR, OUTPUT);

  if (!lox.begin()) {
    //    Serial.println(F("Failed to boot VL53L0X"));
    while (1);
  }

  startMillis = millis();  //initial start time
}

void loop() {
  currentMillis = millis();
  while (currentMillis - startMillis < period4) {
    currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
    if (currentMillis - startMillis >= period1 && currentMillis - startMillis < period2)  //test whether the period has elapsed
    {
      digitalWrite(ledPinG, HIGH);
      digitalWrite(ledPinR, LOW);

    } if
    (currentMillis - startMillis >= period2 && currentMillis - startMillis < period3)
    {
      digitalWrite(ledPinY, HIGH);
      digitalWrite(ledPinG, LOW);

    } if (currentMillis - startMillis >= period3 && currentMillis - startMillis < period4)
    { digitalWrite(ledPinR, HIGH);
      digitalWrite(ledPinY, LOW);

    } if (currentMillis - startMillis >= period4) {
      //    lights = !lights;
      switch (platform) {
        case WINDOWS:
          Keyboard.press(KEY_LEFT_CTRL);
          Keyboard.press(KEY_LEFT_ALT);
          Keyboard.press('s');
          delay(10);
          Keyboard.releaseAll();
      }
    }
  }
  if (currentMillis - startMillis >= period4) {

    VL53L0X_RangingMeasurementData_t measure;
    distance = measure.RangeMilliMeter;

    lox.rangingTest(&measure, false); // pass in 'true' to get debug data printout!

    if (measure.RangeStatus != 4) {  // phase failures have incorrect data
      Serial.print("Distance (mm): "); Serial.println(measure.RangeMilliMeter);
      //              //          digitalWrite(ledPinR, HIGH);
      if (distance > 850) {
        delay(1);
        Keyboard.press(KEY_UP_ARROW);
        Keyboard.releaseAll();

        delay(2000);
        startMillis = currentMillis;

      }
    }
  }
  Serial.print(startMillis);
Serial.println(currentMillis);
//  if (currentMillis - startMillis > 
This is our whole code.
 

Enclosure Prototype

For our enclosure, we created a box with 3 holes for the 3 LEDs as well as a hole for the distance sensor. The bottom of the box is U-shaped so that it can sit on top of the monitor comfortably.
Here is our prototype when the yellow LED is lit.

What’s Next

 
One of the things we discussed, is that if we had the proper materials, ideally we could make our computer attachment smaller and less obtrusive to the user. Making the device smaller could mean that the user can go about doing their work without even noticing the device and thus the device would not disrupt the work flow.

Another area we could clean up is our code. We feel that there must be ways in which to make our code more concise.

For our demo, we reduced our testing time drastically so we could see the device cycle through the different LEDs and then cause the computer to fall asleep. In practice, the lights would only cycle after about 45min have elapsed. There is actually time being counted when the computer is put to sleep, then awakened, which means in our test this time affected our LEDs to start lightening quite quickly after waking the computer. We believe that if we increased our time limit as it was envisioned, this delay would not affect the LEDs as much.