Windows Phone

# Sensors and Services : Accelerometer

3/9/2011 5:56:23 PM
Windows Phones contain an accelerometer—a small hardware device that essentially measures force, which elementary physics tells us is proportional to acceleration. When the phone is held still, the accelerometer responds to the force of gravity, so the accelerometer can tell your application the direction of the Earth relative to the phone.

A simulation of a bubble level is an archetypal application that makes use of an accelerometer, but the accelerometer can also provide a basis for interactive animations. For example, you might pilot a messenger bike through the streets of Manhattan by tilting the phone left or right to indicate steering.

The accelerometer also responds to sudden movements such as shakes or jerks, useful for simulations of dice or some other type of randomizing activity. Coming up with creative uses of the accelerometer is one of the many challenges of phone development.

It is convenient to represent the accelerometer output as a vector in three-dimensional space. Vectors are commonly written in boldface, so the acceleration vector can be symbolized as (x, y, z). XNA defines a three-dimensional vector type; Silverlight does not.

While a three-dimensional point (x, y, z) indicates a particular location in space, the vector (x, y, z) encapsulates instead a direction and a magnitude. Obviously the point and the vector are related: The direction of the vector (x, y, z) is the direction from the point (0, 0, 0) to the point (x, y, z). But the vector (x, y, z) is definitely not the line from (0, 0, 0) to (x, y, z). It’s only the direction of that line.

The magnitude of the vector (x, y, z) is calculable from the three-dimensional form of the Pythagorean Theorem:

For working with the accelerometer, you can imagine the phone as defining a three-dimensional coordinate system. No matter how the phone is oriented, the positive Y axis points from the bottom of the phone (with the buttons) to the top, the positive X axis points from left to right,

This is a traditional three-dimensional coordinate system, the same coordinate system used in XNA 3D programming. It’s termed a right-hand coordinate system: Point the index finger of your right hand to increasing X, the middle finger to increase Y, and your thumb points to increasing Z. Or, curve the fingers of your right hand from the positive X axis to the positive Y axis. Your thumb again points to increasing Z.

This coordinate system remains fixed relative to the phone regardless how you hold the phone, and regardless of the orientation of any programs running on the phone. In fact, as you might expect, the accelerometer is the basis for performing orientation changes of Windows Phone 7 applications.

When the phone is still, the accelerometer vector points towards the Earth. The magnitude is 1, meaning 1 g, which is the force of gravity on the earth’s surface. When holding your phone in the upright position, the acceleration vector is (0, –1, 0), that is, straight down.

Turn the phone 90° counter-clockwise (called landscape left) and the acceleration vector becomes (–1, 0, 0), upside down it’s (0, 1, 0), and another 90° counter-clockwise turn brings you to the landscape right orientation and an accelerometer value of (1, 0, 0). Sit the phone down on the desk with the display facing up, and the acceleration vector is (0, 0, –1). (That final value is what the Windows Phone 7 emulator always reports.)

Of course, the acceleration vector will rarely be those exact values, and even the magnitude won’t be exact. For a still phone, the magnitude may vary by a few percentage points with different orientations. When you visit the Moon with your Windows Phone 7, you can expect acceleration vector magnitudes in the region of 0.17 but limited cell phone reception.

I’ve been describing values of the acceleration vector when the device is still. The acceleration vector can point in other directions (and the magnitude can become larger or smaller) when the phone is accelerating, that is, gaining or losing velocity. For example, if you jerk the phone to the left, the acceleration vector points to the right but only when the device is gaining velocity. As the velocity stabilizes, the acceleration vector again registers only gravity. When you decelerate this jerk to the left, the acceleration vector goes to the left briefly as the device comes to a stop.

If the phone is in free fall, the magnitude of the accelerometer vector should theoretically go down to zero.

To use the accelerometer, you’ll need a reference to the Microsoft.Devices.Sensors library, and a using directive for the Microsoft.Devices.Sensors namespace. In WMAppManifest.xml, you need

`<Capability Name="ID_CAP_SENSORS" />`

This is set by default.

In your program you create an instance of the Accelerometer class, set an event handler for the ReadingChanging event, and call Start.

And then it gets a little tricky. Let’s take a look at a project named SilverlightAccelerometer. that simply displays the current reading in its content grid. A centered TextBlock is defined in the XAML file:

##### Example 1. Silverlight Project: SilverlightAccelerometer File: MainPage.xaml (excerpt)
 ` `

This is a program that will display the accelerometer vector throughout its lifetime, so it creates the Accelerometer class in its constructor and calls Start:

##### Example 2. Silverlight Project: SilverlightAccelerometer File: MainPage.xaml.cs (excerpt)
 `public MainPage(){ InitializeComponent(); Accelerometer acc = new Accelerometer(); acc.ReadingChanged += OnAccelerometerReadingChanged; try { acc.Start(); } catch (Exception exc) { txtblk.Text = exc.Message; }}`

The documentation warns that calling Start might raise an exception, so the program protects itself against that eventuality. The Accelerometer also supports Stop and Dispose methods, but this program doesn’t make use of them. A State property is also available if you need to know if the accelerometer is available and what it’s currently doing.

A ReadingChanged event is accompanied by the AccelerometerReadingEventArgs event arguments. The object has properties named X, Y, and Z of type double and TimeStamp of type DateTimeOffset. In the SilverlightAccelerometer program, the job of the event handler is to format this information into a string and set it to the Text property of the TextBlock.

The catch here is that the event handler (in this case OnAccelerometerReadingChanged) is called on a different thread of execution, and this means it must be handled in a special way.

A little background: All the user-interface elements and objects in a Silverlight application are created and accessed in a main thread of execution often called the user interface thread or the UI thread. These user-interface objects are not thread safe; they are not built to be accessed simultaneously from multiple threads. For this reason, Silverlight will not allow you to access a user-interface object from a non-UI thread.

This means that the OnAccelerometerReadingChanged method cannot directly access the TextBlock element to set a new value to its Text property.

Fortunately, there’s a solution involving a class named Dispatcher defined in the System.Windows.Threading namespace. Through the Dispatcher class, you can post jobs from a non-UI thread on a queue where they are later executed by the UI thread. This process sounds complex, but from the programmer’s perspective it’s fairly easy because these jobs take the form of simple method calls.

An instance of this Dispatcher is readily available. The DependencyObject class defines a property named Dispatcher of type Dispatcher, and many Silverlight classes derive from DependencyObject. Instances of all of these classes can be accessed from non-UI threads because they all have Dispatcher properties. You can use any Dispatcher object from any DependencyObject derivative created in your UI thread. They are all the same.

The Dispatcher class defines a method named CheckAccess that returns true if you can access a particular user interface object from the current thread. (The CheckAccess method is also duplicated by DependencyObject itself.) If an object can’t be accessed from the current thread, then Dispatcher provides two versions of a method named Invoke that you use to post the job to the UI thread.

The SilverlightAccelerometer project implements a syntactically elaborate version of the code, but then I’ll show you how to chop it down in size.

The verbose version requires a delegate and a method defined in accordance with that delegate. The delegate (and method) should have no return value, but as many arguments as you need to do the job, in this case the job of setting a string to the Text property of a TextBlock:

##### Example 3. Project: SilverlightAccelerometer File: MainPage.xaml.cs (excerpt)
 `delegate void SetTextBlockTextDelegate(TextBlock txtblk, string text);void SetTextBlockText(TextBlock txtblk, string text){ txtblk.Text = text;}`

The OnAccelerometerReadingChanged is responsible for calling SetTextBlockText. It first makes use of CheckAccess to see if it can just call the SetTextBlockText method directly. If not, then the handler calls the BeginInvoke method. The first argument is an instantiation of the delegate with the SetTextBlockText method; this is followed by all the arguments that SetTextBlockText requires:

##### Example 4. Project: SilverlightAccelerometer File: MainPage.xaml.cs (excerpt)
 `void OnAccelerometerReadingChanged(object sender, AccelerometerReadingEventArgs args){ string str = String.Format("X = {0:F2}\n" + "Y = {1:F2}\n" + "Z = {2:F2}\n\n" + "Magnitude = {3:F2}\n\n" + "{4}", args.X, args.Y, args.Z, Math.Sqrt(args.X * args.X + args.Y * args.Y + args.Z * args.Z), args.Timestamp); if (txtblk.CheckAccess()) { SetTextBlockText(txtblk, str); } else { txtblk.Dispatcher.BeginInvoke(new SetTextBlockTextDelegate(SetTextBlockText), txtblk, str); }} `

This is not too bad, but the need for the code to jump across threads has necessitated an additional method and a delegate. Is there a way to do the whole job right in the event handler?

Yes! The BeginInvoke method has an overload that accepts an Action delegate, which defines a method that has no return value and no arguments. You can create an anonymous method right in the BeginInvoke call. The complete code following the creation of the string object looks like this:

`if (txtblk.CheckAccess()){    txtblk.Text = str;}else{    txtblk.Dispatcher.BeginInvoke(delegate()    {        txtblk.Text = str;    });}`

The anonymous method begins with the keyword delegate and concludes with the curly brace following the method body. The empty parentheses following the delegate keyword are not required.

The anonymous method can also be defined using a lambda expression:

`if (txtblk.CheckAccess()){    txtblk.Text = str;}else{    txtblk.Dispatcher.BeginInvoke(() =>    {        txtblk.Text = str;    });}`

The duplicated code that sets the Text property of TextBlock to str looks a little ugly here (and would be undesirable if it involved more than just one statement), but you don’t really need to call CheckAccess. You can just call BeginInvoke and nothing bad will happen even if you are calling it from the UI thead.

The Windows Phone 7 emulator doesn’t contain any actual accelerometer, so it always reports a value of (0, 0, –1), which indicates the phone is lying on a flat surface. The program only makes sense when running on an actual phone:

The values here indicate the phone is roughly upright but tilted back a bit, which is a very natural orientation in actual use.