CoreMotionActivityManager returning either Automot

2019-09-17 01:48发布

I'm trying to detect Automotive ActivtyType, however the problem is if "I go on a drive and then stop the car and stay in the car" and simply check the coreMotion logs: I would continue to get numerous mixed callbacks of either

high Confidence: Automotive: True, Stationary: True 

or

high confidence: Automotive: True, Stationary: False

or

low confidence: Automotive: True, Stationary: True

I do not get an only Stationary: True, it always comes with automotive being True as well

There's not much of a pattern to how they come, or at least I haven't been able to find a pattern.

Q: Has anyone found a reliable way of detecting when the car is truly automotive?

I've tried counting the number of callbacks I get and then doing some calculation but that doesn't seem reliable.

FWIW the moment the user gets out of the car then I get either a walking or stationary (with no automotive...which is good) callback and use those callbacks to set a flag to true...so after that if I get any automotive callback...then I know it’s a real automotive...

My code:

func beginMotionTracking(){

    let motionLog = OSLog(subsystem: "Spike", category: "Motion")

    shouldUseTimer = false
    motionActivityManager = CMMotionActivityManager()
    var totalWalking = 0
    var totalAutomotive = 0
    var totalStationary = 0
    var totalFalseAutomotive = 0

    motionActivityManager?.startActivityUpdates(to: OperationQueue.main){
        [weak self] activity in

        os_log("Motion is Tracking | desiredAccuracy is %{public}f | RemainingTime : %{public}f ",log: motionLog, type: .default, (self?.locationManager.desiredAccuracy)! , UIApplication.shared.remainingTime())

        if activity?.walking == true && (activity?.confidence == .medium || activity?.confidence == .high) && activity?.automotive == false && activity?.stationary == false && activity?.unknown == false {
            totalWalking += 1

            os_log("medium and high conf: walking %{public}d time", log: motionLog, type: .error, totalWalking)

        }else if activity?.stationary == true && (activity?.confidence == .medium || activity?.confidence == .high) && activity?.automotive == false && activity?.walking == false && activity?.unknown == false {
            totalStationary += 1

            os_log("medium and high conf: stationary %{public}d time", log: motionLog, type: .error, totalStationary)

            // false automotive
        }else if activity?.automotive == true && activity?.stationary == true && (activity?.confidence == .high) && activity?.walking == false  && activity?.unknown == false {
            totalFalseAutomotive += 1
            os_log("high conf: FALSE Automotive %{public}d time", log: motionLog, type: .error, totalFalseAutomotive)


            if totalFalseAutomotive > 2{
                totalFalseAutomotive = 0
                totalAutomotive = 0
                totalStationary = 0
                totalWalking = 0

                os_log("Too many FALSE automotives, REST all counts back to 0", log: motionLog, type: .fault)
            }
        }
        else if activity?.automotive == true && (activity?.confidence == .high) && activity?.walking == false && activity?.stationary == false && activity?.unknown == false {
            totalAutomotive += 1
            os_log("high conf: Automotive %{public}d time", log: motionLog, type: .error, totalAutomotive)

            if ((totalWalking > 3 && totalAutomotive > 2) || (totalStationary > 3 && totalAutomotive > 2) || (totalAutomotive > 7)){
                self?.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters

                os_log("Motion is Automotive and is about to be stopped: desired AccuracyChanged to HundredMeters | RemainingTime : %{public}f ", log: motionLog, type: .fault, UIApplication.shared.remainingTime())

                self?.shouldUseTimer = true
                self?.motionActivityManager?.stopActivityUpdates()
            }
        }
    }
}

I'm going through all this hassle, because I'm trying to degrade my core-location Accuracy whenever the user isn't driving for more than 3 minutes and then later using core-motion to detect automotive Motion and use that to put back location Accuracy to hundredMeter.

1条回答
做个烂人
2楼-- · 2019-09-17 02:23

This is what works for my similar use case, where I want to aggressively restrict interaction when .automotive has become set, but where I'm ok allowing an easy restoration of interaction if it becomes stationary. In logging the messages, it seems to hold onto the .automotive until another mode is detected (e.g. walking)

Since I commute on a bus with WiFi in heavy traffic, I saw repeated messages of:

confidence low, stationary true, automotive true
confidence high, stationary false, automotive true
....

They toggle as such over and over (and I never saw any medium confidence activities) and only when stationary for a sufficient time (10-12s) does the confidence to go high with stationary true, automotive true so I key off that.

Here's the code that I got to work:

func handleMotionActivityUpdates(activity: CMMotionActivity?) {
    if let a = activity {
        if a.automotive && !a.stationary && (a.confidence == .medium || a.confidence == .high) {
            //restrict interaction
        } else
        if (!a.automotive || a.stationary) && (a.confidence == .medium || a.confidence == .high) {
            //re-enable interaction
        }
    }
}
查看更多
登录 后发表回答