Posted on Wed 13 April 2016

# Standing Automation

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:

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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:

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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

© Julian Schrittwieser. Built using Pelican. Theme by Giulio Fidente on github. .