5

官方开发文档建议通过以下方式从 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 个轴的加速度计算合成加速度是有意义的。

我真的很困惑为什么也可以用围绕3 个轴的子旋转率来计算结果旋转率。这对我来说没有意义。

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

4

2 回答 2

20

由于您的标题与您的问题不完全匹配,因此我正在尝试尽可能多地回答。

陀螺仪不提供绝对方向(如ROTATION_VECTOR),而只提供围绕它们构建为“旋转”的那些轴的旋转速度。这是由于陀螺仪的设计和构造。想象一下下面的结构。金色的东西是旋转的,由于物理定律,它不想改变它的旋转。现在您可以旋转框架并测量这些旋转。

陀螺仪的插图

现在,如果您想从陀螺仪获得“当前旋转状态”,您必须从初始旋转开始,调用它q0并不断添加陀螺仪围绕轴测量的微小旋转差异q1 = q0 + gyro0q2 = q1 + gyro1, ...

换句话说:陀螺仪给你它围绕三个构造轴旋转的差异,所以你不是在组成绝对值,而是组成小的增量。

现在这是非常笼统的,还有几个问题没有得到解答:

  1. 我从哪里获得初始位置?答:看一下旋转矢量传感器 - 您可以使用从那里获得的四元数作为初始化
  2. 如何“求和”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());

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

如果您想简单地了解设备的旋转(我假设这是您最终想要的),我强烈推荐 ROTATION_VECTOR-Sensor。另一方面,陀螺仪在测量旋转速度方面非常精确,并且具有非常好的动态响应,但会受到漂移的影响,并且不会为您提供绝对方向(指向磁北或根据重力)。

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

于 2013-09-14T09:00:22.810 回答
0

我感觉合理。当力施加到被测量的轴上时,加速度传感器通常通过一些可测量的量变化来工作。例如,如果重力拉低测量该轴的传感器,它会更好地导电。所以现在你可以知道重力或某个方向的加速度有多大的拉力。简单的。

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

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

于 2013-09-05T21:08:14.737 回答