firmware: v8 — handshake GO/OK bidireccional

Problema raiz: el bootloader ROM del ESP32 emite logs a 115200 baud.
Al recibirlos a 9600 baud en el ESP8266 salen bytes aleatorios, alguno
de los cuales puede ser F/B/L/R (mover ruedas) o '!' (activar espReady).

Solucion: handshake con string de 2 chars "GO\n" / "OK\n":
- ESP32-CAM envia "GO\n" cada 300ms hasta recibir "OK\n"
- ESP8266 descarta todo el buffer al arrancar (basura del bootloader),
  luego espera exactamente "GO\n" y responde "OK\n"
- En loop(), si ESP32 reinicia y manda "G", el ESP8266 repite el handshake
- Probabilidad de falso positivo: << 1 en millones vs ~40% del '!' solo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Natxo1000
2026-06-02 13:31:33 +02:00
parent 1688cdb185
commit 7707953d4d
6 changed files with 61 additions and 16 deletions

View File

@@ -7,7 +7,7 @@
// ================================================================ // ================================================================
// OTA CONFIG // OTA CONFIG
// ================================================================ // ================================================================
#define FW_VERSION 6 #define FW_VERSION 8
#define GITEA_HOST "https://git.nacho.myds.me" #define GITEA_HOST "https://git.nacho.myds.me"
#define GITEA_OWNER "Natxo" #define GITEA_OWNER "Natxo"
#define GITEA_REPO "Arduino-Car" #define GITEA_REPO "Arduino-Car"
@@ -99,20 +99,39 @@ static void checkOTA() {
WiFi.mode(WIFI_OFF); // apaga radio para ahorrar energía WiFi.mode(WIFI_OFF); // apaga radio para ahorrar energía
} }
bool espReady = false; // true cuando el ESP32-CAM ha enviado '!' bool espReady = false;
// ── Handshake con ESP32-CAM ──────────────────────────────────────
// Descarta basura del bootloader ROM (115200 baud → bytes aleatorios),
// luego espera exactamente "GO\n" y responde "OK\n".
void waitForReady() { void waitForReady() {
// Espera la señal '!' del ESP32-CAM (máx 90s por si hace OTA) // Descarta todo lo que haya en el buffer (logs de arranque del ESP32)
delay(300);
while (Serial.available()) Serial.read();
// Espera "GO\n" del ESP32-CAM (máx 90s por si está haciendo OTA)
unsigned long timeout = millis() + 90000UL; unsigned long timeout = millis() + 90000UL;
String buf = "";
while (millis() < timeout) { while (millis() < timeout) {
if (Serial.available()) { while (Serial.available()) {
char c = Serial.read(); char c = Serial.read();
if (c == '!') { espReady = true; return; } if (c == '\n') {
buf.trim();
if (buf == "GO") {
Serial.print("OK\n");
delay(50);
while (Serial.available()) Serial.read(); // flush post-handshake
espReady = true;
return;
}
buf = "";
} else if (c != '\r') {
if (buf.length() < 8) buf += c;
}
} }
delay(10); delay(10);
} }
// Timeout: arranca igual para no quedarse bloqueado indefinidamente espReady = true; // timeout: arranca igual
espReady = true;
} }
void setup() { void setup() {
@@ -145,10 +164,17 @@ void loop() {
if (Serial.available()) { if (Serial.available()) {
char c = Serial.read(); char c = Serial.read();
// Señal de listo del ESP32-CAM (también en loop por si reinicia) // Detecta re-arranque del ESP32-CAM: envía "GO\n" de nuevo
if (c == '!') { espReady = true; return; } if (c == 'G') {
Serial.readStringUntil('\n'); // consume "O\n"
Serial.print("OK\n");
delay(50);
while (Serial.available()) Serial.read();
espReady = true;
return;
}
// Ignorar todo hasta recibir '!' — evita movimientos al arrancar // Ignorar todo hasta completar el handshake
if (!espReady) return; if (!espReady) return;
if (c == 'F') forward(); if (c == 'F') forward();

View File

@@ -10,7 +10,7 @@
// ================================================================ // ================================================================
// OTA CONFIG // OTA CONFIG
// ================================================================ // ================================================================
#define FW_VERSION 7 #define FW_VERSION 8
#define GITEA_HOST "https://git.nacho.myds.me" #define GITEA_HOST "https://git.nacho.myds.me"
#define GITEA_OWNER "Natxo" #define GITEA_OWNER "Natxo"
#define GITEA_REPO "Arduino-Car" #define GITEA_REPO "Arduino-Car"
@@ -24,6 +24,26 @@ const char *password = "Suprak1llm1ndS23S";
void startCameraServer(); void startCameraServer();
void setupLedFlash(); void setupLedFlash();
// ── Handshake bidireccional con ESP8266 ─────────────────────────
// Envía "GO\n" cada 300ms hasta recibir "OK\n".
// Protege contra basura del bootloader ROM (115200 baud → bytes aleatorios).
static void handshakeEsp8266() {
unsigned long deadline = millis() + 30000UL; // máx 30s
while (millis() < deadline) {
Serial.print("GO\n");
unsigned long t = millis();
while (millis() - t < 300) {
if (Serial.available()) {
String resp = Serial.readStringUntil('\n');
resp.trim();
if (resp == "OK") return;
}
delay(5);
}
}
// Timeout: continúa sin confirmación
}
// ── OTA: comprueba si hay firmware nuevo y actualiza si hace falta ── // ── OTA: comprueba si hay firmware nuevo y actualiza si hace falta ──
static void checkOTA() { static void checkOTA() {
WiFiClientSecure client; WiFiClientSecure client;
@@ -147,9 +167,8 @@ void setup() {
// ── Servidor cámara ─────────────────────────────────────────────── // ── Servidor cámara ───────────────────────────────────────────────
startCameraServer(); startCameraServer();
// Señal al ESP8266: estoy listo, puede empezar a procesar comandos // Handshake bidireccional: espera ACK del ESP8266
delay(200); handshakeEsp8266();
Serial.print("!");
} }
void loop() { void loop() {

Binary file not shown.

View File

@@ -1 +1 @@
7 8

Binary file not shown.

View File

@@ -1 +1 @@
6 8