Xamarin Датчик ориентации Quaternion
Я пытаюсь определить 3d вектор Vector3
представляя ориентацию моих телефонов без угла. То, что я ищу, это вектор, который образно выходит из задней части телефона, как луч, в основном нормальный вектор телефона.
Я знаю, что кватернион дает мне преобразование, но к чему?
Кроме того, я нашел Quaternion.ToAxisAngle()
, который преобразует кватернион в ось и соответствующий ей угол крена. Я подумал, отлично, это то, что мне нужно, я могу просто игнорировать угол.
Когда телефон лежит на столе, я получаю следующую ось:
axis = [0,0,-1]
И угол в основном представляет угол компаса. В этой конкретной ситуации это то, что я ожидал. Но когда телефон имеет другое произвольное пространственное положение, ось больше не является нормальным вектором телефона.
Как рассчитать вектор нормали к плоскости телефона?
1 ответ
"Все относительно"
Так что вам нужно сохранить кватернион и использовать его в качестве источника (это также вызов centre
), а затем вы можете локализовать любые новые кватернионы, чтобы определить, какие изменения ориентации произошли.
калибровка
Калибровку можно выполнить, попросив пользователя держать телефон в устойчивом положении, а затем произвести выборку и отсеивание потока кватернионов и усреднить их за определенный период времени. Но для этого примера. Просто поместите устройство на стол, просмотрите экран перед запуском приложения и возьмите первый образец (не очень, но для быстрого запуска это работает).
Примечание. Наблюдаемая System.Reactive отлично работает для выборки и устранения неполадок.
Примечание: сохраните этот кватернион как обратный (Quaternion.Inverse
), так как это на один расчет меньше вы должны выполнить для каждого образца.
Рассчитайте разницу по каждому образцу:
Вы хотите умножить текущий выборочный кватернион на начало координат / центр (в обратной форме).
Примечание: Помните, что умножение некоммутативно с кватернионами, поэтому порядок имеет значение (!)
var currentQ = e.Reading.Orientation;
var q = Quaternion.Multiply(originQ, currentQ);
Преобразовать ваш локализованный кватернион
Итак, теперь у вас есть локализованный кватернион, который вы можете преобразовать в Vector3 (преобразовать его с помощью базового вектора (вверх, вперед, вниз, ...) или получить некоторые углы Эйлера или...
Пример:
Таким образом, используя образец Xamarin Essentials, я бы изменил OrientationSensor_ReadingChanged
событие как очень быстрый пример.
Примечание: событие выборки называется LOT в зависимости от устройства и SensorSpeed
действительно бесполезно контролировать скорость производства. Если вы пытаетесь напрямую обновить экран с помощью этих примеров (в соотношении 1 к 1), у вас могут возникнуть серьезные проблемы (сборщик мусора Mono может едва поспевать за 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;
});
});
}
Примечание: просто перейдите в вашей любимой процедуре кватерниона к углам Эйлера (и, если хотите, напишите процедуру сглаживания и регулирования).