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)

Ultrasonic Modul mit I2C-Interface

Am Schülerforschungszentrum phænovum in Lörrach experimentieren wir mit autonomen Modell-Fahrzeugen, also Fahrzeuge, die weitgehend selbstständig ihren Weg finden. Dieses Thema ist ein wunderschönes Experimentierfeld für Algorithmen.

Hier zeige ich ein Modul mit 5 Abstandssensoren, das die Experimente mit den autonomen Fahrzeugen vereinfachen und unterstützen soll. Die Verwaltung der Sensoren wird von einem separaten Prozessor übernommen und das Ergebnis der Messungen über eine einfache Schnittstelle bereit gestellt. Firmware, Schaltplan, Platinen-Design und Arduino-Bibliothek stehen auf GitHub zur Verfügung.

Die Idee

Die wichtigste Anforderung an ein autonomes Fahrzeug ist, dass es Kollisionen vermeidet. Dazu muss die Umgebung aktiv nach Hindernissen abgesucht werden. Eine einfache Methode bieten die Ultraschall-Sensoren HC-SR04. Sie sind preisgünstig und einigermaßen einfach auszulesen. Die Sensoren werden mit einem kurzen Trigger-Signal aktiviert und antworten darauf mit einem Echo-Impuls. Die Länge des Echos entspricht der Laufzeit des Ultraschall-Signals und ist ein Maß für die Entfernung zum nächsten Hindernis. Zur Auswertung der Antwort muss ein Mikrocontroller (z.B. ein Arduino) die Zeit des Impulses exakt in Mikrosekunden messen.

Die Signalfolge am HC-SR04 mit dem Oszilloskop: Die blaue Kurv zeigt das Trigger-Signal und die gelbe Kurve das Echo. Die Länge des Echo-Impulses ist ein Maß für den Abstand zum Hindernis.

Diese eigentlich einfache Aufgabe kann kompliziert werden, wenn mehrere Sensoren ins Spiel kommen und der Arduino gleichzeitig noch andere Aufgaben hat, z.B. die Motoren drehen, weitere Sensoren auslesen, die Fahrtrichtung bestimmen und mehr. An dieser Stelle soll das hier gezeigte “Ultrasonic Modul” helfen. Es kombiniert 5 Sensoren auf einem Board. Ein ATmega328 ist dazu abgestellt, sich ausschließlich um die Sensoren zu kümmern, wodurch der Hauptprozessor auf dem Fahrzeug entlastet wird. Die Messergebnisse werden über eine I2C-Schnittstelle zur Verfügung gestellt. In der Arduino-Welt ist diese Schnittstelle als Wire bekannt und kann einfach ausgelesen werden.

Die Schaltung

Der Schaltplan ist vergleichsweise simpel. Die 5 Ultraschall-Module (nummeriert von 0 bis 4) werden mit 5V versorgt und liegen mit ihren Trigger- und Echo-Pins direkt an den Ports des ATmega. Der Prozessor wird über einen Low Drop-Spannungsregler mit 3.3V versorgt, so dass das I2C-Interface kompatibel mit dem Spannungslevel von Raspberry Pi oder ESP32 und gleichzeitig 5V tolerant ist. Da der Prozessor mit dem internen Taktgenerator (8 MHz) arbeitet, ist kein Quarz notwendig. Schließlich gibt es noch eine Leuchtdiode, die von der Arbeit des Prozessors berichtet. Die Leitungen für das I2C-Interface werden an eine Steckerleiste herausgeführt. Die Schaltung enthält Pull Up-Widerstände für SDA und SCL, die bei Bedarf bestückt werden können. Alles wird mit 100 nF Blockkondensatoren versehen. Das ist dann auch schon alles.

Die Schaltung ist überschaubar. Der Stecker für den ISP-Adapter (Mitte rechts) ist optional.

Die Platine

Um den Aufbau zu erleichtern, habe ich eine Platine mit KiCad entworfen. Die Sensoren sitzen direkt auf der Platine und zeigen nach links, links vorne, vorne, rechts vorne und rechts. Ob die Winkel der seitlichen Sensoren von 90 und 45 Grad wirklich geeignet sind, wird sich erweisen. Möglicherweise sind kleinere Winkel sinnvoll. Z.B. wären 30 und 60 Grad denkbar.

Auf der Platine ist ein Lötbrücke, mit der die I2C-Adresse verändert werden kann. So können zwei solcher Module an einem Arduino betrieben werden.

Platine im 3D-Viewer. Vorne rechts befindet sich der 6-polige Stecker für den ISP-Programmier-Adapter, so dass der ATmega direkt in der Schaltung programmiert werden kann. Wenn kein Bedarf dafür besteht, kann der Stecker einfach unbestückt bleiben
Stückliste

Software

Die Software wurde mit dem Atmel Studio Version 7 entwickelt und wird weitgehend über Interrupts gesteuert. Folgende Interrupts kommen zum Einsatz:

  • Timer 0 (ein 8-Bit Timer) produziert einen regelmäßigen Interrupt, typischerweise mit einem 40 ms Intervall. Das Programm verwendet den Interrupt als Erinnerung (via job_flag), dass es Zeit ist, den nächsten Sensor zu aktivieren und dort ein Trigger-Signal auszulösen.
  • Die Echo-Signale der Sensoren lösen Pin-Change-Interrupts aus. Die entsprechende Interrupt-Routine übernimmt die Messung der Laufzeit des Echo-Signals.
  • I2C-Interrupts werden von der Schnittstelle ausgelöst und bedeuten, dass der Host Daten benötigt. Mehr dazu weiter unten.
  • Schließlich gibt es noch Timer 1 (ein 16-Bit Timer), der zwar keinen Interrupt auslöst, aber mit einem Vorteiler (Prescaler) von 8 die Zeit in Mikrosekunden misst.

Ein Herzstück des Programms ist der Pin-Change-Interrupt, der vom Echo-Impuls der Sensoren ausgelöst wird. Zur Steuerung der Auswertung gibt es eine Variable echo_flag, die den Status des zugehörigen Sensors festhält. Wenn das Hauptprogramm einen Trigger setzt, wird echo_flag für den entsprechenden Sensor auf den Wert 1 gesetzt. So hat die Interrupt-Routine die Information, dass von diesem Sensor ein Echo-Impuls zu erwarten ist. Der Pin-Change-Interrupt wird sowohl von steigenden als auch von fallenden Flanken aktiviert. In der Interrupt-Routine muss untersucht werden, (1) welcher Sensor den Interrupt ausgelöst hat und (2) ob es sich um eine ansteigende oder eine fallende Flanke handelt. Zu (1) wird die beschrieben Variable echo_flag ausgewertet. Für (2) wird der aktuelle Wert des Ports abgefragt. Ist dieser high, dann war es eine ansteigende Flanke, und der aktuelle Wert des Timer 1 wird als Startzeit abgelegt. Außerdem wird der Wert des echo_flag auf 2 erhöht. Damit bekommt die Interrupt-Routine die Information, dass für diesen Sensor eine fallende Flanke zu erwarten ist. Ist das echo_flag also 2 und zeigt der zugehörige Port den Pegel low, dann war es offensichtlich eine fallende Flanke. Jetzt wird die Laufzeit aus der Differenz des aktuellen Timer-Werts und der Startzeit errechnet. Dabei muss ein möglicher Überlauf des Timers berücksichtigt werden. Der zugehörige Source-Code sieht so aus:

Die vollständige Software besteht aus 3 Dateien.

  • main.c enthält das Hauptprogramm mit der Verwaltung der Sensoren
  • TWI_slave.c und TWI_slave.h enthalten die Logik für das I2C-Slave-Interface. Ich verwende den offiziell von Microchip publizierten Source-Code (siehe AVR311), der den I2C-Slave-Mode auf dem ATmega bereit stellt.

Alle Dateien müssen im Atmel-Studio in das Projekt eingebunden werden, damit die Kompilierung klappt. Der kommentierte Source-Code mit weiteren Details befindet sich auf GitHub.

Gelegentlich bekomme ich Fragen zur Programmierung der ATmega und ATiny-Chips: Der ATmega arbeitet hier ohne die Arduino-Umgebung und hat deshalb auch kein USB-Interface an Board. Die Software muss mit einem der üblichen Programmier-Adapter auf den Prozessor kopiert werden. Ich arbeite seit vielen Jahren mit einem Atmel AVRISP mkII. Aber es gibt auch andere. Mehr dazu unter AVR In System Programmer – Mikrocontroller.net.

Die Platine trägt einen Stecker für den AVRISP Programmierer, so dass der ATmega direkt in der Schaltung “geflasht” werden kann. Das ist sehr nützlich, wenn die Software weiter entwickelt werden soll.

I2C Interface

Das Modul ist als I2C-Slave unter der Adresse 0x5A (Lötbrücke an Port B2 offen) oder 0x5B (Port B2 über Brücke auf Masse gelegt) erreichbar.

Der Host (z.B. ein Arduino) muss das Modul ansprechen, um eine Antwort zu bekommen. Das geschieht, indem ein Byte gesendet wird. Wir nennen es “Register”. Als Antwort auf Register-Werte zwischen 0 und 4 liefert das Modul die aktuelle gemessene Entfernung des entsprechenden Sensors in Millimetern. Das ist ein 16-Bit-Wert. Die Sensoren sind im Uhrzeigersinn von links durchlaufend nummeriert. Der Sensor vorne in der Mitte hat also die Nummer 2.

Darüber hinaus gibt es drei Register, die die Arbeitsweise des Moduls beeinflussen. Das Register ist der untere Nibble. Die eigentlichen Daten werden als oberes Nibble übertragen :

  • set_status (unteres Nibble = 10) kann die Entfernungsmessungen anhalten (oberes Nibble == 0) oder wieder starten (oberes Nibble > 0).
  • set_cycle_time (unteres Nibble = 11) setzt die Zeit (oberes Nibble mit dem Wert 1 bis 15) zwischen zwei aufeinanderfolgenden Messungen in 10 ms. Der Default-Wert ist 4 (entspricht 40 ms). Kleinere Werte ergeben schnellere Abfolgen, können aber möglicherwiese dazu führen, dass überlappende Echo-Signale eintreffen, was zu Fehlmessungen führt. Hier ist Raum zum Experimentieren.
  • set_mode (unteres Nibble = 12) definiert die Anzahl der Sensoren und die Sequenz (wir nennen es “Mode”), mit der sie nacheinander abgefragt werden. Das obere Nibble kann folgende Werte annehmen:
  • Mode 0: Sensor 0 -> Sensor 2 -> Sensor 4 -> Sensor 1 -> Sensor 3
  • Mode 1: Sensor 0 -> Sensor 2 -> Sensor 4
  • Mode 2: Sensor 1 -> Sensor 3
  • Mode 3: Sensor 2

Die Werte für Cycle Time und Mode werden im EEPROM abgelegt und bleiben nach dem Abschalten der Spannungsversorgung erhalten.

Einsatz mit Arduino

Das Modul benötigt 4 Anschlussleitungen zum Host: GND, SDA, SCL und Vcc (+5V). Die Spannungsversorgung geschieht über GND und Vcc. Diese Pins sind auf der Platine doppelt ausgeführt, da man in einem Projekt nie genug solcher Anschlüsse haben kann.

Die I2C-Schnittstelle mit den beiden Leitungen SCL (Takt) und SDA (daten) muss mit den entsprechenden Pins am Arduino verbunden werden. Z.B. beim Arduino Uno oder Nano sind es A5 für SCL und A4 für SDA.

Es gibt eine kleine Arduino-Bibliothek, die alle Funktionen des Moduls zur Verfügung stellt.

Ein einfaches Beispiel für ein Anwendungs-Programm ist hier gezeigt:

Fazit

Testlauf an einem Arduino Nano, der die Messdaten auf einem LCD-Display (ebenfalls per I2C) anzeigt.

Das Ultrasonic Modul macht den Einsatz von mehreren Ultraschall-Abstands-Sensoren so einfach wie möglich. Das Modul lässt sich gut in Arduino-Systeme integrieren, arbeitet aber auch mit einem Raspberry Pi zusammen. Ob es tatsächlich für das autonome Steuern von Fahrzeugen hilfreich ist, wird sich noch erweisen müssen. Mehr davon zu gegebener Zeit …

Update vom17. März 2021

In der ersten Version der Software hatte sich ein Bug versteckt, der dazu führte, dass das Modul nach kurzer Zeit keine sinnvollen Daten mehr lieferte. Das I2C-Slave-Interface blieb am “Busy-Flag” hängen. Der Fehler ist jetzt behoben. Inzwischen gibt es auch ein Fahrzeug, dass mit dem Modul seine Runden dreht und auch bei längeren Touren zuverlässige Daten bekommt.

Prototyp-Fahrzeug mit dem Ultrasonic-Modul

Ressourcen

GitHub – smlaage/Ultrasonic-I2C-Module: A module comprising 5 ultrasonic distance sensors and I2C interface

Erste Schritte mit dem Prototyp auf Lochrasterplatte …