## Tuesday, November 22, 2011

### Gyroscope & Accelerometer - iOS SDK

Gyroscope : A gyroscope measures the rate at which a device rotates around each of the three spatial axes
Accelerometer : measures the acceleration of the device along each of the three spatial axes.

Access Accelerometer using UIAccelerometer

Configuring the accelerometer
#define kAccelerometerFrequency        50.0 //Hz
-(void)configureAccelerometer
{
UIAccelerometer*  theAccelerometer = [UIAccelerometer sharedAccelerometer];
theAccelerometer.updateInterval = 1 / kAccelerometerFrequency;
theAccelerometer.delegate = self;
// Delegate events begin immediately.
}

Receiving an accelerometer event
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
UIAccelerationValue x, y, z;
x = acceleration.x;
y = acceleration.y;
z = acceleration.z;
// Do something with the values.
}

It shows a simplified version of a low-pass filter.

This example uses a low-value filtering factor to generate a value that uses 10 percent of the
unfiltered acceleration data and 90 percent of the previously filtered value

Isolating the effects of gravity from accelerometer data
#define kFilteringFactor 0.1
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
// Use a basic low-pass filter to keep only the gravity component of each axis.
accelX = (acceleration.x * kFilteringFactor) + (accelX * (1.0 - kFilteringFactor));
accelY = (acceleration.y * kFilteringFactor) + (accelY * (1.0 - kFilteringFactor));
accelZ = (acceleration.z * kFilteringFactor) + (accelZ * (1.0 - kFilteringFactor));
// Use the acceleration data.
}

shows a simplified high-pass filter computation with constant effect of gravity.
Getting the instantaneous portion of movement from accelerometer data

#define kFilteringFactor 0.1
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
// Subtract the low-pass value from the current value to get a simplified high-pass filter
accelX = acceleration.x - ( (acceleration.x * kFilteringFactor) + (accelX * (1.0 - kFilteringFactor)) );
accelY = acceleration.y - ( (acceleration.y * kFilteringFactor) + (accelY * (1.0 - kFilteringFactor)) );
accelZ = acceleration.z - ( (acceleration.z * kFilteringFactor) + (accelZ * (1.0 - kFilteringFactor)) );
// Use the acceleration data.
}
Handling Accelerometer and Gycometer using COREMOTION

Core Motion is a system framework that obtains motion data from sensors on a device and presents that data to applications for processing.

Core Motion defines a manager class, CMMotionManager, and three classes whose instances encapsulate measurements of motion data of various types:
A CMAccelerometerData object encapsulates a data structure that records a measurement of device acceleration along the three spatial axes. This data derives from the accelerometer.
A CMGyroData object encapsulates a data structure that records a biased estimate of a device’s rate of rotation along the three spatial axes.
A CMDeviceMotion
object encapsulates processed device-motion data that derives from both the accelerometer and the gyroscope.

************Handling Accelerometer using CoreMotion************

To start receiving and handling accelerometer data, create an instance of the CMMotionManager class and call one of the following two methods on it:
startAccelerometerUpdates
After this method is called, Core Motion continuously updates the accelerometerData property of CMMotionManager with the latest measurement of accelerometer activity.
startAccelerometerUpdatesToQueue:withHandler:
Before calling this method, the application assigns an update interval to the accelerometerUpdateInterval property. It also creates an instance of NSOperationQueue and implements a block of the CMAccelerometerHandler type that handles the accelerometer updates.

Configuring the motion manager and starting updates
- (void)startAnimation {
if (!animating) {
// code that configures and schedules CADisplayLink or timer here ...
}
motionManager = [[CMMotionManager alloc] init]// motionManager is an instance variable
motionManager.accelerometerUpdateInterval = 0.01// 100Hz
memset(filteredAcceleration, 0sizeof(filteredAcceleration));
[motionManager startAccelerometerUpdates];
}

- (void)stopAnimation {
if (animating) {
// code that invalidates CADisplayLink or timer here...
}
[motionManager stopAccelerometerUpdates];
}

Below code shows how the application, in this same method, gets the latest accelerometer data and runs it through a low-pass filter. It then updates the drawing model with the filtered acceleration values and renders its view.
Listing 4-8  Sampling and filtering accelerometer data

- (void)drawView {
// alpha is the filter value (instance variable)
CMAccelerometerData *newestAccel = motionManager.accelerometerData;
filteredAcceleration = filteredAcceleration * (1.0-alpha) + newestAccel.acceleration.x * alpha;
filteredAcceleration = filteredAcceleration * (1.0-alpha) + newestAccel.acceleration.y * alpha;
filteredAcceleration = filteredAcceleration * (1.0-alpha) + newestAccel.acceleration.z * alpha;
[self updateModelsWithAcceleration:filteredAcceleration];
[renderer render];
}
Note: You can apply a low-pass or high-pass filter to acceleration values and thereby isolate the gravity and user-acceleration components:
To apply a low-pass filter, thereby isolating the gravity component,
To apply a high-pass filter, thereby isolating the user-acceleration component

*******Handling Gyroscope Using CORE MOTION*******

To start receiving and handling rotation-rate data, create an instance of the CMMotionManager class and call one of the following two methods on it:

startGyroUpdates
After this method is called, Core Motion continuously updates the gyroData property of CMMotionManager with the latest measurement of gyroscope activity.

startGyroUpdatesToQueue:withHandler:
Before calling this method, the application assigns an update interval to the gyroUpdateInterval property.

It also creates an instance of NSOperationQueue and implements a block of the CMGyroHandler type that handles the gyroscope updates.

Creating the CMMotionManager object and setting up for gyroscope updates
- (void)viewDidLoad {
[super viewDidLoad];
motionManager = [[CMMotionManager alloc] init];
motionManager.gyroUpdateInterval = 1.0/60.0;
if (motionManager.gyroAvailable) {
opQ = [[NSOperationQueue currentQueue] retain];
gyroHandler = ^ (CMGyroData *gyroData, NSError *error) {
CMRotationRate rotate = gyroData.rotationRate;
// handle rotation-rate data here......
};
} else {
NSLog(@"No gyroscope on device.");
toggleButton.enabled = NO;
[motionManager release];
}
}

Starting and stopping gyroscope updates
- (IBAction)toggleGyroUpdates:(id)sender {
if ([[(UIButton *)sender currentTitle] isEqualToString:@"Start"]) {
[motionManager startGyroUpdatesToQueue:opQ withHandler:gyroHandler];
} else {
[motionManager stopGyroUpdates];
}

}