Über USB binäre GPS-Daten empfangen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Hallo zusammen
ich übe (mit Betonung auf übe :lol: ) mit einem Raspberry Pi3+ und Raspian von einem GPS-Empfänger binäre Daten auszulesen. (Präzisionsdaten sind in NMEA nicht drin, das wäre einfacher)

Das GPS sendet zyklisch jede Sekunde 44 Byte. Die ersten 4 Byte sind Fixwerte (ID) 0xb5, 0x62, 0x01, 0x14, danach folgen die Nutzdaten, welche anschliessend berechnet werden müssen und zum Schluss noch 2 Byte CRC
Komisch ist, dass mit meinem Code plötzlich zeilenweise die Enddaten fehlen. Und irgendwann wieder gut sind. Geschätzt sind etwa 10% falsche und dann gerade aneinander über mehrere Sekunden. Dass der Empfänger diese nicht sendet schliesse ich mit höchster Wahrscheinlichkeit aus (hab auch mal mit einem Terminalprogramm verglichen). Es muss am Programm oder am Raspi liegen.

Müsste ich an meinem Code etwas ändern, damit das nicht passiert? Zudem finde ich Code auch nicht gerade "schön". Gibt es eine elegantere Lösung?!
Im Netz bin ich noch nicht auf eine gute Variante gestossen...
Danke schon mal...

Code: Alles auswählen

import serial
import codecs
import time

import binascii
    
list = []
a = []
b = False

serport = serial.Serial("/dev/ttyACM0", baudrate = 9600)
while (True):
    byte_in = serport.read()
    x = binascii.hexlify(byte_in)
    if x == "b5":
        byte_in = serport.read()
        x = binascii.hexlify(byte_in)
        if x == "62":
            byte_in = serport.read()
            x = binascii.hexlify(byte_in)
            if x == "01":
                byte_in = serport.read()
                x = binascii.hexlify(byte_in)
                if x == "14":
                    #print(" ".join(list))
                    a = list
                    list = []
                    b = True
    else:
        list.append(x)

    if b == True:
        print(" ".join(a))
        b = False
    

# Ausgabe (nur die erste Zeile ist korrekt - vollständig, in den andern Zeilen fehlt der Schluss, Beginn ist ohne ID - die ist ja fix)

#24 00 00 00 00 00 f8 72 22 22 f8 4a c7 04 8f 61 9c 1b e4 b4 0e 00 4f fc 0d 00 15 29 03 03 76 2a 00 00 0c 39 00 00 c2 b1

#24 00 00 00 00 00 20 19 22 22 c7 4a c7 04 8d 61 9c 1b 68 00 d3 fc 0d 00 09 2d ff fe ac 29 00 00 35 38 00 00 b3 92
#24 00 00 00 00 00 08 1d 22 22 ca 4a c7 04 8d 61 9c 1b 6a 00 d5 fc 0d 00 cf d6 04 03 ad 29 00 00 2d 38 00 00 18 7c
#24 00 00 00 00 00 f0 20 22 22 cc 4a c7 04 8b 61 9c 1b 6d 00 d8 fc 0d 00 f3 1f fe fe 00 00 2a 38 00 00 70 eb
#24 00 00 00 00 00 d8 24 22 22 ce 4a c7 04 8a 61 9c 1b 6c 00 d7 fc 0d 00 e6 10 02 02 c5 29 00 00 2e 38 00 00 5b fe
#24 00 00 00 00 00 c0 28 22 22 cf 4a c7 04 8a 61 9c 1b 62 00 cd fc 0d 00 f7 db 03 03 ce 29 00 00 2f 38 00 00 1c 12
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Du ignorierst alle B5-Bytes und das Byte, das danach kommt, egal wo sie vorkommen.

Das Lesen sollte eher so aussehen:

Code: Alles auswählen

SIGNATURE = b"\xb5\x62\x01\x14"
serport = serial.Serial("/dev/ttyACM0", baudrate = 9600)
while True:
    while True:
        for ch in SIGNATURE:
            byte_in = serport.read(1)
            if byte_in != ch:
                break
        else:
            # signature found
            break
    data = serport.read(40)
    # do something with data
Zuletzt geändert von Sirius3 am Samstag 19. Mai 2018, 17:34, insgesamt 2-mal geändert.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du schreibst nicht welchen pi du benuzt. Ich hab mit einem LIDAR und dem PI 1 schlechte Erfahrungen gemacht, wenn ich so wie auf dem PC byteweise gearbeitet habe. Die Kiste war so lahm, das mir verloren gegangen sind.

Abhilfe haben das prüfen auf die Anzahl der Bytes, und gleich entsprechend viele zu lesen, sowie eine optimierte Verarbeitung gebracht.

Da hast du auch noch Potential, zb indem du dir das unnötige umgewandel in hex-strings klemmst, und gleich mit zb 0xb5 vergleichst.

Ausserdem solltest du die empfangenen Daten buffern, und im Buffer nach deinem Präfix suchen. Dann das datagramm verarbeiten, den Buffer entsprechend zuschneiden, und von vorne anfangen.
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Sirius3 hat geschrieben: Samstag 19. Mai 2018, 17:28 Du ignorierst alle B5-Bytes und das Byte, das danach kommt, egal wo sie vorkommen.
Oh ja - da hast Du völlig recht, dass da nicht alles mitkommt. Nachdem ich den Beitrag schon abgeschickt hatte, ist mir sowas in diese Richtung noch kurz durch den Kopf.

Erste Test's mit Deinem Script sehen sehr gut aus. Nun kann ich mich an die Nutzdatenauswertung machen.

Vielen lieben Dank
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

__deets__ hat geschrieben: Samstag 19. Mai 2018, 17:32 Du schreibst nicht welchen pi du benuzt. Ich hab mit einem LIDAR und dem PI 1 schlechte Erfahrungen gemacht, wenn ich so wie auf dem PC byteweise gearbeitet habe.
...doch es Stand da immer schon, dass es sich um einen PI 3+ handelt 8). Denkst - oder weisst Du, dass mit der USB am Pi 3 besser ist als PI1?
Deine andern Hinweise werde ich auch überdenken/einbinden. Denke, wenn ich den CRC rechne und vergleiche. Bin ich schon mal ziemlich sicher dass die Daten korrekt sind.

Ist Dein LIDAR-Projekt ein Erfolg geworden? So ein Projekt ist bei mir nämlich auch in der untersten Schublade und zwar zusammen mit dem RTK-GPS an dem ich gerade bin, um beides auf eine Drohne zu packen. Wie es halt auch schon einige machen.

Danke für die nützlichen Hinweise.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Verzeih. Hab ich nicht gut genug gelesen.

Das Projekt ist ein Erfolg, zu besichtigen im jagdmuseum in München. Allerdings ist es deutlich weniger anspruchsvoll als sowas auf ne Drohne zu packen.
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

__deets__ hat geschrieben: Samstag 19. Mai 2018, 21:50 Verzeih. Hab ich nicht gut genug gelesen.
Keine Ursache geht doch allen so...
__deets__ hat geschrieben: Samstag 19. Mai 2018, 21:50 Das Projekt ist ein Erfolg, zu besichtigen im jagdmuseum in München. Allerdings ist es deutlich weniger anspruchsvoll als sowas auf ne Drohne zu packen.
Oh da muss ich mal reinschauen, wenn ich in der Gegend bin.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ist nicht ganz einfach zu erkennen. Ist eine Weitsprung-Station. Die Erfassung des Absprungs geschieht mit einem LIDAR den ich noch rumliegen hatte.

Der PI 1 ist damit ganz schön an der Grenze gewesen. Ohne PyPy wäre das Ding in die Hose gegangen bzw hätte in C++ umgesetzt werden müssen.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Achso, weil du gefragt hast: alle PI Versionen haben die gleiche Peripherie. Nur die CPU-Kerne unterscheiden sich. USB selbst ist also nicht schneller, aber natürlich hat eine beschleunigte CPU positive Effekte für den Durchsatz des Systems.
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

... Mann! Ich tue mich gerade schwer mit der Auswertung der Daten. Vielleicht darf ich eure Hilfe nochmal kurz in Anspruch nehmen?
Da es nicht auf Anhieb funktioniert, versuche ich Teilergebnisse auszugeben. Aber mit der Teilergebnissausgabe in lesbarem Zustand verwirre ich mich durch Umwandlung von str, hex, dez wohl mehr, als das es zur Lösung beiträgt.

z.B ist in "data[14:18]" der Breitengrad enthalten (little Endian, 2er Complement)
output des unten stehenden scripts:
<type 'str'>
‡aœ
87619c1b

0x1b9c6187 ist nun die Breite ‭463233415‬ (‭46.3233415‬)

Code: Alles auswählen

    data = serport.read(40)
    print type(data)
    print(data[14:18])
    print(binascii.b2a_hex(data[14:18]))
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich würde struct.unpack benuzten, ungefähr so (ungetestet und nur schematisch):

Code: Alles auswählen

print(struct.unpack(“<i”, data[....]))
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

__deets__ hat geschrieben: Sonntag 20. Mai 2018, 11:04 Ich würde struct.unpack benuzten, ungefähr so (ungetestet und nur schematisch):

Code: Alles auswählen

print(struct.unpack(“<i”, data[....]))
Wauw, ich habs für Dich getestet :lol: sieht super aus. Eine Zeile! Ich kam mit 10 Zeilen nicht ans Ziel. Wer programmieren kann ist klar im Vorteil. Vielleicht gehöre ich auch irgendwann mal zu denen. (also mit Assembler, TurboPascal, Delphi war ich vor laaaanger Zeit auch mal gut unterwegs...)

Vielen Dank
Den Output zeige ich jetzt nicht, sonst wissen alle auf der Welt Zentimeter genau wo ich wohne :mrgreen: Sollte trotzdem Bedarf sein, einfach google fragen, der weiss es bestimmt...

Code: Alles auswählen

    data = serport.read(40)
    lon = struct.unpack("<i", data[10:14])
    lat = struct.unpack("<i", data[14:18])
    print(lon, lat)
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Und statt jedes einzelne Element zu entpacken, macht man das in einem Rutsch:

Code: Alles auswählen

lon, lan = struct.unpack_from("<ii", data, 10)
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Code: Alles auswählen

lon, lan = struct.unpack_from("<ii", data, 10)
Ist gerade nochmals eine Verbesserung. struct steht in meinem Python-Buch auf Seite 962, so weit bin ich noch nicht damit, darum kannte ich das nicht.

So - ein wenig freude hatte ich heute Abend schon, als beim meinem GPS-Test die Position in der Lage mit X:13mm und Y:7mm daneben war. Habe einen Punkt der Landesvermessung dazu benutzt, wessen Koordinaten bekannt sind. Genauigkeit des Punktes ist mit 20mm angegeben.

Dank eurer Mithilfe. Vielen Dank!!!
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wie kommst du denn auf so präzise Werte? Ich dachte selbst mit DGPS kommt man auf einen Meter.
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Mit den Korrekturen der Systembetreiber sind 1-Meter Genauigkeiten möglich. Mit DGPS oder besser DGNSS (GPS ist genau genommen das System der Amerikaner, es gibt ein paar andere noch) sind durchaus Genauigkeiten im cm Bereich möglich. Also mit lokalen Korrekturdaten. So nutzen es auch Vermessungsbüros. Kosten deren Geräte so ab €20'000.- (Entwicklungskosten halt, Hardware wär wohl noch zu bezahlen)
Bin noch ziemlich neu mit DGNSS / RTK. Der verwendete Empfänger ist von u-blox ein sehr präziser Chip ~€100.-. Dann verwende ich eine eigene Basisstation auf dem Dach, welche die Korrekturdaten per Funk versendet (bis jetzt auch nur mit rudimentären Mitteln eingemessen - staune selbst über die Genauigkeit).
Werd da wohl noch einige Stunden in das Projekt investieren, ist gerade sehr spannend und vielleicht werde ich mal reich damit :roll: :lol: .
So 5-6 Geräte à €10'000 pro Jahr verkaufen - das würde reichen...
Antworten