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, but I am concerned about battery consumption since this is to be a real-time measurement that could be used for up to a couple of hours at a time. My understanding is that while you are actively monitoring for events from the LocationManager (even though I don't actually care about GPS location) it is battery-intensive.
The other obvious option to explore would be using the accelerometers to try and calculate speed, but there is nothing in the API to help you do so. Based on my research, it should be possible to do this, but seems extremely complicated and error-prone. Translating from acceleration to velocity can be tricky to begin with, plus the iPhone accelerometer data can be "noisy". I'm familiar with the SDK example that demonstrates using low/high pass filtering, etc. -- but I have not seen a good example anywhere that shows calculating velocity.
Does anyone have any real-world experience with this they can share? Code would be fantastic, but really I just want to know if anyone has successfully done this (for a long-lived app) and what approach they took.
EDIT: I've got a working prototype that uses the LocationManager API. It works OK, but the update cycle is far from ideal for a real-time measurement of velocity. Depending on circumstances, it can take up to 4-5 seconds sometimes to update. Cruising at a given speed tends to work OK, but accel/decel tend to lag very badly from a user interaction standpoint. Also, I need to feed velocity into some other calculations that I'm doing and the precision is not really what I need.
It seems possible based on (very few) other apps I've seen, notably gMeter which claims to make no use of GPS but calculates velocity accurately. I'm really surprised there are no references or any sample code that demonstrates this anywhere that I can find. I realize it's complex, but surely there's something out there.
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];
}