Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/199.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何获得电话';s方位角与罗盘读数和陀螺仪读数?_Android_Sensors_Android Sensors_Gyroscope_Magnetometer - Fatal编程技术网

Android 如何获得电话';s方位角与罗盘读数和陀螺仪读数?

Android 如何获得电话';s方位角与罗盘读数和陀螺仪读数?,android,sensors,android-sensors,gyroscope,magnetometer,Android,Sensors,Android Sensors,Gyroscope,Magnetometer,我希望通过以下方法获取手机的当前方向: 首先通过getRotationMatrix()和getOrientation()获取初始方向(方位角) 将陀螺仪读数随时间的积分添加到其中,以获得当前方向 电话定位: 手机的x-y平面与地平面平行固定。i、 例如,处于“边走边发短信”的状态 “getOrientation()”退货: Android API允许我从getOrientation()轻松获取方向,即方位角、俯仰、滚动 请注意此方法始终返回其范围内的值:[0,-PI]和[o,PI] 我的问题:

我希望通过以下方法获取手机的当前方向:

  • 首先通过
    getRotationMatrix()
    getOrientation()
    获取初始方向(方位角)
  • 将陀螺仪读数随时间的积分添加到其中,以获得当前方向
  • 电话定位:

    手机的x-y平面与地平面平行固定。i、 例如,处于“边走边发短信”的状态

    getOrientation()
    ”退货:

    Android API允许我从
    getOrientation()
    轻松获取方向,即方位角、俯仰、滚动

    注意此方法始终返回其范围内的值:
    [0,-PI]
    [o,PI]

    我的问题:

    由于陀螺仪读数的积分(用
    dR
    表示)可能很大,因此当我做
    CurrentOrientation+=dR
    时,
    CurrentOrientation
    可能超过
    [0,-PI]
    范围

    需要进行哪些操作才能始终获得
    [0,-PI]
    [o,PI]
    范围内的当前方向?

    我在Python中尝试了以下内容,但我高度怀疑其正确性

    rotation = scipy.integrate.trapz(gyroSeries, timeSeries) # integration
    if (headingDirection - rotation) < -np.pi:
        headingDirection += 2 * np.pi
    elif (headingDirection - rotation) > np.pi:
        headingDirection -= 2 * np.pi
    # Complementary Filter
    headingDirection = ALPHA * (headingDirection - rotation) + (1 - ALPHA) * np.mean(azimuth[np.array(stepNo.tolist()) == i])
    if headingDirection < -np.pi:
        headingDirection += 2 * np.pi
    elif headingDirection > np.pi:
        headingDirection -= 2 * np.pi
    
    rotation=scipy.integrate.trapz(陀螺系列、时间系列)#集成
    如果(前进方向-旋转)<-np.pi:
    车头方向+=2*np.pi
    elif(前进方向-旋转)>np.pi:
    车头方向-=2*np.pi
    #互补滤波器
    航向=α*(航向-旋转)+(1-α)*np.平均值(方位角[np.阵列(stepNo.tolist())==i])
    如果车头方向<-np.pi:
    车头方向+=2*np.pi
    elif头向>np.pi:
    车头方向-=2*np.pi
    

    备注

    这并不是那么简单,因为它涉及到以下问题制造者:

  • 方向传感器读数从
    0
    -PI
    ,然后直接跳到
    +PI
    ,并通过
    +PI/2
    逐渐返回到
    0
  • 陀螺读数的集成也会导致一些问题。我应该向方向添加
    dR
    ,还是减去
    dR
  • 在给出确认答案之前,请先参考Android文档。

    估计答案不会有帮助

    方位传感器实际上从实际的磁强计和加速计中获取读数

    我想这可能是混乱的根源。文件中在哪里说明了这一点?更重要的是,文件中是否明确说明忽略了陀螺读数?据我所知,本视频中描述的方法是:

    该方法使用陀螺仪并整合其读数。这几乎使问题的其余部分变得毫无意义;不过,我会尽力回答


    方位传感器已经在为您整合陀螺仪读数,这就是您获得方位的方式。我不明白你为什么自己做这件事

    您没有正确集成陀螺仪读数,这比
    CurrentOrientation+=dR更复杂(这是不正确的)。如果您需要集成陀螺读数(我不明白为什么,SensorManager已经在为您进行集成),请阅读如何正确进行集成(方程式17)

    不要尝试与欧拉角积分(又称方位角、俯仰角、横滚角),不会有好结果

    请在计算中使用四元数或旋转矩阵,而不是欧拉角。如果使用旋转矩阵,则始终可以将其转换为Euler角度,请参见

    (对于四元数也是如此。)有两种方法(在非退根情况下)表示旋转,即,将得到两个欧拉角。选择所需范围内的一个。(如果存在,则有无限多个欧拉角,请参见上面的PDF)。只要保证在将旋转矩阵转换为欧拉角后,在计算中不再开始使用欧拉角

    现在还不清楚你在用互补滤波器做什么。你可以在手稿的基础上实现一个非常好的传感器融合,这基本上是一个教程。这不是小事,但我不认为你会找到一个更好的,更容易理解的教程比这篇手稿

    当我在这篇手稿的基础上实现传感器融合时,我必须要发现的一件事是,所谓的融合是可能发生的。我通过限定
    TotalCorrection
    (第27页)来处理它。如果你实施这种传感器融合,你就会明白我在说什么



    更新:我在这里回答您在接受答案后在评论中发布的问题

    我想指南针通过重力和磁场给了我当前的方位,对吗?罗盘中使用陀螺仪吗

    是的,如果手机至少静止半秒钟,你只需要使用重力和指南针就可以得到很好的方位估计。以下是如何做到这一点:

    不,罗盘中没有使用陀螺仪

    你能解释一下为什么我做的整合是错误的吗?我知道如果我的手机的俯仰点向上,欧拉角就会失效。但是我的集成还有什么问题吗

    有两件不相关的事情:(i)积分应该以不同的方式进行,(ii)欧拉角是一个麻烦,因为万向锁。我再说一遍,这两个是不相关的

    至于
    public class Compass  implements SensorEventListener
    {
        public static final float TWENTY_FIVE_DEGREE_IN_RADIAN = 0.436332313f;
        public static final float ONE_FIFTY_FIVE_DEGREE_IN_RADIAN = 2.7052603f;
    
        private SensorManager mSensorManager;
        private float[] mGravity;
        private float[] mMagnetic;
        // If the device is flat mOrientation[0] = azimuth, mOrientation[1] = pitch
        // and mOrientation[2] = roll, otherwise mOrientation[0] is equal to Float.NAN
        private float[] mOrientation = new float[3];
        private LinkedList<Float> mCompassHist = new LinkedList<Float>();
        private float[] mCompassHistSum = new float[]{0.0f, 0.0f};
        private int mHistoryMaxLength;
    
        public Compass(Context context)
        {
             mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
             // Adjust the history length to fit your need, the faster the sensor rate
             // the larger value is needed for stable result.
             mHistoryMaxLength = 20;
        }
    
        public void registerListener(int sensorRate)
        {
            Sensor magneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
            if (magneticSensor != null)
            {
                mSensorManager.registerListener(this, magneticSensor, sensorRate);
            }
            Sensor gravitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
            if (gravitySensor != null)
            {
                mSensorManager.registerListener(this, gravitySensor, sensorRate);
            }
        }
    
        public void unregisterListener()
        {
             mSensorManager.unregisterListener(this);
        }
    
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy)
        {
    
        }
    
        @Override
        public void onSensorChanged(SensorEvent event)
        {
            if (event.sensor.getType() == Sensor.TYPE_GRAVITY)
            {
                mGravity = event.values.clone();
            }
            else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
            {
                mMagnetic = event.values.clone();
            }
            if (!(mGravity == null || mMagnetic == null))
            {
                mOrientation = getOrientation();
            } 
        }
    
        private void getOrientation()
        {
            float[] rotMatrix = new float[9];
            if (SensorManager.getRotationMatrix(rotMatrix, null, 
                mGravity, mMagnetic))
            {
                float inclination = (float) Math.acos(rotMatrix[8]);
                // device is flat
                if (inclination < TWENTY_FIVE_DEGREE_IN_RADIAN 
                    || inclination > ONE_FIFTY_FIVE_DEGREE_IN_RADIAN)
                {
                    float[] orientation = sensorManager.getOrientation(rotMatrix, mOrientation);
                    mCompassHist.add(orientation[0]);
                    mOrientation[0] = averageAngle();
                }
                else
                {
                    mOrientation[0] = Float.NAN;
                    clearCompassHist();
                }
            }
        }
    
        private void clearCompassHist()
        {
            mCompassHistSum[0] = 0;
            mCompassHistSum[1] = 0;
            mCompassHist.clear();
        }
    
        public float averageAngle()
        {
            int totalTerms = mCompassHist.size();
            if (totalTerms > mHistoryMaxLength)
            {
                float firstTerm = mCompassHist.removeFirst();
                mCompassHistSum[0] -= Math.sin(firstTerm);
                mCompassHistSum[1] -= Math.cos(firstTerm);
                totalTerms -= 1;
            }
            float lastTerm = mCompassHist.getLast();
            mCompassHistSum[0] += Math.sin(lastTerm);
            mCompassHistSum[1] += Math.cos(lastTerm);
            float angle = (float) Math.atan2(mCompassHistSum[0] / totalTerms, mCompassHistSum[1] / totalTerms);
    
            return angle;
        }
    }
    
    private Compass mCompass;
    
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
    
        mCompass = new Compass(this);
    }
    
    @Override
    protected void onPause()
    {
        super.onPause();
    
        mCompass.unregisterListener();
    }
    
    @Override
    protected void onResume()
    {
        super.onResume();
    
        mCompass.registerListener(SensorManager.SENSOR_DELAY_NORMAL);
    }
    
    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        switch (sensorEvent.sensor.getType()) {
            case Sensor.TYPE_ACCELEROMETER:
                mAccValues[0] = sensorEvent.values[0];
                mAccValues[1] = sensorEvent.values[1];
                mAccValues[2] = sensorEvent.values[2];
                break;
            case Sensor.TYPE_MAGNETIC_FIELD:
                mMagValues[0] = sensorEvent.values[0];
                mMagValues[1] = sensorEvent.values[1];
                mMagValues[2] = sensorEvent.values[2];
                break;
        }
    
    }
    
        private void updateData() {
        SensorManager.getRotationMatrix(mR, mI, mAccValues, mMagValues);
    
        /**
         * arg 2: what world(according to app) axis , device's x axis aligns with
         * arg 3: what world(according to app) axis , device's y axis aligns with
         * world x = app's x = app's east
         * world y = app's y = app's north
         * device x = device's left side = device's east
         * device y = device's top side  = device's north
         */
    
        switch (mDispRotation) {
            case Surface.ROTATION_90:
                SensorManager.remapCoordinateSystem(mR, SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_X, mR2);
                break;
            case Surface.ROTATION_270:
                SensorManager.remapCoordinateSystem(mR, SensorManager.AXIS_MINUS_Y, SensorManager.AXIS_X, mR2);
                break;
            case Surface.ROTATION_180:
                SensorManager.remapCoordinateSystem(mR, SensorManager.AXIS_MINUS_X, SensorManager.AXIS_MINUS_Y, mR2);
                break;
            case Surface.ROTATION_0:
            default:
                mR2 = mR;
        }
    
        SensorManager.getOrientation(mR2, mO);
    
    
        //--upside down when abs roll > 90--
        if (Math.abs(mO[2]) > PI_BY_TWO) {
            //--fix, azimuth always to true north, even when device upside down, realistic --
            mO[0] = -mO[0];
    
            //--fix, roll never upside down, even when device upside down, unrealistic --
            //mO[2] = mO[2] > 0 ? PI - mO[2] : - (PI - Math.abs(mO[2]));
    
            //--fix, pitch comes from opposite , when device goes upside down, realistic --
            mO[1] = -mO[1];
        }
    
        CircleUtils.convertRadToDegrees(mO, mOut);
        CircleUtils.normalize(mOut);
    
        //--write--
        mResults[0] = mOut[0];
        mResults[1] = mOut[1];
        mResults[2] = mOut[2];
    }