Android getOrientation Azimuth gets polluted when phone is tilted

后端 未结 1 1357
猫巷女王i
猫巷女王i 2020-11-29 08:01

I\'m having a really annoying problem with a AR view acting like a compass. So when I hold the phone in portrait (so that the screen is pointing to my face), then I call the

相关标签:
1条回答
  • 2020-11-29 08:37

    For complete code see https://github.com/hoananguyen/dsensor
    Keep a history and average out, I do not know the correct interpretation of pitch and roll so the following code is for azimuth only.

    Class members

    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;
    }
    
    0 讨论(0)
提交回复
热议问题