Ausprobiert Teil 2

Rundes 1.28-Zoll-IPS-LCD-Display 240 x 240 Pixel
- RP2040, 6-Achsen-Sensor - Waveshare 22668
Ein wenig Mathematik muss sein:
- kleiner Exkurs in die Winkelfunktionen -



Bildbox 1 (klick hier)

Hardware

- Rundes 1,28-Zoll-IPS-LCD-Display
- RP Pico 2040 (inclusive)
- USB-A zu USB-C Kabel


Unser Display ist rund. Deshalb kommt man z.B. bei der Darstellung von Punkten, Zeigern u.ä. nicht ohne die Winkelfunktionen Sinus und Cosinus aus. Gehen wir kurz auf die Definitionen von Sinus und Cosinus ein.
sin(alpha) = Gegenkathete / Radius
Da die Gegenkathete hier der y-Koordinate im Koordinatensystem entspricht folgt daraus:
y = r * sin(alpha)
Analog gilt dann für den Cosinus:
cos(alpha) = Ankathete / Radius
Dabei entspricht die Ankathete der x-Koordinate, also:
x = r * cos(alpha)
Klicken Sie auf die Bildbox 1 (oben) und sehen sich die Abbildungen dazu an.

Auf den beiden unteren Fotos wird das für die 'Sekundenpunkte', 'Minutenpunkte', 'Stundenpunkte' bzw. die Position der Zeigerspitzen genuzt.




Los gehts mit einem Beispiel

Das Display hat 240 x 240 Pixel. Der Mittelpunkt liegt also bei P(120/120), so dass wir als Koordinaten nachfolgend immer xpos = 120 und ypos = 120 nutzen.

Die jeweils neue x-Koordinate ergibt sich dann aus
xpos_neu = int(xpos + 100*math.cos((alpha)*math.pi/30)
und die y-Koordinate
ypos_neu = int(ypos + 100*math.sin((alpha)*math.pi/30).

Da 2*pi bekanntlich 360 Grad entsprechen, lassen sich mit pi/30 die 60 'Positionen' (360 / 180 * 30 = 60) darstellen. Mit der 100 wird in unserem Fall der Radius festgelegt. Hier nun das Beispielprogramm:

  
  

1  # SPDX-FileCopyrightText: 2023 Detlef Gebhardt, written for CircuitPython
2  # SPDX-FileCopyrightText: Copyright (c) 2023 Detlef Gebhardt
3  #
4  # SPDX-License-Identifier: GEBMEDIA
5  import time
6  import gc
7  import board
8  import busio
9  from busio import I2C
10 import displayio
11 import terminalio
12 import gc9a01
13 from adafruit_display_text import label
14 from adafruit_display_shapes.circle import Circle
15 import random
16 import math
17
18 # Release any resources currently in use for the displays
19 displayio.release_displays()
20
21 # Make the displayio SPI bus and the GC9A01 display
22 spi = busio.SPI(clock=board.LCD_CLK, MOSI=board.LCD_DIN)
23 display_bus = displayio.FourWire(spi, command=board.LCD_DC, chip_select=board.LCD_CS, reset=board.LCD_RST)
24 display = gc9a01.GC9A01(display_bus, width=240, height=240, rotation=90, backlight_pin=board.LCD_BL)
25
26 # Make the display context
27 group1 = displayio.Group()
28 display.show(group1)
29
30 width = 240
31 height = 240
32 xpos = 120
33 ypos = 120
34 radius = 120
35 i = 0
36
37# Make some circle:
38 circle = Circle(xpos, ypos, 120, fill=0xff0000, outline=0x000000)
39 group1.append(circle)
40 circle = Circle(xpos, ypos, 115, fill=0x000000, outline=0x000000)
41 group1.append(circle)
42 circle = Circle(xpos, ypos, 85, fill=0xffff00, outline=0xffff00)
43 group1.append(circle)
44 circle = Circle(xpos, ypos, 10, fill=0x0000ff, outline=0xffff00)
45 group1.append(circle)
46
47 while True:
48     for i in range (60):
49         xpos_neu = int(width/2 + 100*math.cos((i -15)*math.pi/30))
50         delta_x = xpos_neu - xpos
51         xpos = xpos_neu
52         ypos_neu = int(height/2 + 100*math.sin((i -15)*math.pi/30))
53         delta_y = ypos_neu - ypos
54         ypos = ypos_neu
55         circle.x = circle.x + delta_x
56         circle.y = circle.y + delta_y
57         time.sleep(0.05)
58         gc.collect()
59    #print(gc.mem_free())
  

Ein paar Erläuterungen. Die Programmzeilen 5 bis 28 entsprechen dem vorigen Beitrag zur Initialisierung des Displays. Hinzu gekommen sind die Module 'from adafruit_display_shapes.circle import Circle' und 'import math', welche für die Kreisdarstellung und die mathematischen Berechnungen gebraucht werden. In den Zeilen 37 bis 45 werden Kreise dargestellt, welche nacheinander das Display rot, dann mit kleinerem Durchmesser schwarz und schließlich gelb einfärben. Zuletzt wird ein kleiner blauer Kreis als Punkt in dem schwarzen Ring dargestellt. Sie sehen, dass die Syntax für den Kreis immer

circle = Circle(xpos, ypos, radius, fillcolor, outlinecolor)

ist. Es folgt die 'while' Schleife in Zeile 47. Dort wird in den Zeilen 56 und 57 eine Eigenschaft bei 'circle' genutzt, welche mit 'circle.x' bzw. 'circle.y' die neue x und y Position des Mittelpunktes annehmen kann, ohne den Kreis neu definieren zu müssen. Stattdessen wird in den Zeilen 49 bis 54 der neue geänderte Wert berechnet und als 'delta_x' und 'delta_y' zu den Mittelpunktkoordinaten addiert. Dass hat den riesigen Vorteil, dass kein zusätzlicher Speicher belegt wird, denn dann würde ganz schnell ein 'MemoryError' das Programm beenden.
Ich habe das Ganze in eine 'for i in range (60)' Schleife gepackt, deshalb steht in Zeile 49 und 52 beim Sinus bzw. Cosinus das 'i'. Die subtrahierte 15 hat ihren Sinn, weil ich das Display bei der Initialisierung um 90 Grad gedreht habe (siehe Zeile 24) und die Bewegung oben beginnen soll. Experimentieren Sie mit dem Beispiel und demnächst geht es weiter.

Zuvor gibt es aber noch eine kleine Zugabe. Probieren Sie das folgende Programm aus. Mit Hilfe der Zufallsfunktion 'random' wird mit 'wert = random.randint(min,max)' ein ganzzahliger Zufallswert zwischen 'min' und 'max' erzeugt. Diesen verwende ich für die x- und y-Koordinaten und lasse den Punkt innerhalb des schwarzen Kreises hin- und herspringen, bis er den weißen Punkt trifft.

  
  

1  # SPDX-FileCopyrightText: 2023 Detlef Gebhardt, written for CircuitPython
2  # SPDX-FileCopyrightText: Copyright (c) 2023 Detlef Gebhardt
3  #
4  # SPDX-License-Identifier: GEBMEDIA
5  import time
6  import gc
7  import board
8  import busio
9  from busio import I2C
10 import displayio
11 import terminalio
12 import gc9a01
13 from adafruit_display_text import label
14 from adafruit_display_shapes.circle import Circle
15 import random
16
17 # Release any resources currently in use for the displays
18 displayio.release_displays()
19
20 # Make the displayio SPI bus and the GC9A01 display
30 spi = busio.SPI(clock=board.LCD_CLK, MOSI=board.LCD_DIN)
31 display_bus = displayio.FourWire(spi, command=board.LCD_DC, chip_select=board.LCD_CS, reset=board.LCD_RST)
32 display = gc9a01.GC9A01(display_bus, width=240, height=240, rotation=90, backlight_pin=board.LCD_BL)
33
34 # Make the display context
35 group1 = displayio.Group()
36 display.show(group1)
37
38 width = 240
39 height = 240
40 xpos = 120
41 ypos = 120
42 radius = 120
43 xpos_neu = 0
44 ypos_neu = 0
45
46 # Make some circle:
47 circle = Circle(xpos, ypos, 120, fill=0xff0000, outline=0x000000)
group1.append(circle)
48 circle = Circle(xpos, ypos, 110, fill=0x000000, outline=0x000000)
49 group1.append(circle)
50 circle_m = Circle(xpos, ypos, 16, fill=0xffffff, outline=0x000000)
51 group1.append(circle_m)
52 circle_p = Circle(xpos, ypos, 10, fill=0x0000ff, outline=0xffff00)
53 group1.append(circle_p)
54
55 while True:
56     while not ((xpos_neu>=114 and xpos_neu<=126)and(ypos_neu>=114 and ypos_neu<=126) ):
57         x = random.randint(-75,75)
58         y = random.randint(-75,75)
59         xpos_neu = int(width/2 + x)
60         delta_x = xpos_neu - xpos
61         xpos = xpos_neu
62         ypos_neu = int(height/2 + y)
63         delta_y = ypos_neu - ypos
64         ypos = ypos_neu
65         circle_p.x = circle_p.x + delta_x
66         circle_p.y = circle_p.y + delta_y
67         time.sleep(0.2)
68         gc.collect()
69     circle_p.x = circle_p.x + 0
70     circle_p.y = circle_p.y + 0
71     #print(gc.mem_free())
  

Erinnert Sie das auch an ein Spiel aus der Kindheit, bei dem eine Kugel in einer kleinen Dose in ein Loch jongliert werden mußte. In unserem Fall steckt die Idee dahinter, dass dies unter Nutzung des Beschleunigungssensors, über den unser rundes Display verfügt, gemacht wird. Leider habe ich unter 'CircuitPython' das Modul QMI8658 noch nicht fertig und so ist das hier vorläufig ein 'fake', aber ich bin mit Hochdruck dran. Sollte jemand das o.g. Modul für 'Circuitpython'(!!!) kennen und mir dabei weiterhelfen können, würde ich mich über entsprechende Hilfe sehr freuen.


Viel Spass und Erfolg beim Ausprobieren.