从Android陀螺仪获取四元数?

Sib*_*ing 5 android quaternions gyroscope

官方开发文档提出了以下从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;
   }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:

这是很从加速度情况不同,在那里,计算使用的加速度的合成加速度ALONG 3个轴是有意义的.

我真的很困惑,为什么得到的转速也可以与子旋转速率来计算 3个轴.这对我来说没有意义.

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

Ale*_*cha 20

由于你的标题与你的问题不符,我正尽力回答.

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

陀螺仪的例证

现在,如果你想获得的东西从陀螺仪的"当前旋转状态",你将有一个初始旋转开始,把它q0不断补充那些小小的旋转差,该陀螺仪绕轴线它测量:q1 = q0 + gyro0,q2 = 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;
}
Run Code Online (Sandbox Code Playgroud)

要使用此方法,假设mRotationMatrix保持当前状态,这两行执行以下操作:

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

如果您选择使用Quaternions,请再次想象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());
Run Code Online (Sandbox Code Playgroud)

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

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

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


Lan*_*nek 0

我感觉合理。加速度传感器的工作原理通常是,当向被测轴施加力时,会产生一些可测量的量变化。例如,如果重力对测量该轴的传感器产生下拉作用,则它的导电性能会更好。现在您可以知道重力或某个方向上的加速度的拉力有多大。简单的。

与此同时,陀螺仪是旋转的东西(好吧,或者像调整过的跳水板一样沿直线来回弹跳)。陀螺仪正在旋转,现在您旋转,陀螺仪看起来会旋转得更快或更慢,具体取决于您旋转的方向。或者,如果你试图移动它,它会抵抗并试图继续按原来的方式移动。所以你只需通过测量它就可以得到旋转变化。然后,您必须通过整合一段时间内的所有变化来找出变化的力量。

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

  • 问题是你的问题是为什么陀螺仪不像线性力传感器那样工作。答案是它们不是同一件事。陀螺仪旋转(或以远离作为黑客测量的振动的水平力振动)。这就是为什么所有陀螺仪测量都基于旋转而不是沿轴的线性力。整个评论试图向您解释每件事是什么以及它们有何不同。您为什么认为除了陀螺仪的旋转之外还可以测量其他任何东西? (2认同)