Xamarin 方向传感器四元数

mef*_*fiX 1 c# math xamarin xamarin.forms xamarin.essentials

Vector3我正在尝试确定代表我的手机方向(没有角度)的3d 矢量。我正在寻找的是像射线一样从手机背面发出的矢量,基本上是手机的法线矢量。

我知道四元数给了我一个变换,但是变换什么呢?

此外,我发现Quaternion.ToAxisAngle(),它将四元数转换为轴及其各自的滚动角。我想,太好了,这就是我所需要的,我可以忽略角度。

当手机放在桌子上时,我得到以下轴:

axis = [0,0,-1]
Run Code Online (Sandbox Code Playgroud)

而角度基本上代表了指南针的角度。在那种特殊情况下,这正是我所期望的。但是,当手机具有不同的任意空间位置时,轴似乎不再是手机的法线向量。

如何计算手机平面的法向矢量?

Sus*_*ver 5

“一切都是相对的”

因此,您需要做的是保存一个四元数并将其用作原点(也称为centre),然后您可以本地化任何新的四元数以确定发生了哪些方向变化。

校准

可以通过告诉用户稳定手机,然后对四元数流进行采样和去抖动并在一段时间内对它们进行平均来执行校准。但对于这个例子来说。只需将设备放在桌子上,在启动应用程序之前打开屏幕,然后获取第一个示例(不是很好,但对于快速使用它是有效的)。

注意: System.Reactive observable 非常适合采样和去抖

注意:将此四元数存储为其逆 ( Quaternion.Inverse),因为这样可以减少您必须对每个样本执行的计算。

计算每个样本的差异:

您想要将当前采样的四元数乘以原点/中心(以相反的形式)。

注意:记住乘法对于四元数是不可交换的,所以顺序很重要(!)

var currentQ = e.Reading.Orientation;
var q = Quaternion.Multiply(originQ, currentQ);
Run Code Online (Sandbox Code Playgroud)

转换您的本地化四元数

现在你有了一个本地化的四元数,你可以将其转换为 Vector3(通过基本向量(向上、向前、向下,...)对其进行转换,或者获得一些欧拉角或...

例子:

因此,使用 Xamarin Essentials 示例,这就是我如何更改OrientationSensor_ReadingChanged事件的一个非常快速的示例。

注意:根据设备的不同,采样事件被称为“很多”,并且SensorSpeed对于控制输出速率实际上毫无用处。如果您直接尝试使用这些示例(一对一)更新屏幕,则可能会遇到严重问题(Mono 垃圾收集器几乎无法跟上 GC 更新 UI 时创建的字符串) (观察应用程序输出,GC 周期不断发生,即使已SensorSpeed.UI设置)。在更新 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;
        });
    });
}
Run Code Online (Sandbox Code Playgroud)

注意:只需将您最喜欢的四元数替换为欧拉角例程(并根据需要编写平滑和节流例程)。

输出:

在此输入图像描述