RP2040-GEEK
GPS Datenlogging



Anleitung für die Firmware CircuitPython



Bildbox 1 (klick hier)


In dieser Anleitung werden die geogr. Koordinaten (Längen- und Breitengrad) mit Hilfe des Moduls 'seeed Grove Air 530' bestimmt und auf dem Pico-GEEK angezeigt bzw. aufgezeichnet. Damit lässt sich z.B. die Entfernung von einem vorgegebenen Ort bestimmen oder ein Datentracking durchführen. Für rund 25 Euro (RP2040-GEEK: 13 Euro + GPS-Modul: 12 Euro) kann man also seinen eigenen GPS-Tracker bauen.

Hardware

- RP2040-GEEK incl. mitgelieferte Kabel
- seeed Grove - GPS Modul (Air530) incl. mitgelieferte Antenne
- (Powerbank zur Stromversorgung, Einsatz autark im Freien)

Los gehts

Das GPS-Modul wird über 'UART' mit dem Pico-GEEK' verbunden, d.h. wir brauchen vier Anschlüsse. Auf dem GPS-Modul benutzen wir dafür VIN, GND, GPS_TXD und GPS_RXD. TX ist der Pin, der Daten vom GPS-Modul an den Mikrocontroller überträgt. Es handelt sich um einen Logikpegel von 3,3 V. Die Daten werden standardmäßig mit 9600 Baud ausgegeben. RX ist der Pin, mit dem die Daten an das GPS gesendet werden können. Es können 3,3-V- oder 5-V-Logik verwenden werden. Es gibt einen Logikpegelumsetzer. Standardmäßig werden 9600-Baud-Daten erwartet. Für die Tests habe ich wie im Bild sichtbar zunächst Headerleisten mit jeweils 5 Stiften an die Platine gelötet. Später werden die Kabel platzsparender direkt an das Modul gelötet.


Bei 'UART' verwendet der Pico üblicherweise GPIO 0, GPIO 1 bzw. GPIO 4, GPIO 5. Aus der Beschriftung auf dem Pico-Geek ist zu entnehmen, dass wir mit GPIO 4 und GPIO5 arbeiten können (siehe unteres Bild). Die Spannung 3,3 V und die Masse greifen wir uns aus der vierpoligen Buchse (I2C/ADC) ab.


In einer Anleitung zur Nutzung von 'UART' beim RP-Pico schreibt Adafruit:

Set Uart0: TX = board.GP0 and RX = board.GP1 or Uart1: TX = board.GP4 and RX = board.GP5
    uart = busio.UART(board.GP4, board.GP5, baudrate=9600, timeout=10)
These are the defaults you should use for the GPS FeatherWing.For other boards set RX = GPS module TX, and TX = GPS module RX pins.
    uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=10)

Was folgt daraus? Dass GPIO 4 an GPS_TX und GPIO 5 an GPS_RX angeschlossen werden sollte, was aber leider nicht funktionierte. Also hält sich der Hersteller nach m.M. nicht an die Standardbelegung, deshalb habe ich es umgekehrt versucht und schon hat das GPS-Modul gearbeitet. D.h. schließen Sie das grüne Kabel an GPS_TXD und das blaue an GPS_RXD des GPS-Moduls an (siehe Foto oben). Die Beschriftung für die GPIO's am 'UART' Port auf dem Gehäuse des Pico-GEEK sollte also besser umgekehrt sein.

Es folgt der eigentliche Programmcode. Zunächst wird die Bibliothek 'adafruit_gps.mpy' benötigt, die Sie hier herunterladen, entpacken und in den 'lib_Ordner' kopieren können. Im unteren Kasten ist der neue Programmcode bis einschließlich der Definition des 'UART' Moduls. Er stimmt in den Zeilen 1 bis 62 mit dem Code in den bisherigen Anleitungen, bis auf das Laden von 'adafruit_gps' in Zeile 13, überein. Und die Initialisierung der SD-Karte hätte es in diesem Beispiel noch nicht gebraucht. Das ist dann später schon vorhanden.

  
  

1   import os
2   import time
3   import board
4   import busio
5   import sdcardio
6   import digitalio
7   import storage
8   from fourwire import FourWire
9   from adafruit_display_text import label
10  import terminalio
11  import displayio
12  from adafruit_st7789 import ST7789
13  import adafruit_gps
14
15  # Display initialisieren
16  lcd_cs=board.GP9
17  lcd_dc=board.GP8
18  lcd_reset=board.GP12
19  # Release any resources currently in use for the displays
20  displayio.release_displays()
21  spi = busio.SPI(board.GP10, board.GP11)
22  display_bus = FourWire(spi, command=lcd_dc, chip_select=lcd_cs, reset=lcd_reset)
23  display = ST7789(display_bus, rotation=90, width=240, height=135, rowstart=40, colstart=53)
24  # Make the display context
25  splash = displayio.Group()
26  display.root_group = splash
27
28  # Make a background color fill
29  color_bitmap = displayio.Bitmap(display.width, display.height, 3)
30  color_palette = displayio.Palette(3)
31  color_palette[0] = 0x660088
32  color_palette[1] = 0x000000
33  color_palette[2] = 0xffffff
34  bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
35  splash.append(bg_sprite)
36
37  # Draw a label
38  text_area = label.Label(font=terminalio.FONT, text="\n   RP2040 GEEK\n\n    it work's" , color=0xFFFF00, scale=2, line_spacing=1 )
39  text_group = displayio.Group(x=15, y=10)
40  text_group.append(text_area)  # Subgroup for text scaling
41  splash.append(text_group)
42
43  # SD Karte mounten
44  SD_SCK = board.GP18
45  SD_MOSI = board.GP19
46  SD_MISO = board.GP20
47  cs = board.GP23
48
49  try:
50      card = busio.SPI(SD_SCK, SD_MOSI, SD_MISO)
51      sdcard = sdcardio.SDCard(card, cs)
52      vfs = storage.VfsFat(sdcard)
53      storage.mount(vfs, "/sd")
54      text_area.text = "\n    SD-Karte\n   erfolgreich\n    gemountet."
55
56  except OSError as exc:
57      error = exc.errno
58      print(error)
59      text_area.text = "\n\n  keine SD-Karte\n\n    vorhanden."
60
61  time.sleep(2)
62
63  # Set Uart0: TX = board.GP0 and RX = board.GP1 (or Uart1: TX = board.GP4 and RX = board.GP5)
64  uart = busio.UART(board.GP4, board.GP5, baudrate=9600, timeout=10)
65
66  # Create a GPS module instance.
67  gps = adafruit_gps.GPS(uart, debug=False)  # Use UART/pyserial
68  # gps = adafruit_gps.GPS_GtopI2C(i2c, debug=False)  # Use I2C interface
69
70  # Turn on the basic GGA and RMC info (what you typically want)
71  gps.send_command(b"PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0")
72  # Set update rate to once a second (1hz) which is what you typically want.
73  gps.send_command(b"PMTK220,1000")
74  # Main loop runs forever printing the location, etc. every second.
75  last_print = time.monotonic()
76
  

In den Zeilen 63 bis 76 habe ich mich weitesgehend an einer Anleitung zur Einrichtung des 'GPS-Moduls' bei Adafruit orientiert. Entscheidend für die Funktion ist der obige Hinweis zu den GPIO's und die Definition von 'UART 1' in Zeile 64. In den Zeilen 66 bis 73 werden Einstellungen vorgenommen, die für die Funktion notwendig sind. Zeile 75 stellt in der 'while-Schleife' die Zeit für die Wiederholungen bereit. Es folgt die 'while-Scheife':

  
  

77 while True:
78     gps.update()
79     # Every second print out current location details if there's a fix.
80     if time.monotonic() - last_print < 4.0:
81         if gps.satellites is not None:
82             if gps.speed_knots == None:
83                 gps.speed_knots = 0
84             text_area.text = ("\nSat.   : " + str(gps.satellites) + "\nGeschw.: " + str(gps.speed_knots*1.852) +
85                               " km/h\nHoehe  : " + str(gps.altitude_m) + " m")
86         else:
87             text_area.text = "\n  z.Z. kein\nSatellitenempfang\n  bitte warten"
88     else:
89         #print("Latitude: {0:.7f} Grad".format(gps.latitude))
90         #print("Longitude: {0:.7f} Grad".format(gps.longitude))
91         #print("Präziser Breitengrad: {} Grad, {:2.2f} Min".format(
92         #        gps.latitude_degrees, gps.latitude_minutes))
93         #print("Präziser Längengrad: {} Grad, {:2.2f} Min".format(
94         #        gps.longitude_degrees, gps.longitude_minutes))
95         ##print("Fix quality: {}".format(gps.fix_quality))
96         ## Some attributes beyond latitude, longitude and timestamp are optional
97         ## and might not be present.  Check if they're None before trying to use!
98         #if gps.satellites is not None:
99         #    print("# Anzahl Satelliten: {}".format(gps.satellites))
100        #if gps.altitude_m is not None:
101        #    print("Höhe: {} meters".format(gps.altitude_m))
102        #if gps.speed_knots is not None:
103        #    print("Geschwindigkeit: {} Knoten".format(gps.speed_knots))
104        #if gps.track_angle_deg is not None:
105        #    print("Spurwinkel: {} degrees".format(gps.track_angle_deg))
106        ##if gps.horizontal_dilution is not None:
107        ##    print("Horizontale Streubreite: {}".format(gps.horizontal_dilution))
108        ##if gps.height_geoid is not None:
109        ##    print("Height geoid: {} meters".format(gps.height_geoid))
110        if gps.satellites is not None:
111            lat = gps.latitude
112            lon = gps.longitude
113            text_area.text = ("\nLatitude:\n   {0:.7f}".format(lat) +
114                             "\nLongitude:\n   {0:.7f}".format(lon))
115        else:
116            text_area.text = "\n  z.Z. kein\nSatellitenempfang\n  bitte warten"
117    if time.monotonic() - last_print >= 10.0:
118        last_print = time.monotonic()
119
  


In der Schleife wird alle 4 Sekunden zwischen der Anzeige von 'Latitude, Longitude' und der Anzahl der Satelliten, Geschwindigkeit und der Höhe gewechselt. Dabei enthält gps.update() (Zeile 78) jeweils die aktuellen Werte. Die auskommentierten Zeilen 89 bis 109 ermöglichen es Ihnen, noch eine ganze Reihe weiterer Werte anzeigen zu lassen. Experimentieren Sie einfach ein wenig damit, indem Sie die Kommentierung entfernen.


Ein letzter Hinweis:
Wenn das Programm gestartet wird, erscheint zunächst die Ausgabe: z.Z. kein Satellitenempfang, bitte warten. Beachten Sie dabei eine Besonderheit des GPS-Moduls, welche in den technischen Daten wie folgt angegeben wird: "30s Zeit für Kaltstart und 4s Zeit für Warmstart" . Also ein klein wenig Geduld und dann


viel Spass und Erfolg beim Ausprobieren.