Search code examples
iosxcode5core-motioncmmotionmanager

CMMotionManager: Device Calibration does not work on a real device


I've a strange behavior with CMMotionManager. I try to calibrate the position of my device to enable my App to support multiple device orientations.

When I debug my App on a real device (not in Simulator), everything is working fine. When I run the same App without debugging, the calibration does not work.

Here's my code:

static CMMotionManager* _motionManager;
static CMAttitude* _referenceAttitude;

// Returns a vector with the current orientation values
// At the first call a reference orientation is saved to ensure the motion detection works for multiple device positions
+(GLKVector3)getMotionVectorWithLowPass{
    // Motion
    CMAttitude *attitude = self.getMotionManager.deviceMotion.attitude;
    if (_referenceAttitude==nil) {
        // Cache Start Orientation
        _referenceAttitude = [_motionManager.deviceMotion.attitude copy];
    } else {
        // Use start orientation to calibrate
        [attitude multiplyByInverseOfAttitude:_referenceAttitude];
        NSLog(@"roll: %f", attitude.roll);
    }
    return [self lowPassWithVector: GLKVector3Make(attitude.pitch,attitude.roll,attitude.yaw)];
}

+(CMMotionManager*)getMotionManager {
    if (_motionManager==nil) {
        _motionManager=[[CMMotionManager alloc]init];
        _motionManager.deviceMotionUpdateInterval=0.25;
        [_motionManager startDeviceMotionUpdates];
    }
    return _motionManager;
}

Solution

  • I've found a solution. The issue was caused due the different timing behavior between debug and non debug mode. CMMotionManager needs a little time for initializing, before it returns correct values. The solution was to postpone the calibration for 0.25 seconds.

    This code works:

    +(GLKVector3)getMotionVectorWithLowPass{
        // Motion
        CMAttitude *attitude = self.getMotionManager.deviceMotion.attitude;
        if (_referenceAttitude==nil) {
            // Cache Start Orientation
            // NEW:
            [self performSelector:@selector(calibrate) withObject:nil afterDelay:0.25];
    
        } else {
            // Use start orientation to calibrate
            [attitude multiplyByInverseOfAttitude:_referenceAttitude];
            NSLog(@"roll: %f", attitude.roll);
        }
        return [self lowPassWithVector: GLKVector3Make(attitude.pitch,attitude.roll,attitude.yaw)];
    }
    
    // NEW:
    +(void)calibrate  
          _referenceAttitude = [self.getMotionManager.deviceMotion.attitude copy]
    }