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

我的问题是:

与加速度情况完全不同,后者使用3个轴的加速度 ALONG 计算加速度。

我真的很困惑,为什么也可以使用3轴的子旋转速度 AROUND 计算出总旋转速度。这对我来说没有意义。

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

最佳答案

由于您的头衔确实与您的问题不符,因此我正在尽力回答。

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

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

换句话说:陀螺仪为您提供了绕三个构造轴旋转的差异,因此您无需合成绝对值,而可以组成较小的增量。

现在,这非常笼统,并留下了一些 Unresolved 问题:

  • 我从哪里获得初始职位?答案:看一下旋转矢量传感器-您可以使用从那里获得的四元数作为初始化
  • 如何“求和” q和陀螺仪?

  • 取决于当前的旋转表示形式:如果使用旋转矩阵,则应按照注释中的建议进行简单的矩阵乘法(注意,此矩阵乘法实现效率不高!):
    /**
     * 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的源代码。

    关于android - 从Android陀螺仪获取四元数?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18587262/

    10-12 01:52