Does anyone have any suggestions on how to obtain the best horizontal accuracy on the location manager? I have set the desired accuracy to NearestTenMeters, but given that the accuracy can always change depending on coverage area, how can I write some code in the locationManager to stop updating only after I get the best horizontal accuracy?
If you want it to be to a certain accuracy, set the delegate method
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
to have
if(newLocation.horizontalAccuracy <= (some number) )
[locationManager stopUpdatingLocation];
something like that.
Typically the longer the hardware is on and the more locations it gets the more accurate it gets. You can try turning on the manager early to let it get accurate and then grab the location. It also helps when the target is moving, the chip is able to get more accurate readings when gps is moving. Also the location of the device makes a diffrence, you will get much better reads if you are outside on a field than if you are in a bunker, so sometimes the read you get is the best thats available. Your code can wait till it gets no more updates from location manager for some time, then its probably at its best accuracy.
Related
On my app, I have pin pointed an area on interest. And also the GPS of my location, how would I now let the app calculate and show the user how far the distance away is for them?
My .h file is setup with a map view, a button for finding my location and set map options to choose between map/satellite and hybrid views.
In my .m file I have all the code setting the location and where I am, and also enabled tracking mode. Also setup the different map views and have set a pin point on my map and set the latitude and longitude, then enable Zoom & Scroll function. I have also set so that on the map, when you click on the pinpointed area it says the name and a small description of the place. So everything works fine at this point :D
I really need to find how to find the distance between my point and the pinpointed area.
*please note I am using MapKit!
here if you use bellow code in delegate method of CLLocationManager then its return the distance from your current point to destination point..
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
CLLocation *appleHQ = [[CLLocation alloc] initWithLatitude:37.322998 longitude:-122.032182];////here put your destination point
NSLog(#"New Location:%#", newLocation);
CLLocationDistance distance = [newLocation distanceFromLocation:appleHQ];
NSLog(#"Distance to Apple HQ %4.0f km", distance);
[appleHQ release];
}
just try this code ...
hope,this help you.
I'm writing an app that monitors the user's location. I have a CLLocationManager object that uses startMonitoringSignificantLocationChanges, so I can get locations updates from the background when the app is not running. I have setup my application didFinishLaunchingWithOptions so if I get a location key I fire up my manager to get the user's location. Everything works fine but the problem is that every time I get a location from the background, the Horizontal Accuracy of this location is very bad. In most of the cases it is 1414 m.
Does anybody know why the horizontal accuracy is so bad when the location comes from the background?
Is there anything I can do to get locations with better accuracy in the background?
When the app is running all the locations I get are very accurate, this only happens when the location comes from the background. Does that have anything to do with the number of cell towers I have in my city? I was thinking maybe the device doesn't use gps of wifi nodes to get locations in the background.
Anyways, Any help here is appreciated.
Please share your thoughts.
Thanks!
The accuracy of locations returned by CLLocationManager is determined by the desiredAccuracy, which is by default, kCLLocationAccuracyBest, and by the available accuracy of the device. For instance, you may get less accurate locations if the device's battery is low, or you may get more accurate locations if they are still cached from another app.
However, getting you incredibly accurate coordinates drains a significant amount of power from the battery and will drain the device. Applications in the background are probably limited to a much lower resolution of accuracy to improve battery performance.
Accurate locations require a lot of power to use the GPS radio while less accurate locations can rely on nearby wifi hotspots and the cell towers within range of the phone.
As your application resumes from the background, the system will try to improve the accuracy of the results you get. It's a tricky concept, but take a look at the Maps application on your phone. At first, the circle representing your location is very large; as the system gets a more accurate sense of your location, the circle becomes smaller. This visualization represents the phone using more power to get a more precise location.
You'll see a similar phenomenon with CLLocationManager as your app resumes from the background: you'll get an inaccurate location and receive subsequent, more accurate updates.
It's a compromise between convenience and battery life that Apple had to make when designing their APIs. The first update to a user's location probably won't be that accurate unless they were just using the Maps application and the location is cached.
The best advice I can give you is to listen for subsequent updates from the location manager and update your UI accordingly. Good luck!
As the name states: The startMonitoringSignificantLocationChanges notification is only there to let you know that a the the user's location significantly different from the last one checked. It's your job when you receive that Notification to update your location according to the desired accuracy you want.The notification won't do that for you. It is only going to let you know the location has change so you can deal with the situation accordingly. If you don't know how to get a better accuracy you may want to check out the Apple sample code for LocateMe.Here's a snippet that stores the accuracy(bestEffortAtLocation) then tests the accuracy each time the delegate is called until a better result comes in or a time-out occurs.:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
// store all of the measurements, just so we can see what kind of data we might receive
[locationMeasurements addObject:newLocation];
// test the age of the location measurement to determine if the measurement is cached
// in most cases you will not want to rely on cached measurements
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > 5.0) return;
// test that the horizontal accuracy does not indicate an invalid measurement
if (newLocation.horizontalAccuracy < 0) return;
// test the measurement to see if it is more accurate than the previous measurement
if (bestEffortAtLocation == nil || bestEffortAtLocation.horizontalAccuracy > newLocation.horizontalAccuracy) {
// store the location as the "best effort"
self.bestEffortAtLocation = newLocation;
// test the measurement to see if it meets the desired accuracy
//
// IMPORTANT!!! kCLLocationAccuracyBest should not be used for comparison with location coordinate or altitidue
// accuracy because it is a negative value. Instead, compare against some predetermined "real" measure of
// acceptable accuracy, or depend on the timeout to stop updating. This sample depends on the timeout.
//
if (newLocation.horizontalAccuracy <= locationManager.desiredAccuracy) {
// we have a measurement that meets our requirements, so we can stop updating the location
//
// IMPORTANT!!! Minimize power usage by stopping the location manager as soon as possible.
//
[self stopUpdatingLocation:NSLocalizedString(#"Acquired Location", #"Acquired Location")];
// we can also cancel our previous performSelector:withObject:afterDelay: - it's no longer necessary
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(stopUpdatingLocation:) object:nil];
}
}
// update the display with the new location data
}
The credit goes to Apple because this is a snippet straight from their sample code LocateMe:
http://developer.apple.com/library/ios/#samplecode/LocateMe/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007801-Intro-DontLinkElementID_2
So when you get the notification and need to get a better result you'll need to update the accuracy and see if that gives you a better result.
I would like to find the distance to a location and which direction the device is heading in relation to that location. I've got the distance working but cant work out how to find the which way the location.
_theLocation = [[CLLocation alloc]initWithLatitude:-41.561004 longitude:173.849030];
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CLLocationDistance meters = [newLocation distanceFromLocation:_theLocation] * 0.000621371192;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
NSString *str = [NSString stringWithFormat:#"Heading = %.f", newHeading.trueHeading];
}
Is it possible to find the heading to _theLocation from our location?
Can't you simply capture the device's location at two instances & figure out the direction wrt the location?
Not a complete solution, but assuming that the device only moves along the line joining the device & the location, you can use – distanceFromLocation:. If you capture the distance from the location at two instances & see if the latter value is less than the former, you can deduce that the device has moved closer to the location.
In fact, from your question, it appears that you want to determine whether the device has moved closer to the location or not (and not the exact direction, say N or NE). If that's the case, then this should work.
HTH,
Akshay
I am writing an app, that uses GPS. I can get successfully the latitude, longitude and other properties, but altitude seems to always return "0.00" i have the following code to test it in the most simplest way and still get 0.00. Code below:
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// Stop updating location if renewed in less than 60 seconds
if ([self timeBetweenLocationandNow] < 60)
{
[locationManager stopUpdatingLocation];
NSLog(#"GPS Stopped");
}
NSLog(#"Altitude:%.2f m",newLocation.altitude);
}
Any ideas on what could be wrong ? also on an init method i have the following:
- (id)init
{
self = [super init];
if (self != nil)
{
// Create location manager Object
locationManager = [[CLLocationManager alloc] init];
// Set the delegate to this object
[locationManager setDelegate:self];
// Set distance filter and accuracy
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locationManager startUpdatingLocation];
}
return self;
}
Will appreciate any insight. thank you
I'm no expert but this is how I understand it: The iPhone is quite different from other gps systems because of the multiple ways in which it goes about figuring out your location. The iPhone figures out the location in three ways: local wifi signals, cell towers, and/or gps chip. Using a gps satellite to find a position can be extremely slow and reception can be pretty much non-existent in populated cities. Therefore, iPhone generally looks to the first 2 options first.
Wifi positioning data comes from people driving around on the streets logging hotspots which obviously isn't going to give much of a hint of an altitude. I'm not sure if cell tower triangulation gives any altitude data but my guess is no. These two methods are extremely fast compared to gps but will yield an altitude of 0 as you have seen. If you are in a place where there is a decent gps satellite reception the iPhone may give you the altitude, but even then, it might not even find it till it has received the satellite signal a few times and called the location delegate multiple times, and even then altitude data for gps can be notoriously inaccurate.
Long story short, it's a bad idea to count on accurate altitude data from the iPhone.
i found the problem. As Deepmist suggested the delegate has to be called several times. I was stopping the GPS after the first fix. Which was giving me accurate data for coordinates but altitude remained # 0.00 until like 3 or so delegate calls. Now i get the altitude data, what is a good way to check for this ? so i can stop the location manager after i get the data ? i can check that altitude is a non-zero value, but was wondering if there are other properties that should be used instead to make sure that you have the highest accuracy possible making all of your location data valid (i.e non-zero on some properties). thank you
I´m playing a bit with the iPhone SDK and I want to show the current speed in my application. There are so many apps that can do that really precise, especially for low speeds like running or biking. The best I've seen is RunKeeper.
But, in my application, the speed is absolutely inaccurate. In low speeds it is always null, and only at higher speeds it shows some values but they are rarely updated and not really useful.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
if (newLocation.timestamp > oldLocation.timestamp &&
newLocation.verticalAccuracy > 0.0f && // GPS is active
newLocation.horizontalAccuracy < 500.0f && // GPS is active
//newLocation.horizontalAccuracy < kCLLocationAccuracyHundredMeters && // good quality GPS signal
//newLocation.speed > 1.0f && // enough movment for accurate speed and course measurement
oldLocation != nil) // oldLocation is nil on the first reading
{
double speed = (newLocation.speed * 3.6);
[self updateDisplayWithSpeed:speed];
//double direction = newLocation.course;
}
}
Does anyone have working code for that? Or can you tell me what´s wrong with mine?
I would try the following.
Remember that you should set the distanceFilter and desiredAccuracy as needed by your scenario: walking is not the same as traveling by car etc. Moreover, when you request high accuracy from the GPS, you must always discard the very first location provided by the GPS and use the second one as the starting location. Quoting the Apple documentation:
You should assign a value to this property that is appropriate for your usage scenario. In other words, if you need only the current location within a few kilometers, you should not specify kCLLocationAccuracyBest for the accuracy. Determining a location with greater accuracy requires more time and more power.
When requesting high accuracy location data, the initial event delivered by the location service may not have the accuracy you requested. The location service delivers the initial event as quickly as possible. It then continues to determine the location with the accuracy you requested and delivers additional events, as necessary, when that data is available.
Here is my suggestion.
First, update the location using the GPS using an interval of at least one second. Below this interval the speed value is useless because it is measured in meters per second and owing to the previous discussion, you are not likely to get a valid update in less than a second with high accuracy.
Second, only use meaningful values for the location coordinates: you should discard values with negative horizontalAccuracy. This is what I am referring to when speaking of good locations.
Third, you can compute the distance by yourself: compute the distance between the last good location and the previous good location using getDistanceFrom() and then divide by the number of seconds elapsed between the location update. This will give you the distance in meters per second. I will try to do this and compare the result with the Apple provided speed.
Please try following in your code :
speedLabel.text = [NSString stringWithFormat:#"SPEED(Km/Hr): %f", [location speed]*3.6];
latitudeLabel.text = [NSString stringWithFormat:#"LATITUDE: %f", location.coordinate.latitude];
longitudeLabel.text = [NSString stringWithFormat:#"LONGITUDE: %f", location.coordinate.longitude];
CLLocationDistance meters = [location distanceFromLocation:orginalLoc];
distanceLabel.text = [NSString stringWithFormat:#"DISTANCE(M): %f", meters];