Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compass calibration objective-c

I try use compass in my ios app. And I have one problem with it. If i implement locationManagerShouldDisplayHeadingCalibration method and return YES in it, then calibration display is showing always. But I should make it like apple maps. I.e. calibration display should be showed sometimes. When compass should be calibration.

like image 675
alex_izh Avatar asked Jun 13 '13 14:06

alex_izh


4 Answers

A much more straight-forward solution:

Objective-C

- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager
{
    CLLocationDirection accuracy = [[manager heading] headingAccuracy];
    return accuracy <= 0.0f || accuracy > 10.0f;
}

This takes advantage of the fact that selectors performed on nil objects always return zero, and the fact the the accuracy is never going to be valid and equal to 0.0f (i.e. 100% accurate).

Swift

Due to the introduction of optionals, the simplest Swift solution does require branching and would look something like:

func locationManagerShouldDisplayHeadingCalibration(manager: CLLocationManager) -> Bool {
    if let h = manager.heading {
        return h.headingAccuracy < 0 || h.headingAccuracy > 10
    }
    return true
}

Note that we're looking at headingAccuracy, for which Apple's docs state:

A positive value in this property represents the potential error between the value reported by the magneticHeading property and the actual direction of magnetic north. Thus, the lower the value of this property, the more accurate the heading. A negative value means that the reported heading is invalid, which can occur when the device is uncalibrated or there is strong interference from local magnetic fields.

like image 73
Benjamin Dobell Avatar answered Oct 19 '22 23:10

Benjamin Dobell


OK I could not leave a comment so I thought I should leave a reply as Claude Houle's reply was useful to me.

I am using this improved version of Claude Houle's response.

- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager{
      if(!manager.heading) return YES; // Got nothing, We can assume we got to calibrate.
      else if(manager.heading.headingAccuracy < 0 ) return YES; // 0 means invalid heading, need to calibrate
      else if(manager.heading.headingAccuracy > 5 ) return YES; // 5 degrees is a small value correct for my needs, too.
      else return NO; // All is good. Compass is precise enough.
}

Also wanted to say what Claude Houle says almost implements the API docs here which states:

If you return NO from this method or do not provide an implementation for it in your delegate, Core Location does not display the heading calibration alert. Even if the alert is not displayed, calibration can still occur naturally when any interfering magnetic fields move away from the device. However, if the device is unable to calibrate itself for any reason, the value in the headingAccuracy property of any subsequent events will reflect the uncalibrated readings.

like image 21
Hiwa Avatar answered Oct 19 '22 21:10

Hiwa


manager.heading is CLHeading. that is why manager.heading > 5 will give a warning. self.currentHeading.headingAccuracy > 5 is the true one.

like image 28
Kaan Esin Avatar answered Oct 19 '22 21:10

Kaan Esin


I use the following code:

@property (nonatomic, retain) CLHeading * currentHeading; // Value updated by @selector(locationManager:didUpdateHeading:)
...
...
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager{
      if( !self.currentHeading ) return YES; // Got nothing, We can assume we got to calibrate.
      else if( self.currentHeading.headingAccuracy < 0 ) return YES; // 0 means invalid heading. we probably need to calibrate
      else if( self.currentHeading.headingAccuracy > 5 )return YES; // 5 degrees is a small value correct for my needs. Tweak yours according to your needs.
      else return NO; // All is good. Compass is precise enough.
}
like image 29
Claude Houle Avatar answered Oct 19 '22 22:10

Claude Houle