In diesem Beitrag geht es um die Raspberry Pi Pico W Benchmark, wo die neue WiFi Geschwindigkeit und generelle Rechenleistung mit anderen MicroController Boards verglichen wird.
Kaum zu glauben, aber der Raspberry Pi Pico W, wieder im Folgenden einfach Pico W, ist schon released. Eigentlich wollte ich vorab noch einen Benchmark machen, aber wie es manchmal so ist, kommen dann doch unerwartet andere Themen auf. Dennoch will ich heute einmal mit kleinen Programmen zeigen, wie gut der Pico W im Vergleich zu dem D1 Mini und ESP32 Node MCU abschneidet. An der Stelle sollte aber klar sein, dass nicht auf alle Aspekte eingegangen wird, sondern erst einmal auf die pure Leistung.
Das brauchst du für die Pi Pico W Benchmark
Um das hier gezeigte nachzubauen, brauchst du folgende Komponenten
- Raspberry Pi Pico W
- Breadboard mit 400 Kontakten
- Jumper / Dupont Kabel Male – Male, trennbar
- 128×64 OLED Display, SH1106
- D1 Mini Pro
- ESP32 NodeMCU Development Board
Aufgrund der hohen Nachfrage einiger Bauteile, gibt es dieses Mal keinen vorgefertigten Warenkorb. Gerade der Pico W und das Display sind aktuell schwer erhältlich, ich bitte hier um Verständnis.
Zu Erinnerung der Pico W
Der Pico W, siehe Abbildung 1, ist der neue MicroController der Raspberry Pi Fundation. Mit den gleichen Maßen wie der Pico, 51,3mm(L) x 21mm(B) X 3,9mm(H), kann dieser perfekt in bestehende Projekte eingebunden oder der alte sogar ausgetauscht werden. Das W steht an dieser Stelle für Wireless, womit klar ist, dass die Wünsche der Maker erhört wurden. Zwar ist Bluetooth, Stand 07.2022, noch nicht freigeschaltet in der Firmware, aber mit dem WLAN kann man schon einige großartige Projekte umsetzen.
Die Verkabelung
Bei der Verkabelung nutzen ich für alle Codes den gleichen Aufbau. Diesen kannst du aus Tabelle 1 entnehmen.
Funktion | Pico W | D1 Mini | ESP32 NodeMCU |
3,3V | 3,3V | 3,3V | 3,3V |
Ground | GND | GND | GND |
SCL | 2 | D2 | D22 |
SDA | 1 | D1 | D21 |
Da ich persönlich ein Fan von Zeichnungen bin, gebe ich natürlich auch noch die Verkabelung als Bild mit für den Pico W, siehe Abbildung 2.
Bei dem ESP32 NodeMCU sieht die Verkabelung wie in Abbildung 3 aus.
Zuletzt noch der D1 Mini mit dem OLED-Display, siehe Abbildung 4.
Die benötigten Bibliotheken
Damit alles nachher funktioniert, musst du in der Paketverwaltung, siehe Abbildung 5, aufrufen.
Suche im Folgendem Dialog nach „OLED“, wähle “micropython-oled“ aus und installiere es anschließend, siehe Abbildung 6.
Beim D1 Mini musst du am Ende noch im Ordner lib -> oled die Datei __ini__.py öffnen und dort die Zeile from .lazy import * mit einem # auskommentieren, siehe Abbildung 7.
Machst du diese Änderung nicht, wird beim Kompilieren der Beispielprogramme eine Meldung erscheinen, dass das Programm zu groß zum für den D1 Mini ist. Mit diesem einfachen Trick umgehst du dieser Meldung, da wir diesen Teil der OLED-Lib nicht brauchen.
Test 1 die Verbindung mit dem WiFi
Was ich zuerst unbedingt ausprobieren musste war, wie schnell sich der Pico W im Vergleich zu den anderen MicroControllern mit meinem Router verbindet. I. Der Code dazu kannst du Code 1 entnehmen.
import network
import time
import machine
from oled import SSD1306_I2C,gfx,Write
from oled.fonts import ubuntu_mono_12, ubuntu_mono_15
bPrintDiag = False
ssid = ‘YOUR-WLAN-ID‘
password = 'WIFI-PASSWORD'
I2C_PORT = 0
I2C_SDA = machine.Pin(0) #Pin on ESP32: 21(D21) D1Mini: 4(D1) Pico W: 0(Pin 1)
I2C_SCL = machine.Pin(1) #Pin on ESP32: 22(D22) D1Mini: 5(D2) Pico W: 1(Pin 2)
#i2c = machine.I2C(I2C_PORT,sda=I2C_SDA, scl=I2C_SCL) # For ESP32 only
i2c = machine.I2C(sda=I2C_SDA, scl=I2C_SCL) # For Pico W and D1 Mini
#Definitions and init for OLED-Display
WIDTH = 128
HIGHT = 64
oled = SSD1306_I2C(WIDTH, HIGHT, i2c)
font = Write(oled,ubuntu_mono_12)
Y_Shift = 13
#Function to connect with the wifi
def connect():
#Connect to WLAN
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
print('Waiting for network . . .')
while wlan.isconnected() == False:
print()
print(' DONE')
print(wlan.ifconfig())
try:
oled.fill(0)
if bPrintDiag:
i2cScan = i2c.scan()
counter = 0
print('-----------------')
print('Found I2C-Devices')
for i in i2cScan:
print("I2C Address " + f'{counter:03d}' + " : "+hex(i).upper())
counter+=1
xPos = 10
yPos = 1
font.text('---Start system---', xPos, yPos)
yPos += Y_Shift
font.text('Start: ' + str(start_time) + 'ms', xPos, yPos)
yPos += Y_Shift
font.text('Try to connect', xPos, yPos)
oled.show()
start_time = time.ticks_ms()
connect()
yPos += Y_Shift
font.text('Connected to WiFi', xPos, yPos)
end_time = time.ticks_ms()
execution_time = round(end_time - start_time,4)
yPos += Y_Shift
font.text('Needed time: ' + str(execution_time) + 'ms', xPos, yPos)
oled.show()
print('Time to connect:' + str(execution_time))
except KeyboardInterrupt:
machine.reset()
Code 1: Auswertung bis WLAN verbunden
Der Code für diesen Test ist recht schlank und überschaubar. Zunächst werden die benötigten Bibliotheken geladen und das OLED-Display wird initialisiert. Ist das erledigt, werden die ersten drei Zeilen auf dem Display ausgegeben und im Anschluss die Verbindung zum Netzwerk durchgeführt. Um messen zu können wie lange es dies gedauert hat, wird vor dem Aufruf der Funktion „connect()“ die aktuelle MicroController-Zeit genommen und nach dem Durchlauf noch einmal. Die Zeitspanne zwischen diesen beiden Zeiten wird gerundet und in den nächsten Zeilen vom OLED-Display ausgegeben.
Das Programm zeigt im Terminal noch mehr Informationen an, dies war aber für mich nur rein interessehalber, um mich mit der Bibliothek „network“ auseinanderzusetzen.
Wenn alles funktioniert hat, sollte das OLED wie in Abbildung 8 aussehen.
Diesen Code habe ich dann auf allen MicroControllern fünf Mal laufen lassen und dann ein Mittelwert der Zeiten gebildet, siehe Tabelle 2.
Pos | Pico W | ESP32 NodeMCU | D1 Mini |
Connection Time [ms] | |||
1 | 1056 | 2864 | 2751 |
2 | 1040 | 2064 | 3887 |
3 | 1042 | 2069 | 2559 |
4 | 1042 | 2069 | 3111 |
5 | 1068 | 2069 | 3086 |
Mittelwert | 1050 | 2227 | 3079 |
Deutlich zu sehen ist, dass der Pico W sich hier am schnellsten mit dem Router verbinden konnte, wobei mich die Zeiten doch etwas überrascht haben. Gerade der D1 Mini, mit im Schnitt knapp 3 Sekunden, brauchte fast dreimal so lange wie der Pico W! Mir ist an dieser Stelle klar, dass ich hier nicht unter Laborbedingungen arbeite, aber um einen ersten Eindruck der Verbindungsgeschwindigkeit zu bekommen, sollte es vollkommen ausreichen.
Test 2 Pi berechne Pi
Der zweite Test der Pico W Benchmark widmet sich der Berechnung der Konstante Pi. Mit der Ailey–Borwein–Plouffe Formel kann, je nachdem wie viele Durchläufe man einstellt, sehr genau Pi und seine Nachkommastellen berechnet werden. Den vollständigen Code findest du in Code 2, der wieder für alle MicroController funktioniert. Beachte bitte wieder den Kommentar in den ersten Zeilen, damit auch die i2c-Schnittstelle funktioniert.
import time
import machine
from oled import SSD1306_I2C,Write,gfx
from oled.fonts import ubuntu_mono_12
I2C_PORT = 0
I2C_SDA = machine.Pin(0) #Pin on ESP32: 21(D21) D1Mini: 4(D1) Pico W: 0(Pin 1)
I2C_SCL = machine.Pin(1) #Pin on ESP32: 22(D22) D1Mini: 5(D2) Pico W: 1(Pin 2)
#i2c = machine.I2C(I2C_PORT,sda=I2C_SDA, scl=I2C_SCL) # For ESP32 only
i2c = machine.I2C(sda=I2C_SDA, scl=I2C_SCL) # For Pico W and D1 Mini
#Definitions and init for OLED-Display
WIDTH = 128
HIGHT = 64
oled = SSD1306_I2C(WIDTH, HIGHT, i2c)
graphics = gfx.GFX(WIDTH, HIGHT, oled.pixel)
font = Write(oled,ubuntu_mono_12)
Y_Shift = 13
def calculate_pi(n):
"""
Calculate the value of pi using the Bailey–Borwein–Plouffe formula.
"""
pi = 0
k = 0
while k < n:
pi += (1 / (16 ** k)) * ((4 / (8 * k + 1)) - (2 / (8 * k + 4)) - (1 / (8 * k + 5)) - (1 / (8 * k + 6)))
k += 1
if k%50 == 0:
graphics.fill_rect(10,27,int(k/n*100),10,1)
oled.show()
return pi
try:
oled.fill(0)
xPos = 10
yPos = 1
font.text('---Calculate Pi---', xPos, yPos)
start_time = time.ticks_ms()
yPos += Y_Shift
font.text('Calculating', xPos, yPos)
oled.show()
pi = calculate_pi(1500)
yPos += Y_Shift*2
end_time = time.ticks_ms()
execution_time = round(end_time - start_time,4)/1000
font.text('Time: ' + str(execution_time) + 's', xPos, yPos)
yPos += Y_Shift
font.text('Result: ' + str(pi) , xPos, yPos)
oled.show()
except KeyboardInterrupt:
machine.reset()
Code 2: Annäherung von Pi mittels Ailey–Borwein–Plouffe Formel
In diesem Code werden wieder Bibliotheken geladen und die i2c-Schnittstelle samt OLED-Display wird initialisiert. Direkt im Anschluss werden die ersten beiden Zeilen auf dem OLED-Display ausgegeben und die Startzeit, also die aktuelle Laufzeit vom MicroController ermittelt. Direkt im Anschluss wird die Funktion calculate_pi() ausgeführt, die 1500 mal eine Schleife durchlaufen lassen soll. Damit du zu diesem Zeitpunkt auch siehst, dass etwas passiert, wird immer bei einem Wert, der ohne Rest durch 50 teilbar ist (Stichwort Modulo), ein Fortschrittsbalken aktualisiert. Ist die Berechnung abgeschlossen wird wieder die aktuelle Laufzeit ermittelt und die Differenz errechnet. Das Resultat von Pi und die benötigte Zeit werden im Anschluss auf dem OLED-Display präsentiert, siehe Abbildung 9.
An der Stelle war ich ein bisschen erstaunt über das Ergebnis, siehe Tabelle 3! Zwar wusste ich, dass der Pico W mit seinem RP2040 nicht so schnell arbeitet wie der ESP32 NodeMCU, aber dass der ESP32 NodeMCU fast nur die Hälfte der Zeit braucht, war beeindruckend.
Pos | Pico W | ESP32 NodeMCU | D1 Mini |
Calc Pi [s] | |||
1 | 11,142 | 4,501 | 22,485 |
2 | 11,143 | 4,501 | 22,470 |
3 | 11,142 | 4,503 | 22,485 |
4 | 11,143 | 4,501 | 22,459 |
5 | 11,143 | 4,5 | 22,465 |
Mittelwert | 11,143 | 4,501 | 22,473 |
Die Taktfrequenz vom ESP32 spielt natürlich eine wesentliche Rolle, da dieser mit bis zu 240 MHz arbeitet. Da kann der RP2040 mit „gerade einmal“ 133 MHz nicht mithalten. Deutliches Schlusslicht macht hier der D1 Mini bzw. der ESP8266 mit fast der doppelten Zeit vom Pico W.
Test 3 Primzahlen ermitteln
Mein letzter Test schlug auch noch einmal in die Kerbe Rechengeschwindigkeit und sollte etwas Klarheit für mich schaffen. Nach kurzem Überlegen wurde ein Programm geschrieben, was Primzahlen ab einer bestimmten Zahl ermitteln, die durchschnittlich gebrauchte Zeit anzeigen und die letzten 8 Primzahlen anzeigen soll. Herausgekommen ist der Code aus Code 3.
import time
import machine
from oled import SSD1306_I2C,Write,gfx
from oled.fonts import ubuntu_mono_12
import array
I2C_PORT = 0
I2C_SDA = machine.Pin(0) #Pin on ESP32: 21(D21) D1Mini: 4(D1) Pico W: 0(Pin 1)
I2C_SCL = machine.Pin(1) #Pin on ESP32: 22(D22) D1Mini: 5(D2) Pico W: 1(Pin 2)
i2c = machine.I2C(I2C_PORT,sda=I2C_SDA, scl=I2C_SCL) # For ESP32 only
#i2c = machine.I2C(sda=I2C_SDA, scl=I2C_SCL) # For Pico W and D1 Mini
#Definitions and init for OLED-Display
WIDTH = 128
HIGHT = 64
oled = SSD1306_I2C(WIDTH, HIGHT, i2c)
graphics = gfx.GFX(WIDTH, HIGHT, oled.pixel)
font = Write(oled,ubuntu_mono_12)
Y_Shift = 13
numbers = [0 ,0 ,0 ,0, 0, 0, 0, 0]
value = 100000
foundPrimes = 0
sumTime = 0
def drawScreen(exTime):
global foundPrimes, sumTime
foundPrimes += 1
sumTime += exTime
averageTime = round(sumTime / foundPrimes,2)
oled.fill(0)
xPos = 10
yPos = 1
font.text('T: ' + str(averageTime) + ' s - F: ' + str(foundPrimes) , xPos, yPos)
yPos += Y_Shift
if numbers[4] > 0:
font.text(str(numbers[0]) + ' ' + str(numbers[4]), xPos, yPos)
else:
font.text(str(numbers[0]), xPos, yPos)
yPos += Y_Shift
if numbers[5] > 0:
font.text(str(numbers[1]) + ' ' + str(numbers[5]), xPos, yPos)
else:
font.text(str(numbers[1]), xPos, yPos)
yPos += Y_Shift
if numbers[6] > 0:
font.text(str(numbers[2]) + ' ' + str(numbers[6]), xPos, yPos)
else:
font.text(str(numbers[2]), xPos, yPos)
yPos += Y_Shift
if numbers[7] > 0:
font.text(str(numbers[3]) + ' ' + str(numbers[7]), xPos, yPos)
else:
font.text(str(numbers[3]), xPos, yPos)
oled.show()
while(True):
if value > 1:
start_time = time.ticks_ms()
for i in range(2, value):
if(value % i) == 0:
value+=1
break
else:
for j in range(7, 0, -1):
prev = j-1
numbers[j] = numbers[prev]
numbers[0] = value
end_time = time.ticks_ms()
execution_time = round(end_time - start_time,4)/1000
drawScreen(execution_time)
value+=1
Code 3: Code zur Berechnung von Primzahlen
Wieder werden die Bibliotheken geladen, die ic2-Schnittstelle und das OLED-Display initialisiert. Dieses Mal wird aber nicht direkt etwas ins Display geschrieben, sondern zunächst wird die erste Primzahl ab der Zahl 100.000 ermittelt. Vorher muss noch die Start- und Endzeit bis zum Finden der nächsten Primzahl ermittelt werden und die letzten 8 Ergebnisse in ein Array geschrieben werden. Damit immer die letzten acht gefunden Primzahlen angezeigt werden, wird bei einer neu gefundenen Primzahl, jeder Wert im Array um eine Position verschoben und der aktuelle Wert an den Anfang vom Array gesetzt.
Mit der Funktion drawScreen() wird dann alles kompakt auf dem Display angezeigt, siehe Abbildung 10.
Für die Erfassung einer Durchschnittszeit, siehe Tabelle 4, wurde immer nach 50 gefundenen Primzahlen, die errechnete Durchschnittszeit erfasst.
Pos | Pico W | ESP32 NodeMCU | D1 Mini |
Calc Prime [s] | |||
1 | 1,18 | 1,04 | 5,83 |
2 | 1,18 | 1,04 | 5,84 |
3 | 1,18 | 1,04 | 5,84 |
4 | 1,18 | 1,05 | 5,84 |
5 | 1,18 | 1,05 | 5,84 |
Mittelwert | 1,18 | 1,04 | 5,838 |
Hier bin ich vom Pico W und dem ESP32 wieder begeistert. Beide MicroController liegen fast gleichauf, auch wenn nun einige behaupten, dass 0,14s eine lange Zeitspanne ist. Ja im Prinzip sind 0,14s für MicroController eine lange Zeit Allerdings wurde hier nichts Zeitkritisches gesteuert. Schlusslicht war wieder einmal der D1 Mini, mit der fast 5-fachen Zeit zu den anderen MicroControllern!
Zusammenfassung der Pico W Benchmark
In meinem ersten Beitrag zum Pico W wurde bereits viel diskutiert, Fragen gestellt und auch auf Fehler meinerseits eingegangen. Diese Tests sind parallel zu den vielen Kommentaren entstanden. Im Prinzip habe ich das Thema WiFi nur angekratzt, ich habe aber nicht die technischen Mittel, um z.B. das WiFi-Signal genau zu analysieren. Hier gibt es andere Fachmagazine, die da durchaus interessante Beiträge zu verfasst haben und ich mit Spannung verfolge. Die hier gezeigte Pico W Benchmark sollte aber, unabhängig ob nun WiFi oder nicht, zeigen, wozu der Pico (W) im Vergleich zu seinen MicroController-Kollegen im Stande ist. Der Pico (W) mag nicht der schnellste Rechenkünstler sein, aber er kann mit einem ESP32 gut mithalten. Wem Zeit egal ist und nur wenige digitale Pins braucht, kann sich gerne einmal den D1 Mini ansehen. Wer von euch hingegen mehr Rechenpower und mehr Pins für diverse Schnittstellen braucht, sollte den Pico W durchaus in Betracht ziehen. Gut gefallen hat mir in diesem Zuge auch die einfache Einleitung ins Thema Wifi mit dem Pico W durch das PDF-Dokument oder die Projektseite der Raspberry Pi Fundation. Es gab mir einen super Einstieg und ich hatte direkt Lust auf mehr.
Mittlerweile habe ich einige ESP32 und ESP8266 auf MicroPython geflasht, da ich immer mehr gefallen an MicroPython und dem Pico W gefunden habe.
Für weitere spannende MicroController Artikel schaue hier vorbei!