Das Projekt hat sich von dem Spiel „Paint Splash“ aus der Wii-Konsole inspiriert. Hier ist eine Demonstration: Paint Splash
Im Projekt werden der Sense Hat und drei externe Buttons verwendet. Aus dem Sense Hat sind der Magnetometer, die 8×8 LED-Matrix und der Joystick relevant. In Pygame wird ein Malprogramm mit einem x-y Koordinatensystem implementiert, sodass der Malstift anhand des Magnetometers gesteuert wird. Um zu bestimmen, wann der Malstift im Malfenster zeichnen soll oder nicht, muss man mit dem Joystick interagieren. Für die Bestimmung der Koordinaten des Malstiftes wird die Position des Sense Hats regelmäßig abgefragt und im Malfenster gespeichert. Nach der Abfrage wird ein Kreis mit vorher definierten Parametern gezeichnet. Durch die kontinuierliche Abfrage der Position und Zeichnung eines Kreises wird die Bewegung eines Malstiftes simuliert. Zusätzlich bieten drei externe Buttons verschiedene Funktionalitäten an, welche beim einmaligen Drücken eines Buttons beispielsweise die Farbe des Malstiftes wechselt. Nachdem der Button gedrückt wurde, erscheint ein 8×8 Bild aus der LED-Matrix. Nachdem das Malfenster geschlossen wird, wird ein Screenshot von der Zeichnung erstellt und in einem bestimmten Verzeichnis des Raspberry Pis gespeichert.
Da der Magnetometer ursprünglich für einen Kompass gedacht ist und nur einen kleinen Wertebereich nutzt, müssen die rohen Daten des Magnetometers verwendet werden. Dadurch vergrößert sich der Wertebereich, sodass die Bewegung im Malfenster erweitert wird. Von den x-y-z Koordinaten des Sense Hats werden nur die x und y Koordinaten verwendet, weil das Zeichenfenster zweidimensional ist. Hinweis: Falls der Magnetometer unerwünschte Werte anzeigt oder man genauere Koordinaten verwenden möchte, gibt es die Möglichkeit den IMU (Inertial Measurement Unit) zu kalibrieren: IMU-Kalibration
Um die Zeichenfunktion im Malprogramm zu aktivieren, gibt der Joystick des Sense Hats zwei Zustände an. Der erste Zustand des Stiftes ist als mittlere Position definiert, sodass die Malfunktion beim Drücken aktiviert wird. Der zweite Zustand ist die untere Position definiert, sodass die Malfunktion beim Drücken nach unten gestoppt wird.
Die freien GPIO Pins des Raspberry Pis können mithilfe eines verlängerten 40 PIN Headers angesprochen werden. Indem der PIN Header des Sense Hats mit den verlängerten PIN Header vertauscht wird, können die Buttons mit ihrem Kabel verbunden werden. Dabei bleibt die Funktionalität des Sense Hats erhalten. Wichtig ist, nicht die gleichen GPIO Pins wie von den Sense Hats zu verwenden, da sonst Fehler entstehen können.
Für das Projekt werden folgende Pakete benötigt:
Python3
sense_hat
enthält alle Funktionen des Sense Hats. Sense-Hat-Doku
Pygame
Mithilfe Pygame wird ein interaktives Malfenster erzeugt. In Pygame gibt es die Möglichkeit, Formen zu zeichnen, dabei ist das Zeichnen von Kreisen relevant. Dazu kann mithilfe einer Methode der Mauscursor bewegt werden, welcher zu den Positionen der Buttons springt. Pygame-Doku
Pygame GUI
ist ein Graphical User Interface, mit dem Buttons im Malfenster angezeigt werden kann. Im Programm dient sie nur zur Orientierung der Funktionalität der externen Buttons. Pygame-GUI-Doku
gpiozero
vereinfacht die Implementation der externen Buttons, da sie Funktionen aus RPI.GPIO in eigene Methoden übernimmt und dadurch den Programmcode verkürzt. gpiozero-doku
m8tricks
vereinfacht die Implementation der LED-Matrix, sodass wenn eine LED im Programm eine andere Farbe als Schwarz ausgewählt wird, auch im Sense Hat angezeigt wird. Dadurch kann leicht überprüft werden, ob ein Bild in 8×8 Format gut oder schlecht aussieht. Dazu kann die aktuelle LED-Matrix in einem Ordner gespeichert werden und später mit Thonny im Hauptprogramm gespeichert werden. M8tricks ist nur eine Hilfsanwendung, es wird nicht mit den Hauptprogramm gleichzeitig ausgeführt. m8tricks
VNC
VNC (Virtual Network Computing) übertragt den Bildschirm des Raspberry Pis mit den Malprogramm auf einen zweiten Raspberry Pi, sodass während der Übertragung keine Maus, Keyboard und HDMI-Kabel benötigt wird. Dies verbessert die Bewegung des Sense Hats mit der Hand. Um VNC zu nutzen, muss im zweiten Raspberry Pi VNC-Viewer installiert werden und beide Raspberry Pis müssen im gleichen Netzwerk sein. Um das Malprogramm zu beenden, muss mit den zweiten Raspberry Pi das Malfenster geschlossen werden. VNC-Anleitung
In Pygame werden Parameter wie Name, Größe und Hintergrundfarbe des Fensters angegeben. Dazu wird für Pygame GUI ein Bereich definiert, welcher später die Buttons im Fenster verarbeitet.
Malfenster
# Fenstergröße und Hintergrundfarbe bestimmen pygame.display.set_caption('AirDraw') screen = pygame.display.set_mode((screenX, screenY)) screen.fill(WE) pygame.display.update() # GUI-Bereich definieren manager = pygame_gui.UIManager((screenX, screenY))
Wenn ein Button im Fenster erzeugt werden soll, müssen bestimmte Parameter angegeben werden. In der Dokumentation von Pygame GUI werden weitere Möglichkeiten für Parameter angegeben.
Beispiel eines Buttons im GUI
# farbeButton erzeugen farbeButton = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((25, 20), (75, 50)), text='FARBE', manager=manager)
Falls ein externer Button gedrückt wird, wird eine Sounddatei abgespielt, der Mauszeiger springt zum jeweiligen Button im Malfenster und beispielsweise die Funktion „setze die Stiftfarbe auf Weiß“ wird ausgeführt. Zusätzlich wird in der LED-Matrix ein 8×8 Bild dargestellt und es folgt eine Pause.
Beispiel eines externen Buttons
if button2.is_pressed: sound_2.play() position2() aktuelleFarbe = WE sense.set_pixels( [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 255), (255, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 255), (255, 0, 255), (255, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 255), (255, 0, 255), (255, 0, 255), (255, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 255), (255, 0, 255), (255, 0, 255), (255, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 255), (255, 0, 255), (255, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 255), (255, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)]) pygame.time.delay(2500) sense.clear()
Um die Koordinaten vom Sense Hat in Pygame korrekt anzeigen zu können, müssen die Sensordaten des Sense Hats formatiert und gerundet werden. Danach wird im Malfenster mit den Koordinaten des Sense Hats ein Kreis gezeichnet.
Kreis an der richtigen Position zeichnen
raw = sense.get_compass_raw() # Button für das Zeichnen wird gedrückt if event.type == Draw and zeichnen is True: # Formatierung und Berechnung der Position des Stiftes xsense = "{x}".format(**raw) ysense = "{y}".format(**raw) xsense = float(xsense) ysense = float(ysense) xsense = round(xsense) ysense = round(ysense) # Multiplikation mit negativer Zahl, weil der SenseHat in Normalposition negative Zahlen anzeigt lastPos = ((ysense * -10) + 350, (xsense * -10) - 200) pygame.draw.circle(screen, aktuelleFarbe, lastPos, radius) pygame.display.update() pygame.time.delay(100)
Am Ende des Malprogramms wird ein Bild vom Malfenster erzeugt und im Verzeichnis „Zeichnungen“ gepeichert. Außerdem wird Pygame heruntergefahren.
Ende des Malprogramms
except StopIteration: pass sense.clear() screenshot.blit(sub, (0, 0)) # Ordner "Zeichnungen" wurde vorher für die Ablage erstellt pygame.image.save(screenshot, "/home/raspberry/Dokumente/Zeichnungen/Zeichnung.bmp") print("Die Zeichnung wurde erfolgreich gespeichert.") # Programm wird beendet pygame.mixer.music.stop() pygame.quit()
# Pakete importieren import pygame import pygame_gui from sense_hat import SenseHat from gpiozero import Button # Buttons definieren button1 = Button("BOARD11") button2 = Button("BOARD13") button3 = Button("BOARD29") # Pygame und Sense Hat starten pygame.mixer.pre_init(44100, -16, 2, 2048) pygame.init() pygame.mixer.init() sense = SenseHat() # LED-Matrix in Normalzustand versetzen sense.clear() # Hintergrundmusik starten pygame.mixer.music.load('noodleSoup.mp3') pygame.mixer.music.play(-1) pygame.mixer.music.set_volume(0.3) # Fenstergröße bestimmen screenX = 800 screenY = 600 # Farben mit RGB-Werten bestimmen WE = (255, 255, 255) SCHW = (0, 0, 0) ROT = (255, 0, 0) GR = (0, 255, 0) BL = (0, 0, 255) # Liste für FarbeButton Farben = [ROT, GR, BL] aktuelleFarbe = SCHW # Zähler für Farben_Button counter = 0 # Bedingung für while-Schleife durchlaufen = True # Fenstergröße und Hintergrundfarbe bestimmen pygame.display.set_caption('AirDraw') screen = pygame.display.set_mode((screenX, screenY)) screen.fill(WE) pygame.display.update() # GUI-Bereich definieren manager = pygame_gui.UIManager((screenX, screenY)) # farbeButton erzeugen farbeButton = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((25, 20), (75, 50)), text='FARBE', manager=manager) # loeschButton erzeugen loeschButton = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((125, 20), (83, 50)), text='LÖSCHEN', manager=manager) # resetButton erzeugen resetButton = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((225, 20), (75, 50)), text='RESET', manager=manager) # Uhr für Bildwiederholrate und Abfrage der Buttons clock = pygame.time.Clock() # boolean zur Bestimmung des Zustandes des Stiftes zeichnen = False # Endposition des Stiftzeigers lastPos = (0, 0) # Radius vom Kreis, also Stiftdicke am Anfang bestimmen radius = 10 # boolean, um Loeschzustand zu bestimmen radierer = 0 # Bildwiederholrate auf 60 FPS, um Leistung zu minimieren timeDelta = clock.tick(60) / 1000.0 # Definition eines eignen Pygame-Events, um in der Methode pygame.event.get() zu erscheinen Draw = pygame.USEREVENT + 0 pygame.time.set_timer(Draw, 100) # Positionen des Mauscursors, um Buttons zu erreichen (zur Veranschaulichung) def startPosition(): { pygame.mouse.set_pos([screenX / 2, screenY / 2]) } def position1(): { pygame.mouse.set_pos([screenX - 742, screenY - 555]) } def position2(): { pygame.mouse.set_pos([screenX - 637, screenY - 555]) } def position3(): { pygame.mouse.set_pos([screenX - 542, screenY - 555]) } # Definition eines Teilfensters, welches als später als Zeichunung.bmp gespeichert wird rect = pygame.Rect(0, 70, 800, 500) sub = screen.subsurface(rect) screenshot = pygame.Surface((screenX, 500)) # Soundeffekte initialisieren sound_1 = pygame.mixer.Sound('decidemp.mp3') sound_1.set_volume(0.4) sound_2 = pygame.mixer.Sound('ding.mp3') sound_2.set_volume(0.4) sound_3 = pygame.mixer.Sound('woosh.mp3') sound_3.set_volume(0.4) # Mauszeiger in der Mitte des Malfensters startPosition() # Programm wird gestartet try: while durchlaufen: # alle externe Button-Events if button1.is_pressed: sound_1.play() position1() if aktuelleFarbe == WE: aktuelleFarbe = SCHW # set_pixels() zeigt im SenseHat die LEDS an sense.set_pixels( [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 0), (255, 0, 0), (0, 0, 0), (0, 0, 0), (0, 255, 0), (0, 255, 0), (0, 0, 0), (0, 0, 0), (255, 0, 0), (255, 0, 0), (0, 0, 0), (0, 0, 0), (0, 255, 0), (0, 255, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 255), (0, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 255), (0, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)]) pygame.time.delay(2500) sense.clear() else: counter = counter + 1 if counter == 1: aktuelleFarbe = Farben[0] sense.set_pixels( [(255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 255, 255), (255, 0, 0), (255, 0, 0), (255, 255, 255), (0, 0, 0), (0, 255, 0), (0, 255, 0), (0, 0, 0), (255, 255, 255), (255, 0, 0), (255, 0, 0), (255, 255, 255), (0, 0, 0), (0, 255, 0), (0, 255, 0), (0, 0, 0), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 255), (0, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 255), (0, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)]) pygame.time.delay(2500) sense.clear() if counter == 2: aktuelleFarbe = Farben[1] sense.set_pixels([(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (0, 0, 0), (255, 0, 0), (255, 0, 0), (0, 0, 0), (255, 255, 255), (0, 255, 0), (0, 255, 0), (255, 255, 255), (0, 0, 0), (255, 0, 0), (255, 0, 0), (0, 0, 0), (255, 255, 255), (0, 255, 0), (0, 255, 0), (255, 255, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 255), (0, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 255), (0, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)]) pygame.time.delay(2500) sense.clear() if counter == 3: aktuelleFarbe = Farben[2] sense.set_pixels( [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 0), (255, 0, 0), (0, 0, 0), (0, 0, 0), (0, 255, 0), (0, 255, 0), (0, 0, 0), (0, 0, 0), (255, 0, 0), (255, 0, 0), (0, 0, 0), (0, 0, 0), (0, 255, 0), (0, 255, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 255, 255), (0, 0, 255), (0, 0, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 255, 255), (0, 0, 255), (0, 0, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255)]) pygame.time.delay(2500) sense.clear() if counter == 4: aktuelleFarbe = SCHW sense.set_pixels( [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 0), (255, 0, 0), (0, 0, 0), (0, 0, 0), (0, 255, 0), (0, 255, 0), (0, 0, 0), (0, 0, 0), (255, 0, 0), (255, 0, 0), (0, 0, 0), (0, 0, 0), (0, 255, 0), (0, 255, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 255, 255), (0, 0, 0), (0, 0, 0), (255, 255, 255), (0, 0, 0), (0, 0, 255), (0, 0, 255), (0, 0, 0), (255, 255, 255), (0, 0, 0), (0, 0, 0), (255, 255, 255), (0, 0, 0), (0, 0, 255), (0, 0, 255), (0, 0, 0), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)]) pygame.time.delay(2500) sense.clear() counter = 0 if button2.is_pressed: sound_2.play() position2() aktuelleFarbe = WE sense.set_pixels( [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 255), (255, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 255), (255, 0, 255), (255, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 255), (255, 0, 255), (255, 0, 255), (255, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 255), (255, 0, 255), (255, 0, 255), (255, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 255), (255, 0, 255), (255, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 0, 255), (255, 0, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)]) pygame.time.delay(2500) sense.clear() if button3.is_pressed: sound_3.play() position3() screen.fill(WE) aktuelleFarbe = SCHW pygame.display.update() sense.set_pixels( [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (255, 255, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)]) pygame.time.delay(2500) sense.clear() # Joystick-Events for event in sense.stick.get_events(): if event.action == 'pressed' and event.direction == 'middle': zeichnen = True elif event.action == 'pressed' and event.direction == 'down': zeichnen = False # allgemeine Events for event in pygame.event.get(): raw = sense.get_compass_raw() # Button für das Zeichnen wird gedrückt if event.type == Draw and zeichnen is True: # Formatierung und Berechnung der Position des Stiftes xsense = "{x}".format(**raw) ysense = "{y}".format(**raw) xsense = float(xsense) ysense = float(ysense) xsense = round(xsense) ysense = round(ysense) # Multiplikation mit negativer Zahl, weil der SenseHat in Normalposition negative Zahlen anzeigt lastPos = ((ysense * -10) + 350, (xsense * -10) - 200) pygame.draw.circle(screen, aktuelleFarbe, lastPos, radius) pygame.display.update() pygame.time.delay(100) # Bedingung wird erfüllt, wenn Malfenster geschlossen wird if event.type == pygame.QUIT: raise StopIteration # führt die Events aus manager.process_events(event) # aktualisiert den Zustand der Buttons manager.update(timeDelta) # die Änderungen im Fenster werden in Pygame verarbeitet screen.blit(screen, (0, 0)) manager.draw_ui(screen) clock.tick(60) pygame.display.update() except StopIteration: pass sense.clear() screenshot.blit(sub, (0, 0)) # Ordner "Zeichnungen" wurde vorher für die Ablage erstellt pygame.image.save(screenshot, "/home/raspberry/Dokumente/Zeichnungen/Zeichnung.bmp") print("Die Zeichnung wurde erfolgreich gespeichert.") # Programm wird beendet pygame.mixer.music.stop() pygame.quit()
Um die Sounddateien im Malprogramm abspielen zu können, müssen sie sich im gleichen Verzeichnis neben der Python-Datei sich befinden.
Fritzing-Quellen
https://forum.fritzing.org/t/raspberry-pi-4-model-b/8622/13
https://github.com/RafaGS/Fritzing/blob/master/Raspberry%20Pi%20Sense%20Hat.fzpz
Dokumentationen
https://pygame-gui.readthedocs.io/en/latest/
https://gpiozero.readthedocs.io/en/stable/
https://pythonhosted.org/sense-hat/api/
https://www.raspberrypi.com/documentation/accessories/sense-hat.html
Programme
https://github.com/topshed/m8tricks
https://buyzero.de/en/blogs/news/wie-kann-ich-realvnc-mit-einem-raspberry-pi-nutzen-remote-desktop
Codebeispiele
https://stackoverflow.com/questions/7746263/how-can-i-play-an-mp3-with-pygame
https://tousu.in/qa/?qa=920344/mouse-how-to-create-ms-paint-clone-with-python-and-pygame
Soundquellen
https://pixabay.com/sound-effects/
Andere Quellen
http://paintsplash.knapnokgames.com/?p=story
https://www.youtube.com/watch?v=Pjhv0I6LShc
https://pinout.xyz/pinout/sense_hat#
https://www.berrybase.de/raspberry-pi-4-computer-modell-b-8gb-ram
https://www.raspberrypi.com/news/raspberry-pi-400-the-70-desktop-pc/
https://www.adafruit.com/product/4301
https://www.berrybase.de/offizielles-sense-hat-f-252-r-raspberry-pi
https://www.pvc-welt.de/Kabelbinder-neutral
https://www.amazon.de/-/en/PL7-Portable-Bluetooth-Protection-sdLighting/dp/B086LST81G
https://www.rototron.info/using-an-i2c-lcd-display-with-a-raspberry-pi/