A couple of weeks ago I went out and bought myself a HTC HD2. Yes, the 4.3inch monster running windows mobile, probably the best windows mobile device ever; this one running Windows Mobile 6.5. Did you just wince in pain on hearing windows mobile? Well, if it makes you feel any better let me assure you that I’ll buy a Windows Phone 7 device as soon as one is available in market. Ok?
I haven’t tweaked around with it too much yet but this week I had some time to look into the accelerometer.
The Accelerometer
The accelerometer sensor measures the gravitational force acting on it. When the phone is at rest the force acting on it is equal to 1g, move the phone around and the force changes (and that is how you detect shake and other gestures). The accelerometer reports the force as vectors along 3-axes, (x, y, z); the magnitude of the force can be calculated using the formula sqrt(x*x + y*y + z*z). If you hold the phone up facing you, the x axis is the horizontal, y axis is the vertical and z axis is along the direction from the phone pointing towards you. This co-ordinate system moves along with the phone. Now the direction along which the values of x, y and z increase and the origin of this co-ordinate system might depend on the implementation on that particular device, so here we will see how it’s implemented on HD2. With respect to HD2 the top-left corner of the phone can be considered as the origin of the co-ordinate system (see image below). Again, with the phone facing you, x axis is horizontal with values increasing towards the right; y axis is the vertical with values increasing as you go from top to bottom; z axis pointing towards you with values increasing as you move from the origin towards you.
Lets do a little exercise. When the phone is lying flat, face-up on a table, what is the acceleration vector? It is (0, 0, –1). These are of course ideal values, in practice there will be slight variations because of inaccuracies in the sensor. Why is the vector (0, 0, –1)? Because when the phone is lying flat, the x and y axes are along the horizontal and there is no gravitational force acting along those axes. The z axis which is pointing upwards now, experiences a gravitational pull of 1g in the opposite direction, that explains the negative sign. Now if you pick the phone up and it is facing you the acceleration vector is (0, 1, 0). When the phone is facing you, the x and the z axes form a horizontal plane and therefore the forces are zero. y axis is pointing downwards, in the same direction as the gravitational force and so the value becomes +1. Now if you turn the phone 90 degrees in counter-clockwise direction the force vector becomes (-1, 0, 0), you should be able to figure this one out. HD2 reports the vector values after scaling them by a factor of 1000. So instead of reporting 0.984, it reports 984. Here are the values that my HD2 reports:
lying flat on a table: (X:-67, Y:84, Z:-973)
facing me: (X:74, Y:974, Z:26)
Accelerometer on HD2
From João Paulo Figueira’s post on the HTC G Sensor I came to know that someone called Scott Seligman reverse engineered the G Sensor driver and figured out how to use it. It also led to a project on Codeplex called “Windows Mobile Unified Sensor API” which provided you with a managed wrapper around various sensors in several devices. I wonder how much effort it takes to reverse engineer and figure out how to use an exported function from a dll, but I am sure it involves biting through a lot of assembly code. Anyways, the accelerometer driver in HD2 is implemented in a dll called HTCSensorSDK.dll.
If you run the dumpbin tool on this dll,
c:\iamdir> dumpbin.exe /EXPORTS HTCSensorSDK.dll
you can see that it implements a few other sensors as well, like the compass and the light sensor (or proximity sensor). The functions of interest to us are HTCSensorOpen(), HTCSensorGetDataOutput() and HTCSensorClose(), which control the accelerometer and are pretty self-explanatory. Open() initializes the accelerometer sensor, GetDataOutput() returns the current (x, y, z) acceleration vector and Close() de-initializes the sensor. These functions are accessed using a combination of LoadLibrary() and GetProcAddress() apis if you want to access it through native code, or you could use the interop services and p/invokes to access it from managed code.
I modified an existing native application to access the accelerometer and there is a lot of unnecessary code in it, if you want the native app leave a comment on this post, I’ll clean it up and post it here. Meanwhile I will be posting the managed application source code here. I have tested it on HD2 and I am guessing it should work well on devices like Touch Pro 2, HTC Diamond as well.
Source Code: AccelerometerDemo-HD2.zip
Here’s a brief video of the sample managed application which uses the data returned by the accelerometer to move a marble on the screen. I shot two videos, one using my pathetic camera (VGA resolution) and the other using a desktop screen capture tool which records at 15fps, so you’ll have to live with these until I buy a better camera.
and,