Calibrer l'odométrie ==================== **S'applique à :** :bdg-warning-line:`Robot réel` Votre robot sait en permanence où il se trouve, en comptant ce que font ses roues. C'est l'\ **odométrie**, et c'est sur elle que reposent la cartographie et la navigation. Mais elle se trompe toujours un peu, et **toujours dans le même sens** : cette page vous explique comment mesurer cette erreur, puis la corriger. Comptez **une heure** pour une campagne complète. Pourquoi c'est nécessaire ------------------------- Deux défauts se glissent dans tout robot à deux roues motrices, quelle que soit la qualité de la fabrication. **Les roues n'ont pas exactement le même diamètre.** Même modèle, même série : un pneu légèrement plus écrasé, un moyeu un peu décentré, et l'écart est de l'ordre du pour cent. Le robot dérive alors en ligne droite **sans le savoir**. **L'entraxe réel n'est pas la cote du plan.** La distance entre les points de contact au sol dépend de la largeur de la gomme et de son écrasement. Toutes les rotations tombent légèrement à côté. Ces deux erreurs sont **systématiques** : elles se répètent à l'identique, donc elles s'accumulent, et donc elles se corrigent. C'est ce que fait la méthode **UMBmark** (Borenstein et Feng, 1996). .. note:: La méthode ne corrige **pas** les erreurs accidentelles — un patinage, une bosse, un obstacle. Celles-là se lisent dans la dispersion des essais, pas dans leur moyenne. Le principe ----------- On demande au robot de tracer un **carré** et de revenir à son point de départ. Il est piloté **sur sa propre odométrie** : il croit sincèrement refermer un carré parfait. Vous, vous mesurez où il est **vraiment** arrivé. L'écart entre sa croyance et votre mètre ruban, c'est la mesure. .. important:: Il faut faire le carré dans **les deux sens**. Les deux erreurs s'additionnent dans un sens et se compensent dans l'autre : avec un seul sens, on constate qu'il y a un problème, mais on ne peut pas savoir lequel des deux. Ce qu'il vous faut ------------------ - **2 m × 2 m** de sol dégagé, plat et uniforme ; - un **L** collé au sol : son coin est l'origine, une branche donne la direction de départ. Du ruban de masquage suffit ; - un **mètre ruban** ; - de quoi marquer des positions au sol (gommettes, ruban) ; - une **batterie chargée** : une campagne complète la sollicite une heure. .. tip:: Choisissez un sol représentatif de celui où le robot travaillera. Une calibration faite sur carrelage ne vaut pas tout à fait sur moquette. Le repère de mesure ------------------- C'est le point sur lequel on se trompe le plus souvent. Prenez trente secondes. .. tikz:: Le repère de mesure. L'origine est le point du sol où le robot démarre. :libs: arrows.meta \draw[-{Stealth[length=3mm]},thick] (0,-2.2) -- (0,2.6) node[above] {$+X$}; \draw[-{Stealth[length=3mm]},thick] (3,0) -- (-3.4,0) node[left] {$+Y$}; \node[below right] at (0.15,-2.0) {$-X$}; \node[below] at (2.6,-0.1) {$-Y$}; \node[align=center,font=\small] at (0,2.15) {droit devant,\\ au départ}; \node[align=center,font=\small,anchor=east] at (-2.0,0.45) {gauche\\ du robot}; \node[align=center,font=\small,anchor=west] at (2.0,0.45) {droite\\ du robot}; \fill (0,0) circle (3pt); \node[below left,font=\bfseries\small] at (-0.1,-0.15) {DÉPART}; - L'origine est le point du sol où le robot **démarre**. - **+X** est la direction dans laquelle il regarde au départ. - **+Y** est à sa **gauche**. - Tout se mesure en **centimètres**. Mesurez toujours **le même point du robot** — le milieu de l'essieu est le plus commode. Marquez-le d'un trait si besoin. .. note:: L'outil redessine ce schéma avant chaque saisie, puis vous **relit ce qu'il a compris** : « le robot a fini 6,5 cm en avant et 11 cm à gauche ». Vérifiez cette phrase-là plutôt que les chiffres : une inversion se voit immédiatement. Où poser le robot ----------------- Le carré se déplie **du côté où le robot tourne**. C'est contre-intuitif une fois sur deux, et poser le robot au mauvais coin l'envoie dans le mur. Le **cap de départ est le même** dans les deux sens. Seul le coin change. .. list-table:: :header-rows: 1 :widths: 20 20 30 30 * - Sens - Il tourne - Le carré occupe - Départ au coin * - Antihoraire (CCW) - à gauche - nord-**ouest** - **sud-est** * - Horaire (CW) - à droite - nord-**est** - **sud-ouest** .. tikz:: Le carré se déplie du côté où le robot tourne. Le cap de départ est le même dans les deux sens ; seul le coin change. :libs: arrows.meta \tikzset{ cote/.style={very thick, -{Stealth[length=2.5mm]}}, axe/.style={gray, -{Stealth[length=2mm]}}, } % ---------- ANTIHORAIRE : le carre part vers +Y, a gauche ---------- \begin{scope}[xshift=-3.2cm] \node[font=\bfseries\small,align=center] at (-1.5,4.1) {ANTIHORAIRE\\ \normalfont\footnotesize il tourne à gauche}; \draw[axe] (0,-0.5) -- (0,3.4) node[right,font=\footnotesize] {$+X$}; \draw[axe] (0.2,-0.5) -- (-3.4,-0.5) node[left,font=\footnotesize] {$+Y$}; \draw[cote] (0,0) -- (0,3); \draw[cote] (0,3) -- (-3,3); \draw[cote] (-3,3) -- (-3,0); \draw[cote] (-3,0) -- (0,0); \fill (0,0) circle (3pt); \node[below right,font=\bfseries\footnotesize,align=left] at (0.05,-0.1) {DÉPART\\ \normalfont coin sud-est}; \node[font=\footnotesize,align=center,gray] at (-1.5,1.5) {le carré se déplie\\ vers $+Y$}; \end{scope} % ---------- HORAIRE : le carre part vers -Y, a droite ---------- \begin{scope}[xshift=3.2cm] \node[font=\bfseries\small,align=center] at (1.5,4.1) {HORAIRE\\ \normalfont\footnotesize il tourne à droite}; \draw[axe] (0,-0.5) -- (0,3.4) node[left,font=\footnotesize] {$+X$}; \draw[axe] (-0.2,-0.5) -- (3.4,-0.5) node[right,font=\footnotesize] {$-Y$}; \draw[cote] (0,0) -- (0,3); \draw[cote] (0,3) -- (3,3); \draw[cote] (3,3) -- (3,0); \draw[cote] (3,0) -- (0,0); \fill (0,0) circle (3pt); \node[below left,font=\bfseries\footnotesize,align=right] at (-0.05,-0.1) {DÉPART\\ \normalfont coin sud-ouest}; \node[font=\footnotesize,align=center,gray] at (1.5,1.5) {le carré se déplie\\ vers $-Y$}; \end{scope} Autrement dit : pour passer du sens antihoraire au sens horaire, vous déplacez le L **d'une longueur de côté**, sans changer l'orientation. Quelle taille de carré ~~~~~~~~~~~~~~~~~~~~~~ Plus le carré est grand, plus les erreurs systématiques ressortent du bruit de votre mètre ruban : elles croissent avec la distance parcourue, tandis que votre précision de mesure, elle, reste la même. Borenstein utilisait 4 m. Mais le robot doit tenir dans la pièce **avec sa dérive** — c'est justement ce qu'on cherche à mesurer, et elle peut atteindre une quinzaine de centimètres au pire coin. .. list-table:: :header-rows: 1 :widths: 20 40 40 * - Côté - Place réellement occupée - Dans 2 m × 2 m * - 1,0 m - ≈ 1,55 m - large * - **1,2 m** - **≈ 1,75 m** - **confortable — valeur recommandée** * - 1,5 m - ≈ 2,05 m - ne passe pas La place occupée ajoute au côté l'encombrement du robot (environ 12 cm de son centre à son bord) et la dérive attendue, de part et d'autre. .. important:: **Un robot garde toujours la même taille de carré.** L'erreur mesurée grandit avec le côté : deux mesures de côtés différents ne se comparent pas. La calibration guidée l'impose : la **première** mesure d'un robot fixe son côté (1,2 m par défaut), et toutes les suivantes le reprennent, sans choix possible. Sur ratbot-1, c'est **1,3 m**, le côté de ses mesures d'octobre 2026. La façon simple : la campagne guidée ------------------------------------ Une fois le sol préparé (le L collé, voir **Où poser le robot**), depuis la racine du dépôt : .. code-block:: bash ./scripts/ratbot-calibrate 1 umbmark Chaque lancement fait **une mesure**, avec les réglages en place dans la carte : #. le script vérifie que le robot répond et que **rien d'autre ne le pilote** : il refuse de démarrer si une navigation, une exploration ou une cartographie tourne pour ce robot, car leurs ordres se mêleraient aux siens. Il **sauvegarde les réglages** de la carte, et demande le commit du firmware flashé : il propose le dernier commit du firmware du dépôt, que l'on accepte d'un Entrée, mais vous seul savez ce qui est réellement flashé (voir **Préparer la session**) ; #. il enchaîne **cinq carrés antihoraires**, au côté du robot (voir **Quelle taille de carré**), puis vous dit de déplacer le L, puis **cinq carrés horaires**. Chaque carré attend un « o », puis votre mesure au sol ; un carré interrompu ou mal mesuré est refait ; #. il analyse la mesure, affiche **E_max,syst**, la compare aux mesures précédentes du robot, et propose trois réglages. Si l'écriture réussit mais pas la sauvegarde qui suit, il le dit, et la correction reste notée. Il ne les écrit dans la carte **qu'après votre accord**, et sauvegarde alors les nouveaux réglages dans ``cahier_de_labo/config/``. **Calibrer, c'est faire deux mesures** : la première, puis la correction, puis une seconde, avec les nouveaux réglages, qui montre si l'erreur a baissé. Trois mois plus tard, une mesure **sans** correction sert de contrôle : il suffit de répondre « non » à la proposition. Chaque mesure a son propre dossier dans ``cahier_de_labo/campagnes/``, nommé ``DATE_ratbotN_umbmark`` : deux mesures ne se mélangent jamais. Une mesure interrompue **reprend** là où elle s'est arrêtée, même un autre jour : relancez la même commande. Le script montre d'abord ce qui est déjà fait et demande s'il faut la reprendre, puisque rien ne doit avoir changé depuis : sol, roues, réglages. Il redemande aussi si le **firmware** est toujours le même. Si vous répondez non, ou si ses carrés n'ont pas le côté du robot, la mesure est **mise de côté**, avec la raison notée, et une nouvelle commence. Une mesure mise de côté reste dans ``cahier_de_labo/campagnes/`` et apparaît dans ``list`` avec sa raison, mais ne compte plus dans ``stats``. Si l'analyse refuse de conclure (deux firmwares, deux réglages), le script propose de même de la mettre de côté. Pour savoir ce que la fusion avec le gyroscope apporte, la même mesure se fait robot piloté sur l'odométrie fusionnée ; elle ne propose aucun réglage : .. code-block:: bash ./scripts/ratbot-calibrate 1 fusion .. warning:: **Pendant les carrés, le bouton PS de la manette n'arrête pas le robot** : l'outil commande les roues directement. Pour l'arrêter, utilisez le **bouton d'arrêt du robot**. Consulter et décider ~~~~~~~~~~~~~~~~~~~~ Le même script consulte les mesures, **toujours pour un robot donné** : .. list-table:: :header-rows: 1 :widths: 46 54 * - Commande - Effet * - ``./scripts/ratbot-calibrate 1 list`` - les campagnes du robot 1 : mesures, gyroscope, lidar, avec leurs carrés, la date d'écriture de leurs réglages, et la raison de celles qui ont été mises de côté * - ``./scripts/ratbot-calibrate 1 stats`` - ses mesures dans l'ordre, avec **E_max,syst**, l'évolution d'une mesure à l'autre et la date des corrections ; l'échelle du gyroscope * - ``./scripts/ratbot-calibrate 1 show NOM`` - le détail d'une campagne, carré par carré * - ``./scripts/ratbot-calibrate 1 compare NOM`` - **l'IMU corrige-t-elle bien ?** Compare, sur les mêmes carrés, l'arrivée estimée par les roues seules et par robot_localization (roues + IMU). Ne modifie rien * - ``./scripts/ratbot-calibrate 1 compute NOM`` - recalcule une mesure, en montrant d'abord les carrés retenus ; ``--last 5`` ne garde que les cinq derniers de chaque sens, ``--skip ccw_06`` en écarte un. N'écrit rien dans la carte, mais **remplace** le ``resultat.yaml`` de la mesure : c'est ce calcul qu'``apply`` écrira, et que ``stats`` affichera (marqué ``*`` s'il porte sur une partie des carrés) * - ``./scripts/ratbot-calibrate 1 apply NOM`` - écrit dans la carte les réglages d'une campagne de ce robot, après accord. Il montre pour chacun la valeur **pendant** la mesure, la valeur **actuelle** et la valeur **proposée** ; il prévient si la carte a changé depuis la mesure (l'appliquer déferait une correction plus récente), dit si les valeurs sont **déjà** dans la carte, et refuse une campagne de simulation sur un vrai robot * - ``./scripts/ratbot-calibrate 1 exclude NOM "raison"`` - met de côté une campagne ratée, dans ``campagnes/_exclus/``, avec sa raison : elle ne compte plus, mais rien n'est perdu. Une campagne de **simulation**, elle, peut être supprimée, après confirmation Sur ratbot-1, ``stats`` donne : .. code-block:: text date mesure carres cote E_max,syst evolution avec IMU reglages 2026-10-03 roues 10 + 5 1.3 m 86.7 mm -- corriges le 2026-10-04 2026-10-04 roues 6 + 6 1.3 m 57.6 mm -34 % -- La colonne **avec IMU** donne l'erreur estimée par robot_localization sur les mêmes carrés. Elle reste vide pour ces deux campagnes, antérieures à l'enregistrement de cette estimation. L'IMU pendant une mesure UMBmark ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Une mesure UMBmark n'utilise pas l'IMU.** Pendant un carré, le robot se guide **uniquement sur ses roues** : ce sont elles qui lui disent quand tourner. Et les corrections calculées à la fin ne viennent **que des roues** et de votre mesure au sol. robot_localization, qui fusionne les roues et l'IMU, tourne de toute façon sur le robot, en permanence. Pendant le carré, il ne conduit pas : il calcule seulement, de son côté, où il pense que le robot se trouve. Le script **note** ce résultat à la fin du carré, sans rien en faire d'autre. Cela permet une vérification gratuite : à la fin de chaque mesure, le script compare trois positions d'arrivée — celle que croient les **roues**, celle que croit **robot_localization**, et la **vraie**, mesurée au mètre ruban. Si robot_localization est plus près de la vérité, l'IMU fait bien son travail ; s'il en est plus loin, son gyroscope est à calibrer (voir :doc:`gyroscope`). Un exemple de cette comparaison, et sa lecture, sont dans **Lire les résultats**, ci-dessous. Dans tous les cas, cette comparaison ne change rien au résultat UMBmark ni aux réglages proposés. En simulation ~~~~~~~~~~~~~ La calibration guidée fonctionne aussi en simulation, pour apprendre l'enchaînement sans robot. Le script la reconnaît d'elle-même, et : - range les mesures dans des dossiers suffixés ``_simulation`` ; - n'écrit **jamais** rien dans une carte : la fin d'une mesure affiche les réglages proposés, puis s'arrête ; - ``stats`` ignore ces mesures, qui ne disent rien du vrai robot ; ``list`` les montre, marquées « (simulation) » ; - ``apply`` refuse d'écrire une campagne de simulation dans un vrai robot. Les mesures au sol y sont fictives : seule la mécanique de l'outil s'y vérifie. Lire les résultats ~~~~~~~~~~~~~~~~~~ **Le tableau de** ``stats`` — exemple, valeurs d'illustration : .. code-block:: text date mesure carres cote E_max,syst evolution avec IMU reglages 2026-11-02 roues 5 + 5 1.2 m 84.0 mm 61.0 mm corriges le 2026-11-02 2026-11-03 roues 5 + 5 1.2 m 55.0 mm -35 % 38.0 mm 2027-02-10 roues 5 + 5 1.2 m 59.0 mm +7 % 40.0 mm .. list-table:: :header-rows: 1 :widths: 22 78 * - Colonne - Ce qu'elle veut dire * - **E_max,syst** - l'erreur **systématique** des roues, celle que la calibration peut corriger. C'est *le* chiffre à suivre : plus il est bas, mieux c'est * - **evolution** - l'écart avec la mesure précédente. Après une correction, il doit être **négatif**. « autre côté » : les deux mesures n'ont pas la même taille de carré, et ne se comparent pas (cas d'anciennes mesures ; la calibration guidée l'empêche désormais) * - **avec IMU** - la même erreur, estimée par robot_localization (roues + IMU) sur les mêmes carrés. Elle doit être **plus basse** que celle des roues * - **reglages** - le jour où les corrections de cette mesure ont été écrites dans la carte. Sans date : la mesure n'a rien changé (un contrôle) Ce que dit l'exemple, ligne par ligne : #. le 2 novembre, première mesure : 84 mm. Les corrections sont écrites ; #. le 3 novembre, nouvelle mesure avec les réglages corrigés : 55 mm, soit **35 % d'erreur en moins**. La calibration a marché ; #. en février, un contrôle sans correction : 59 mm. L'erreur a un peu remonté, mais reste loin des 84 mm de départ : **rien à faire**. Une remontée vers la valeur de départ, elle, appellerait une nouvelle calibration (sol différent, roue usée, roue remontée). Sur toutes les lignes, la colonne **avec IMU** reste sous **E_max,syst** : l'IMU améliore bien la position. **La comparaison de l'IMU**, à la fin de chaque mesure (ou avec ``compare``) : .. code-block:: text E_max,syst erreur moyenne roues seules 55.0 mm 41.0 mm robot_localization (roues + IMU) 38.0 mm 29.0 mm avec l'IMU : -31 % -- l'IMU AMELIORE la position (10 carres) - **E_max,syst** : l'erreur systématique, la même que dans ``stats`` ; - **erreur moyenne** : la distance moyenne entre l'arrivée estimée et la vraie, sur un carré. Elle contient en plus les erreurs accidentelles (glissade, bosse) ; - **la dernière ligne** donne l'écart en pourcentage, et le verdict : .. list-table:: :header-rows: 1 :widths: 30 70 * - Verdict - Que faire * - l'IMU AMÉLIORE la position (moins de −5 %) - rien : le gyroscope est bien réglé * - pas de différence nette (entre −5 % et +5 %) - rien d'urgent ; sur peu de carrés, la différence peut se perdre dans la dispersion. Vérifier l'échelle du gyroscope à l'occasion * - l'IMU DÉGRADE la position (plus de +5 %) - **calibrer le gyroscope** : ``./scripts/ratbot-calibrate 1 gyro`` (voir :doc:`gyroscope`), puis refaire une mesure Les sections suivantes détaillent chaque étape, et donnent les commandes pour la conduire à la main. Préparer la session ------------------- Une seule fois, au début : .. code-block:: bash cd ~/ratbot_ws/ros2_ws source /opt/ros/humble/setup.bash source install/setup.bash export ROS_DOMAIN_ID=77 # Où ranger cette campagne : un répertoire par campagne, daté export OUT=~/ratbot_ws/cahier_de_labo/campagnes/$(date +%F)_avant Notez le **commit du firmware flashé sur la carte** : il sera inscrit dans chaque essai, et c'est lui qui prouve que toute la campagne a tourné sur la même version. Sur la machine qui a compilé et flashé le firmware : .. code-block:: bash git log -1 --format=%h -- firmware/ .. warning:: **Pas** ``git rev-parse HEAD`` sur le Raspberry Pi : c'est le commit de son dépôt, pas celui du firmware de la carte. Les deux diffèrent dès qu'on a commité autre chose depuis le flash — et la campagne porterait alors un numéro qui ne dit rien de ce qui roulait. Laissez enfin le robot **immobile une dizaine de secondes** après l'avoir posé : il en profite pour remesurer le zéro de son gyroscope (voir :doc:`gyroscope`). Lancer un carré --------------- .. video:: _static/calibration/umbmark-carre-ccw.mp4 :width: 100% :muted: :loop: :playsinline: :preload: metadata :caption: Un carré antihoraire complet sur ratbot-1, accéléré trois fois. .. code-block:: bash ros2 run ratbot_calibration umbmark-run --robot 1 --path square_ccw \ --side 1.2 --out $OUT --name ccw_01 --firmware cb83d48 Ce qui se passe, dans l'ordre : 1. Le repère et le sens du parcours s'affichent. 2. Le programme attend que vous posiez le robot sur le L, puis **Entrée**. 3. Le robot fait **tout le carré d'une traite** : quatre côtés, quatre virages, avec un court arrêt entre chaque. Il ne vous demande rien en route. 4. Au retour, il vous annonce où il **croit** être arrivé. 5. Il vous demande **x**, puis **y** — **une valeur à la fois**, en centimètres, avec le signe ; la virgule ou le point conviennent pour les décimales. Puis il vous **relit** votre mesure en clair pour confirmation. 6. Tout est écrit dans un ``summary.yaml``, à côté de l'enregistrement complet. **Seule l'arrivée se mesure.** Les erreurs des quatre côtés et des quatre virages s'accumulent toutes dans ce point d'arrivée : c'est tout l'intérêt de la méthode. .. tip:: **Protection contre les fautes de frappe.** Si la mesure que vous tapez est à plus de 30 cm de ce que croit le robot, l'outil vous prévient et vous propose de la ressaisir — les vrais écarts restent bien en dessous. Un « 109 » tapé pour « 21 » est ainsi rattrapé avant d'entrer dans les résultats. .. warning:: **Ne bousculez pas le robot** pendant un essai. À l'arrêt, une roue peut se trouver dans l'angle mort de son capteur : si votre main la fait tourner, la carte ne le voit pas et la suite de l'essai sera fausse. **Entre deux carrés**, vous pouvez le soulever et le replacer librement : ni l'arrêt automatique pour choc, ni celui pour patinage ne se déclenchent quand on manipule un robot arrêté. Reposez-le, puis laissez-le **quelques secondes immobile** avant d'appuyer sur Entrée. Options utiles : .. list-table:: :header-rows: 1 :widths: 25 75 * - Option - Effet * - ``--out RÉPERTOIRE`` - où écrire l'essai (par défaut : le répertoire courant) * - ``--side 1.2`` - côté du carré, en mètres (voir **Quelle taille de carré** : toujours le même pour un robot) * - ``--marks`` - s'arrêter à chaque coin pour poser un repère au sol. Par défaut, le carré se fait d'une traite : seule l'arrivée entre dans le calcul * - ``--no-ask`` - ne pas demander la mesure au sol * - ``--odom fused`` - piloter le robot sur l'odométrie **fusionnée** (roues + gyroscope) au lieu des roues seules. Voir **Odométrie seule ou fusionnée** plus bas * - ``--firmware COMMIT`` - le commit du firmware flashé, inscrit dans chaque essai (voir **Préparer la session**) La campagne complète -------------------- **Cinq carrés antihoraires**, en changeant seulement le nom : .. code-block:: bash ros2 run ratbot_calibration umbmark-run --robot 1 --path square_ccw \ --side 1.2 --out $OUT --name ccw_01 --firmware cb83d48 # puis ccw_02, ccw_03, ccw_04, ccw_05 Puis déplacez le L et faites **cinq carrés horaires** : .. code-block:: bash ros2 run ratbot_calibration umbmark-run --robot 1 --path square_cw \ --side 1.2 --out $OUT --name cw_01 --firmware cb83d48 # puis cw_02 ... cw_05 Vous pouvez faire une pause entre les deux séries. Si vous avez le temps, **plus de carrés vaut mieux** : un petit robot à servomoteurs a des erreurs aléatoires importantes (une roue qui démarre un peu avant l'autre, un virage qui déborde), et la méthode les moyenne. Sur RatBot, dix carrés dans un sens ont été nécessaires pour s'assurer qu'un écart inhabituel n'était qu'une dispersion normale. Un essai raté ~~~~~~~~~~~~~ - **Vous l'avez interrompu** (Ctrl-C), ou il s'est arrêté seul : il n'a pas de ``summary.yaml`` ou porte ``aborted``. L'analyse l'ignore toute seule. Rangez-le quand même à part, avec la raison : .. code-block:: bash mkdir -p $OUT/_exclus && mv $OUT/20261004_120346_cw_01 $OUT/_exclus/ - **Vous voulez refaire un essai** : relancez-le, sous le même nom ou un autre. Chaque essai a son propre répertoire, préfixé par l'heure : **rien n'est jamais écrasé**. - **Vous avez mal saisi une mesure** et vous connaissez la bonne : corrigez-la dans le ``summary.yaml`` **en gardant la trace** — recopiez l'ancien bloc ``measured`` sous le nom ``measured_as_entered``, puis corrigez ``measured`` et ajoutez une ligne ``correction`` qui dit qui a corrigé, quand et pourquoi. Notez-le aussi dans votre cahier. .. important:: **Rien ne doit changer pendant une campagne** : ni le firmware, ni les paramètres, ni la hauteur des roues, ni le sol. Dix essais répartis sur deux versions ne se moyennent pas — ils ne mesurent plus rien. Avant de commencer, mettez de côté les réglages de la carte — voir :doc:`parametres` : .. code-block:: bash ./scripts/ratbot config 1 save avant_campagne.yaml Vérifier un sens avant de se lancer ----------------------------------- Si vous avez un doute sur le sens de rotation ou sur la place disponible, un seul quart de tour suffit à le lever : .. code-block:: bash ros2 run ratbot_calibration umbmark-run --robot 1 --path turn_cw Cela évite de découvrir un problème au troisième carré. Ce que produit chaque essai --------------------------- Un répertoire horodaté contenant l'enregistrement complet (rosbag2) et un ``summary.yaml`` : .. code-block:: yaml path: square_ccw firmware: cb83d48 aborted: null odometry_end: x_m: 0.0611 y_m: -0.0509 yaw_deg: 1.07 measured: x_cm: 6.5 y_cm: -4.5 notes: '' ``odometry_end`` est ce que **croyait** le robot, ``measured`` ce que vous avez **mesuré**. Tout le reste de la méthode se calcule à partir de ces deux blocs. .. note:: Si ``aborted`` n'est pas ``null``, l'essai s'est interrompu — le plus souvent parce que la liaison avec la carte est tombée. **Ne le comptez pas**, et refaites-le. Calculer les corrections ------------------------ Une fois les dix essais faits, un seul outil lit toute la campagne : .. code-block:: bash ros2 run ratbot_calibration umbmark-analyze $OUT \ --config ~/ratbot_ws/cahier_de_labo/config/ratbot1.yaml \ --out $OUT/resultat.yaml Le ``--config`` lui donne la géométrie actuelle du robot ; à défaut, passez ``--wheelbase`` et ``--radius`` à la main. Le ``--out`` range le résultat à côté de la campagne — gardez-le, c'est lui que vous comparerez plus tard. Il affiche d'abord quels essais il retient et lesquels il écarte, puis : .. code-block:: text Centres of gravity of the return errors [mm] clockwise x -135.5 y -133.4 radius 190.2 counter-clockwise x +10.2 y -9.1 radius 13.7 E_max,syst = 190.2 mm The two error sources beta = +2.0648 deg straight legs curve; the wheels differ by Ed = 1.00506 (right / left diameter) alpha = +1.7873 deg turns miss 90 deg; the real wheelbase is Eb = 1.02026 times the assumed one Settings to write into the board wheel_radius_left 0.025934 (was 0.026000) wheel_radius_right 0.026066 (was 0.026000) wheel_separation 0.142837 (was 0.140000) Comment lire ça ~~~~~~~~~~~~~~~ **E_max,syst** est *le* chiffre de la méthode : la précision systématique de votre odométrie, en millimètres. C'est lui qu'on compare avant et après. **bêta** dit que les lignes droites se courbent, parce que les roues n'ont pas le même diamètre. **alpha** dit que les virages ne font pas 90°, parce que l'entraxe réel diffère. Les deux dernières lignes sont les réglages à écrire. .. note:: L'outil refuse de conclure si la campagne mélange **deux firmwares** ou **deux tailles de carré**, et si un seul sens de rotation est exploitable. Ce ne sont pas des caprices : dans ces trois cas le résultat n'aurait aucun sens. Il peut aussi afficher ``NOTE: geometry not recorded for ...`` : la géométrie de la carte n'a pas pu être lue pour certains essais. Il les garde seulement si tous les autres essais **et** le fichier ``--config`` donnent la même géométrie. Appliquer les corrections ------------------------- Reprenez les trois valeurs affichées par l'outil — celles ci-dessous sont l'exemple, pas les vôtres. .. code-block:: bash cd ~/ratbot_ws # TOUJOURS, avant de changer quoi que ce soit -- voir :doc:`parametres` ./scripts/ratbot config 1 save cahier_de_labo/config/ratbot1_avant_calibration.yaml ros2 param set /ratbot_1/ratbot_controller wheel_radius_left 0.025934 ros2 param set /ratbot_1/ratbot_controller wheel_radius_right 0.026066 ros2 param set /ratbot_1/ratbot_controller wheel_separation 0.142837 ./scripts/ratbot config 1 save cahier_de_labo/config/ratbot1.yaml \ --origin "campagne UMBmark $(date +%F)" .. note:: L'écriture en flash est temporisée de 3 secondes pour l'épargner. Laissez passer quelques secondes avant de couper le robot, sinon la dernière valeur n'est pas enregistrée. La sauvegarde, la restauration et le détail de chaque réglage sont décrits dans :doc:`parametres`. Vérifier le résultat -------------------- Refaites **les dix mêmes essais, sans rien recalculer**. C'est cette seconde campagne qui prouve quelque chose ; la première ne faisait que mesurer. .. danger:: **Rangez-la dans un répertoire NEUF.** .. code-block:: bash export OUT=~/ratbot_ws/cahier_de_labo/campagnes/$(date +%F)_apres Si vous la mettez dans le répertoire de la première, l'outil trouvera vingt essais et moyennera l'avant avec l'après. Le résultat serait lisse, crédible, et entièrement faux. L'outil se défend : chaque essai enregistre la géométrie avec laquelle il a roulé, et l'analyse refuse de mélanger deux géométries. Mais ne comptez pas dessus — rangez proprement. Puis relancez l'analyse sur la nouvelle campagne et comparez **E_max,syst** : .. code-block:: bash ros2 run ratbot_calibration umbmark-analyze $OUT \ --config ~/ratbot_ws/cahier_de_labo/config/ratbot1.yaml \ --out $OUT/resultat.yaml grep e_max_syst_mm ~/ratbot_ws/cahier_de_labo/campagnes/*/resultat.yaml .. tip:: Dans l'article d'origine, E_max,syst passe de 317 mm à 21 mm sur un carré de 4 m : un facteur 15. C'est l'ordre de grandeur à espérer. Si le chiffre **ne baisse pas**, ne recalculez pas de nouveaux coefficients par-dessus : c'est le signe que l'erreur dominante n'est pas systématique (sol glissant, roue mal serrée, robot bousculé) et qu'aucun coefficient ne la corrigera. **Sur RatBot, à titre d'exemple** (carré de 1,3 m, octobre 2026) : E_max,syst est passé de **86,7 mm à 57,6 mm**, soit un tiers de moins. Loin du facteur 15 de l'article : sur un petit robot à servomoteurs, les erreurs **aléatoires** pèsent autant que les erreurs systématiques, et la méthode ne corrige que les secondes. **Une seconde itération** est justifiée dans un cas précis : E_max,syst a **baissé**, mais **alpha** ou **bêta** a **changé de signe** — la correction est allée trop loin. L'analyse de la campagne « après » propose alors de nouvelles valeurs, à partir des réglages en place : appliquez-les, puis refaites une campagne de vérification, dans un **troisième** répertoire. Odométrie seule ou fusionnée avec le gyroscope ---------------------------------------------- En navigation, le robot ne se fie pas qu'à ses roues : l'EKF y fusionne le gyroscope. Pour savoir ce que la fusion apporte, rejouez une campagne : .. code-block:: bash ros2 run ratbot_calibration umbmark-fusion $OUT --out $OUT/fusion.yaml Pour chaque essai, l'outil compare à votre mesure au sol l'arrivée estimée par les **roues seules** et par les **roues + gyroscope**, sur le même parcours. .. important:: Le gyroscope doit être **calibré lui aussi** (voir :doc:`gyroscope`). Mesuré sur RatBot : avec un zéro mal réglé, la fusion faisait 30 cm d'erreur au lieu de 7 ; et tant que son échelle n'est pas vérifiée, elle ne bat pas les roues calibrées. Ce rejeu estime ce que la fusion **aurait** donné. Pour le vérifier en vrai, faites une **campagne fusionnée** : les mêmes dix carrés, mais le robot se pilote sur l'odométrie fusionnée, comme il le fera en navigation. .. code-block:: bash ros2 run ratbot_calibration umbmark-run --robot 1 --path square_ccw \ --side 1.2 --odom fused --out $OUT_FUSION --name ccw_01 \ --firmware COMMIT - Mettez-la dans **son propre répertoire** : l'analyse refuse de mélanger des essais roues seules et fusionnés. - Au départ, l'outil remet à zéro l'odométrie des roues **et** celle de l'EKF. Chaque essai enregistre les deux, et le résumé dit aussi où l'autre croyait finir (``witness_end``). - L'analyse donne l'**E_max** à comparer avec celui de la campagne roues seules. Elle ne propose **pas** de nouvelle géométrie de roues : le gyroscope est dans la boucle, le calcul n'aurait plus de sens. Garder la trace --------------- Pour chaque campagne, conservez ensemble : - le répertoire des dix essais, avec leurs ``summary.yaml`` ; - le ``resultat.yaml`` de l'analyse ; - le fichier de configuration produit par ``ratbot config save`` (voir :doc:`parametres`). Les trois se suffisent : ils disent ce que le robot croyait, ce que vous avez mesuré, ce qu'on en a déduit, et ce qui a été appliqué. En cas de souci --------------- .. list-table:: :header-rows: 1 :widths: 40 60 * - Symptôme - Piste * - ``FAILED: no odometry`` - L'agent micro-ROS ne tourne pas, ou le ``ROS_DOMAIN_ID`` n'est pas le bon. Voir :doc:`depannage`. Avec ``--odom fused`` : l'EKF ne tourne pas (pile lancée avec ``use_ekf:=false``) * - ``FAILED: … did not reset`` - La remise à zéro de l'odométrie au départ a été ignorée. Relancez l'essai ; si le problème persiste, redémarrez la pile du robot * - ``ABORTED: link lost`` - La liaison avec la carte est tombée en cours d'essai. Refaites-le, et regardez le journal de bord (:doc:`journal`). * - Le robot part du mauvais côté - Le L est au mauvais coin. Revoyez **Où poser le robot**. * - Les mesures ne retombent jamais pareil - Sol glissant ou irrégulier, ou robot bousculé pendant les arrêts. * - Le robot ne bouge pas du tout - Arrêt d'urgence enclenché. Voir :doc:`signaux` — voyant rouge clignotant. * - Le robot s'arrête en cours de carré, voyant **orange** - L'arrêt automatique s'est déclenché : 6 bips longs puis 3 courts pour un patinage, 4 pour un choc. Réarmez (5 appuis sur SW1, voir :doc:`arrets`), regardez ce qui a pu se passer (sol glissant, obstacle), et refaites l'essai. * - ``WARNING: that is ... cm away from where the robot believes it is`` - La mesure tapée est très loin de ce que croit le robot : faute de frappe probable. Répondez **n** et ressaisissez. * - Le robot met plus de 15 s à partir après Entrée - Il lit les réglages de la carte avant de partir ; normalement une fraction de seconde. Une version ancienne de l'outil attendait jusqu'à 15 s quand la carte ne répondait pas : mettez à jour le Raspberry Pi.