如何让设备倾斜?

时间:2014-06-16 11:46:01

标签: android rotation sensor android-sensors sensor-fusion

我试图让设备倾斜(设备沿y轴旋转但不幸的是我无法实现我的目标。我尝试了很多东西使用TYPE_ACCELEROMETER和TYPE_MAGNETIC_FIELD作为组合传感器(传感器融合)。我也有跟着Motion Sensors

我想要什么?

我希望获得附在车辆上的设备(手机)的倾向。比方说,我将一个设备安装在汽车中,汽车静止不动。因此倾斜度为0度。当车辆通过通行证或天桥时,倾斜度应相应。 我试过计算一​​下,这是我的代码:

...
...
    private static float ALPHA = 0.005f
    TextView tv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        tv = (TextView) findViewById(R.id.tv);
        edtAlpha = (EditText) findViewById(R.id.alpha);
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        accelerometer = mSensorManager
                .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        magnetometer = mSensorManager
                .getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        if (accelerometer == null) {
            Toast.makeText(this, "Oh  not found", Toast.LENGTH_SHORT).show();
        }
        if (magnetometer == null) {
            Toast.makeText(this, "Oh magnetometer not found",
                    Toast.LENGTH_SHORT).show();
        }

    }

    protected float[] lowPass(float[] input, float[] output) {
        if (output == null)
            return input;
        String s = edtAlpha.getText().toString();
        if (s != null && s.length() > 0) {
            try {
                ALPHA = Float.valueOf(s);
            } catch (NumberFormatException e) {
                ALPHA = 0.005f;
            }
        } else {
            ALPHA = 0.005f;
        }
        for (int i = 0; i < input.length; i++) {
            output[i] = output[i] + ALPHA * (input[i] - output[i]);
        }
        return output;
    }

    public int getRotation(final Activity activity) {
        int result = 1;
        Method mDefaultDisplay_getRotation;
        try {
            mDefaultDisplay_getRotation = Display.class.getMethod(
                    "getRotation", new Class[] {});
            Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
                    .getDefaultDisplay();

            Object retObj = mDefaultDisplay_getRotation.invoke(display);
            if (retObj != null) {
                result = (Integer) retObj;
            }
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return result;
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        Log.d(tag, "onSensorChanged");

        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            gravSensorVals = lowPass(event.values.clone(), gravSensorVals);

        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            magSensorVals = lowPass(event.values.clone(), magSensorVals);
        }

        if (gravSensorVals != null && magSensorVals != null) {
            SensorManager.getRotationMatrix(RTmp, I, gravSensorVals,
                    magSensorVals);

            int rotation = getRotation(this);

            if (rotation == 1) {
                SensorManager.remapCoordinateSystem(RTmp, SensorManager.AXIS_X,
                        SensorManager.AXIS_MINUS_Z, Rot);
            } else {
                SensorManager.remapCoordinateSystem(RTmp, SensorManager.AXIS_Y,
                        SensorManager.AXIS_MINUS_Z, Rot);
            }

            SensorManager.getOrientation(Rot, results);

            float azimuth = (float) (((results[0] * 180) / Math.PI) + 180);
            float pitch = (float) (((results[1] * 180 / Math.PI)) + 90);
            float roll = (float) (((results[2] * 180 / Math.PI)));

            tv.setText("Azimuth : " + df.format(azimuth) + "\nPitch : "
                    + df.format(pitch) + "\nRoll : " + df.format(roll));
        }

        Log.d(tag, "Sensor type : " + event.sensor.getType());

    }

    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(this, accelerometer,
                SensorManager.SENSOR_DELAY_UI);
        mSensorManager.registerListener(this, magnetometer,
                SensorManager.SENSOR_DELAY_UI);
    }
...
...

我的代码有什么问题?

当我快速加速/减速我的汽车时,角度会快速增加/减少但不应该。换句话说,当我加速/减速车辆时,不应该对角度产生任何影响。 我也尝试过这些教程: Link 1 Link 2等。

2 个答案:

答案 0 :(得分:2)

首先,您应该避免直接使用加速度计或磁力计数据,除非您真正了解其含义以及从这些传感器接收的数据。

我个人建议您使用预定义的ROTATION_VECTOR传感器,它将卡路里滤波器中的加速度计,磁力计和陀螺仪融合在一起。 (参见this如何从ROTATION_VECTOR传感器获取数据和this如何使用数据。

当您从this项目开始时,您可以访问四元数并使用旋转矩阵并使用旋转矩阵并应用相应的conversion来获取设备的euler角度(名称)并不总是一致,但你很可能对银行或态度感兴趣)。 最后一句话:请注意,euler-angle受gimbal lock(又名。&#34;跳跃&#34;值)的影响。

答案 1 :(得分:0)

只要您使用加速计和磁力计而不使用陀螺仪,当设备经历快速加速/减速时,您的方法将失败。你可以尝试过于聪明,并做一些特别的黑客攻击,这似乎可以排除你发现的这种特殊的失败模式,但我甚至都不会尝试。

真正的解决方案是使用陀螺仪。根据我的经验,这很有效。

TYPE_ROTATION_VECTOR有什么问题?