Tappa 6
Firmware
Uno sketch Arduino per il XIAO ESP32S3 Sense che fa tutto: muove i servo, legge l’IMU, trasmette video e audio, ospita la web app di controllo e decide come camminare.
I file
- repo/firmware/pulcino/pulcino.ino — setup, ciclo principale a 50 Hz, scelta del generatore di movimento
- repo/firmware/pulcino/config.h — l’unico file da modificare: Wi-Fi, token, variante, calibrazione
- repo/firmware/pulcino/policy.h — pesi della rete neurale (nel repo c’è un segnaposto)
- repo/firmware/pulcino/web/index.html — la web app per iPhone, incorporata nel firmware
- repo/firmware/README.md — istruzioni dettagliate
Architettura
┌──────────── ciclo di controllo 50 Hz ────────────┐
IMU ──────▶│ orientamento (filtro complementare) │
comandi ──▶│ generatore: pose │ cpg │ policy ──▶ q[6] (rad) │──▶ servo
(WS/HTTP) │ limiti giunti, watchdog 1 s │
└──────────────────────────────────────────────────┘
camera ──▶ /stream (porta 81), /capture mic ⇄ speaker ──▶ WS /audio
telemetria ~5 Hz ──▶ WS /ws Wi-Fi / AP / mDNS pulcino.local
Tutti i generatori producono lo stesso risultato: sei angoli dei giunti in radianti con la convenzione dei segni condivisa. Solo il modulo servo li trasforma in gradi e impulsi.
I moduli, uno per uno
Servo
Converte ogni angolo con 90 + SERVO_DIR[i] · gradi(q) + CALIB_OFFSET[i], limita tra 5° e 175° e pilota i pin con ESP32Servo (timer LEDC 1–3, perché lo 0 è della camera) oppure il PCA9685.
IMU
Legge l’MPU6050 via I²C, rimappa gli assi nel frame del robot (x avanti, y sinistra, z su) e stima rollio e beccheggio con un filtro complementare. Fornisce anche il vettore gravità per la politica.
Pose
Pose a keyframe interpolate: stand (tutto a 0), rest (hip_roll +0,25, gambe larghe e servo poco caricati), wave (sposta il peso, alza e agita il piede destro, dice “ciao” e lampeggia gli occhi).
CPG
Camminata a oscillatori letta da gait.json: ogni giunto segue offset + amp·sin(2π·freq·t + fase), la gamba destra è sfasata di π. Il comando vx scala il passo, wz fa curvare, speed la frequenza.
Politica
Una piccola rete neurale (16 → 32 → 32 → 6, tanh) eseguita a 50 Hz. Se POLICY_VALID è 0 il firmware ripiega automaticamente sul CPG.
Rete e web
Wi-Fi di casa oppure Access Point Pulcino-XXXX, mDNS pulcino.local, server HTTP con la web app, API REST, WebSocket per comandi, telemetria e audio, video MJPEG sulla porta 81.
Audio
Microfono PDM interno a 16 kHz verso i client; audio ricevuto e suoni generati (bip, “ciao”) verso il MAX98357A via I²S.
Sicurezza
Watchdog di movimento: senza messaggi per 1 s il robot si ferma. Token opzionale per comandi e POST. Tutti gli angoli sono limitati ai limiti dei giunti.
config.h
Prima di caricare lo sketch apri config.h e controlla almeno queste righe:
#define WIFI_SSID "la-tua-rete" // vuoto = solo Access Point
#define WIFI_PASS "la-tua-password"
#define API_TOKEN "" // non vuoto = comandi protetti con ?token=
#define USE_PCA9685 0 // 1 = variante con PCA9685
static const int8_t SERVO_DIR[6] = { +1, +1, +1, -1, -1, -1 };
static const float CALIB_OFFSET[6] = { 0, 0, 0, 0, 0, 0 };
Non pubblicare mai il tuo config.h con la password del Wi-Fi: se fai un fork, tienilo fuori dai commit.
Calibrazione: un solo array di offset
Tutta la calibrazione sta in un array di 6 numeri, CALIB_OFFSET[6], in gradi: la correzione di quanto ogni corno è entrato storto. Lo modifichi dalla pagina http://pulcino.local/calib (slider + “Salva”) o con l’API GET/POST /api/calib. I valori sono salvati nella memoria NVS del XIAO e hanno la precedenza su quelli scritti in config.h.
SERVO_DIR[6] invece dice in che verso gira ogni servo montato: se muovendo un giunto di +10° il piede va dalla parte sbagliata, cambia il segno di quella voce.
Pose e camminata
Il firmware ha tre generatori di movimento, selezionabili con {"cmd":"mode","m":"cpg|policy"} e {"cmd":"pose","name":"stand|rest|wave"}:
- pose: keyframe interpolati, per stare in piedi, riposare e salutare;
- cpg: oscillatori sinusoidali con parametri in
gait.json(li puoi allenare nella Palestra e caricarli conPOST /api/gait; vengono salvati in LittleFS); - policy: la rete neurale addestrata in MuJoCo (vedi Apprendimento).
Anteprima del CPG predefinito (frequenza 1,6 Hz):
La politica neurale in 20 righe
Ogni 20 ms il firmware costruisce un’osservazione di 16 numeri (gravità, giroscopio, ultima azione, comando, fase del passo), la normalizza con OBS_MEAN/OBS_STD, la passa nella rete e ottiene 6 azioni tra −1 e 1:
q_target = POSE_STAND + azione · ACTION_SCALE // {0.3, 0.6, 0.6} per roll/pitch/ankle
q = 0.6 · q_target + 0.4 · q_precedente // filtro passa-basso
q = clip(q, limiti del giunto)
Sono circa 2 000 moltiplicazioni: all’ESP32-S3 bastano pochi decimi di millisecondo.
Web server e API
| Endpoint | Porta | A cosa serve |
|---|---|---|
GET / | 80 | Web app di controllo (vedi Controllo) |
GET /stream | 81 | Video MJPEG |
GET /capture | 80 | Una foto JPEG |
GET /api/status | 80 | Telemetria JSON |
GET/POST /api/gait | 80 | Legge/scrive gait.json |
GET/POST /api/calib | 80 | Legge/scrive gli offset |
WS /ws | 80 | Comandi e telemetria |
WS /audio | 80 | Audio PCM 16 kHz nei due sensi |
La web app sta in web/index.html e viene incorporata nel firmware durante la compilazione: niente file system da caricare a parte.
Impostazioni di Arduino IDE
- Installa Arduino IDE 2. In Impostazioni → URL aggiuntivi per il Gestore schede aggiungi l’indice delle schede ESP32 di Espressif (
https://espressif.github.io/arduino-esp32/package_esp32_index.json) e installa il pacchetto esp32 (versione 3.x). - Installa le librerie indicate nel README del firmware (tra cui
ESP32Servo). - Scegli la scheda e le opzioni:
Scheda XIAO_ESP32S3 PSRAM OPI PSRAM (indispensabile per la camera) Flash size 8MB Partition scheme 8M with spiffs (3MB APP/1.5MB SPIFFS) o simile con file system USB CDC On Boot Enabled (per vedere i messaggi sul monitor seriale) Monitor seriale 115200 baud - Apri
firmware/pulcino/pulcino.ino, modificaconfig.h, collega il cavo USB-C (interruttore della batteria spento) e premi Carica. - Se la scheda non viene vista: tieni premuto il tasto B (BOOT) mentre la colleghi, poi riprova.
Nel monitor seriale compare l’indirizzo del robot. Da lì: calibrazione e poi controllo.