Telecomandă WiFi din browser — joystick pe telefonul tău
Cum face ESP32 un mic server web cu joystick virtual. Conduci mașina din pagina de pe forge.udev.ro pe telefon.
Ce înveți
- Cum face ESP32 un server WiFi (Soft AP sau client pe rețea locală)
- Ce-i WebSocket și de ce-i mai bun decât HTTP pentru un joystick (latență mică)
- Cum pui pe pagina web un joystick care funcționează pe touch
- Cum mapezi (x, y) joystick → comenzi pentru 2 motoare (tank drive)
Ce ai nevoie
Două moduri de a conecta telefonul la mașină
1. Mașina e CLIENT pe WiFi-ul casei (cel mai simplu)
WiFi.begin("WiFi-acasa", "parola-mea");
ESP32 se conectează la routerul tău. Primește IP (ex: 192.168.1.50). Tu deschizi
pe telefon http://192.168.1.50/ și acolo-i joystick-ul.
Avantaj: integrat în rețea, simplu. Dezavantaj: trebuie să fii acasă cu acel WiFi.
2. Mașina e Soft AP (hotspot propriu)
WiFi.softAP("CARTK-M1", "parola123");
ESP32 devine propriul router. Telefonul se conectează la rețeaua CARTK-M1.
Apoi deschizi http://192.168.4.1/ (default AP IP).
Avantaj: funcționează ORIUNDE, fără router. Dezavantaj: telefonul „pierde internetul” cât e conectat la mașină.
Pentru CART-K începem cu Soft AP — mai puțină dependență.
WebSocket pe ESP32
#include <WiFi.h>
#include <WebSocketsServer.h>
WebSocketsServer ws(81); // port 81
void onMessage(uint8_t num, WStype_t type, uint8_t* payload, size_t length) {
if (type == WStype_TEXT) {
// payload = "x=42,y=-18"
int x, y;
sscanf((char*)payload, "x=%d,y=%d", &x, &y);
drive(x, y);
}
}
void setup() {
WiFi.softAP("CARTK-M1", "parola123");
ws.begin();
ws.onEvent(onMessage);
}
void loop() {
ws.loop();
}
Pe telefon — joystick touch
<canvas id="joy" width="300" height="300"></canvas>
<script>
const ws = new WebSocket('ws://192.168.4.1:81/');
const canvas = document.getElementById('joy');
const ctx = canvas.getContext('2d');
let touching = false;
let x = 0, y = 0;
canvas.addEventListener('touchmove', (e) => {
const t = e.touches[0];
const rect = canvas.getBoundingClientRect();
x = Math.round((t.clientX - rect.left - 150) / 1.5); // -100..+100
y = -Math.round((t.clientY - rect.top - 150) / 1.5);
ws.send(`x=${x},y=${y}`);
redraw();
});
canvas.addEventListener('touchend', () => {
x = 0; y = 0;
ws.send('x=0,y=0'); // stop
redraw();
});
function redraw() {
ctx.clearRect(0, 0, 300, 300);
ctx.beginPath();
ctx.arc(150 + x * 1.5, 150 - y * 1.5, 30, 0, 7);
ctx.fillStyle = '#1d4ed8';
ctx.fill();
}
</script>
Tank drive din (x, y)
void drive(int x, int y) {
// y = -100..+100 (înainte/înapoi)
// x = -100..+100 (stânga/dreapta)
int stanga = y + x; // -200..+200
int dreapta = y - x;
stanga = constrain(stanga, -200, 200);
dreapta = constrain(dreapta, -200, 200);
int pwm_s = abs(stanga) * 255 / 200;
int pwm_d = abs(dreapta) * 255 / 200;
if (stanga > 0) forwardLeft(pwm_s); else if (stanga < 0) backwardLeft(pwm_s); else stopLeft();
if (dreapta > 0) forwardRight(pwm_d); else if (dreapta < 0) backwardRight(pwm_d); else stopRight();
}
Pentru CART-K — pagina de control pe site
În loc să servim HTML din ESP32 (greoi), facem pagina /sergiu/cart-k/control/
pe forge.udev.ro care se conectează prin WebSocket la IP-ul mașinii (ws://192.168.4.1:81/).
Avantaj: poți schimba interfața fără să reflash-ezi mașina.
Pas următor
Lecția 13: cum cele 2 mașini comunică între ele cu ESP-NOW pentru PvP (scut, magnet, lovituri).
După lecția asta, poți
- Faci ESP32 să fie WiFi access point fără router (mașina e propriul ei hotspot)
- Conduci o mașină RC din orice telefon — fără cablu, fără telecomandă specială
- Înțelegi diferența între HTTP poll (la 100ms) și WebSocket push (instant)