NOTICE: This question was originally posted before Apple introduced motion-detection hardware and associated APIs in the iOS SDK. Answers to this question, however, remain relevant.
I'm creating an iPhone iOS app which involves tracking a user's running and / or walking. It is very important that the recorded results of the users runs and walks remain honest. I need a way to catch a user who may be cheating (or accidentally have left the tracker on) when using a car.
To check if the user is driving or riding in a car I first thought of these two checks, however neither can really determine if the user is in a car or not (to a point).
Check the user's current speed in the following method. If the user is traveling faster than 20-ish MPH, then I could assume that the user is in a car:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation *recentLocation = [locations lastObject];
recentLocation.speed; //If speed is over 20 MPH, assume the user is not on their feet.
However, I'm not sure if this is really a good check because people have been recorded to go faster than that before. Is this a good check or should I use something else?
Determine how fast the user is accelerating using the Accelerometer and Motion APIs provided with the Core Motion Framework. If the user accelerates over a certain rate, then I could assume the user is traveling in a vehicle.
Are these assumptions correct? I guess my real question is this: Is there any better way to detect if the user is moving in a vehicle - if so how?. And if not, then are these checks suitable for this case or would this just be annoying to some users who are actually that fast? Is CoreMotion the proper API to do this with?
EDIT: The new iPhones 5S M7 Coprocessor provides more accurate movement detection. Could anyone explain how to use the new M7 APIs?
All the advice about the wisdom (or lack thereof) in guessing about motion states from location data still applies. But regarding your update about Core Motion and M7...
Yes, you can use Core Motion on devices with an M7, M8, M9, etc motion coprocessor(*) to get an indication of whether the user might be driving.
CMMotionActivityManager
object (after using its class method isActivityAvailable
to determine whether you you have M7(+) features), and either start activity updates or query it for recent activities.CMMotionActivity
objects' automotive
property to see if iOS thinks the user is/was in a car.Like the GPS inferences, though, you should still take this information with a grain of salt. CoreMotion APIs give you iOS' best guess as to the user's activity, but there's no guarantee it's 100% accurate. (For example, I'm not sure if riding a train might count as automotive
. Also note that the different activity types are not mutually exclusive.) It's better for your app to check for the activity types you're interested in than to try to exclude the ones you don't want.
(*) M7 devices are those with the A7 SoC: iPhone 5s, iPad Air, iPad mini 2. M8 is A8, M9 is A9, etc. In short, every iOS device introduced since Fall 2013, excluding iPhone 5c.
You can use this simple library to detect if user is walking, running, on vehicle or not moving.
Works on all iOS devices and no need M7 chip.
https://github.com/SocialObjects-Software/SOMotionDetector
In repo you can find demo project
The CLLocation
based check is the only reliable information you can get. As specified by Ali in Need to find Distance using Gyro+Accelerometer it is useless to find velocity and position for a longer period of time. The integrated acceleration values start drifting after 0.5 - 2 seconds and there is no chance to get them calibrated again.
Depending on your use case I see some more problems than Usain Bolt's 44.72 km/h (27.79 mph):
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With