“一切都是相对的”
因此,您需要做的是保存一个四元数并将其用作原点(也称为 call centre
),然后您可以定位任何新的四元数以确定发生了哪些方向变化。
校准
可以通过告诉用户保持手机稳定然后对四元数流进行采样和去抖动并在一段时间内对它们进行平均来执行校准。但是对于这个例子。只需将设备放在桌子上,屏幕向上,然后再启动应用程序,然后获取第一个示例(不是很好,但它可以快速运行)。
注意: System.Reactive observable 非常适合采样和去抖动
注意:将此四元数存储为其倒数 ( Quaternion.Inverse
),因为您必须对每个样本执行更少的计算。
计算每个样本的差异:
您想将当前采样的四元数乘以原点/中心(以逆形式)。
注意:请记住,乘法与四元数不可交换,因此顺序很重要(!)
var currentQ = e.Reading.Orientation;
var q = Quaternion.Multiply(originQ, currentQ);
转换本地化的四元数
所以现在你有一个本地化的四元数,你可以将它转换为 Vector3(通过基本向量(向上、向前、向下,...)转换它或获得一些欧拉角或......
例子:
因此,使用 Xamarin Essentials 示例,这就是我将如何更改OrientationSensor_ReadingChanged
事件作为一个非常简单的示例。
注意:采样事件被称为 A LOT 取决于设备,并且SensorSpeed
对于控制输出速率实际上没有用。如果您直接尝试使用这些示例更新屏幕(以一对一的方式),您可能会遇到严重的问题(Mono 垃圾收集器几乎无法跟上更新 UI 时创建的字符串的 GC (观察应用程序输出,GC 循环不断发生,即使SensorSpeed.UI
设置了。)我使用 Reactive Observables 来平滑样本并将传感器输出限制在合理的更新周期(16ms 或更多)之前更新 UI。
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;
});
});
}
注意:只需将您最喜欢的四元数转换为欧拉角例程(如果需要,还可以编写一个平滑和节流例程)。
输出: