La découverte DDS : qui voit qui
Important
C’est la couche à laquelle personne ne pense, jusqu’au jour où elle lâche. Quand elle tombe, aucun message d’erreur n’apparaît : les nœuds démarrent, publient, et les compteurs restent à zéro à l’autre bout. On soupçonne alors la QoS, le firmware, le matériel — et on cherche des heures.
La page Bringup, section Réseau, traite de l’adressage. Celle-ci traite de la découverte et du transport : comment deux nœuds apprennent l’existence l’un de l’autre, puis par où passent leurs données.
Le principe
ROS 2 n’a pas d’annuaire central. Chaque participant s’annonce et écoute les annonces des autres. Deux nœuds qui se découvrent négocient ensuite leurs QoS, et seulement alors les messages circulent.
Quatre faits suffisent à comprendre tout ce qui suit :
Le transport dépend de la topologie. Fast DDS, l’implémentation par défaut sous Humble, fait passer les données entre deux processus d’une même machine par la mémoire partagée (
/dev/shm), et entre deux machines par l’UDP. Quand la mémoire partagée est utilisable, elle est prioritaire et l’UDP n’est pas utilisé pour ce couple.Les segments de mémoire partagée s’ouvrent par leur NOM, des fichiers
fastrtps_*dans/dev/shm. Un processus déjà en marche garde ses projections même si le fichier disparaît ; un nouvel appariement, lui, ne trouve plus rien.Un participant lit l’état des interfaces réseau à sa création, et ne le relit pas. Ce qui change après coup ne l’atteint pas.
Rien ne signale un échec d’appariement ni de livraison.
ros2 topic infocontinue d’afficher les deux extrémités, en QoS compatibles.
La panne de septembre 2026 : logind effaçait la mémoire partagée
Le symptôme
Premier essai du pilotage à la manette, le 2026-09-26 : le robot ne bougeait pas, et le voyant restait éteint.
mesure |
ce qu’on en concluait |
|---|---|
la chaîne de commande sur la Pi publie 2086 → 401 → 402 → 394
messages, jusqu’à |
la chaîne ROS calcule juste |
|
la carte ne reçoit rien |
la même consigne publiée depuis le PC : le compteur monte |
la carte reçoit très bien d’ailleurs |
|
l’appariement est bon |
|
le matériel est sain |
Tout avait l’air juste, et rien n’arrivait. Une relance de la pile réparait tout — jusqu’au démarrage suivant.
La cause
Par défaut, systemd-logind applique RemoveIPC=yes : dès que la
dernière session d’un utilisateur se ferme, il efface tous ses objets de
communication inter-processus, dont la mémoire partagée de /dev/shm. Seuls les
comptes système (uid < 1000) sont épargnés.
Or :
la pile tourne en service sous l’utilisateur
ratbot, uid 1000 — concerné ;ce compte n’a pas de session persistante (
Linger=no) ;chaque connexion SSH ouvre puis ferme une session
ratbot.
Chaque déconnexion SSH effaçait donc les segments de la pile en marche. Par les faits n° 1 et 2 : les couples déjà établis continuaient de marcher sur leurs projections, mais tout appariement local fait ensuite cherchait des segments disparus et ne délivrait rien. Un PC distant passait par l’UDP et n’était pas touché.
La preuve
Pendant la panne, les segments étaient encore projetés par chacun des
processus de la pile, mais marqués effacés dans /proc/<pid>/maps — et
/dev/shm était vide :
micro_ros_agent /dev/shm/fastrtps_port26661 (deleted)
status_manager /dev/shm/fastrtps_port26663 (deleted)
cmd_vel_gate /dev/shm/fastrtps_port26665 (deleted)
Le journal de logind montrait des sessions ratbot fermées juste avant la
dernière modification de /dev/shm.
Puis l’expérience à une seule variable, le 2026-09-27 : même démarrage, serveur de temps allumé, aucune relance de la pile.
|
|
voyant |
|
|---|---|---|---|
|
vide, segments effacés |
éteint |
0 |
|
plein, aucun effacé |
bleu |
223 |
Et avec RemoveIPC=no, une vingtaine de sessions SSH ouvertes et fermées
pendant le démarrage n’ont rien effacé.
Le correctif
deploy/logind-ratbot.conf, installé dans
/etc/systemd/logind.conf.d/ratbot.conf par ./scripts/ratbot services :
[Login]
RemoveIPC=no
logind ne relit sa configuration qu’à son démarrage : il faut redémarrer la
Pi après l’installation. Le script le rappelle, et ne relance pas logind
lui-même — ça peut fermer les sessions ouvertes.
Deux autres correctifs existaient, écartés : loginctl enable-linger ratbot
marche mais par effet de bord, et un compte système pour la pile obligerait à
déplacer le dépôt, les droits sur le port série et le workspace.
Pourquoi tout avait l’air contradictoire
Le déclencheur est une déconnexion SSH, pas un événement du robot. D’où des résultats qui semblaient se contredire d’un essai à l’autre :
observation |
explication |
|---|---|
le PC délivrait toujours |
il passe par l’UDP, pas par |
une relance de la pile réparait |
elle recrée des segments neufs, et les couples s’établissent avant la prochaine déconnexion |
ça marchait quand le serveur de temps était éteint |
|
deux processus lancés à la main sur la Pi se voyaient et s’échangeaient des données |
ils créaient leurs segments après l’effacement |
les services restaient invisibles et sourds depuis un shell |
leurs segments à eux avaient été effacés |
l’hypothèse |
le test était faussé : une connexion SSH en arrière-plan était restée ouverte, donc la « dernière session » ne se fermait jamais |
Warning
La leçon de méthode. Un test qui innocente doit reproduire toutes les conditions de la panne. Ici, un terminal oublié ouvert suffisait à empêcher l’effacement — et a coûté une nuit.
Les fausses pistes
Chacune a été écartée par une expérience. À ne pas reproposer sans élément nouveau :
piste |
ce qui la réfute |
|---|---|
la QoS |
depuis le PC, un éditeur fiable et un éditeur best-effort atteignent la
carte ; sur |
l’ordre de démarrage |
|
le saut d’horloge |
serveur de temps allumé, horloge juste avant la pile, un seul démarrage : la panne restait |
le pilotage de bande Wi-Fi |
défaut réel, corrigé côté box — voir plus bas — mais la panne persistait |
le démon |
|
Le drapeau MULTICAST sur lo
lo n’a pas le drapeau MULTICAST par défaut sous Linux.
deploy/ratbot-loopback-multicast.service le pose au démarrage, avant la
pile (fait n° 3).
L’expérience qui l’a fait adopter semblait nette : drapeau posé sans toucher aux
services, et status_manager puis ratbot_controller sont apparus aussitôt
dans ros2 node list lancé sur la Pi.
Note
Son utilité réelle reste à revérifier. Cette expérience a été faite
pendant que logind effaçait la mémoire partagée : la découverte locale
devait alors se rabattre sur l’UDP multicast de la boucle locale, qui a besoin
de ce drapeau. Avec RemoveIPC=no, il est possible qu’il ne serve plus à
rien. Il ne coûte rien, donc on le garde — mais la question est ouverte.
systemctl is-active ratbot-loopback-multicast # doit repondre « active »
ip link show lo | grep -o MULTICAST # doit repondre « MULTICAST »
Le Wi-Fi qui change de radio sous les pieds
Défaut distinct, trouvé le même soir.
La box diffusait le même nom de réseau sur ses radios 2,4 et 5 GHz, et faisait du pilotage de bande (802.11v / MBO) : une quarantaine de secondes après l’association, elle ordonnait à la Pi de changer de point d’accès.
20:47:06 la pile demarre
20:47:19 wlan0: MBO-TRANSITION-REASON reason=9
20:47:19 wlan0: Lost carrier / DHCPv6 lease lost
20:47:23 wlan0: Associated with 92:55:1f:b6:e5:6d <- BSSID different
Par le fait n° 3, un participant né avant ce basculement peut garder des adresses
qui n’existent plus — et Restart=always ne le verrait pas, puisqu’il ne meurt
pas. Ce n’était pas la cause de la panne manette, mais un robot qui change de
radio en pleine manip reste un risque.
Correctif, côté box : séparer les bandes, pour que chaque radio ait son propre nom. Sur la Bbox du labo, l’option s’appelle « Séparer les bandes 2.4, 5 et 6 GHz », et elle a donné :
nom du réseau |
bande |
remarque |
|---|---|---|
|
2,4 GHz |
garde le nom de base : les robots s’y reconnectent sans rien changer |
|
5 GHz |
plus rapide (433 contre 72 Mbit/s mesurés) |
|
6 GHz |
hors de portée d’une Pi 4, qui est en Wi-Fi 5 |
Tip
Avant de séparer les bandes, vérifier quel nom garde la bande de base : si le nom enregistré dans le robot disparaît de toutes les bandes, une Pi sans écran devient injoignable. Ici le nom de base est resté sur le 2,4 GHz — une chance, pas une garantie.
La configuration réseau du robot ne déclare aucune interface Ethernet :
un câble ne le récupérerait pas. Un repli eth0 en DHCP serait un filet de
sécurité utile.
Diagnostiquer
Devant « la Pi publie, la carte ne reçoit rien », dans cet ordre :
# 1. L'arbitre : la carte compte-t-elle les consignes recues ?
ros2 topic echo /diagnostics | grep -A8 traction
# 2. La memoire partagee est-elle encore la ? (sur la Pi)
ls /dev/shm | grep -c fastrtps # 0 avec la pile en marche : suspect
PID=$(pgrep -f 'micro_ros_agent serial' | head -1)
sudo grep -c 'fastrtps.*(deleted)' /proc/$PID/maps # doit valoir 0
# 3. logind efface-t-il encore ?
busctl get-property org.freedesktop.login1 /org/freedesktop/login1 \
org.freedesktop.login1.Manager RemoveIPC # doit valoir « b false »
# 4. Le lien Wi-Fi a-t-il change depuis le demarrage de la pile ?
journalctl -b | grep -iE "MBO-TRANSITION|Lost carrier|Associated with"
Le compteur commands_received du bloc traction est l’arbitre : il
distingue « la consigne n’arrive pas » de « la consigne arrive et le robot ne
bouge pas », deux pannes qui n’ont rien à voir. Pour le lire par programme,
s’abonner en best-effort : un abonné fiable ne reçoit rien de ces éditeurs.
Serveur de découverte : l’option de parc
Fast DDS sait remplacer le multicast par un serveur de découverte : chaque machine s’annonce en unicast à une adresse unique.
# sur la machine hôte (le binaire vient de ros-humble-fastrtps)
fast-discovery-server -i 0 -p 11811
# sur toutes les autres
export ROS_DISCOVERY_SERVER="<adresse de l hote>:11811"
Aucune modification du firmware. La carte parle XRCE-DDS à l’agent par la liaison série et ne fait pas de découverte DDS ; seul l’agent devient client du serveur.
Warning
Ce n’est pas une décision RatBot. Un serveur de découverte est nécessairement commun : un participant qui en devient client ne découvre plus les participants restés en multicast. Le basculement est donc indivisible — il concerne toutes les machines du domaine à la fois.
Or le domaine 77 est partagé avec d’autres machines du labo. Le serveur
relève donc de l’infrastructure commune, et la décision se prend à ce
niveau-là, pas dans RatBot.
RatBot ne doit pas en dépendre. Le robot est intégré par un système hôte ; il ne s’accroche pas à lui. Un RatBot posé sur une table, hors de tout système hôte, doit continuer de fonctionner.
Note
Pourquoi le serveur NTP, lui, reste une dépendance acceptable. RatBot est bien client du serveur de temps du testbed (192.168.1.190), et cela ne change pas. La différence n’est pas l’appartenance de la machine, c’est la façon dont la dépendance tombe :
serveur NTP absent |
serveur de découverte absent |
|
|---|---|---|
conséquence |
la RTC sur pile de la carte garde l’heure, chrony se rattrape au retour |
aucun nœud n’en trouve un autre : plus rien ne fonctionne |
nature |
dégradation progressive |
panne totale |
Une dépendance qui se dégrade proprement est acceptable ; une dépendance dont l’absence arrête tout ne l’est pas. C’est le même critère qui fait que la carte signale sans la Pi, et que le champignon est câblé et non logiciel.
ce qu’on gagne |
ce qu’on paie |
|---|---|
le multicast disparaît du parc entier |
point unique de défaillance pour la découverte seulement : deux nœuds déjà appariés continuent de se parler, mais un robot qui démarre pendant la panne ne trouve personne |
fiable là où le multicast Wi-Fi est bridé par le point d’accès — le problème qui attend un parc de quatre robots |
|
le trafic de découverte cesse d’inonder le réseau |
les outils |