Les géomètres utilisent des systèmes GPS différentiels pour obtenir des emplacements précis. Un GPS fixe et un vagabond travailler ensemble pour annuler certaines erreurs.J'ai pensé que je pouvais construire un GPS différentiel du pauvre avec deux GPS bon marché en collectant les données des deux et en soustrayant les vecteurs de mouvement de l'appareil stationnaire du rover. Mais cela ne fonctionne pas avec les GPS grand public. Si je le ferais lisez d'abord , je serais peut-être allé directement à...
La moyenne de plusieurs sorties GPS d'appareils adjacents produit une meilleure réponse qu'un seul appareil.Je me suis retrouvé avec trois sur un rebord de fenêtre, alimentant une machine Linux via des ports USB.
USB GPSs in a windowGPS USB dans une fenêtre
J'ai fait une autre erreur lorsque j'ai écrit le code Python qui lit les appareils, vers la fin :
### edited for presentation, may not be functional without some TLC
# dmesg after plug in gives usb port info
import serial
import math
import re
import datetime
import sys
# https://github.com/Knio/pynmea2/blob/master/pynmea2/nmea_utils.py
def timestamp(s):
'''
Converts a timestamp given in "hhmmss[.ss]" ASCII format to a
datetime.time object
'''
ms_s = s[6:]
ms = ms_s and int(float(ms_s) * 1000000) or 0
t = datetime.time(
hour=int(s[0:2]),
minute=int(s[2:4]),
second=int(s[4:6]),
microsecond=ms)
return t
def datestamp(s):
'''
Converts a datestamp given in "DDMMYY" ASCII format to a
datetime.datetime object
'''
return datetime.datetime.strptime(s, '%d%m%y').date()
def dm_to_sd(dm):
'''
Converts a geographic coordiante given in "degres/minutes" dddmm.mmmm
format (ie, "12319.943281" = 123 degrees, 19.953281 minutes) to a signed
decimal (python float) format
'''
# '12319.943281'
if not dm or dm == '0':
return 0.
d, m = re.match(r'^(\d+)(\d\d\.\d+)$', dm).groups()
return float(d) + float(m) / 60
ser0 = serial.Serial('/dev/ttyACM0', 2*9600)
ser1 = serial.Serial('/dev/ttyACM1', 2*9600)
ser2 = serial.Serial('/dev/ttyACM2', 2*9600)
lat0=0
lon0=0
lat1=0
lon1=0
lat2=0
lon2=0
time = ""
while True :
state=ser0.readline().split(",")
if state[0]=="$GPRMC":
lat0 = dm_to_sd(state[3])
lon0 = -dm_to_sd(state[5])
time = datetime.datetime.combine(datestamp(state[9]), timestamp(state[1]))
state=ser1.readline().split(",")
if state[0]=="$GPRMC":
lat1 = dm_to_sd(state[3])
lon1 = -dm_to_sd(state[5])
time = datetime.datetime.combine(datestamp(state[9]), timestamp(state[1]))
state=ser2.readline().split(",")
if state[0]=="$GPRMC":
lat2 = dm_to_sd(state[3])
lon2 = -dm_to_sd(state[5])
time = datetime.datetime.combine(datestamp(state[9]), timestamp(state[1]))
print time.strftime("%Y-%m-%dT%H:%M:%S")+","+str(lat0)+","+str(lon0)+","+str(lat1)+","+str(lon1)+","+str(lat2)+","+str(lon2)
sys.stdout.flush()
Le code boucle indéfiniment, lisant chacun des trois appareils, recherchant le GPRMC message contenant les données intéressantes et impression d'un message formaté dans le fichier de sortie. Rétrospectivement, cette simple déclaration d'impression aurait dû formater les données pour qu'elles aient la forme que je voulais finalement. Ce que j'ai est un fichier comme
2017-06-29T13:59:59, 35.111,-78.222,35.112,-78.223,35.113,-78.224
où 35 et -78 sont la latitude et la longitude, approximativement. Mais ce que je vais vouloir est un peu réarrangé:
2017-06-29T13:59:59, 35.111,-78.222,1
2017-06-29T13:59:59, 35.112,-78.223,2
2017-06-29T13:59:59, 35.113,-78.224,3
où le 1,2,3 à la fin identifie le capteur. Comme je pourrais réimporter les données, j'ai écrit ce JSL pour effectuer la conversion. (En fait, la majeure partie du code consiste à produire les images, notes à la fin.)
colors={{255,0,0},{0,255,0},{0,0,255},{0,0,0}};
ipicture=1e7; // sequence number with leading digit
path="H:\GPSWander\images\";
takePicture = function({},
// {filename=path||"gps"||char(ipicture++)||".png"},
// Report( gb )[framebox( 1 )]<<SAVEPICTURE>= .003, trans = trans * .80,
Report( gb )[framebox( 1 )] << Transparency( trans );
takePicture();
);
Report( gb )[framebox( 1 )] << Transparency( 1.0 );
Report( gb )[framebox( 1 )] << Marker Size( 2 );
dt << selectrows( 5 :: N Rows( dt ) );
dt << hide( 1 );
dt << clearselect;
step = N Rows( dt ) / 10000; // frames in video
For( i = 1, i < N Rows( dt ), i += step,
dt << selectrows( i :: i + step + step + step + step ); // trail
dt << hide( 0 );
takePicture();
dt << hide( 1 );
dt << clearselect;
);
</SAVEPICTURE>
Recherchez la fonction ouverte pour "gpsLog3.txt". Il contient le script que j'ai copié à partir d'une table de données avec laquelle l'aperçu de l'importation m'a aidé. Les quelques lignes suivantes suppriment certaines lignes avec des données invalides. Il n'y en avait que 6 mauvais; Je ne sais pas pourquoi le GPS sur le canal 2 a signalé 0,0.
Les quelques lignes suivantes créent lat9,lon9 comme la moyenne de lat1,2,3 et lon1,2,3. Un message <
L'étape suivante crée des sous-ensembles avec uniquement les colonnes à concaténer, les renomme, ajoute la variable id. Ensuite, les tables sont concaténées, les tables inutiles fermées.
Le tableau récapitulatif généré ensuite est utilisé pour définir les lignes de référence et les limites des axes dans le GraphBuilder qui suit. Ensuite, il y a quelques boucles pour piloter une séquence d'animation dans le générateur de graphes (et la fonction impaire au début pour prendre des photos.)
- J'ai emprunté du code github pour gérer certains des problèmes de GPS NMEA, merci Knio !
- Si vous essayez de le faire, vous aurez probablement aussi besoin de "sudo adduser $USER dialout", recherchez-le.
Explaining the density ellipse in the videoExpliquer l'ellipse de densité dans la vidéo
Le Balade GPS vidéo.