Robot mobile contrôlé en Wi-Fi en temps réel
Voiture télécommandée à architecture à deux cartes : un ESP32-S3 crée le réseau Wi-Fi et transmet les commandes TCP par UART à un STM32 sous FreeRTOS, qui pilote les moteurs et le servo de direction et s'arrête devant un obstacle. Pilotée depuis une interface PyQt5.
Projet final individuel de Microcontrôleurs et Électronique de puissance (UNCuyo, 2025).
- STM32
- C
- ESP32
- ESP-IDF
- FreeRTOS
- PyQt5
- TCP
- UART
- PWM

Le projet et son origine
L'objectif était un véhicule qui reçoit des commandes depuis une interface graphique sur PC et les exécute en temps réel : commande de moteurs DC, détection d'obstacles par capteur à ultrasons, écran OLED pour l'état et commande sans fil par Wi-Fi.
L'idée vient d'une architecture similaire avec laquelle j'ai travaillé à l'ENIB (Brest). Je n'avais pas le même matériel et j'ai donc refait la conception autour de ce que j'avais : une NUCLEO-F446RE et un ESP32-S3 WROOM. L'ESP32 était nouveau pour moi : j'ai dû apprendre ESP-IDF et PlatformIO en cours de route. Il n'a pas de finalité industrielle ; c'est une base pour la robotique mobile et les systèmes embarqués.
Architecture : deux cartes et un PC
J'ai séparé le travail en deux pour que la commande temps réel ne rivalise pas avec le réseau :
- PC : interface PyQt5 qui envoie des commandes texte en Wi-Fi/TCP.
- ESP32-S3 (ESP-IDF, FreeRTOS) : crée son propre point d'accès Wi-Fi, exécute un serveur TCP et transmet chaque commande au STM32 par UART.
- STM32 NUCLEO-F446RE (FreeRTOS) : reçoit les commandes par UART avec DMA et pilote le reste : PWM du TIM3 et GPIO pour les moteurs DC via un DRV8833, PWM du TIM12 pour le servo de direction MF90, TIM2 pour déclencher et chronométrer le HC-SR04, et I²C pour l'OLED SSD1306.
- Alimentation : deux blocs de deux cellules 18650 en série et deux convertisseurs abaisseurs XL4016, l'un à 5 V pour la NUCLEO et l'ESP32, l'autre à 6 V pour le pilote moteur et le servo.

Comment il a été construit
Je l'ai construit par étapes en validant chacune avant la suivante :
- Tests unitaires de chaque module isolé (capteur à ultrasons, servo, moteurs DC).
- Commande de mouvement de base : moteurs et servo pilotés depuis la NUCLEO avec des commandes saisies sur UART2, puis une interface simple pour les envoyer.
- Intégration de l'ESP32 pour la commande Wi-Fi. Sa caméra et les nombreuses variantes de la carte m'ont obligé à vérifier soigneusement les broches et l'alimentation.
- Un premier module caméra avec un panneau vidéo dans l'interface et un détecteur simple d'objets rouges qui dessinait un cadre englobant. Je l'ai abandonné à la fin : il n'était pas lié à la commande embarquée, je l'ai donc laissé comme travail futur.
- Conception physique : un châssis téléchargé sur Thingiverse et imprimé à plus grande échelle. Le montage des pièces a été la partie difficile, surtout le servo (voir la section des problèmes).
- Essais d'abord sur support fixe puis au sol, avec toujours l'envoi des commandes par UART depuis le PC.
- Écran OLED, qui a aussi permis d'utiliser le bus I²C.
- Intégration finale de l'alimentation et essais complets avec commande à distance en Wi-Fi.


Firmware STM32 sous FreeRTOS
Chaque fonction est une tâche, et les interruptions ne font que libérer des sémaphores pour rester courtes :
- Les commandes arrivent sur UART2/UART4 (115200 bauds) avec réception par DMA. Le callback libère un sémaphore binaire qui réveille CmdProcessing_Task (priorité supérieure à la normale).
- Les commandes sont des lignes de texte : vXXX règle la vitesse de −100 à 100 (le signe est le sens) et sXXX règle l'angle du servo. Tout le reste est ignoré. Les commandes valides vont dans la file des moteurs ou du servo.
- Motor_Task (priorité normale) lit la file des moteurs et applique le sens et le rapport cyclique PWM. Servo_Task (basse) transforme l'angle en impulsion de 1 à 2 ms.
- UltraSonic_Task (priorité haute, pour que la sécurité l'emporte) : le TIM2 émet un déclenchement de 10 µs toutes les 100 ms (environ 10 Hz) et deux canaux de capture mesurent l'écho. Si l'écho dure moins de 1160 µs (environ 20 cm), elle envoie une commande d'arrêt dans la file des moteurs.
- OLED_Task (basse) affiche la distance, ou « Obstaculo » à l'arrêt.
La gestion des ultrasons est faite maison, sans bibliothèque externe ; le pilote OLED est une bibliothèque SSD1306 open source.

Passerelle ESP32 et interface PC
Le firmware de l'ESP32 est découpé en modules : main initialise la mémoire et l'UART et lance la tâche Wi-Fi ; wifi_manager configure le point d'accès ; tcp_server écoute sur le port 1234 et démarre une tâche de réception par client, qui découpe le texte par sauts de ligne ; uart_comm transmet chaque ligne à la NUCLEO avec un sémaphore et une tâche d'envoi dédiée.
L'interface PC est en PyQt5 avec une séparation MVC interne (vue, contrôleur, modèle). Un worker série permet de parler directement à la carte par UART, c'est ainsi que j'ai testé avant le Wi-Fi, et un worker TCP se connecte à l'ESP32 comme client. L'interface a aussi un panneau vidéo issu de l'essai de caméra.
Démonstration
Téléopération du prototype depuis l'interface du PC.
Chiffres
Mesuré :
- NUCLEO et périphériques (OLED et capteur compris) : environ 110 mA à 3,3 V avec les moteurs à pleine vitesse.
- ESP32 : environ 52 mA à 5 V, avec des pics plus élevés au démarrage du Wi-Fi.
- Voiture entière au repos, sans moteurs ni charge : environ 100 mA.
Estimé :
- Autonomie : 3 à 4 heures au repos et environ 1,5 à 2,5 heures moteurs en marche.
- Portée Wi-Fi : 15 à 20 m en intérieur.
Autres valeurs de conception : précision du HC-SR04 de ±1 cm de 2 à 200 cm, échantillonné à environ 10 Hz ; un diviseur de 200 Ω et 100 Ω ramène le signal d'écho de 5 V à environ 3,3 V ; filtrage 470 µF et 100 nF sur la branche 5 V, doublé sur la branche 6 V, plus 470 µF au pilote moteur et au servo.
Problèmes et suite
- Servo : son couple était trop faible pour un braquage ferme des roues. La fixation au fil a laissé du jeu, et j'ai eu du mal à faire correspondre l'angle physique naturel du servo à l'angle numérique pour rouler droit.
- Alimentation : des problèmes d'alimentation sont apparus dès que j'ai retiré les câbles USB. J'ai ajouté un second XL4016 et séparé le circuit en deux branches indépendantes, 5 V pour la logique et 6 V pour les moteurs et le servo, ce qui a stabilisé les essais au sol.
- TCP : déconnexions sporadiques quand beaucoup de commandes sont envoyées en rafale. Cela n'empêche pas la voiture de fonctionner, mais c'est le principal point à corriger.
- Pas de codeurs : la vitesse est en boucle ouverte, donc pas de régulation PID.
Suite : codeurs et PID, un meilleur serveur TCP sur l'ESP32, une interface mobile ou web, la caméra avec IA sur le flux vidéo et davantage de capteurs pour la conduite autonome. Dans une version commerciale hypothétique, je remplacerais le HC-SR04 par un capteur laser VL53L0X, j'utiliserais un Raspberry Pi pour le Wi-Fi et la vision, des moteurs Pololu 12 V et une batterie LiPo 4S.