PicoBoy - elektronische Wasserwaage
technische Daten wie beim RPi Pico
MC RP2040 mit OLED-Display 128x64 Pixel
Anleitung für die Firmware CircuitPython 9.x.x
Hardware
- Pico-Boy (z.B. von hier)
- Gehäuse vom 3D-Drucker
- USB-A zu USB-C Kabel
komplette Firm- und Software als uf2-Datei:
- picoboy_spiritlevel.uf2
Software zum schrittweisen Ausprobieren
- CircuitPython 9.x.x oder neuer
- Bibliotheken im 'lib'-Ordner
PicoBoy - elektronische Wasserwaage
technische Daten wie beim RPi PicoMC RP2040 mit OLED-Display 128x64 Pixel
Anleitung für die Firmware CircuitPython 9.x.x
Heute geht es um eine echt praktische Anwendung. Mit Hilfe des Pico-Boys im Gehäuse aus dem ersten Beitrag wird eine elektronische Wasserwaage
realisiert, welche jederzeit einsatzbereit ist. Die dabei genutzten Progressbalken zeigen mit ihrem Ausschlag nach links oder rechts an, wenn
der Untergrund nicht in der Waage ist. Durch die relativ kurze Zeit, die das 'Gerät' eingeschaltet sein muss und den integrierten 'Ruhemodus'
, reicht auch die Kapazität der Knopfzelle für einen längeren Zeitraum.
Los gehts
Um die Abweichung aus der Waagerechten zu erfassen, wird der Beschleunigungssensor des Pico-Boys genutzt. Wie man das macht, habe ich in
diesem Beitrag auf meiner Seite beschrieben. Grundlage
dafür bietet der von mir in CircuitPython angepasste Treiber 'my_stk8ba58.py'. Daraus folgt der im unteren Kasten
dargestellt Programmanfang:
1 import time 2 import board 3 import busio 4 import displayio 5 import digitalio 6 import terminalio 7 from fourwire import FourWire 8 from adafruit_display_text import label 9 from adafruit_display_shapes.roundrect import RoundRect 10 from adafruit_display_shapes.circle import Circle 11 import adafruit_displayio_sh1106 12 import my_stk8ba58 13 from adafruit_progressbar.horizontalprogressbar import ( 14 HorizontalProgressBar, HorizontalFillDirection,) 15 16 #rote LED 17 led_red = digitalio.DigitalInOut(board.GP5) 18 led_red.direction = digitalio.Direction.OUTPUT 19 #gruene LED 20 led_green = digitalio.DigitalInOut(board.GP7) 21 led_green.direction = digitalio.Direction.OUTPUT 22 #JOY_CENTER = GP0 23 center = digitalio.DigitalInOut(board.GP0) 24 center.direction = digitalio.Direction.INPUT 25 center.pull = digitalio.Pull.UP 26 27 # built-in a display 28 displayio.release_displays() 29 # Make the displayio SPI bus and the sh1106 display 30 spi = busio.SPI(board.GP18, board.GP19) 31 display_bus = FourWire(spi, command=board.GP8, chip_select=board.GP10, reset=board.GP9, baudrate=1000000) 32 display =adafruit_displayio_sh1106.SH1106(display_bus, width=132, height=64, rotation=0) 33 34 # Make the display context 35 splash = displayio.Group() 36 sleep = displayio.Group() 37 38 # ACC-Sensor initialisieren 39 sensor=my_stk8ba58.STK8BA58() 40
In den beiden Programmzeilen 35 und 36 werden zwei (!) Displaybereiche definiert
- splash = displayio.Group() und
- sleep = displayio.Group()
zwischen denen beim Betätigen der Joystick-Taste umgeschaltet wird. Der Befehl
dazu lautet jetzt display.root_group = sleep bzw. display.root_group = splash und ersetzt den
früheren Befehl display.show(xxxxx), der ab Version 9.x.x nicht mehr vorkommt. Was will ich mit den beiden
Anzeigebereichen erreichen? Beim Einschalten des Pico-Boys ist der Bereich 'sleep' zu sehen.
Bei einem Druck auf den Joystick-Button wird in den 'Messmodus' gewechselt bzw. aus dem 'Messmodus' wieder in den 'Ruhemodus' zurückgeschaltet.
Dazu werden vorab Textlabel und Zeichenelemente definiert, wie sie im Kasten in den Zeilen 54 bis 99 dargestellt sind. Im Anschluss werde ich
die Benutzung der 'ProgressBar' erklären:
41 # Make the background bitmap when it sleeps 42 color_bitmap = displayio.Bitmap(128, 64, 1) 43 color_palette = displayio.Palette(1) 44 color_palette[0] = 0x000000 45 bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) 46 sleep.append(bg_sprite) 47 # create the label, when it sleeps 48 text_label = label.Label(font=terminalio.FONT, text="PicoBoy", scale=2, color=0xffffff, line_spacing=1) 49 text_label.anchor_point = (0, 0) 50 text_label.anchored_position = (30, 0) 51 sleep.append(text_label) 52 text_label = label.Label(font=terminalio.FONT, text="press Joystick\n to start", scale=1, color=0xffffff, line_spacing=1) 53 text_label.anchor_point = (0, 0) 54 text_label.anchored_position = (30, 40) 55 sleep.append(text_label) 56 57 rect1 = RoundRect(1,1,130,63,10,fill=0xffffff, outline=None) 58 splash.append(rect1) 59 rect2 = RoundRect(3,3,126,59,8,fill=0x000000, outline=None) 60 splash.append(rect2) 61 62 # Accelerometer Properties. Normally accelerometer well calibrated 63 # Will give a maximum output of 10 mts / s**2 64 # We create our bar displays 65 left_horizontal_bar = HorizontalProgressBar( 66 (20, 20),(50, 25), min_value=0, max_value=2, 67 direction=HorizontalFillDirection.RIGHT_TO_LEFT, 68 bar_color=0x00cc00, outline_color=0xffffff, fill_color=0x606060) 69 splash.append(left_horizontal_bar) 70 71 right_horizontal_bar = HorizontalProgressBar( 72 (70, 20), (50, 25), min_value=0, max_value=2, 73 direction=HorizontalFillDirection.LEFT_TO_RIGHT, 74 bar_color=0x00cc00, outline_color=0xffffff, fill_color=0x606060) 75 splash.append(right_horizontal_bar) 76 77 78 # create the label 79 text_label = label.Label(font=terminalio.FONT, text=" PicoBoy\n\n\n\nspirit-level", scale=1, color=0xffffff, line_spacing=0.95) 80 text_label.anchor_point = (0, 0) 81 text_label.anchored_position = (35, 4) 82 splash.append(text_label) 83 84 on = 0 85 display.root_group = sleep 86
Die 'ProgressBars' werden unterschieden nach
- HorizontalProgressBar und
- VerticalProgressBar
In unserem Fall verwende ich eine left_horizontal_bar (Zeile 65) und eine
right_horizontal_bar (Zeile 71), um den Ausschlag nach links bzw. rechts anzuzeigen.
Als Parameter werden:
- die Koordinaten der oberen linken Ecke (bzw. rechten Ecke) der Fortschrittsleiste erwartet,
- die Größe (Breite, Höhe) des Fortschrittsbalkens in Pixeln,
- der niedrigste und höchste Wert min_value = xx und max_value = yy und
- weiterhin direction, bar_color, outline_color und fill_color.
Beachte: Nicht der Name left_horizontal_bar bzw. right_horizontal_bar legt die
Richtung des Ausschlags fest, sondern der Parameter direction=HorizontalFillDirection.RIGHT_TO_LEFT bzw.
direction=HorizontalFillDirection.LEFT_TO_RIGHT.
In Zeile 84 wird die Variable 'on=0' gesetzt und der 'Ruhemodus' angezeigt. Nun folgt die 'while-Schleife'.
87 while True: 88 if center.value == False and on == 1: 89 on = 0 90 display.root_group = sleep 91 led_red.value = False 92 led_green.value = False 93 time.sleep(1) 94 if center.value == False and on == 0: 95 on = 1 96 display.root_group = splash 97 time.sleep(1) 98 if on == 1: 99 #read STK8BA58 100 wert_y = sensor.yAcc() * 10 101 #wert_y etwas kleiner kalibrieren laut Versuchen 102 wert_y = wert_y - 0.16 103 if wert_y >= 0 and wert_y < 0.2 or wert_y < 0 and wert_y >= -0.2 : 104 led_green.value=True 105 led_red.value=False 106 # Ausschlag nach links und rechts 107 if wert_y > 0 and wert_y <= 2: 108 if wert_y >= 0.2: 109 led_red.value = True 110 led_green.value = False 111 left_horizontal_bar.value = wert_y 112 right_horizontal_bar.value = 0 113 left_horizontal_bar.bar_color=0x00cc00 114 if wert_y < 0 and wert_y >= -2: 115 if wert_y <= -0.2: 116 led_red.value = True 117 led_green.value = False 118 right_horizontal_bar.value = -wert_y 119 left_horizontal_bar.value = 0 120 right_horizontal_bar.bar_color=0x00cc00 121 time.sleep(0.2)
Erläuterungen:
Zeilen 88 bis 93: Der Messmodus ist an und es wurde der Joystick gedrückt. Darauf wird in den Ruhemodus umgeschaltet und
die rote und grüne LED ausgeschaltet. Die Sekunde 'time.sleep(1) dient dem Entprellen des Tasters.
Zeilen 94 bis 97: Es wird aus dem Ruhemodus in den Messmodus umgeschaltet.
Die Zeilen 98 bis 121 beschreiben die Abarbeitung im Messmodus. Als Sensorwert wird wert_y = sensor.yAcc() * 10
gesetzt. Versuche haben ergeben, dass es genauer war, diesen um 0.16 zu verringern (evtl. ist das Gehäuse nicht exakt gleich hoch
auf beiden Seiten).
Wenn sich nun die Werte zwischen -0.2 und +0.2 befinden (Zeile 103), wird fast kein Ausschlag angezeigt und die
grüne LED ist an (rote LED aus). Damit wird der Zustand 'waagerecht' wiedergegeben. Alle anderen Werte zwischen -2 und +2 zeigen
den entsprechenden Ausschlag nach links bzw. rechts und die rote LED ist an (Zeilen 107 bis 120). D.h. der Untergrund ist nach der
entsprechenden Seite 'schief'.
Fazit:
Das Ziel bei der Messung ist also, dass die rote LED möglichst nicht und die grüne LED durchgehend leuchtet. Dann liegt das
Gehäuse des Pico-Boy in der Waage bzw. der Untergrund ist waagerecht ausgerichtet. Durch einen kurzen Druck auf die Joysticktaste
wird das Gerät in den Ruhemodus geschaltet, um Strom zu sparen und die Lebensdauer der Knopfzelle zu verlängern.
Viel Spass und Erfolg beim Ausprobieren.
Viel Spass und Erfolg beim Ausprobieren.