I've had a standing desk at work for a long time, but I've always felt that I wasn't using it enough, that I still spent most of my timing sitting.
This week I finally decided to do something about it.
I bought a small sonar sensor (LV-MaxSonar-EZ1), hooked it up to an Arduino and added a little Python script to sample the sensor once a minute.
The sonar is mounted to my table and measures the distance to the floor, and with ~3 cm accuracy it's very easy to distinguish whether I'm sitting or standing.
Since the Sonar happily runs of 5V, I just connected its power input pins directly to the VCC and GND pins of my Arduino. Conveniently it also provides the measured distance as analog voltage on a pin, I just connected that to A0 on the Arduino.
The Arduino code to regularly sample the sonar is then very simple, even with basic smoothing included:
void setup() {
Serial.begin(9600);
}
const float sample_duration = 500;
void loop() {
// Protect against timer overflow.
unsigned long start = millis();
const unsigned long deadline = start + sample_duration;
double cumulative_sensor_value = 0;
unsigned long steps = 0;
while (millis() < deadline && millis() >= start) {
cumulative_sensor_value += analogRead(A0);
steps++;
}
// Sonar values are (Vcc/512) per inch, Arduino sensor range is [0, 1023].
float distance_inch = (cumulative_sensor_value / steps) / 2.0;
float distance_m = distance_inch * 2.54 / 100;
Serial.println(distance_m);
}
The Arduino includes a USB serial interface, so I can just connect it directly to my computer and it's straightforward to read its output with Python:
import serial
import sys
import time
desk_height = None
deadline = time.time() + 30
with serial.Serial(port='/dev/ttyUSB0', timeout=1) as ser:
while desk_height is None:
line = ser.readline().strip()
if line:
try:
desk_height = float(line)
except ValueError:
pass
if time.time() > deadline:
print "failed to read desk height"
sys.exit(1)
print 'standing' if desk_height > 0.5 else 'sitting'
At this point I can do whatever I want with the data - create daily or weekly graphs, send automated email reminders if I haven't been standing in the last 2 hours, etc.
To ignore periods where I'm not actually at my computer, I use xprintidle
, which prints the time in milliseconds since the last user activity, i.e. mouse or keyboard input.
Tags: misc