用倾角仪计算重力

时间:2014-01-30 16:57:50

标签: c# windows-phone-8 accelerometer physics

如何将倾斜仪(俯仰,俯仰和滚转)转换为[X,Y,Z]系统中预期的引力?

处于某个俯仰,偏转和俯仰角度的静止系统应该在某个[X*g,Y*g,Z*g]被拉到地面,假设这是出于模拟目的。我想创建一个输入是Pitch,Yaw和Roll的函数,输出是下降时刻的Vector3(X,Y,Z)

意味着一个物体静止而它向后向后会从加速度计输出[0,-1,0][pitch,yaw,roll]->[0,-1,0],其中[0,-1,0]减去[0,-1,0],导致[0,0,0] }。或者如果我们以1g的速度向左拉,我们有一个加速计显示[1,-1,0],使新值[1,0,0]

系统背面[俯仰,偏航,滚动] - > [0,-1,0]功能正是我所追求的

Vector3 OriToXYZ(float pitch, float yaw, float roll){
    Vector3 XYZ = Vector.Zero;
    //Simulate what the XYZ should be on a object in this orientation
    //oriented against gravity
    ...
    return XYZ;
}

是的我知道,因为下面的解释显示我无法检测系统是否基于滚动而不是基于滚动仅提供(-90到90),但这是一个不同的问题。

这就是方向的布局方式。 inclometer decriptor

有关使用此信息的原因,内容和方式的详细信息,请继续阅读。

计划是使用测斜仪作为陀螺仪的替代方案,通过模拟/计算方向上的重力预期值(俯仰,偏航,侧倾),将重力分量移除到加速度计数据。

由于加速度计(XYZ)是重力(XYZ)和运动(XYZ)两个分量的组合,我假设gravity(XYZ)-calc_g(XYZ) = 0,允许我执行accelerometer(XYZ)- calc_g(XYZ) =movement(XYZ)

说明为什么我认为这是可能的。当我绘制手机中的数值并在稍微摆动时将手机侧向移动时,看起来像正弦/余弦运动的线条是倾斜的,其他线条是XYZ加速度计:

  • red =(Pitch& accell-X)
  • green =(Yaw& accell-Y)
  • blue =(Roll& accell-Z)

加速度值乘以90,因为它的范围为(-2到2),因此它在图形中的范围从-180到180,俯仰偏航和滚转范围如上面的指示所示。图像的中间是Y = 0,左侧是X = 0(X =时间)

Sensor measurements

解决 解决方案 Romasz

VectorX = Cos(Pitch)*Sin(Roll);
VectorY = -Sin(Pitch);
VectorZ = -Cos(Pitch)*Cos(Roll);

结果 enter image description here

*图表不是来自同一测量。

2 个答案:

答案 0 :(得分:3)

(评论后完全编辑)

如果你想在倾斜方向上计算重力分量,那么你将只需要俯仰和滚转(在WP惯例中) - 绕Z(Yaw)的旋转对加速度计没有影响。公式应如下所示:

VectorX = Cos(Pitch)*Sin(Roll);
VectorY = -Sin(Pitch);
VectorZ = -Cos(Pitch)*Cos(Roll);

(您可以找到类似的公式,例如herehere

由于许多原因,准确性可能存在一些问题:

  • 倾斜度是单精度,加速度加倍
  • 倾角仪可能需要一段时间来稳定
  • 从测斜仪和加速度计执行读数时的不同时序(因为这些传感器具有不同的最小报告间隔,因此需要了解)
  • 加速度计根据其位置具有不同的准确度

另请注意,因为加速度计可能会过载(其范围为+ -2g) - 例如,如果您拍摄手机。


为了测试它,我编写了一个简单的应用程序(which you can download here) - 比较加速度计指示的值和通过倾斜度计算的值。因为加速度计的值与重力相关,所以它很明确:
在XAML中 - 几个TextBlocks:

<Grid x:Name="LayoutRoot" Background="Transparent" Margin="20">
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" VerticalAlignment="Center" Orientation="Horizontal">
            <TextBlock Text="Incliation:" FontSize="16"/>
            <TextBlock Name="incXTB" Margin="10"/>
            <TextBlock Name="incYTB" Margin="10"/>
        </StackPanel>
        <StackPanel Grid.Row="1" VerticalAlignment="Center" Orientation="Horizontal">
            <TextBlock Text="Accelerometers:" FontSize="16"/>
            <TextBlock Name="accXTB" Margin="10"/>
            <TextBlock Name="accYTB" Margin="10"/>
            <TextBlock Name="accZTB" Margin="10"/>
        </StackPanel>
        <StackPanel Grid.Row="2" VerticalAlignment="Center" Orientation="Horizontal">
            <TextBlock Text="Through Inc:" FontSize="16"/>
            <TextBlock Name="accincXTB" Margin="10"/>
            <TextBlock Name="accincYTB" Margin="10"/>
            <TextBlock Name="accincZTB" Margin="10"/>
        </StackPanel>
</Grid>

在代码背后:

public partial class MainPage : PhoneApplicationPage
{
    private Inclinometer myIncMeter = null;
    private float inclX = 0;
    private float inclY = 0;

    private Accelerometer myAccel = null;
    private double accX = 0;
    private double accY = 0;
    private double accZ = 0;

    public MainPage()
    {
        InitializeComponent();
        this.DataContext = this;
        myIncMeter = Inclinometer.GetDefault();
        myIncMeter.ReportInterval = myIncMeter.MinimumReportInterval;
        myAccel = Accelerometer.GetDefault();
        myAccel.ReportInterval = myIncMeter.MinimumReportInterval;

        CompositionTarget.Rendering += CompositionTarget_Rendering;
    }

    private void CompositionTarget_Rendering(object sender, EventArgs e)
    {
        InclinometerReading incRead = myIncMeter.GetCurrentReading();
        AccelerometerReading accRead = myAccel.GetCurrentReading();

        accX = accRead.AccelerationX;
        accY = accRead.AccelerationY;
        accZ = accRead.AccelerationZ;

        inclX = incRead.RollDegrees;
        inclY = incRead.PitchDegrees;

        incXTB.Text = "X: " + inclX.ToString("0.00");
        incYTB.Text = "Y: " + inclY.ToString("0.00");

        accXTB.Text = "X: " + accX.ToString("0.00");
        accYTB.Text = "Y: " + accY.ToString("0.00");
        accZTB.Text = "Z: " + accZ.ToString("0.00");

        accincXTB.Text = "X: " + ((Math.Cos(inclY * Math.PI / 180) * Math.Sin(inclX * Math.PI / 180))).ToString("0.00");
        accincYTB.Text = "Y: " + (-Math.Sin(inclY * Math.PI / 180)).ToString("0.00");
        accincZTB.Text = "Z: " + (-(Math.Cos(inclX * Math.PI / 180) * Math.Cos(inclY * Math.PI / 180))).ToString("0.00");
    }
}

答案 1 :(得分:2)

首先要做的事情是:加速度计不测量重力。它们测量由于每个真实力而不是重力引起的加速度(这是牛顿的解释。相对论的解释更加容易:加速度计测量由于加速度计上的所有实际力引起的加速度。重力是广义相对论中的虚拟力。)

加速度计不感知重力的第一个线索是观察地球表面静止的加速度计的输出。它记录了大约1g 向上的加速度。作用在加速度计上的力是重力,向下约1g,法向力向上约1g。如果加速度计确实感知到重力,则地球表面上静止的加速度计将接近零加速度。他们没有。所有他们都敏感的是1g以上的正常力量。

另一条线索:将加速度计带到跳伞运动员身上。当跳伞者站在飞机上等待飞机到达落点时。飞机的地板向上推动跳伞者,并且该力量在整个跳伞者的身体内传播到加速度计。加速度计将向上注册约1g。当跳伞者跳跃时,加速度计将突然记录侧向加速度,因为作用在跳伞者上的唯一力是水平风。注册的加速度不会有向上或向下的分量。当跳伞者下降并且垂直速度加快时,阻力将向上移动,使加速度计的输出从侧向移动到向上。当跳伞者拉动拉绳时加速度计输出将会飙升,然后随着跳伞者达到稳定速度而下降。即使重力几乎没有变化,加速度计的输出也发生了巨大的变化。


那么如何实现你想要的呢?因为加速度计不能感知引力,所以在软件中需要某种模型来引力。根据需要,此模型的复杂程度可以从

开始
  • 游戏控制器中使用的非常简单的模型。那些游戏控制程序员可能甚至不知道他们正在构建地球本地重力场的模型。由于控制器移动不多,模型不一定非常复杂。

  • 用于车辆系统的更复杂的车型可能会穿越或绕城飞行。有些要求操作员启动系统,直到软件说它没问题才动作。在启动期间,软件正在校准局部重力场。

  • 更长距离车辆系统中使用的更复杂的车型。现在地球的曲率意味着“向下”改变方向,也意味着重力加速度的大小不同。

  • 用于检测油田的更复杂的模型,以及引力场的变化。

  • 用于与其他卫星对接的军用飞机和卫星的非常复杂的模型。

你没有说出你需要什么样的复杂程度。这可能不是最后一类;如果是的话,你就不会问。你会参加这个课程的课程。你可以通过一个学习局部重力场的系统来解决问题。启动时的简单平均方案可能就足够了,或者您可能需要卡尔曼滤波器。该应用程序将决定所需的准确性,反过来将决定所需的复杂性。