• 0
Bob32

Ориентация на Север и углы наклона телефона

Вопросы

Добрый день, Друзья!

Имеем Delphi 10.3 Community Edition

Пытаюсь с помощью компонент TOrientationSensor и TMotionSensor получить три адекватных угла - азимут на Север, и два угла наклона телефона.


Действую так :

(алгоритм и теорию взял отсюда https://cache.freescale.com/files/sensors/doc/app_note/AN4248.pdf )


1) получаю данные акселерометра .
Gx:=MotionSensor1.Sensor.AccelerationX;
Gy:=MotionSensor1.Sensor.AccelerationY;
Gz:=MotionSensor1.Sensor.AccelerationZ;
2) получаю данный вектора магнитной индукции
Bx:=OrientationSensor1.Sensor.HeadingX;
By:=OrientationSensor1.Sensor.HeadingY;
Bz:=OrientationSensor1.Sensor.HeadingZ;

далее по формулам из ссылки рассчитываю эти углы. Все получается, но есть такая проблема:
- Углы скачут, нет плавности, стоит пошатать немного телефон и получаешь разброс по 20..30 градусов.
Это жутко контрастирует с плавностью хода, которые демонстрируют другие приложения, например компаса, на ПлейМаркете.

Ставил в качестве теста apk-шку приложения под андроид, которое использует два метода -
GetRotationMatrix и GetOrientation - работает офигенно плавно.
Но алгоритм, исползуемый в этих методах неизвестен.

ВОПРОС: решали ли кто-то адекватно эту задачу под Дельфи? как ? может как-то можно из среды Дельфи вызывать эти методы (GetRotationMatrix и GetOrientation)?

Близок к отчаянию - вторую неделю бьюсь (
Буду признателен за любой дельный совет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

26 ответов на этот вопрос

  • 0

А если использовать апроксимацию значений? Разброс должен уменьшиться

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

а я уже делаю среднее арифметическое последних 6 значений  - все равно плохо.

по всей видимости, эти методы, о которых я упомянул (getrotationmatrix и getorientation), используют математику похлеще - что то типа фильтров Калмана и Маджвика. я их сам не закодирую - они замороченные. есть код одного из них на cpp. Можно ли как-то из него сделать что-то типа модуля и вызвать из Дельфи?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

График значений для начала постройте, оцените разброс значений. Возможно всё не так плохо

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
21 час назад, Alexander сказал:

График значений для начала постройте, оцените разброс значений. Возможно всё не так плохо

плохо. это видно при отрисовке компонентов дополненной реальности, который я рисую. они скачут, нет плавности.

здесь именно задача на сглаживание этих показателей. но не средним арифметическим а каким нить фильтром, например Калмана.

Просто - это изобретение велосипеда. методы getrotationmatrix и getorientation из Андроид Студио делают нечто подобное в "стандартной комплектации", без самописных огородов.

Может в Дельфи есть что-то подобное..... или какой-то простой воркэраунд.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 05.03.2019 в 01:42, Bob32 сказал:

плохо. это видно при отрисовке компонентов дополненной реальности, который я рисую. они скачут, нет плавности.

здесь именно задача на сглаживание этих показателей. но не средним арифметическим а каким нить фильтром, например Калмана.

Просто - это изобретение велосипеда. методы getrotationmatrix и getorientation из Андроид Студио делают нечто подобное в "стандартной комплектации", без самописных огородов.

Может в Дельфи есть что-то подобное..... или какой-то простой воркэраунд.

А в чем проблема использовать getOrientationMatrix SensorManager'a? Обертки есть от FMXExpress к примеру, или самому можно перевести.

Может если время сегодня хватит - набросаю проект и скину

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
4 часа назад, mazayhin сказал:

А в чем проблема использовать getOrientationMatrix SensorManager'a? Обертки есть от FMXExpress к примеру, или самому можно перевести.

Может если время сегодня хватит - набросаю проект и скину

а как это сделать? Подскажете?

Да, я видел на примере других приложений, написанных под андроид-студио, что getRotationMantrix + getOrientation дает необходимый эффект. но как их вызывать из Дельфи?

я в прошлом был Дельфи-программист (лет 10 назад). а сейчас FMX и фич Андроида не знаю ( вот, осваиваю методом проб и ошибок. 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
15 минут назад, Bob32 сказал:

а как это сделать? Подскажете?

Да, я видел на примере других приложений, написанных под андроид-студио, что getRotationMantrix + getOrientation дает необходимый эффект. но как их вызывать из Дельфи?

я в прошлом был Дельфи-программист (лет 10 назад). а сейчас FMX и фич Андроида не знаю ( вот, осваиваю методом проб и ошибок. 

 

Не успел сегодня.

В общем, необходимо создать обертку для андроидовского system.hardware.SensorManager. и через нее уже работать.

Получить интерфейс JSensorManager, вызвать registerListner для обоих сенсоров (листнер надо описать как клас ... = class (IJavaLocsl, JSensorEventListner), вроде так, пишу с телефона), его процедура по событию системы и будет вызываться. Ну а там, собственно уже, TJavaSensorManager.JavaClass.getRotationMatrix(R, nil, A, G)

.getOrientation(R, O)

Все переменные это TJavaArray<single>, размер у R: 16, остальные 3

В общем, работы совсем ничего. Хотите-попробуйте посмотреть и разобраться, ну или завтра будет пример с простейшей оберткой, на нем и посмотрите.

Изменено пользователем mazayhin

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
6 часов назад, mazayhin сказал:

Не успел сегодня.

В общем, необходимо создать обертку для андроидовского system.hardware.SensorManager. и через нее уже работать.

Получить интерфейс JSensorManager, вызвать registerListner для обоих сенсоров (листнер надо описать как клас ... = class (IJavaLocsl, JSensorEventListner), вроде так, пишу с телефона), его процедура по событию системы и будет вызываться. Ну а там, собственно уже, TJavaSensorManager.JavaClass.getRotationMatrix(R, nil, A, G)

.getOrientation(R, O)

Все переменные это TJavaArray<single>, размер у R: 16, остальные 3

В общем, работы совсем ничего. Хотите-попробуйте посмотреть и разобраться, ну или завтра будет пример с простейшей оберткой, на нем и посмотрите.

сложновато это пока для меня. подожду завтрашнего дня )

спасибо огромное!!!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 1
13 часов назад, Bob32 сказал:

сложновато это пока для меня. подожду завтрашнего дня )

спасибо огромное!!!!!

Все на скорую руку. Никаких проверок не делал. Вообще, за основу брал статью с хабра https://habr.com/ru/post/137820/

Так же учтите, что необходимо проверить наличие магнитного датчика, т.к. без него getRotationMatrix всегда будет возвращать false, т.о. не получится определить положение устройства. Так же, еще, getOrientation вернет неправильные значения при повороте телефона, для этого надо определять текущую ориентацию экрана, и на основании этого делать remapCoordinateSystem, и только после этого уже определять положение.

Смотрите, принцип понятен.

Обертки взял от FMXExpress, немного подчистил, что бы не тянуть лишнего.

Если будете брать сами, то обратите внимание:

android.hardware.SensorManager:

надо изменить JavaSignature на [JavaSignature('android/hardware/SensorManager')] для интерфейса JSensorManager (убрать $ и что после него, иначе, EJNIFatal)

android.hardware.SensorEventListener:

неправильно унаследованы интерфейсы (от JObject), а так как SensorEventListener это интерфейс, наследуемся от IJavaClass и IJavaInstance соответственно.

 

SensorManager.zip

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
1 минуту назад, mazayhin сказал:

Все на скорую руку. Никаких проверок не делал. Вообще, за основу брал статью с хабра https://habr.com/ru/post/137820/

Так же учтите, что необходимо проверить наличие магнитного датчика, т.к. без него getRotationMatrix всегда будет возвращать false, т.о. не получится определить положение устройства. Так же, еще, getOrientation вернет неправильные значения при повороте телефона, для этого надо определять текущую ориентацию экрана, и на основании этого делать remapCoordinateSystem, и только после этого уже определять положение.

Смотрите, принцип понятен.

Обертки взял от FMXExpress, немного подчистил, что бы не тянуть лишнего.

Если будете брать сами, то обратите внимание:

android.hardware.SensorManager:

надо изменить JavaSignature на [JavaSignature('android/hardware/SensorManager')] для интерфейса JSensorManager (убрать $ и что после него, иначе, EJNIFatal)

android.hardware.SensorEventListener:

неправильно унаследованы интерфейсы (от JObject), а так как SensorEventListener это интерфейс, наследуемся от IJavaClass и IJavaInstance соответственно.

 

SensorManager.zip

Спасибо огромное! Сейчас буду изучать.

если что - можно будет Вам голосом вопрос задать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
2 минуты назад, Bob32 сказал:

Спасибо огромное! Сейчас буду изучать.

если что - можно будет Вам голосом вопрос задать?

Наверное можно, если смогу - подскажу.

Ну и по итогам, хорошо, если б вы все привели это в нормальный вид, и выложили готовое решение на форум.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
4 часа назад, mazayhin сказал:

Наверное можно, если смогу - подскажу.

Ну и по итогам, хорошо, если б вы все привели это в нормальный вид, и выложили готовое решение на форум.

конечно выложу, если ума хватит ))))

откомпилировал Ваше приложение = все работает, получаем данные акселерометра, магнитного датчика и углы (их я перевел в градусы для большей наглядности).

но тут наступает вот какой момент (возможно, Вы именно о нем писали, когда упоминали об ориентации экрана)…

когда телефон горизонтально (смотришь на экран сверху) - четко видно, что в первом углу = Азимут на север, который меняется от -180 до +180. 0 - север.

когда поднимаешь телефон вертикально (смотришь на телефон сбоку) - этот угол  "едет" - те он начинает показывать что-то, но не азимут на север.

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

Вы об этом говорили, когда писали про "ориентацию экрана" или имели ввиду что-то другое?

Изменено пользователем Bob32

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
Только что, Bob32 сказал:

конечно выложу, если ума хватит ))))

откомпилировал Ваше приложение = все работает, получаем данные акселерометра, магнитного датчика и углы (их я перевел в градусы для большей наглядности).

но тут наступает вот какой момент (возможно, Вы именно о нем писали, когда упоминали об ориентации экрана)…

когда телефон горизонтально (смотришь на экран сверху) - четко видно, что в первом углу = Азимут на север, который меняется от -180 до +180. 0 - север.

когда поднимаешь телефон вертикально (смотришь на телефон сбоку) - этот угол  "едет" - те он начинает показывать что-то, но не азимут на север.

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

Вы об этом говорили, когда писали про "ориентацию экрана" или имели ввиду что-то другое?

если что- мой номер +7 9162070089

Да, все верно, именно об этом и писал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
11 минут назад, mazayhin сказал:

Да, все верно, именно об этом и писал.

 а как этот remapCoordinateSystem вызывать?

сорри - это для вас "простая обертка" - я на Дельфи 2.0 15 лет назад программировал.

Все эти "андроидовские штучки" не знаю. если книжку или ссылку путевую про это посоветуете - буду также крайне признателен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 1
9 минут назад, Bob32 сказал:

 а как этот remapCoordinateSystem вызывать?

сорри - это для вас "простая обертка" - я на Дельфи 2.0 15 лет назад программировал.

Все эти "андроидовские штучки" не знаю. если книжку или ссылку путевую про это посоветуете - буду также крайне признателен.

После получения матрицы, определяете поворот устройства через IFMXScreenService.GetScreenOrientation к примеру, или опять же, напрямую через api.

Получаете углы (var x, y: integer; OutMatrix: TJavaArray<single>(16)):

0: ничего не делаем, в т.ч. ремап

90: X := TJSensorManager.JavaClass.AXIS_Y; Y := TJSensorManager.JavaClass.AXIS_MINUS_X;

180: X := TJSensorManager.JavaClass.AXIS_X; Y := TJSensorManager.JavaClass.AXIS_MINUS_Y;

270: X := TJSensorManager.JavaClass.AXIS_MINUS_Y; Y := TJSensorManager.JavaClass.AXIS_X;

TJSensorManager.JavaClass.remapCoordinateSystem(FMatrix(изначальная матрица), x, y, OutMatrix)

TJSensorManager.JavaClass.getOrientation(OutMatrix, FOrientation)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
21 минуту назад, mazayhin сказал:

После получения матрицы, определяете поворот устройства через IFMXScreenService.GetScreenOrientation к примеру, или опять же, напрямую через api.

Получаете углы (var x, y: integer; OutMatrix: TJavaArray<single>(16)):

0: ничего не делаем, в т.ч. ремап

90: X := TJSensorManager.JavaClass.AXIS_Y; Y := TJSensorManager.JavaClass.AXIS_MINUS_X;

180: X := TJSensorManager.JavaClass.AXIS_X; Y := TJSensorManager.JavaClass.AXIS_MINUS_Y;

270: X := TJSensorManager.JavaClass.AXIS_MINUS_Y; Y := TJSensorManager.JavaClass.AXIS_X;

TJSensorManager.JavaClass.remapCoordinateSystem(FMatrix(изначальная матрица), x, y, OutMatrix)

TJSensorManager.JavaClass.getOrientation(OutMatrix, FOrientation)

СПАСИБО! )

а "получаете углы" - имеется ввиду углы наклона телефона из IFMXScreenService.GetScreenOrientation - верно?

те - этот код нужно вставить между getRotationMatrix и getOrientation

и getOrientation передавать OutMatrix вместо FMatrix, как сейчас. так?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
3 минуты назад, Bob32 сказал:

СПАСИБО! )

а "получаете углы" - имеется ввиду углы наклона телефона из IFMXScreenService.GetScreenOrientation - верно?

те - этот код нужно вставить между getRotationMatrix и getOrientation

и getOrientation передавать OutMatrix вместо FMatrix, как сейчас. так?

Немного не то имел ввиду.

GetScreenOrientation не даст никаких углов, он укажет, грубо говоря, куда направлен верх телефона (где камера). Portrait = 0градусов, вверх.

remapCoordinateSystem нужен как раз для того, что бы пересчитать матрицу в соответствии с изменившимся положением устройства на осях (верно ведь?).

Если оси не изменились, смысла в лишней работе телефона нет, ровно как и в создании OutMatrix (его надо обязательно создать и задать размер).

Как поступить - решать вам. Или считать дополнительно каждый раз, или только по необходимости.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Посмотрите про RotationMatrix в https://developer.android.com/reference/android/hardware/SensorManager.html#getRotationMatrix(float[], float[], float[], float[])

Там описано, что это и откуда "берется"

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
4 минуты назад, mazayhin сказал:

Немного не то имел ввиду.

GetScreenOrientation не даст никаких углов, он укажет, грубо говоря, куда направлен верх телефона (где камера). Portrait = 0градусов, вверх.

remapCoordinateSystem нужен как раз для того, что бы пересчитать матрицу в соответствии с изменившимся положением устройства на осях (верно ведь?).

Если оси не изменились, смысла в лишней работе телефона нет, ровно как и в создании OutMatrix (его надо обязательно создать и задать размер).

Как поступить - решать вам. Или считать дополнительно каждый раз, или только по необходимости.

я все так и понял )

еще вопрос - хелп пишет, что состояния InvertedPortrait и InvertedLandscape - under IOS. 

типа что под андроидом будет только Portrait и Landscape

вы пробовали под андроидом с ними работать - они будут "срабатывать"?

(это у нас 180 и 270)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
3 минуты назад, Bob32 сказал:

я все так и понял )

еще вопрос - хелп пишет, что состояния InvertedPortrait и InvertedLandscape - under IOS. 

типа что под андроидом будет только Portrait и Landscape

вы пробовали под андроидом с ними работать - они будут "срабатывать"?

(это у нас 180 и 270)

Вот этого не скажу. Можно попробовать и посмотреть. Если не даст то уже из api брать

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

через Api можно сделать, к примеру, так:

var JObj: JObject; WindowManager: JWindowManager;
    Rotation: Integer;
begin
  JObj := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.WINDOW_SERVICE);
  WindowManager := TJWindowManager.Wrap((JObj as ILocalObject).GetObjectID);
  Rotation := WindowManager.getDefaultDisplay.getRotation;
  if Rotation = TJSurface.JavaClass.ROTATION_180 then
  begin

  end else
  if Rotation = TJSurface.JavaClass.ROTATION_270 then
  begin

  end else
  if Rotation = TJSurface.JavaClass.ROTATION_90 then
  begin

  end;

Подключать ничего не надо, Androidapi.JNI.GraphicsContentViewText (в нашем случае) уже подключен

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

вот только такой момент - когда я телефон наклонял из горизонтальной плоскости в вертикальную - разве я менял его ориентацию - портрет или ландскейп? я же его не так крутил (крутил не в плоскости телефона)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

По идее да. Разбирайтесь :)

Все что было связано с изначальным вопросом я дал, работайте как в АС, от fmx по части работы с сенсором нет ничего, те же результаты получите и в АС

Изменено пользователем mazayhin

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
3 минуты назад, mazayhin сказал:

По идее да. Разбирайтесь :)

Все что было связано с изначальным вопросом я дал, работайте как в АС

спасибо! извините за глупые вопросы )

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу