home     Inhaltsverzeichnis
erste Version am 05.07.2016
letzte Änderung am 12.07.2016

Raspberry Pi als GPS-Tracker
Seite 3


Track-Visualisierung mit Anzeige von Zusatzdaten

Wenn ich nun schon die Geschwindigkeit und die Anzahl genutzter Satelliten in den Track mit reinschreibe, dann möchte ich die auch in der OpenStreetMap-Ansicht angezeigt bekommen.
Meine Suche hat mich erstmal hierher geführt. Von dort aus hatte ich dann bald diese Seite entdeckt, auf der schon fast genau das von mir gewünschte Verhalten als Beispiel gezeigt wird.
Allerdings habe ich nicht die hinreichenden Kenntnisse in JavaScript, um das so umzubauen, dass die angezeigten Daten aus einem Tag kommen, welches sich auf fünfter Ebene im XML befindet. Daher habe ich kurzerhand ein Python-Script gebaut, das eine vom RasPi-Tracker geschriebene GPX-Datei so erweitert, dass diese von dem JavaScript nach meinen Vorstellungen verarbeitet werden kann.

Hier die leicht modifizierte Beispiel-Seite, in der ein kurzes Gassi-gehen mit dem Hund samt Geschwindigkeits-Anzeige anhand dieser GPX-Datei auf die OSM-Ansicht gemappt wird.
Um die Geschwindigkeit an einem Punkt angezeigt zu bekommen, muss die Maus über den Punkt bewegt werden. Links unter der Karte erscheint daraufhin die Geschwindigkeit und die Satelliten-Anzahl. BTW: die Anzahl der genutzten Satelliten ist als erster Hinweis zur Genauigkeit einer Position gedacht.


Wardriving einrichten

Nun habe ich mal ein bischen zum Thema Wardriving recherchiert.
Offenbar sollte das WLAN-Device dazu den sog. Monitor Mode beherrschen.
Und der EDIMAX EW-7811UN mit seinem RTL8188CUS-Chipsatz hat da wohl gewisse Schwierigkeiten:
dede@rp3-1:~ $ sudo iw dev wlan1 set monitor none
command failed: Operation not supported (-95)
Bei dem im RasPi3 integrierten WLAN-Chip kommt die selbe Meldung.

Weil es der Reichweite sicherlich zugute kommen wird, wenn das WLAN-Modul mit einer externen Antenne ausgestattet ist, habe ich mir eben mal drei USB-WLAN-Module mit RT5370-Chipsatz bestellt. Einen EP-N8531 (ohne ext. Antenne), einen tinxi® Mini USB 2.0 150M 802.11 n/g/b WiFi und einen Adattatore TW-WIFI-5370. Und außerdem noch ein 15cm langes USB-Verlängerungskabel, um den Stick samt der Antenne besser in der Fahrradtasche verstauen zu können.

Zum Erschnuppern der aktuell verfügbaren WLAN's gibt es Kismet.
Installation mit:
sudo apt-get install kismet
cd
mkdir usbstick/wardriving
chmod 777 usbstick/wardriving

sudo nano /etc/kismet/kismet.conf
und in kismet.conf setzen:
logprefix=/home/dede/usbstick/wardriving
ncsource=wlan1

Heute vormittag wurde (von Hermes) der tinxi-Adapter geliefert.
Leider hat es damit nicht wie erhofft funktioniert.
Daher habe ich die Version von kismet aus den Repos wieder deinstalliert, um es in aktuellster Version selbst zu compilieren.
wget https://www.kismetwireless.net/code/kismet-2016-07-R1.tar.xz
tar xf kismet-2016-07-R1.tar.xz
cd kismet-2016-07-R1/

sudo apt-get install ncurses-dev libpcap-dev libnl-dev

./configure

make dep
make
sudo make install
sudo make suidinstall

sudo usermod -a -G kismet dede

Damit lief es aber immer noch nicht.
Irgendwann ist mir dann aufgefallen, dass die MAC-Adressen der WLAN-Devices komisch aussehen. Also konkret die Zuordnung zum Interface.
Kurzum: das onboard-WLAN wird zu wlan1, wenn bei Hochfahren der USB-WLAN-Stick steckt ... welcher dann wlan0 wird.
Liegt vielleicht am Wert der MAC-Adresse (kleinere zuerst) - oder daran welcher zuerst gesehen wird.
Trotz entsprechender Anpassungen wollte der tinxi-Adapter immer noch nicht so, wie ich wollte.

Nachmittags kam (per DHL) der WLAN-Stick TW-WIFI-5370.
Und mit dem lief es dann auf Anhieb, nachdem ich die Konfiguration von hostapd, dnsmasq und /etc/network/interfaces ja bereits auf wlan1 umgebogen hatte.
Beim selbst übersetzten kismet liegt die Konfiguration unter /usr/local/etc/kismet.conf und enthält folgende Anpassungen:
logprefix=/home/dede/usbstick/wardriving
ncsource=wlan0:type=rt2800usb
writeinterval=60

Bezüglich des obigen Vortests kommt bei gestecktem TW-WIFI-5370 jetzt übrigends:
dede@rp3-1:~ $ sudo ifconfig wlan0 down
dede@rp3-1:~ $ sudo iw dev wlan0 set monitor none
dede@rp3-1:~ $ iwconfig wlan0
wlan0     IEEE 802.11bgn  Mode:Monitor  Tx-Power=20 dBm  
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Power Management:off

Zwischenzeitlich hatte ich noch die Idee, mittels eines regelmäßig laufenden
sudo iwlist wlan0 scan
ebenfalls an die gewünschten Daten zu kommen.
Das funktioniert sogar, wenn der AccessPoint auf dem selben Interface mit dem Smartphone spricht.
Käme also ohne zusätzlichen WLAN-Stick aus.
Aber nun habe ich ja einen mit richtiger Antenne und will den dann auch nutzen.


mein erstes Wardriving in Wees

Nach ein paar ersten Vortests habe ich den kismet_server ebenfalls per crontab @reboot starten lassen, habe alles in die Fahrradtasche gequetscht und eine Tour durch den Osten von Wees gemacht.
Parallel zum GPX-Track wurde nun vom kismet_server eine .netxml-Datei erzeugt.

Wieder zuhause angekommen wurde direkt eine angepasste Version von dem Python-wpt-Erzeuge-Script gebastelt.
Ich wollte das Ergebnis schnell auf der Karte sehen.
Und hier die bekannte Visualisierung mit dem angepassten Input, der jetzt WLANs statt Geschwindigkeiten anzeigt (vorsichtshalber mal anonymisiert, um senilen ...sagen wir mal... Menschen keinen abstrusen Klage-Grund zu geben).


Analyse der beim Wardriving ermittelten Daten

Mein Script von gestern hat die .netxml-Datei geparsed und jeweils einen wpt-Satz pro <wireless-network> geschrieben.
<wireless-network ....>
  <SSID ....>
    <encryption>c.1</encryption>
    <encryption>c.2</encryption>
    <encryption>c.n</encryption>
    <essid ....>ssid</essid>
  </SSID>
  <BSSID>bssid</BSSID>
  <gps-info>
    <avg-lat>lat</avg-lat>
    <avg-lon>lon</avg-lon>
  </gps-info>
</wireless-network>
Erste Auffälligkeit bei obiger Visualisierung der Daten ist, dass die Positionen der WLANs dann eher nicht direkt auf der Straße liegen, wenn drumrum gefahren wurde. Das WLAN also aus mehreren Richtungen gesehen wurde.
Besonders extrem ist dies an dem WLAN "RaspAP" zu erkennen. Das liegt ziemlich zentral in der Mitte des von mir abgefahrenen Weges. Praktisch ist es aber immer mitgefahren, weil es ja das onboard-WLAN-Interface des RasPi3 ist.

Das kann also nur bedeuten, dass der kismet_server einmal in die .netxml-Datei geschriebene wireless-network-Sätze wieder anfasst bzw. korrigiert, wenn er ein WLAN erneut sieht (und daher werde ich das writeinterval@kismet.conf auch wieder auf seinen Defaultwert von 300 setzen).
Die Positionen werden umso genauer, umso öfter sie aus unterschiedlichen Positionen gesehen werden. Das erscheint logisch, denn schließlich kann ich auf einer Geraden (also wenn ich nur einmal daran vorbei fahre) eher nicht so gut triangulieren, wie auf einer Fläche.

Nun stellt sich aber die Frage, was man tun kann, um die Koordinate eines WLAN nachträglich zu verbessern - auch wenn der kismet_server zwischendurch runtergefahren war.
Die Antwort könnte in der von Kismet ebenfalls geschriebenen .gpsxml-Datei liegen.
Die .gpsxml-Datei von gestern enthält 13.558 Zeilen. In 2.214 Zeilen steht die BSSID meines RasPi-Interfaces und die sehen beim ersten und letzten Eintrag so aus:
<gps-point bssid="B8:27:EB:65:BA:64" source="B8:27:EB:65:BA:64" time-sec="1468080920" time-usec="640333" lat="54.805153" lon="9.524595" spd="2.727000" heading="195.610001" fix="3" alt="51.799999" signal_dbm="-17" noise_dbm="0"/>

<gps-point bssid="B8:27:EB:65:BA:64" source="B8:27:EB:65:BA:64" time-sec="1468082575" time-usec="497493" lat="54.805099" lon="9.524930" spd="0.885000" heading="175.610001" fix="3" alt="58.900002" signal_dbm="-19" noise_dbm="0"/>
Würde man nun all diese 2.214 Sätze nehmen, jeweils "lat" und "lon" auslesen und daraus den Mittelpunkt bilden, sollte das zu den Daten gemäß .netxml-Datei passen. Denen hier:
<gps-info>
  <min-lat>54.804306</min-lat>
  <min-lon>9.517880</min-lon>

  <max-lat>54.809582</max-lat>
  <max-lon>9.529642</max-lon>

  <avg-lat>54.806016</avg-lat>
  <avg-lon>9.524307</avg-lon>
</gps-info>
Korrekterweise müsste wahrscheinlich auch der jeweilige Wert von signal_dbm mit in die Berechnung einbezogen werden.
Und was es mit diesem heading auf sich hat, muss ich erstmal rausfinden. Die Werte liegen zwischen 0 und 360. Wird also irgend ein Winkel sein.

Jetzt werde ich aber erstmal ein mir bekanntes stationäres WLAN untersuchen.
Der Name lautet FreifunkWees01.1 (http://ffw), die BSSID lautet "64:66:B3:FA:34:98".
Zur dieser BSSID gibt es 364 Sätze in der .gpsxml-Datei.
Wenn ich die alle in die Karte mappe und jeweils signal_dbm und heading als Wert anzeige, kann ich daraus ja vielleicht irgendeine Erkenntnis ableiten.
Sieht so aus:

Screenshot


Leicht zu erkennen sind die zwei Häufungen.

Die rechte Häufung ist entstanden, weil ich die Fahrradtasche mit dem RasPi3 als erstes zum "Satelliten finden" vor die Haustür gelegt habe. Erst danach habe ich die restliche Sachen zusammengesammelt, um dann schließlich neben dem Carport (linke Häufung) die Fahrradtasche ans Fahrrad zu friemeln.

Eigentlich nützt mir das so nix.

Ich sollte das wiederholen und den RasPi3 erst dann einschalten, wenn ich außerhalb des Sende-Bereichs von "FreifunkWees01.1 (http://ffw)" bin.


BTW: der aufmerksame Leser (hihi) mag sich fragen, warum hier Häufungen auftreten, bei den unter erstes Wardriving in Wees angezeigten Daten aber nicht. Das liegt daran, dass ich diese Daten etwas gekürzt habe. Konkret sind alle trkpt-Sätze am Anfang und am Ende der Datei gelöscht, bei denen speedkmh==0 und sat<5 galt. Daher enthält die gpx-Datei die zwei Häufungen jetzt nicht mehr - in der gpsxml-Datei sind sie aber noch enthalten.


Nun also die eben angedachte Wiederholung...erstmal für genug Entfernung sorgen, dann RasPi3 einschalten und auf Satelliten warten.
Ein entsprechender Rundgang hat 103 Koordinaten für die BSSID "64:66:B3:FA:34:98" geliefert und sieht so aus.
Das Attribut "heading" ist offenbar der Winkel der Bewegungsrichtung zur Himmelsrichtung - und nützt mir hier nix.
Und die Dämpfung hat keine sonderliche Varianz. Nützt also wohl auch eher wenig.

Todo1: auch der kismet_server darf erst nach Setzen der Uhrzeit gestartet werden, sonst passt der Name der erzeugten Dateien nicht.

Todo2: diese vermeintlich offenen WLANs mit dem Namen "Vodafone Hotspot" sollten noch irgendwie als "eingeschränkt offen" gekennzeichnet werden. Beim "auf Satelliten warten" habe ich aus Langeweile das Smartphone da eingebucht und landete nur auf einer Logon-Seite. Vielleicht ließe sich die diesbezügliche Überprüfung mit "Verbinden + ping 8.8.8.8" automatisch und ad hoc implementieren. Eine Frage wäre allerdings, welches Interface diese Prüfung machen sollte. Und die nächste Frage wäre, ob das zeitlich überhaupt reicht, wenn ich mit dem Fahrrad mit 25km/h daran vorbei fahre.


Das Zentrum mehrerer Koordinaten bestimmen

Ich bin immer noch auf der Suche nach einer Möglichkeit, WLAN-Positionen nachträglich verbessern zu können. Bei meinem ersten Wardriving bin ich z.B. nicht an der Nordstraße entlang gefahren. Hätte ich das getan, wären sicher einige der Punkte, die jetzt mitten auf der Straße Peerekopp liegen, etwas südlicher (also innerhalb von Häusern) gelandet.
Fahre ich nun aber ein paar Tage später die Nordstraße entlang, müsste ich bei dieser Tour sicher auch nochmal durch Peerekopp fahren, um verbesserte WLAN-Positionen zu bekommen. Außerdem stellt sich die Frage, wie ich demnächst das westliche Wees und Wees-Bahnhof zufügen sollte. Duplikate ließen sich ja noch ausblenden, aber was ist, wenn ein und die selbe BSSID an unterschiedlichen Koordinaten erscheint - welche davon soll in der Karte landen...?

Also muss ich die Rohdaten (aus der .gpsxml-Datei) vorhalten und die WLAN-Positionen daraus selbst berechnen.

Im ersten Ansatz habe ich für die 103 Koordinaten von dem Rundgang jeweils Summen für lat und lon gebildet und beide final durch 103 geteilt.
Dabei kam exakt die Koordinate heraus, die vom kismet_server als "average" gemeldet wurde.... :-)
Eigentlich hätte ich schon erwartet, dass dort etwas mehr Aufwand betrieben worden wäre, um die Koordinate eines APs zu bestimmen.
Aber vielleicht ist es ja auch so gedacht, dass entsprechende Visualisierungs-GUIs die Koordinaten nicht aus der .netxml-, sondern aus der .gpsxml-Dateien lesen, um damit dann genaue Koordinaten berechnen zu können.

Der erste Schritt zur Verbesserung könnte die Einbeziehung der jew. Dämpfung sein.
Deren Werte aus dem Rundgang gehen von -61 bis -91. Laut Wikipedia also von 1nW bis zu 1pW. Somit Faktor 1000 dazwischen.
Die Koordinate mit -61 befindet sich fast auf Höhe des AP, 31 Meter davon entfernt. Lediglich das Dach mit seiner Isolierung stört die direkte Sichtverbindung.
Bei der Koordinate mit -91 befinden sich 91 Meter und locker drei Häuser zwischen AP und RasPi3.
Eine Koordinate mit geringer Dämpfung muss mit mehr Gewicht ins Ergebnis eingehen, als eine mit hoher Dämpfung.
Wenn die Koordinate mit -91 einmal ins Ergebnis eingeht, muss die Koordinate mit -61 entsprechend 1000 mal ins Ergebnis eingehen.
Eine mit -70 dann 100 mal, eine mit -80 folglich 10 mal.
Leider landete die Ergebnis-Koordinate damit fast direkt an den Messpunkt-Koordinaten mit Dämpfung=-61.
Na gut, Faktor 1000 erschien mir ohnehin etwas arg viel für einen Unterschied von 30 dBm.
Aber auch bei deutlich kleineren Faktoren war das Ergebnis nicht viel brauchbarer.
Fazit: die Einbeziehung der Dämpfung macht den Mittelwert-Algorithmus auch nicht besser.

Also nächster Ansatz: den Polygon-Mittelpunkt (oder eher Polygon-Schwerpunkt) berechnen.
Und da sieht das Ergebnis schon sehr viel schöner aus:

Screenshot
Interessant sind die drei Punkte in der Mitte.

Der obere Punkt ist die vom kismet_server ermittelte Koordinate des AP und damit ist er gleichzeitig die Koordinate, die herauskommt, wenn die Summe aller gemessenen Koordinaten durch deren Anzahl geteilt wird.

Der untere Punkt ist die echte Position des AP.

Der mittlere Punkt zeigt den Polygon-Mittelpunkt. Er liegt zwar vier bis fünf Meter über der realen Position, aber mehr ist wohl nicht zu wollen, ohne die Dämpfung in die Rechnung mit einfließen zu lassen. Und immerhin bekomme ich ein besseres Ergebnis, als vom kismet_server.



Mit diesen Erkenntnissen sollte sich ein Programm bauen lassen, das
  1. alle erkannten BSSIDs (<BSSID>), WLAN-Namen (<essid>) und Verschlüsselungs-Infos (<encryption>) aus der .netxml-Datei in eine Datenbank-Tabelle A schreibt.
  2. alle Koordinaten (<lat> und <lon>) aus der .gpsxml-Datei in eine Datenbank-Tabelle B schreibt und die Tabelle A über BSSID referenziert.
Ein weiteres Programm könnte nun daraus pro BSSID den Polygon-Mittelpunkt berechnen und dies zusammen mit WLAN-Namen und Verschlüsselungs-Info in einen wpt-Satz schreiben.
Ergänzungen wären jederzeit möglich. Sowohl für neue BSSIDs als auch für weitere Messpunkte von bereits bekannten BSSIDs.
Erst wenn die Datenmenge in der Datenbank deutlich größer wird, könnte es unerfreulich werden, immer alles neu berechnen zu müssen.
Daher sollte vielleicht noch gespeichert werden, wann ein Messpunkt aufgenommen wurde. Anhand dieses Attributes ließe sich bestimmen, ob der Polygon-Mittelpunkt für eine gegebene BSSID neu berechnet werden muss, oder nicht.

Damit gehts dann auf Seite 4 weiter.