我有一个应用程序,它使用方向数据,这是非常好地使用使用Sensor.TYPE_ORIENTAITON
的pre API-8方法。平滑这些数据是相对容易的。
我正在尝试更新代码,以避免使用这种过时的方法。新的标准方法是将单个Sensor.TYPE_ORIENTATION
替换为Sensor.TYPE_ACCELEROMETER
和Sensor.TYPE_MAGENTIC_FIELD
的组合。当接收到该数据时,它被(通过SensorManager.getRotationMatrix()
)发送到SensorManager.getOrientation()
。这(理论上)返回与Sensor.TYPE_ORIENTATION
相同的信息(除了不同的单位和轴方向)。
然而,这种方法似乎生成的数据比被弃用的方法(仍然有效)要抖动(即噪声)得多。因此,如果您在同一设备上比较相同的信息,则不推荐使用的方法提供的噪声数据比当前方法少得多。
我如何获得被弃用的方法所提供的实际相同(噪音较小)的数据?
让我的问题更清晰一点:我已经阅读了关于这个问题的各种答案,我已经尝试了所有类型的滤波器:你建议的简单KF / IIR低通;中值滤波器在5到19点之间,但到目前为止,我还没有接近手机通过TYPE_ORIENTATION提供的数据的平滑度。
发布于 2015-01-11 23:34:20
事实证明,还有另一种没有特别记录的方式来获取定位数据。隐藏在传感器类型列表中的是TYPE_ROTATION_VECTOR
。所以,设置一个:
Sensor mRotationVectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
sensorManager.registerListener(this, mRotationVectorSensor, SensorManager.SENSOR_DELAY_GAME);
然后:
@Override
public void onSensorChanged(SensorEvent event) {
final int eventType = event.sensor.getType();
if (eventType != Sensor.TYPE_ROTATION_VECTOR) return;
long timeNow = System.nanoTime();
float mOrientationData[] = new float[3];
calcOrientation(mOrientationData, event.values.clone());
// Do what you want with mOrientationData
}
关键机制是通过旋转矩阵将输入的旋转数据转换为方向向量。有点令人沮丧的是,方向向量最初来自四元数数据,但我不知道如何直接传递四元数。(如果您想知道四元数与方向和旋转信息的关系以及使用它们的原因,请参见here。)
private void calcOrientation(float[] orientation, float[] incomingValues) {
// Get the quaternion
float[] quatF = new float[4];
SensorManager.getQuaternionFromVector(quatF, incomingValues);
// Get the rotation matrix
//
// This is a variant on the code presented in
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/
// which has been altered for scaling and (I think) a different axis arrangement. It
// tells you the rotation required to get from the between the phone's axis
// system and the earth's.
//
// Phone axis system:
// https://developer.android.com/guide/topics/sensors/sensors_overview.html#sensors-coords
//
// Earth axis system:
// https://developer.android.com/reference/android/hardware/SensorManager.html#getRotationMatrix(float[], float[], float[], float[])
//
// Background information:
// https://en.wikipedia.org/wiki/Rotation_matrix
//
float[][] rotMatF = new float[3][3];
rotMatF[0][0] = quatF[1]*quatF[1] + quatF[0]*quatF[0] - 0.5f;
rotMatF[0][1] = quatF[1]*quatF[2] - quatF[3]*quatF[0];
rotMatF[0][2] = quatF[1]*quatF[3] + quatF[2]*quatF[0];
rotMatF[1][0] = quatF[1]*quatF[2] + quatF[3]*quatF[0];
rotMatF[1][1] = quatF[2]*quatF[2] + quatF[0]*quatF[0] - 0.5f;
rotMatF[1][2] = quatF[2]*quatF[3] - quatF[1]*quatF[0];
rotMatF[2][0] = quatF[1]*quatF[3] - quatF[2]*quatF[0];
rotMatF[2][1] = quatF[2]*quatF[3] + quatF[1]*quatF[0];
rotMatF[2][2] = quatF[3]*quatF[3] + quatF[0]*quatF[0] - 0.5f;
// Get the orientation of the phone from the rotation matrix
//
// There is some discussion of this at
// http://stackoverflow.com/questions/30279065/how-to-get-the-euler-angles-from-the-rotation-vector-sensor-type-rotation-vecto
// in particular equation 451.
//
final float rad2deg = (float)(180.0 / PI);
orientation[0] = (float)Math.atan2(-rotMatF[1][0], rotMatF[0][0]) * rad2deg;
orientation[1] = (float)Math.atan2(-rotMatF[2][1], rotMatF[2][2]) * rad2deg;
orientation[2] = (float)Math.asin ( rotMatF[2][0]) * rad2deg;
if (orientation[0] < 0) orientation[0] += 360;
}
这似乎给出的数据在感觉上与旧的TYPE_ORIENTATION
数据非常相似(我还没有运行数字测试):它可用于边缘过滤设备的运动控制。
https://stackoverflow.com/questions/27846604
复制相似问题