Wie du das kleine Spiel „Pixel Chaser“ für den Raspberry PI Pico programmierst, möchte ich dir in diesem Beitrag zeigen.
Was ist Pixel Chaser?
Das Spiel „Pixel Chaser“ funktioniert recht einfach. Du musst lediglich eine Taste betätigen, wenn zwei NeoPixel übereinander liegen. Die Schwierigkeit dabei liegt daran dass, der eine Pixel feststeht und der andere sich im Kreis dreht.
Aufbau der Schaltung
Für den Aufbau der Schaltung benötigst du:
- Raspberry PI Pico*,
- ein 8bit NeoPixel Ring* (besser noch ein 16bit* oder 24bit*)
- ein Piezo Buzzer*,
- ein Taster für die Printmontage* inkl. Kappe,
- ein 10 kOhm Widerstand*,
- diverse Breadboardkabel*,
- ein 170 Pin Breadboard*
Hinweis von mir: Die mit einem Sternchen (*) markierten Links sind Affiliate-Links. Wenn du über diese Links einkaufst, erhalte ich eine kleine Provision, die dazu beiträgt, diesen Blog zu unterstützen. Der Preis für dich bleibt dabei unverändert. Vielen Dank für deine Unterstützung!
Achtung!
Der Raspberry PI Pico kann nur maximal 30 NeoPixel gleichzeitig betreiben, d.h. alle NeoPixel sind aktiviert. Wenn du mehr als 30 an einem Pi Pico steuern möchtest, so musst du eine externe 5V Stromquelle einbinden.
Das kannst du zbsp. mit einem Power Shield für die 400 bzw. 720 Pin Breadboards* erledigen.
Das Modul „Power Supply for Breadboards“ kann 3,3V und 5V liefern, welches mit einem Jumper gesetzt werden kann.
Wenn du dieses Modul in deine Schaltung integrierst, dann musst du zusätzlich noch den Minus-Pol des Power Supply Moduls mit einem GND des Raspberry PI Pico verbinden!
Anschluss des NeoPixel Ring
Zunächst widmen wir uns dem Pixel Ring, dieser verfügt auf der Rückseite über 3 Lötpunkte an welche Breadboardkabel angelötet werden können.



ABER diese Kabel sind recht dünn und daher reißen diese bei mehrmaliger Bewegung recht schnell ab.
Da an diesem Pixel Ring ein NeoPixel defekt ist, habe ich mir schnell ein neuen, etwas größeren Ring (16bit = 16 NeoPixel) bei Roboter-Bausatz.de für knapp 7 € inkl. Versandkosten bestellt.
Dieser NeoPixel Ring hat vier Pins.
| Beschriftung | Beschreibung |
|---|---|
| DI | digital IN |
| 5V | Versorgungsspannung |
| GND | Minus-Pol |
| DO | digital OUT |
Über den DO Pin kann ein oder mehrere NeoPixel Ringe kaskadierend angeschlossen werden.
Schaltbild
Programmieren in CircuitPython
Für die Programmierung des NeoPixel Rings für den Raspberry PI Pico gibt es diverse Bibliotheken. Jedoch habe ich mit der Adafruit Bibliothek deutlichen erfolg gehabt. Diese Bibliothek findest du als Download unter https://circuitpython.org/libraries bzw. zum direkten Download der knapp 4 MB großen ZIP Datei.
Der Download hat mit meiner 100MBit Leitung knapp 4 Minuten gedauert, also bitte etwas Zeit beim Download mitbringen.
Download & kopieren der NeoPixel Bibliothek
Wenn die knapp 4 MB große ZIP Datei heruntergeladen und entpackt wurde, muss die Datei „neopixel.mpy“ nach X:\CIRCUPY\lib kopiert werden.
Erstellen des Programmes im MU Editor
Für die Programmierung nutze ich die kostenfreie, kleine IDE „MU Editor“ welche du von der Seite https://codewith.mu/en/download herunterladen kannst. Diesen Editor bekommst du für Microsoft Windows, MacOS sowie als Python Package (für Linux).
Programmieren des Spieles „Pixel Chaser“ in X Schritten
Wie du das Spiel „Pixel Chaser“ programmierst, möchte ich dir in x einfachen Schritten zeigen.
Schritt 1 – steuern eines NeoPixel Rings
Im ersten Schritt wollen wir einen NeoPixel Ring ansteuern. Im Detail heißt dass, das wir zunächst einmal prüfen, wie wir die einzelnen Pixel eines NeoPixel Rings ansteuern können.
# importieren der Funktion sleep aus dem Modul time
from time import sleep
# Modul "board" für die Ansteuerung der GPIOs
import board
# Modul zum Ansteuern eines NeoPixel
import neopixel
#Anzahl der verfügbaren NeoPixel
numPixels = 12
#initialisieren der NeoPixel am GPO0 und der Anzahl "numPixels"
pixels = neopixel.NeoPixel(board.GP0, numPixels)
#Helligkeit auf 50% setzen
pixels.brightness = 0.5
#Endlosschleife
while True:
#von 0 bis Anzahl "numPixels" mache...
for pixel in range(num_pixels):
#NeoPixel an Position "pixel" in die Farbe grün färben
pixels[pixel] = (0, 255, 0)
#eine Pause von 0,03 Sekunden
sleep(0.03)
#NeoPixel an Position "pixel" in die Farbe schwarz färben
#quasi den Pixel deaktivieren
pixels[pixel] = (0, 0, 0)
steuern der Geschwindigkeit mit einem Drehpotentiometer
Die Geschwindigkeit des Umschaltens steuern wir im Code mit einer kleinen Pause, in diesem Fall sind es 0,03 Sekunden. Wir können diese Pause auch über einen 50 kOhm Drehpotentiometer manipulieren.
Quellcode
# importieren der Funktion sleep aus dem Modul time
from time import sleep
# Modul "board" für die Ansteuerung der GPIOs
import board
# Modul zum Ansteuern eines NeoPixel
import neopixel
from analogio import AnalogIn
#Anzahl der verfügbaren NeoPixel
numPixels = 12
#initialisieren der NeoPixel am GPO0 und der Anzahl "numPixels"
pixels = neopixel.NeoPixel(board.GP0, numPixels)
#Helligkeit auf 50% setzen
pixels.brightness = 0.5
poti = AnalogIn(board.GP27)
#Funktion zum Mappen eines Werte zu einer Range
#https://stackoverflow.com/questions/1969240/mapping-a-range-of-values-to-another
def translate(value, leftMin, leftMax, rightMin, rightMax):
leftSpan = leftMax - leftMin
rightSpan = rightMax - rightMin
valueScaled = float(value - leftMin) / float(leftSpan)
return rightMin + (valueScaled * rightSpan)
#berechnen eines Wertes für die Pause
def pauseValue():
value = poti.value
return translate(value, 0,65520, 0,5)
#Endlosschleife
while True:
#von 0 bis Anzahl "numPixels" mache...
for pixel in range(numPixels):
#NeoPixel an Position "pixel" in die Farbe grün färben
pixels[pixel] = (0, 255, 0)
#eine Pause von 0,03 Sekunden
sleep(pauseValue())
#NeoPixel an Position "pixel" in die Farbe schwarz färben
#quasi den Pixel deaktivieren
pixels[pixel] = (0, 0, 0)
Video
Über diesen Drehpotentiometer können wir nun den Schwierigkeitsgrad des Spieles einstellen. Oder wir lassen diesen vom Mikrocontroller einstellen. Beide Varianten sind möglich.
Schritt 2 – einbau des Tasters
Wie du einen Taster an einem Raspberry PI Pico anschließt und auslesen kannst, habe ich dir bereits im Beitrag Raspberry PI Pico #4 – Taster mit PullDown & PullUp abfragen ausführlich erläutert.
# Modul "board" für die Ansteuerung der GPIOs import board # Modul um den Status eines Buttons einzulegen import digitalio # Taster am GPIO1 angeschlossen button = digitalio.DigitalInOut(board.GP1) button.direction = digitalio.Direction.INPUT
Schritt 3 – Piezo Buzzer für die Ausgabe eines Tones
Damit wir eine akustische Rückmeldung haben, ob wir gewonnen oder verloren haben, bauen wir nun einen Piezo Buzzer ein.
import time
import board
import pulseio
tones = [ 200, 800]
buzzer = pulseio.PWMOut(board.GP2, variable_frequency=True)
buzzer.frequency = tones[0]
buzzer.duty_cycle = 2**15
while True:
buzzer.frequency = tones[0]
time.sleep(0.5)
buzzer.frequency = tones[1]
time.sleep(0.5)
fertiges Spiel „Pixel Chaser“
Hier nun der fertige Code.
# Modul für den Import einer Funktion zum einlegen einen Pause im Code
from time import sleep
# Modul "board" für die Ansteuerung der GPIOs
import board
# Modul um den Status eines Buttons einzulegen
import digitalio
# Modul zum Ansteuern eines NeoPixel
import neopixel
# Modul um eine Zufallszah lzu generieren
from random import randint
# Modul um ein PWM Signal zu erzeugen (wird für den Piezo Buzzer benötigt)
import pulseio
# Taster am GPIO1 angeschlossen
button = digitalio.DigitalInOut(board.GP1)
button.direction = digitalio.Direction.INPUT
# initialisieren des Piezo Buzzers am GPIO2 Pin
buzzer = pulseio.PWMOut(board.GP2, variable_frequency=True)
# zunächst die Frequenz auf 1 und die Wellenlänge auf 0
buzzer.frequency = 1
buzzer.duty_cycle = 0
# Anzahl der verfügbaren NeoPixel
numPixels = 16
# aktiver Pixel
activePixel = -1
# initialisieren der NeoPixel am GPO0 und der Anzahl "numPixels"
pixels = neopixel.NeoPixel(board.GP0, numPixels)
# Helligkeit auf 10% setzen
pixels.brightness = 0.1
# Töne welche wiedergegeben werden sollen
tone = [
200, # Ton für verloren
800 # Ton für gewonnen
]
# erzeugen einer Zufallszahl & aktivieren des Pixels
# dieser aktivierte Pixel wird in der globalen Variable
# activePixel gespeichert
def activateRandomPixel():
global activePixel
activePixel = randint(0, numPixels-1)
pixels[activePixel] = (255, 0, 0)
# löscht alle aktiven NeoPixel
def clearPixels():
for pixel in range(numPixels):
pixels[pixel] = (0, 0, 0)
# deaktivieren des Piezo Buzzers
def turnPiezoBuzzerOff():
buzzer.duty_cycle = 0
# aktivieren des Piezo Buzzers
def turnPiezoBuzzerOn():
buzzer.duty_cycle = 2**15
activateRandomPixel()
# Endlosschleife
while True:
# von 0 bis Anzahl "numPixels" mache...
for pixel in range(numPixels):
# wenn der aktive Pixel nicht der gleiche aus der Schleife ist,
# dann mache...
if pixel != activePixel:
# NeoPixel an Position "pixel" in die Farbe grün färben
pixels[pixel] = (0, 255, 0)
# eine Pause von 0,03 Sekunden
sleep(0.25)
# NeoPixel an Position "pixel" in die Farbe schwarz färben
# quasi den Pixel deaktivieren
pixels[pixel] = (0, 0, 0)
# Wenn der Button gedrückt ist, dann...
if not button.value:
# aktivieren des Piezo Buzzers
turnPiezoBuzzerOn()
# ausgeben der Pixel auf der Console
print(activePixel, pixel, sep="|")
# Wenn der aktive Pixel gleich der Pixel aus der
# Schleife ist, dann...
if (activePixel-1) == pixel:
# ausgeben der Zeichenkette "gewonnen"
print("gewonnen")
# ausgeben eines Tones
buzzer.frequency = tone[1]
# eine kleine Pause
sleep(0.1)
buzzer.frequency = tone[1]
sleep(0.1)
buzzer.frequency = 1
# löschen aller Pixel
clearPixels()
# ermitteln eines neuen Pixels welcher gesucht werden soll
activateRandomPixel()
else: # Wenn die beiden Pixel nicht übereinander liegen dann...
buzzer.frequency = tone[0]
sleep(0.25)
buzzer.frequency = 1
# deaktivieren des Piezo Buzzers
turnPiezoBuzzerOff()
Letzte Aktualisierung am: 09. März 2024





