Basics of Accelerometer, Gyroscope, and Magnetometer Sensors for iOS Apps - dummies

Basics of Accelerometer, Gyroscope, and Magnetometer Sensors for iOS Apps

By Rajiv Ramnath

An iOS device has three with well-documented interfaces for sensors — the accelerometer, the gyroscope, and the magnetometer. As with the orientation sensor, the process for these sensors begins by starting and initializing a listener that listens for sensor events. Here is the code from the ViewDidLoad method of the Sensors view controller:

- (void)viewDidLoad{
 …
 accelerationTextView.enabled = NO;
 gyroscopeTextView.enabled = NO;
 magnetometerTextView.enabled = NO;
 …
 // Set up the motion manager
 self->motionManager = [[CMMotionManager alloc] init];
 self->motionManager.accelerometerUpdateInterval = 1;
 self->motionManager.gyroUpdateInterval = 1;
 self->motionManager. magnetometerUpdateInterval = 1;
 …
}

The object that gives you access to sensor events is an instance of the CMMotionManager class. You need to create one, and only one, instance of this class (that is, you must treat it like a Singleton, even though it isn’t). Then you set properties like the update interval for each of the sensors.

Next, you start the monitoring using the methods startAccelerometerUpdatesToQueue, startGyroUpdatesToQueue, and startMagnetometerUpdatesToQueue, as shown in the method startMonitoringSensors (which is called when you press the Start Monitoring button):

- (IBAction) startMonitoringSensors:(id)sender{
 [self->motionManager
   startAccelerometerUpdatesToQueue:
    [NSOperationQueue currentQueue]
    withHandler:^(CMAccelerometerData *accelerometerData,
    NSError *error) {
     [self
      handleAccelerationUpdates:accelerometerData.acceleration];
    }
 ];
 [self->motionManager
   startGyroUpdatesToQueue:
    [NSOperationQueue currentQueue]
    withHandler:^(CMGyroData *gyroscopeData, NSError *error) {
     [self handleGyroUpdates:gyroscopeData.rotationRate];
    }
 ];
 [self->motionManager
   startMagnetometerUpdatesToQueue:
    [NSOperationQueue currentQueue]
     withHandler:^(CMMagnetometerData *magnetometerData,
     NSError *error) {
     [self handleMagnetometerUpdates:
        magnetometerData.magneticField];
    }
 ];
}

Each of these methods is called with an inline handler block using the withHandler construct. These inline handler blocks call the handleAccelerationUpdates, handleGyroUpdates, and handleMagnetometerUpdates. These methods are as follows:

- (void) handleAccelerationUpdates: (CMAcceleration) accelerationData {
 NSLog(@"Acceleration.x >%f<n", accelerationData.x);
 NSLog(@"Acceleration.y >%f<n", accelerationData.y);
 NSLog(@"Acceleration.z >%f<n", accelerationData.z);
 if (((accelerationData.x > 1.0)||(accelerationData.x < -1.0))||
  ((accelerationData.y > 1.0)||(accelerationData.y < -1.0))||
  ((accelerationData.z > 1.0)||(accelerationData.z < -1.0))){
  [accelerationTextView setText:@"I’M GOING FAST"];
 }else{
  [accelerationTextView setText:@"TOO SLOW"];
 }
}
- (void) handleGyroUpdates: (CMRotationRate) gyroRotationRate {
 NSLog(@"Rotation x >%f<n", gyroRotationRate.x);
 NSLog(@"Rotation y >%f<n", gyroRotationRate.y);
 NSLog(@"Rotation z >%f<n", gyroRotationRate.z);
 if (((gyroRotationRate.x > 0.5)||(gyroRotationRate.x < -0.5))||
  ((gyroRotationRate.y > 0.5)||(gyroRotationRate.y < -0.5))||
  ((gyroRotationRate.z > 0.5)||(gyroRotationRate.z < -0.5))){
  [gyroscopeTextView setText:@"WHEEE!"];
 }else{
  [gyroscopeTextView setText:@"SPIN ME FASTER!"];
 }
}
- (void) handleMagnetometerUpdates: (CMMagneticField) magneticField {
 NSLog(@"Magnetic field x >%f<n", magneticField.x);
 NSLog(@"Magnetic field y >%f<n", magneticField.y);
 NSLog(@"Magnetic field z >%f<n", magneticField.z);
 static float savedX=0.0, savedY=0.0, savedZ=0.0;
 float change = pow((magneticField.x - savedX), 2.0) +
     pow((magneticField.y - savedY), 2.0) +
     pow((magneticField.z - savedZ), 2.0);
 NSLog(@"Magnetic field change >%f<n", change);
 if (change > 3000.0){
  savedX = magneticField.x;
  savedY = magneticField.y;
  savedZ = magneticField.z;
  [magnetometerTextView setText:@"I SENSE SOMETHING!"];
 }else{
  [magnetometerTextView setText:@"ALL CLEAR!"];
 }
}

These methods log the raw data. Raw sensor readings displayed by use of NSLog are displayed below.

image0.jpg

The preceding sensor methods also interpret the raw sensor values to generate the view shown in below.

image1.jpg

The sensors use heuristics to provide meaningful insights:

  • The accelerometer measures acceleration in g-forces, where 1 g-force is equivalent to the pull of the Earth’s gravity.

    If the accelerometer senses movement greater than the Earth’s gravitational pull in any direction, it excitedly displays the message, I’M GOING FAST! Otherwise, it displays TOO SLOW.

  • The gyroscope measures rotation of the device’s three axes in radians per second (1 radian per second means about a sixth of a rotation every second). Therefore, if it senses most any rotation, it prints WHEE!

  • In the magnetometer code, you would use a distance heuristic to sense a large change in the magnetic field.

    If such a change occurs, the app shows I SENSE SOMETHING!

    If nothing changes for one interval, it goes back to thinking the coast is clear.