Posts mit dem Label Formel werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Formel werden angezeigt. Alle Posts anzeigen

Dienstag, 15. April 2014

Luftdrucksensor BMP085 mit dem Netduino - Höhenangabe (Teil 4)

image_thumb8_thumb_thumb

Mit dem Luftdruck lässt sich in etwa auch die Höhe ermitteln. Allerdings ist dieser Wert bedingt verwendbar. Zum einen muss der Sensor beim einschalten mit der aktuellen Höhe kalibriert werden und zum anderen gibt es verschiedene Formeln für die Berechnung, die spezielle Anforderungen erfüllen.

Wie immer kommt es darauf an, was man möchte. Im Dokument selbst, wird nur der Luftdruck verwendet. Die Formel hierfür ist nicht sonderlich komplex und lässt sich daher in wenigen Codezeilen umsetzen.

altitude = 44330 * (1 – (p/p0) 1/5.255)
Nach dem Dokument auf Seite 14, ist diese Formel zu verwenden.

Auffällig dürften die festen Zahlenwerten sein, die auf den ersten Blick keinen Bezug darstellen. Die Beschreibung für diese Sache ist leider ohne Begründung, was mir selbst etwas Kopfzerbrechen bildet und mich auf den Weg brachte im weiten Internet nach einer plausiblen Antwort zu suchen. Leider mit geringen Erfolg und steht daher noch auf der TODO Liste.

Wer bereits für den Arduino nach einem Beispiel Code gesucht hat, so findet sich oft die folgende Methode mit etwas anderen Werten, die jedoch alle das selbe Ergebnis erzielen.

float calcAltitude(float pressure){
  float A = pressure/101325;
  float B = 1/5.25588;
  float C = pow(A,B);
  C = 1 - C;
  C = C /0.0000225577;
  return c;
}

Bei der Formel aus dem Dokument und das was sich aus dem Arduino Umfeld findet, fällt auf, dass die Temperatur nicht berücksichtigt wird. Das führt bedingt zu Ungenauigkeiten. Nach etwas längerem suchen fand ich die Seite Explorermagazin, auf der verschiedene Formeln vorgestellt werden. Am Ende habe ich mich für die Variante 2b entschieden.

p(h) = p(h0) * (1 - 0.00651 K/m *(h-h0)/T0)**5.255

h: Höhe (in Meter) über NN.
p(h): Luftdruck (in hPa) in Höhe h.
h0: Bezugshöhe (in Meter).
p(h0): Luftdruck (in hPa) auf Bezugshöhe
T0: Temperatur auf Bezugshöhe in Grad Kelvin (K)

Die Höhenberechnung wird in Abhängigkeit der Temperatur berücksichtigt, die hier Minus 0,651 Kelvin pro 100 Meter (-0,65K/100m) sind. Der Wert 5,255 wurde leider hier ebenfalls nicht beschrieben. Daher belasse ich diesen Punkt und stelle die Formel für die Zielumsetzung um.

image

Kommen wir zum Programmcode in C#. Leider oder auch gut so, ist dass die Formel nicht in eine Zeile programmiert werden kann und sich somit in einzelnen Schritten abgebildet werden muss.

// Zweite Variante für die Höhen Berechnung
// Luftdruck bei Meeresspiegel

private double _ph0 = 1013.25;
// Bezugshöhe
private double _h0 = 0;

Anlegen der Member Variablen mit den Werten der Höhe 0 Meter und 1013,25hPa.

Den Quellcode den ich zur Verfügung stelle, hat noch zusätzlich die herkömliche Variante der Höhenberechnung, die nur mit dem Luftdruck berechnet wird. Für den Post verbleibe ich mit der Folgenden Methode, die mit Hilfe des Luftdrucks und der Temperatur ausgeführt wird, die sich aus der Formelumstellung ergab.

// Die Höhenberechnung aus Luftdruck und Temperatur.
private double GetAltitude(double pressure, double temperature)
{

    // Luftdruck in hPa umrechnen
    pressure = pressure / 100.0;

    // aktueller Luftdruck durch Bezugshöhe und dessen Luftdruck
    double p1 = pressure / _ph0;
    // Wurzel ziehen
    double p2 = System.Math.Pow(p1, 1.0 / 5.255);
    // minus 1, Wert Invertieren
    double p3 = (p2 - 1);
    // mal Temperatur ind Kelvin
    double p4 = p3 * (temperature + 273.15);
    // durch Kelvin pro Meter
    double p5 = p4 / 0.00651;

    // Relative Höhe des Vorangehenden Luftdrucks hinzu rechnen
   return p5 + _h0;
}

Eines sollte gleich klar sein. Das richtige Ergebnis ist nur draußen zu erhalten. Luftdruck und Außentemperatur wirken zusammen. Zuletzt noch ein Hinweis zur gemessenen Luftdrucks. Der Wert ist in Pascal und muss für die Berechnung in Hektopascal umgerechnet werden, das am Anfang der Mehtode umgerechnet wird.

Effektiv erzielt die Berechnung der Höhe ähnliche Ergebnisse wie die Formel ohne Temperatur Bezug. Für den Einsatz für Quadrocopter lohnt sich der Einsatz über fünf Meter Höhe. Für genaue und präzise Erfassung der Höhe, bleibt der Einsatz von Ultraschall- oder Optischer Distanzsensoren.

Nun das war meine kleine Serie über den Luftdruck Sensor und dessen Umsetzung. Wenn Fragen sind, können diese über die Kommentar Funktion gestellt werden.

Beispiel Programm zum Herunterladen (C# und .NET Micro Framework)

Wikipedia: Luftdruck

Barometrische Höhenformel

Dienstag, 23. Juli 2013

Kreisgeschwindigkeit aus dem Sensor umrechnen (Die Zweite)

image
Von mir entwickeltes Programm zum darstellen eines künstlichen Horizontes und ein Würfel, das die Bewegungen des Sensors wieder gibt.

Im letzten Post zeigte ich eine relativ ungenaue Lösung für das Umrechnen der Winkellage. Grund hierfür ist, dass der Zeitabstand nicht verwendet wird. Als Provisorium reicht es allerdings aus.

Nun, welche Formel wird stattdessen benötigt?

image
Kreisgeschwindigkeit = Drehwinkel / Zeitspanne
image steht für die Winkelgeschwindigkeit
image steht für den Drehwinkel
image steht für die vergangene Zeit

Im nächsten Schritt muss ich die Formel umstellen, um später an das Ergebnis des Drehwinkels heran zu kommen. Der Sensor gibt pro Abfrage die Winkelgeschwindigkeit, und die Zeit wird zwischen der aktuellen Abfrage und der letzten Abfrage bestimmt.

image

Die verwendeten Werte nehme ich wie zuletzt aus dem Sensor MPU6050 mit den entsprechenden Einstellungen. Der Wert 32768 ist der Maximale Einheiten Wert der in eine Richtung gemessen werden kann. Die vergangene Zeit wird durch 1000ms dividiert, weil die Formel eigentlich für Sekunden ausgelegt ist. Die 2000.0 kommt aus der Einstellung für die Gyroskop Empfindlichkeit, also 2000°/s.

image

Daraus kann nun der Programmcode gebildet werden.

double winkel = ((((measurement - _Offset) / 32768.0) *
                                  ((double)timeelapsed / 1000.0))) * 2000.0;
measurement = Messergebnis
_Offset = Abweichungswert das den Messwert an die eigentliche Lage bringt
timeelapsed = vergangene Zeit zwischen der Abfrage und der letzten

Die Aufstellung ist für den Netduino relativ lang und sollte daher gekürzt werden. Am besten geht das auf einem Blatt Papier.

Formelumstellung
Überflüssiges kürzen

Somit sieht dann der Programmcode schon etwas schlanker aus.

double winkel = ((measurement - _Offset) * (double)timeelapsed) / 16384.0;

Der errechnete Wert zeigt den zurückgelegten Winkel. Damit daraus eine Lagebestimmung wird, muss daraus eine Integralrechnung werden, sowie bereits in meinem letzten Blogeintrag erwähnt. Damit sieht nun die Klasse folgendermaßen aus:

public class GyroscopeAxis
{
    /// Derzeitige Winkellage
    private double _Angle = 0;

    /// Ruft ab, ob der Offset gesetzt wurde oder legt diesen fest.
    private bool _IsOffset_Done = false;

    /// Ruft den Offset ab oder legt diesen fest.
    /// Wird benötigt, um die Abweichung runter zurechnen.
    private double _Offset = 0;

    /// Nimmt den aktuellen Beschleunigungswert und summiert den auf den Winkelwert
    public double UpdateAngle(double measurement, ref int timeelapsed)
    { 
        // Offsetwert festlegen, wenn nicht gesetzt.
        if (!_IsOffset_Done)
        {
            _Offset = measurement;
            _IsOffset_Done = true;
        }

       // Aktuellen Wert summieren und den Offset Wert Abziehen
        _Angle -= ((measurement - _Offset) * (double)timeelapsed) / 16384.0;

        return _Angle;
    }
}

Die Klasse für das Bestimmen der Winkellage

Anders als in meinem vorigen Blog Post habe ich die Abweichung (Offset) mit eingebracht. Dieser Wert wird beim Kalibrieren ermittelt, um die waagerechte Haltung anzugleichen. Was allerdings noch bleibt und auch nicht zu verhindern ist, sind weiterhin die Messfehler, die nur durch das Komplementieren mit der Beschleunigungsdaten gefiltert werden können.

Ameisen Simulation und andere Dinge

Wer lange sich schon mit C# beschäftig, hat sicherlich schon mal was von AntMe gelesen oder gehört. Diese Idee hatte ich aufgegriffen und mi...