从Android陀螺仪获取四元数?

时间:2013-09-03 08:15:11

标签: android quaternions gyroscope

The official development documentation建议从3D旋转速率向量(wx, wy, wz)获取四元数的以下方法。

// Create a constant to convert nanoseconds to seconds.
private static final float NS2S = 1.0f / 1000000000.0f;
private final float[] deltaRotationVector = new float[4]();
private float timestamp;

public void onSensorChanged(SensorEvent event) {
  // This timestep's delta rotation to be multiplied by the current rotation
  // after computing it from the gyro sample data.
  if (timestamp != 0) {
    final float dT = (event.timestamp - timestamp) * NS2S;
    // Axis of the rotation sample, not normalized yet.
    float axisX = event.values[0];
    float axisY = event.values[1];
    float axisZ = event.values[2];

    // Calculate the angular speed of the sample
    float omegaMagnitude = sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);

    // Normalize the rotation vector if it's big enough to get the axis
    // (that is, EPSILON should represent your maximum allowable margin of error)
    if (omegaMagnitude > EPSILON) {
      axisX /= omegaMagnitude;
      axisY /= omegaMagnitude;
      axisZ /= omegaMagnitude;
    }

    // Integrate around this axis with the angular speed by the timestep
    // in order to get a delta rotation from this sample over the timestep
    // We will convert this axis-angle representation of the delta rotation
    // into a quaternion before turning it into the rotation matrix.
    float thetaOverTwo = omegaMagnitude * dT / 2.0f;
    float sinThetaOverTwo = sin(thetaOverTwo);
    float cosThetaOverTwo = cos(thetaOverTwo);
    deltaRotationVector[0] = sinThetaOverTwo * axisX;
    deltaRotationVector[1] = sinThetaOverTwo * axisY;
    deltaRotationVector[2] = sinThetaOverTwo * axisZ;
    deltaRotationVector[3] = cosThetaOverTwo;
  }
  timestamp = event.timestamp;
  float[] deltaRotationMatrix = new float[9];
  SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
    // User code should concatenate the delta rotation we computed with the current rotation
    // in order to get the updated rotation.
    // rotationCurrent = rotationCurrent * deltaRotationMatrix;
   }
}

我的问题是:

与加速情况相当,使用加速度 ALONG 3轴计算合成加速度是有意义的。

我真的很困惑为什么也可以用3轴的子旋转速率 AROUND 来计算合成转速。这对我没有意义。

为什么这种方法 - 找到复合旋转速度幅度 - 甚至可以工作?

2 个答案:

答案 0 :(得分:20)

由于你的标题与你的问题不符,我试图尽可能多地回答。

陀螺仪没有给出绝对方向(如ROTATION_VECTOR),但只围绕这些轴的旋转速度,它们被构建为“旋转”。这是由于gyroscope的设计和构造。想象一下下面的结构。黄金的东西是旋转,由于laws of physics它不想改变它的旋转。现在您可以旋转框架并测量这些旋转。

Illustration of a Gyroscope

现在,如果你想从陀螺仪获得某些东西作为“当前旋转状态”,你将不得不从初始旋转开始,称之为q0并不断添加陀螺仪的微小旋转差异。围绕轴测量:q1 = q0 + gyro0q2 = q1 + gyro1,...

换句话说:陀螺仪为您提供了围绕三个构造轴旋转的差异,因此您不是在构成绝对值而是组成小的增量。

现在这很普遍,留下了几个未回答的问题:

  1. 我从哪里获得初始职位?答:看看旋转矢量传感器 - 您可以使用从那里获得的四元数作为初始化
  2. 如何'总结'q和陀螺?
  3. 取决于旋转的当前表示:如果使用旋转矩阵,则应按照注释中的建议执行简单的矩阵乘法(请注意,此矩阵乘法实现效率不高!):

    /**
     * Performs naiv n^3 matrix multiplication and returns C = A * B
     * 
     * @param A Matrix in the array form (e.g. 3x3 => 9 values)
     * @param B Matrix in the array form (e.g. 3x3 => 9 values)
     * @return A * B
     */
    public float[] naivMatrixMultiply(float[] B, float[] A) {
        int mA, nA, mB, nB;
        mA = nA = (int) Math.sqrt(A.length);
        mB = nB = (int) Math.sqrt(B.length);
    
        if (nA != mB)
            throw new RuntimeException("Illegal matrix dimensions.");
    
        float[] C = new float[mA * nB];
        for (int i = 0; i < mA; i++)
            for (int j = 0; j < nB; j++)
                for (int k = 0; k < nA; k++)
                    C[i + nA * j] += (A[i + nA * k] * B[k + nB * j]);
        return C;
    }
    

    要使用此方法,假设mRotationMatrix保持当前状态,这两行完成工作:

    SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
    mRotationMatrix = naivMatrixMultiply(mRotationMatrix, deltaRotationMatrix);
    // Apply rotation matrix in OpenGL
    gl.glMultMatrixf(mRotationMatrix, 0);
    

    如果您选择使用四元数,请再次想象mQuaternion包含当前状态:

    // Perform Quaternion multiplication
    mQuaternion.multiplyByQuat(deltaRotationVector);
    // Apply Quaternion in OpenGL
    gl.glRotatef((float) (2.0f * Math.acos(mQuaternion.getW()) * 180.0f / Math.PI),mQuaternion.getX(),mQuaternion.getY(), mQuaternion.getZ());
    

    描述了四元数乘法here - equation (23)。请确保正确应用乘法,因为它不是可交换的!

    如果您只想知道设备的旋转(我认为这是您最终想要的),我强烈推荐使用ROTATION_VECTOR-Sensor。另一方面,陀螺仪对于测量旋转速度非常精确,并且具有非常好的动态响应,但是受到漂移的影响并且不会给出绝对定向(磁北极或根据重力)。

    更新:如果您想查看完整示例,可以从demo-app下载简单https://bitbucket.org/apacha/sensor-fusion-demo的源代码。

答案 1 :(得分:0)

对我有意义。加速度传感器通常通过在向被测轴施加力时具有一些可测量的量变化来工作。例如。如果重力在测量该轴的传感器上拉下来,它会更好地导电。所以现在你可以知道重力或某个方向的加速度是如何拉动的。容易。

同时陀螺仪是旋转的东西(好的,或者像一个经过调整的跳水板一样在直线上来回弹跳)。陀螺正在旋转,现在你旋转,根据你旋转的方向,陀螺仪会看起来更快或更慢。或者如果你试图移动它,它会抵制并试图继续前进。因此,您只需通过测量来获得旋转变化。然后你必须通过整合所有变化来计算出变化的力量。

通常,这些东西都不是一个传感器。它们通常是3个不同的传感器,它们彼此垂直排列,并测量不同的轴。有时所有传感器都在同一芯片上,但它们仍然是芯片上不同的东西。