如何将游戏旋转矢量传感器结果转换为轴角度

时间:2016-12-31 13:27:45

标签: android rotation game-physics android-sensors motion-detection

参考下面的代码,我从Game_Rotation_Vector传感器事件中得到4个数字,我想要实现的是获得手机的轴角旋转。

例如。如果我逆时针旋转手机屏幕90度,我想从传感器数据中获得实际值90deg。

任何人都可以提供将4个游戏旋转矢量值转换为3个轴角度值的代码吗?

2 个答案:

答案 0 :(得分:0)

将值放入单位四元数like so

sensors_event_t.data[0] = rot_axis.x*sin(theta/2);
sensors_event_t.data[1] = rot_axis.y*sin(theta/2);
sensors_event_t.data[2] = rot_axis.z*sin(theta/2);
sensors_event_t.data[3] = cos(theta/2)

所以反过来就是:

double theta = Math.acos(vals[3])*2;
double sinv = Math.sin(theta/2);

double xa = vals[0]/sinv;
double ya = vals[1]/sinv;
double za = vals[2]/sinv;

xa,xy和xz不是角度,它们是轴的坐标,如文档中所述。我不确定你想要的是什么,你可能最好直接用单位四元数来实现你未说明的目标。

使用unit quaternion的原因是为了避免gimble lock,基本上你不能用三个角度,滚动/俯仰/偏航来描述每个可能的旋转,例如在一定的俯仰角和偏航角你可能会失去滚动的能力。

因此,使用此方法的一种方法是转换为旋转矩阵:

Source

if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
    // convert the rotation-vector to a 4x4 matrix. the matrix
    // is interpreted by Open GL as the inverse of the
    // rotation-vector, which is what we want.
    SensorManager.getRotationMatrixFromVector(
            mRotationMatrix , event.values);
}

答案 1 :(得分:0)

所以我们知道旋转矢量数据是一个单位四元数。

幸运的是,维基百科上有一个关于四元数转换的页面。

https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles

提供了两个例子。一个用C ++编写,一个用Python编写。我会在这里添加它们。

C ++:

static void toEulerAngle(const Quaterniond& q, double& roll, double& pitch, double& yaw)
{
    // roll (x-axis rotation)
    double sinr = +2.0 * (q.w() * q.x() + q.y() * q.z());
    double cosr = +1.0 - 2.0 * (q.x() * q.x() + q.y() * q.y());
    roll = atan2(sinr, cosr);

    // pitch (y-axis rotation)
    double sinp = +2.0 * (q.w() * q.y() - q.z() * q.x());
    if (fabs(sinp) >= 1)
        pitch = copysign(M_PI / 2, sinp); // use 90 degrees if out of range
    else
        pitch = asin(sinp);

    // yaw (z-axis rotation)
    double siny = +2.0 * (q.w() * q.z() + q.x() * q.y());
    double cosy = +1.0 - 2.0 * (q.y() * q.y() + q.z() * q.z());  
    yaw = atan2(siny, cosy);
}

的Python:

import math

def quaternion_to_euler_angle(w, x, y, z):
    ysqr = y * y

    t0 = +2.0 * (w * x + y * z)
    t1 = +1.0 - 2.0 * (x * x + ysqr)
    X = math.degrees(math.atan2(t0, t1))

    t2 = +2.0 * (w * y - z * x)
    t2 = +1.0 if t2 > +1.0 else t2
    t2 = -1.0 if t2 < -1.0 else t2
    Y = math.degrees(math.asin(t2))

    t3 = +2.0 * (w * z + x * y)
    t4 = +1.0 - 2.0 * (ysqr + z * z)
    Z = math.degrees(math.atan2(t3, t4))

    return X, Y, Z

请注意,在Android的单位四元数中,旋转矢量的标量分量是最后一个变量(四个中的变量)。在这些代码片段中,它是第一个变量。

我希望这有帮助!