How to use the accelerometer in a ThinkPad x220
Older ThinkPads had built-in accelerometers so they could detect falls
and protect the hard disk. It’s really easy to get access to the
accelerometer data in Linux: just install tp_smapi
and then load the
hdaps module with sudo modprobe hdaps
(or add it to the list of
modules to be loaded at boot in /etc/modules
or
/etc/modules-load.d/modules.conf
). You should then be able to get
the accelerometer output from the file
/sys/devices/platform/hdaps/position
, which will contain a single line
of the form (<roll>,<pitch>)\n
where roll
and pitch
are numbers.
If the only acceleration of your ThinkPad is due to gravity you can
work out the roll and pitch angles from these. On my x220,
holding the keyboard dead level (i.e. in a plane perpendicular to the
direction of gravity) gives readings of (505, 505), and the individual
readings run from about 360 to 650 as the angle varies from -90 to 90
degrees.
A fun thing to do with the accelerometer is to use it to control your computer through gestures. I will show you how to write a very short Python script so that if you tilt the ThinkPad left or right, you move to the previous or next workspace (in i3wm, but it will adapt to your preferred window manager). There are some (old) more complex scripts linked here.
First we will write a generator to return the content of the accelerometer data file:
def follow(file):
while True:
file.seek(0)
line = file.readline()
yield line
This lets us get the accelerometer readings in a for loop.
Now all we need to do is look for a roll to the left or the right and
send the appropriate key event. The easiest way I know to do this
is using xdotool
. I have i3wm set up so that ctrl+alt+Right and
ctrl+alt+Left move to the next and previous workspaces, and to simulate
pressing these keys we just run xdotool key ctrl+alt+Right
or xdotool key ctrl+alt+Left
.
We’ll also need to debounce by pausing briefly after a
left or right tilt is detected so that the same tilt doesn’t send lots
of key events, which we can do using the sleep method in the standard
library’s time module.
import os # for sending system commands
import time # for waiting a fixed amount of time
thresh = 15 # experiment to get a good tilt threshold
with open('/sys/devices/platform/hdaps/position') as f:
lines = follow(f)
for line in lines: # "(<roll>,<pitch>)\n"
roll, pitch = map(int, line[1:-2].split(","))
if roll > 505 + thresh: # roll right
os.popen("xdotool key ctrl+alt+Right")
time.sleep(0.5) # avoid generating multiple events from the same tilt
elif roll < 505 - thresh: # roll left
os.popen("xdotool key ctrl+alt+Left")
time.sleep(0.5)
time.sleep(0.2) # experiment for a good value
That’s it!