How to make speed calculation accurate in iOS? - iphone

I use CLLocation with accuracy of kCLLocationAccuracyBestForNavigation. I am able to calculate the speed accurately. However, there is a 10sec delay in calculation...
For example, when I drive car at from 45mph to 55mph, the device shows 55mph around 10 secs later.
Is there a way we could make it a bit more precise?
Here is the code...
- (void)getSpeed
{
[self.locMgr startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
double numericSpeed;
self.location = [locations lastObject];
numericSpeed = self.location.speed * 3.6 * 0.621371;
}

Related

How can I calculate my speed with an iPhone? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to calculate speed of our car using iphone
How can I calculate my speed with an iPhone? For example, I might want to measure the speed of my car when driving. How can I implement this?
Try something like this:
- (id) init
{
self = [super init];
if (self != nil) {
self.manager = [[CLLocationManager alloc] init];
self.manager.delegate = self;
[self.manager startUpdatingLocation];
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"Speed = %f", newLocation.speed);
}
1>You can use GPS
Use the location services to get the latitude and longitude at a particular point of time and the you can get the same after a certain period of time say t.You can get the distance traveled from Latitude and longitude and divide it by the taken to get the speed
See the Apple GPS Doc
2>You can use Accelerometer
if you start from a halt, you should be able to calculate the distance you travel
based off the acceleration over time of the device.
See the Apple Accelerometer Doc

iOS CoreLocation not working over 3G in USA only

My app is unable to determine lat/long coordinates over 3G in North America. It works perfectly when connected to Wi-Fi. This has been confirmed with both AT&T and Verizon with iOS 5. In the UK it works as expected on both 3G and Wi-Fi with o2.
I'm really stumped as to what the cause may be. I think my code is quite forgiving with regards to accuracy, but as I'm on the other side of the pond, I could be way off?
Can anyone sport any glaring mistakes in my code? (I've removed some unrelated methods).
static NSTimeInterval MaxLocationAge = 60.0; // Seconds.
static CLLocationAccuracy DesiredHorizontalAccuracy = 200.0; // Meters.
static NSTimeInterval UpdateTimeout = 30.0; // Seconds.
#implementation AFLocation
#synthesize locationManager = _locationManager, delegate = _delegate, bestEffortAtLocation = _bestEffortAtLocation, updateStartedAt = _updateStartedAt;
- (id)init
{
self = [super init];
if (self) {
CLLocationManager *manager = [[CLLocationManager alloc] init];
self.locationManager = manager;
[manager release];
self.locationManager.delegate = self;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
}
return self;
}
- (void)update
{
self.updateStartedAt = [NSDate date];
isUpdating = YES;
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
if ([[NSDate date] timeIntervalSinceDate:self.updateStartedAt] > UpdateTimeout) {
[self.locationManager stopUpdatingLocation];
if (isUpdating) {
[self updateDidTimeout];
}
isUpdating = NO;
}
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > MaxLocationAge) {
return;
}
if (newLocation.horizontalAccuracy < 0) {
return;
}
if (self.bestEffortAtLocation == nil || self.bestEffortAtLocation.horizontalAccuracy > newLocation.horizontalAccuracy) {
self.bestEffortAtLocation = newLocation;
if (newLocation.horizontalAccuracy <= DesiredHorizontalAccuracy) {
self.bestEffortAtLocation = nil;
isUpdating = NO;
[self.locationManager stopUpdatingLocation];
[self didUpdateWithDesiredAccuracyToLocation:newLocation];
}
}
}
#end
WiFi and 3G are only used to speed up the process of getting a high accuracy (<300m) location. Without internet connectivity it can take 3-10 minutes to get a fix using GPS only. (They are used for low accuracy fixes with cell tower or wifi triangulation and also to download the satellite ephemeris data to speed up GPS signal acquisition).
The initial fix with WiFi or 3G could be around 800m accuracy that's expected, but if the device has 3G (or WiFi or Edge) connectivity and can get a strong enough signals from the GPS satellites it should be able to get a GPS position within 20-90 seconds.
Perhaps you're app isn't waiting long enough, or the user has weak GPS signal, or has a device without GPS (ie: iPhone1 or iPod Touch or non-3G iPads). In that case they won't get enough the 200m accuracy required.
You've set the CLLocationManager to use a desired accuracy of kCLLocationAccuracyBestForNavigation, but you're comparing the location's accuracy with an arbitrary accuracy of 200 meters. With kCLLocationAccuracyBestForNavigation being an opaque type, how do you know that the manager is even striving for your 200 meter accuracy? When I receive location updates, I check to see if the accuracy is less than or equal to the desired accuracy set on my location manager.

MapKit - didUpdateToLocation called but userLocation not updated

I have a MKMapView configured like so:
mapView = [[MKMapView alloc] init];
[mapView setMapType:MKMapTypeStandard];
[mapView setShowsUserLocation:YES];
[mapView setDelegate:self];
I then initialize a CLLocationManager and call startUpdatingLocation.
I am using iSimulate to send the GPS data from my phone, to the simulator, which seems to be working since the CLLocationManager delegate method is invoked with my correct GPS coordinates. However the MKMapView never moves the blue dot away from Cupertino.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
NSLog(#"Did Update Location = %f / %f", [newLocation coordinate].latitude, [newLocation coordinate].longitude);
NSLog(#"Current User Location = %f / %f", [[mapView userLocation] coordinate].latitude, [[mapView userLocation] coordinate].longitude);
}
The above method outputs the following:
>>> Did Update Location = 40.740100 / -73.989900 # Correct
>>> Current User Location = 37.331693 / -122.030457 # Cupertino... Incorrect
Even if I manually update the userLocation's coordinate using:
[[mapView userLocation] setCoordinate:[newLocation coordinate]];
The dot still just sits on Cupertino. Am I missing something?
The problem with CLLocation manger is that is caches the old location and some time it returns the old location. To get a new location just check the time stamp of the CLLocation object if it is older than the time limit then ignore this location
-(void) locationManager:(CLLocationManager*)manager
didUpdateToLocation:(CLLocation*)newLocation
fromLocation:(CLLocation*) oldLocation
{
NSDate* time = newLocation.timestamp;
NSTimeInterval timePeriod = [time timeIntervalSinceNow];
if(timePeriod < 2.0 ) { //usually it take less than 0.5 sec to get a new location but you can use any value greater than 0.5 but i recommend 1.0 or 2.0
[manager stopUpdatingLocation];
// process the location
} else {
// skip the location
}
}
The dot still just sits on Cupertino. Am I missing something?
Are you testing this on the simulator? Note that in the simulator, the location dot always remains in Cupertino. Try it on a device - maybe you don't have a bug at all!

Small Location Change Detection

I'm need to detect small location change for the iphone , I tried the sample that's called Locate Me, but it doesn't recognize the small change in the location. Is there any way for doing this?
Thanks in Advance.
Best regards
John
How small is the change that you expected?
Maybe you should set the accuracy to it's maximum and calculate the displacement on the delegate method.
Configure the location manager to give you it's best.
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locationManager setDistanceFilter:0.0];
And then on the delegate method:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
// Calculate the distance between the two locations
CGFloat distance = [newLocation distanceFromLocation:oldLocation];
if (distance >= MIN_DISPLACEMENT) {
// Do something
} else {
// Do something
}
}
To get more accurate data from the location manager, set the proper keys for UIRequiredDeviceCapabilities (location-services, gps) on the Info.plist.

CLLocation speed

I am developing GPS application.
Do you know about how to detect speed of mobile device ?
Actually, I need to detect the speed every 2 seconds.
I know didUpdateToLocation method is called when location changed.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
But I think this method is not suitable for my issue.
So, Do I need to check speed of [CLLocationManager location] in 2 seconds ?
Any suggestion ?
Thanks in advance.
How about the code below which works from the delegate method.
Alternatively, if you did want to poll, then keep your previous location and check the distance changed from the last poll and use the manual method (also shown below) to calculate the speed.
Speed is calculated/provided in m/s so multiply by 3.6 for kmph or 2.23693629 for mph.
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
//simply get the speed provided by the phone from newLocation
double gpsSpeed = newLocation.speed;
// alternative manual method
if(oldLocation != nil)
{
CLLocationDistance distanceChange = [newLocation getDistanceFrom:oldLocation];
NSTimeInterval sinceLastUpdate = [newLocation.timestamp timeIntervalSinceDate:oldLocation.timestamp];
double calculatedSpeed = distanceChange / sinceLastUpdate;
}
}
You can only really use the delegate method you have suggested in your question.
Even if you access the [CLLocationManager location] every 2 seconds, you will only receive the coordinate you last received in the delegate method above.
Why the need to poll every two seconds? The iphone can update it's coordinates in less time on some cases.
HTH