Welcome to Jeff Fansler's Blog

I've spent many years in the computer industry. I've worked in labs installing software, building computers, setting up networks, and teaching people how to use a mouse. I've worked as a developer building business applications and products. I've worked as a manager building teams and processes. In the end I've ventured on building a company which allows me to do a little of everything. This blog is where I talk about what I've learned during my journey

 

Introduction to the Windows Phone 7 Accelerometer

posted on Monday, July 26, 2010 7:33 PM | Filed Under [ WP7 ]

Before I begin this post I want to be clear, although I have made some tweaks, using the Wiimote as accelerometer input was done by Bill Reiss. Thank you Bill for giving me something fun to play with.

Let's start at the beginning. What is an accelerometer? You can read about it in more detail here: http://en.wikipedia.org/wiki/Accelerometer, but effectively it's a little doohickey that allows a device (in our case the Windows Phone) to detect the magnitude and direction of acceleration.

Windows Phone 7 (WP7) will have an accelerometer in it. The framework namespace that covers the accelerometer is Microsoft.Devices.Sensors. The class we care about here is the Accelerometer class. This class has 2 important methods Start and Stop. As you can likely guess, start tells the system you want to start reading values from the accelerometer and stop means you are done. The Accelerometer also has an important event called ReadingChanged. This event fires once you have started the accelerometer and one of the accelerometer values has changed. The event uses the AccelerometerReadingEventArgs class to return back the values that have changed. There are 3 important values, X, Y, and Z. Each represents the force of acceleration on that axis.

When I first started playing with the accelerometer I didn't quite understand what the values for X, Y, and Z meant. When a device is sitting face up on a desk, X and Y will both be zero (or close to it). Z will be 1. if you took a nail and hammered your device to the table, that nail would represent the Z axis. It's value is 1 because gravity is pulling it down in that direction. If you turn the device over (face down) Z would now be equal to -1. The same pattern follows for X and Y. If you put the device on it's right side X will be 1. Put it on it's left side and X will be -1. If you stand the device up Y will be -1. If you turn the device upside down, Y will be 1. Keep in mind that these values can be greater than zero for when greater than normal forces are put on them. Shaking for example.

As you can probably figure out, based on these values you can tell when a user tilts to the left, right, top, bottom, up or down.

The Accelerometer and the WP7 Emulator

Unfortunately there's no easy way to test accelerometer code using the WP7 emulator. It currently doesn't pick up an accelerometer even if you have one on your PC. There are a few solutions for testing floating around. The one I like the most is using a Wiimote's accelerometer. If your computer has an accelerometer in it and you can access it from .NET I'm sure you could use code very similar to the Wiimote version. As I mentioned at the beginning of this post, I didn't think of this. This was Bill Reis's idea. I just used it as a way to understand how to use the Accelerometer.

Code

Using the accelerometer is pretty easy. For my example, I'm going to use a menu button to start and stop the accelerometer. The start stop code looks like this:

private void AppBarStartStopClick(object sender, EventArgs e)
{
    // If the accelerometer is null, initialize and start
    if (_accelerometer == null)
    {
        // Instantiate the accelerometer sensor object
        _accelerometer = new WiimoteAccelerometer();

        // Add an event handler for the ReadingChanged event.
        _accelerometer.ReadingChanged += AccelerometerReadingChanged;
        _accelerometer.Start();                                
    }
    else
    {
        // if the accelerometer is not null, call Stop
        _accelerometer.ReadingChanged -= AccelerometerReadingChanged;
        _accelerometer.Stop();
        _accelerometer = null;
        txtCoordinates.Text = "X=?, Y=?, Z=?";                    
    }
}

This code simply wires up to the ReadingChanged event and starts the accelerometer if it hasn't been started yet. All the magic happens in that event. When the event fires I want to move around an image on a canvas based on the accelerometer values. The first gotcha that I found is that this event does not return on the UI thread. That means you have to jump back to the UI thread with some BeginInvoke magic. That code looks like this:

private void AccelerometerReadingChanged(object sender, AccelerometerEventArgs e)
{
    //acceleromter returns on a different thread so let's go back to the UI thread
    Deployment.Current.Dispatcher.BeginInvoke(() => MyReadingChanged(e));
}

All that's left is setting the actual Top and Left values of the image. In this code I am multiplying the accelerometer values by 5. I do this because I want the image to move a little faster so it's easier to see it working.

private void MyReadingChanged(AccelerometerEventArgs e)
{
    var left = Canvas.GetLeft(imageLogo) + e.X * 5;
    var top = Canvas.GetTop(imageLogo) - e.Y * 5;

    //constrain the image to the canvas
    if (left < 0)
    {
        left = 0;
    }
    else if (left > canvasMain.Width - imageLogo.Width)
    {
        left = canvasMain.Width - imageLogo.Width;
    }                

    if (top < 0)
    {
        top = 0;
    }
    else if (top > canvasMain.Height - imageLogo.Height)
    {
        top = canvasMain.Height - imageLogo.Height;
    }

    Canvas.SetLeft(imageLogo, left);
    Canvas.SetTop(imageLogo, top);

    txtCoordinates.Text = string.Format("X={0}, Y={1}, Z={2}",
            e.X.ToString("0.00"), 
            e.Y.ToString("0.00"),
            e.Z.ToString("0.00"));            
}

That's it for the code. Not very complex. If I had a device I'd just deploy that to the device and stare for hours as the logo moved around the screen. Getting it running with the Wiimote is a little different, but not much more work.

Getting it Running with the Wiimote

The Wiimote can't talk directly to the WP7 emulator. To get around that, we are going to use the Wiimote Accelerometer server. This is a fairly simple piece of code that exposes the accelerometer values as a service. Instead of using the normal WP7 Accelerometer class we'll use the WiimoteAccelerometer class. This class will use the WiimoteAccelerometerProxy class to request values from the service every 100ms.

To get this running, we have to first connect the Wiimote via Bluetooth. You can read about how to do that here. Once connected run the WiimoteAccelerometerServer.exe. If everything is working correctly you should see the X, Y, and Z values scroll down your screen. One note here, run this in a console as an admin.

Once that's running you should be all set. Fire up the emulator and run your app. Click the start icon and watch the icon float around the screen as you move the Wiimote.

That's it. You can download the source code for this sample here.


Comments

No comments posted yet.
Post Comment
Title *
Name *
Email
Url
Comment *  
Please add 6 and 8 and type the answer here: