用测角仪计算重力

[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]

系统背后[pitch,yaw,roll] - > [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),但这是另一个问题)。

这是如何定位的方向。 测距仪描述符

有关为什么以及如何使用这些信息的额外信息,请继续阅读。

通过模拟/计算定位时的重力期望值(俯仰,偏航,滚动),该计划将使用倾角仪作为陀螺仪的替代方案,以便将重力分量去除到加速度计数据中。

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

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

  • 红色=(Pitch&accell-X)
  • 绿色=(偏航&加速-Y)
  • 蓝色=(滚动&加速-Z)
  • 加速度值乘以90,因为它范围从(-2到2),因此它在图中的范围从-180到180,俯仰偏航和滚动范围如上面的指导所示。 图像的中间是Y = 0,左侧是X = 0(X =时间)

    由Romasz解决的解决方案

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

    结果 在这里输入图像描述

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


    (在评论之后编辑(完全))

    如果你想计算倾斜方向的重力分量,那么你将只需要Pitch and Roll(按照WP惯例) - 关于Z(偏航)的旋转对加速度计没有影响。 公式应该如下所示:

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

    (你可以在这里或这里找到类似的公式)

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

  • 倾角是单精度,双加速度
  • 测斜仪可能需要一段时间才能稳定下来
  • 不同的时间同时执行测斜仪和加速度计的读数(因为这些传感器具有不同的最小报告间隔)
  • 加速度计根据其位置具有不同的精度
  • 另外要小心,因为加速度计可能会超载(范围是+ -2g) - 例如,如果您敲击手机。


    为了测试它,我写了一个简单的应用程序(可以在此下载) - 比较加速度计指示的值和通过倾斜度计算的值。 由于加速度计的值与重力有关,所以它的直观性:
    在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");
        }
    }
    

    首先要做的是:加速度计不测量重力。 他们测量由于每个真实力量而引起的加速度,但是引力。 (这是牛顿的解释,相对论的解释更容易:加速度计测量加速度,因为所有的真实力作用在加速度计上,重力是广义相对论中的虚构力。)

    加速度计不感应重力的第一条线索是查看放置在地球表面的加速度计的输出。 它向上注册约1g的加速度。 作用在加速度计上的力是重力,大约1g向下,法向力大约1g向上。 如果加速度计感觉到重力,那么静止在地球表面的加速度计将记录接近零的加速度。 他们不。 所有他们敏感的是1克向上的正常力量。

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


    那么如何实现你想要的? 由于加速度计不感应引力,因此需要某种类型的软件引力模型。 根据需要,这个模型的复杂程度可以从

  • 游戏控制器中使用的非常简单的模型。 那些游戏控制程序员可能甚至不知道他们正在构建地球局部重力场的模型。 这个模型并不需要那么复杂,因为控制器移动得并不多。

  • 用于可能驾驶或在城镇周围飞行的车辆系统中使用的稍微复杂的模型。 有些需要操作员启动系统,直到软件没有问题才移动。 在启动期间,软件正在校准局部重力场。

  • 用于更远距离车辆系统的更复杂的模型。 现在地球的曲率意味着“向下”改变方向,并且也意味着重力加速度的量值变化。

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

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

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

    链接地址: http://www.djcxy.com/p/65403.html

    上一篇: Calculate gravity with inclometer

    下一篇: Gravity in C++ using classes and lists (no graphical representation)