Tutorial · Mittelstufe · 1,5 Stunden

Einen Roboter per Browser fahren mit ESP32-Webserver

Einen ESP32 in einen WLAN-Access-Point verwandeln, der seine Steuerseite serviert – damit jedes Handy den Roboter aus dem Browser fährt, ohne App-Installation.

Einführung

Ein HC-05 braucht eine Serienterminal-App und einen Paarungstanz. Ein ESP32 kann etwas Besseres: sein eigenes Netz sein und seine eigene Steuerseite servieren. Man verbindet sein Handy mit dem Roboter-WLAN, öffnet einen Browser und fährt. Nichts zu installieren – und es geht von jedem Gerät mit Browser.

Der ESP32 hat WLAN und Bluetooth auf dem Chip, zwei Kerne mit 240 MHz und genug RAM, um eine Webseite im Flash zu halten und zu servieren. Das ist der ganze Trick.

Ein fünfstufiges vertikales Flussdiagramm. Ein Handybrowser sendet eine HTTP-GET-Anfrage für die Vorwärtsroute. Der ESP32, als Soft-Access-Point oder in ein Netz eingebunden, empfängt sie. Sein HTTP-Server routet die Anfrage an einen Handler. Der Handler treibt die Richtungspins und PWM des Motortreibers. Die Räder drehen sich und der Roboter bewegt sich. Ein Hinweis warnt, dass ein Watchdog die Motoren stoppt, wenn keine Anfragen mehr eintreffen.
Jede Schicht zwischen Daumen und Rad. Der Watchdog zählt am meisten: Ohne ihn fährt der Roboter bei abgerissener Verbindung weiter. SVG herunterladen

Access Point oder bestehendes Netz?

Zwei Modi – und die Wahl zählt mehr, als es aussieht.

Access Point (AP) – der ESP32 erzeugt sein eigenes WLAN und das Handy tritt bei.

  • Funktioniert überall, ohne Router. Der Roboter ist eigenständig.
  • Das Handy verliert seine Internetverbindung während der Fahrt – und manche Handys wechseln lautlos zurück auf mobile Daten und werfen dich raus.
  • Die Adresse ist immer dieselbe, typisch 192.168.4.1.

Station (STA) – der ESP32 tritt deinem bestehenden WLAN bei.

  • Das Handy behält seine Internetverbindung.
  • Die Roboter-IP vergibt der Router und sie kann sich zwischen Starts ändern.
  • Außerhalb dieses einen Netzes nutzlos – was Vorführungen ausschließt.

Für einen Roboter, den man herumträgt, ist AP-Modus fast immer richtig:

#include <WiFi.h>
#include <WebServer.h>

WebServer server(80);

void setup() {
  WiFi.softAP("RobotCar", "drive1234");   // password must be 8+ characters
  Serial.println(WiFi.softAPIP());        // 192.168.4.1
  server.on("/", handleRoot);
  server.on("/cmd", handleCommand);
  server.begin();
}

void loop() {
  server.handleClient();
  applyDeadman();                          // see below — this is not optional
}

Die Steuerseite servieren

Die Seite liegt als Rohstring im Flash. Klein halten – jedes Byte serviert ein Mikrocontroller –, und die Steuerung touchfreundlich machen: Denn der ganze Sinn ist Fahren vom Handy.

const char PAGE[] PROGMEM = R"(
<!doctype html><meta name=viewport content="width=device-width,initial-scale=1">
<style>
  body{font-family:system-ui;margin:0;display:grid;place-items:center;height:100vh}
  button{width:90px;height:90px;font-size:24px;margin:4px;touch-action:manipulation}
</style>
<div>
  <div style="text-align:center"><button data-c="F">▲</button></div>
  <div><button data-c="L">◀</button><button data-c="S">■</button><button data-c="R">▶</button></div>
  <div style="text-align:center"><button data-c="B">▼</button></div>
</div>
<script>
let held = null;
const send = c => fetch('/cmd?c=' + c);
for (const b of document.querySelectorAll('button')) {
  // Repeat while held, so releasing and losing signal look the same to the robot.
  b.onpointerdown = e => { held = b.dataset.c; send(held);
                           b.setPointerCapture(e.pointerId); };
  b.onpointerup = b.onpointercancel = () => { held = null; send('S'); };
}
setInterval(() => held && send(held), 100);
</script>
)";

void handleRoot() { server.send_P(200, "text/html", PAGE); }

touch-action: manipulation an den Buttons zählt: Ohne warten Mobilbrowser ~300 ms, ob du Doppeltipp meintest – und der Roboter fühlt sich kaputt an.

Der Totmann-Timeout, erneut

Alles, was das Bluetooth-Tutorial über Verbindungsverlust sagt, gilt hier – und mehr: WLAN-Reichweite endet abrupt statt graceful.

unsigned long lastCommandAt = 0;

void handleCommand() {
  char c = server.arg("c")[0];
  drive(c);
  lastCommandAt = millis();
  server.send(200, "text/plain", "ok");
}

void applyDeadman() {
  if (millis() - lastCommandAt > 400) stop();
}

Der Browser sendet den gehaltenen Befehl alle 100 ms – ein 400-ms-Timeout verträgt also drei verlorene Anfragen vor dem Stopp. Dieses Verhältnis gilt es abzustimmen: zu eng und der Roboter stottert bei schwacher Verbindung, zu weit und er fährt weiter, nachdem man ihn verloren hat.

Wann man zu WebSockets wechselt

Der fetch-Ansatz oben öffnet pro Befehl eine frische HTTP-Verbindung. Er ist einfach, im Netzwerk-Tab des Browsers leicht zu debuggen, und bei 10 Befehlen pro Sekunde in Ordnung.

Er hört auf, in Ordnung zu sein, wenn man Telemetrie zurück will. Sensorwerte per weitere HTTP-Anfragen zu pollen verdoppelt den Verkehr und fügt beiden Richtungen Latenz hinzu. Ein WebSocket hält eine Verbindung offen und lässt jede Seite jederzeit sprechen:

#include <WebSocketsServer.h>
WebSocketsServer ws(81);

void onWsEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t len) {
  if (type == WStype_TEXT) { drive(payload[0]); lastCommandAt = millis(); }
  if (type == WStype_DISCONNECTED) stop();   // the link closing IS a stop command
}

Die letzte Zeile ist das echte Upgrade. Mit HTTP kann der Roboter eine verlorene Verbindung nur aus Schweigen schließen; ein WebSocket meldet den Moment des Schließens – der Roboter stoppt also sofort statt nach Timeout.

Mit HTTP anfangen. Zu WebSockets wechseln, wenn der Roboter zurücksprechen soll.

Versorgen

Der ESP32 ist ein 3,3-V-Teil und zieht beim Funksenden Strom in scharfen Stößen – deutlich über 200 mA in der Spitze. Zwei Folgen:

Nicht aus dem 3,3-V-Pin des Arduino versorgen. Dieser Regler schafft die Sendespitzen nicht – Symptom ist ein Board, das neustartet, wann immer das WLAN beschäftigt wird, was wie ein Codefehler aussieht und keiner ist.

Seine GPIO-Pins sind nicht 5-V-tolerant. Alles, was ein Signal in den ESP32 aus 5-V-Logik speist, braucht Teiler oder Pegelwandler – wie die RX-Leitung des HC-05.

Aus dem Akkupack über einen eigenen Regler ordentlich versorgen, mit getrennter Motorversorgung.

Prüfen, bevor du fährst

  1. Die Seite servieren. Ein Handy mit RobotCar verbinden, http://192.168.4.1 öffnen und bestätigen, dass die Buttons erscheinen.
  2. Die Befehle beobachten. Jeden empfangenen Befehl über USB ausgeben. Einen Button halten und bestätigen, dass Wiederholungen mit grob 10 pro Sekunde eintreffen.
  3. Die Verbindung töten. Vorwärts halten, dann das Handy-WLAN ausschalten. Der Roboter muss innerhalb des Timeouts stoppen.

Dann in einen Roboter einbauen: Das handygesteuerte Roboterprojekt baut das Ganze – mit beliebigem Funk – auf einem Chassis, das auch selbst fahren kann.

Den Graphen erkunden

Teil dieser Bauprojekte

Projekte und Lernpfade, die dieses Tutorial enthalten.

Weiterführende Literatur

Quellen