#android #math #accelerometer
#Android #математика #акселерометр
Вопрос:
Используя только встроенный в телефон (Android) акселерометр, как я могу определить его скорость?
Я возился с математикой этого, но любая функция, которую я придумываю, имеет тенденцию приводить к экспоненциальному росту скорости. Я исхожу из предположения, что при запуске приложения телефон останавливается. Это определенно должно сделать возможным определение скорости (по крайней мере, приблизительно).
У меня также есть приличный опыт в физике и математике, поэтому у меня не должно возникнуть никаких трудностей с какими-либо концепциями здесь.
Как я должен это сделать?
Комментарии:
1. @Ignacio Что? Постоянное ускорение означает, что скорость увеличивается линейно.
2. У вас есть какое-либо рабочее решение, можете ли вы указать мне на это или поделиться кодом.
3. Привет, ты когда-нибудь думал закрыть этот вопрос?
4. В вашем телефоне используются датчики размером в половину горошины, которые стоят около 2 долларов и были изготовлены путем травления крошечных кусочков металла в форме грубых пружин и грузиков. Достаточно знать, в какую сторону вы держите телефон и встряхивается ли он. Из этого никогда не получится достойный пакет инерциальных датчиков. Поверьте мне, ошибки накапливаются так быстро, что это безнадежная проблема для решения. (Источник: я отвечал за встроенную прошивку для этого на телефоне Amazon Fire, когда работал в Amazon.)
5. Я только что нашел это превосходное видео, объясняющее, почему это сложно: youtube.com/watch?v=C7JQ7Rpwn2k#t=23m20s
Ответ №1:
Это действительно будет зависеть от того, каково ускорение и как долго. Небольшое, длительное ускорение можно измерить, но любое внезапное увеличение ускорения, за которым следует постоянная скорость, сделает ваши измерения довольно сложными и подверженными ошибкам.
Предполагая постоянное ускорение, формула чрезвычайно проста: a = (V1-V0) / t . Итак, зная время и ускорение и предполагая, что V0 = 0, тогда V1 = a * t
В более реальном мире у вас, вероятно, не будет постоянного ускорения, поэтому вам следует вычислять дельту V для каждого измерения и добавлять все эти изменения скорости, чтобы получить конечную скорость. Всегда учитывайте, что у вас не будет данных о непрерывном ускорении, поэтому это наиболее возможный способ (т. Е. реальные данные против интегральной математической теории).
В любом случае, даже в лучшем случае, вы получите очень высокую погрешность, поэтому я не рекомендую этот подход для любого приложения, которое действительно зависит от реальных скоростей.
Комментарии:
1. На случай, если никто не заметил, V1 = a * t!
Ответ №2:
Во-первых, вы должны удалить ускорение из-за силы тяжести из данных акселерометра. Тогда это просто вопрос интеграции ускорения, чтобы получить скорость. Не забывайте, что ускорение и скорость являются правильными векторами, а не скалярами, и что вам также придется отслеживать вращение телефона в пространстве, чтобы правильно определить ориентацию вектора ускорения относительно вычисленного вектора скорости.
Комментарии:
1. можете ли вы объяснить с точки зрения кодирования или указать на ссылку, по которой я могу получить более подробную информацию об этом.
2. Датчик TYPE_LINEAR_ACCELERATION даст вам ускорение с отфильтрованной силой тяжести, так что это приятно. TYPE_ROTATION_VECTOR задаст вам ориентацию устройства в виде кватерниона, который можно легко преобразовать в матрицу вращения 3×3. В каждом временном срезе используйте матрицу вращения, чтобы преобразовать ускорение в вектор в трехмерном пространстве. Интегрируйте это со временем, чтобы получить ускорение (другой вектор), и интегрируйте это , чтобы получить положение относительно начальной позиции. (Все это предполагает, что начальная скорость была равна нулю.) Затем отправляйтесь в паб и выпейте пинту пива, потому что с дешевыми датчиками все безнадежно.
Ответ №3:
Ничего другого не остается, как согласиться с разумными аргументами, выдвинутыми во всех замечательных ответах выше, однако, если вы прагматичный тип, как я, мне нужно придумать решение, которое как-то работает.
У меня возникла проблема, похожая на вашу, и я решил создать свое собственное решение, не найдя ничего онлайн. Мне нужен был только простой ввод «наклона» для управления игрой, поэтому это решение, вероятно, не подойдет для более сложных нужд, однако я решил поделиться им на случай, если другие будут искать что-то подобное.
ПРИМЕЧАНИЕ: Я вставил сюда весь свой код, и его можно свободно использовать для любых целей.
В основном, что я делаю в своем коде, это ищу датчик акселерометра. Если не найдено, обратная связь по наклону будет отключена. Если датчик акселерометра присутствует, я ищу датчик магнитного поля, и если он присутствует, я получаю рекомендуемый угол наклона, комбинируя данные акселерометра и магнитного поля.
public TiltSensor(Context c) {
man = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);
mag_sensor = man.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
acc_sensor = man.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
has_mag = man.registerListener(this, mag_sensor, delay);
has_acc = man.registerListener(this, acc_sensor, delay);
if (has_acc) {
tiltAvailble = true;
if (has_mag) {
Log.d("TiltCalc", "Using accelerometer compass.");
}
else {
Log.d("TiltCalc", "Using only accelerometer.");
}
}
else {
tiltAvailble = false;
Log.d("TiltCalc", "No acceptable hardware found, tilt not available.");
//No use in having listeners registered
pause();
}
}
Однако, если присутствовал только датчик акселерометра, я возвращаюсь к накоплению ускорения, которое непрерывно затухает (умножается на 0,99), чтобы устранить любой дрейф. Для моих простых потребностей в наклоне это отлично работает.
@Override
public void onSensorChanged(SensorEvent e) {
final float[] vals = e.values;
final int type = e.sensor.getType();
switch (type) {
case (Sensor.TYPE_ACCELEROMETER): {
needsRecalc = true;
if (!has_mag) {
System.arraycopy(accelerometer, 0, old_acc, 0, 3);
}
System.arraycopy(vals, 0, accelerometer, 0, 3);
if (!has_mag) {
for (int i = 0; i < 3; i ) {
//Accumulate changes
final float sensitivity = 0.08f;
dampened_acc[i] = (accelerometer[i] - old_acc[i]) * sensitivity;
//Even out drift over time
dampened_acc[i] *= 0.99;
}
}
}
break;
case (Sensor.TYPE_MAGNETIC_FIELD): {
needsRecalc = true;
System.arraycopy(vals, 0, magnetic_field, 0, 3);
}
break;
}
}
В заключение я просто повторю, что это, вероятно, никоим образом не «правильно», это просто работает как простой ввод в игру. Чтобы использовать этот код, я просто делаю что-то вроде следующего (да, магические константы плохие, mkay):
Ship ship = mShipLayer.getShip();
mTiltSensor.getTilt(vals);
float deltaY = -vals[1] * 2;//1 is the index of the axis we are after
float offset = ((deltaY - (deltaY / 1.5f)));
if (null != ship) {
ship.setOffset(offset);
}
Наслаждайся!
Ответ №4:
Интеграция ускорения для получения скорости является нестабильной проблемой, и ваша ошибка исчезнет примерно через пару секунд. Телефонные акселерометры также не очень точны, что не помогает, а некоторые из них не позволяют вам легко отличить наклон от перевода, и в этом случае у вас действительно проблемы.
Ответ №5:
Акселерометры в телефоне практически бесполезны для такой задачи. Вам нужны высокоточные акселерометры с очень низким дрейфом — то, что намного превосходит то, что вы найдете в телефоне. В лучшем случае вы можете получить полезные результаты в течение нескольких секунд, или, если очень повезет, в течение минуты или двух, после чего результаты становятся бессмысленными.
Кроме того, у вас должен быть трехосевой гироскоп, который вы использовали бы для интегрирования скорости в правильном направлении. В некоторых телефонах есть гироскопы, но они даже хуже акселерометров в том, что касается дрейфа и точности.
Одним из, возможно, полезных приложений было бы использовать акселерометры в сочетании с гироскопами или магнитным компасом для заполнения недостающих данных с GPS. Каждый раз, когда GPS выдает хорошее исправление, нужно сбрасывать начальные условия положения, скорости и ориентации, и акселерометры будут предоставлять данные до следующего действительного исправления GPS.
Комментарии:
1. Допустим, я хочу получить информацию о наклоне для управления игрой. В этом сценарии я смогу сделать много предположений. Например, я могу предположить, что пользователь держит устройство определенным образом. Нельзя ли было бы сгладить данные таким образом, чтобы внезапные изменения выделялись и становились полезными в качестве входных данных для игры?
Ответ №6:
Гравитация уничтожит все ваши измерения. Телефон при остановке испытывает высокое постоянное ускорение вверх (да, именно ВВЕРХ). Акселерометр не может отличить ускорение от силы тяжести (технически, это одно и то же), поэтому через несколько секунд он достигнет чрезвычайно высоких скоростей. Если вы никогда не наклоняете свой акселерометр даже слегка, вы можете просто вычесть постоянное гравитационное притяжение из оси z (или любой другой оси, направленной вверх / вниз), но это маловероятно.
В принципе, вы должны использовать сложную систему из гироскопа / магнитометра и акселерометра, чтобы вычислить точное направление силы тяжести, а затем вычесть ускорение.
Комментарии:
1. Sensor Fusion может отфильтровать это для вас. Просто используйте датчик TYPE_LINEAR_ACCELERATION.
Ответ №7:
v = интеграл (a)?
В целом, я бы подумал, что неточности в акселерометрах сделают это довольно сложным
Комментарии:
1. Зависит от типа неточностей. Вы могли бы откалибровать линейную ошибку, нет?
Ответ №8:
Если телефон находится в режиме ожидания, у вас нулевое ускорение, поэтому ваша скорость равна 0. Вероятно, вам следует найти данные о местоположении с помощью GPS и получить соответствующие временные выборки и вычислить расстояние скорости с течением времени.
Комментарии:
1. Да, скорость равна 0 «при запуске приложения». Я калибрую его с этого момента.
2. «Стоять на месте» на самом деле должно быть легко обнаружить. Если входные данные с акселерометра (используйте TYPE_LINEAR_ACCELERATION) очень постоянны, телефон, вероятно, не обрабатывается.