ti-pote/docs/hardware.md
2026-03-27 10:40:24 +01:00

18 KiB
Raw Permalink Blame History

Architecture Hardware

Philosophie

Le robot Ti-Pote est un client léger. Il ne fait aucun traitement lourd d'IA. Son rôle est de capter l'environnement (son, image), d'envoyer les données au cloud, et de restituer les réponses (audio, écran, mouvement). Le choix du hardware est guidé par ce principe : fiable, basse consommation, suffisant pour le streaming et le wake word local.

Architecture dual-chip

Ti-Pote utilise une architecture à deux processeurs couplés, chacun spécialisé dans son domaine. Ce pattern classique en robotique embarquée sépare le "cerveau" (orchestration, réseau) des "réflexes" (audio temps réel, actionneurs).

                    ┌─────────────────────────────────┐
                    │       RASPBERRY PI ZERO 2 W      │
                    │         (Cerveau / Client)        │
                    │                                   │
                    │  • Client WebSocket vers cloud    │
                    │  • Wake word (OpenWakeWord)        │
                    │  • Orchestration des commandes     │
                    │  • Caméra (CSI)                   │
                    │  • OTA updates                    │
                    │  • Logs / diagnostics             │
                    │                                   │
                    └───────────┬───────────────────────┘
                                │
                          UART (TX/RX/GND)
                          921600 baud
                                │
                    ┌───────────▼───────────────────────┐
                    │         ESP32-S3                   │
                    │     (Réflexes / Temps réel)        │
                    │                                   │
                    │  • Capture audio I2S (micro MEMS) │
                    │  • Sortie audio I2S (ampli)       │
                    │  • Contrôle PWM des servos        │
                    │  • LEDs (NeoPixel WS2812B)        │
                    │  • Capteurs (touch, PIR...)        │
                    │  • Mode idle autonome             │
                    │                                   │
                    └───────────────────────────────────┘

Pourquoi deux chips ?

Raspberry Pi Zero 2 W — Tourne sous Linux (Raspberry Pi OS Lite). Permet de coder le client en TypeScript/Node.js, cohérent avec le reste du stack. Gère la connexion WebSocket, le protocole applicatif, et le wake word via OpenWakeWord (Python). Pas de contrainte temps réel ici : les latences réseau dominent.

ESP32-S3 — Microcontrôleur temps réel, pas d'OS. Gère nativement l'audio I2S (micro + speaker), le PWM pour les servos, et les LEDs — le tout avec des latences de l'ordre de la microseconde. Pas besoin de stack TCP/WebSocket complexe côté firmware : il reçoit des commandes simples du Pi et les exécute.

Avantages de cette architecture

  • Séparation des responsabilités : le Pi n'a pas à gérer l'audio ni les servos en temps réel, ses 512 Mo et son CPU suffisent largement. L'ESP32 n'a pas à gérer le réseau ni le protocole applicatif.
  • Résilience : si le Pi redémarre (OTA, crash), l'ESP32 peut maintenir un mode "idle animation" autonome (respiration des LEDs, position neutre des servos).
  • Découpage du travail : Juliann peut développer le firmware ESP32 en Arduino/C++ pendant qu'Arthur développe le client Pi en TypeScript, avec une interface série bien définie entre les deux.
  • Coût : l'ESP32-S3 ajoute ~5€ et un PCB de 2×3 cm — négligeable dans un boîtier imprimé 3D.

Communication inter-chips

Liaison physique

La communication entre le Pi Zero 2 W et l'ESP32-S3 se fait en UART série :

Paramètre Valeur
Protocole UART
Baud rate 921600
Fils 3 (TX, RX, GND)
Débit effectif ~90 Ko/s
Latence < 1 ms

Note : SPI est envisageable si le débit UART s'avère insuffisant (ex: streaming vidéo depuis l'ESP32). SPI offre plusieurs Mo/s mais nécessite plus de fils (MOSI, MISO, CLK, CS) et un protocole master/slave plus complexe.

Protocole de frames

Chaque message échangé entre les deux chips suit un format binaire simple :

┌────────┬──────┬──────────┬──────────┬─────────────┬──────┐
│ START  │ TYPE │ LENGTH_H │ LENGTH_L │  PAYLOAD    │ CRC8 │
│ 0xAA   │ 1B   │ 1B       │ 1B       │ 0-65535 B   │ 1B   │
└────────┴──────┴──────────┴──────────┴─────────────┴──────┘
Champ Taille Description
START 1 octet Octet de synchronisation : 0xAA
TYPE 1 octet Type de message (voir table ci-dessous)
LENGTH 2 octets Taille du payload (big-endian)
PAYLOAD 0-65535 octets Données du message
CRC8 1 octet Checksum CRC-8 sur TYPE + LENGTH + PAYLOAD

Types de messages

Code Nom Direction Description
0x01 AUDIO_UP ESP32 → Pi Chunk audio capturé par le micro (PCM 16kHz 16bit mono)
0x02 AUDIO_DOWN Pi → ESP32 Chunk audio TTS à jouer sur le speaker
0x03 SERVO_CMD Pi → ESP32 Commande servo : {servo_id: u8, angle: u16, speed: u16}
0x04 LED_CMD Pi → ESP32 Commande LED : {mode: u8, r: u8, g: u8, b: u8, duration: u16}
0x05 STATUS Bidirectionnel Heartbeat et état : {state: u8, battery: u8, temp: u8}
0x06 SENSOR_DATA ESP32 → Pi Données capteurs (touch, PIR, température...)
0x07 CONFIG Pi → ESP32 Paramètres runtime (volume, sensibilité micro, servo trim...)
0x08 ACK Bidirectionnel Acquittement pour les commandes critiques
0x09 IDLE_MODE Pi → ESP32 Active/désactive le mode idle autonome

Flux audio détaillé

Micro MEMS (INMP441)
    │
    │ I2S (16kHz, 16bit, mono)
    ▼
ESP32-S3                    Pi Zero 2 W                    Cloud
┌──────────────┐  UART    ┌──────────────┐  WebSocket   ┌──────────┐
│ Buffer       │ ────────►│ Réception    │ ────────────►│ STT      │
│ circulaire   │ AUDIO_UP │ frames       │  audio PCM   │ (Deepgram│
│ DMA → UART   │          │ → WebSocket  │              │  /Whisper)│
└──────────────┘          └──────────────┘              └──────────┘

L'ESP32-S3 capture l'audio via I2S depuis un micro MEMS (INMP441). Les samples sont accumulés dans un buffer circulaire DMA puis envoyés au Pi toutes les ~20ms sous forme de frames AUDIO_UP. Le Pi reçoit ces frames, extrait le payload PCM, et le pousse dans le WebSocket vers le backend NestJS qui le forward au service STT.

Débit audio : 16000 Hz × 16 bits × 1 canal = 32 Ko/s. Avec l'overhead du protocole (~5 octets par frame), on reste bien en dessous des 90 Ko/s du UART à 921600 baud.

Cloud                       Pi Zero 2 W                    ESP32-S3
┌──────────┐  WebSocket   ┌──────────────┐  UART        ┌──────────────┐
│ TTS      │ ────────────►│ Réception    │ ────────────►│ Buffer I2S   │
│(Eleven-  │  audio PCM   │ WebSocket    │ AUDIO_DOWN   │ DMA → DAC    │
│ Labs)    │              │ → frames     │              │ → Ampli      │
└──────────┘              └──────────────┘              │ → Speaker    │
                                                        └──────────────┘

Le backend envoie les chunks audio TTS via WebSocket au Pi. Le Pi les encapsule en frames AUDIO_DOWN et les transmet à l'ESP32 via UART. L'ESP32 les injecte dans son buffer I2S en sortie, connecté à un ampli MAX98357A, puis au speaker. L'ESP32 gère le timing audio hardware — pas de glitch ni de jitter.

Mode idle autonome

Quand le Pi est indisponible (redémarrage, OTA, perte réseau), l'ESP32 bascule en mode idle après un timeout configurable (défaut : 5 secondes sans heartbeat). En mode idle :

  • Les LEDs passent en respiration lente (bleu/blanc)
  • Les servos reviennent en position neutre avec un mouvement fluide
  • L'ESP32 continue de monitorer les capteurs
  • Dès que le Pi renvoie un heartbeat STATUS, l'ESP32 quitte le mode idle

Composants détaillés

Carte principale : Raspberry Pi Zero 2 W

Spec Détail
CPU Broadcom BCM2710A1, quad-core Cortex-A53 @ 1GHz
RAM 512 Mo LPDDR2
Connectivité Wi-Fi 802.11 b/g/n, Bluetooth 4.2 BLE
GPIO 40 pins (UART, SPI, I2C, CSI)
Prix ~15€
Consommation ~0.5W idle, ~1.5W en charge

Le Pi Zero 2 W est suffisant pour ce rôle : il ne gère ni l'audio ni les servos, seulement la connexion WebSocket (faible bande passante), le wake word (OpenWakeWord tourne en CPU sur ARM), et le relai de commandes vers l'ESP32. Linux permet de coder le client en TypeScript/Node.js.

Contrôleur temps réel : ESP32-S3

Spec Détail
CPU Xtensa LX7, dual-core @ 240MHz
RAM 512 Ko SRAM + 8 Mo PSRAM (selon module)
Périphériques I2S ×2, UART ×3, SPI ×4, PWM, ADC, GPIO
Prix ~5€ (module ESP32-S3-WROOM-1)
Consommation ~0.1W idle, ~0.5W en charge

Le S3 (et non le S2 ou le classique) est recommandé pour son double cœur (un pour l'audio I2S, un pour le UART + servos) et son support USB natif (utile pour le flash/debug).

Microphone : INMP441 (micro MEMS I2S)

Spec Détail
Interface I2S directe avec l'ESP32-S3
Sample rate Jusqu'à 48kHz (on utilise 16kHz)
SNR 61 dB
Prix ~3€ le module

Avantage par rapport au ReSpeaker HAT : connexion I2S directe sur l'ESP32, pas besoin de HAT ni de driver Linux. Plusieurs INMP441 peuvent être combinés pour du beamforming basique si nécessaire.

Amplificateur audio : MAX98357A (I2S)

Spec Détail
Interface I2S directe avec l'ESP32-S3
Puissance 3.2W @ 4Ω
Prix ~4€ le breakout board

Connecté directement à l'ESP32 en I2S. Pas de DAC externe nécessaire — le MAX98357A intègre le DAC et l'ampli. Sortie directe sur un petit speaker 3W.

Haut-parleur

Option A — Mini haut-parleur 3W (~5€)

  • Petit, s'intègre dans le boîtier imprimé 3D
  • Qualité suffisante pour la parole
  • Connecté directement au MAX98357A

Option B — Haut-parleur 5W avec amplificateur (~15€)

  • Meilleur volume et qualité audio
  • Recommandé pour un usage dans une pièce plus grande

Caméra (module optionnel)

Raspberry Pi Camera Module 3 (~30€)

  • 12 MP, autofocus
  • Connecteur CSI direct sur le Pi Zero 2 W
  • Bon pour la reconnaissance visuelle et l'OCR
  • Faible latence de capture

Alternative : Raspberry Pi Camera Module 3 Wide (~35€) — champ de vision plus large (120°).

Écran (module optionnel)

Option A — Écran OLED 1.3" SH1106 (~8€)

  • Petit écran pour afficher des émotions (yeux), l'heure, des icônes de statut
  • Interface I2C — peut être connecté soit au Pi, soit à l'ESP32
  • Basse consommation
  • Parfait pour un robot de bureau compact

Option B — Écran LCD 3.5" ILI9486 (~20€)

  • Plus grand, peut afficher du texte, des images, des animations
  • Interface SPI
  • Permet d'afficher la météo, le prochain rendez-vous, etc.

Option C — Écran tactile 5" HDMI (~40€)

  • Écran complet avec tactile
  • Connecté en mini-HDMI sur le Pi Zero 2 W
  • Le plus polyvalent mais aussi le plus encombrant et énergivore

Servos

Les servos pour l'animation (tête, bras, paupières...) sont connectés directement aux pins PWM de l'ESP32-S3. L'ESP32 gère le timing PWM hardware — mouvements fluides garantis sans jitter, contrairement à un contrôle depuis Linux (softPWM).

  • Micro servos SG90 (~3€ pièce) pour les petits mouvements (paupières, oreilles)
  • Servos MG90S (~5€ pièce) pour les axes principaux (rotation tête, inclinaison)

Alimentation

Alimentation secteur (configuration desk)

  • Alimentation USB-C 5V 3A (~10€) — suffisante pour le Pi Zero 2 W + ESP32 + servos
  • Le robot desk est branché en permanence

Module batterie (optionnel, pour la mobilité)

  • PiSugar 2 (~30€) — batterie intégrée pour Pi Zero, avec circuit de charge
  • Autonomie estimée : 3-6h grâce à la faible consommation du Pi Zero 2 W

LEDs et feedback visuel

Les LEDs sont pilotées par l'ESP32-S3 (temps réel, animations fluides) :

État Animation LED
Écoute Bleue pulsante
Réflexion Jaune clignotante
Parle Verte
Erreur Rouge
Veille Blanche très faible
Mode idle (Pi indisponible) Bleu/blanc respiration lente

Options : anneau NeoPixel WS2812B 12 LEDs (~8€) connecté au GPIO de l'ESP32.

Module base mobile (optionnel)

Pour rendre Ti-Pote mobile, on réutilise l'ESP32-S3 existant (il a assez de pins et de puissance) ou on ajoute un second ESP32 dédié aux moteurs :

Moteurs et châssis

  • 2x moteurs DC avec encodeur (~15€ le kit) — traction différentielle
  • Driver moteur DRV8833 (~5€)
  • Roue omnidirectionnelle arrière (bille) pour la stabilité
  • Le châssis est imprimé en 3D (design par Juliann)

Contrôle moteur

Si l'ESP32-S3 principal a assez de GPIO disponibles, il peut gérer les moteurs en plus de l'audio et des servos (le dual-core le permet). Sinon, un second ESP32 ou Arduino Nano dédié au contrôle moteur communique avec le premier ESP32 en I2C.

Capteurs de navigation (optionnels)

  • Capteurs ultrason HC-SR04 (~3€ x3) — détection d'obstacles
  • Capteur infrarouge TCRT5000 (~2€ x2) — détection de bord de table
  • IMU MPU6050 (~5€) — accéléromètre + gyroscope

BOM estimé (Bill of Materials)

Configuration minimale (desk, voix uniquement)

Composant Prix estimé
Raspberry Pi Zero 2 W 15€
ESP32-S3-WROOM-1 (module) 5€
INMP441 micro MEMS I2S 3€
MAX98357A ampli I2S 4€
Mini haut-parleur 3W 5€
Carte microSD 32Go 8€
Alimentation USB-C 5V 3A 10€
Filament PLA (boîtier) ~5€
Visserie, câbles, PCB ~5€
Total ~60€

Configuration complète (desk, voix + caméra + écran)

Composant Prix estimé
Configuration minimale 60€
Pi Camera Module 3 30€
Écran OLED 1.3" 8€
NeoPixel Ring (12 LEDs) 8€
2x micro servos SG90 6€
Total ~112€

Configuration mobile

Composant Prix estimé
Configuration complète 112€
2x moteurs DC + encodeurs 15€
Driver moteur DRV8833 5€
Batterie PiSugar 2 30€
Capteurs ultrason x3 9€
Total ~171€

Wake word — détail technique

Le wake word est la seule tâche d'IA qui tourne localement, sur le Pi Zero 2 W. L'ESP32 streame l'audio capturé au Pi en continu ; le Pi fait tourner OpenWakeWord en parallèle sur le flux audio entrant.

OpenWakeWord (recommandé pour le MVP)

  • Open source, gratuit
  • Tourne sur CPU (le quad-core Cortex-A53 du Pi Zero 2 W est suffisant)
  • Modèles pré-entraînés disponibles
  • Possibilité d'entraîner un modèle custom pour "Hey Ti-Pote"
  • Latence : <200ms
  • Python, intégrable facilement

Porcupine (Picovoice)

  • Solution commerciale, plan gratuit limité
  • Très optimisé, ultra basse latence (<100ms)
  • Console web pour créer des wake words custom
  • Payant si plus de 3 devices en production

Recommandation : OpenWakeWord pour le MVP. Entraîner un modèle custom "Hey Ti-Pote". Garder Porcupine comme alternative si la précision est insuffisante.

Firmware

Côté Pi Zero 2 W (TypeScript/Node.js)

Le client tourne sous Linux (Raspberry Pi OS Lite) et gère :

  1. Connexion WebSocket permanente avec le backend NestJS
  2. Réception des frames UART depuis l'ESP32 (audio up, sensor data)
  3. Envoi des frames UART vers l'ESP32 (audio down, servo/LED commands)
  4. Wake word detection via OpenWakeWord (Python, appelé en subprocess ou FFI)
  5. Capture image à la demande via la caméra CSI
  6. OTA updates pour lui-même et pour l'ESP32 (flash via UART)
  7. Logs et diagnostics envoyés au cloud

Côté ESP32-S3 (Arduino/C++ ou ESP-IDF)

Le firmware temps réel gère :

  1. Capture audio I2S en continu (buffer DMA circulaire)
  2. Playback audio I2S (réception des chunks, buffer, sortie DAC)
  3. Contrôle PWM des servos (positions, vitesses, interpolation)
  4. Contrôle LED (modes d'animation, transitions fluides)
  5. Lecture des capteurs (touch, PIR, température)
  6. Parsing des frames UART (réception des commandes du Pi)
  7. Mode idle autonome (si perte de heartbeat du Pi)

Interface série — contrat entre les deux firmwares

L'interface UART entre le Pi et l'ESP32 est le contrat qui permet aux deux équipes de travailler en parallèle. Tant que les deux côtés respectent le protocole de frames défini plus haut (START + TYPE + LENGTH + PAYLOAD + CRC8), chaque firmware peut évoluer indépendamment.

Pour le développement, un simulateur d'ESP32 côté Pi (qui génère des frames UART factices) et un simulateur de Pi côté ESP32 (qui envoie des commandes de test via USB-serial) permettent de développer et tester chaque côté isolément.