Значения CMDeviceMotion нестабильны, когда iPhone вертикальный

В прототипе iOS я использую комбинацию CMDeviceMotion.deviceMotion.yaw и CLHeading.trueHeading, чтобы сделать стабильный заголовок компаса, который является отзывчивым и точным. Это хорошо работает, когда iPhone удерживается плоским, где у меня есть графическая стрелка, указывающая на стабильный заголовок компаса.

Проблема возникает, когда iPhone удерживается вертикально в режиме portait. UIDeviceOrientation постоянно изменяется с UIDeviceOrientationFaceDown на UIDeviceOrientationFaceUp и обратно. Это делает значение рыскания проскальзыванием вперед и назад +/- 180 градусов на основе небольших изменений высоты тона. Можно ли заблокировать устройство до одной ориентации, что дает стабильное значение рыскания, предсказать изменение без сбоев или вычислить гироскоп (или рулон в этой ориентации) другими способами?

У этого бедного парня такая же проблема, без ответов. Возможны двойные точки!:) https://stackoverflow.com/info/10470938/euler-angle-yaw-not-working-when-iphone-orientation-changes

Ответ 1

Я просто искал ответ на эту проблему. Это немного разбило мне сердце, чтобы увидеть, что вы опубликовали это более года назад, но я подумал, что вы или кто-то другой могли бы воспользоваться этим решением.

Проблема заключается в блокировке карданного вала. Когда шаг составляет около 90 градусов, рыскание и ролл совпадают, и гироскоп теряет степень свободы. Кватернионы - один из способов избежать карданного замка, но я, честно говоря, не хотел обманывать меня. Вместо этого я заметил, что рыскание и бросок действительно совпадают и могут быть просто подведены для решения проблемы (предполагая, что вы только заботитесь о рыскании).

РЕШЕНИЕ:

    float yawDegrees = currentAttitude.yaw * (180.0 / M_PI);
    float pitchDegrees = currentAttitude.pitch  * (180.0 / M_PI);
    float rollDegrees = currentAttitude.roll * (180.0 / M_PI);

    double rotationDegrees;
    if(rollDegrees < 0 && yawDegrees < 0) // This is the condition where simply
                                          // summing yawDegrees with rollDegrees
                                          // wouldn't work.
                                          // Suppose yaw = -177 and pitch = -165. 
                                          // rotationDegrees would then be -342, 
                                          // making your rotation angle jump all
                                          // the way around the circle.
    {
        rotationDegrees = 360 - (-1 * (yawDegrees + rollDegrees));
    }
    else
    {
        rotationDegrees = yawDegrees + rollDegrees;
    }

    // Use rotationDegrees with range 0 - 360 to do whatever you want.

Я надеюсь, что это поможет кому-то еще!

Ответ 2

Если кто-то заинтересован в реализации в iOS Swift, код приведен ниже:

    let queue = NSOperationQueue()
    motionManager.startDeviceMotionUpdatesToQueue(queue) {
        [weak self] (data: CMDeviceMotion!, error: NSError!) in
    var yawDegrees: Double = self!.motionManager.deviceMotion.attitude.yaw * (180.0 / M_PI)
        var pitchDegrees: Double = self!.motionManager.deviceMotion.attitude.pitch * (180.0 / M_PI)
        var rollDegrees: Double = self!.motionManager.deviceMotion.attitude.roll * (180.0 / M_PI)


        if(rollDegrees < 0 && yawDegrees < 0){
            self!.rotationDegrees = 360 - (-1 * (yawDegrees + rollDegrees))
        }
        else {
            self!.rotationDegrees = yawDegrees + rollDegrees
        }
   }

Однако у меня возникают некоторые проблемы, и я надеюсь, что @blkhp19 может помочь мне в этом, потому что в определенные моменты углы попадают в отрицательные значения, которые затем испортят весь расчет, и я не могу понять, в чем проблема.