我的AR View 像指南针一样遇到了一个非常烦人的问题。因此,当我将手机纵向放置时(屏幕指向我的脸),然后我将其纵向放置时的音调为0称为remapCoordinateSystem。这样,方位角(罗盘功能)就完美了,但是一旦我倾斜手机,方位角就会毁了,如果我向前弯曲,方位角会增加,而如果我向后弯曲,方位角会减小。

我使用2个传感器来获取读数Sensor.TYPE_MAGNETIC_FIELDSensor.TYPE_GRAVITY

我使用了一个非常基本的低通滤波器,它通过一个alpha常量实现,并直接用于传感器的读取值。

这是我的代码:

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和magneticometerValues时,我将这段代码称为。

我的问题是倾斜手机时如何防止方位角发疯?

我在Google Play商店Compass上检查了一个免费应用程序,它尚未解决此问题,但我希望有解决方案。

我有2个解决方案:
  • 使AR View 仅在非常受限的俯仰角下工作,现在我有了pitch >= -5 && pitch <= 30之类的东西。如果未完全满足要求,则会显示一个屏幕,要求用户将手机旋转至纵向。
  • 以某种方式使用音高来抑制方位角,尽管这似乎是针对特定设备的漂亮解决方案,但是我当然愿意征求建议。

  • 我还可以补充一点,我一直在寻找一个体面的解决方案几个小时,但没有找到比2)更好的解决方案。

    提前致谢!

    最佳答案

    有关完整的代码,请参见https://github.com/hoananguyen/dsensor
    保持历史记录和平均值,我不知道对俯仰和横滚的正确解释,因此以下代码仅适用于方位角。

    类(class)成员

    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;
    }
    

    关于倾斜手机时,Android getOrientation方位角会受到污染,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17979238/

    10-09 22:54