Le banc de test sur PC ====================== ``firmware/ratbot_firmware_card/test/`` compile les **vrais fichiers de la carte** — pas une copie, pas une réécriture — avec du faux matériel, et les fait tourner sur le PC de développement. .. code-block:: bash cd firmware/ratbot_firmware_card/test make .. code-block:: text === traction === un tour complet rend bien 2*pi radians (1229 pas, pas 1024) en marche avant, la vitesse mesuree ne passe jamais negative ... === traction, XL430 === XL430 : trois tours rendent 6*pi, sans secteur aveugle ni credit ... 67 verifications, 0 echec(s) Pourquoi il existe ------------------ L'estimateur de roue (:doc:`traction`) est du **calcul pur** : des comptes entrent, des radians sortent. Rien n'oblige à le déboguer sur le robot, où chaque essai coûte un flash, une batterie et un mètre ruban. Surtout, ses défauts sont **difficiles à provoquer à la demande** : il faut que la roue s'arrête pile dans le secteur aveugle, ou qu'un fantôme apparaisse au bon moment. Sur le banc, on les écrit en trois lignes et ils se rejouent à chaque compilation. Ce qu'il ne fait pas : il ne teste ni FreeRTOS, ni le DMA, ni le bus Dynamixel réel, ni micro-ROS. Il teste la **logique**. Pour le XL430 en particulier, l'échange réel sur le fil (délais, réception bourrée) reste à essayer avec les moteurs. Comment il est bâti ------------------- .. list-table:: :header-rows: 1 :widths: 26 74 * - Fichier - Rôle * - ``faux/main.h``, ``faux/cmsis_os.h`` - de quoi satisfaire les ``#include`` du firmware sans HAL ni FreeRTOS * - ``faux_materiel.c`` - le bus Dynamixel simulé, ``HAL_GetTick()``, la configuration, l'arrêt d'urgence * - ``cadre.c`` - trois macros : ``CAS``, ``VERIFIE``, ``PROCHE``. Rien de plus * - ``test_traction.c`` - les cas, et le modèle du capteur AX-18A ; depuis le 2026-10-19, ceux du XL430 : odométrie sur trois tours, repli de la position à 2³¹, servo qui redémarre (remis en service), consigne écrêtée et jamais répétée, arrêt d'urgence, mise en service (EEPROM écrite une fois, couple coupé), modèle refusé * - ``test_dxl_frame2.c`` - les trames du protocole 2.0 : les exemples du manuel ROBOTIS **à l'octet près** (CRC compris), les trames abîmées, et le bourrage dans les deux sens — une position de −32 tours s'écrit ``FF FF FD FF`` —, et la recherche de la réponse derrière l'écho, même décalée d'un parasite * - ``test_tof.c`` - la tâche ToF avec un faux capteur : démarrage (8 × 8, 15 Hz, cible la plus proche), capteur absent puis branché, image convertie (colonnes retournées), panne puis redémarrage, image corrompue, température transmise, et la place laissée dans le diagnostic à ``ros_tof`` * - ``test_config.c`` - la configuration en flash, avec une fausse flash : une version 4 (la calibration de ratbot-1) est relue et convertie, une v4 abîmée retombe sur les défauts * - ``test_rearm_gesture.c`` - le geste de réarmement local — 5 appuis sur SW1 : fronts montants, fenêtre de 4 s, pas de second déclenchement, débordement de l'horloge ``traction.c`` est **inclus dans la compilation du test**, ce qui donne accès à ses statiques. Les options y sont plus sévères que sur la carte — ``-Wextra`` et ``-Wconversion`` — parce que ces fichiers-là sont du calcul et qu'autant en profiter. .. warning:: ``traction.c`` doit figurer dans les **dépendances** de la cible, et pas seulement dans la ligne de compilation. Sans cela, une modification du firmware ne reconstruit rien et le banc rejoue l'ancienne version. C'est arrivé : il a annoncé « 0 échec » sur un correctif qu'il n'avait pas compilé. Le modèle du capteur -------------------- ``capteur(angle_rad)`` reproduit l'AX-18A : 1024 pas sur 300 degrés, puis 60 degrés où le registre colle à 1023 en entrant et à 0 en sortant. Deux détails qui ont chacun coûté une séance : **Le signe du servo.** L'angle reçu est celui de la roue dans le repère du robot ; le servo tourne dans le sens que lui impose son montage. Le modèle applique donc ``wheel[0].sign``, le même signe que le firmware. Sans cette ligne, le banc simulait encore les moteurs du banc d'essai et plus ceux du robot monté — cinq tests échouaient pour une mauvaise raison. **L'angle zéro est au milieu de la course visible**, pas à son bord. Partir du bord mettait la roue simulée dans le secteur aveugle dès le premier échantillon, à vitesse nulle, et les scénarios de secteur aveugle passaient **sans rien prouver** — un robot à l'arrêt ne traverse jamais ce trou, il y reste. Les cas ------- .. list-table:: :header-rows: 1 :widths: 46 54 * - Cas - Ce qu'il empêche de revenir * - un tour vaut 1229 pas - perdre un sixième de tour à chaque passage * - la vitesse ne passe jamais négative en marche avant - la boucle qui pousse à fond en voyant une roue reculer * - un fantôme ne crédite rien - le saut de −2 rad pris pour une sortie de trou * - une roue débranchée puis rebranchée ne crédite rien - 78 mm de déplacement fantôme à la reconnexion * - l'intégrale s'arrête au plafond de sortie - la roue qui pousse 1,5 s après l'ordre de ralentir * - une roue arrêtée dans le trou ne fait pas dériver l'odométrie - les 600 rad en cinq minutes, robot à l'arrêt * - freinage actif puis coupure - les virages qui dépassent de 13 à 22 degrés * - un fantôme au redémarrage n'est pas une sortie - les sauts de 3,4 rad au départ des virages * - l'estime s'arrête avec la roue - 107 plafonnements en un seul arrêt * - remise à zéro roue garée dans le trou - les +6,9 degrés de cap du troisième carré UMBmark * - chaque roue prend son propre rayon - qu'un des quatre usages du rayon reste sur l'autre roue Chaque ligne de la colonne de droite est un défaut **qui s'est réellement produit**, avec sa mesure. C'est la règle du banc : on n'y ajoute pas de cas spéculatif, on y ajoute le cas qui vient de coûter une séance. Vérifier qu'un test a des dents ------------------------------- Un test qui passe ne prouve rien tant qu'on n'a pas vu qu'il pouvait échouer. La pratique retenue est le **test par mutation** : on casse volontairement la ligne visée, on vérifie que le banc proteste, puis on restaure. .. code-block:: bash # Exemple : la roue droite emprunte le rayon de la gauche sed -i 's|/ cfg->wheel_radius_right|/ cfg->wheel_radius_left|' ../App/traction.c make # doit afficher « 1 echec(s) » git checkout ../App/traction.c make # doit repasser au vert Sans cette vérification, un test peut être vide de sens et rassurer pour rien. Ajouter un cas -------------- .. code-block:: c static void cas_mon_scenario(void) { CAS("ce que le cas demontre, en une phrase"); roue_neuve(); commande(4.6); /* consigne suivie, rad/s */ lire(capteur(angle), 20u); /* un pas de 20 ms */ PROCHE(wheel[0].position_rad, attendu, 0.01, "pourquoi c'est ca"); } Puis l'appeler depuis ``main()``. Les helpers disponibles : - ``roue_neuve()`` — remet la roue, le faux bus et les compteurs à zéro ; - ``commande(omega)`` — pose la consigne, que ``blind_estimate()`` consulte ; - ``lire(compte, dt_ms)`` — avance le temps, pose la réponse du capteur, appelle ``wheel_read_position()`` ; - ``capteur(angle_rad)`` — le modèle du capteur ; - ``faux_config_radii(gauche, droite)`` — les deux rayons de roue. Voir aussi ---------- - :doc:`traction` — ce que ces cas protègent.