Frage CMDeviceMotion Gierwerte sind instabil, wenn das iPhone vertikal steht


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.

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


12
2018-05-21 20:43


Ursprung


Antworten:


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 hilft jemand anderem!


14
2017-07-29 18:27



Wenn jemand an der Implementierung in iOS Swift interessiert ist, ist 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
        }
   }

Allerdings habe ich einige Probleme und ich hoffe @ blkhp19 kann mir dabei helfen, denn an bestimmten Punkten gehen die Winkel in negative Werte, was dann die gesamte Berechnung durcheinander bringt und ich kann nicht herausfinden, was das Problem ist.


1
2018-05-22 08:39