2012-05-21 3 views
10

In einem iOS-Prototyp verwende ich eine Kombination aus CMDeviceMotion.deviceMotion.yaw und CLHeading.trueHeading, um eine stabile Kompassrichtung zu erstellen, die reaktionsschnell und genau ist. Dies funktioniert gut, wenn das iPhone flach gehalten wird, wo ich einen grafischen Pfeil habe, der auf eine stabile Kompassrichtung zeigt.CMDeviceMotion Gierwerte instabil, wenn das iPhone senkrecht steht

Das Problem tritt auf, wenn das iPhone im Portait-Modus vertikal gehalten wird. Die UIDeviceOrientation wechselt ständig von UIDeviceOrientationFaceDown zu UIDeviceOrientationFaceUp und zurück. Dies bewirkt, dass der Gierwert basierend auf kleinen Änderungen der Tonhöhe um +/- 180 Grad vor und zurück springt. Ist es möglich, das Gerät in einer Ausrichtung zu verriegeln, die einen stabilen Gierwert liefert, die Änderung ohne Störungen vorherzusagen oder das Gyroskop-Gieren (oder das Rollen in dieser Ausrichtung) auf andere Weise zu berechnen?

Dieser arme Kerl hat das gleiche Problem, ohne Antworten. Doppelte Punkte mögliche Leute! :) https://stackoverflow.com/questions/10470938/euler-angle-yaw-not-working-when-iphone-orientation-changes

Antwort

13

Ich war nur auf der Suche nach einer Antwort auf dieses Problem. Es hat mir ein wenig das Herz gebrochen zu sehen, dass du das vor über einem Jahr gepostet hast, aber ich dachte mir, dass du oder jemand anders von der Lösung profitieren könnte.

Das Problem ist Gimbal Lock. Wenn die Neigung etwa 90 Grad beträgt, passen sich Gieren und Rollen zusammen und der Kreisel verliert einen Freiheitsgrad. Quaternionen sind eine Möglichkeit, die kardanische Verriegelung zu vermeiden, aber ich hatte wirklich keine Lust, mich daran zu gewöhnen. Stattdessen habe ich festgestellt, dass Gieren und Rollen tatsächlich zusammenpassen und einfach zusammengefasst werden können, um das Problem zu lösen (vorausgesetzt, man kümmert sich nur um Gieren).

LÖSUNG:

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. 

Ich hoffe, das jemand anderes hilft!

+0

Es tat einfach, DANKE !!! –

+0

@ blkph19 können Sie bitte auf meine Antwort Ich konnte nicht den gesamten Code in den Kommentarabschnitt passen. – Deveram

1

Wenn jemand bei der Implementierung in iOS Swift interessiert ist, wird der Code unten angegeben:

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 
     } 
    } 

Jedoch habe ich einige Probleme habe und ich hoffe @ blkhp19 mich mit diesem, weil an bestimmten Punkten helfen können die Winkel gehen in negative Werte, die dann die gesamte Berechnung vermasseln und ich kann nicht herausfinden, was das Problem ist.