PicoBoy Color - Neues Projekt


RPi PicoBoy Color und
Magnetometer MMC56X3

Projekte und Anleitung in CircuitPython 9.x.x



Bildbox 1 (klick hier)

Andere PicoBoy-Color Projekte:

PicoBoy-Color vorgestellt

Hardware des PicoBoy - Color und Inbetriebnahme (1 - Display)

Hardware des PicoBoy - Color: Benutzung Joystick, Tasten und LED

Projekt mit PicoBoy - Color: Temperatur und Luftdruck messen

Projekt mit PicoBoy - Color: Neopixelring

Bewegte Bilder auf dem PicoBoy-Color - Spiele mit Sprites

Projekt mit PicoBoy - Color als Compass

In dieser neuen Anleitung wird mit Hilfe eines Magnetometers MMC56X3 von Adafruit eine Compassanwendung auf dem PicoBoy-Color dargestellt. Der Chip wird am I2C-Bus des PicoBoys betrieben und an den Lötpads der GPIO 20 und 21 angeschlossen.

Hardware

- PicoBoy-Color (z.B. von hier )
- USB-A zu USB-C Kabel
- Magnetometer MMC56X3 von Adafruit (z.B. von hier )

Software

- aktuelle Firmeware CircuitPython z.B. 9.x
- library adafruit_mmc5656x3.mpy aus dem CircuitPython-Bundle zur Firmewareversion
- library adafruit_st7789.mpy aus dem CircuitPython-Bundle zur Firmewareversion
- Ordner adafruit_imageload aus dem CircuitPython-Bundle zur Firmewareversion
- Ordner adafruit_register aus dem CircuitPython-Bundle zur Firmewareversion
- Ordner adafruit_display_text aus dem CircuitPython-Bundle zur Firmewareversion

Los gehts

Da der PicoBoy-Color nicht über eine Stemma QT-Buchse verfügt, wie das Magnetometer MMC56x3 von Adafruit, müssen vier Kabel an den Lötpads des PicoBoy-Color angelötet werden. Falls Sie ein Qwiic-Kabel 'spendieren', können Sie den Stecker auf einer Seite abschneiden und wie im Foto gezeigt, an den Lötpads anlöten. Oder Sie verbinden das Magnetometer mit dem PicoBoy-Color über vier Kabel, wie im Foto unten dargestellt. Damit bei den Tests reproduzierbare Werte entstehen, habe ich das Magnetometer-Board auf der Unterseite des PicoBoy-Color fixiert (siehe Bild 2 in Bildbox 1). In einem späteren Gehäuse wird es dann einen geeigneten Platz bekommen.



Wenn das erledigt ist, kann das Magnetometer in betrieb genommen werden. Adafruit beschreibt in seinen Anleitungen einen ersten s.g. 'simpletest.py', der im unteren Kasten gezeigt ist. Beachten Sie, dass sich die Bibliothek adafruit_mmc5656x3.mpy im 'lib-Ordner' befindet.

  
  
1  # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
2  # SPDX-License-Identifier: MIT
3
4  # Simple demo of the MMC56x3 magnetometer.
5  # Will print the magnetometer values every second.
6  import time
7  import board
8  import busio
9  import adafruit_mmc56x3
10
11 # Initialize I2C bus and sensor.
12 i2c = busio.I2C(board.GP21, board.GP20)
13 # i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller
14 sensor = adafruit_mmc56x3.MMC5603(i2c)
15
16 # values every second and print them out.
17 while True:
18     mag_x, mag_y, mag_z = sensor.magnetic
19     temp = sensor.temperature
20     # Print values.
21     print(
22         "Magnetometer (gauss): ({0:0.3f},{1:0.3f},{2:0.3f})".format(mag_x, mag_y, mag_z)
23     )
24     print("Temperature: {0:0.3f}C".format(temp))
25     # Delay for a second.
26     time.sleep(1.0)
  

Wenn Sie das Programm starten und den PicoBoy-Color auf einer flachen Unterlage etwas hin- und herbewegen, werden in der Console der Thonny-IDE entsprechende Werte ausgegeben:



Bildbox 2 (klick hier)


Was die Werte bedeuten und wie sie genutzt werden können, wird nachfolgend erklärt. Dass der Chip auch die Temperatur erfasst, sei hier nur am Rande erwähnt und wird nicht weiter verfolgt.

Notwendigkeit zum Kalibrieren des Sensors:

Magnetometer können verwendet werden, um die Orientierung in Bezug auf das Erdmagnetfeld zu ermitteln. Im Grunde wie ein Kompass! Beim Kompass richtet sich eine Magnetnadel in Richtung des Erdmagnetfeldes aus und zeigt zum magnetischen Nordpol. So können wir sagen, wo Norden ist. Aber Magnetometer müssen in einer Welt voller Magnete (Motoren, Spulen, Stromleitungen, Maschinen aus Eisen/Stahl u.s.w.) ein sehr kleines Magnetfeld von 35-65 µTesla messen. Deshalb müssen sie kalibriert werden. Durch eine s.g. Hard-Iron-Offset-Berechnung werden starke Offsetwerte ausgeschlossen. So können sie den magnetischen Norden finden.

Methode zum Kalibrieren des Sensors:

Eine einfache Methode zur Kalibrierung verwendet das Aufzeichnen von Werten, um die minimalen und maximalen Messwerte auf allen drei Achsen zu erfassen. Während Sie die Aufzeichnung ausführen, drehen Sie das Modul mehrmals langsam in allen drei Achsen. Das Ziel besteht darin, die absoluten Minima und Maxima für jede Achse aufzuzeichnen. Je mehr Sie es also drehen, desto wahrscheinlicher ist es, dass Sie den absoluten Spitzenwert erfassen.

Das Programm im folgenden Kasten bestimmt diese Minimal- und Maximalwerte und schreibt sie in ein Array, welches im späteren Compass-Programm genutzt wird.

  
  
1  # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
2  # SPDX-License-Identifier: MIT
3
4  """ Calibrate the magnetometer and print out the hard-iron calibrations """
5
6  import time
7  import board
8  import busio
9  import adafruit_mmc56x3
10
11 # Initialize I2C bus and sensor.
12 i2c = busio.I2C(board.GP21, board.GP20)
13 magnetometer = adafruit_mmc56x3.MMC5603(i2c)
14
15 # calibration for magnetometer X (min, max), Y and Z
16 hardiron_calibration = [[1000, -1000], [1000, -1000], [1000, -1000]]
17
18 def calibrate():
19     start_time = time.monotonic()
20     # Update the high and low extremes
21     while time.monotonic() - start_time < 15.0:
22         magval = magnetometer.magnetic
23         print("Calibrating - X:{0:10.2f}, Y:{1:10.2f}, Z:{2:10.2f} uT".format(*magval))
24         for i, axis in enumerate(magval):
25             hardiron_calibration[i][0] = min(hardiron_calibration[i][0], axis)
26             hardiron_calibration[i][1] = max(hardiron_calibration[i][1], axis)
27     print("Calibration complete:")
28     print("hardiron_calibration =", hardiron_calibration)
29
30 print("Prepare to calibrate! Twist the magnetometer around in 3D in...")
31 print("3...")
32 time.sleep(1)
33 print("2...")
34 time.sleep(1)
35 print("1...")
36 time.sleep(1)
37
38 calibrate()
  

Wenn Sie das Programm starten und den PicoBoy-Color langsam in verschiedene Richtungen bewegen, werden in der Console der Thonny-IDE entsprechende Werte ausgegeben:



Bildbox 3 (klick hier)


Entscheidend ist die letzte Zeile in der Kommandozeile:

hardiron_calibration = [[14.8625, 69.6], [-40.6875, 31.3062], [-56.4312, -11.0562]]

Hier sind die Minimal- und Maximalwerte für die X, Y und Z Richtung enthalten. Speichern Sie die komplette Zeile in die Zwischenablage, um sie später in das Compass-Programm einzusetzen.

Damit sind wir so weit, um ein erstes kurzes Programm mit der Kompassrichtung zu testen. Auf dem Kompass ist eine Scheibe mit einer im Uhrzeigersinn aufgetragenen 360-Grad-Einteilung angebracht (Kompassrose). Die vier Himmelsrichtungen Norden, Osten, Süden und Westen entsprechen 0°, 90°, 180° und 270°. Der Sensor des Magnetometers gibt uns die Werte des Magnetfeldes der Erde in µTesla an. Zur Berechnung benutzen wir die x- und y-Richtung des Sensors. Um die Mikrotesla-Werte in eine Kompassrichtung von 0-360 Grad umzuwandeln, können wir die Funktion atan2() verwenden. Das Ergebnis wird in Radiant angegeben, also multiplizieren wir es mit 180 Grad und dividieren durch Pi, um es in Grad umzuwandeln. Im unteren Kasten finden Sie dafür den Quellcode, wie ihn Adafruit für eine Vielzahl seiner Magnetometer vorschlägt:

  
  
1  # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
2  # SPDX-License-Identifier: MIT
3
4  """ Display compass heading data from a calibrated magnetometer """
5
6  import time
7  import math
8  import board
9  import busio
10 import adafruit_mmc56x3
11
12 # Initialize I2C bus and sensor.
13 i2c = busio.I2C(board.GP21, board.GP20)
14 sensor = adafruit_mmc56x3.MMC5603(i2c)
15
16 # You need t copy your own value for hardiron_calibration from the output and paste it
17 # into this script here:
18 hardiron_calibration = [[14.8625, 69.6], [-40.6875, 31.3062], [-56.4312, -11.0562]]
19
20 # This will take the magnetometer values, adjust them with the calibrations
21 # and return a new array with the XYZ values ranging from -100 to 100
22 def normalize(_magvals):
23     ret = [0, 0, 0]
24     for i, axis in enumerate(_magvals):
25         minv, maxv = hardiron_calibration[i]
26         axis = min(max(minv, axis), maxv)  # keep within min/max calibration
27         ret[i] = (axis - minv) * 200 / (maxv - minv) + -100
28     return ret
29
30
31 while True:
32     magvals = sensor.magnetic
33     normvals = normalize(magvals)
34
35     # we will only use X and Y for the compass calculations, so hold it level!
36     compass_heading = int(math.atan2(normvals[1], normvals[0]) * 180 / math.pi)
37     # compass_heading is between -180 and +180 since atan2 returns -pi to +pi
38     # this translates it to be between 0 and 360
39     if compass_heading < 0:
40         compass_heading += 360
41
42     print("Heading:", compass_heading)
43     time.sleep(1)
  

Was bedeuten die Anzeigen?

- Richtung: 0°      Norden
- Richtung: 90°    Osten
- Richtung: 180°   Süden
- Richtung: 270°   Westen

Nun wäre es natürlich schön, wenn die Werte nicht nur in der Console der Thonny-IDE angezeigt würden. Deshalb folgt hier noch ein Vorschlag, wie eine Kompassrose auf dem Display des PicoBoy-Color dargestellt wird, die sich bei Bewegung des PicoBoy's dreht und immer nach Norden ausrichtet.


Bildbox 4 (klick hier)


Bevor Sie den Quellcode aus dem unteren Kasten ausprobieren, erinnere ich noch einmal an die unter 'Software' genannten Bibliotheken und Bibliotheksordner, die sich jetzt alle im 'lib-Ordner' befinden müssen. Ausserdem wird die Bitmap-Datei 'compass.bmp' in einem Ordner 'images' benötigt. Legen Sie den Ordner auf dem PicoBoy Laufwerk an, downloaden die Bilddatei von hier und speichern sie im Ordner 'images'.

  
  
1   # SPDX-FileCopyrightText : 2025 Detlef Gebhardt, written for CircuitPython 9.1.4
2   # SPDX-FileCopyrightText : Copyright (c) 2025 Detlef Gebhardt
3   # SPDX-Filename          : PicoBoy-Color Compass
4   # SPDX-License-Identifier: https://dgebhardt.de
5   import time
6   import board
7   from adafruit_display_text.bitmap_label import Label
8   from displayio import Group
9   import busio
10  import displayio
11  import terminalio
12  import adafruit_imageload
13  import bitmaptools
14  from adafruit_st7789 import ST7789
15  import adafruit_mmc56x3
16  import math
17
18  # 1,69 Zoll 240x280 Pixel ST7789 Display
19  # SPI-Bus,  in Portrait format
20  dc=board.GP8
21  reset=board.GP9
22  cs=board.GP10
23  sck=board.GP18
24  mosi=board.GP19
25  bl=board.GP26
26  # Release any resources currently in use for the displays
27  displayio.release_displays()
28  spi = busio.SPI(sck, mosi)
29  display_bus = displayio.FourWire(spi, command=dc, chip_select=cs, reset=reset)
30  display = ST7789(display_bus, rotation=0, width=240, height=280, backlight_pin=bl, rowstart=20, colstart=0)
31  display.brightness = 1
32  # create a main_group to hold anything we want to show on the display.
33  main_group = Group()
34
35  # Bitmap-Dateien fuer Hintergrund und Zeiger
36  zifferblatt = "/images/compass.bmp"
37  ## Compassnadel 240x240 Hintergrund
38  bg_bitmap, bg_pal = adafruit_imageload.load(zifferblatt, bitmap=displayio.Bitmap,palette=displayio.Palette)
39  bg_pal.make_transparent(0)
40  bg_bitmap_scribble = displayio.Bitmap(display.width, display.height, len(bg_pal))
41  bg_tile_grid = displayio.TileGrid(bg_bitmap_scribble, pixel_shader=bg_pal)
42  main_group.append(bg_tile_grid)
43  bitmaptools.rotozoom( bg_bitmap_scribble, bg_bitmap, angle = 0)
44
45  # Initialize I2C bus and sensor.
46  i2c = busio.I2C(board.GP21, board.GP20)
47  sensor = adafruit_mmc56x3.MMC5603(i2c)
48
49  # set the main_group as the root_group of the built-in DISPLAY
50  display.root_group = main_group
51
52  sensor.data_rate = 10  # in Hz, from 1-255 or 1000
53  sensor.continuous_mode = True
54
55  #my values
56  hardiron_calibration = [[32.0, 62.0], [-22.0, 7.5], [-18.0, -12.0]]
57
58  # This will take the magnetometer values, adjust them with the calibrations
59  # and return a new array with the XYZ values ranging from -100 to 100
60  def normalize(_magvals):
61      ret = [0, 0, 0]
62      for i, axis in enumerate(_magvals):
63          minv, maxv = hardiron_calibration[i]
64          axis = min(max(minv, axis), maxv)  # keep within min/max calibration
65          ret[i] = (axis - minv) * 200 / (maxv - minv) + -100
66      return ret
67
68  # begin main loop
69  while True:
70      magvals = sensor.magnetic
71      normvals = normalize(magvals)
72      # we will only use X and Y for the compass calculations
73      compass_heading = math.atan2(normvals[1], normvals[0]) * 30 / math.pi
74      # this translates it to be between 0 and 60
75      if compass_heading < 0:
76          compass_heading += 60
77      #print("Kurswinkel: ", 6*int(compass_heading + 0.5))
78      bitmaptools.rotozoom( bg_bitmap_scribble, bg_bitmap, angle = math.pi/30 * (1 - compass_heading))
79      time.sleep(0.3)
  

Zum Abschluss noch ein paar Erläuterungen zum Programm:
Die Zeilen 1- 34 importieren die benötigten Bibliotheken und Module und initialisieren das Display. In den Zeilen 35 bis 43 wird eine Tile_Grid mit der Bilddatei als Hintergrundbild angelegt und mit Hilfe von 'bitmaptools.rotozoom' (43) als drehbar definiert. Die Zeilen 45 bis 72 entsprechen im Wesentlichen den vorangegangenen Tests. Die Angabe des Winkels für die Kompassrichtung in Zeile 73 habe ich zwischen 0 und 60 gewählt. So kann ich in Zeile 78 die Ausrichtung der 'Nadel' ähnlich den Sekunden auf dem Zifferblatt einer Uhr vornehmen. D.h. wenn der Zeiger senkrecht nach oben zeigt, wie in Bild 2 von Bildbox 4, wäre die Venedigkarte 'eingenordet'. Ansonsten findet man Norden bei beliebiger Lage des PicoBoy-Color, da der Zeiger immer in diese Richtung zeigt (siehe Bild 1 Bildbox 4).




Viel Spass und Erfolg beim Ausprobieren.