16

I have the following setup:

enter image description here

An iPhone lies with the display to the ceiling on a table (alpha = 0 degrees). When the iPhone is moved upwards like shown in the image above the alpha angle increases.

How do I compute the value of the alpha angle without taking care of any other axes which could change. I am only interested in this one axis.

How do I get the correct alpha angle the iPhone has when lifting up from the table? How do I get notified when the value of alpha changes?

Michael
  • 32,527
  • 49
  • 210
  • 370

2 Answers2

19

You can use the CMMotionManager class to monitor device motion changes.

Objective C

// Ensure to keep a strong reference to the motion manager otherwise you won't get updates
self.motionManager = [[CMMotionManager alloc] init];
if (self.motionManager.deviceMotionAvailable) {
    
    self.motionManager.deviceMotionUpdateInterval = 0.1;
    
    // For use in the montionManager's handler to prevent strong reference cycle
    __weak typeof(self) weakSelf = self;

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [self.motionManager startDeviceMotionUpdatesToQueue:queue
                                            withHandler:^(CMDeviceMotion *motion, NSError *error) {
                                                
                                                // Get the attitude of the device
                                                CMAttitude *attitude = motion.attitude;
      
                                                // Get the pitch (in radians) and convert to degrees.                                          
                                                NSLog(@"%f", attitude.pitch * 180.0/M_PI);

                                                dispatch_async(dispatch_get_main_queue(), ^{
                                                    // Update some UI
                                                });
                                                
                                            }];
    
    NSLog(@"Device motion started");
}else {
    NSLog(@"Device motion unavailable");
}

Swift

// Ensure to keep a strong reference to the motion manager otherwise you won't get updates
self.motionManager = CMMotionManager()

if motionManager?.deviceMotionAvailable == true {
        
    motionManager?.deviceMotionUpdateInterval = 0.1
        
    let queue = OperationQueue()
    motionManager?.startDeviceMotionUpdatesToQueue(queue, withHandler: { [weak self] motion, error in
            
        // Get the attitude of the device
        if let attitude = motion?.attitude {
            // Get the pitch (in radians) and convert to degrees.
            print(attitude.pitch * 180.0/Double.pi)

            DispatchQueue.main.async {
                // Update some UI
            }
        }
            
    })
        
    print("Device motion started")
}else {
    print("Device motion unavailable")
}

NSHipster is (as always) a great source of information, and the article on CMDeviceMotion is no exception.

Alain Bianchini
  • 3,883
  • 1
  • 7
  • 27
Steve Wilford
  • 8,894
  • 5
  • 42
  • 66
  • Thank you may be you have an idea on this related question too? http://stackoverflow.com/questions/31643371/how-can-i-draw-and-rotate-an-arrow-at-an-orientation-in-3d-space – Michael Jul 31 '15 at 21:39
  • How do you send the update to a background queue? Could you please extends your example – Michael Aug 01 '15 at 12:11
  • @confile The use of a background queue is described in the [linked NSHipster article](http://nshipster.com/cmdevicemotion/#queueing-up). I have also updated the answer. – Steve Wilford Aug 02 '15 at 15:54
  • 1
    @SteveWilford it gives positive value for alpha or for 180 - alpha. Is there any way to differentiate between them? – Priyal Feb 27 '18 at 11:43
5

Swift 4:

  let motionManager = CMMotionManager()

   if motionManager.isDeviceMotionAvailable {

       motionManager.deviceMotionUpdateInterval = 0.1

       motionManager.startDeviceMotionUpdates(to: OperationQueue()) { [weak self] (motion, error) -> Void in

           if let attitude = motion?.attitude {

                print(attitude.pitch * 180 / Double.pi)

                DispatchQueue.main.async{
                    // Update UI
               }
           }

       }

       print("Device motion started")
    }
   else {
       print("Device motion unavailable")
    }
Aaron Halvorsen
  • 2,610
  • 1
  • 23
  • 31