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 + gyro0
,q2 = q1 + gyro1
,...
换句话说:陀螺仪为您提供了绕三个构造轴旋转的差异,因此您无需合成绝对值,而可以组成较小的增量。
现在,这非常笼统,并留下了一些 Unresolved 问题:
取决于当前的旋转表示形式:如果使用旋转矩阵,则应按照注释中的建议进行简单的矩阵乘法(注意,此矩阵乘法实现效率不高!):
/**
* 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/