Как рассчитать вертикальное расстояние, пройденное Android телефоном при падении с руки? - PullRequest
1 голос
/ 31 марта 2020

Так что я использовал акселерометр для проверки, не падает ли телефон. Эта часть работает отлично. Я использовал приведенную ниже ссылку для вышеуказанной цели. https://github.com/altermarkive/experimental-fall-detector-android-app

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

Я получаю данные ускорения от датчика акселерометра, после чего я использовал приведенные ниже формулы для расчета пройденного расстояния.

1-й код, который я попробовал: -

    long curTime = System.currentTimeMillis();

    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        // sampling frequency f= 10Hz.
        if ((curTime - lastUpdate) > CHECK_INTERVAL) {

            long diffTime = (curTime - lastUpdate);
            lastUpdate = curTime;

            accel_values = event.values.clone();

            if (last_accel_values != null) {

                mAccelLast = mAccelCurrent;
                mAccelCurrent =(float)Math.sqrt(accel_values[0]* accel_values[0] + 
                          accel_values[1]*accel_values[1]
                        + accel_values[2]*accel_values[2]);

                Message msg = mHandler.obtainMessage(Constants.MESSAGE_CHANGED);
                Bundle bundle = new Bundle();
                bundle.putFloat(Constants.VALUE, mAccelCurrent);
                msg.setData(bundle);
                mHandler.sendMessage(msg);

                mWindow.add(mAccelCurrent);
                if (mWindow.isFull() && mWindow.isFallDetected()){
                    Log.w(TAG, "Fall detected by window class");
                    actime = curTime - diffTime;
                    velocity = actime * acceleration;
                    avgvelocity = velocity / 2;
                    height = avgvelocity * actime;
                    mWindow.clear();
                    msg = mHandler.obtainMessage(Constants.MESSAGE_EMERGENCY);
                    mHandler.sendMessage(msg);
                }
            }

            last_accel_values = accel_values.clone();
        }
    }

2-й код, который я попробовал: -

            final double alpha = 0.8;

            double gravity[] = new double[3], linear_acceleration[] = new double[3];
            // Isolate the force of gravity with the low-pass filter.
            gravity[0] = alpha * gravity[0] + (1 - alpha) * sensorEvent.values[0];
            gravity[1] = alpha * gravity[1] + (1 - alpha) * sensorEvent.values[1];
            gravity[2] = alpha * gravity[2] + (1 - alpha) * sensorEvent.values[2];
            double curr_gravity = gravity[0] + gravity[1] + gravity[2];

            // Remove the gravity contribution with the high-pass filter.
            linear_acceleration[0] = sensorEvent.values[0] - gravity[0];
            linear_acceleration[1] = sensorEvent.values[1] - gravity[1];
            linear_acceleration[2] = sensorEvent.values[2] - gravity[2];

            double curr_acc = linear_acceleration[0] + linear_acceleration[1] + linear_acceleration[2];

            long seconds = System.currentTimeMillis();
            double velocity = curr_acc * seconds;
            double init_vel = velocity / 2;

            double time = (velocity - init_vel) / curr_gravity;
            double height = (((seconds * 9.8)/2) - init_vel);

3-я формула, которую я попробовал: -

long curTime = System.currentTimeMillis ();

    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        // sampling frequency f= 10Hz.
        if ((curTime - lastUpdate) > CHECK_INTERVAL) {

            long diffTime = (curTime - lastUpdate);
            lastUpdate = curTime;

            accel_values = event.values.clone();

            if (last_accel_values != null) {

                mAccelLast = mAccelCurrent;
                mAccelCurrent =(float)Math.sqrt(accel_values[0]* accel_values[0] + 
                          accel_values[1]*accel_values[1]
                        + accel_values[2]*accel_values[2]);

                Message msg = mHandler.obtainMessage(Constants.MESSAGE_CHANGED);
                Bundle bundle = new Bundle();
                bundle.putFloat(Constants.VALUE, mAccelCurrent);
                msg.setData(bundle);
                mHandler.sendMessage(msg);

                mWindow.add(mAccelCurrent);
                if (mWindow.isFull() && mWindow.isFallDetected()){
                    Log.w(TAG, "Fall detected by window class");
                    actime = curTime - diffTime;
                    height = 0.5*9.8*actime*actime;
                    mWindow.clear();
                    msg = mHandler.obtainMessage(Constants.MESSAGE_EMERGENCY);
                    mHandler.sendMessage(msg);
                }
            }

            last_accel_values = accel_values.clone();
        }
    }

Я также пытался использовать другие датчики для той же цели, что и барометр, но я получаю от них тот же результат (высота не соответствует ожидаемой). Кроме того, я пытался искать сторонние SDK, но они также используют свое собственное оборудование. Любая помощь будет оценена. Кроме того, если кто-то может вести правильно, это было бы очень полезно. Заранее спасибо.

1 Ответ

0 голосов
/ 01 мая 2020

Кажется, у вас одна и та же ошибка во всех трех подходах. Во всех трех случаях вы в какой-то момент умножаете свое ускорение на абсолютную метку времени System.currentTimeMillis(). Это миллисекунды с 1970 года и не имеет прямого значения в вашей ситуации, если вы не используете его для вычисления временных интервалов как разностей. В некоторых примерах вы делаете это, но вы снова вычитаете его из System.currentTimeMillis(), что снова приводит к миллисекундам с 1970 года.

Похоже, вы пытаетесь реализовать s = 1/2 a t², но это действительно только для постоянного ускорения от покоя в течение интервала времени t. Если вы хотите получить расстояние из последовательности ускорений мер, вам нужно численно интегрировать их (это звучит сложнее, чем есть) и, возможно, вы хотите использовать некоторую фильтрацию.

Однако я рекомендую просто предположить, что свободное падение с ускорением 9,81 м / с². Это не учитывает аэродинамическое сопротивление или локальные изменения в ускорении Земли, но если вы не хотите использовать это в некоторых странных ситуациях, это, вероятно, будет гораздо более точным, чем использование показаний датчика. Особенно, когда телефон вращается, но также из-за плохой калибровки и некоторой фильтрации, чтобы отделить фактическое ускорение от гравитационного ускорения, я бы не ожидал, что показания датчика будут превосходить приближенные к идеальному свободному падению. В конце концов, смартфоны являются довольно плотными объектами и мало подвержены влиянию аэродинамического сопротивления.

Плюс в том, что вы можете просто использовать s = 1/2 a t². Просто убедитесь, что t - это не временной интервал с 1970 года, а интервал таймера от начала падения (который, как вы сказали, вы можете надежно обнаружить) до конца падения (т. Е. Разница отметки времени в начале и отметка времени в конце). Кроме того, я бы предложил использовать время от событий датчика вместо System.currentTimeMillis(), поскольку оно имеет лучшее разрешение и предназначено для расчетов такого типа.

...