Датчик ориентации Xamarin Quaternion

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

Я знаю, что кватернион дает мне преобразование, но к чему?

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

Когда телефон лежит на столе, у меня получается следующая ось:

axis = [0,0,-1]

И угол в основном представляет собой угол компаса. В той конкретной ситуации я именно этого и ожидал. Но когда телефон имеет другое произвольное пространственное положение, ось больше не кажется нормальным вектором телефона.

Как вычислить вектор нормали к плоскости телефона?


person mefiX    schedule 05.02.2019    source источник
comment
Вы смотрели раздел с примерами: docs.microsoft.com/en- us/xamarin/essentials/ориентация-датчик   -  person SushiHangover    schedule 05.02.2019
comment
Да, я действительно сделал. ‹em›Кватернион описывает вращение системы координат устройства относительно системы координат Земли.‹/em›. Итак, как я могу получить локальный вектор ориентации, который не относится к земной системе координат?   -  person mefiX    schedule 05.02.2019


Ответы (1)


"Все относительно" ????

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

Калибровка

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

Примечание. Наблюдаемый объект System.Reactive отлично подходит для выборки и устранения дребезга.

Примечание. Сохраните этот кватернион как его инверсию (Quaternion.Inverse), так как это на одно вычисление меньше, которое вам придется выполнять для каждого образца.

Рассчитайте разницу для каждого образца:

Вы хотите умножить текущий выбранный кватернион на начало/центр (в обратной форме).

Примечание. Помните, что умножение не является коммутативным с кватернионами, поэтому порядок имеет значение(!)

var currentQ = e.Reading.Orientation;
var q = Quaternion.Multiply(originQ, currentQ);

Преобразуйте свой локализованный кватернион

Итак, теперь у вас есть локализованный кватернион, который вы можете преобразовать в Vector3 (преобразовать его по базовому вектору (вверх, вперед, вниз,...) или получить некоторые углы Эйлера или...

Пример:

Итак, используя пример Xamarin Essentials, я бы изменил событие OrientationSensor_ReadingChanged в качестве очень быстрого примера.

Примечание. Событие выборки называется A LOT в зависимости от устройства, и SensorSpeed действительно бесполезна для управления скоростью вывода. Если вы напрямую пытаетесь обновить экран с помощью этих образцов (на основе 1-к-1), у вас могут возникнуть серьезные проблемы (сборщик мусора Mono едва справляется с GC'ированием строк, которые создаются при обновлении пользовательского интерфейса). (следите за выводом приложения, циклы GC происходят постоянно, даже с установленным SensorSpeed.UI) Я использую Reactive Observables для сглаживания выборок и дросселирования вывода датчика до разумных циклов обновления (16 мс или более) перед обновлением пользовательского интерфейса.

void OrientationSensor_ReadingChanged(object sender, OrientationSensorChangedEventArgs e)
{
    if (originQ == Quaternion.Identity) // auto-origin on first sample or when requested
    {
        originQ = Quaternion.Inverse(e.Reading.Orientation);
    }

    var q = Quaternion.Multiply(originQ, e.Reading.Orientation);

    GetEulerAngles(q, out yaw, out pitch, out roll); // assuming "right-hand" orientation

    SmoothAndThrottle(yaw, pitch, roll, () =>
    {
        Device.BeginInvokeOnMainThread(() =>
        {
            pitchLabel.Text = pitch.ToString();
            rollLabel.Text = roll.ToString();
            yawLabel.Text = yaw.ToString();

            // This will appear to keep the image aligned to the origin/centre.
            direction.RotateTo(90 * yaw, 1);
            direction.RotationX = 90 * pitch;
            direction.RotationY = -90 * roll;
        });
    });
}

Примечание. Просто подключите свою любимую процедуру кватерниона к углам Эйлера (и при желании напишите процедуру сглаживания и дросселирования).

Выход:

введите здесь описание изображения

person SushiHangover    schedule 06.02.2019
comment
Вау, большое спасибо за такой подробный ответ. Я понимаю аспект калибровки и обратный кватернион, чтобы прийти к локализованному кватерниону. Однако мне не нужны углы Эйлера для каждого образца, а трехмерный вектор является нормальным/ортогональным к поверхности/плоскости моего телефона. (...) Итак, теперь у вас есть локализованный кватернион, который вы можете преобразовать в Vector3 (преобразовать его с помощью базового вектора (...) это часть, которую я не понимаю. Что вы подразумеваете под базовым вектором (1 ,0,0)?И что вы подразумеваете под преобразованием его по базовому вектору? - person mefiX; 06.02.2019
comment
@mefiX Базовым вектором может быть стандартный VectorUp|VectorForward|... (Unity|XNA|... и другие предопределяют их, но вы можете использовать любой вектор в зависимости от ваших потребностей. VectorUp будет определен как new Vector3(0f, 1f, 0f); в правой системе координат. Оттуда вы можете преобразовать этот вектор с помощью вашего локализованного кватерниона, System.Numerics.Vector3 имеет статическое преобразование, поэтому Vector3.Transform(VectorUp, q); вернет вектор, повернутый от его основания поворотом кватерниона. Имеет смысл? - person SushiHangover; 06.02.2019
comment
Локализованный кватернион по-прежнему является умножением кватерниона обратного происхождения и текущего выборочного кватерниона (в таком порядке)? - person mefiX; 06.02.2019
comment
@mefiX Да ... слишком раннее преобразование в векторы приведет вас в мир, наполненный такими проблемами, как карданные замки и тому подобное. Вы всегда должны работать с кватернионами, так как они могут свободно выражать любое вращение. С точки зрения пользовательского представления кватерниона, используйте последний в цепочке поворотов, прежде чем применять какое-либо реальное преобразование. - person SushiHangover; 06.02.2019
comment
Вот в чем дело. Я думаю, что это намного проще, чем я думал. Если я преобразовываю форварда ака. из задней части телефонного вектора [0,0,-1] только с текущим прочитанным кватернионом я получаю именно то, что хочу. - person mefiX; 07.02.2019
comment
Извините, я только что понял, что мне, возможно, придется перефразировать свой вопрос. Мне нужен трехмерный вектор ориентации в (lat,lon,altitude) (WGS). Мне нужно рассчитать угол между вектором ориентации моего телефона o и вектором расстояния d между местоположением телефона p=(lat,lon,alt) и другим фиксированным положением f=(lat,lon,alt), равным d = f - p. Итак, собственно вопрос: как мне перейти от одного кватерниона к вектору ориентации в WGS? - person mefiX; 07.02.2019
comment
@mefiX Я делаю что-то подобное в приложении для авиационной навигации (учитывая точку A и точку B, каков начальный пеленг, который, если следовать по прямой линии вдоль дуги большого круга, ведет от A к B). Опубликуйте новый вопрос с тем, что вы уже сделали и что вы ищете. - person SushiHangover; 07.02.2019
comment
Ха, интересно, мы могли бы работать в похожих контекстах. Моя проблема тоже связана с авиацией. Я напишу новый вопрос и опубликую ссылку здесь. - person mefiX; 08.02.2019
comment
Вот новый вопрос: stackoverflow.com/questions/54589349/ Спасибо, кстати, за подсказку к реактивному! Я действительно копаю эту концепцию! .Throttle не работает, т.к. Не знаю почему. - person mefiX; 08.02.2019
comment
@SushiHangover - у вас есть «GetEulerAngles()» с открытым исходным кодом, который вы бы порекомендовали? - person DefenestrationDay; 30.10.2019