Guilhem Carmouze

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.

Rôle
Partie 2, le vrai robot : l’interface web (application monopage Web Bluetooth, flux caméra, règle de centrage de la balle, cadencement des commandes vocales). Partie 1 : analyse des images, entrées et sorties de fichiers, seuils de couleur et structures de clusters du détecteur en C.
Équipe
Partie 2 : une équipe de six, avec cinq coéquipiers. Partie 1 : avec un camarade de promotion.
Période
Partie 1 : janvier 2025. Partie 2 : printemps 2025.
Organisation
UPSSITECH, Université de Toulouse. Cursus Systèmes Robotiques et Interactifs (SRI), première année du cycle ingénieur.
Technologies
JavaScript, API Web Bluetooth, Bootstrap 5, MJPEG sur HTTP. Partie 1 : C11, GNU Make, CMake. Sur le robot, écrit par mes coéquipiers : Arduino, Raspberry Pi, RPLiDAR, Python et OpenCV.
Ce que voit la caméra du robot, tel que la page web le montre : chaque balle est entourée avec sa position et une traînée. Enregistrement de démonstration de l’équipe. La détection tourne sur le Raspberry Pi et c’est le travail de mes coéquipiers. Afficher le flux dans la page, et transformer les positions en commandes de conduite, c’est le mien.

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.

Le robot à quatre roues à côté d’une caisse grise dans une arène de test. À droite, deux graphiques d’un écran : le scan LiDAR en direct en rouge et la carte construite à partir de scans successifs en bleu.
Le robot de l’équipe dans son arène, à côté du scan LiDAR en direct (graphique de gauche) et de la carte construite à partir de scans successifs (graphique de droite). La cartographie, avec l’appariement de scans par ICP, est le travail de mes coéquipiers. Les titres des graphiques sont en français.

Ce que j’ai réalisé

  1. 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

  2. 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.

  3. 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.

  4. 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

  1. 01Webcam et OpenCV sur le Raspberry Pidétection des balles par couleur
  2. Tant qu’une balle est suivie : le robot bouge, et la caméra voit la balle ailleurs

    1. 02Flux MJPEG et position de la balleservis sur le Wi-Fi local
    2. 03Vue caméra dans la page webvue vocale, affichée quand une commande de suivi de balle est détectée
    3. 04Règle de centrage de la ballela position horizontale de la balle sur l’image : tourner à gauche, tourner à droite ou avancer
    4. 05Écriture Web Bluetoothune seule liaison pour le pavé, la vue vocale et la règle
    5. 06Pilotage des moteurs par Arduinoquatre moteurs à courant continu
Ma partLe travail de mes coéquipiersLa page parle à deux machines différentes : le Raspberry Pi par Wi-Fi pour l’image et la position de la balle, et l’Arduino par Bluetooth pour les moteurs.
La page sur un téléphone, en mode manuel, qui pilote le robot dans un couloir. Enregistrement de démonstration de l’équipe.
Le pavé : quatre flèches et trois boutons colorés, et le robot qui traverse un hall. Enregistrement de démonstration de l’équipe.
La vue vocale sur un téléphone, puis le robot qui roule dans un hall. Enregistrement de démonstration de l’équipe.

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.

Deux rangées de trois panneaux. À gauche : une photo de 300 par 300 de balles colorées sur un sol. Au milieu : les masques de couleur, une silhouette atténuée de tout ce qui est dans les seuils et une plus grande composante lumineuse avec sa boîte englobante. À droite : la photo à nouveau, avec un cercle, une croix et une étiquette sur chaque balle, par exemple orange en (158, 204) de rayon 42.
D’une image texte à une position de balle, sur deux des 20 photos : les masques, puis le cercle dérivé de la boîte englobante. Les seuils n’attrapent qu’une partie d’une balle orange ou jaune, ce qui explique que la boîte soit décentrée et que trois corrections empiriques de la fin du projet aient été conservées.

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éValeurComment le lire
Erreur de centre du cercle rapporté, médiane (maximum), sur les 28 balles4,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 empiriques11,0 px → 6,1 pxLes 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 Windows7 ms, 40 msDémarrage et analyse du fichier texte de 1 Mo inclus, sur un CPU de portable, sans GPU.
Vérifications de la suite de tests101 + 58101 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.
Partie 1, le détecteur en C sur ses 20 photos. Les 28 balles ont été étiquetées à l’œil en octobre 2026, à environ 2 px près, et chaque nombre est écrit par un script du dépôt qui lance le programme compilé. Pour les erreurs, plus bas est mieux.
Une grille des 20 photos de test, des balles de trois couleurs sur des sols gris, chaque balle entourée par le détecteur. Les trois dernières photos, des sols vides, portent la mention « empty scene, nothing detected ».
Les 20 photos de test avec le cercle que le détecteur rapporte pour chaque balle, dessinés par un script du dépôt. L’origine des photos n’y est pas documentée.

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.