根据加速度数据创建四元数

时间:2018-08-03 11:00:17

标签: c# wpf accelerometer quaternions helix-3d-toolkit

所以我有一个加速度传感器,可以提供加速度数据。该设备当前处于特定位置,因此数据看起来像这样(每轴有一些噪音):

ACCELX = 264
ACCELY = -43
ACCELZ = 964

然后有一个3D模型代表设备,“我想要的”就是代表真实设备方向的3D模型。在尝试了解quaternions in .NET的用法时,下面是我编写的代码:

/* globals */
Vector3D PrevVector = new Vector3D(0, 0, 0);
ModelVisual3D model; // initialized and model file loaded

private async void TimerEvent() 
{
    RotateTransform3D rot = new RotateTransform3D();
    QuaternionRotation3D q = new QuaternionRotation3D();

    double x = 0, y = 0, z = 0;

    List<Reading> results = await Device.ReadSensor();

    foreach (Reading r in results)
    {
        switch (r.Type)
        {
            case "RPF_SEN_ACCELX":
                x = r.Value;
                break;

            case "RPF_SEN_ACCELY":
                y = r.Value;
                break;

            case "RPF_SEN_ACCELZ":
                z = r.Value;
                break;
        }
    }

    double angle = Vector3D.AngleBetween(new Vector3D(x, y, z), PrevVector);

    q.Quaternion = new Quaternion(new Vector3D(x, y, z), angle);

    rot.Rotation = q;
    model.Transform = rot;

    PrevVector = new Vector3D(x, y, z); 
}

移动真实设备确实会导致报告的值发生变化,但是屏幕上的模型只是在我看来是随机的方向上抽动,距离噪声远不远,而且似乎与旋转真实设备无关。我相当确定我正在错误地构造和使用四元数。我该怎么办?

这是带有WPF的.NET。也有HelixToolkit.WPF可用,但是我还没有见过任何从那里的加速度数据创建四元数的函数。更高级别的框架(如虚幻引擎或Unity)不适用于该项目。

2 个答案:

答案 0 :(得分:0)

您的传感器输出旋转值是累积的还是差异?有时输出旋转是差异,您需要先前的旋转值加上差异才能计算出当前的新旋转。

您可以尝试保存先前的四元数,并用先前的四元数添加当前四元数以获得新的累积旋转。

答案 1 :(得分:0)

事实证明,我的问题的性质完全不同:我必须使用一个名为Transform3DGroup的类。这是必须更改代码以实现绕Z轴旋转的方式:

/* globals */
ModelVisual3D model; // initialized and model file loaded
Transform3DGroup tg = new Transform3DGroup();

private async void TimerEvent() 
{
    RotateTransform3D rot = new RotateTransform3D();
    QuaternionRotation3D q = new QuaternionRotation3D();

    double x = 0, y = 0, z = 0;

    List<Reading> results = await Device.ReadSensor();


    foreach (Reading r in results)
    {
        switch (r.Type)
        {
            case "RPF_SEN_ACCELX":
                x = r.Value;
                break;

            case "RPF_SEN_ACCELY":
                y = r.Value;
                break;

            case "RPF_SEN_ACCELZ":
                z = r.Value;
                angle = GetAngle(x, y).ToDegrees();
                q.Quaternion = new Quaternion(new Vector3D(0, 0, 1), angle);
                break;
        }

        rot.Rotation = q;

        tg.Children.Clear();
        tg.Children.Add(rot);

        model.Transform = tg; // Use Transform3DGroup!
    }
}

我尚未找到有关强制使用Transform3DGroup的任何文档。

为了完整起见,以下是Bill Wallis on Math Overflow派生的GetAngle()的内部信息:

private double GetAngle(double x, double y)
{
    if (x > 0)
    {
        return 2 * Math.PI - Math.Atan(y / x);
    }
    else if (x < 0)
    {
        return Math.PI - Math.Atan(y / x);
    }
    else // x == 0
    {
        return 2 * Math.PI - Math.Sign(y) * Math.PI / 2;
    }
}

double类型的扩展名可以在弧度和度之间(在类外部,在名称空间内)转换双精度值:

public static class NumericExtensions
{
    public static double ToRadians(this double val)
    {
        return (Math.PI / 180) * val;
    }
    public static double ToDegrees(this double val)
    {
        return (180 / Math.PI) * val;
    }
}