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 + gyro0: q2 = q1 + gyro1、...

つまり、ジャイロスコープは、構築された 3 つの軸を中心に回転した差を提供するため、絶対値ではなく小さなデルタを構成しています。

現在、これは非常に一般的であり、未回答の質問がいくつかあります。

  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は、 が現在の状態を保持していると想像してください。次の 2 行がその役割を果たします。

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

私には理にかなっています。加速度センサーは、通常、測定対象の軸に力が加えられたときに、測定可能な量の変化を起こすことによって機能します。たとえば、重力がその軸を測定するセンサーを下に引っ張っている場合、電気をよりよく伝導します。これで、重力またはある方向の加速度がどれだけ強く引っ張られているかがわかります。簡単。

一方、ジャイロは回転するものです(OK、または微調整した飛び込み台のように直線で前後に跳ね返ります)。ジャイロが回転している、回転すると、回転する方向に応じて、ジャイロの回転が速くなったり遅くなったりするように見えます。または、動かそうとすると、抵抗して、そのまま進み続けようとします。したがって、測定から回転の変化が得られます。次に、時間の経過に伴うすべての変化を統合することにより、変化からの力を把握する必要があります。

通常、これらのいずれも 1 つのセンサーではありません。多くの場合、それらはすべて互いに垂直に配置され、異なる軸を測定する 3 つの異なるセンサーです。すべてのセンサーが同じチップ上にある場合もありますが、それらはチップ上で別々に測定される別のものです。

于 2013-09-05T21:08:14.737 に答える