Construire un robot ROS 2 qui voit et roule vers un marqueur
Un robot qui repère un marqueur à travers une pièce, calcule où il est par rapport à lui, et s'en approche de face — structuré en vrai graphe de nœuds ROS 2.
Ce que vous construisez
Un robot déposé quelque part dans une pièce, qui tourne jusqu’à trouver un marqueur imprimé sur un mur, et s’en approche — en s’arrêtant à un demi-mètre, d’équerre à la face du marqueur plutôt que simplement près de lui.
Tous les autres montages de ce site exécutent un programme sur un microcontrôleur. Celui-ci est un ordinateur à roues, et cela change l’objet du projet. Les parties dures ne sont plus timing et câblage ; ce sont de savoir où sont les choses les unes par rapport aux autres, et de garder plusieurs logiciels honnêtes entre eux pendant qu’ils tournent tous à la fois.
Pourquoi ce robot a besoin d’un ordinateur
Un Arduino ne peut pas faire cela, et la raison mérite d’être précise. Ce n’est pas la vitesse brute — c’est qu’une image de caméra fait un quart de mégaoctet, la détection ArUco veut de l’algèbre linéaire en flottants, et le tout doit arriver pendant que les roues sont encore commandées à 50 Hz. C’est un travail pour un système d’exploitation avec vraie mémoire et vrai ordonnancement.
Ce que vous obtenez en échange de ce boîtier Linux est la capacité de regarder dans un robot en marche. Chaque message entre chaque partie est un topic auquel vous pouvez vous abonner depuis un portable. Quand le robot passe devant le marqueur au lieu d’aller vers lui, vous n’ajoutez pas d’affichages et ne reflashez pas — vous faites ros2 topic echo de la pose et la regardez être fausse en temps réel.
La forme du graphe de nœuds
Cinq responsabilités, un nœud chacune :
| Nœud | Publie | Travail |
|---|---|---|
camera |
/image_raw, /camera_info |
Tire les images du bus CSI |
aruco_detector |
TF camera_link → marker_7 |
Trouve l’étiquette, résout sa pose |
docking_controller |
/cmd_vel |
Décide où rouler |
diff_drive |
série vers l’Arduino | Torsion vers vitesses de roues |
odometry |
TF odom → base_link |
Intègre les tops codeurs |
Les interfaces font l’intérêt de cette structure. Le contrôleur ne touche jamais une caméra ni un moteur — il consomme une transformée et produit un Twist. Cela signifie que vous pouvez conduire le même robot en téléop clavier, tester le contrôleur contre une transformée factice sans aucun matériel, et plus tard déposer une pile de navigation qui publie le topic identique.
Lisez nœuds, topics, services et actions avant de dessiner votre propre version de ce tableau. L’erreur la plus fréquente à ce stade est de faire du contrôleur d’accostage un service — c’est un objectif long qu’il faut pouvoir annuler, exactement ce à quoi sert une action.
Nomenclature
C’est le robot à deux cerveaux, et la liste de pièces le reflète : un ordinateur pour la perception et un microcontrôleur pour ce qu’un ordinateur ne fait pas fiablement.
| Pièce | Qté | Coût approx. | Notes |
|---|---|---|---|
| Raspberry Pi 4, 4 Go | 1 | $55 | 4 Go est le plancher pratique pour ROS 2 plus vision. 1 Go swappe et meurt |
| Caméra Pi Module 3 | 1 | $25 | La variante Wide convient mieux à la navigation — 102° au lieu de 66° |
| microSD classe A2, 32 Go | 1 | $8 | Ou démarrage depuis un SSD USB, vraiment plus rapide |
| Dissipateur ou ventilateur | 1 | $5 | Un Pi 4 bride à 80 °C, et un Pi bridé perd des images |
| Arduino Uno ou Nano | 1 | $5 | Codeurs et commande moteur — la moitié temps réel |
| Moteurs à codeurs N20 | 2 | $16 | |
| TB6612FNG | 1 | $3 | |
| Châssis 2 roues motrices | 1 | $12 | Place pour un Pi, un mât de caméra et une batterie |
| Pack batterie | 1 | $15 | 3S avec régulateur 5 V à découpage calibré 3 A |
| Marqueurs ArUco imprimés | — | $0 | Imprimez, mesurez la taille imprimée, et utilisez la mesure |
Total : environ $145–175. C’est de loin le projet le plus cher du site, et l’essentiel est le Pi.
L’alimentation est là où ces robots échouent, et l’échec coûte cher. Une microcoupure pendant une écriture carte SD corrompt toute l’image système. Utilisez un régulateur à découpage bien au-dessus du tirage du Pi, ne partagez jamais le rail avec les moteurs, et vérifiez vcgencmd get_throttled — tout non-zéro signifie une alimentation insuffisante et une carte corrompue à venir.
Mesurez vos marqueurs imprimés. Une solution de pose ArUco est directement proportionnelle à la taille de marqueur déclarée. Un marqueur imprimé à 95 % par un « ajuster à la page » donne des poses fausses de 5 % à toute distance, et rien dans le pipeline ne vous le dira.
Ordre de montage
1 — Faites tourner ROS 2 et prouvez le réseau. Suivez installer ROS 2 sur un Raspberry Pi. Ne passez pas à la suite tant que ros2 topic echo sur votre portable ne montre pas un topic publié sur le robot. La découverte en Wi-Fi est la chose la plus susceptible de manger une soirée, et vous voulez la manger maintenant plutôt qu’en déboguant la vision.
2 — Faites obéir les roues à un Twist. Câblez l’Arduino, les codeurs et le TB6612FNG, et construisez le pont cmd_vel. Jalon : la téléop clavier depuis le portable conduit le vrai robot. Calibrez l’entraxe ici — tout l’aval en hérite.
3 — Calibrez la caméra. Correctement, avec une vraie mire, en suivant calibration de caméra et pose ArUco. Une caméra non calibrée produit des poses plausibles et fausses de dizaines de pourcents aux bords de l’image, ce qui est le pire mode de panne disponible.
4 — Publiez le marqueur comme une transformée. Pas comme un message personnalisé avec un x et un y dedans. Publier camera_link → marker_7 dans TF2 signifie que le contrôleur peut demander « où est le marqueur, en base_link ? » et la réponse tient compte exactement de comment votre caméra est montée — y compris qu’elle est inclinée, ce qu’elle est.
5 — Roulez vers le marqueur. Un contrôleur proportionnel sur le relèvement : tournez vers lui, roulez en avant, arrêtez à la distance de recul. Cela marche, et cela arrive en angle, ce qui est le propos de l’étape suivante.
6 — Approchez le long de la normale. Au lieu de diriger vers le marqueur, calculez un waypoint décollé de la face du marqueur le long de sa normale, roulez jusque-là, et seulement alors roulez droit dedans. C’est la différence entre atteindre le quai et accoster. C’est aussi là que l’orientation du marqueur — la partie de la pose inutile jusque-là — commence à compter, et où vous rencontrerez l’ambiguïté de pose.
7 — Enveloppez dans une machine à états. Recherche, approche, alignement, finale, terminé, plus les transitions hors de chacune quand le marqueur est perdu. Machines à états finis pour le comportement robotique couvre la structure ; le besoin spécifique de ce robot est un timeout de marqueur perdu qui revient en recherche plutôt que de continuer sur la dernière pose connue.
Notes matérielles importantes
Montez la caméra rigidement, et mesurez comment. Chaque pose calculée par le robot est relative à la caméra, et TF2 la transforme en pose relative au robot avec la transformée que vous déclarez de base_link à camera_link. Une caméra sur un support flexible rend cette transformée déclarée mensongère et variable avec l’accélération.
Inclinez la caméra vers le bas, et dites-le. Une caméra pointée à l’horizon perd le marqueur exactement quand le robot s’approche. Dix à quinze degrés vers le bas le gardent dans le cadre jusqu’à l’approche finale — et cette inclinaison va dans la transformée statique, pas dans un facteur arbitraire du contrôleur.
Mesurez le marqueur au pied à coulisse. L’échelle de pose est directement proportionnelle à la taille de marqueur dite au solveur. Imprimer à 96 % parce que l’imprimante a réduit pour ajuster rend chaque distance fausse de 4 %, silencieusement et systématiquement.
Alimentez le Pi séparément des moteurs. Un moteur qui cale fait chuter le rail, et là où un Arduino redémarrerait sans dommage, un Pi corrompt son système de fichiers. Soit un régulateur séparé soit un pack séparé — ce n’est pas l’endroit pour économiser un composant.
Tenez la nappe caméra loin des fils moteurs. C’est une liaison haute vitesse non blindée. Le bruit moteur couplé dedans apparaît comme des images corrompues, qui apparaissent comme des détections qui clignotent sans raison visible.
À quoi ressemble un bon résultat
| Mesure | Typique sur Pi 4 |
|---|---|
| Capture caméra à 640×480 | 30 im/s |
| Détection ArUco, 640×480 | 25–30 im/s, avec 40–60 % d’un cœur |
| Détection ArUco, 1920×1080 | 5–8 im/s — et chaque image est périmée |
| Portée de détection (marqueur 100 mm, 640×480) | 1,5–2,5 m |
| Précision de pose à 1 m | ±2–5 cm en position, ±3–5° en orientation |
| Latence totale image-décision | 60–120 ms |
| Boucle de commande moteur, sur l’Arduino | 100–200 Hz |
| Latence topic ROS 2, Pi vers Arduino en série | 5–15 ms |
Deux lignes portent la leçon de tout le projet.
La résolution n’est pas gratuite, et plus haute est souvent pire. Passer de 640×480 à 1080p coûte 4–6× le traitement pour environ 1,7× la portée de détection. Sauf besoin spécifique de voir un marqueur plus loin, la petite image donne une réponse plus rapide et plus fraîche — et la fraîcheur compte plus que la précision dans une boucle de commande.
La ligne de latence explique la découpe à deux cerveaux. À 0,3 m/s, 100 ms de latence vision font 3 cm de trajet ; en tournant à 90°/s cela fait 9° de rotation. Chaque mesure de vision décrit où le robot était. Boucler une boucle rapide directement dessus oscillera. La structure qui marche est celle qu’utilise ce robot : l’Arduino tient la boucle rapide sur codeurs, et la vision la corrige lentement — exactement la même forme que fusionner GPS avec odométrie sur le rover à waypoints, et exactement pour la même raison.
Obturateur déroulant, si le robot bouge en regardant
Les modules caméra Pi standard ont un obturateur déroulant : les lignes sont exposées l’une après l’autre, donc le haut d’une image est capturé quelques millisecondes avant le bas. À l’arrêt, c’est invisible. En tournant à 90°/s, les quatre coins d’un marqueur ArUco ont été capturés à quatre orientations différentes du robot — et la pose résolue est fausse d’une façon que la calibration ne corrige pas.
Si le robot doit voir en bougeant, c’est à cela que sert le module Global Shutter. S’il peut s’arrêter, regarder, puis bouger, le module moins cher convient entièrement — et s’arrêter pour regarder est un choix de conception légitime, pas un contournement.
Quand ça tourne mal
| Symptôme | Habituellement |
|---|---|
| Le portable ne voit aucun topic | Multicast bloqué par le point d’accès, ou ROS_DOMAIN_ID discordant |
| Marqueur détecté, le robot ne bouge pas | Twist publié contre un abonné TwistStamped |
| Distance systématiquement fausse de quelques pourcents | Taille de marqueur fausse, ou l’imprimante a réduit la page |
| La pose tremble fort à distance | Marqueur trop petit dans l’image — rapprochez ou imprimez plus grand |
| La normale du marqueur bascule | Ambiguïté de pose — approchez hors axe, ou utilisez un plateau ChArUco |
| Le robot arrive près du marqueur mais de travers | Direction vers le marqueur au lieu du long de sa normale |
| Dépasse en approche finale | Asservissement sur une pose vieille de 50–100 ms — ralentissez près de la fin |
| Continue après que le marqueur sort du cadre | Pas de timeout de marqueur perdu dans la machine à états |
La distribution de ce tableau mérite d’être remarquée avant de commencer : presque rien n’est de la vision par ordinateur. C’est du réseau, des repères, des unités et de la commande — ce qu’enseigne vraiment la construction d’un robot ROS 2, et pourquoi le parcours fondations ROS 2 passe son temps sur les motifs de communication et les repères plutôt que sur OpenCV.
Si c’est un pas trop grand, la Micromouse enseigne cartographie et planification sur microcontrôleur sans Linux, et le robot piloté au téléphone couvre la moitié « les commandes arrivent par réseau » de ce problème pour une fraction des pièces.
Parcours du projet
Le parcours de construction
Suivez l'arbre technologique, des pièces jusqu'à un robot qui fonctionne. Chaque nœud se débloque quand ses prérequis sont terminés, et votre progression est enregistrée sur cet appareil.
0 / 19 terminés
Composants
- ContrôleurRaspberry PiUn ordinateur Linux complet de la taille d'une carte — le cerveau pour les robots à vision et ROS.
- CapteurRaspberry Pi CameraUne caméra sur sa propre voie de données, pour que la vision ne se batte pas avec le bus USB.
- ContrôleurArduino UnoLa carte 8 bits indulgente par laquelle la plupart découvrent la robotique.
- PiloteTB6612FNG Motor DriverUn pont en H MOSFET qui garde les volts réellement payés.
- ActionneurN20 Encoder GearmotorUn micromoteur à réducteur métal avec codeur à l'arrière : le robot sait jusqu'où il est vraiment allé.
- Châssis2WD Robot ChassisLe plateau sur lequel se fixent deux moteurs, une roulette libre et votre électronique.
- AlimentationRobot Battery & Power PackLa différence entre un robot qui roule et un qui redémarre sans cesse.
Tutoriels de ce parcours
- Débutant · 1 h de lectureInstaller ROS 2 sur un Raspberry Pi et créer un workspaceChoisissez l'OS, installez ROS 2 depuis apt, construisez un espace de travail colcon, et faites parler un portable au robot.
- Débutant · 19 min de lectureNœuds, sujets, services et actions en ROS 2Choisissez le bon motif de communication ROS 2 et inspectez comment les nœuds échangent données et commandes du robot.
- Intermédiaire · 20 min de lectureRepères de coordonnées TF2 sous ROS 2 pour robots mobilesConstruisez et déboguez un arbre de repères TF2, de map et odom jusqu'à la base du robot et chaque capteur.
- Intermédiaire · 22 min de lectureÉtalonnage de caméra et pose ArUco avec OpenCVÉtalonnez les paramètres intrinsèques de la caméra, validez l'erreur de reprojection, et estimez la pose 3D d'un marqueur ArUco.
- Intermédiaire · 45 min de lectureDe cmd_vel aux vitesses de roues en ROS 2Convertissez un Twist en vitesses de roues gauche et droite — cinématique, saturation, bande morte et chien de garde.
- Débutant · 17 min de lectureLire des encodeurs en quadrature pour distance et vitesseTransformez les impulsions d'un encodeur en quadrature en mesures fiables de sens, distance et vitesse de roue.
- Débutant · 17 min de lectureMachines à états finis pour le comportement robotiqueRemplacez les conditionnels robotiques emmêlés par des états, événements, transitions, temporisations et récupération explicites.
Questions fréquentes
Pourquoi utiliser ROS 2 plutôt qu'un seul script Python ?
Pour ce seul robot, un seul script marcherait, et il serait plus court. Ce qu'il ne survivrait pas, c'est la seconde fonctionnalité. Dès que la boucle caméra, la boucle de conduite et la logique de décision doivent tourner à des cadences différentes et continuer quand l'une cale, un seul script devient un problème d'ordonnancement à résoudre soi-même. ROS 2 donne la séparation des processus, un format sur le fil entre les parties, et — ce qu'on sent aussitôt — la capacité d'inspecter tout topic depuis un portable pendant que le robot tourne. Le projet vaut d'être fait car il enseigne cette structure sur un problème assez petit pour rester compréhensible.
Faut-il un Arduino en plus du Raspberry Pi ?
Pas strictement, mais le robot est bien meilleur avec. Un Pi tourne sous Linux, ce qui signifie que votre boucle moteur est ordonnancée avec tout le reste et sera parfois en retard de millisecondes. C'est invisible pour la vision et fatal pour un PID de roue. Découper le robot — Pi pour la perception et les décisions, microcontrôleur pour les boucles qui ne doivent pas trembler — est l'architecture standard pour une raison, et c'est exactement la découpe qu'encourage ROS 2 de toute façon.
Pourquoi un marqueur ArUco plutôt que détecter un vrai objet ?
Parce que le marqueur donne une pose 6-DOF complète depuis une image sans données d'entraînement ni ambiguïté sur l'objet trouvé. Détecter une chaise dit à peu près où est une chaise ; détecter une étiquette ArUco donne sa position et son orientation en mètres, ce qu'exige vraiment un contrôleur. C'est aussi le point de départ honnête — les vraies stations d'accostage, les robots d'entrepôt et les plateformes d'atterrissage de drones utilisent des marqueurs fiduciels pour la même raison.
Pourquoi l'orientation du marqueur bascule-t-elle ?
C'est l'ambiguïté de pose, et c'est une propriété de la géométrie plutôt qu'un bug de votre code. Un carré plat vu presque de face a deux orientations 3D qui se projettent sur presque les mêmes pixels, donc de minuscules bruits font basculer le solveur entre elles. La distance reste stable pendant que la normale estimée saute. Utilisez un marqueur physiquement plus grand, approchez légèrement hors axe où les deux solutions se séparent, ou passez à un plateau ChArUco ou plusieurs marqueurs sur le quai — qui donnent tous plus de géométrie au solveur pour se contredire.
Quelle est la précision de l'accostage ?
Avec une caméra calibrée et un marqueur mesuré au millimètre, un ou deux centimètres à un demi-mètre de recul est réaliste. Les erreurs qui dominent ne sont pas celles attendues : une taille de marqueur entrée fausse met à l'échelle chaque estimation de distance proportionnellement, et la latence du pipeline caméra signifie que la pose asservie décrit où était le marqueur il y a 50 à 100 millisecondes. Ralentir sur les 30 derniers centimètres supprime l'essentiel du second problème gratuitement.
Puis-je faire cela sur un Raspberry Pi Zero ?
Pour ce projet, non — pas confortablement. Un Zero 2 W peut exécuter ROS 2 et décoder un flux caméra, mais la détection ArUco à cadence utile par-dessus ne laisse rien derrière, et construire un espace de travail dessus est pénible. Utilisez un Pi 4 avec 4 Go ou un Pi 5. Le Zero est une bonne carte pour un robot dont le Pi ne fait que relayer des commandes.