Как я могу наклонить устройство?

Я пытаюсь получить наклон устройства (вращение устройства по оси Y, но, к сожалению, я не могу достичь своей цели. Я пробовал много вещей, используя TYPE_ACCELEROMETER и TYPE_MAGNETIC_FIELD в качестве комбинированного датчика (Sensor fusion). Я также следил за Датчики движения

Чего я хочу?

я хочу получить наклон устройства (мобильного телефона), прикрепленного к транспортному средству. Допустим, я прикрепил устройство к машине, а машина стоит. Таким образом, наклон равен 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);
    }
...
...

Что не так с моим кодом?

Когда я быстро разгоняю/сбрасываю скорость своей машины, угол быстро увеличивается/уменьшается, но этого не должно быть. Другими словами, когда я разгоняю/сбрасываю скорость автомобиля, не должно быть никакого влияния на угол. Я также пытался следовать этим руководствам: Ссылка 1 Ссылка 2 и т. д.


person Mohammad Imran    schedule 16.06.2014    source источник


Ответы (2)


Прежде всего, вам следует избегать прямого использования данных акселерометра или магнитометра, если вы ДЕЙСТВИТЕЛЬНО не знаете, каковы последствия и какие данные вы получаете от этих датчиков.

Я лично рекомендую вам использовать предопределенный датчик ROTATION_VECTOR, который объединяет акселерометр, магнитометр и гироскоп в фильтре Калмана. (см. ">это способ получения данных с датчика ROTATION_VECTOR и это как использовать данные).

Когда вы начинаете с этого проекта, вы можете просто получить доступ к кватерниону и поиграть с или с матрицей вращения и примените соответствующее преобразование к получите углы Эйлера вашего устройства (названия не всегда совпадают, но вас, вполне вероятно, интересует крен или отношение). Последнее замечание: обратите внимание, что углы Эйлера страдают от and-or-quaternions-f">gimbal lock (иначе "прыгающие" значения).

person Alexander Pacha    schedule 18.06.2014
comment
Сначала спасибо за ответ на мой вопрос. Я использовал ваш код в своем примере приложения. Я использовал ImprovedOrientationSensor1Provider и ImprovedOrientationSensor2Provider из вашего кода (включая необходимые классы). Но я получаю переменные результаты (угол), даже если мое устройство (LG-Nexus 4) неподвижно лежит на столе. Вот как я использую ваш код: Quaternion q = currentOrientationProvider.getQuaternion(); угол плавания = (плавающий) (2.0f * Math.acos(q.getW()) * 180.0f / Math.PI); Log.d(угол, String.valueOf(угол)); Не могли бы вы сказать мне, что я делаю неправильно? - person Mohammad Imran; 20.06.2014
comment
Вот результат: 132,06401, 132,06432, 132,06334, 132,06345, 132,06252, 132,06252, 132,06168, 132,06107, 132,06134, 132,06215, 132,06207, 132,06268, 132,06332, 132,06416, 132,06346, 132,06425, 132,06326, 132,06314, 227,93698, 227,93661, 227,9361, 227,93614, 227,93663, 227.93794, 227.93794, 227.93845, 227.9378, 132.06181, 227.93822, 227.93892, 132.06259, 204.06075, 204.06076, 204.06076, 204.06076, 204.06076, 204.06078, 225.64037, 225.64124, 225.64375 - person Mohammad Imran; 20.06.2014

Пока вы используете акселерометр и магнитометр, но не гироскопы, ваш метод не сработает, когда устройство будет быстро ускоряться/замедляться. Вы можете попытаться быть слишком умным и сделать какой-нибудь специальный хак, который может показаться исключающим этот конкретный режим отказа, который вы обнаружили, но я бы даже не стал пытаться это делать.

Истинное решение состоит в том, чтобы также использовать гироскопы. По моему опыту, это работает очень хорошо.

Что не так с TYPE_ROTATION_VECTOR?

person Ali    schedule 16.06.2014
comment
Спасибо, Али, гироскоп дает только изменение. Он не обеспечивает непрерывное изменение, например. транспортное средство движется через подземный переход, тогда гироскоп даст вам внезапное изменение значения. Кроме того, большинство устройств не имеют гироскопа. ROTATION_VACTOR : ROTATION_VACTOR связан с вращением устройства. Будет ли какое-либо влияние на датчик вращения разгона/замедления? Думаю, это будет иметь такой же эффект - person Mohammad Imran; 17.06.2014
comment
@MohammadImran Пожалуйста, перечитайте мой ответ. Я говорю, что вы должны использовать гироскопы также. Так что используйте акселерометр и магнитометр, как и раньше, но дополните их гироскопами. Это единственный способ получить надежную ориентацию. Да, ускорение и торможение будут незначительно влиять на результаты, надеюсь, вы даже не заметите этого благодаря гироскопам. Итак, в целом, я говорю, что следует использовать датчик ориентации (который предположительно использует акселерометр, магнитометр и гироскопы). - person Ali; 17.06.2014
comment
Еще раз спасибо. Не могли бы вы показать здесь пример кода в своем ответе? очень ценю ваш ответ. - person Mohammad Imran; 17.06.2014
comment
@MohammadImran Нет, я сам не программирую для Android. Я реализовал слияние датчиков и отслеживание ориентации на C++ на платформе Shimmer2. Однако я не знаком с Android API. Суть, которую я пытаюсь подчеркнуть в своем ответе: мне понадобится устройство с гироскопами, а вам нужно будет использовать датчик ориентации; затем, в зависимости от вашего определения наклона, вы можете вывести математическую формулу наклона. - person Ali; 17.06.2014
comment
Не могли бы вы поделиться математическими формулами здесь? - person Mohammad Imran; 17.06.2014
comment
@MohammadImran Пожалуйста, перечитайте мой предыдущий комментарий. Как я уже писал: в зависимости от вашего определения наклона вы можете вывести математическую формулу для наклона. Я не знаю, как вы определили наклон в своем приложении, поэтому я не могу дать вам точное определение наклона. формула. - person Ali; 17.06.2014
comment
Давайте продолжим обсуждение в чате. - person Mohammad Imran; 18.06.2014