Minimalste Rohdaten exportieren für Micrcontroller-Kartengerät

Meine erste naive Herangehensweise wäre hier wie folgt: Ich würde zunächst einmal über die gesamte Karte ein Raster legen, um so jeden Punkt einem Bereich zuordnen zu können. Das ist deshalb wichtig, weil man versuchen muss, die Daten am Stück einzulesen. Denn ständig neue Kleinstleseoperationen für einzelne Objekte kosten relativ viel Zeit. Da innerhalb eines solchen Bereichs unterschiedliche Datenmengen vorliegen können, sind die Bereiche von der Größe auf dem Datenträger natürlich unterschiedlich groß - es braucht also einen Index (eventuell schafft man es, den immer RAM zu halten, so dass man wirklich für jeden Bereich mit einer Leseoperation hinkommt und nicht den Index immer erst lesen muss).

Die nächste grundsätzliche Überlegung ist, ob es tatsächlich sinnvoll ist, die Punkte hart in Linien oder Flächen einzukodieren oder ob man hier mit einem Index bei der Zuordnung von Punkten zu Linien und Flächen arbeitet. Wenn Punkte häufig zu mehreren Linien gehören, ist ein Index sinnvoller, wenn es dagegen selten ist, kann man sie auch direkt in die Linien / Flächenrandzüge einbauen und hat sie eben ggf. in mehreren solchen Linien stehen, spart dafür aber die Datenmenge für die Indexierung.

Flächen und Linien haben natürlich das Problem, dass sie sich über mehrere solcher Bereiche erstrecken können. Ich würde sie hier auf die jeweiligen Bereichsgrenzen herunterbrechen (beispielsweise bei einer Linie das Stück in einem solchen Bereich speichern, welches in den Bereich fällt, ggf. mit zusätzlichen Punkten genau auf den Bereichsgrenzen - bei Flächen wird das Polygon ggf. auf den Bereichsgrenzen ergänzt, wenn sie nur zum Teil im Bereich liegen bzw. den Bereich auch vollständig ausfüllen). Damit ist das Rendern eines Bereiches immer in sich abgeschlossen.

Nächster Punkt wäre die Speicherung von Koordinaten. Es ist unnötig hier Globalkoordinaten zu speichern. Es reicht aus, wenn man Koordinaten relativ zum aktuellen Bereich speichert. Die Bereiche kann man dann global absoluten Koordinaten zuordnen und rechnet entsprechend um. Je nach Größe der Bereiche und gewünschter Präzission kommt man also mit 1 oder maximal 2 Byte für jeden Koordinatenteil aus. Dabei wäre (0,0) beispielsweise die Nordwestecke des Bereichs und (255,255) oder (65535, 65535) die Südostecke.

Dann hatte ich das gestern richtig verstanden…bin ne exportierte OSM kurz überflogen. Die ID könnte ich dann theoretisch 1:1 übernehmen. Evtl müsste ich dann als Long speichern, da “unsigned int” nur bis 65535 geht.
Viele der Daten sind ja für die Anzeige einer Karte irrelevant. Ich bräuchte nur die Nodes + Ways + Flächen. Auch wenn später ein Routing kommen sollte, werden die Rels usw. nicht benötigt.

Die Nodes selbst sind aber reine Punkte ohne einen bestimmten Typ, ist das korrekt? Also ob der Punkt jetzt nen Briefkasten, Strasse oder Wald ist…oder kann/wird das dann auch schon beim Node selbst definiert?

Eventuell reicht schon ein Quadtree mit guten Indizes. Dann sollte die passende Stelle mit relativ wenig Sprüngen erreicht werden können. Da kein Routing erforderlich ist, würde ich aber auf eine zusätzliche Indirektion verzichten und die Koordinaten (ggf. redundant) für jeden Knoten direkt speichern.

Das hängt vom Einzelfall ab. Da ein Briefkasten üblicherweise nur als Punkt und nicht als Fläche kartiert wird, stehen dessen Informationen natürlich direkt an der Node selbst. Bei Linien (Straßen) oder Polygonen (Flächen) sind die meisten Punkte dagegen üblicherweise einfach nur Koordinatenpaare, die verknüpften Informationen hängen am Way bzw. Multipolygon. Nur wenn an einem Teil der Linie selbst etwas Punktförmiges ist (beispielsweise eine Ampel auf der Straße oder ein Poller auf dem Weg), dann hat dieser Knoten der Linie wiederum selbst Informationen zu diesem Objekt.

Flächen wird - für dich - schwierig. Da gibt es 2 Modelle, die beide in den OSM-Daten drin stecken, da wir den Typ Area (noch) nicht kennen:

  • Flächen sind geschlossene Ways - aber nicht alle.
  • Flächen können auch durch Rels dargestellt werden - und da wird es wirklich heftig.

Klar, das musst du alles bei dem Preprozessing abarbeiten. Kannst du/hast du evtl. Postgis wo am laufen? Da kenne ich einen gangbaren Weg für dich.

Jo, es gibt “solitäre” Nodes mit Tags (POI, Adressen, einzelne Bäume, …) und auch Nodes ohne Tags. Beide können selbstverständlich auch in Ways (z.B. Grenzsteine) verwendet werden. Da ist die Datenhaltung in OSM identisch.

Gruss
walter

ps: ich finde, du hättest dich von Anfang an mit den Datenstrukturen von OSM auseinandersetzten sollen. Top-Down macht ja Spass, aber wenn es “unten” auf einmal klemmt, nicht mehr so viel.

HUCH: Fällt mir gerade ein. Es gibt ja inzwischen Server, die bereits Vektordaten ausliefern. Eventuell wäre das ein Ansatz für dich? Dann brauchst du dich mit den Basisdaten garnicht herumzuschlagen. Und das wäre ein hochmoderner Ansatz.

Sowas dachte ich mir schon…hm. Für die “normalen” Daten - also Strassen + Flächen - benötige ich ja Nodes ohne Typ + die Zuweisung zu Strasse usw… Der Rest würde in eine Extra-POI-Datei kommen. Je nach aktivierter Detailstufe (oder Zoom) kann man dann die POI dazu laden oder auch nicht. Würde die Dateien abspecken und die Verarbeitung beschleunigen.

@wambacher: ich bin “am Anfang” :wink: Die Idee kam mir erst am Wochenende…ich bin erst in der Planungsphase. Hardware kam gestern an - 1,8" TFT mit 160x128 Pixeln und ein 1,3" Monochrom-OLED mit 128x32 Pixeln für den Logger. Das 1,3"er ist so breit wie das 1,8"er, wie ich es gehofft habe. Soll im Gehäuse direkt darüber. Jetzt gehe ich dran erste, einfache Testdaten zu generieren und dort anzuzeigen. Daher die Überlegungen zum Datenformat uswusw.

Momentan steht mir nur der nackte Teensy 3.2 zur verfügung, der gestern ankam. Das ist ein 32 Bit Microprozessor mit einem einstellbaren Takt von 72 bzw. 96 Mhz. Der RAM beträgt hier 64 KB - das soll um vier 128KB Chips erweitert werden (0,5 MB), welche rein für die aktuellen Kartendaten der Umgebung zur Verfügung stehen werden.
Das kommt aber erst später - momentan muss ich mit den 64 KB klar kommen, was für einige Strassen und POIs ausreicht (1000 Nodes müssten 10 KB belegen, wenn ich von 2 Byte für Node-ID und je 4 Byte pro Koordinate ausgehe).

Welche Server wären das denn? :slight_smile: Es sollten dort aber alle OSM-Daten zur Verfügung stehen. Das ganze hier mache ich ja nicht nur für mich…ich liebe den Open-Gedanken, weshalb die ganze Hard+Software hier von mir komplett zur Verfügung gestellt wird. Hardware bestellen, paar Lötpunkte setzen, per USB anschließen + Software aufspielen - fertig.
Daher sollten es offizielle und langlebige Datenquellen sein. Wenn ich nach Norwegen will, dann will ich eine Norwegen-Karte runter laden können und diese für das Gerät umkonvertieren - bzw. das soll dann jeder machen können, der das Gerät nachbaut.

Sorry, Vektortiles sind (noch) nicht meine Baustelle. Ich wollte dir das nur nicht vorenthalten. Muttu mal nach Vectortiles hier im Forum oder auf wiki.openstreetmap.org suchen (veCtor und veKtor).

Gruss
walter

ps: gibt es wohl von MapQuest (?)

Sorry…irgendwie hatten wir wohl parallel gepostet, weshalb ich deinen Eintrag übersehen hatte.
Genau so meinte ich das ja mit den “Tiles” - die Karte in feste Bereiche von z.B. 1x1 km unterteilen und an den Schnittkanten die Koordinaten ergänzen. Also an jeder Linie die über den Rand hinaus geht an genau dieser Position noch einen Punkt hinzufügen.
Index im Speicher ist vorgesehen. Der interne Flash des Microcontrollers beträgt 256KB. Dort wird nur der kompilierte Code hoch geladen, der im normalfall nur wenige kb klein ist. Ich reche damit, dass ich hier mind. 100kb-150kb für einen Index frei hätte. Da der Flash nur 10.000 Schreib/Löschzyklen aushält würde man den Index nur rein laden, wenn Änderungen auf der SD-Karte festgestellt werden.

Die Koordinaten würde ich schon gerne so lassen, da POI-Dateien auch drauf können sollen - dann müsste ich diese immer beim Einlesen umrechenn. Es soll z.B. auch möglich sein, dass man z.b. Deutschland+Dänemark+Norwegen drauf lädt, welche parallel dargestellt werden sollen. Es soll ja auch weltweit funktionieren…da jedes mal die Koordinaten auf ein komisches, eigenes Format umrechnen muss nicht sein.
Der nachfolgechip Teensy 3.6, welcher noch nicht erhältlich ist, wird 256KB RAM haben, was einen Zusatzspeicher unnötig macht, da man hier locker über 20.000 Nodes speicher könnte - und das soll nur der Bereich sein in dem man sich befindet, ausgeweitet um die selbe breite/höhe in alle Richtungen. Im Normalfall ja um 1-9 km². Würde mich wundern, wenn man reine Strassen- und Fläachendarstellung nicht auf den aktuellen 64 KB RAM des Teensy 3.2 problemlos zum laufen bekommt.

Je mehr du darüber schreibst und je mehr ich darüber nachdenke, desto weniger passt das, was du planst, zu deiner Hardware.

Selbst wenn deine Vector-Tiles 1 km² groß sind, was in Großstädten auch bei Beschränkung auf Straßen und Flächen schon eine relativ große Datenmenge darstellen kann (insbesondere, wenn du noch nicht einmal die Koordinaten passend komprimieren willst), so dass du dort schon Probleme bekommen könntest, diesen Bereich auf einmal in den RAM zu laden, um ihn zu rendern (zumal für die Ausgabe auch noch Platz im RAM gebraucht wird, insbesondere wenn man auch die Umgebung zwecks flüssigem Scrolling vorrendern muss), so wären das für ganz Deutschland mehr als 350.000 Tiles. Auch wenn dein Index nur aus zwei Koordinaten (je 4 Byte) und einem Zeiger auf den Start des Bereichs (ebenfalls 4 Byte) bestünde, so wären das für Deutschland schon mehr als 4 MByte Index. Und dann gleich noch ein paar umliegende Staaten zusätzlich…

Wenn überhaupt, dann müsste der Index mehrstufig organisiert sein, um ihn in überschaubaren Größen zu halten. Aber diese Index-Bereiche können dann natürlich wiederum nur in den RAM und nicht in den Flash geladen werden, weil natürlich ständig andere Bereiche gebraucht werden. An den Bereichsgrenzen braucht es dann am besten auch die Möglichkeit, mehrere gleichzeitig im RAM zu halten. Aber der Index im RAM, die Vector-Tiles im RAM, die Ausgabe im RAM - das ist selbst mit 256 KByte RAM wenig realistisch.

MIst…jetzt war der ganze Text hier weg :frowning: Also noch mal:

Dafür schreibe ich ja das Tool, welches die Daten entsprechend filtert und optimiert. Optimiert heißt, dass Linien und Polygone vereinfacht werden.
Die einzigen Polygone sollen momentan nur Waldflächen sein - Parkplätze, Spielplätze, Grasflächen usw. sind beim Wandern und Biken irrelevant. Strassen werden auch nur als Linie übernommen. Strassenflächen können sowieso nicht zum Routing genutzt werden.

Ich habe eben mal mit dem Overpass Turbo ein wenig gespielt und die ganzen Strassen von Höxter und Umgebung exportiert (Script dazu ganz unten gepostet). Auf einer Fläche von über 25 km² sind es gerade mal 5776 Nodes bzw. 880 Ways. D.h. bei einem Speicherbedarf von 11 Byte (1 Typ, 2 ID und 8 Koordinate) wären das 63,5 KB. Wird noch die Bezeichnung mit gespeichert (falls vorhanden), sind es ein paar KB mehr. Aaber: bei einer übersicht von 4x5 km wird natürlich nicht jede Strasse benötigt bzw. angezeigt. Hier würde jedes normale Navi nur noch Landstrassen/Hauptstrassen anzeigen. Auf einem 128x160 Pixel Display (auch wenns 240x320 sein sollten) macht es keinen Sinn bei einem 4x5 km Ausschnitt jeden Pfad, Nebenstrasse usw. anzuzeigen (Overpasst nur mit primary, secondary und residential: 2553 Nodes und 431 Ways). Hier kommt wieder der Optimierer zum Zuge, welcher die Tiles entsprechend vorfiltern soll. D.h. ich will darin die Daten je nach Zoomstofe sortieren. Wird komplett rein gezoomt (sagen wir Bereich < 1 km²), dann wird die Datei komplett eingelesen und agezeigt. Das ist dann aber ein kleinerer Bereich. Von 1km² Tiles ausgehend, wären das nur 9 km², die geladen werden müssten. Das muss ich mir halt noch überlegen. Ob es eher sinn macht die Teils je Zoomstufe mehrfach anzulegen - wie das bei vorgerenderten der Fall ist - oder je Datei pro Zoomstofe die Objekte anzugeben. Bei größeren Bereichen müssten halt viel mehr Dateien eingelesen werden. Da würde es sich schon auswirken, wenn man in diesem Fall z.B. 5x5 km große Tiles hätte, welche nur Hauptstrassen + Waldflächen enthalten. Im 3D-Grafikbereich nennt sich so eine Optimierung LOD - Level of Details. 3D-Objekte, welche weiter entfernt sind, enthalten viel weniger Polygone und auch viel kleinere Texturen, damit diese nur so viel Ressourcen verbrauchen wie nötig. Das lässt sich hier auch sehr gut anwenden.

Bezüglich der Ausgabe/Ram: es wird nichts gerendert. Und schon gar nicht im Speicher. Die DIsplays werden über Grafikbibliotheken angesprochen. D:h. die Befehle gehen direkt an die Displays. Hier muss ich dann schauen, inwieweit die Performance ausreicht für das Einlesen, Berechnen und an das Display schicken - das ist die Stelle, wo ggf. ein zweiter Microprozessor als Co-Prozessor dazu kommen würde.
Die Bereiche außerhalb des sichtbaren Bereichs existieren nur als Vektorkoordinaten im RAM. Scrollt man in die Bereiche, werden die Verschiebungen an das Display weiter gegeben, indem die Zeichenkoordinanten neu berechnet werden. Danach werden die Bereiche hinter diesen nachgeladen und die davor aus dem RAM geschmissen (wenn man nach rechts in den “noch nciht sichtbaren” Bereich scrollt, dann werden die drei Bereiche ganz links aus dem Speicher geschmissen und ganz rechts drei Bereiche (oben reichts, rechts und unten rechts) in den Speicher nachgeladen.

[out:json][timeout:25];
// gather results
(
// query part for: “path”
way"highway"=“secondary”;
way"highway"=“primaray”;
way"highway"=“residential”;
way"highway"=“path”;
way"highway"=“living_street”;
way"highway"=“pedestrian”;
way"highway"=“track”;
way"highway"=“road”;
);
// print results
out body;

;
out skel qt;

War die letzten 1,5 Tage mit Barometer + GPS beschäftigt, welche nun laufen. Die Bibliothek für GPS funktionierte irgendwie nicht korrekt, weshalb ich jetzt anfange die wichtigen Strings selber zu zerlegen. Koordinate selber kam schnell, aber für Fix/Anzahl Sat usw. hat das manchmal um 5 Min gedauert. Den String zerlege ich jetzt selber und habe innerhalb einer halben Minute den Fix, Anzahl usw…
GPS-Empfänger ist ein u-Blox NEO 6M, welcher standardmäßig für Microcontroller genutzt wird. Es gibt glaube nur eine Alternative, welche aber nichit besser sein sollte. Koordinate kommt nach maximal 3 Sekunden nachdem man den Microcontroller gestartet hat- während u-Blox schon fix hatte. Wird der u-Blox vorher vom Strom genommen, so hat er nach 4-5 Sekunden bereits einen fix. D.h. hier wäre das Abfragen jede 30 Sekunden mit gut 20-25 Sekunden im Aus-Zustand möglich. Zudem ist der u-Blox selbst Batteriegepuffert, wodurch er deshalb wohl so schnell wieder den fix bekommt.
Barometer - obwohl der billigste (Bosch BMP180, 3,5€. Norma um 8-10 €) funktioniert sehr gut. Genauigkeit lag nach dem Kalibrieren bei +/- 1m. Bereits eingabaut ist ein Thermometer, damit er die Höhe korrekt berechnen kann. Habe trotzdem noch einen zweiten (digitalen) Thermometer eingeplant, welcher eine Genauigkeit um 0,5 °C hat.
Als nächstes wollte ich das 1,8" Display zum laufen bekommen, damit ich die exportierten Strassen erstmal grob zeichenn kann. So sehe ich was die an RAM verbrauchen und wie die Performace allgemein ist. Speicherchips werde ich wohl die Woche dann bestellen - endlich einen Shop gefunden, der sie nicht mit 20 € Versand verschickt. Preis liegt bei 2-2,5 € das Stück. Also 10 € für 0,5 MB RAM, wo jede Menge Kartenmaterial passen wird :slight_smile:
Wenn das ganze so halbwegs läuft, werde ich hier nen Extra-Thread erstellen. Das ganze soll ja Open laufen, weshalb es jeder auch nachbauen darf und vor allem können soll. Programmiere daher die Sensoren alle nicht fest rein, sondern sehe diese vor. Es werden dann also mehrere Sensortypen eingebaut, wo man nicht auf einen ganze bestimmten angewiesen ist.
Beim Display gibts die größte Auswahl. Ich werde 128x160 sowie 240x320 Pixel Auflösung vorsehen. Das 128er sollte Performancemäßig problemlos funktionieren. Die 240er brauchen ja schon mal 4-mal so lange zum zeichnen. Erfreulich: Arduino kompatible Displays gibt es ab ca. 1,5" bis über 3" - je nach Lust und Laune kann man sich dann das entsprechende Display aussuchen und verbauen. Ggf. muss nur hier und da mal eine Bibliothek ergänzt werden, damit ein unbekanntes Display erkannt wird.

Kosten bisher:
20 € - Teensy 2.0 Microprozessor-Platine (Hauptrechner zur Kartenberechnung + Darstellung)
7 € - Arduino Pro Mini Microprozessor-Platine (Logging, Bedienung)
10-15 € - 4 x 128 KB SRAM Speicherchips. Hauptspeicher für die aktuellen Kartendaten.
8 € - 512 KB SRAM Speicherchip + SMD-2,54mm-Adapterplatine. Hauptspeicher für die aktuellen Kartendaten.
10 € - 1,3" Monochrom-OLED mit 128x32 Pixeln für die Anzeige der Grunddaten/Logging
12 € - 1,8" TFT mit 128x160 Pixeln. 28 € kostet ein OLED Display in 1,69" mit selber Auflösung
16 € - u-Blox NEO 6M GPS
3,5 € - BMP180 Barometer+Thermometer
1 € - LDR zur Helligkeitsmessung
<10 € - Digitaler LUX-Sensor zur Helligkeitsmessung (Alternativ zum LDR)
5 € - (optional) 3-Achsen Beschleunigungsmesser + 3-Achsen Gyrometer. Erkennung von Bewegung (Start logging / Stromsparmodus) + Aufrechthaltung des GPS-Empfängers mittels Servomotor (falls gewünscht → Stromverbrauch)
2 € - Mini-Servomotor (optional - habe ich mir ausgedacht zum automatischen waagerecht halten der Antenne. Vor allem beim Fahrradfahren eine nette Geschichte)
1 € - (optional) Digitaler Thermometersensor DS18S20 (0,5°C Genauigkeit)
8-10 € - (optional) Bluetooth-Modul. Theoretisch könnte dann das Gerät als BT-GPS-Maus fungieren. Eher geplant für die Steuerung/Übertragung mit dem Smartphone.
10-15 € - Gehäuse und Kleinteile wie Taster. Das Gehäuse baue ich mir selbst. Ggf. aus leichtem Balsa-Holz, welches man in jedem Modellbaushop oder Baumarkt bekommt. Eine hübschere Alternative zum Plastikgehäuse :wink:

Falls man nur einen Logger braucht, fallen Teensy und das große Display raus. Dann hätte man einen einen GPS Logger mit MicroSD und Display. Für unter 50 €.

Die Korrektur der Barometerdaten per Thermometer kann man sich vermutlich schenken, da die natürliche Schwankung des Luftdrucks ohne Temperaturänderung nur durch Wetter größer sein dürfte.
Die Höhe an meinem Garmin mit Barometer weicht nach Rückkehr an den selben Ort nach ein paar Stunden schon um ein paar Meter ab. Bei extremen Wetterlagen (nahendes Gewitter) können das auch einige Dutzends Meter sein.
Barometrische Messung ist gut geeignet für Bestimmung von Höhenänderungen, da viel ruhiger als das GPS-Höhen-Gezappel, aber auch nach Kalibrierung nicht all zu lange für absolute Höhen.

verstehe zwar immer noch nicht, wie du so rendern willst, aber zumindest einen Typo solltest du fixen:

way[“highway”=“primaray”] —> way[“highway”=“primary”]

Gruss
walter

@seichter: Temperatur ist mit im Barometer verbaut…die muss man abrufen bzw. mit übergeben, damit er die Höhe berechnet. Ich rechne nichts, sondern bekomme schon einen fertigen Wert :slight_smile:

@wambacher: Ups…danke :wink: Wenns ich was am laufen hab, dann zeig ichs natürlich :slight_smile:

Bei den Straßen fehlen ganz wesentlich noch “footway” und “cycleway”. Die Koordinaten der Stützpunkte brauchst Du ja auch. Außerdem kann man das mit regulärem Ausdruck noch wesentlich kompakter ausdrücken:

[out:json];
way
  (51.75338994968633,9.32962417602539,51.79396552788619,9.408760070800781)
  ["highway"~"(path|track|footway|cyclewa|road|residential|pedestrian|unclassified|tertiary|secondary|primary)"];
(._;node(w););
out skel qt;

Dass die Ausgabe als OSM-xml möglich ist, weisst Du ja sicher. Für das Präprozessing wäre das mein bevorzugtes Format.

Danke! :slight_smile: Klar - habs natürlich als OSM XML exportiert.
Display funktioniert schon mal. Kann mich nun also an den XML-Konverter machen.

Mit deiner Abfrage sinds 7678 Nodes und 1259 Ways. Also nicht vieel mehr. Und das vor der Optimierung. Denke, dass ich einige Nodes wegoptimiert kriege.
Auswahl nur nach pri+sec ergibt nämlich 487 Nodes auf 106 Ways - das sind aber nur drei ziemlich simple Strassen. Viele unnötige Punkte dabei, die weg können.