Alessio Campanelli
Alessio Campanelli

Reputation: 1020

Detect physical movement of iPhone/Apple Watch

I'm trying to detect the movement (to the right or left) performed by users. We assume that the user starts with his arm extended in front of him and then moves his arm to the right or to the left (about 90 degrees off center).

I've integrated CMMotionManager and want to understand detecting direction via startAccelerometerUpdatesToQueue and startDeviceMotionUpdatesToQueue methods.

Can anyone suggest how to implement this logic on an iPhone and then on an Apple Watch?

Upvotes: 3

Views: 3129

Answers (1)

user4151918
user4151918

Reputation:

Apple provides watchOS 3 SwingWatch sample code demonstrating how to use CMMotionManager() and startDeviceMotionUpdates(to:) to count swings in a racquet sport.

Their code demonstrates how to detect the direction of a one-second interval of motion, although you may have to tweak the thresholds to account for the characteristics of the motion you want to track.

func processDeviceMotion(_ deviceMotion: CMDeviceMotion) {
    let gravity = deviceMotion.gravity
    let rotationRate = deviceMotion.rotationRate

    let rateAlongGravity = rotationRate.x * gravity.x // r⃗ · ĝ
                         + rotationRate.y * gravity.y
                         + rotationRate.z * gravity.z
    rateAlongGravityBuffer.addSample(rateAlongGravity)

    if !rateAlongGravityBuffer.isFull() {
        return
    }

    let accumulatedYawRot = rateAlongGravityBuffer.sum() * sampleInterval
    let peakRate = accumulatedYawRot > 0 ?
        rateAlongGravityBuffer.max() : rateAlongGravityBuffer.min()

    if (accumulatedYawRot < -yawThreshold && peakRate < -rateThreshold) {
        // Counter clockwise swing.
        if (wristLocationIsLeft) {
            incrementBackhandCountAndUpdateDelegate()
        } else {
            incrementForehandCountAndUpdateDelegate()
        }
    } else if (accumulatedYawRot > yawThreshold && peakRate > rateThreshold) {
        // Clockwise swing.
        if (wristLocationIsLeft) {
            incrementForehandCountAndUpdateDelegate()
        } else {
            incrementBackhandCountAndUpdateDelegate()
        }
    }

    // Reset after letting the rate settle to catch the return swing.
    if (recentDetection && abs(rateAlongGravityBuffer.recentMean()) < resetThreshold) {
        recentDetection = false
        rateAlongGravityBuffer.reset()
    }
}

Upvotes: 4

Related Questions