XY-Plotter

Der Corona-Lockdown bedeutet mehr Zeit zuhause und im Home-Office. Was also machen mit der vielen Zeit? Ich habe eine alte Idee ausgegraben, der Selbstbau eines XY-Plotters, also einer Maschine, die einen Stift über Papier führt und so Zeichnungen produziert.

Natürlich kann jeder Laser- oder Inkjet-Drucker beliebige Bilder mit hoher Qualität ausdrucken. Es reizte mich aber, Zeichnungen mit einem geführten Stift maschinell zu erstellen. Die Resultate sind Unikate, die von den Eigenschaften von Stift und Papier abhängen. Und mir gefiel die selbst gestellte Aufgabe als eine spannende Herausforderung.

Dieses Projekt begann im ersten Corona-Lockdown im März 2020 und hat bis heute einen sehr schön funktionierenden Prototyp und allerlei interessante Zeichnungen ergeben. Eine Galerie findet sich am Ende dieses Beitrags.

Inhalt

Das Konzept

Die Aufgabe eines Plotters ist es, einen Stift zu führen, so dass er Spuren auf dem Papier hinterlässt. Ein Bild kommt aber erst im Zusammenspiel mit einem PC zustande, der die passenden Zeichenanweisungen erzeugt und an den Plotter sendet. Dazu stellt der Plotter Funktionen zum Zeichnen von Linien, Rechtecke, Kreise, Ellipsen, Kreisbögen und mehr bereit, beherrscht sogar einen einfachen Zeichensatz für Texte. Es gibt eine (stetig wachsende) Befehlstabelle (siehe hier). Die Verbindung zwischen PC and Plotter kann über die serielle USB-Schnittstelle oder über das WLAN erfolgen.

Die Zeichnungen können auf dem PC mit beliebiger Software erstellt werden. Ich verwende hauptsächlich Python-Skripts, die ansprechende Grafiken produzieren. Dabei beschäftige ich mich auch mit der Umwandlung von Fotos in Vektor-Zeichnungen im SVG-Format, die dann vom Plotter zu Papier gebracht werden – ein weites Experimentierfeld.

Plotter in action

Die Mechanik

Das Design ist schnell beschrieben. Es gibt eine X- und eine Y-Achse, die mit Schrittmotoren betrieben werden. Die Mechanik basiert auf dem von 3D-Druckern bekannten Verfahren. Die Achsen werden aus Linearwellen (polierter Rundstahl mit 8 mm Durchmesser) aufgebaut, auf denen Schlitten mit Linearlagern laufen. Die horizontale X-Achse ist doppelt ausgeführt und bewegt zwei gegenüberliegende Schlitten, die die vertikale Y-Achse tragen. Auf der Y-Achse bewegt sich ein Schlitten mit dem Stifthalter. Die Positionierung erfolgt über Zahnriemen.

Der Plotter im Überblick

Der Zeichenstift ist an einer Wippe befestigt, die mit einem Modellbau-Servo gehoben oder gesenkt wird. Der Anpressdruck auf dem Papier wird mit einer Feder angepasst. Der Stifthalter kann beliebige Stifte aufnehmen, allerdings nur einen Stift zur Zeit. Mehrere Farben benötigen also einen manuellen Stiftwechsel. Das Papier wird mit Magneten fixiert, so dass es schnell gewechselt werden kann. Die bei professionellen Plottern verbreitete Fixierung mit Unterdruck erschien mir für den Selbstbau zu aufwendig.

Überall kommen Linear- und Kugellager zum Einsatz, so dass die Mechanik weitgehend spielfrei funktioniert. Die benötigten Komponenten sind bei den üblichen Online-Händlern zu akzeptablen Preisen verfügbar.

Konstruktion der Bauteile mit FreeCAD

Die benötigten Konstruktionsteile kommen aus dem 3D-Drucker. Zur Konstruktion verwende ich durchgängig FreeCad und zur Herstellung der Teile meinen bewährten Dremel 3D40.

Detail-Ansichten

Die Auswahl eines geeignetes Stifts ist nicht ganz unproblematisch. Beim Zeichnen können durchaus lange Strecken zusammenkommen, so dass sich der Stift schnell abnutzt. Ich habe gute Erfahrungen mit Tintenrollern oder Gelrollern gemacht.

Die Elektronik

Im Zentrum der Maschine werkelt ein ESP32. Er treibt die Schrittmotoren XA, XB und Y mit Hilfe der üblichen A4988 Treiber-Module, die als Breakout-Board verfügbar sind. Ich verwende den 8tel-Schritt-Modus (MS1 und MS2 liegen auf +3.3V). Die Enable-Leitungen aller 3 Treiber sind zusammengefasst. Der Prozessor kann damit alle Motoren ein- oder ausschalten. Jeder Motor-Treiber hat einen Step- und einen Dir-Eingang, die unabhängig voneinander angesteuert werden. Für jede Achse gibt es einen Endtaster, der nach dem Einschalten angefahren wird (“Referenzfahrt”), um eine definierte 0-Position zu finden.

Weiterhin gibt es ein alphanumerisches LCD-Display, das über das I2C-Interface betrieben wird. Das Display hat 4 Zeilen mit jeweils 20 Zeichen und gibt Status-Informationen aus.

Das System beinhaltet 3 Taster, mit denen der Anwender den Ablauf beeinflussen kann:

  • Taster 0 (“Stop”, grün) hält die Ausführung an bzw. setzt sie fort.
  • Taster 1 (“Standby”, blau) schaltet den Motostrom ab. Sobald der Plotter irgendein Zeichenkommando bekommt, werden die Motoren wieder eingeschaltet.
  • Taster 2 (“Pen Up/Down”, gelb) hebt oder senkt den Stift. Das ist hilfreich zum Einsetzen eines Stifts.
Die drei Taster befinden sich unterhalb vom LC-Display

Die Schaltung arbeitet mit 3 verschiedenen Spannungen: Sie wird von einem externen Netzteil mit 12V versorgt. Die Spannung dient direkt zum Treiben der Motoren (Vmot). Ein Spannungsregler auf der Platine erzeugt daraus 5V (Vdd) für die Stromversorgung von ESP32, LCD-Display und Stift-Servo. Der ESP32 trägt auf seinem Board einen 3.3V Spannungsregler (Vcc). Diese Spannung wird außerdem für die Versorgung der Logik der Schrittmotortreiber verwendet

Der Schaltplan für den Plotter. Links oben die Spannungsregelung (12 -> 5V). Links der ESP32. Oben Mitte das LC-Display. In der Mitte die drei Motortreiber mit A4988. Unten Mitte die Anschlüsse für die Endschalter, den Servo und die Taster.

Die Schaltung ist im Laufe der Zeit auf einer Lochrasterplatine im Prototyp-Stil “gewachsen”. Das Resultat ist nicht schön, funktioniert aber zuverlässig. Bei Gelegenheit kann man dafür eine Platine anfertigen.

Der Aufbau der Platine ist historisch gewachsen …

Ursprünglich war der Plotter als horizontaler “Flachbett-Plotter” konzipiert. Aus Platzgründen in meinem Home-Office habe ich ihn dann aber auf ein Gestell gesetzt, so dass er mit etwa 60 Grad Neigung im Bücherregal steht. Leider reicht es jetzt nicht mehr ganz für das A3-Papierformat.

Der Plotter steht auf einem Gestell mit etwa 60 Grad Neigung und passt so ins Bücherregal.

Die Software

Wie so oft bei diesen Projekten benötigt die Software den größten Arbeitsaufwand. Die “Firmware” für den ESP32 habe ich mit der Arduino-IDE entwickelt. Sie übernimmt die Steuerung der Motoren und des Servos für den Stift und kann eine Reihe von Grafik-Primitiven ausführen. Eingaben kommen über die serielle Schnittstelle oder das WLAN und landen in einem internen Puffer, der sukzessive abgearbeitet wird.

Die Schrittmotoren werden über einen Timer-Interrupt gesteuert. Der Interrupt beherrscht den Bresenham-Algorithmus, um zwei beliebige Punkte mit einer geraden Linie zu verbinden, was die Grundlage für alle Zeichenfunktionen bildet. Die Motoren werden mit einer Rampe auf Geschwindigkeit gebracht und vor dem Ziel wieder abgebremst. So kann der Plotter den Schlitten relativ schnell bewegen, ohne Schritte zu verlieren. Das klappt tatsächlich ausgesprochen gut. Die Logik unterscheidet zwischen Bewegungen mit gehobenem (schnell) und gesenktem Stift (einstellbare Geschwindigkeit, normalerweise langsamer). Weitere Anforderungen an das Timing müssen beachten werden. Zum Beispiel wird nach dem Befehl pen down für einen kurzen Moment gewartet, bis der Stift auf dem Papier angekommen ist.

Der Eingabepuffer nimmt mit 70 kB den größten Teil des verfügbaren RAM-Speichers auf dem ESP32 in Anspruch. Die Steuerung der Motoren und das Abarbeiten des Puffers geschieht vollständig im Hintergrund. Die Schnittstellen werden auch während des Plot-Betriebs bedient. Das sendende Programm muss allerdings abfragen, ob genügend Platz für weitere Anweisungen im Puffer vorhanden ist. Dazu dient das Kommando F, das den aktuell verfügbaren Speicherplatz zurück gibt.

Für die WLAN-Verbindung verwende ich die Socket-Kommunikation, die an anderer Stelle beschrieben wurde. Bei der ersten Inbetriebnahme muss der Anwender das Netzwerk über die serielle Schnittstelle auswählen und das zugehörige Passwort eingeben. Die Einstellung einer statischen Adresse ist möglich. Die Daten werden im Flash-Speicher abgelegt, so dass sich der Plotter beim nächsten Einschalten direkt und ohne weitere Eingaben mit dem Netzwerk verbindet.

Das LC-Display zeigt einige System-Parameter im laufenden Betrieb.

Die Software ist ein umfangreiches Projekt und hat in der aktuellen Version sicherlich noch einen experimentellen Charakter, läuft aber stabil und produziert schon sehr ansehnliche Bilder.

Protokollarisches

Wie bringt man den Plotter dazu, etwas zu zeichnen? Dafür verwende ich ein einfaches Protokoll. Die Syntax ist angelehnt an die Scalable Vector Graphics-Sprache. Jede Anweisung besteht aus einem Buchstaben, der die Art des Befehls kennzeichnet, gefolgt von Parametern, z.B. Koordinaten. Die Parameter werden durch Komma getrennt. Leerzeichen werden ignoriert. Eine Anweisung wird durch ein Semikolon oder das Zeilenende abgeschlossen.

Der Plotter verwendet ein X/Y-Koordinatensystem. Der Nullpunkt ist unten links und wird nach dem Einschalten angesteuert. Ein Schritt entspricht 0,025 mm, was eine recht hohe Auflösung für diese Anwendung ist. Auch mit sehr feinen Stiften lassen sich keine Treppenstufen erkennen. Zur Zeit gibt es 37 Befehle. Hier ist ein Ausschnitt der Tabelle.

Ausschnitt aus der Befehlstabelle. Die Tabelle umfasst derzeit 37 Anweisungen.

Ein einfaches Beispiel: Die hier gezeigte Sequenz zeichnet ein Smiley, bestehend aus Kreisen, Ellipsen, Kreisbögen und geraden Linien, die ein Dreieck bilden. Die Anweisung Z (Zeile 4) schließt den Polygon-Zug, wobei der Stift an die letzte durch ein M angesteuerte Position zurückkehrt.

Smiley (Bleistift auf Zeichenkarton)

Es gibt auch Anweisungen zum Zeichnen von Text. Der Plotter hat einen eingebauten Zeichensatz, der allerdings noch recht eingeschränkt ist und im Wesentlichen die unteren 80 Zeichen der ASCII-Tabelle enthält.

Zeichensatz

Zeichenprogramme

Der Plotter ist ein Werkzeug, das Anweisungen empfängt und den Stift bedient. Eine ansprechende Grafik besteht aber aus sehr vielen Anweisungen und kommt in der Regel von einem Programm auf dem PC. Ich verwende verschiedene Python Programme, die mit unterschiedlichen Algorithmen Grafiken produzieren oder Fotos in Zeichnungen umsetzen.

Zum Testen des Plotters und der Verbindung eignet sich eine kleine Python-Anwendung, die manuelle Eingaben per Tastatur entgegennimmt und über die WebSocket-Schnittstelle an den Plotter sendet.

Das Skript verbindet sich mit dem WebSocket-Server auf dem Plotter und öffnet eine interaktive Session, in der man die einzelnen Grafik-Befehle ausprobieren kann.

Die Python-Programme, mit denen ich meine Grafiken erstelle, produzieren eine Liste von Zeichenanweisungen, die als Zwischenschritt erst einmal in einer Datei landen. Bei mir heißt diese Datei meistens plot_file.plt. Diese Datei wird dann mit einem Python-Skript zum Plotter gesendet. Dabei muss das Skript regelmäßig den verfügbaren Pufferplatz auf dem Plotter abfragen und darf die Daten nur bei ausreichend Platz senden. Ein sehr einfaches Programm für diese Aufgabe ist hier gezeigt. Dieses Skript hält den Transfer an, wenn der freie Pufferplatz unter 1 kB fällt und startet den Transfer, wenn er über 10 kB ansteigt:

Zum Abschluss ein kurzes Python-Programm, das eine einfache Zeichnung erstellt und in der Datei plot_file.plt ablegt. Die Computer-Grafiken der 80er Jahre feiern hier ein Revival.

Das Ergebnis des Skripts “nested_check.py”

Die Python-Unterstützung des Plotters ist im Moment noch rudimentär und wird im Laufe der Zeit weiter entwickelt. Auch die Erstellung von Grafiken mit Python-Skripts ist ein weites Feld. Zu gegebener Zeit werden weitere Beispiele folge.

Fazit

Spielereien mit Computer-Grafik haben mich schon immer fasziniert. Der Bau eines Plotters ist ein spannendes Projekt. Die mit dem Stift gezeichneten Ergebnisse habe einen eigenen Reiz.

Der Eigenbau eines solchen Gerätes wird durch die Verfügbarkeit von 3D-Druck und leistungsfähiger Hardware-Komponenten erst möglich. Es ist erstaunlich, welche Präzision sich in der heimischen Werkstatt erreichen lässt. Der ESP32 hat mich mit seiner Leistungsfähigkeit wieder einmal beeindruckt. Die Verwaltung der Motoren mit schnellen Interrupt-Folgen parallel zur Bedienung des Eingabepuffers, LCD, Stift-Servo und Netzwerk sind eine anspruchsvolle Aufgabe, die den ESP32 aber noch lange nicht an seine Grenzen bringt.

Galerie

Baum – entstanden aus einer rekursive Funktion mit zufälligen Variationen
Bäume – rekursive Funktion in Python
dat10 – Drehende gekoppelte Scheiben
dat07 – Noch mehr Drehungen
Pusteblume – rekursive Strukturen im Kreis
Sailboat – Konvertierung eines Handy-Fotos in eine SVG-Grafik mit Nachbearbeitung in Python

Ressourcen

WebSocket-Kommunikation mit dem ESP32 – Eine Wetterstation mit BME280

In den letzten Monaten hat sich der ESP32 zu einem Arbeitspferd für viele Projekte entwickelt. Zum einen ist es ein leistungsfähiger Prozessor mit beachtlicher Busbreite und Taktrate. Zum anderen ist die Kommunikation via WLAN eine sehr praktische Angelegenheit.

Es muss aber nicht immer eine Web-Server sein, der, wie in vielen Tutorials gezeigt, HTML produziert. In diesem Projekt gehe ich auf einen tieferen Level und möchte zeigen, wie man mit der WebSocket-Schnittstelle eine Datenverbindung mit geringem Overhead aufbauen kann. WebSocket bietet eine zuverlässige Verbindung, bei der Nachrichten nicht verloren gehen und in der korrekten Reihenfolge übermittelt werden. Der Komfort steht dem einer seriellen Schnittstelle in nichts nach … ganz ohne lästiges Kabel!

Die Idee

Als Beispiel-Anwendung habe ich mir den Sensor BME280 herausgesucht, der Luftdruck, Luftfeuchtigkeit und Temperatur misst und die Daten per I2C zur Verfügung stellt. Die Daten werden vom ESP32 ausgelesen, der sie dann als WebSocket-Server für Clients abrufbar macht. Bei der Gelegenheit habe ich noch zwei Leuchtdioden an den ESP32 angeschlossen, die über den Client geschaltet werden können. Als Beispiel für einen Client gibt es hier eine GUI-Anwendung mit Python und TKinter, die zum Beispiel auf einem Laptop oder einem Raspberry Pi läuft. Die Verbindung über das serielle Interface und den WebSocket werden exakt gleich behandelt und können vom ESP32 auch gleichzeitig bedient werden. Soweit das Konzept.

Der ESP32 empfängt die Daten vom Sensor (BME280) (rechts) und stellt sie über die serielle Schnittstelle und über den WebSocket-Server zur Verfügung. Als WebSocket-Client dient ein Python-Programm auf einem Computer (links).

Die Schaltung

Die Schaltung ist auf einem Steckbrett schnell zusammengebaut. Für den BME280-Sensor gibt es ein praktisches Breakout-Board, das Masse, Vcc und die beiden I2C-Leitung SCL und SDA herausführt. Die I2C-Leitungen bekommen Pull Up-Widerstände, die den Ruhepegel auf Vcc ziehen. Auf dem Steckbrett befindet sich noch eine zweifarbige LED mit gemeinsamer Kathode, die den Status der Netzwerkverbindung anzeigt. Schließlich gibt es noch zwei Leuchtdioden, die an Ports des ESP32 gelegt sind.

Schaltplan des ESP32 mit dem Sensor BME280 und einigen Leuchtdioden
Aufbau auf einem Steckbrett

BME280

Der Bosch-Sensor ist bereits kalibriert und stellt die Daten in digitaler Form bereit, was die Anwendung enorm vereinfacht. Ich verwende die Arduino-Bibliothek BME280 von Tyler Glenn, die schon in der Version 3.0 vorliegt. Der Sensor wird nach dem Laden der Include-Datei als globales Objekt eingerichtet. Die Funktionen zum Auslesen von Luftdruck, Temperatur und Luftfeuchtigkeit können direkt aufgerufen werden und liefern die Ergebnisse als Float-Variable.

Verbindungsaufbau mit dem Modul web_socket

Bei meiner Arbeit mit dem ESP32 habe ich ein Software-Modul web_socket entwickelt, das den Verbindungsaufbau übernimmt und Funktionen zum Lesen und Schreiben der Daten zur Verfügung stellt. Es besteht aus den Dateien web_socket.cpp und web_socket.h und verwendet seinerseits die WebSockets-Bibliothek für Arduino (GitHub – Links2004/arduinoWebSockets: arduinoWebSockets), die gegebenenfalls in der Arduino-Umgebung installiert werden muss.

Eine der Aufgaben von web_socket ist der Aufbau der Verbindung zum WLAN-Router. In vielen Beispielen im Internet wird dabei der Namen des Netzwerks (SSID) und das Passwort in den Source-Code eingebettet. Das ist für Experimente praktisch, für reale Anwendungen aber nicht tragbar. Deshalb bietet das Modul web_socket die Möglichkeit, die Netzwerk-Credentials per Dialog über die serielle Schnittstelle abzufragen und im nichtflüchtigen Speicher (preferences) abzulegen. Beim nächsten Start klappt der Verbindungsaufbau dann ohne weitere Angaben. Die Schaltung muss also nur bei der ersten Inbetriebnahme an der seriellen Schnittstelle angeschlossen sein. Außerdem gibt es die Möglichkeit, eine statische IP-Adresse anzugeben, so dass der WebSocket-Server immer unter einer festen Adresse erreichbar ist.

Auf dem PC kann die serielle Schnittstelle z.B. mit dem seriellen Monitor der Arduino-Umgebung oder einem der vielen Terminal-Programme bedient werden. Der Dialog zur Auswahl des Netzwerks und zur Abfrage des Passwords sieht so aus:

Dialog über die serielle Schnittstelle zur Auswahl des Netzwerks und Eingabe der Credentials

Hier eine kurze Beschreibung, wie das Modul web_socket in der Praxis eingesetzt wird. Es enthält die Klasse Socket. Ein Objekt dieser Klasse wird im Anwenderprogramm als globale Variable erstellt.

Das Objekt stellt alle Funktionen zum Aufbau der Verbindung und zur Kommunikation mit dem Client bereit. Zuerst wird die Methode begin() aufgerufen. Damit werden die Netzwerk-Daten aus dem nichtflüchtigen Speicher kopiert, sofern sie dort vorhanden sind. begin() meldet true zurück, wenn das der Fall ist. Für den Verbindungsaufbau zum WLAN gibt es die Methode connect(), und zwar in drei Varianten.

  1. connect() ohne Argumente verwendet die vorhanden Netzwerkdaten aus dem nichtflüchtigen Speicher.
  2. connect(ssid, password) stellt eine Verbindung für das angegebene Netzwerk her, wobei die IP-Adresse dynamisch vom Router zugewiesen wird.
  3. connect(ssid, password, static_ip, gateway_ip) stellt eine Verbindung mit einer statischen IP-Adresse her. Das kann natürlich nur dann funktionieren, wenn auf dem Router die statische IP-Adresse auch verfügbar ist.

Wenn eine Verbindung erfolgreich aufgebaut ist, werden die Netzwerk-Daten in den nichtflüchtigen Speicher kopiert und stehen dort für den nächsten Systemstart zur Verfügung.

Die manuelle Auswahl des Netzwerkes mit dem oben gezeigten Dialog kann mit der Methode select() ausgelöst werden. All das kann in der Arduino setup()-Funktion komfortabel erledigt werden, z.B. so:

Senden und Empfangen

Jetzt können eingehende Nachrichten mit read_chararray(char buf[], int size) gelesen oder ausgehende Nachrichten mit send(char buf[]) gesendet werden. Um die Sache einfach zu halten, beschränke ich mich auf Text-Nachrichten von maximal 256 ASCII-Zeichen. Das ist für die kleinen Datenmengen, um die es hier geht, völlig ausreichend und hat den angenehmen Nebeneffekt, dass der Programmierer bei Bedarf mitlesen kann.

Das Modul web_socket enthält einen internen Puffer (2048 Bytes), der mehrere eingehende Nachrichten aufnehmen kann. Die Methode available() gibt die aktuelle Zahl der Zeichen im Eingangspuffer aus.

Hier ist eine Übersicht der Methoden des Objekts Socket:

Wichtig ist, dass die Methode run_socket_loop() regelmässig aufgerufen wird. Diese Funktion bedient die webSocket.loop(), die benötigt wird, um auf Ereignisse zu reagieren. In meinen Anwendungen wird run_socket_loop() mehrmals pro Sekunde aufgerufen. So werden timeout-Fehler auf der Client-Seite vermieden.

Gesprächsbedarf: Das Protokoll

Für die Kommunikation zwischen Client und Sever verwende ich bei meinen Projekten ein einfaches Protokoll. Dabei sendet der Client eine Anfrage an den Server. Diese Anfrage beginnt immer mit einem “Command-Token”. Das ist ein ASCII-Zeichen, das die Art der Anfrage kennzeichnet. Gegebenenfalls können zusätzliche Daten folgen. Der Server antwortet dann mit den gewünschten Daten und/oder führt die jeweilige Aktion aus, z.B. An- oder Ausschalten einer LED. Ich habe mir angewöhnt, in jedem Fall eine Antwort zum Client zu senden, auch dann, wenn eigentlich kein Bedarf für eine Rückmeldung besteht. So kann der Client sicherstellen, dass er “gehört” wurde.

Das Protokoll für den Datenaustausch ist für das konkrete Beispiel sehr einfach. Es gibt die folgenden Command-Token:

Die Arduino loop()-Funktion des EPS32 hat die Aufgabe, das serielle Interface und den WebSocket-Server ständig abzufragen, ob eine Nachricht angekommen ist. Wenn das der Fall ist, wird die einkommende Nachricht in der Funktion process_input() bearbeitet, also z.B. der Luftdruck-Wert gelesen und oder eine der LEDs geschaltet. Die booleschen Variablen net_input und ser_input merken sich, aus welchem Kanal die Eingabe kam, und verwendet diese, um die Antwort an den richtigen Kanal zurück zu senden.

Der Luftdruck bekommt eine zusätzliche Behandlung: Die eigentlich interessante Information ist die zeitliche Entwicklung. Deshalb wird alle 10 Minuten der Luftdruck gemessen und in einem Array float pres_trend[] abgelegt. Dort ist Platz für 30 Werte, also die Daten der letzten 5 Stunden. Die Daten können mit dem Command-Token “D” abgerufen werden. Daraus produziert der Client eine kleine Grafik zum zeitlichen Verlauf.

Das Protokoll kann mit dem seriellen Monitor der Arduino-IDE sehr schön ausprobiert werden. Die ASCII-String-Kommunikation macht es möglich. Hier eine Beispiel-Session mit dem seriellen Monitor der Arduino-IDE:

Das Protokoll wird an der seriellen Schnittstelle ausprobiert. Die Pfeile markieren die Eingaben von der Tastatur.

WebSocket Client

Für erste Tests verwende ich ein einfaches Python Skript, das auf einem PC oder Raspberry Pi läuft. Der PC und der ESP32 müssen in demselben Netzwerk angemeldet sein, so dass sie sich im Netzwerk “sehen” können. IP-Adresse und Port-Nummer des Servers müssen natürlich bekannt sein, in meinem Fall 192.168.1.210 und Port 90.

Auf der Python-Seite verwende ich das Modul websocket, das gegebenenfalls mit pip nachinstalliert werden muss. Das Skript verbindet sich mit dem WebSocket-Server, wartet auf einer User-Eingabe, sendet diese an den Server und zeigt die Antwort. Natürlich kann es immer die Situation geben, dass der Server nicht erreichbar ist (z.B. abgeschaltet oder hat eine andere IP-Adresse). Dafür gibt es eine Fehlerbehandlung mit try … except.

Jetzt sind die Dienstleistungen des WebSocket-Servers genau wie mit der seriellen Schnittstelle abrufbar. Hier eine Beispiel-Session mit der Python-Shell:

Zum Abschluss: Eine GUI-Applikation mit Wetter-Daten

Nachdem die Verbindung zuverlässig und stabil ist, kann man mit etwas Python und TKinter eine kleine GUI-Applikation zusammensetzen. Das Skript besteht aus nur einem File “bme.py”. Es öffnet ein Fenster auf dem Desktop, platziert alle Widgets und führt ein regelmäßiges Refresh der Daten durch, so dass die Daten immer aktuell sind. Damit die Datenbeschaffung per WebSocket die Antwortzeiten des User-Interface nicht beeinträchtigt, wird sie in einen eigenen Thread ausgelagert, der im Hintergrund läuft und alle 120 Sekunden die aktuellen Werte anfordert. Außerdem gibt es noch eine Konfigurations-Datei bme_config.dat, in der die wichtigsten Parameter, besonders die IP-Adresse und die Port-Nummer bereit liegen müssen. Diese Datei wird beim Start des Python-Skripts eingelesen.

Die Datei bme_config.dat hält die wichtigsten System-Parameter bereit.

Das Ergebnis ist eine kleine “Wetter-App”, die die Daten vom BME280 auf dem Desktop sichtbar macht.

Downloads

Der Source Code für die Arduino-Anwendung und alle hier erwähnten Python-Skripts sind auf GitHub verfügbar. Dort befinden sich auch der Schaltplan und weitere Fotos.

Link: smlaage/esp32_websocket: ESP32 WebSocket Server with Python Client (github.com)