Article

Getting Raw Gyroscope Events

Retrieve data from the onboard gyroscopes.

Overview

A gyroscope measures the rate at which a device rotates around a spatial axis. Many iOS devices have a three-axis gyroscope, which delivers rotation values in each of the three axes shown in Figure 1. Rotation values are measured in radians per second around the given axis. Rotation values may be positive or negative depending on the direction of rotation.

Figure 1

Gyroscopes measure the rotation rate around the x, y, and z axes

Gyroscopes measure the rotation rate around the x, y, and z axes

You access the raw gyroscope data using the classes of the Core Motion framework. Specifically, the CMMotionManager class provides the interfaces for enabling the gyroscope hardware. Before enabling that hardware, always check the value of the isGyroAvailable property to verify that the gyroscopes are available for you to use. When enabling the hardware, choose the interfaces that are best suited for your app. You can pull the gyroscope data only when you need it, or you can ask the framework to push updates to your app at regular intervals. Each technique involves different configuration steps and has a different use case.

The raw rotation rate data delivered by the gyroscope interfaces may be biased by other factors such as device acceleration. If your app requires unbiased rotation values, use the device-motion interfaces instead. The device-motion interfaces use special algorithms to remove any bias and deliver more precise rotation values. For more information, see Getting Processed Device-Motion Data.

Getting Gyroscope Data Only When You Need It

For apps that process gyroscope data on their own schedule, such as games, use the startGyroUpdates() method of CMMotionManager to start the delivery of rotation data. When you call this method, the system enables the gyroscope hardware and begins updating the gyroData property of your CMMotionManager object. However, the system does not notify you when it updates that property. You must explicitly check the value of the property when you need the rotation data.

Before you start the delivery of gyroscope updates, specify an update frequency by assigning a value to the gyroUpdateInterval property. The maximum frequency at which you can request updates is hardware-dependent but is usually at least 100 Hz. If you request a frequency that is greater than what the hardware supports, Core Motion uses the supported maximum instead.

Listing 1 shows a method that configures gyroscope updates to occur 60 times per second. The method then configures a timer to fetch those updates at the same frequency and do something with the data. You could configure the timer to fire at a lower frequency, but doing so would waste power by causing the hardware to generate more updates than were actually used.

Listing 1

Fetching gyroscope data on demand

func startGyros() {
   if motion.isGyroAvailable {
      self.motion.gyroUpdateInterval = 1.0 / 60.0
      self.motion.startGyroUpdates()

      // Configure a timer to fetch the accelerometer data.
      self.timer = Timer(fire: Date(), interval: (1.0/60.0), 
             repeats: true, block: { (timer) in
         // Get the gyro data.
         if let data = self.motion.gyroData {
            let x = data.rotationRate.x
            let y = data.rotationRate.y
            let z = data.rotationRate.z

            // Use the gyroscope data in your app. 
         }
      })

      // Add the timer to the current run loop.
      RunLoop.current.add(self.timer!, forMode: .defaultRunLoopMode)
   }
}

func stopGyros() {
   if self.timer != nil {
      self.timer?.invalidate()
      self.timer = nil

      self.motion.stopGyroUpdates()
   }
}

Processing a Steady Stream of Gyroscope Updates

When you want to capture all of the gyroscope data, perhaps so you can analyze it for movement patterns, use the startGyroUpdates(to:withHandler:) method of CMMotionManager. This method pushes each new set of rotation values to your app by executing your handler block on the specified queue. The queueing of these blocks ensures that your app receives all of the gyroscope data, even if your app becomes busy and is unable to process updates for a brief period of time.

Before you start the delivery of gyroscope updates, specify an update frequency by assigning a value to the gyroUpdateInterval property. The maximum frequency at which you can request updates is hardware-dependent but is usually at least 100 Hz. If you request a frequency that is greater than what the hardware supports, Core Motion uses the supported maximum instead.

Listing 2 shows a method from the MotionGraphs sample code project, which you can examine for more context. The app displays a real-time graph of rotation data from the onboard gyroscopes. The user configures the update frequency for the gyroscopes using a slider, the changing of which results in a call to the startUpdatesWithSliderValue: method shown in the example. This method restarts the gyroscope updates with the new frequency. Each time a new sample is received, the specified block is queued on the main thread. That block updates the app’s graph view and labels with the new rotation values.

Listing 2

Accessing raw gyroscope data

static const NSTimeInterval gyroMin = 0.01;
- (void)startUpdatesWithSliderValue:(int)sliderValue {
   // Determine the update interval
   NSTimeInterval delta = 0.005;
   NSTimeInterval updateInterval = gyroMin + delta * sliderValue;

   // Create a CMMotionManager
   CMMotionManager *mManager = [(APLAppDelegate *)
            [[UIApplication sharedApplication] delegate] sharedManager];
   APLGyroGraphViewController * __weak weakSelf = self;

   // Check whether the gyroscope is available
   if ([mManager isGyroAvailable] == YES) {
      // Assign the update interval to the motion manager
      [mManager setGyroUpdateInterval:updateInterval];
      [mManager startGyroUpdatesToQueue:[NSOperationQueue mainQueue] 
               withHandler:^(CMGyroData *gyroData, NSError *error) {
         [weakSelf.graphView addX:gyroData.rotationRate.x 
                  y:gyroData.rotationRate.y 
                  z:gyroData.rotationRate.z];
         [weakSelf setLabelValueX:gyroData.rotationRate.x 
                  y:gyroData.rotationRate.y 
                  z:gyroData.rotationRate.z];
      }];
   }
   self.updateIntervalLabel.text = [NSString stringWithFormat:@"%f", updateInterval];
}
- (void)stopUpdates{
   CMMotionManager *mManager = [(APLAppDelegate *)
            [[UIApplication sharedApplication] delegate] sharedManager];
   if ([mManager isGyroActive] == YES) {
      [mManager stopGyroUpdates];
   }
}

See Also

Gyroscopes

class CMGyroData

A single measurement of the device’s rotation rate.