Рассчитать гравитацию с помощью счетчика

Как можно преобразовать инклинометры (Pitch, Yaw and Roll) в гравитационное вытягивание, ожидаемое в системе в [X,Y,Z]?

Система, покоящаяся в определенном уголке Pitch, Yaw и Roll, должна быть вытащена на Землю при некотором [X*g,Y*g,Z*g], скажем, это для целей симуляции. Я хочу, чтобы функция whoose вводила 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;
}

Да, я знаю, как объяснение ниже показывает, что я не могу определить, перевернуты ли системы или нет на основе рулона, поскольку roll только дает (от -90 до 90), но это другая проблема).

Вот как выкладывается ориентация. inclometer decriptor

За дополнительной информацией о том, почему и как использовать эту информацию, читайте.

План состоит в том, чтобы использовать счетчик в качестве альтернативы гирометру для снятия гравитационной составляющей с данными акселерометра путем имитации/вычисления ожидаемого значения силы тяжести при ориентации (Pitch, Yaw, Roll).

Поскольку акселерометр (XYZ) представляет собой комбинацию силы тяжести двух компонентов (XYZ) и движения (XYZ), я предполагаю, что gravity(XYZ)-calc_g(XYZ) = 0, позволяет мне выполнять accelerometer(XYZ)- calc_g(XYZ) =movement(XYZ)

чтобы показать, почему я думаю, что это возможно. когда я рисую значения с телефона и двигаю телефон в сторону в несколько маятниковом движении, линии, которые выглядят как синусоидальные движения, являются инклинометром, а другие - акселерометром XYZ:

  • red = (Pitch and 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

* Графики не от одного и того же измерения.

Ответ 1

(Отредактировано (полностью) после комментариев)

Если вы хотите рассчитать компоненты силы тяжести в направлении наклона, вам понадобится только Pitch and Roll (в соглашении WP) - вращение вокруг Z (Yaw) не оказывает влияния на акселерометры. Формула должна выглядеть так:

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

(Аналогичная формула вы можете найти, например здесь или здесь)

С точностью до нескольких причин могут возникнуть некоторые проблемы:

  • Наклон - одинарная точность, двойное ускорение
  • может потребоваться некоторое время для стабилизации инклинометров.
  • различное время при выполнении показаний с инклинометра и акселерометра (смотри, потому что эти датчики имеют разный минимальный интервал отчета).
  • акселерометры имеют различную точность, зависящую от их положения.

Также следите, потому что акселерометры могут быть перегружены (их диапазон + -2g) - например, если вы щелкнете по телефону.


Чтобы проверить это, я написал простое приложение (которое вы можете скачать здесь) - сравнение значений, указанных акселерометрами, и значений, рассчитанных с помощью наклона, Поскольку значения акселерометров относительно гравитации, его strightforward:
В 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");
    }
}

Ответ 2

Прежде всего: акселерометры не измеряют гравитацию. Они измеряют ускорение из-за любой реальной силы, но силы тяжести. (Это объяснение Ньютоном. Релятивистское объяснение еще проще: акселерометры измеряют ускорение из-за всех реальных сил, действующих на акселерометр. Гравитация - это фиктивная сила в общей теории относительности.)

Первая подсказка, что акселерометры не воспринимают гравитацию, - это смотреть на выход акселерометра, покоящегося на поверхности Земли. Он регистрирует ускорение около 1 г вверх. Силы, действующие на акселерометр, являются силой тяжести, около 1 г направлены вниз, а нормальная сила - около 1 г, направленная вверх. Если бы акселерометры действительно воспринимали гравитацию, то акселерометр, находящийся в покое на поверхности Земли, регистрировал бы близкое к нулю ускорение. Они этого не делают. Все они чувствительны к тому, что 1g вверх нормальная сила.

Еще одна подсказка: Наденьте акселерометр на парашютиста. Пока парашютист стоит в самолете и ждет, когда самолет достигнет пятна падения. Пол самолета подталкивает парашютиста вверх, и эта сила распространяется по всему корпусу парашютиста на акселерометр. Акселерометр будет регистрировать около 1 г вверх. Когда прыжок с парашютом прыгает, акселерометр внезапно зарегистрирует боковое ускорение, потому что единственная сила, действующая на парашютиста, - это горизонтальный ветер. У зарегистрированного ускорения не будет ни вверх, ни вниз компонента. Сила сопротивления сдвинется вверх, так как парашютист падает и поднимает вертикальную скорость, делая выход акселерометра сдвигающимся сбоку вверх. Выход акселерометра будет увеличиваться, когда парашютист вытащит рипкорд, а затем упадет, когда парашютист достигнет постоянной скорости. Выход акселерометра сильно изменился, хотя гравитационная сила немного изменилась.


Итак, как выполнить то, что вы хотите? Поскольку акселерометры не воспринимают гравитацию, вам нужна какая-то модель для гравитации в вашем программном обеспечении. В зависимости от потребности эта модель может варьироваться по сложности от

  • Очень простые модели, используемые в игровых контроллерах. Эти программисты по управлению играми могут даже не знать, что они строят модель локального гравитационного поля Земли. Модель не обязательно должна быть сложной, поскольку контроллер не сильно двигается.

  • Несколько более сложные модели, используемые в системах для транспортных средств, которые могут проезжать или летать по городу. Некоторым требуется, чтобы оператор запускал систему и не двигался, пока программное обеспечение не сообщит об этом. В течение этого времени запуска программное обеспечение выполняет калибровку локального поля гравитации.

  • Еще более сложные модели, используемые в автомобильных системах дальнего действия. Теперь кривизна Земли означает "вниз", направление изменения, а также означает, что гравитационное ускорение изменяется по величине.

  • Еще более сложные модели, используемые для обнаружения нефтяных месторождений и т.д. вариациями в гравитационном поле.

  • Очень сложные модели, используемые в военных самолетах и ​​спутниках, которые состыковываются с другими спутниками.

Вы не сказали, какой уровень сложности вам нужен. Вероятно, это не последняя категория; если бы это было так, вы бы не спрашивали. Вы бы взяли занятия по этому предмету. Вы, вероятно, можете пройти с помощью системы, которая изучает местное поле гравитации. Простая схема усреднения при запуске может быть достаточной, или вам может понадобиться фильтр Калмана. Приложение будет диктовать необходимую точность, а это, в свою очередь, будет определять требуемую сложность.