@varchar: Thanks for your help. Actually I resolved the error a few days ago.
I colored the part red which caused the error. Other parts which are still not clear to me are colored in green or blue.
Maybe you (or anybody else) would be so kind to take a look at the 2 latter methods. Especially at the part where I try to calculate the current and the average speed. Sadly it isn't workin --> My idea was to take the "good" locations which are calculatedin the method (void)updatedGPSCLLocation *)goodLocation fromLocationCLLocation *)oldLocation and use them for calculating the speed.
@silviuccia: I tried the same like you, but it seems that this attribute isn't implemented, yet. So that it isn't workin.
Please let me know if something is not clear.
parts of my code:
Code:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSDate *newLocationEventDate = newLocation.timestamp;
NSTimeInterval howRecentNewLocation = [newLocationEventDate timeIntervalSinceNow];
//initial Update, no oldLocation available therefore it won't be checked how good the data is
if(firstUpdate) {
[self updatedGPS:newLocation fromLocation:oldLocation];
firstUpdate = NO;
return;
}
if(isUpdating){
timesFired++;
//filter cached and too old locations
<-- old Code -->
//if((myLocation || myLocation.horizontalAccuracy > newLocation.horizontalAccuracy) && (howRecentNewLocation < -0.0 && howRecentNewLocation > -10.0))
<-- I took the commented if-clause from the example in this thread, but it doesn't update the location, it uses mostly old cached value.
That's why I'm using the following simplified if-clause. Maybe anyone has an idea why it isn't workin. -->
if (howRecentNewLocation < -0.0 && howRecentNewLocation > -10.0){
if(myLocation)
//release the cached location
[myLocation release];
<-- I forgot to assign the new value -->
myLocation =[newLocation retain];
}
<-- This if-clause isn't workin neither, it won't be accessed although the horizontalAccuracy is always '0'. I don't understand why? -->
//if ( myLocation.horizontalAccuracy <= 100 || (timesFired >= 3 && myLocation.horizontalAccuracy <= 1000) )
{
[self updatedGPS:myLocation fromLocation:oldLocation];
//timesFired = 0;
return;
}
/*will be entered if a --> don't remember what i wanted to do here or if else-statement is really needed
else{
return;
}*/
}
}
- (void)updatedGPS:(CLLocation *)goodLocation fromLocation:(CLLocation *)oldLocation{
//methode variables for calculating the current and avg speed
CLLocationDistance distanceMoved;
NSTimeInterval timeElapsed;
...
//calculate distance moved and time elapsed, but only if we have an "old" location
if(oldLocation != nil) {
distanceMoved = [goodLocation getDistanceFrom:oldLocation];
timeElapsed = [goodLocation.timestamp timeIntervalSinceDate:oldLocation.timestamp];
}
//formatting to km/h
currentSpeed = (distanceMoved*0.001)/(timeElapsed*360);
if(oldLocation != nil){
avgSpeed = [self returnAVGSpeed:[NSNumber numberWithDouble:currentSpeed]];
}
}
- (double)returnAVGSpeed:(NSNumber *)addCurrentSpeed{
double sumSpeeds;
if(avgSpeedPostion == 3)
avgSpeedPostion = 0;
//for the first 3 initiliazing steps, insertObject:atIndex method has to be used, after the third step replaceObjectAtIndex:withObject has to be used
//if-else condition isn't ideal, 2 different ints are used to determine position: "firstThreeSpeeds", "avgSpeedPostion";
if( firstThreeSpeeds < 3 ){
[latestSpeeds insertObject:addCurrentSpeed atIndex:firstThreeSpeeds];
firstThreeSpeeds++;
}
else{
[latestSpeeds replaceObjectAtIndex:avgSpeedPostion withObject:addCurrentSpeed];
avgSpeedPostion++;
}
NSEnumerator *speedsEnumerator = [latestSpeeds objectEnumerator];
NSNumber *object;
while (object = [speedsEnumerator nextObject]) {
sumSpeeds = sumSpeeds + [object doubleValue];
}
//would it be better to release speedsEnumerator here, or is a autorelease enough?
return (sumSpeeds/[latestSpeeds count]);
}
I'm still trying to figure out how to calculate the current speed of my application. From my point of view the calculation should be correct but now I only get values of 0.0 or slightly above.
I tried it with my car when I drove about 50km/h. I would be very grateful if somebody could help me.
Here is my code:
Code:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSLog(@"Updating location");
NSDate *newLocationEventDate = newLocation.timestamp;
//no pointer because it is a C-Class
NSTimeInterval howRecentNewLocation = [newLocationEventDate timeIntervalSinceNow];
//initial Update, no oldLocation available therefore it won't be checked how good the data is
if(firstUpdate) {
if (signbit(newLocation.horizontalAccuracy)) {
// Negative accuracy means an invalid or unavailable measurement
NSLog(@"LatLongUnavailable");
UIAlertView *myAlert = [[UIAlertView alloc] initWithTitle:@"Error Alert" message:@"LatLongUnavailable" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"exit", nil];
[myAlert show];
[myAlert release];
}
else{
myLocation = [newLocation retain];
[self updatedGPS:newLocation];
firstUpdate = NO;
[mySpinner stopAnimating];
isUpdating = NO;
return;
}
}
if(isUpdating){
if (signbit(newLocation.horizontalAccuracy)) {
// Negative accuracy means an invalid or unavailable measurement
NSLog(@"LatLongUnavailable");
UIAlertView *myAlert = [[UIAlertView alloc] initWithTitle:@"Error Alert" message:@"LatLongUnavailable" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"exit", nil];
[myAlert show];
[myAlert release];
}
else{
timesFired++;
//filter cached and too old locations
//1.Version:
//if((myLocation.horizontalAccuracy > newLocation.horizontalAccuracy) && (howRecentNewLocation < -0.0 && howRecentNewLocation > -10.0)) {
//2.Version
if(howRecentNewLocation < -0.0 && howRecentNewLocation > -10.0){
//release the cached location, if available
if(myLocation)
[myLocation release];
myLocation =[newLocation retain];
}
[self updatedGPS:myLocation];
timesFired = 0;
[mySpinner stopAnimating];
return;
}
}
}
}
- (void)updatedGPS:(CLLocation *)goodLocation{
//methode variables for calculating the current and avg speed
CLLocationDistance distanceMoved;
NSTimeInterval timeElapsed;
NSLog(@"uptadedGPS entered:");
NSLog(@"Lat: %f", goodLocation.coordinate.latitude);
NSLog(@"Long: %f", goodLocation.coordinate.longitude);
//calculate distance moved and time elapsed, but only if we have an "old" location
if(oldLocation != nil) {
distanceMoved = [goodLocation getDistanceFrom:oldLocation];
timeElapsed = [goodLocation.timestamp timeIntervalSinceDate:oldLocation.timestamp];
}
else{
distanceMoved = 0.0;
timeElapsed = 1.0;
}
//formatting to km/h
currentSpeed = (distanceMoved*0.001)/(timeElapsed*360);
currentSpeedLabel.text = [NSString stringWithFormat:@"%3.1f", currentSpeed];
NSLog(@"currentSpeed: %f", currentSpeed);
}
//save the latest goodLocation for calculating the speed
oldLocation = [goodLocation retain];
}
The first if-clause only was entered on the first update (because of "!myLocation"). After that this if-clause won't be entered and I always thought "2604785438 >= 0" is TRUE, maybe I shouldn't have skipped Math in school
Therefore I had to change the first is-clause, so that only the time interval was checked no matter how good the horizontalAccuracy was.
That brings me to the 2nd if-clause, so I had the value myLocation.horizontalAccuracy = 0;
but this if-clause wasn't entered neither, unless "timesFired" was incremented to 3.
I really don't know why this isn't working. I need this application for my thesis so your help would really be appreciated.
I could post my hole code here or I can send you my app, whatever you would need, so that this fu@!ing problem could be solved.
I've written a simple approach to calculate the current speed:
Code:
- (void)updatedGPS:(CLLocation *)goodLocation{
//methode variables for calculating the current and avg speed
CLLocationDistance distanceMoved;
NSTimeInterval timeElapsed;
//calculate distance moved and time elapsed, but only if we have an "old" location
if(oldLocation != nil) {
distanceMoved = [goodLocation getDistanceFrom:oldLocation];
timeElapsed = [goodLocation.timestamp timeIntervalSinceDate:oldLocation.timestamp];
}
else{
distanceMoved = 0.0;
timeElapsed = 1.0;
}
//formatting to km/h
currentSpeed = ((distanceMoved*0.001)/timeElapsed)*3600;
NSLog(@"currentSpeed: %f", currentSpeed);
if(oldLocation)
[self.oldLocation release];
self.oldLocation = [goodLocation retain];
//return;
}
It isn't very sophisticated but you could use it as a starting point and improve it by using a weighted average or kalman filter etc.
I totally different approach would be the use of the IPhone's internal accelerometer to calculate the speed, maybe this is more accurate.
@scotopia:
I don't know if you can generalize it. I think if your IPhone is a steady position, you could get quite good results. Look e.g. here: gmeter
But I have to say that I haven't tested it myself, I only got this info from a friend.
I have tested it extensively; I am a Physics professor and was interested in creating applications for use in physics; applying the classical equations resulted in dismal results. It basically goes like this:
1) the accelerometer is not that accurate and slightly wonky at times
2) have to integrate (or use an approximation method) those values once to get velocity; this greatly magnifies any lack of precision inherent in the source data
3) if you want position you have to integrate again and make the values even more innacurrate.
= garbage unless you really don't care about precision at all.
If there is anyone out there who has spent hours creating poop-shining algorithms that make the data sort of decent please let me know; I would definitely use it!
If you want to verify the wonkiness of the accelerometer hook it up to some sort of nigh frictionless slide that goes along one axis and roll it back and forth. Instead of seeing action along only the axis you are moving along you will see moderate to wild jumps on the other axes too; very frustrating!
@scotopia:
Thanks for your informative information.
So you could say that applications like gMeter don't deliver reliable information.
I myself am trying to receive reliable data from the locationManager to determine accurate speed values for my thesis.
And I'm also not so satisfied with functionality which the Location-API provides, neither. As a developer you haven't much control over the localization process.
I think gMeter might be using some sort of combination of everything to get values. I also think it is because gMeter is dealing with values over larger distances which is more forgiving. For instance I am talking about trying to measure your speed as your walking across the room or something; that definitely ain't happening (at least I don't know of any success).
It is OK to use the accelerometer to measure G, or history of G.
However, if you need to measure the change of G (for example, you need that to measure walking distance) for any accuracy, then it is completely useless.
Hi,
this thread is very interesting
I have a question.
I try to get speed, but compiler give me a error that don't exits structure.
I use this notation:
Code:
double speed = newLocation.speed;
Thanks
Silvia
you need to compile against 2.2 - speed and course are unknown in prior versions.
Basically the way to solve is to ignore the locationupdate if it is not very accurate or it is to old.
Below is the code... It works like a charm.... I get amazing accuracy... I am so happy!
Code:
// Called when the location is updated
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSDate* newLocationeventDate = newLocation.timestamp;
NSTimeInterval howRecentNewLocation = [newLocationeventDate timeIntervalSinceNow];
// Needed to filter cached and too old locations
if ((!currentLocation || currentLocation.horizontalAccuracy > newLocation.horizontalAccuracy) &&
(howRecentNewLocation < -0.0 && howRecentNewLocation > -10.0)) {
if (currentLocation)
[currentLocation release];
currentLocation = [newLocation retain];
}
}
In addition to the above, I use a timer which checks if currentLocation has latest data, if so, then it takes the coordinates. The timer also checks how many times the GPS was called and if it has been called more than the preset amount of time, then I give error to user (meaning the user is not in a good GPS spot [maybe underground?] )
Here is the code:
Code:
-(void)setLocation:(NSTimer *)timer {
timerFires++;
//NSLog(@"timerFires=%d",timerFires);
if ((currentLocation && currentLocation.horizontalAccuracy < accuracyThreshold) || timerFires >= maxFires) {
[timer invalidate];
[locationManager stopUpdatingLocation];
timerFires = 0;
// Catch here in case currenLocation is not set..
if (!currentLocation) {
// Give error to user
}
myCurrentLatitude = [NSString stringWithFormat:@"%lf",currentLocation.coordinate.latitude];
myCurrentLongitude = [NSString stringWithFormat:@"%lf",currentLocation.coordinate.longitude];
// Now lets go do the process we want with the gps info
[self LogGPSStuff];
return;
}
else {
return;
}
}
I hope the above helps you.... It took me days and days to get this right.... and I am very happy with it... but I am sure it can be improved....
i didnt understood it clearly, but its really a great job that u have solved this issue and even now i am not able to understand, if possible can u explain it in detail or can u post the complete code, plz friend, i am very much in need of it now. thank you.
awesome! thanks! I was wondering why my gps data wasn't updating as frequently as it should have... I thought Apple was just 'dumbing down' the GPS portions of the SDK they gave us so people would always use Google Maps.... It'd be awesome if filtering out old location data makes me as accurate as google... Here's hoping it works!
can you help me out in explaining about how to solve this issue clearly.
Basically the way to solve is to ignore the locationupdate if it is not very accurate or it is to old.
Below is the code... It works like a charm.... I get amazing accuracy... I am so happy!
Code:
// Called when the location is updated
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSDate* newLocationeventDate = newLocation.timestamp;
NSTimeInterval howRecentNewLocation = [newLocationeventDate timeIntervalSinceNow];
// Needed to filter cached and too old locations
if ((!currentLocation || currentLocation.horizontalAccuracy > newLocation.horizontalAccuracy) &&
(howRecentNewLocation < -0.0 && howRecentNewLocation > -10.0)) {
if (currentLocation)
[currentLocation release];
currentLocation = [newLocation retain];
}
}
In addition to the above, I use a timer which checks if currentLocation has latest data, if so, then it takes the coordinates. The timer also checks how many times the GPS was called and if it has been called more than the preset amount of time, then I give error to user (meaning the user is not in a good GPS spot [maybe underground?] )
Here is the code:
Code:
-(void)setLocation:(NSTimer *)timer {
timerFires++;
//NSLog(@"timerFires=%d",timerFires);
if ((currentLocation && currentLocation.horizontalAccuracy < accuracyThreshold) || timerFires >= maxFires) {
[timer invalidate];
[locationManager stopUpdatingLocation];
timerFires = 0;
// Catch here in case currenLocation is not set..
if (!currentLocation) {
// Give error to user
}
myCurrentLatitude = [NSString stringWithFormat:@"%lf",currentLocation.coordinate.latitude];
myCurrentLongitude = [NSString stringWithFormat:@"%lf",currentLocation.coordinate.longitude];
// Now lets go do the process we want with the gps info
[self LogGPSStuff];
return;
}
else {
return;
}
}
I hope the above helps you.... It took me days and days to get this right.... and I am very happy with it... but I am sure it can be improved....
can u give the guidence for when to call the timer, when to set the current location and setLocation method.
But first to say that all the apple examples are not working correct for a practical use (look at the maps app - never they used the apple example code *g*).
Only a short exp:
- With every GPS update i update the current location if it is more accurate then the last one and if it is new (< 10 seconds). If you dont test for the time interval you will get the latest (cached) location back!
- After a maximum of repeats (in my case five) i decide if the accuracy is ok (best case <= 10 meters, bad case <= 100 meters) and if not i call the error delegate (then i use the last known location of the current app user - NOT the last cached because the last cached is device dependend).
After some device tests that seems to work for me- If you have some other ideas to do it more accurate let me know :-)
Ralf
it is somewhat clear, if possible can u please explain it in detail and provide the code for updating the location, and when to call the "startUpdating" method and what are the classes, methods, properties that are being used by you.
Here is some further info about accuracy coming from locationmanager:
1st call => Giving the last location (old one for example from the maps app)
2nd call => Giving a new location but very inaccurate!
3rd call => Giving a new location with better acuracy
Further calls can give more accuracy but they are time consuming (the fourth call is statistically takeing more time!) and there is no guarantee that the accuracy is better then the third call!
I think maps app is handling three calls (very fast and a hopefully good accuracy)
And there is my old (other problem) that there is NO GUARANTEE thet gps is called more than three times - sometimes it does sometimes not. I did not found out when/why ...
My strategy is to run it three times and:
- if the accuracy is better than 20 meters i return (result good)
- if the three calls are gone and the accuracy is better than 100 meters i return (bad but good enough to use)
- if the three calls are gone and the accuracy is bader than 100 meters i take the last known location and the user is able to retry it
Ralf
Hi pashik, did u get the solution there, if so please help me out , even i stuck with this issue, it is giving me only the first location which i got when application has started , later if i try to update its not giving me the latest location.
Hi,
this thread is very interesting
I have a question.
I try to get speed, but compiler give me a error that don't exits structure.
I use this notation:
Code:
double speed = newLocation.speed;
Thanks
Silvia
I know this was ages ago but you'll want to look into heading instead of location for speed.. as its classified under heading.. in the location framework..