The other day on the MSDN forums, someone asked about how to detect a shaking motion on Windows Phone 7. I've been playing with the accelerometer lately, so I took great joy in answering this along with providing a working implementation. The question was asking about shaking motion in a left-right direction. I made a class that detects left-right and up-down motion (totally ignoring the Z-axis all together for now). Though extending it to consider the Z-axis wouldn't be hard.
The code for detecting the motion has been abstracted in a class called ShakeDetector
. The algorithm used has a few variables/constants defined that can be modified to tune the behaviour of the class. The classes constructor accepts an [optional] parameter of how many times the phone should be shaken before the motion is considered acceptable. <codeminimumaccelerationmagnitude>
can be raised or lowered to control how hard the device needs to be shaken to be considered acceptable. And MinimumShakeTime
takes a time span that defines the maximum length of time over which a shake sequence must occur to be considered acceptable. Once the user moves the phone in a way that meets the requirements for the type of shake we wanted to detect a ShakeDetected
event is raised.
I've reduced the direction in which the device is moving to one of 8 directions (North
, East
, South
, West
, and the directions in between those). I could have kept the direction as an angle and just ensured that there was atleast a minimum difference between the angles but I thought using the directions on a map would make it easier for someone else to understand.
void _accelerometer_ReadingChanged(object sender, AccelerometerReadingEventArgs e)
{
if ((e.X*e.X + e.Y*e.Y) > MinimumAccelerationMagnitudeSquared)
{
double degrees = 180.0*Math.Atan2(e.Y, e.X)/Math.PI;
Direction direction = DegreesToDirection(degrees);
if ((direction & _shakeRecordList[_shakeRecordIndex].ShakeDirection)
!= Direction.None)
return;
ShakeRecord record = new ShakeRecord();
record.EventTime = DateTime.Now;
record.ShakeDirection = direction;
_shakeRecordIndex = (_shakeRecordIndex + 1)%_minimumShakes;
_shakeRecordList[_shakeRecordIndex] = record;
CheckForShakes();
}
}
void CheckForShakes()
{
int startIndex = (_shakeRecordIndex - 1);
if (startIndex < 0) startIndex = _minimumShakes - 1;
int endIndex = _shakeRecordIndex;
if ((_shakeRecordList[endIndex].EventTime.Subtract
(_shakeRecordList[startIndex].EventTime)) <= MinimumShakeTime)
{
OnShakeEvent();
}
}
The example code can be found in my SkyDrive account here. If you want to see the program in action, there is a video on YouTube.
CodeProject