Feuille de route
État au 2026-09-12, et ce qui reste à faire. Cette page existe pour que rien ne se perde entre deux séances : elle est versionnée, contrairement à un historique de terminal.
Note
Nomenclature. La carte électronique s’appelle le ratbot_controller,
plus « la STM32 ». Le nom du microcontrôleur est un détail d’implémentation ;
le rôle, lui, est stable. Le nœud ROS suit : /ratbot_N/ratbot_controller
(anciennement ratbot_stm32, renommé le 2026-09-11).
Ce qui fonctionne
Sous-système |
État |
|---|---|
Lien micro-ROS |
UART5 à 3 Mbaud, DMA, exécution depuis la flash QSPI externe avec les deux caches actifs |
Traction dynamixel |
deux AX-18A (gauche ID 14, droite ID 10) sur le connecteur du groupe 2, mode roue, asservissement PI avec terme direct et gain de freinage, rampe à 1 m/s², watchdog 500 ms. L’estimateur reconstruit la position malgré les 60° aveugles du capteur — voir Traction : estimateur de roue et odométrie |
Arrêt d’urgence |
contact matériel, verrou logiciel, réarmement par service ou par
5 appuis sur SW1, sans ROS. Champignon 1NC à accrochage sur les
trois robots depuis le 2026-10-27 : sécurité positive, une coupure du
câble arrête le robot ( |
Capteurs |
température TMP102, batterie |
Voyant et LED |
RGB avec PWM logiciel sur le bleu, 4 LED de façade |
Écran OLED |
SSD1309, 6 expressions, animation de repos autonome |
Buzzer |
15 mélodies non bloquantes sur le passif, plus les codes de bips comptés ; le buzzer actif est réservé à la sécurité |
Paramètres |
11 paramètres ROS persistés en flash U7, dont |
Centrale inertielle |
LSM6DSOX sur I2C3, gyro et accéléromètre à 104 Hz, LPF1 à 11,5 Hz, biais mesuré au démarrage |
Signalisation |
voyant et sons pilotés par la tâche IHM : bilan de démarrage en codes façon BIOS, priorité danger > panne > pas de Pi > couleur de la Pi. Voir Signaux : couleurs, sons et codes |
Heure |
RTC sur pile, recalée sur le serveur NTP du labo par l’agent, et capable de dépanner une Pi qui démarre sans réseau |
Watchdog |
IWDG1 à 8 s, critère de vie fondé sur |
Journal et boîte noire |
256 événements datés en flash de données, cause du dernier plantage gardée sur pile. Voir Journal de bord et boîte noire |
Diagnostic |
|
Banc de test |
36 vérifications sur PC, qui compilent les vrais fichiers de la carte avec du faux matériel — voir Le banc de test sur PC |
Calibration |
paquet |
Ventilateurs |
deux sorties PWM indépendantes à 200 Hz, réglables à chaud. Un ventilateur 2 fils ne se ralentit pas : il cale dès 95 % |
1. Exploitation quotidienne
Ces points ne sont pas du développement, mais ils coûtent du temps à chaque séance.
Fait : la pile embarquée est un service. ratbot.service, avec
Restart=always, attend l’heure (chronyc waitsync) avant de démarrer, puis
séquence l’agent, la signalisation et la chaîne de commande dans
boot.launch.py. Un agent mort se manifestait par un robot totalement muet —
symptôme trompeur qui envoie chercher la panne ailleurs.
Fait : ROS_DOMAIN_ID=77 est dans /etc/environment, donc présent dans
les shells non interactifs et les unités systemd — précisément là où on en a
besoin.
Adresses fixes : fait pour ratbot-1 (192.168.1.171, 2026-09-11). Les
suivants : sudo ./scripts/ratbot network sur chacun, voir
Bringup.
Ce qui reste côté Pi. L’espace de travail n’y est pas construit et les
paquets de navigation ne sont pas installés : ratbot_status ne tourne donc
pas, et c’est lui qui lit led_states.yaml pour envoyer couleurs et sons à la
carte. Toute la signalisation côté carte est validée sur le robot ; la
moitié Pi n’a jamais tourné. ./scripts/ratbot deps puis build.
Accessoirement : systemd-networkd-wait-online échoue et coûte ~2 min au
démarrage ; la clé GitLab du Pi est une clé de compte utilisateur et non une
clé de déploiement en lecture seule ; nav2_msgs manque, donc explore_lite
ne compile pas sur le Pi.
2. L’heure : le ratbot_controller est la mémoire du temps — fait le 2026-09-11
Note
Tout ce qui suit fonctionne et a été mesuré sur le robot : RTC conservée sur pile à travers une coupure, Pi 44 jours en retard rattrapée depuis la carte, premier échantillon chrony à +0,27 ms du serveur du labo. Le détail d’exploitation est dans Bringup. La section est gardée parce qu’elle explique pourquoi c’est fait comme ça.
Deux pièges découverts en route : le CSS du LSE ne doit jamais être armé sur cette carte (ES0396 §2.2.19 — il efface l’heure à chaque coupure alors que le quartz va très bien), et un saut d’horloge sous un agent vivant rend les entités DDS invisibles, d’où le redémarrage de l’agent après une remise à l’heure.
Le problème. La Raspberry Pi n’a pas d’horloge sauvegardée : elle démarre à une date fausse tant qu’elle n’a pas vu le réseau. Le ratbot_controller, lui, a un RTC sur quartz LSE avec domaine sauvegardé — il garde l’heure même Pi éteinte.
Pourquoi ça compte. Les frames doivent être horodatées avec précision pour être exploitables dans un système multi-robots, où elles sont recoupées avec celles d’autres capteurs et des autres robots. Une horloge fausse ne se voit pas à l’usage : elle se découvre à l’analyse, des heures plus tard, quand les données ne se recalent plus.
Le cycle à mettre en place :
1. la Pi demarre -> demande l'heure au ratbot_controller
2. la Pi se synchronise -> serveur de temps du testbed (.190)
3. periodiquement -> la Pi remet le RTC du controller a l'heure
L’étape 3 est celle qu’on oublie : sans elle, le RTC dérive (~20 ppm sur un quartz LSE, soit quelques secondes par jour) et l’étape 1 repart d’une valeur fausse au prochain démarrage. Une remise à l’heure toutes les quelques minutes suffit largement — la période exacte reste à fixer.
Important
Ne pas confondre avec l’horodatage des messages. Celui-ci passe déjà par
rmw_uros_sync_session() : la carte prend l’heure de l’agent, donc de la
Pi. Tant que la Pi est juste, les messages sont justes.
Le RTC sert à deux choses différentes : amorcer l’horloge de la Pi au démarrage, et garder l’heure quand ROS ne tourne pas. Les deux mécanismes sont complémentaires, pas redondants.
Comment c’est fait. La carte publie status/rtc
(sensor_msgs/TimeReference) ; ratbot-time.service lit ce topic au
démarrage de la Pi, sous l’utilisateur de l’agent, et n’avance l’horloge système
que si la carte a plus de 60 s d’avance. Dans l’autre sens,
rmw_uros_sync_session() toutes les 2 s donne à la carte l’heure de l’agent,
donc du serveur NTP, et la RTC n’est réécrite qu’au-delà d’une seconde
d’écart — la réécrire toutes les deux secondes userait le domaine de sauvegarde
pour rien.
3. Le biais du gyroscope, et ce qu’il faut encore mesurer
Mesure du 2026-09-09, carte et moteurs posés sur la table :
moteurs arretes moyenne -0,00168 ecart-type 0,00074 rad/s
moteurs en rotation moyenne -0,00162 ecart-type 0,00062 rad/s
Warning
Cette mesure ne prouve pas encore que le filtre suffit. Le robot n’étant pas assemblé, les moteurs ne sont pas solidaires du châssis qui porte la carte : il n’existe aucun chemin mécanique pour que leur vibration atteigne le gyroscope. Elle montre seulement qu’il n’y a pas de couplage électrique.
À refaire châssis monté. C’est le seul essai qui dira ce que le LPF à 11,5 Hz apporte réellement.
Elle révèle en revanche autre chose. La moyenne résiduelle, −0,0017 rad/s, vaut 2,3 fois l’écart-type du bruit : c’est le biais qui a dérivé depuis la calibration, faite quelques minutes plus tôt. En cap, cela fait 5,8° par minute.
Autrement dit, la stabilité du biais domine largement le bruit — ce qui confirme après coup le critère de choix du composant. La suite utile n’est donc pas plus de filtrage, mais une recalibration automatique dès que les roues sont à l’arrêt depuis quelques secondes. On dispose déjà des vitesses de roue pour le savoir.
4. Sécurité inertielle : chocs, renversement, patinage
Note
Renversement et blocage : faits le 2026-09-27, validés sur ratbot-1
(App/motion_guard.c, 19 cas au banc). Renversé = plus de 60° pendant
0,5 s ; bloqué = puissance commandée ≥ 40 % et roue sous 0,5 rad/s pendant
1 s. Mode banc par SW2 tenu 3 s ou le service bench_mode
(std_srvs/SetBool), jamais sauvegardé. Documentation utilisateur :
Arrêter et relancer le robot.
Mesures qui ont fixé les réglages :
la centrale est montée à l’envers : à plat, Z = −9,67 m/s². L’axe haut est −Z ; l’avant est Y, le côté X ;
la puissance ne distingue pas la boîte du mur : à vide, 57 à 69 % à 6-7,6 rad/s. C’est la vitesse qui les sépare ;
une roue freinée ne gagne que 5 % de puissance par seconde : à 70 %, un blocage lent aurait mis dix secondes à être vu. À 40 %, environ deux ;
le registre
PRESENT_SPEEDdes AX-18A, lu jusque-là comme « rapport de puissance », rend la vitesse en mode roue — et zéro sur une roue bloquée. La puissance vient désormais de la commande (last_sent).
Patinage, fait le même jour : écart d’au moins 0,35 rad/s (et de la moitié) entre le lacet des roues et celui du gyroscope, pendant 1 s. Roues et gyroscope concordent à 0,03 rad/s près jusqu’à 1,5 rad/s, et en pivot sur une roue.
Mesures contre un mur, par terre : les roues patinent à leur vitesse de
consigne, avec la même puissance commandée et la même charge
(PRESENT_LOAD) qu’en roulant librement. Le robot est léger, ses roues
décrochent avant de forcer. Une poussée droite contre un mur reste donc
invisible : seul un patinage qui fait tourner les roues différemment se
voit. Pas de pare-chocs prévu (décidé le 2026-09-27) ; piste restante sans
matériel : Nav2 Collision Monitor sur le lidar, côté Pi.
L’orientation de la centrale a été vérifiée de trois façons : poses
statiques, rotation, et force centrifuge en tournant sur place (Y de la
centrale −0,16 m/s² à 1,5 rad/s, dans les deux sens ; X inchangé). L’URDF
la déclarait à l’endroit : l’EKF fusionnait un lacet de signe inverse.
Corrigé (rpy="π 0 −π/2", 45 mm derrière l’axe des roues).
Choc, fait le même jour : sensors.c garde le pic de l’écart
horizontal (X, Y) entre chaque échantillon et la moyenne du bloc précédent
— la moyenne seule effaçait les chocs. Seuil 5 m/s² : la conduite la plus
brusque culmine à 2,2 m/s² (mesuré) ; aucun choc n’a été provoqué, 5 est
estimé (mur heurté à 0,05 m/s). Le pic de chaque seconde est publié
(shock_peak_cms2) pour le revoir sur le terrain.
Choc à l’arrêt ignoré (2026-10-04) : reposer le robot donnait 5,1 à 9,4 m/s² et l’a coupé sept fois pendant les campagnes UMBmark. Un choc ne compte plus que pendant la conduite (une roue à ≥ 5 % de puissance ou ≥ 0,5 rad/s) ou dans les 500 ms qui suivent.
Zéro du gyroscope remesuré à chaque immobilité (2026-10-04) :
App/gyro_zero.c, 10 cas au banc. Le pilote mesure le biais une fois au
démarrage, à l’aveugle ; un robot touché pendant ces 2 s a gardé
+13,7 °/min de dérive toute la soirée du 03/10. Désormais, roues arrêtées
sans puissance, puis 0,5 s d’attente et 2 s de gyroscope calme (moins de
0,5 °/s d’amplitude sur chaque axe) : la moyenne remplace le résidu. Les
arrêts de 1,5 s d’un carré UMBmark ne suffisent pas : le zéro ne change
jamais au milieu d’un essai.
Échelle du gyroscope (2026-10-04) : réglage gyro_scale par robot
(configuration v4), appliqué au lacet après le zéro. Mesuré par
gyro-scale-run (dix tours sur place contre un repère) : 1,007 sur
ratbot-1. Rejoué sur les campagnes UMBmark, il fait passer la fusion roues +
gyroscope de 4,3 à 2,3 cm d’erreur d’arrivée (roues seules : 4,2). Le zéro
et l’échelle sont publiés dans le bloc imu.
Campagne fusionnée, outil prêt : umbmark-run --odom fused pilote
sur odometry/filtered ; l’EKF est remis à zéro au départ par son
service set_pose (il ne fusionne que des vitesses : remettre à zéro
l’odométrie de la carte ne le ramène pas à l’origine). Vérifié contre un
vrai ekf_node, pas encore sur le robot.
Reste à faire : la chute libre, et la poussée droite contre un mur.
Une fois l’IMU installée, le robot doit s’arrêter tout seul sur :
un choc — pic d’accélération ;
un renversement — le vecteur gravité quitte l’axe vertical durablement ;
un patinage ou un blocage contre un mur.
Cette couche viendra s’ajouter aux trois de Les topics du robot — même principe : elle vit dans le contrôleur, donc elle survit à une panne ROS.
Tip
Le blocage contre un mur est détectable dès aujourd’hui, sans IMU.
On lit déjà les deux grandeurs nécessaires : le rapport de puissance réellement appliqué par le servo, et la vitesse mesurée de la roue. Une puissance au plafond avec une vitesse quasi nulle est un blocage — c’est d’ailleurs ce qui fait chauffer et déclencher la protection thermique des AX-18A.
Le patinage, lui, demande vraiment l’IMU : les roues tournent normalement, c’est le robot qui n’avance pas, et seule une mesure extérieure au moteur peut le dire.
5. Finir l’écran
ratbot_msgs/ScreenCommand existe et ses tailles sont bornées — il ne manque
que de l’ajouter aux extra_packages de la bibliothèque micro-ROS et de
régénérer celle-ci.
Ensuite screen/command dans le firmware, avec ses quatre modes : repos,
expression, message, menu. C’est ce qui permet d’afficher du texte, donc les
alertes lisibles et le menu embarqué.
Note
ScreenCommand désigne les expressions par face_id (0..5), la galerie
du firmware les désigne par leur nom. Il faudra figer l’ordre des images pour
que les deux coïncident, ou publier la correspondance.
6. L’odométrie
Les deux moteurs sont en place — gauche ID 14, droite ID 10 — et la
cinématique différentielle est validée : une consigne angular.z de 1 rad/s
donne bien −2,74 et +2,89 rad/s aux deux roues, pour −2,80 / +2,80 attendus.
Note
Déclarer un moteur ne demande aucune recompilation : un
ros2 param set dxl_id_right 10, écrit en flash U7, relu au démarrage.
Warning
Les deux identifiants ont été échangés le 2026-09-24. Une consigne à gauche faisait tourner à droite, et l’odométrie voyait chaque dérive du côté opposé — ce qui donnait une trajectoire cohérente en apparence, mais symétrique de la vraie. Corrigé en remettant les ID dans le bon sens, pas en inversant les signes : l’inversion des signes, tentée d’abord, était la mauvaise réponse à la bonne observation.
base/odom et reset_odometry sont faits. L’intégration se fait sur
les positions de roue par la méthode du point milieu, et la vitesse rapportée
colle à la consigne :
consigne lineaire 0.060 m/s -> mesure 0.0598 / 0.0606 < 1 %
consigne angulaire 1.000 rad/s -> mesure 0.9992 / 0.9998 < 0,1 %
La traversée du secteur aveugle reste faite à l’estime, dans le driver : la position déroulée qu’il reconstruit est déjà la meilleure estimation disponible, et intégrer la vitesse par-dessus ajouterait une seconde source de dérive sans rien apporter.
La pose est validée au sol depuis le 2026-09-24 : distance parcourue à
0,1–0,35 %, rotation continue à 0,5 %, et un carré de 4 m qui se referme à 1 cm
de ce que croyait le robot. Il a fallu pour cela corriger quatre défauts, dont
deux dans le secteur aveugle et un dans la QoS de cmd_vel — voir
Traction : estimateur de roue et odométrie et Communication avec la carte STM32.
Reste :
La campagne UMBmark, cinq carrés dans chaque sens, pour séparer l’erreur de diamètre des roues de celle d’entraxe et les corriger. L’outillage est prêt (
ratbot_calibration), la mesure au sol reste à faire. Puis une seconde campagne, sans recalculer, pour prouver que l’erreur a baissé.L’écart entre roues, mesuré à ~4 % : la gauche tourne 1,8 % sous la consigne, la droite 2,5 % au-dessus. Chaque roue ayant sa propre boucle, ce n’est pas la géométrie mais de la friction ou de la dispersion entre servos. C’est distinct de l’écart de diamètre que corrige UMBmark, et les deux se cumulent.
La cadence. 27 Hz mesurés à la source pour 30 visés. Ce n’est pas la Pi qui perd des messages : c’est le coût d’un message de 750 octets à travers
cubemx_transport_writeet sonosDelay(1), le même plafond que celui relevé le 2026-09-06.
7. Décisions en suspens
Fait le 2026-09-11 : le nœud ratbot_stm32 s’appelle désormais
ratbot_controller. Les paramètres persistants, stockés en flash, ne
dépendent pas du nom du nœud : rien n’a été perdu.
Le nommage ``cmd_vel`` / ``cmd_vel_safe``. Inverser ferait du chemin par
défaut le chemin dangereux : un nœud publiant naïvement sur cmd_vel
court-circuiterait l’arbitrage, le limiteur et le garde-barrière. D’où le refus
d’inverser — mais c’est un choix de contrat, pas une fatalité.
La géométrie vit en double, dans la flash du contrôleur et dans l’URDF. Les faire diverger fausserait silencieusement soit les commandes, soit la simulation. Le plus propre serait que le Pi lise la géométrie depuis les paramètres du contrôleur.
8. Optimiser la boucle : le cache de données
La tâche micro-ROS tourne à 32,5 Hz, pas 100. Le profilage au compteur de cycles du cœur donne la répartition :
base 16 071 us odom (750 o) + transactions dynamixel
sensors 8 912 us IMU (330 o) + lecture I2C
executor 3 152 us
diag 1 607 us
autres < 1 000 us
Deux corrections ont déjà été appliquées : 3 Mbaud au lieu de 1 (le diviseur
tombe juste des deux côtés — 60/20 sur le STM32, 48/16 sur le PL011 du Pi, qui
est son maximum) et une attente serrée dans le transport à la place d’un
osDelay(1) qui arrondissait chaque tour à la milliseconde. Ensemble :
21,0 → 32,5 Hz.
Fait. Le cache de données est maintenant actif, avec un MPU_Config
écrit à la main : QSPI en écriture immédiate, AXI SRAM en écriture différée, et
8 Kio non cacheables à 0x30000000 pour les tampons DMA. La boucle micro-ROS est
passée de 32,5 Hz à environ 130, et l’odométrie tient ses 50 Hz, calées sur les
pas d’asservissement.
Ce qui suit reste pour mémoire — c’est le raisonnement qui a conduit là, et les pièges valent encore pour toute nouvelle zone DMA :
avant : SCB->CCR = 0x00060200 bit 17 I-cache = 1 bit 16 D-cache = 0
Le cache d’instructions, lui, est actif — inutile donc de déplacer du code en ITCM, il est déjà servi depuis le cache. C’est le côté données qui coûte : sérialiser 750 octets sans cache, ce sont des centaines d’accès à pleine latence en AXI SRAM.
Warning
Ce n’est pas un interrupteur. Avec le D-cache actif, tout tampon DMA doit être traité : sinon le DMA lit des données restées en cache, ou écrit des données que le processeur ne voit pas. C’est la famille de pannes silencieuses qui a déjà coûté cher trois fois sur ce projet.
Deux voies : marquer RAM_D2 non-cacheable par le MPU — mais le
MPU_Config généré est justement désactivé, sa région de 4 Go en
NO_ACCESS empêchant l’exécution depuis la QSPI — ou ajouter les opérations
de maintenance à chaque transfert.
La raison d’origine de le désactiver a disparu : les structures étaient relues
à chaud au ST-LINK, ce que /diagnostics a remplacé.
9. En attente de matériel
Un ventilateur 4 fils. Le 2 fils actuel ne se ralentit pas : son électronique de commutation est alimentée par les deux mêmes fils que le moteur, et décroche dès 15 % de temps mort. Mesuré le 2026-09-26 : il tourne à 100 %, cale à 95 %, et même une montée en régime complète de six secondes avant de redescendre à 70 % ne le maintient pas. Un 4 fils a une entrée PWM dédiée et se réglerait de 20 à 100 %.
Les trois autres robots, attendus vers le 2026-10-10. Tout ce qui a été outillé ce mois-ci — configuration sauvegardable, calibration, point d’entrée unique piloté par le nom d’hôte — vise à ce que les mettre en service ne soit qu’une répétition.
Les moteurs à courant continu et leurs encodeurs ne concernent pas RatBot.
La carte est générique et les porte pour un autre robot ; motor_dc.c et
encoder.c restent des squelettes tant qu’aucun projet ne les demande.
10. Le capteur de distance avant (ToF)
Le lidar balaie à ~20 cm du sol et ne voit pas le pied des tables à pied central. Un VL53L5CX (8 × 8 zones) à l’avant, à 10 cm du sol, sur J4 (I2C2), décidé le 2026-10-14. Contrat et choix : Les topics du robot.
Le contrat et la simulation — fait le 2026-10-14. Image 8 × 8 en millimètres, capteur imité dans Gazebo, conversion en nuage avec reconnaissance du sol, couche voxels dans Nav2, décor
tables. En chemin : les cartes de coûts de Nav2 écoutaient…/local_costmap/scanau lieu de/ratbot_N/scanet n’avaient jamais reçu le lidar.La carte publie l’image — fait et mesuré le 2026-10-14. Tâche
tofà 15 Hz, image d’essai (tof_frame_fake: 3 m et plus, hors de ce que Nav2 marque),ros_tofqui la publie, bloctofdes diagnostics en WARN. Conversion des statuts du pilote et retournements prêts et testés au banc (tof_frame.c). Mesuré sur ratbot-1, même code avec et sans ToF : la boucle passe de 27,4 à 23,2 Hz, l’odométrie de 27,3 à 23,2 Hz, les IMU non publiées de 100 à 215 par minute ; ~7 ms de processeur par image publiée, un coût fixe par publication plus que lié à la taille. La boucle tournait déjà à 27 Hz sans le ToF, contre 132 Hz après l’activation du cache. Cause trouvée le jour même : le code de publication relu depuis la QSPI. Placé en ITCM, la boucle tourne à 175 Hz avec l’image ToF, l’odométrie à 50 Hz sans pas sauté (Architecture de l’application firmware, « Le chemin de publication en ITCM »).Le capteur — pilote écrit le 2026-10-20, capteur pas encore vu. Pilote ST ULD 2.0.1 (firmware MM1.8, BSD-3) recopié tel quel dans
App/drivers/vl53l5cx/, plateforme à nous sur I2C2 ; tâchetofseule propriétaire d’I2C2, TMP102 compris (vérifié sur la carte : 24,25 °C, 0 erreur) ; 8 × 8, 15 Hz, continu, cible la plus proche ; retentative toutes les 5 s ; balayage du bus dans le diagnostic ; banctest_tof.c. Le module de ratbot-1 ne répond à aucune adresse (seul 0x48 répond) : alimentation à mesurer, ou module à essayer sur la Pi (i2cdetect -y 1). Vu le même jour : la sérigraphie du connecteur était inversée. 15,2 images/s. Restent : l’orientation vérifiée (main devant un coin). I2C2 en DMA le même jour : la tâche ToF passe de 22 à 6,4 % du processeur, la boucle micro-ROS de 11,3 à ~5 ms ; 0 repli, 0 erreur sur 1 400 images ; puce stable à 65-66 °C en mode continu, et 57-58 °C une fois la pompe de charge de l’émetteur coupée, sans rien perdre de près (mur à 30 cm : 302 mm, bruit 1,2 mm au lieu de 1,5). Piste si besoin : demander « image prête ? » moins souvent (100 fois/s pour 15 images, en attente active).Ce qui était prévu : I2C2 tourne déjà à 400 kHz (
firmware-fixes), le minimum de la fiche technique (400 kHz à 1 MHz) ; tâche dédiée à basse priorité, seule propriétaire d’I2C2, pour que la lecture de l’IMU n’attende jamais ; pilote ST (envoi de son micrologiciel de 86 Ko au démarrage, ~2 s) ; image réduite (distance et statut seulement). LPn n’est pas câblé : pas de remise à zéro matérielle, la carte doit continuer sans le capteur et le signaler. Puis, le capteur monté : sa pose mesurée dans l’URDF, et le mode de distance (radial ou perpendiculaire) tranché devant un mur.Hauteur du capteur, essais en simulation du 2026-10-14. 4, 5, 7 et 10 cm évitent les pieds de table aussi bien ; plus bas, en revanche, le sol reconnu tolère moins les irrégularités (tolérance relative : 5 mm de seuil font 12 % à 4 cm). Prévu à 10 cm. Ce qui faisait la différence était côté Nav2 : marge de 25 cm au lieu de 15 (socle en disque évité à 38 cm au lieu de 20-28).
12. Conduire au clavier, apprendre un trajet — fait le 2026-10-15
ratbot key N (clavier, même voie que la manette) et ratbot route
record|follow|list : on conduit le robot pendant que sa pose est notée,
puis Nav2 refait le trajet, par points ou sur la ligne exacte. Essayé en
simulation (écart moyen 6 et 3 cm). À essayer sur le vrai robot. Détails :
Carte et localisation, « Trajets appris ».
14. Plusieurs robots : cartes privées par défaut, partage en option
Le constat (2026-10-19, en préparant une démonstration). Les cartes ne suivent pas une règle, mais trois décisions prises à des moments différents :
ratbot slam Ndonne à chaque robot sa carte,/ratbot_N/map;ratbot nav N CARTEcharge une carte commune,/map, sur laquelle toute la flotte se localise. Lancernavpour un second robot avec une autre carte démarrerait un second serveur commun, en conflit avec le premier ;ratbot explore N, posé sur la navigation, écrit donc sur la carte commune : on n’explore qu’avec un robot à la fois.
D’où deux formes de map save (avec et sans numéro), qu’il faut connaître
pour s’en servir. Le paquet de fusion multirobot_map_merge est dans le
dépôt (m-explore-ros2), mais écarté de la compilation (COLCON_IGNORE,
voir Carte et localisation).
Le principe retenu : privé par défaut, partage explicite. Deux usages de recherche, servis par le même code :
des agents indépendants : chaque robot n’a que sa carte et ce qu’il a vu lui-même. Ce qu’un robot sait d’un autre passe par une communication explicite, qui est un acte : que dire, à qui, quand, et que faire d’un message perdu ou d’une information périmée (un robot croit une porte ouverte parce qu’il l’a vue ouverte il y a une heure). C’est le terrain de la planification épistémique ;
une équipe qui coopère : les cartes sont fusionnées en une carte commune, et les robots se répartissent le travail.
Une carte partagée par défaut ruinerait le premier usage, en silence : une expérience sur des agents indépendants dont les cartes fuient l’une dans l’autre ne mesure plus ce qu’elle croit mesurer.
Ce que ça donne :
chaque robot a toujours sa propre carte, dans son espace de noms, avec
slam,exploreetnav:./scripts/ratbot nav 1 salon # le robot 1 sur SA copie de salon ./scripts/ratbot nav 2 salon # le robot 2 sur la sienne ./scripts/ratbot nav 3 cuisine # le robot 3 sur une autre carte
Le serveur de carte et AMCL passent dans
/ratbot_N; la carte commune/mapne sert plus que lorsqu’on demande le partage ;le partage est une option,
--shared:./scripts/ratbot explore 1 2 # deux agents indépendants ./scripts/ratbot explore 1 2 --shared # une équipe, carte fusionnée ./scripts/ratbot nav 1 2 3 salon --shared
Avec
--shared,map_mergefusionne en continu les cartes des robots dans/map, et chaqueexplore_litechoisit ses frontières sur la carte fusionnée, pour que deux robots n’explorent pas la même zone. Les positions de départ sont connues en simulation ; sur le vrai parc, elles devront l’être aussi, ou être estimées par la fusion. Sans--shared, deux robots peuvent explorer la même pièce en double : c’est voulu ;la provenance est écrite dans la carte, et non dans son nom. Une carte décrit un lieu, pas un robot :
salon_1deviendrait faux dès qu’on la partage.map saveajoute au.yaml:robot: 1 method: explore # slam, explore ou merge merged_from: [] # [1, 2, 3] pour une carte fusionnée date: 2026-10-19T20:33
et
map listl’affiche (salon robot 1, explore, 2026-10-19), commeroute listle fait déjà pour les trajets ;une seule règle pour enregistrer :
map save NOMenregistre « la » carte, sans numéro, dès qu’elle est unique :ce qui tourne
map save salonun seul robot (
slam 1,explore 1)la carte de ce robot
plusieurs robots,
--sharedla carte fusionnée
plusieurs robots, indépendants
demande laquelle :
map save 1 salon, ou--all, qui les enregistre toutes (le nom porte alors le robot, pour éviter le conflit)rien
le dit
Le numéro ne sert que pour vouloir volontairement un morceau précis, par exemple la carte d’un robot quand la fusion se passe mal. Une carte existante n’est jamais écrasée sans confirmation, comme aujourd’hui ;
un canal de communication entre robots, fourni ; son contenu, au chercheur. RatBot donne une interface standard pour qu’un robot envoie un message à un autre (ou à tous), datée et attribuée, que l’on peut limiter en portée ou en débit, ou dont on peut simuler des pertes pour étudier la robustesse. Ce qui est dit, et quand, reste à la charge de chaque projet : ce n’est pas à la plateforme de faire ce travail ;
une épreuve au banc à 2 et 3 robots, dans les deux modes : temps pour couvrir le décor, qualité de la carte fusionnée contre le plan, aucun contact entre robots, et, en mode indépendant, aucune information qui passe d’une carte à l’autre.
En simulation d’abord, avant l’arrivée des robots 2 et 3. C’est aussi la matière de la section multi-robots de l’article.