«Все относительно» 100
Итак, вам нужно сохранить кватернион и использовать его в качестве источника (это также называется centre
), а затем вы можете локализовать любые новые кватернионы, чтобы определитькакие изменения ориентации произошли.
Калибровка
Калибровку можно выполнить, попросив пользователя держать телефон устойчиво, а затем произвести выборку и отсеивание потока кватернионов и усреднить их за период времени.,Но для этого примера.Просто положите устройство на стол, откройте экран, прежде чем запускать приложение, и возьмите первый образец (не очень, но для быстрого запуска).
Примечание: Система.Реактивная наблюдаемая прекрасно подходит для выборки и дебасинга
Примечание: Сохраните этот кватернион как его обратное значение (Quaternion.Inverse
), так как это на один расчет меньше, чем вы должны выполнить для каждой выборки.
Рассчитайте разницу для каждого образца:
Вы хотите умножить текущий кватернион выборки на начало координат / центр (в обратной форме).
Примечание: запомнитьумножение не является коммутативным с кватернионами, поэтому порядок имеет значение (!)
var currentQ = e.Reading.Orientation;
var q = Quaternion.Multiply(originQ, currentQ);
Преобразование вашего локализованного кватерниона
Так что теперь у вас есть локализованный кватернион, который вы можете преобразовать в Vector3 (преобразовать его с помощьюбазовый вектор (вверх, вперед, вниз, ...) или получить некоторые углы Эйлера или ...
Пример:
Так что, используя образец Xamarin Essentials, я бы так изменилOrientationSensor_ReadingChanged
событие как vочень быстрый пример.
Примечание: Событие выборки называется 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;
});
});
}
Примечание. Просто добавьте в свой любимый кватернион подпрограмму углов Эйлера (и, при желании, напишите подпрограмму сглаживания и дросселирования).
Вывод: