iOS core motion detect forard / backward tilt

流过昼夜 提交于 2019-12-06 15:24:45

Using attitude pitch, leaning forward and backward are indistinguishable. However with quaternions you can calculate pitch, and if you convert radians to degrees,

  • 0 means the device is on its back
  • 90 means it's standing up
  • 180 means it's on its face

The opposite hemisphere of rotation is 0 to -180. Here's the code:

func radiansToDegrees(_ radians: Double) -> Double {
    return radians * (180.0 / Double.pi)
}

let quat = motionData.attitude.quaternion
let qPitch = CGFloat(radiansToDegrees(atan2(2 * (quat.x * quat.w + quat.y * quat.z), 1 - 2 * quat.x * quat.x - 2 * quat.z * quat.z)))

Try this:

// Create a CMMotionManager
CMMotionManager *mManager = [(AppDelegate *)[[UIApplication sharedApplication] delegate] sharedManager];
// Check whether the accelerometer is available
if ([mManager isAccelerometerAvailable] == YES) {
    [mManager setAccelerometerUpdateInterval: .02];
    [mManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
        [self updateGravityWithAccelerometerX:accelerometerData.acceleration.x y:accelerometerData.acceleration.y z:accelerometerData.acceleration.z];
    }];
}

This will call updateGravityWithAccelerometerData every .02 seconds. You should be able to create that method and use NSLog to watch the values change to decipher what you are looking for. I believe you are looking for the acceleration.y value.

You are right, pitch works that way, considering the 4 typical quadrants (http://en.wikipedia.org/wiki/Quadrant_(plane_geometry)) and the counterclockwise direction:

  • Quadrant I, values range from 0 to PI/2 (or 0 to 90 in degrees).
  • Quadrant II, values range from PI/2 to 0 (or 90 to 0 in degrees).
  • Quadrant III, values range from 0 to -PI/2 (or 0 to -90 in degrees).
  • Quadrant IV, values range from -PI/2 to 0 (or -90 to 0 in degrees).

Considering this looks pretty obvious that you cannot difference between the phone leaning forwards or backwards.

I have recently faced the same problem for an iOS app that counts the number of flips that the phone does. Apple has rejected it so I have published it on GitHub, may be useful for you:

Flip Your Phone! - https://github.com/apascual/flip-your-phone

You don't want to read the accelerometer for tilt. Accelerometer is for detecting differences in movements. You want the gyroscope so you can determine the absolute attitude (i.e. yaw, pitch and roll). In your case it sounds like you just want roll.

Use startDeviceMotionUpdatesToQueue and then attitude.roll for front and back and attitude.pitch for side to side. Here is what I did in Swift:

    func motion(data: CMDeviceMotion){  

    let pitch = data.attitude.pitch
    let roll = data.attitude.roll

    let dampener:Float = -0.25 // the ball was rolling too fast

    var forward_force = Float(1.6 - roll) * dampener  //1.6 is vertical
    var side_force = Float(pitch) * dampener  // 0 is untilted when rotating cw/ccw

    ballNode.physicsBody?.applyForce(SCNVector3Make(side_force, 0, forward_force), atPosition: SCNVector3Make(0, 0, 0), impulse: true)

}

With this you can see if it tilted frontward or backward based on whether the roll is greater than or equal to 1.6 which is approximately straight up.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!