Piloter un robot
avec une Tsetlin Machine,
sans GPU et hors ligne
Moondream labellise le sol praticable, la Tsetlin Machine apprend et délimite les zones où un robot peut rouler — un pipeline sans cloud à l'inférence : la Tsetlin Machine tourne sur un PC local sans GPU et pilote un robot ESP32 + Raspberry Pi.
Projet : Moondream • GroundTM • Tsetlin.jl • ESP32 • Raspberry Pi
Un robot qui doit voir où il roule
Un robot roulant — une plateforme ESP32 avec un Raspberry Pi et une caméra — doit savoir où il peut avancer. Le capteur principal, c'est la caméra. Depuis le châssis, elle capture des photos en 320×240 pixels de la zone devant le robot. Le problème revient à classer chaque portion de l'image en deux catégories : roulable ou bloqué.
Une Tsetlin Machine est bien adaptée à ce besoin : frugale en mémoire, déterministe, interprétable. Mais il faut d'abord l'entraîner — et pour ça, il faut des données labellisées. C'est là que Moondream entre en jeu.
Frugale
Modèle de 59 Ko, une image classée en 6 ms (médiane) sur un PC de bureau, sans GPU.
Déterministe
Mêmes entrées → mêmes décisions, contrairement aux VLM à formulations variables.
Interprétable
Règles booléennes lisibles : la décision se décompose en ET/NON.
Moondream labellise le sol roulable
Moondream est un VLM (Vision-Language Model) capable de segmenter une image à partir d'une description en langage naturel. On l'utilise via l'API cloud (api.moondream.ai/v1/segment, modèle moondream3.1-9B-A2B) — une seule fois, en amont, pour labelliser un jeu de photos de terrain.
Le prompt qui définit ce qu'est une surface roulable :
"floor surface, walkable ground"
Moondream répond avec un masque de segmentation : un chemin SVG qui délimite les zones praticables dans l'image. Le script label_ground_moondream.py prend ce masque, le rastérise, et le fusionne en une grille de labels :
- 1 → traversable (sol roulable)
- 2 → bloqué (tout ce qui ne l'est pas — mur, rocher, plante, ciel)
L'image source (320×240 px) est redimensionnée par box-average en une grille de 64×24, soit 1 536 cellules, et chaque cellule reçoit un label. Une seule requête segment par photo, une seule clé API.
python scripts/label_ground_moondream.py viz/pipeline/robot_cam.jpg
→ viz/moondream/robot_cam_32x24.ppm # features visuelles 32×24
→ viz/moondream/robot_cam_labels.pgm # labels 1 (roulable) / 2 (bloqué)
Entraînement de la Tsetlin Machine
Les labels Moondream deviennent les règles de la TM.
Les labels Moondream alimentent le pipeline d'entraînement sur un serveur Julia. Le module GroundTM implémente la version de la Tsetlin Machine spécialisée pour la classification pixel par pixel :
- Binarisation — Chaque pixel RVB (et ses voisins, définis par un
radius) est transformé en un vecteur de bits. Le moduleGroundBinarizationtraduit intensité, différence et motifs locaux en booléens. - Entraînement — Le classifieur
TMClassifier(deTsetlin.jl) apprend à associer chaque vecteur de bits à son label. Hyperparamètres : 160 clauses (80 par classe, 40 positives et 40 négatives), marge de vote T = 80, valeurs de mémorisation S = 20 et d'oubli L = 80. - Export — Une fois entraîné, le modèle est compilé avec
export_tmen un fichier.tmbinportable de 59 Ko.
La boucle itérative
Corriger les erreurs de l'un par l'autre.
Le premier entraînement produit rarement un modèle parfait. On fait inférer la TM sur les photos d'entraînement, on isole les désaccords, on re-soumet ces cas ambigus à Moondream pour vérifier ou corriger le label — et on ré-entraîne.
Après quelques itérations, la TM atteint 85,5 % de précision sur les photos de validation (meilleure époque ; détail dans la section Performances), avec l'avantage du déterminisme pur — pas de variation entre deux formulations possibles.
Inférence et navigation
Le robot voit la route.
À l'inférence, le Raspberry Pi du robot capture une image et l'envoie par WiFi local à un PC (AMD Ryzen 5 5600G, sans GPU), où la Tsetlin Machine tourne en Julia. Le PC renvoie la grille au robot. Le pipeline est le même qu'à l'entraînement : décodage JPEG → redimensionnement → binarisation → classification TM. Le résultat est une grille de décision — chaque cellule reçoit la classe traversable (1) ou blocked (2).
L'image 320×240 est classée en une grille de cellules. Pour la navigation temps réel, le module AutoPilot.Policy ne considère que la moitié inférieure — celle qui correspond au sol devant le robot jusqu'à l'horizon.
Pipeline inférence : image JPEG → décodage → redimensionnement box-average → binarisation GroundTM → TM predict → grille de décision.
Architecture actuelle : Raspberry Pi = caméra et pilotage ; ESP32 = moteurs et centrale inertielle (IMU) ; PC local = inférence Julia, sans GPU ni connexion internet. Rien ne tourne encore en embarqué sur le Pi : y faire tourner le modèle de 59 Ko est une prochaine étape possible.
Performances
En clair : l'entraînement prend quelques minutes sur un PC de bureau sans GPU, une décision prend quelques millisecondes, et le modèle pèse 59 Ko.
| Modèle | 160 clauses (80 par classe : 40 positives, 40 négatives)T = 80, S = 20, L = 80 |
|---|---|
| Photos étiquetées | 876, dont 841 utilisables |
| Cellules d'entraînement | 1 244 950rééquilibrées : 622 475 par classe |
| Cellules d'évaluation | 247 29620 % des photos |
| Préparation des données | 11 s115 s avant optimisation |
| Une époque d'entraînement | 36 s51 s avec l'ancienne version de Tsetlin.jl (−29 %) |
| Entraînement complet (10 époques) | environ 6 minutes467 s mesurées, étiquetage Moondream de 47 nouvelles photos compris ; l'apprentissage domine : ~360 s sur ~390 |
| Précision sur les photos de validation | 85,5 %meilleure époque ; 78 à 85 % selon les époques |
| « Faux libre » (obstacle vu comme du sol) | 4,24 ± 0,43 %quand les « faux bloqué » sont fixés à 8 % |
| Taille du modèle | 59 Ko (.tmbin).tm avec états d'apprentissage : 524 Ko |
| Classer une image sur le PC | 6 ms en médiane, 7 ms au 90e centileun seul cœur ; JPEG → grille de 1 536 cellules |
| Raspberry Pi Zero (ancien essai) | 226 ms par imageNIF Rust (tsetlin_runner), ancienne grille 32×24 et ancien modèle ; non remesuré, le Pi ne classe plus |
Méthode : le taux de « faux libre » est mesuré sur 5 entraînements, avec des jeux de photos séparés (630 pour l'entraînement, 98 pour la validation, 113 pour le test).
Source des chiffres : journal de mesures du projet (docs/journal.md, tableau de bilan et sections 4, 7 et 11). PC de mesure : AMD Ryzen 5 5600G, sans GPU.
Résultats
Moondream n'intervient qu'à l'entraînement. À l'inférence, la Tsetlin Machine classe chaque image en 6 ms (médiane) sur le PC local — sans cloud, sans GPU, sans appel API.
Taille
Modèle .tmbin : 59 Ko (524 Ko avec les états d'apprentissage).
Latence
6 ms par image en médiane, 7 ms au 90e centile, sur un seul cœur du PC.
Matériel
Raspberry Pi (caméra, pilotage) + ESP32 (moteurs, IMU), inférence sur un PC local sans GPU, sans cloud à l'inférence.
Déterministe
Pas de variation de formulation — la TM prend toujours la même décision pour la même entrée.
Le corridor le plus praticable devient la prochaine commande moteur, et le robot roule.
Vous voulez en savoir plus ?
Ce pipeline fait partie de mon travail sur l'IA locale et frugale. La bibliothèque Tsetlin.jl utilisée ici est open source sur GitHub.