C# 从加速度数据创建四元数

C# 从加速度数据创建四元数,c#,wpf,accelerometer,quaternions,helix-3d-toolkit,C#,Wpf,Accelerometer,Quaternions,Helix 3d Toolkit,所以我有一个加速度传感器,可以提供加速度数据。设备当前处于某个位置,因此数据如下所示(每个轴有一些噪声): 然后是一个3D模型来表示设备,“我想要的”是这个3D模型来表示真实设备的方向。在我试图理解的用法中,以下是我狼吞虎咽的代码: /* globals */ Vector3D PrevVector = new Vector3D(0, 0, 0); ModelVisual3D model; // initialized and model file loaded private async v

所以我有一个加速度传感器,可以提供加速度数据。设备当前处于某个位置,因此数据如下所示(每个轴有一些噪声):

然后是一个3D模型来表示设备,“我想要的”是这个3D模型来表示真实设备的方向。在我试图理解的用法中,以下是我狼吞虎咽的代码:

/* 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); 
}
/*全局*/
Vector3D PrevVector=新的Vector3D(0,0,0);
ModelVisual3D模型;//初始化并加载模型文件
私有异步void TimerEvent()
{
RotateTransform3D rot=新的RotateTransform3D();
四元数旋转3D q=新的四元数旋转3D();
双x=0,y=0,z=0;
列表结果=等待设备。读取传感器();
foreach(在结果中读取r)
{
开关(r型)
{
案例“RPF_SEN_ACCELX”:
x=r.值;
打破
案例“RPF_SEN_ACCELY”:
y=r.值;
打破
案例“RPF_SEN_ACCELZ”:
z=r.值;
打破
}
}
双角度=Vector3D.AngleBetween(新的Vector3D(x,y,z),PrevVector);
q、 四元数=新四元数(新矢量3D(x,y,z),角度);
旋转=q;
model.Transform=rot;
PrevVector=新矢量3D(x,y,z);
}
移动我的真实设备确实会产生报告值的变化,但屏幕上的模型在我看来只是在随机方向上抖动,距离噪音稍远,似乎与我旋转真实设备的方式无关。我相当肯定我构造和使用四元数是错误的。我该怎么做才对呢


这是带WPF的.NET。也有可用的,但我还没有看到任何从加速度数据中创建四元数的函数。此项目不提供更高级别的框架,如Unreal Engine或Unity。

传感器输出旋转值是累积的还是差异的?有时输出旋转是不同的,您需要以前的旋转值加上这些差异来计算当前的新旋转


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

结果表明,我的问题性质完全不同:我必须使用一个名为
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!
    }
}
以及double类型的扩展,用于在弧度和度之间转换double(类外,命名空间内):


我不确定,但我想到的第一件事是:你是在每次迭代中用新值更新原始位置/旋转,还是在下一次迭代中用新值和新值更新上一个位置/旋转,依此类推。对我来说,它看起来像第二个。由于更新了
PrevVector
@MartinBackasch行
model.Transform=rot
假定设置并立即更新模型。我很快通过删除这条线并观察到视图中的三维模型完全停止了抖动来验证这一点。我不熟悉
ModelVisual3D
,但遵循我的最初想法。如果四元数相同或静止不动,您可以通过尝试和错误检查
Transform
是否旋转模型。
List results=wait Device.ReadSensor()的一些示例结果是什么不移动,我想没有输入值。输出结果总是相对于静态位置。最后,四元数不是问题所在,而是模型的应用程序:我似乎必须使用
Transform3DGroup
类,否则更改将不适用。我还没有找到合适的文档,只是注意到它被用于多个教程和答案中。
/* 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!
    }
}
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;
    }
}
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;
    }
}