Android getOrientation Азимут загрязняется, когда телефон наклонен
У меня действительно раздражающая проблема, когда вид AR ведет себя как компас. Поэтому, когда я держу телефон в портретном режиме (чтобы экран был направлен на мое лицо), тогда я вызываю remapCoordinateSystem
что высота тона равна 0, когда он находится в портретном положении. Тогда азимут (функция компаса) идеален, но как только я наклоняю телефон, азимут разрушается, если я наклоняюсь вперед, азимут увеличивается, а если я наклоняюсь назад, он уменьшается.
Я использую 2 датчика, чтобы получить показания, Sensor.TYPE_MAGNETIC_FIELD
а также Sensor.TYPE_GRAVITY
,
Я использую lowpassfilter, который довольно прост, он реализован с альфа- константой и используется непосредственно для считывания значений с датчиков.
Вот мой код:
float[] rotationMatrix = new float[9];
SensorManager.getRotationMatrix(rotationMatrix, null, gravitymeterValues,
magnetometerValues);
float[] remappedRotationMatrix = new float[9];
SensorManager.remapCoordinateSystem(rotationMatrix, SensorManager.AXIS_X,
SensorManager.AXIS_Z, remappedRotationMatrix);
float results[] = new float[3];
SensorManager.getOrientation(remappedRotationMatrix, results);
float azimuth = (float) (results[0] * 180 / Math.PI);
if (azimuth < 0) {
azimuth += 360;
}
float pitch = (float) (results[1] * 180 / Math.PI);
float roll = (float) (results[2] * 180 / Math.PI);
Как видите, здесь нет магии. Я вызываю этот кусок кода, когда параметры gravitymeterValues и magnetometerValues готовы к использованию.
У меня вопрос: как я могу остановить сумасшедший азимут, когда я наклоняю телефон?
Я проверил бесплатное приложение в Google Play Store, Compass, и оно не решило эту проблему, но я надеюсь, что есть решение.
Я имею в виду 2 решения:
Заставьте AR работать только в очень ограниченных углах наклона, сейчас у меня есть что-то вроде
pitch >= -5 && pitch <= 30
, Если это не заполнено, пользователю показывают экран, который просит, чтобы он / она повернул телефон к портрету.Каким-то образом используйте тональность для подавления азимута, хотя это кажется довольно специфичным для устройства решением, но, конечно, я открыт для предложений.
Я также могу добавить, что я искал подходящее решение в течение нескольких часов, и я не нашел ни одного, который дал бы мне лучшие решения, чем 2) здесь.
Заранее спасибо!
1 ответ
Полный код см. https://github.com/hoananguyen/dsensor
Сохраняйте историю и усредняйте, я не знаю правильной интерпретации шага и крена, поэтому следующий код предназначен только для азимута.
Члены класса
private List<float[]> mRotHist = new ArrayList<float[]>();
private int mRotHistIndex;
// Change the value so that the azimuth is stable and fit your requirement
private int mHistoryMaxLength = 40;
float[] mGravity;
float[] mMagnetic;
float[] mRotationMatrix = new float[9];
// the direction of the back camera, only valid if the device is tilted up by
// at least 25 degrees.
private float mFacing = Float.NAN;
public static final float TWENTY_FIVE_DEGREE_IN_RADIAN = 0.436332313f;
public static final float ONE_FIFTY_FIVE_DEGREE_IN_RADIAN = 2.7052603f;
onSensorChanged
@Override
public void onSensorChanged(SensorEvent event)
{
if (event.sensor.getType() == Sensor.TYPE_GRAVITY)
{
mGravity = event.values.clone();
}
else
{
mMagnetic = event.values.clone();
}
if (mGravity != null && mMagnetic != null)
{
if (SensorManager.getRotationMatrix(mRotationMatrix, null, mGravity, mMagnetic))
{
// inclination is the degree of tilt by the device independent of orientation (portrait or landscape)
// if less than 25 or more than 155 degrees the device is considered lying flat
float inclination = (float) Math.acos(mRotationMatrix[8]);
if (inclination < TWENTY_FIVE_DEGREE_IN_RADIAN
|| inclination > ONE_FIFTY_FIVE_DEGREE_IN_RADIAN)
{
// mFacing is undefined, so we need to clear the history
clearRotHist();
mFacing = Float.NaN;
}
else
{
setRotHist();
// mFacing = azimuth is in radian
mFacing = findFacing();
}
}
}
}
private void clearRotHist()
{
if (DEBUG) {Log.d(TAG, "clearRotHist()");}
mRotHist.clear();
mRotHistIndex = 0;
}
private void setRotHist()
{
if (DEBUG) {Log.d(TAG, "setRotHist()");}
float[] hist = mRotationMatrix.clone();
if (mRotHist.size() == mHistoryMaxLength)
{
mRotHist.remove(mRotHistIndex);
}
mRotHist.add(mRotHistIndex++, hist);
mRotHistIndex %= mHistoryMaxLength;
}
private float findFacing()
{
if (DEBUG) {Log.d(TAG, "findFacing()");}
float[] averageRotHist = average(mRotHist);
return (float) Math.atan2(-averageRotHist[2], -averageRotHist[5]);
}
public float[] average(List<float[]> values)
{
float[] result = new float[9];
for (float[] value : values)
{
for (int i = 0; i < 9; i++)
{
result[i] += value[i];
}
}
for (int i = 0; i < 9; i++)
{
result[i] = result[i] / values.size();
}
return result;
}