GPS Daten

Moin zusammen,

ich würde gerne ein Display wie in dem folgenden Beispiel prgrammieren.

Mein Knackpunkt ist der Bereich links oben. Weiß jemand von Euch, welche Daten vom GPS dafür herangezogen werden und wie diese dann auf den Kreisen positioniert werden?

Die Daten des GPS Moduls werte ich mit einem Arduino aus.

Gruß Kai

BlackMizi: Mein Knackpunkt ist der Bereich links oben. Weiß jemand von Euch, welche Daten vom GPS dafür herangezogen werden und wie diese dann auf den Kreisen positioniert werden?

Links oben sieht ja wohl nach einer Kompaßrose aus und da werden bestimmt die Daten der $GPGSV Datensätze (GPS Satellites in view) zur Darstellung verwendet werden.

Ein Punkt zentral in der Mitte wäre ein Satellit direkt über Dir mit Elevation in Degrees= 90°, und je weiter weg vom Mittelpunkt, desto tiefer steht der Satellit. Äußerer Kreis = Satellit am Horizont.

P.S.: Aus denselben Datensätzen ziehst Du ja wohl auch die Signalstärke für das Balkendiagramm darunter.

Danke Dir für die Info.

Hast Du eine Idee, wie man eine Kompaßrose programmiert?

BlackMizi: Danke Dir für die Info.

Hast Du eine Idee, wie man eine Kompaßrose programmiert?

Eine Kompassrose ist erstmal ein einfacher Kreis, den Du umlaufend mit einer gedachten Winkelgradskala versiehst. So wie oben auf dem von Dir geposteten Bild. Oder hier in ASCII-Art Darstellung:

    N
    ____
   /    \ 
  /      \
W|        |O
 |        |
  \      /
   \____/
     S

Norden ist oben, Süden ist unten, die 4 Hauptrichtungen in Winkelgraden sind: N= 0° = 360° O= 90° S= 180° W= 270°

Wenn das Display sehr groß und sehr hochauflösend ist, kannst Du die Anzeige ausschmücken wie es Dir gefällt, z.B.: |500x499

Und um so etwas auf einem grafikfähigen Display auszugeben, wirst Du Dich wohl darum kümmern müssen, wie Du auf Deinem Display einen Kreis um einen vorgegebenen Mittelpunkt zeichnen kannst.

Und um dann die Satelliten mit kleinen Minikreisen in den großen Kreis einzuzeichnen, mußt Du Dir über sin/cos den Abstand in der Projektion ausrechnen z.B.: - 90° Elevation des Satelliten, Satellit direkt über Dir, wird im Mittelpunkt eingezeichnet) - 0° Elevation des Satelliten, Satellit steht am Horizont, wird am Rand des großen Kreises eingezeichnet

Und der Richtungswinkel, unter dem der Satellit gepeilt wird, steht direkt im $GPGSV Datensatz drin, den Du vom GPS-Empfänger bekommst.

Wenn man das als Bitmap speichert kann nichts mehr "darüber" angezeigt werden, oder?

Ähnliches gibt es ja schon zusehen:

https://www.youtube.com/watch?v=x64iNRlT2WY

http://playground.arduino.cc/uploads/Code/GLCD_Documentation.pdf

Du kannst erst den Hintergrund zeichnen und dann die Satelliten darüber

Etwas schwieriger wird es wenn man den Satelliten bewegen muss. Da muss man erst mal die aktuelle Position schwarz überzeichnen. Da man dabei aber eventuell Teile des Hintergrunds mit löscht muss man den dann neu zeichnen und dann den neuen Satelliten. Das geht bei den zwei. drei Kreisen aber sehr schnell.

Scherheinz: Wenn man das als Bitmap speichert kann nichts mehr "darüber" angezeigt werden, oder?

Irgendwo irgendwas drübermalen geht immer.

Aber wenn Du eine animierte Bildschirmdarstellung so aufbaust: - schicke ein nacktes Bitmap zum Bildschirm - male irgendwas drüber dann ergibt das in der Anzeige ein heilloses Geflacker

Eine weitgehend flackerfreie Darstellung animierter Inhalte bekommst Du nur, wenn Du stets in einem nicht angezeigten Bildschirm herummalst.

Also entweder: - Im RAM-Speicher Platz für das Bild reservieren - Bitmap hineinkopieren - herummalen wie gewünscht - fertig gemaltes Bild zum Display senden

Es gibt auch Displays die einen doppelten Bildschirmspeicher haben, bestehend aus einem inaktiven und einem aktiven Bild. Das aktive Bild wird zur Zeit jeweils dargestellt. Aber auf beiden Bildern kann man malen.

Die generelle Vorgehensweise wäre dann - zeige das aktive Bild an - schalte zum Malen auf das nicht-aktive Bild um - lade das Bitmap - male im Bitmap herum - vertausche nun das aktive und das nicht-aktive Bild D.h. Du könntest dann immer (flackerfrei) im gerade nicht angezeigten Bildschirm herummalen, und wenn fertig, schaltest Du blitzschnell die Bildseite um, das fertige Bild in der Anzeige wechselt auf Schlag, und Du machst dann damit weiter, dass Du auf der gerade nicht angezeigten Bildshchirmseite das nächste Bild malst.

Da ich allerdings auf Mikrocontrollern nicht mit grafikfähigen Displays arbeite und Animationen ohnehin nicht mein Spezialgebiet sind, kann ich Dir zu Hardware und verfügbaren Libraries für Arduino leider keine Tipps geben.

Für Double Buffering ist auf den AVRs aber i.d.R. nicht genug RAM vorhanden. Was man machen könnte ist nur 1 Bit pro Pixel zu nehmen (an/aus, monochrom). Dann kann man in einem Byte 8 Pixel abspeichern. Das wird aber alles mit den Standard Libraries nichts. Die schreiben direkt auf das Display. Man kann natürlich die vorhandenen Methoden als Basis nehmen und anpassen. Dann muss man nicht die Zeichen-Algorithmen neu erfinden.

Ich habe auf einem 3,2" ein Menü in dem ich mit +/- Werte verändere auf der Basis eine Kurve anzeige die sich mit dem Ändern der Werte verschiebt. Im Hintergrund ist ein Koordinaten-Gitter. Ja, es flackert natürlich etwas, aber ich kann damit leben. Wobei das bei dieser Anwendung weit deutlicher wird.

Moin zusammen,

danke für die vielen Hinweise. Nicht das Zeichnen der Kreise ist mein Problem, sondern die Matematik dahinter. :( Vielleicht weiß ja jemand von Euch, wie ich das

Und um dann die Satelliten mit kleinen Minikreisen in den großen Kreis einzuzeichnen, mußt Du Dir über
sin/cos den Abstand in der Projektion ausrechnen z.B.:
- 90° Elevation des Satelliten, Satellit direkt über Dir, wird im Mittelpunkt eingezeichnet)
- 0° Elevation des Satelliten, Satellit steht am Horizont, wird am Rand des großen Kreises eingezeichnet

Und der Richtungswinkel, unter dem der Satellit gepeilt wird, steht direkt im $GPGSV Datensatz drin, 
den Du vom GPS-Empfänger bekommst.

in eine Formel / Funktion gieße.

Gruß und Dank Kai

BlackMizi: Vielleicht weiß ja jemand von Euch, wie ich das ... in eine Formel / Funktion gieße.

Was Dir fehlt, sind vermutlich ein paar Grundlagen in Trigonometrie. Evtl. hilfreich: https://de.wikipedia.org/wiki/Trigonometrie

Gruß

Gregor

Das rettet mich leider nicht! :(

BlackMizi: Das rettet mich leider nicht!

Dann musst Du Dein Vorhaben wohl begraben (oder darauf hoffen, dass ein Anderer Deine Arbeit erledigt).

Gruß

Gregor

Wenn Programmier, sowie erweiterte/fortgeschrittene Mathekenntnisse nicht vorhanden sind, wird das Projekt für dich so nicht realisierbar sein. Wobei hier die Trigonometrie eher zu den Basics gehört.

Arbeite dich erst einmal in die Programmierung ein, später kann man auch die Mathekenntnisse nachholen und das Projekt beginnen.

Du hast die Koordinaten des Mittelpunkts der Kreise und den Winkel (aus dem Datensatz). Die Distanz (Hypotenuse) bekommst du aus der Elevation per Dreisatz wenn ich das richtig sehe. Daraus kannst du die zwei anderen Strecken berechnen. Diese werden dann auf die Koordinaten des Mittelpunkts gerechnet.

Das einzige größere Problem das ich sehe dass man den Winkel erst mal auf 0° < alpha < 90° zurechtstutzen muss, damit die Rechnung funktioniert. Danach kann man entweder eine Fallunterscheidung je nach Quadrant machen um auf die End-Koordinaten zu kommen. Oder man rotiert die errechneten Koordinaten einfach um den Mittelpunkt (Stichwort: Koordinatentransformation).

Vielleicht geht es auch einfacher…

Wenn ich weiter darüber nachdenke ist das glaube ich doch nicht nötig da sich ja das Vorzeichen von Sinus und Kosinus mit dem Quadranten ändert :)

Was du generell unterscheiden musst ist das mathematische System der Koordinaten und die Koordinaten auf dem TFT. Am einfachsten rechnet man hier immer erst mal rein mathematisch mit M als Nullpunkt des Koordinatensystems. Dann schreibst man sich zwei Konvertierungsfunktionen für X und Y die die mathematischen Koordinaten auf TFT-Koordinaten umrechnen. Bei Y muss man da aufpassen da auf dem TFT (0, 0) oben links ist.

Serenifly: ... ziemlich viel ...

Hybsche Zeichnung!

Um die Winkelfunktionen zu verstehen, hilft es IMO sehr, sich vorzustellen, dass es um ein rechtwinkliges Dreieck geht, und dass man die Horizontale mit sin() berechnet und die Vertikale mit cos() (bzw. umgekehrt, je nachdem). Im Wikipedia-Artikel ist das IMO ziemlich umständlich beschrieben. Ich würde das Lesen ab https://de.wikipedia.org/wiki/Trigonometrie#Definition_der_trigonometrischen_Funktionen_am_Einheitskreis empfehlen. Wenn man mit Sinus und Cosinus einen Kreis malen kann, ist das zumindest schonmal nicht schlecht.

Gruß

Gregor

MSPaint :)

Ist halt nicht das einzige. Wenn man die zwei Strecken hat, dann muss man diese auf die Koordinaten des Mittelpunkts der Kreise rechnen. Und dann muss man diese Koordinaten auf TFT Koordinaten umrechnen. Darüber kann man sich auch den Kopf zerbrechen. Da hilft es wenn man den ganzen Bildschirm erst mal als einfaches Koordinatensystem betrachtet und direkt Werte plottet ohne was zu rechnen.

Was ich da oben erst geschrieben hatte braucht man doch nicht. Da hat mir genau dieses Bild einen Strich durch die Rechnung gemacht. Die Vorzeichen der errechneten Strecken ändern sich ja durch sin()/cos() automatisch je nach dem in welchem Quadranten man ist.

Die Koordinaten umrechnen kann man so machen:

inline int get_x_coord(int x) __attribute__((always_inline));
int get_x_coord(int x)
{
   return x + OFFSET_X;
}

inline int get_y_coord(int y) __attribute__((always_inline));
int get_y_coord(int y)
{
   return 239 - y - OFFSET_Y;
}

Das ist für ein 320*240 Display bei mir. Deshalb 239. Und OFFSET_X/Y ist um den Nullpunkt woanders auf dem TFT zu legen. Sonst ist (0/0) unten links. Da könnte man z.B. (100/100) nehmen. Dann wird der mathematische Punk (0/0) auf dem Display auf (100/139) gezeichnet.

BlackMizi:
Das rettet mich leider nicht! :frowning:

Was haste denn in Schule oder Studium so an Mathe gelernt?
Minimum für so eine Rechnung wäre wohl ein erfolgreich absolvierter “Leistungskurs Mathe” auf einer gymnasialen Oberstufe. Besser wären vielleicht noch ein, zwei Semester Studium in einem ingenieurwissenschaftlichen Fach obendrauf.

Die NMEA-Datensätze bekommst Du ausgelesen, so dass Du die Satellitendaten für Elevation und Azimuth vom GPS-Empfänger bekommst?

Ich habe mal ein paar Beispieldaten in ein Array gepackt und gerechnet:

/*
Example data for 11 satellites in view, received NMEA sentences:
$GPGSV,3,1,11,03,03,111,00,04,15,270,00,06,01,010,00,13,06,292,00*74
$GPGSV,3,2,11,14,25,170,00,16,57,208,39,18,67,296,40,19,40,246,00*74
$GPGSV,3,3,11,22,42,067,42,24,14,311,43,27,05,244,00,,,,*4D
*/

struct sat_t {byte id; byte elevation; int azimuth; byte snr;};


sat_t sats[]={  // satellite data extracted from $GPGSV sentences
  {3,03,111,0},
  {4,15,270,0},
  {6,01,10,0},
  {13,06,292,0},
  {14,25,170,0},
  {16,57,208,39},
  {18,67,296,40},
  {19,40,246,0},
  {22,42,67,42},
  {24,14,311,43},
  {27,5,244,0},
};

/*
sat_t sats[]={  // some different test data
  {3,0,0,00},
  {4,0,90,00},
  {6,0,180,00},
  {13,0,270,00},
  {14,85,0,00},
  {16,85,90,39},
  {18,85,180,40},
  {19,85,270,00},
  {22,42,67,42},
  {24,14,311,43},
  {27,5,244,00},
};
*/


#define NUMSATS 11

struct point_t {int x; int y;};

point_t center={100,100}; // Mittelpunkt der Kompassrose
int compassRadius=90; //  Radius der Kompassrose

void setup() {
  Serial.begin(9600);
  Serial.println();
  Serial.println("Calculate satellite positions in compass circle:");
  Serial.println();
  for (int i=0;i<NUMSATS;i++)
  {
    float fCenterDist=compassRadius;
    fCenterDist *= cos(radians(sats[i].elevation));
    int satPointX = lround(center.x + fCenterDist * sin(radians(sats[i].azimuth)));
    int satPointY = lround(center.y + fCenterDist * cos(radians(sats[i].azimuth)));
    Serial.print("Sat ID:\t");Serial.print(sats[i].id);
    Serial.print("\tElev:\t");Serial.print(sats[i].elevation);
    Serial.print("\tAzim.:\t");Serial.print(sats[i].azimuth);
    Serial.print("\tpX:\t");Serial.print(satPointX);
    Serial.print("\tpY:\t");Serial.print(satPointY);
    Serial.println();
  }
}

void loop() {
  // put your main code here, to run repeatedly: 
  
}

Die Mittelpunktkoordinaten (100, 100) und der Radius der Kompassrose (90) stehen als Zahlenkonstanten im Quelltext und sind daher leicht anpassbar.

Annahme: Der Nullpunkt (0,0) sei in der linken, unteren Ecke des Bildschirms.

Ausgerechnet werden dann für alle Satellitendaten im Array die Koordinaten der Punkte, an denen diese in der Kompassrose einzuzeichnen wären.

Ohne Gewähr für die Richtigkeit.

Und wenn sich an Deinem Bildschirm der Koordinaten-Nullpunkt (0,0) in der linken oberen Ecke befindet, mußt Du die Koordinaten für den Bildschirm ein wenig umrechnen, sonst erhältst Du eine gespiegelte Ansicht.

Naja, Sinus und Cosinus auf dem Arduino macht nicht wirklich Spaß. Ich würde da eher ein Vieleck statt eines Kreises nehmen bzw. eine Tabelle mit vorher ausgerechneten Daten (LUT - "look up table"). So ab ca. 25 ... 30 Stützpukten sieht man auf diesem Minidsplay nicht mehr, dass es kein Kreis ist ...

qualidat: ... Sinus und Cosinus auf dem Arduino macht nicht wirklich Spaß.

Das verstehe ich jetzt nicht. Du musst das ja nur tippen, nicht rechnen.

qualidat: Ich würde da eher ein Vieleck statt eines Kreises nehmen bzw. eine Tabelle mit vorher ausgerechneten Daten (LUT - "look up table"). So ab ca. 25 ... 30 Stützpukten sieht man auf diesem Minidsplay nicht mehr, dass es kein Kreis ist ...

So ein „Fake“ ist allerdings auch eine Möglichkeit.

Gruß

Gregor