使用倾角仪计算重力

12
如何将倾斜仪(俯仰、偏航和翻滚)转换为系统在 [X,Y,Z] 上受到的重力拉力?一个处于某个俯仰、偏航和翻滚角度下的系统应该以一定的[X*g,Y*g,Z*g]被地球吸引,假设这是为了模拟目的。我想制作一个函数,其输入是俯仰、偏航和翻滚,输出是向下力矩的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)的值,但这是另一个问题。

方向布局如下图所示: inclometer decriptor

有关更多信息以及如何使用此信息的内容,请继续阅读。

计划使用倾斜计作为去除加速度计数据中重力分量的替代陀螺仪,通过模拟/计算在方向(俯仰,偏航,翻滚)处预期的重力值。

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

为了说明我认为这是可能的原因。当我从手机中获取值并将手机向侧面用略微钟摆运动的方式移动时,看起来像正弦/余弦运动的线是倾角仪和其他线条是XYZ加速度计:

  • 红色=(俯仰&加速度计-X)
  • 绿色=(偏航&加速度计-Y)
  • 蓝色=(翻滚&加速度计-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

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


3
这是一个数学问题,与编程无关。 - Ashigore
6
这个问题似乎不符合主题要求,因为它涉及物理学。 - 123 456 789 0
13
这是程序员在日常工作中可能遇到过多次的问题。这非常相关,将来很可能对某些人有意义。 - Stachu
2
天哪,我以为它们会被校准以避免这种情况。我仍然认为实际问题是数学问题,而不是编程问题,即使它可以用于编程。如果没有其他的话,我怀疑你在http://math.stackexchange.com/上可能会得到更好、更快的答案,而不是在这里。 - Chris
2
这是一个非常典型的编程问题。物理方面很容易,但编程并不简单。投票以便重新开放。 - David Hammen
显示剩余15条评论
2个回答

4
如果你想计算倾斜方向的重力分量,那么你只需要使用俯仰角和横滚角(在WP约定中)- 绕Z轴旋转(偏航)对加速度计没有影响。公式应该是这样的:
VectorX = Cos(Pitch)*Sin(Roll);
VectorY = -Sin(Pitch);
VectorZ = -Cos(Pitch)*Cos(Roll);

您可以在这里找到类似的公式:这里这里

  • 倾角是单精度,加速度是双精度,可能存在精度问题。
  • 倾角计稳定需要一段时间。
  • 从倾角计和加速度计读取数据的时间不同(注意它们具有不同的最小报告间隔)。
  • 加速度计的精度因其位置而异。

此外,要注意加速度计可能会超载(其范围为±2g),例如如果您突然拍手机。


我编写了一个简单的应用程序(您可以在此处下载),通过比较加速计指示的值和通过倾斜角度计算出的值来测试它。由于加速度计的值相对于重力,因此很简单:
在XAML中使用文本块:

<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
@ThomasAndreèLian 那么抱歉,我不理解问题出在哪里。除非加速度计没有自校准且倾斜仪固定,否则您应该能够执行 acc-9.81 * incl = acc_mov。对我而言,最大的问题可能就是准确性和时间控制,因为运动可能非常快。 - Romasz
1
@ThomasAndreèLian,现在我想,那么抱歉,但我可能误解了你的问题:)。看来你想计算特定方向的重力分量。然后忘掉我的答案(我将在一天内删除它)。只需注意到提到的问题(如果您尚未),还有一个问题:根据我的经验,某些加速度计(我不知道手机)的精度会因其位置而异。 - Romasz
1
@ThomasAndreèLian,我重新构建了我的答案,展示了如何确定具有倾斜角的重力矢量分量以及代码示例。也许这会有所帮助。 - Romasz
1
那个运行得非常好。计算和测量的重力在图表中完美地重叠。你遇到了时间上的问题吗?考虑使用每个计算和测量的图形线条,然后取第一秒的数据来找到偏差并进行校正。这对我很有效。我只运行了5分钟,但我没有检测到任何随时间变化的偏移。 - Thomas Andreè Wang
1
@ThomasAndreèLian 很好,我有一天会试试(如果我只有更多的时间 :))。 我只是对这个100 Hz感到好奇,如果您在VS reportInterval中检查,则Inclinometer的最小值为16ms,加速度计为10ms。 正如http://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.sensors.accelerometer.reportinterval所述,灵敏度可能会有所不同。 我很好奇这个间隔是否仅与报告事件或传感器数据收集相关。 - Romasz
显示剩余6条评论

2
首先,重力不是加速度计所测量的内容。它们测量的是由于所有真实力(不包括重力)而引起的加速度。(这是牛顿力学的解释。相对论解释更简单:加速度计测量加速度,因为所有真实的力都在作用于加速度计上。在广义相对论中,重力是一种虚假的力。)
第一个线索表明加速度计不能感应到重力是看加速度计静置在地球表面时的输出。它会向上注册大约1g的加速度。作用于加速度计的力有向下的重力约1g和向上的法力约1g。如果加速度计能感受到重力,那么静置在地球表面上的加速度计会显示出接近于0的加速度。但它们并没有。它们只对向上1g的法力敏感。
另一个线索:将加速度计绑在跳伞者身上。当跳伞者站在飞机上等待飞机到达投放点时,飞机的地板会向上推动跳伞者,并且这个力会传播到跳伞者的身体到达加速度计。加速度计将向上注册大约1g。当跳伞者跳下去时,加速度计会突然注册侧向加速度,因为影响跳伞者的唯一力是水平风。并没有上下方向的成分。随着跳伞者落下并获得垂直速度,阻力力会转移到向上,使加速度计的输出从侧向变为向上。当跳伞者拉开降落伞时,加速度计输出将急剧上升,然后在跳伞者达到稳定速度时下降。尽管重力几乎没有变化,但加速度计的输出已经发生了巨大的变化。
那么如何实现您想要的呢?因为加速度计无法感应重力,所以您需要在软件中使用某种重力模型。根据需要,该模型的复杂程度可以范围从:
- 游戏控制器中使用的非常简单的模型。这些游戏控制程序员可能甚至不知道他们正在构建地球本地重力场的模型。模型不必太复杂,因为控制器几乎不动。 - 用于可以驾驶或飞越城镇的车辆系统中使用的略微更复杂的模型。有些需要操作员启动系统并等待软件提示说可以行动。在启动期间,软件正在校准当地的重力场。 - 用于较长程度的车辆系统中使用的更为复杂的模型。现在,地球的曲率意味着“下”方向发生了变化,并且重力加速度的大小也会发生变化。 - 用于通过重力场的变化来检测油田等内容的更为复杂的模型。 - 军用飞机和对接其他卫星的卫星中使用的非常复杂的模型。

您并没有说明需要多高级的翻译。这可能不是最终的类别;如果是的话,您就不会询问了。您可以通过一个学习本地重力场的系统来解决问题。在启动时使用简单的平均方案可能就足够了,或者您可能需要使用卡尔曼滤波器。应用程序将决定所需的精度,进而决定所需的复杂程度。


是的,加速度计不测量重力,但它们确实测量加速度,而地球以9.81米/秒^2的速度向下拉动加速度计,在加速度计的ZYX分量上分布(就像我们在地球上所知道的重力一样)。实际上,您只是确认了世界的运作方式,并需要模拟“重力”,计划将此解决方案与补偿和卡尔曼滤波器进行比较,后者随时间消除了部分“重力”。 - Thomas Andreè Wang
加速度计不测量向上的正压力。它们只是一些小质量和弹簧:重力将质量向下拉,并测量这种偏差。如果设备以1g向上加速,那么质量将经历完全相同的向下偏差,因此这些状态会给出相同的读数。在自由落体中,重力仍然使质量向下加速,但是设备的其余部分也向下加速,因此没有相对偏差,测量值为0。 - tom10
@tom10 - 这是错误的。重力不是一种力。在牛顿力学中,它是一种力,但牛顿力学并不是对现实的最佳描述。想想等效原理。你在一个没有窗户的电梯里醒来。你感受到身体上的正常重力。你怎么知道你是站在地球表面还是被某个外星飞船劫持,在以1g的加速度运动?你无法判断。重力不是一种力。它是一种虚构力。加速计对虚构力不敏感,因为它们是虚构的。 - David Hammen
@tom10 - 牛顿的解释也非常好,只要说加速度计对除重力以外的所有真实力都很敏感。从建筑物上扔下一个降落伞上的加速度计。随着降落伞+加速度计系统加速并遇到风阻力,加速度计读数逐渐从零增加。将加速度计固定在氦气球上并放开它。当气球上升时,加速度计读数超过1g向上。...继续 - David Hammen
在所有情况下,您可以绘制作用于加速度计的所有力的自由体图。将所有这些力(重力除外)相加,除以加速度计的质量,就可以得到加速度计的读数(当然不包括加速度计倾向于产生的噪声)。 - David Hammen
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接