Projet Fil Rouge. Première année du cycle ingénieur, 2024-2025.
Un vrai robot, piloté depuis une page web
Au printemps 2025, une équipe de six a construit un vrai robot mobile. Ma part était ce que touche l’opérateur : une page web qui le pilote en Bluetooth, montre ce que voit sa caméra et transforme la position d’une balle en commandes qui la gardent centrée. Le semestre d’avant, avec un camarade de promotion, j’avais écrit un détecteur de balles de couleur en C pur.
En trois lignes
- Problème
- Un vrai robot devait se piloter depuis un téléphone ou un ordinateur, à la main, à la voix et en suivant une balle, sur une liaison Bluetooth qu’un simple rechargement de page coupait à chaque fois.
- Ce que j’ai réalisé
- Une application monopage à trois vues qui pilote le robot par l’API Web Bluetooth, le flux caméra du Raspberry Pi dans la vue vocale, une règle qui transforme la position image de la balle en commandes de conduite, et le cadencement des commandes vocales découpées : 2 s par mètre, 4 s par quart de tour.
- Résultat
- Un robot que l’équipe a montré en train de rouler depuis la page, à la voix et en suivant une balle, et en cartographiant son environnement. Le détecteur en C de la première moitié trouve 28 balles sur 28 sur ses 20 photos, sans fausse détection, un score réglé sur ces photos qui ne mesure pas la généralisation.
Contexte
Le Projet Fil Rouge est le projet transversal de la première année du cycle ingénieur à l’UPSSITECH, sur deux semestres. La première moitié (semestre 5, janvier 2025) était du logiciel en C. Dans la seconde (semestre 6, printemps 2025), chaque équipe devait passer d’un monde simulé à un vrai robot qui se déplace dans une pièce, réagit à des commandes vocales et détecte des objets avec ses capteurs.
Notre robot combine pilotage des moteurs par Arduino, caméra Raspberry Pi, cartographie RPLiDAR avec ICP, commandes vocales, suivi de balle et une interface web. Nous étions six : mes cinq coéquipiers et moi. Le code, le rapport, les diapositives et les enregistrements de démonstration sont dans le dépôt d’équipe PFR2.

Ce que j’ai réalisé
Partie 2, la page
Une application monopage qui ne coupe jamais la liaison
Le robot se pilote en Bluetooth avec l’API Web Bluetooth, et un rechargement normal de la page coupait cette liaison à chaque fois. L’interface est donc une application monopage : un menu d’accueil, un pavé de pilotage manuel et une vue vocale s’échangent sur place, sans rechargement. Un point vert ou rouge permanent indique si la liaison est active, et le bouton de connexion disparaît dès qu’elle l’est. Le pavé a quatre flèches et trois grands boutons colorés (plus vite, moins vite, mode automatique), dimensionnés et colorés pour un usage immédiat. L’interface est construite avec Bootstrap 5.
Web Bluetooth fonctionne dans Chrome et Edge sur ordinateur. Sur iOS, le rapport recommande une application de navigateur tierce (Blueify).
Dépôt : PFR2dépôt d’équipe, Code/IHM
Partie 2, la caméra
La vue du robot dans la page
Le Raspberry Pi traite la vidéo de la webcam et la sert en flux MJPEG, avec la position de la balle détectée, sur le Wi-Fi local. Dans la vue vocale, dès qu’une commande de suivi de balle est détectée, ma page affiche le flux en direct.
Le côté Raspberry Pi, la détection OpenCV et son serveur vidéo, est le travail de mes coéquipiers.
Partie 2, la balle
Garder la balle centrée
La page reçoit la position (x, y) de la balle et convertit sa coordonnée horizontale en commandes de conduite pour l’Arduino. Quand la balle est hors de l’axe central de l’image, le robot tourne vers elle ; quand elle est sur l’axe, le robot avance. Sans balle en vue, il tourne pour en chercher une, et si la caméra est injoignable, il s’arrête. Les commandes partent par la même liaison Bluetooth que le pavé.
La règle est dans le code de l’interface du dépôt d’équipe.
Partie 2, la voix
Cadencer les séquences parlées
Le code d’un coéquipier transforme une phrase française parlée en une liste de commandes, et un algorithme d’un collègue la découpe en étapes (avancer de deux mètres, puis un quart de tour à droite). J’ai intégré ce découpage, puis calculé et appliqué les délais entre les commandes : 2 s par mètre et 4 s par quart de tour.
Suivre une balle depuis la page web
- 01Webcam et OpenCV sur le Raspberry Pidétection des balles par couleur
Tant qu’une balle est suivie : le robot bouge, et la caméra voit la balle ailleurs
- 02Flux MJPEG et position de la balleservis sur le Wi-Fi local
- 03Vue caméra dans la page webvue vocale, affichée quand une commande de suivi de balle est détectée
- 04Règle de centrage de la ballela position horizontale de la balle sur l’image : tourner à gauche, tourner à droite ou avancer
- 05Écriture Web Bluetoothune seule liaison pour le pavé, la vue vocale et la règle
- 06Pilotage des moteurs par Arduinoquatre moteurs à courant continu
Partie 1, janvier 2025 : un détecteur de balles de couleur en C pur
Avec un camarade de promotion, j’ai écrit la partie traitement d’image de la première moitié du projet : un programme C11 qui trouve des balles orange, bleues et jaunes dans une image RGB de 300 × 300 et rapporte le centre et le rayon de chacune, sans bibliothèque de vision. Il lit l’image sous forme d’export texte, segmente chaque couleur avec des seuils RGB fixes, garde la plus grande tache 4-connexe de chaque couleur et la mesure par sa boîte englobante.
Par git blame, ma part est l’analyseur d’image et sa structure, la lecture et l’écriture de fichiers, les seuils de couleur et la construction des masques, et la liste de clusters avec leur boîte englobante, leur centre et leur rayon. Mon camarade de promotion a écrit la quantification RGB et le filtre de la plus grande composante.
En octobre 2026, j’ai nettoyé le dépôt, avec un assistant de code IA : la version réglée utilisée à la fin du projet a été reprise, les bugs restants ont été corrigés (un débordement de pile dans le remplissage par diffusion (flood fill) récursif, des fuites mémoire, un plantage à la suppression d’une petite tache), et des tests, une évaluation étiquetée et les figures ont été ajoutés.

Résultats
La partie 2 est une démonstration, pas une mesure
Le robot a été montré en train de rouler depuis la page en mode manuel, à partir d’une phrase parlée et en suivant une balle, et en cartographiant avec son LiDAR : les enregistrements sont dans le dépôt d’équipe. Je n’ai aucune mesure à moi à citer pour cette partie. Les seuls nombres de ma part sont la règle de cadencement : 2 s par mètre et 4 s par quart de tour.
28 / 28
balles trouvées avec la bonne couleur, centre à l’intérieur de la balle étiquetée, sur les 20 photos de test de la partie 1, sans fausse détection et avec les 3 scènes vides laissées vides. Les seuils et les corrections ont été réglés sur ces mêmes photos : cela montre de la cohérence, pas de la généralisation.
| Ce qui a été mesuré | Valeur | Comment le lire |
|---|---|---|
| Erreur de centre du cercle rapporté, médiane (maximum), sur les 28 balles | 4,1 px (18,0 px) | Le pire cas est une balle vue de très près. Les masques orange et jaune ratent environ la moitié de la balle, toujours du même côté. |
| Balles orange, erreur de centre médiane avant et après les trois corrections empiriques | 11,0 px → 6,1 px | Les corrections aident sur cet ensemble, qui est vraisemblablement celui sur lequel elles ont été ajustées. |
| Recouvrement du cercle rapporté avec le cercle étiqueté (IoU), médiane (minimum) | 0,85 (0,59) | Les balles bleues sont localisées à quelques pixels près, les orange et jaunes moins bien. |
| Temps d’exécution par image, dans un conteneur Linux et sous Windows | 7 ms, 40 ms | Démarrage et analyse du fichier texte de 1 Mo inclus, sur un CPU de portable, sans GPU. |
| Vérifications de la suite de tests | 101 + 58 | 101 vérifications unitaires sur les modules et 58 sur le programme compilé : les 20 photos contre des sorties enregistrées, des scènes synthétiques et des entrées mal formées. |

Ce qui a échoué ou reste inachevé
0 / 7
balles jaunes trouvées quand chaque pixel des 20 photos est assombri à 70 % (un changement d’exposition simulé). Les seuils RGB fixes sont liés à l’exposition de ces photos : un changement de 10 % dans un sens ou dans l’autre fait déjà perdre une balle.
Une balle par couleur, et aucune vérification de forme. Seule la plus grande tache de chaque couleur est rapportée, et toute tache assez grande d’une couleur connue compte comme une balle. La position est approximative.
Le détecteur en C n’a jamais tourné sur le robot. Sur le robot, le suivi de balle est un programme Python distinct sur le Raspberry Pi, écrit par mes coéquipiers avec OpenCV d’après l’idée du détecteur de la partie 1. Il suit deux ou trois couleurs au plus : le rapport note qu’avec davantage il devient instable, et que la webcam réagit à l’éclairage et prend un objet brillant pour une balle.
Le cadencement vocal est en boucle ouverte. Les délais sont des durées, pas des distances mesurées : le robot n’avait pas d’odométrie, donc un mètre, ce sont deux secondes de conduite et un quart de tour, quatre.
Web Bluetooth n’est pas disponible partout. Il fonctionne dans Chrome et Edge sur ordinateur. Sur un iPhone, le rapport recommande une application de navigateur tierce.
Je n’ai pas écrit le traitement d’image de la partie 2. Contrairement à la partie 1, la détection qui alimente la règle de centrage est le travail de mes coéquipiers. Ma part commence aux coordonnées de la balle.
Crédits
Les autres parties du robot sont le travail de mes cinq coéquipiers, comme le disent les sections individuelles du rapport d’équipe : reconnaissance vocale et filtre de commandes (un coéquipier, qui a aussi contribué au code Arduino et à l’interface utilisateur), suivi de balle sur le Raspberry Pi et son serveur vidéo (deux coéquipiers), cartographie LiDAR avec ICP (un coéquipier), code Arduino et câblage des capteurs (un coéquipier).
Le robot, les enregistrements de démonstration, le rapport et les diapositives appartiennent à l’équipe. Les enregistrements de cette page viennent du dépôt d’équipe PFR2, hébergé par un coéquipier.
La partie 1 a été écrite avec un camarade de promotion. Le nettoyage et l’évaluation d’octobre 2026 sont les miens, faits avec un assistant de code IA : ces commits portent la mention Co-Authored-By.