I need to implement a native iPhone app to measure the velocity of the phone (basically a speedometer). I know that you can do so via the CoreLocation API fairly easily, bu
While I don't know the iPhone API, I do know something about GPS and inertial navigation. It might be useful.
The GPS receivers I have worked with can all provide a direct measurement of velocity from the GPS signals they receive. These measurements are more accurate than position data even. I don't know if the Apple API provides access, or even if apple has configured their receiver to provide this data. This would be the more efficient route to getting a velocity measurement.
The next path, given that you have accelerometer data and GPS data is to combine them as mentioned earlier by other posters and comments. Using the GPS to periodically correct the accumulated intertial measurement from the accelerometer data works very well in practice. It provides the benefit of more frequent accelerometer measurements, and the accuracy of the GPS measurements. A Kalman filter is commonly used. But given the accuracy and timing limits of your chosen platform a kalman filter may be overkill and something simpler to implement and run should work fine.
Anyway, just some things to think about.
The error in the acceleration will accumulate over time. Your best bet is to get an accurate velocity from the GPS, maybe once a minute or less:
distanceTravelled = sqrt( (position2.x-position1.x)^2 + (position2.y-position1.y)^2 )
velocity = distanceTravelled/timeBetweenGPSReadings
(where ^2
means squared)
Then take frequent measurements of the accelerometer:
newVelocity = oldVelocity + accelerometer*timeBetweenAccelerometerReadings
From a practical standpoint, you are not going get accurate velocity from forces acting on the accelerometer.
Use the GPS with readings taken at 1 minute intervals and put the GPS to sleep inbetween.
Here is an example:
SpeedViewController.h
CLLocationManager *locManager;
CLLocationSpeed speed;
NSTimer *timer;
@property (nonantomic,retain) NSTimer *timer;
SpeedViewController.m
#define kRequiredAccuracy 500.0 //meters
#define kMaxAge 10.0 //seconds
- (void)startReadingLocation {
[locManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSTimeInterval ageInSeconds = [newLocation.timestamp timeIntervalSinceNow];
//ensure you have an accurate and non-cached reading
if( newLocation.horizontalAccuracy > kRequiredAccuracy || fabs(ageInSeconds) > kMaxAge )
return;
//get current speed
currentSpeed = newLocation.speed;
//this puts the GPS to sleep, saving power
[locManager stopUpdatingLocation];
//timer fires after 60 seconds, then stops
self.timer = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(timeIntervalEnded:) userInfo:nil repeats:NO];
}
//this is a wrapper method to fit the required selector signature
- (void)timeIntervalEnded:(NSTimer*)timer {
[self startReadingLocation];
}
I'm not sure you'll get very far trying to track velocity using the accelerometer. To do this, you'd have to make sure you captured EVERY acceleration, since any missed data points would indicate the wrong velocity (this is assuming, of course, you're able to convert the reported accelerometer values into standard units). Thus, you'd have to constantly run the accelerometer stuff, which sucks quite a bit of juice in itself (and, again, you won't be guaranteed all accelerations). I'd recommend using CoreLocation.
Since the GPS and accelerometer have different weaknesses, your best option is probably a combined approach - Get a measurement from the GPS every minute or so, then add realtime changes from the accelerometer.