Перейти к содержанию
Fire Monkey от А до Я
  • 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)?

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

Ссылка на комментарий

Рекомендуемые сообщения

  • 0

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

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

Ссылка на комментарий
  • 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
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 сказал:

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

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

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

Ссылка на комментарий

Присоединяйтесь к обсуждению

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

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

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

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