🧶Les pelotes de ficelle

On attrape un bout, on tire le fil, on déroule la pelote.

← Revenir à la pelote

Neato erreur 4202 « batterie déchargée » : le jour où mon aspirateur a décidé qu'il était mort

Un D800 privé de cloud, une batterie déclarée « à remplacer », et trois fils sur un ESP32 à deux euros pour lui demander ce qu'elle a vraiment

En deux minutes, si votre Neato clignote rouge avec l’erreur 4202

  • Le symptôme : voyant rouge, erreur 4202, « batterie déchargée », le robot refuse de charger ou de partir. Sur les D8, D9, D10 et D800, l’application (tant qu’elle existait) ajoutait que le compteur de charge de la batterie était dépassé.
  • Ce que ça veut dire : pas forcément que la batterie est morte. Elle contient une puce qui parle au robot ; c’est ce qu’elle raconte qui déclenche l’erreur. Changer les cellules (les « piles » à l’intérieur) ne change pas ce qu’elle raconte.
  • Ce qu’on a trouvé en la faisant parler avec un microcontrôleur à deux euros : aucune panne, aucune protection déclenchée, un compteur à 1547 cycles, et un « ne me charge pas » qui n’était que son mode veille.
  • Ce qu’on a fait : sauvegardé sa mémoire, remis le compteur à zéro. Le robot a remarché… une journée. Mise à jour du 1er septembre : la vraie cause était ailleurs — une cellule de récupération plus faible qui déclenchait la protection de surtension à chaque charge (240 fois en trois jours). Tension de charge abaissée, jauge remise en apprentissage, en observation (voir Où on en est).
  • Épilogue : les cellules « mortes » d’origine, passées au testeur de capacité, rendent encore 1819 à 1916 mAh sur 2500 nominaux. Elles n’avaient rien à se reprocher non plus.
  • Avant d’acheter une batterie : lisez Pour reproduire. Il faut un fer à souder, trois fils, un ESP32 et une soirée. Pas de programmateur du fabricant à 150 €, pas de mot de passe à casser.

Ce billet se veut lisible sans rien connaître à l’électronique : chaque terme technique est expliqué la première fois qu’il apparaît, et un glossaire récapitule à la fin. Les encarts « Pour aller au fond » se déplient pour ceux qui veulent les registres, les adresses et les octets.

La carte électronique du pack Neato, gaine ouverte : les pastilles C+ et C− au centre, et à droite les deux petites pastilles marquées DA et CL, avec les fils jaunes déjà soudés

La carte du pack, une fois la gaine ouverte. Les deux petites pastilles marquées « DA » et « CL », à droite, sont tout ce dont on a besoin. Les grosses au centre, C+ et C−, sont celles qu’on ne touche pas.

Un cloud éteint, puis un bouton qui meurt

Mon robot aspirateur est un Neato D800. Un bon robot : un LIDAR rotatif (un petit radar laser qui tourne sur le dessus et mesure les distances aux murs), une cartographie de la maison, des lignes interdites qu’on trace dans l’application, 600 € à l’époque. En 2023, Neato Robotics a fermé. Vorwerk, la maison mère, a gardé les serveurs allumés un moment — le « cloud », c’est-à-dire les ordinateurs distants sans lesquels l’application, les cartes et la programmation ne fonctionnent pas —, puis a annoncé le 6 octobre 2025 (copie locale) que ce cloud s’éteignait. « Your Neato robot will continue to function manually. Simply press the button once to launch a full house run. » Un robot à 600 € rétrogradé en aspirateur à un bouton, par communiqué.

Et puis, quelques mois plus tard, le bouton lui-même a cessé de répondre. Voyant rouge, erreur 4202, « batterie déchargée ». L’application, dans ses derniers souffles, précisait que le compteur de charge de la batterie était dépassé et qu’il fallait la remplacer. Batterie d’origine : 90 €, quand on en trouve. Compatible : 30 à 50 €, avec le risque bien documenté sur les forums que le robot la refuse.

Ce billet raconte comment on est passé de « robot mort, batterie morte » à une batterie qui explique elle-même ce qui ne va pas — sans rien acheter, avec trois fils et un microcontrôleur qui coûte le prix d’un café. Il raconte aussi un faux espoir, parce que c’est ce qui arrive quand on cherche pour de vrai. Il s’arrête sur ce que cette enquête m’aurait coûté il y a trois ans, avant qu’une IA puisse lire un manuel de 250 pages à ma place, et sur la petite puce remarquable qui gère cette batterie. Et il explique pourquoi cette histoire me laisse un goût amer sur la manière dont on fabrique les objets.

Premier réflexe : les cellules

Une batterie de robot, c’est un boîtier qui contient plusieurs cellules — des accumulateurs lithium au format 18650 (18 mm de diamètre, 65 mm de long, l’allure d’une grosse pile AA) — reliées en série et gérées par une petite carte électronique. Une batterie « déchargée » qui ne se recharge plus, c’est classiquement des cellules mortes. J’ai donc fait ce que fait tout bricoleur : ouvert le pack, dessoudé les quatre cellules, soudé à la place quatre cellules de récupération — dépareillées, ce qui aura son importance plus loin —, refermé.

Résultat : toujours erreur 4202.

Multimètre en main (l’appareil qui mesure la tension, c’est-à-dire la « pression » électrique, en volts), pourtant, tout était parfait. 4,1 V sur chaque cellule, ce qui est une cellule lithium pleine ; 16,4 V aux bornes du pack ; 16,4 V au connecteur de sortie, ce qui signifie que le circuit de protection — l’interrupteur électronique qui peut isoler les cellules en cas de danger — laissait bien passer le courant. La thermistance (une résistance dont la valeur change avec la température, que le robot lit pour surveiller la batterie) affichait 6 kΩ, une valeur normale pour une pièce tiède. Le robot avait entre les mains une batterie chargée à 95 % et en bonne santé, et il affichait « batterie déchargée ».

C’est le moment où l’on comprend que le problème n’est pas la batterie. C’est ce que la batterie dit d’elle-même.

Pour aller au fond : mesurer sans se brûler

Le pack fait 14,4 V nominal (quatre cellules en série, « 4S »), 16,8 V chargé. Ce n’est pas une tension dangereuse pour la peau, mais un court-circuit — relier directement le plus et le moins — sur des 18650 laisse passer des dizaines d’ampères : de quoi souder une pince, faire fondre une gaine ou enflammer une cellule. Règles simples : pas de bracelet ni de bague, un seul outil métallique à la fois, et on mesure sur les pastilles B+ / B− (côté cellules) ou C+ / C− (côté connecteur) sans jamais les relier. La thermistance (une NTC de 10 kΩ à 25 °C : sa résistance baisse quand il fait chaud) se lit entre le fil de température et le moins.

Si la tension est bonne côté cellules mais nulle au connecteur, c’est le circuit de protection qui a coupé : là, c’est bien la puce qui a décidé, et on est dans le sujet de ce billet.

La batterie a un cerveau

Les packs des Neato de dernière génération (D8, D9, D10, D800) sont des « batteries intelligentes » (smart batteries) : à côté des cellules, la petite carte porte une jauge de charge, une puce — un circuit intégré, une minuscule plaquette de silicium qui contient un ordinateur spécialisé — de Texas Instruments, le bq40z50-R2. C’est elle qui mesure le courant, additionne ce qui entre et ce qui sort, en déduit l’état de charge, coupe en cas de surtension ou de surchauffe — et c’est elle qui parle au robot, par un bus série : deux fils sur lesquels circulent des messages numériques, un fil pour les données et un pour l’horloge qui rythme la conversation. Le protocole (la langue parlée sur ces fils) s’appelle SMBus, cousin industriel de l’I²C que connaissent tous les bricoleurs d’Arduino. Un fil bleu supplémentaire dans le connecteur du pack porte cette conversation jusqu’au robot.

Le robot ne mesure pas la tension de la batterie. Il demande à la jauge : « tu es chargée à combien ? », « quel courant de charge veux-tu ? », « quelle tension ? », « combien de cycles as-tu faits ? ». Et il obéit à ce qu’elle répond. Si la jauge dit « 0 % » ou « ne me charge pas », le robot affiche « batterie déchargée », quelle que soit la réalité électrique à trois centimètres de là.

Cette architecture n’est pas absurde : une jauge dans le pack connaît l’historique des cellules, gère leur équilibrage (maintenir les quatre cellules au même niveau de charge, faute de quoi la plus faible s’use en premier), et protège efficacement contre l’emballement thermique (la réaction en chaîne qui fait prendre feu une cellule lithium maltraitée). Mais elle a une conséquence : remplacer les cellules ne remet pas la jauge à zéro. Le compteur de cycles, la capacité apprise, les drapeaux d’erreur (des cases « oui/non » que la puce coche quand elle détecte un problème) — tout ça vit dans la mémoire de la puce, pas dans les cellules. On change le cœur, le cerveau garde ses souvenirs.

Sur les forums, la piste s’arrête généralement là. Les puces des packs D3–D7 sont d’un fabricant obscur et verrouillées ; pour les bq40z50 « il faut un EV2400 et bqStudio » — l’adaptateur officiel de Texas Instruments, 150 €, et son logiciel Windows — et personne ne sait vraiment quelles données le robot vérifie. Fin de l’histoire, achetez une batterie.

Pour aller au fond : SMBus, SBS et ce que « smart battery » veut dire

Le Smart Battery System (SBS) est une norme des années 1990, née pour les ordinateurs portables. Une batterie SBS est un périphérique à l’adresse SMBus 0x0B — sur un bus partagé, chaque puce a un numéro pour qu’on sache à qui l’on parle ; la notation 0x… signifie que le nombre est écrit en hexadécimal, en base 16, l’habitude des informaticiens — qui répond à une centaine de commandes standardisées, chacune désignée par un numéro : 0x09 tension, 0x0A courant, 0x0D état de charge relatif (RSOC, le « pourcentage de batterie »), 0x10 capacité à pleine charge, 0x17 compteur de cycles, 0x14 / 0x15 courant et tension de charge demandés… Ce que renvoie une commande, on l’appelle un registre : une petite case de mémoire lisible de l’extérieur. Un chargeur « intelligent » lit ces deux derniers registres et fournit exactement ce qu’on lui demande. À zéro, il ne fournit rien.

Le bq40z50 ajoute par-dessus une commande fourre-tout, ManufacturerBlockAccess (0x44), par laquelle on lit les registres d’état internes (statut de sécurité, défauts permanents, état des transistors) et, en accès suffisant, toute la mémoire flash de configuration — la mémoire qui survit à l’extinction, comme une clé USB —, 8 Ko d’adresses 0x4000 à 0x5FFF, où vivent le compteur de cycles, la capacité nominale, les seuils de protection et une cinquantaine d’options.

Trois niveaux d’accès existent : Sealed (scellé, lecture des registres standards seulement), Unsealed (déverrouillé par une clé de 32 bits) et Full Access (tout, y compris l’écriture de la flash, derrière une seconde clé). TI recommande de sceller avant de sortir d’usine.

Trois fils et un ESP32 à deux euros

Sauf que le bq40z50 est une puce publiquement documentée. Texas Instruments publie son Technical Reference Manual — le manuel de référence, 250 pages qui décrivent chaque registre, chaque commande, chaque adresse en mémoire (copie locale du PDF, 1,6 Mo). Et le SMBus, n’importe quel microcontrôleur — un ordinateur complet sur une puce, quelques euros, celui qu’on trouve dans une carte Arduino — sait le parler dès qu’il a deux broches I²C.

J’ai des ESP32-C3 « Super Mini » plein un tiroir : une carte de la taille d’un timbre, deux euros pièce, qui se branche en USB et se programme comme un Arduino.

Le dessous d'un ESP32-C3 Super Mini : de haut en bas les broches 5V, G, 3.3, 4, 3, 2, 1, 0 ; on utilise G, 4 et 5

Sur la carte du pack, deux pastilles de test — des points de contact laissés exprès par le fabricant pour brancher ses appareils de contrôle en fin de chaîne — sont sérigraphiées DA et CL : data et clock, les deux fils du SMBus. Un fil sur DA, un sur CL, un sur le moins des cellules, et de l’autre côté les broches GPIO 4, GPIO 5 (GPIO : les broches d’entrée-sortie numérotées d’un microcontrôleur) et GND (la masse, le « zéro volt » commun) de l’ESP32. Pas de composant à ajouter, pas d’alimentation à fournir : la jauge est alimentée par ses cellules et l’ESP32 par son USB.

Schéma de câblage : GPIO 4 de l'ESP32-C3 vers la pastille DA, GPIO 5 vers CL, GND vers le moins des cellules ; C+ à 16,4 V n'est jamais touché

Côté logiciel, deux cents lignes en Arduino, écrites avec une IA (Claude) qui a lu le manuel à ma place : on lit les registres standards (tension, courant, état de charge, compteur de cycles, tensions par cellule), puis les registres d’état internes — statut de sécurité, défauts permanents, état des transistors de charge et de décharge —, puis on recopie la mémoire flash. Rien n’est écrit sans un ordre explicite. On écoute.

Pour aller au fond : le câblage, les pull-ups et le code
Pack (carte BMS) ESP32-C3 Super Mini
Pastille DA (SMBus data) GPIO 4 (SDA)
Pastille CL (SMBus clock) GPIO 5 (SCL)
Fil noir (− des cellules, pastille B−) G (GND)

Le SMBus a besoin de résistances de rappel (pull-up : elles tirent doucement chaque ligne vers 3,3 V quand personne ne parle, faute de quoi le signal flotte) sur les deux lignes. Les résistances internes de l’ESP32 (≈ 45 kΩ) ont suffi ici à 100 kHz sur dix centimètres de fil ; si la puce ne répond pas au scan I²C, ajouter deux 4,7 kΩ entre chaque ligne et le 3,3 V de l’ESP32. La jauge tolère 3,3 V sur ses lignes de bus, on ne relie jamais le 3,3 V ni le 5 V de l’ESP32 au pack.

Le sketch — c’est le nom qu’Arduino donne à un programme — (bq40z50-reader.cpp, platformio.ini) tourne en boucle : toutes les dix secondes, un relevé complet sur le port série (le canal texte entre la carte et l’ordinateur, lu dans un « moniteur série ») à 115200 bauds (la vitesse de la liaison). Il n’écrit dans la jauge que sur trois lettres tapées dans le moniteur : r (redémarrage de la puce), c (compteur de cycles à zéro), C (compteur remis à sa valeur d’origine). Tout le reste est de la lecture.

Ce que la puce a dit

Première lecture, sur le moniteur série :

Voltage            : 16386 mV
RSOC               : 97 %
RemainingCapacity  : 2343 mAh
FullChargeCapacity : 2437 mAh
DesignCapacity     : 2500 mAh
CycleCount         : 1547
ChargingCurrent    : 0 mA
ChargingVoltage    : 0 mV
Cellules           : 4094 / 4097 / 4100 / 4095 mV
ManufacturerName   : BLUEWAY-
DeviceName         : bq40z50-
ManufactureDate    : 2022-01-09
OperationStatus    : PRES DSG CHG SEC0  -> sécurité : FULL ACCESS
SafetyStatus       : (aucun flag)
PFStatus           : (aucun flag)

Pour lire ce relevé : mV et mA sont des millivolts et des milliampères (millièmes de volt et d’ampère) ; les mAh, milliampères-heures, mesurent une quantité d’énergie stockée — 2437 mAh, c’est de quoi fournir 2,4 A pendant une heure ; RSOC est le pourcentage de batterie affiché ; FullChargeCapacity est ce que la jauge pense pouvoir stocker aujourd’hui, DesignCapacity ce que le pack stockait neuf.

Trois choses sautent aux yeux.

La jauge est en pleine forme. Aucun défaut de sécurité, aucun défaut permanent, transistors de charge et de décharge passants (les transistors, ou FET, sont les interrupteurs électroniques par lesquels la jauge autorise ou coupe la charge et la décharge), état de charge estimé à 97 % — cohérent avec les 4,1 V par cellule. Elle n’est pas « déchargée », et elle le sait.

Elle n’est même pas verrouillée. Le niveau de sécurité est FULL ACCESS : le mode le plus permissif de la puce, celui que TI recommande de quitter avant de sortir de l’usine. Pas de mot de passe à casser, pas de clé à deviner. Toute la mémoire est lisible et inscriptible. Le fabricant du pack a livré la maison avec les clés sur la porte.

Et pourtant elle dit au robot de ne pas la charger. ChargingCurrent = 0 mA, ChargingVoltage = 0 mV. Ce sont les deux registres qu’un chargeur intelligent lit pour savoir quoi faire. À zéro, ils signifient : « n’envoie pas de courant ».

Et le compteur : 1547 cycles. Un cycle, pour une jauge, c’est une décharge cumulée équivalant à une batterie entière — deux demi-décharges font un cycle. Pour une batterie fabriquée en janvier 2022, c’est un cycle par jour depuis quatre ans — plausible pour un robot qui passe quotidiennement. C’est aussi le nombre que l’application m’avait reproché.

Pour aller au fond : lire les drapeaux d'état

OperationStatus (commande 0x44 + 0x0054) est un mot de 32 bits — trente-deux cases valant 0 ou 1, chacune un drapeau. Ceux qui comptent ici : PRES (le robot est détecté), DSG et CHG (transistors de décharge et de charge passants), SEC1:SEC0 (niveau de sécurité : 01 = Full Access, 10 = Unsealed, 11 = Sealed), PF (défaut permanent : le pack s’est auto-condamné), XCHG / XDSG (charge / décharge interdites), SLEEP (retenez celui-là). SafetyStatus (0x0051) liste les protections actives — surtension, sous-tension, surintensité, température ; PFStatus (0x0053) les défauts permanents, ceux qu’aucun redémarrage n’efface : cellule ouverte, fusible grillé, déséquilibre irrécupérable. Tout était à zéro.

Dix-sept mille lignes de manuel, et un faux espoir

La question devient : pourquoi la jauge refuse-t-elle la charge ? Le manuel TI liste précisément les cas où ChargingVoltage() tombe à zéro : transistor de charge coupé par une protection, température hors plage, défaut permanent, pack déclaré « retiré », surtension du chargeur détectée. On les a tous vérifiés, registre par registre. Aucun n’était actif. Température 26 °C, région de température « recommandée », région de tension « haute », tout au vert.

On a aussi exploré une piste séduisante : le bq40z50 possède une fonction de dégradation par compteur de cycles, qui réduit volontairement la tension et le courant de charge à mesure que le pack vieillit — une obsolescence programmée au sens littéral, activable par un bit de configuration. On a lu ce bit dans la mémoire flash. Il était à zéro. Neato ne l’avait pas activée. La table de charge disait 4,2 V par cellule et 1,5 A dans toutes les plages de température. Sur le papier, la jauge devait annoncer 16,8 V et 1500 mA. Elle annonçait 0 et 0.

Avant d’aller plus loin, on a fait ce qu’il faut toujours faire avant de toucher à une mémoire qu’on ne pourra pas racheter : une sauvegarde complète. 8 Ko, 256 blocs de 32 octets (un octet, c’est huit bits, la plus petite unité de mémoire), lus un par un et rangés dans un fichier (le voici, si le vôtre est le même pack). Si une écriture tourne mal, on peut tout remettre.

Puis on a tenté la chose la plus bête du monde. Le manuel documente une commande 0x0041 : Reset — redémarrage de la puce : sa mémoire vive (la mémoire de travail, effacée à chaque redémarrage) est reconstruite depuis la flash, rien n’est écrit. L’équivalent de « tu as essayé de l’éteindre et de le rallumer ? ». Une lettre r envoyée sur le moniteur série, trois secondes d’attente :

>>> Envoi MAC 0x0041 Reset
ChargingCurrent    : 1500 mA
ChargingVoltage    : 16800 mV
RSOC               : 97 %
FET DSG ON, FET CHG ON, PF inactif

Victoire, a-t-on cru. Pack remonté, robot posé sur sa base : plus d’erreur, il charge, il annonce qu’il est prêt. J’ai écrit une première version de ce billet le soir même, avec une conclusion triomphante sur le compteur de cycles dont « le robot ne s’était jamais soucié ».

Le lendemain matin, voyant rouge, erreur 4202.

Le symptôme qui disparaît quand on le regarde

Pack rebranché sur l’ESP32. ChargingCurrent : 0 mA, à nouveau. Redémarrage : 1500 mA. Et là, au lieu de crier victoire, on a laissé tourner et on a regardé l’horloge.

À 3 secondes : 1500 mA. À 20 secondes : 1500 mA. À 31 secondes : 0 mA — et dans le même relevé, un drapeau qui n’y était pas dix secondes plus tôt : SLEEP. Deux essais, deux relevés complets comparés ligne à ligne : entre 20 et 31 secondes, la seule chose qui change, c’est ce drapeau.

La jauge s’endort. Dès qu’il ne circule presque aucun courant (moins de 10 mA, seuil réglé dans sa configuration), elle passe en veille pour économiser ses cellules, et dans cet état elle annonce « courant de charge : 0 ». Le redémarrage ne réparait rien : il la réveillait trente secondes. Sur l’établi, avec un ESP32 qui ne consomme rien, elle se rendormait aussitôt. Dans le robot, qui tire quelques centaines de milliampères, elle est éveillée et annonce 1500 mA. Le « ne me charge pas » n’a jamais été le problème. C’était un mirage de laboratoire.

Le laboratoire du lendemain : sur un canapé, le pack Neato sous ruban kapton jaune relié par trois fils à un ESP32-C3, lui-même branché en USB à un ordinateur portable dont l'écran affiche les relevés de la jauge

Le laboratoire du lendemain matin : un canapé, le pack sous kapton (le ruban adhésif jaune qui isole et résiste à la chaleur), l’ESP32 au bout de trois fils, et un terminal qui compare les relevés à dix secondes d’intervalle.

C’est une leçon que je connaissais et que j’ai quand même dû réapprendre : quand un symptôme disparaît au moment où on l’observe, c’est probablement l’observation qui l’a fait disparaître. Il faut regarder ce qui revient, pas ce qui part.

Pour aller au fond : la configuration de veille, et une doc imprécise

Dans la flash, DA Configuration (0x4A7D) vaut 0x001F : quatre cellules, NR = 1 (pack déclaré non amovible), IN_SYSTEM_SLEEP = 1 et SLEEP = 1. Sleep Current (0x48A3) = 10 mA, Bus Timeout = 5 s. Le TRM (§ 4.12, table des conditions de ChargingVoltage() = 0) ne prévoit la mise à zéro en veille que si FET Options[SLEEPCHG] = 0 ; ici FET Options (0x4887) vaut 0x7D, donc SLEEPCHG = 1, et le transistor de charge reste d’ailleurs bien passant en veille. La mise à zéro de ChargingCurrent() / ChargingVoltage() se produit quand même. Le comportement réel a le dernier mot sur la doc — raison de plus pour mesurer.

Cette configuration est celle d’usine, elle n’a pas bougé : le robot a toujours vécu avec une jauge qui s’endort à la moindre pause. Le Neato la réveille simplement en consommant.

Le compteur

Restait le suspect initial, celui que l’application avait nommé : 1547 cycles. La jauge, elle, s’en moque — la dégradation par cycles est désactivée, on l’a vérifié. Mais le robot lit ce nombre (CycleCount, commande 0x17), et un logiciel embarqué (un firmware : le programme gravé dans le robot) qui affiche « compteur de charge dépassé » a forcément un seuil quelque part.

Le compteur est une simple valeur sur deux octets en flash, à l’adresse 0x4340. En Full Access, on l’écrit comme on l’a lue : une commande de bloc, l’adresse, deux octets. On a écrit zéro.

>>> CycleCount SBS avant = 1547 ; écriture DF 0x4340 = 0
>>> relecture 0x4340 : 00 00  (OK)
>>> CycleCount SBS après écriture = 0

Immédiat, sans redémarrage, aucun drapeau de sécurité levé. Une batterie neuve, aux yeux de qui ne regarde que ce nombre.

Pour aller au fond : écrire dans la data-flash

TRM § 14.1.67 : une écriture flash est un SMBus block write (l’envoi d’un paquet d’octets d’un coup) sur la commande 0x44, dont le bloc est l’adresse de départ (petit-boutiste : l’octet de poids faible d’abord) suivie de 1 à 32 octets de données. Pour CycleCount = 0 : 0x44, longueur 4, 0x40 0x43 0x00 0x00. On relit ensuite le bloc (block write de l’adresse seule, puis block read de 0x44, qui renvoie l’adresse et 32 octets) pour vérifier. La valeur SBS 0x17 a suivi sans redémarrage. La commande C du sketch remet 0x0B 0x06 (1547) si l’on veut revenir en arrière.

Ce qu’on n’a pas touché, et pourquoi : Qmax (la capacité chimique des cellules telle que la jauge l’a apprise, 0x4306…0x430E, cinq fois 2650 mAh) et la table de résistances internes datent des cellules d’origine ; Design Capacity (0x48E5) vaut 2500 mAh ; l’état de santé que la jauge annonce (FullChargeCapacity / DesignCapacity) oscille donc entre 73 % et 92 % selon l’heure. On pourrait tricher en baissant Design Capacity, ou forcer Qmax. On a préféré laisser la jauge réapprendre honnêtement sur des cycles complets — voir ci-dessous. La carte complète de la flash, décodée, est ici.

Le rebondissement

Le 1er septembre au soir, voyant rouge. Erreur 4202. Le robot avait tenu une journée.

Troisième fois que le scénario se joue : on touche au pack, on le rebranche, le robot repart, et le lendemain il s’arrête. Le redémarrage de la jauge avait « marché » un soir ; le compteur à zéro, un jour et quelques cycles. Vu de près, ces deux « victoires » ont un point commun qui n’est pas la correction : à chaque fois, on a débranché puis rebranché le pack. Le robot redémarre, oublie son état « batterie déchargée », réessaie — et retombe sur la même cause, qu’on n’avait pas trouvée.

Cette fois, avant tout redémarrage, pack sur l’ESP32 tel quel. Compteur de cycles : toujours 0. Aucune protection active, aucun défaut permanent, jauge en pleine forme — le même relevé rassurant que le premier soir. Sauf qu’on avait appris à se méfier des relevés rassurants, et on est allé lire une zone de la flash qu’on n’avait jamais décodée : les données de vie (Lifetimes), le journal que la jauge tient sur elle-même depuis sa sortie d’usine — tensions extrêmes vues par chaque cellule, nombre de fois où chaque protection s’est déclenchée, et à quel cycle pour la dernière.

Comparée à la sauvegarde du 29 août, elle disait ceci :

                          29 août      1er septembre
COV (surtension cellule)  6            246   (+240 en trois jours)
Vmax à vie, cellule 4     4213 mV      4293 mV   (seuil COV : 4225)
Fins de charge valides    21813        21813 (aucune depuis le recellage)
Cellules au repos         —            3986 / 3986 / 3995 / 3939 mV

Deux cent quarante déclenchements de la protection de surtension en trois jours, tous sur la cellule 4 — et pas une seule charge menée à son terme. Le pack d’origine en avait connu six en quatre ans.

L’explication tient en une image. Quatre cellules en série, c’est quatre seaux qu’on remplit par le même tuyau : si l’un est plus petit, il déborde le premier. La cellule 4 de mon jeu de récupération a moins de capacité que les trois autres — au repos elle est la plus basse (3,94 V contre 3,99), et en charge elle est la première à franchir 4,225 V. La jauge fait alors son travail : elle coupe le transistor de charge, attend que la cellule redescende à 4,1 V, rouvre, recoupe une seconde plus tard. Deux cent quarante fois. Le chargeur du robot, lui, voit une charge qui ne se termine jamais ; au bout d’un moment, son firmware en tire la seule conclusion qu’il connaît : « batterie déchargée », 4202.

Le compteur de cycles n’y était pour rien — ou pas pour tout. Pour le pack d’origine, on ne le saura pas : j’ai changé deux choses à la fois. Ses données de vie, elles, montrent 67 sous-tensions, la dernière au 1547ᵉ cycle ; la cellule à 41 mΩ qui s’affaissait en pleine aspiration est une explication au moins aussi bonne que le compteur. Le code 4202 est un fourre-tout.

La nouvelle tentative. La solution propre, c’est de passer les quatre cellules de récupération au testeur, comme les originales, et de remonter un pack avec les quatre cellules les mieux appariées parmi les huit. En attendant, la jauge permet un palliatif sans fer à souder, toujours par les trois fils — et c’est ce qu’on a fait le soir même :

  • tension de charge abaissée de 4200 à 4100 mV par cellule : le pack s’arrête à 16,4 V au lieu de 16,8 ; la cellule 4 reste sous le seuil de surtension, et on perd environ 10 % d’autonomie ;
  • capacité de référence ramenée à 2100 mAh (elle était restée à 2500, celle du pack neuf), capacité chimique des cellules alignée dessus ;
  • jauge remise en mode apprentissage : ses valeurs apprises (capacité chimique, table de résistances) dataient des cellules de 2022 ; un bit lui dit de tout réapprendre sur les prochains cycles.

Redémarrage : la jauge annonce 16 400 mV et 1500 mA, une capacité à pleine charge estimée à 1792 mAh, aucun défaut. Pack refermé, robot sur sa base. Cette fois, on ne crie pas victoire : on attend quelques jours, et on rouvrira le journal de la jauge. Si le compteur de surtensions est toujours à 246, c’était ça.

Pour aller au fond : les données de vie, et ce qu'on a écrit

La zone Lifetimes occupe la flash de 0x4380 à 0x43F7 (TRM ch. 18) : tensions min/max de chaque cellule (0x4380), puis pour chaque protection un compteur d’événements et le compteur de cycles au dernier événement — COV en 0x43A0/0x43A2, CUV en 0x43A4/0x43A6, etc. —, puis les fins de charge valides (0x43D0), les mises à jour Qmax/Ra (0x43D4…), le temps de fonctionnement. Le seuil COV est en 0x494E (4225 mV ici, délai 1 s, recovery 4100 mV en 0x4959).

Écritures du 1er septembre, toutes relues après coup : tension de charge par cellule dans les cinq régions de température de l’algorithme de charge (0x4A19, 0x4A21, 0x4A29, 0x4A31, 0x4A39 : 4200 → 4100) ; Design Capacity 0x48E5 = 2100 mAh et 0x48E7 = 3024 cWh ; Qmax cellules 1–4 et pack 0x4306–0x430E = 2100 ; Qmax Cycle Count 0x4310 = 0 ; Update Status 0x4312 = 0x04 (Impedance Track actif, « pas encore appris » : la jauge refera Qmax puis la table Ra sur les prochains cycles, TRM 15.13.8.2 et 6.4.6) ; puis reset 0x0041. Vérifié avant d’écrire : les drapeaux « pleine charge » (FC/TC) sont posés ici par la terminaison de charge valide (courant sous 130 mA, cellule à moins de 75 mV de la tension de charge), pas par un seuil fixe à 4200 mV — baisser la tension ne les casse pas. Marge sur la cellule 4 : une trentaine de millivolts sous le seuil ; le sketch a une commande pour descendre à 4050 si ça ne suffit pas. Commandes : v/w/V (tension 4100 / 4050 / 4200), d/D (capacité et apprentissage / valeurs d’usine).

Où on en est

État au 1er septembre 2026 : en observation. L’erreur 4202 est revenue le 1er septembre après une journée de fonctionnement ; la cause réelle est une cellule de récupération plus faible qui déclenchait la protection de surtension à chaque charge, 240 fois en trois jours (voir Le rebondissement). Palliatif appliqué le soir même par les trois fils : tension de charge 4100 mV par cellule, capacité de référence 2100 mAh, jauge en réapprentissage. Le robot est sur sa base ; verdict dans quelques jours, en rouvrant le journal de la jauge — si le compteur de surtensions n’a pas bougé, c’était ça. Toujours aucune pièce achetée.

Et puis il y a l’épilogue que je n’avais pas vu venir. Les quatre cellules d’origine, celles que j’avais dessoudées au début parce que « la batterie était morte », traînaient sur l’établi. Par acquit de conscience, je les ai mesurées : 3,6 V chacune. Aucune n’est en dessous du seuil où une cellule lithium se condamne. Je les ai donc passées au testeur de capacité — un Liitokala Lii-500, un chargeur-analyseur d’une trentaine d’euros, en mode « NOR TEST » : il charge la cellule à fond, la décharge ensuite à courant constant en comptant les milliampères-heures qui sortent, puis la recharge. C’est la seule façon honnête de savoir ce que vaut une cellule : la vider en la chronométrant.

Verdict, sur des cellules données pour 2500 mAh neuves :

Cellule Capacité mesurée Part du nominal
A 1916 mAh 77 %
B 1912 mAh 76 %
C 1855 mAh 74 %
D 1819 mAh 73 %

Le testeur donne aussi la résistance interne de chaque cellule — la « friction » électrique du chimique, en milliohms (mΩ) : plus elle est élevée, plus la tension s’effondre quand le robot tire du courant, et plus la cellule chauffe au lieu de fournir. Trois cellules oscillent entre 16 et 19 mΩ, ce qui est bon pour des 18650 de cet âge. La quatrième est à 41 mΩ : plus du double. C’est le maillon faible du pack — celui qui s’affaisse le premier en pleine aspiration, entraîne les autres vers le seuil de coupure et donc écourte l’autonomie bien plus que ses 1819 mAh ne le laissent croire.

Mais aucune n’est morte. Après quelque chose comme 1547 cycles, ces cellules rendent encore les trois quarts de leur capacité d’origine : une perte normale, celle qu’on attend d’un lithium arrivé au bout de sa vie annoncée. Concrètement, l’autonomie serait passée de la pleine heure et demie à un peu plus d’une heure. Un aspirateur un peu moins endurant — pas un aspirateur mort.

C’est là que l’histoire prend son sens. Le pack qui a déclenché tout ça n’était pas défaillant : il était usé de 25 %, et quelque chose — un compteur, ou plus probablement sa cellule à 41 mΩ qui s’affaissait en pleine aspiration — a décidé que c’était fini. Le recellage que j’ai fait au premier réflexe n’était probablement pas nécessaire, et fait avec des cellules de récupération jamais mesurées, il a ajouté un problème (voir Le rebondissement) ; il m’aura au moins laissé quatre cellules d’origine en état de marche, mesurées, tracées, prêtes à servir de rechange le jour où celles de récupération lâcheront.

Ce que ça m’aurait coûté il y a trois ans

Soyons honnêtes sur la marche que j’ai franchie sans la voir.

Il y a trois ans, cette histoire se serait arrêtée au paragraphe « Premier réflexe : les cellules ». Cellules changées, erreur toujours là, multimètre formel : la batterie est bonne. Et ensuite ? Ensuite, un cul-de-sac. J’aurais cherché sur les forums, trouvé les mêmes fils que tout le monde — « il faut un EV2400 et bqStudio », « la puce est verrouillée », « achetez une batterie » — et j’aurais soit acheté, soit rangé le robot dans un placard en attendant un courage qui ne vient jamais.

Car la suite de la démarche, qui tient ici en quelques paragraphes, représente un travail que je n’aurais pas pu fournir en soirées de bricoleur. Mettons-le à plat :

  1. Identifier la puce et trouver son manuel : facile.
  2. Lire le manuel : 250 pages, 17 000 lignes en anglais technique dense, écrites pour des ingénieurs batterie qui en connaissent déjà le vocabulaire. Il ne s’agit pas de le survoler : il faut y trouver les trois tables qui disent quand le courant de charge tombe à zéro, la procédure d’écriture de la flash, la carte des 400 adresses de configuration, la signification de chaque bit d’une dizaine de registres d’état.
  3. Apprendre le SMBus au niveau du protocole (le block read, le block write, la commande 0x44 et son écho, l’auto-incrément d’adresse) et écrire un programme qui le parle sans erreur.
  4. Interpréter un relevé de quarante drapeaux et 8 Ko d’octets bruts, en les croisant avec le manuel.
  5. Concevoir les expériences : le redémarrage, puis — après le faux espoir — l’idée de comparer deux relevés complets à dix secondes d’intervalle pour isoler la ligne qui change.
  6. Écrire dans la flash sans rien casser.

Pour un développeur compétent qui n’est pas ingénieur batterie, c’est plusieurs semaines de soirées, avec un vrai risque d’abandon au point 2 — et c’est exactement là que s’arrêtent les fils de forum. Ce n’est pas que ce soit difficile au sens intellectuel ; c’est que c’est long, et que rien ne garantit, au départ, que ces semaines mènent quelque part.

Avec Claude, les points 2 à 6 ont pris deux soirées et une matinée. L’IA a absorbé le manuel en quelques secondes, écrit le sketch en une passe, décodé les registres à mesure qu’ils arrivaient, proposé le redémarrage, puis — quand le redémarrage a menti — proposé de le refaire en enregistrant tout, et trouvé le drapeau SLEEP dans la comparaison. Ce que je gardais, moi : le fer à souder, le multimètre, les photos, les décisions (« on ne touche pas à Qmax, on laisse apprendre »), et surtout le doute : c’est le test d’une nuit dans le vrai robot qui a démenti la victoire, pas une lecture de plus.

Deux nuances, pour ne pas en faire un conte. D’abord, l’IA a co-signé le faux espoir : elle avait la même fausse conclusion que moi le premier soir, parce qu’on avait les mêmes données incomplètes. Elle lit vite, elle ne mesure pas à ma place. Ensuite, elle a trouvé une erreur dans le manuel lui-même (la veille qui met le courant à zéro alors que la doc dit le contraire) uniquement parce qu’on a mesuré le contraire ; sans l’ESP32 branché, elle aurait défendu la doc.

Mais le déplacement est réel, et il me semble important pour la réparation en général : un savoir qui était enfermé dans un manuel de 250 pages, donc réservé aux professionnels, devient accessible à quelqu’un qui sait tenir un fer à souder et poser une question. Les fabricants comptent, sans le dire, sur le fait que personne ne lira le manuel. Cette hypothèse vient de tomber.

Focus : le bq40z50, la puce qui gère votre batterie

Puisqu’on a passé deux jours avec elle, présentons-la. Le bq40z50-R2 est ce que Texas Instruments appelle un battery pack manager : une seule puce, de la taille d’un ongle (boîtier QFN de 32 broches, les contacts sont sous le boîtier), qui fait tout ce qu’un pack lithium de 1 à 4 cellules en série a besoin de faire. On la trouve dans une grande partie des batteries d’ordinateurs portables des dix dernières années, dans des outils électroportatifs, des robots, des drones, des batteries médicales.

Ce qu’elle fait

  • Jauger : elle mesure le courant à travers une résistance de mesure (un shunt, quelques milliohms) et la tension de chaque cellule, et en déduit l’état de charge par un algorithme maison, Impedance Track : au lieu de simplement compter ce qui entre et sort (ce qui dérive avec le temps), elle apprend la capacité chimique réelle des cellules (Qmax) et leur résistance interne à chaque cycle, et corrige en permanence. C’est ce qui donne les pourcentages précis des portables récents.
  • Protéger : elle intègre l’AFE (analog front-end : la partie analogique qui surveille les tensions et les courants en temps réel, indépendamment du logiciel) et pilote directement les transistors de charge et de décharge. Surtension et sous-tension par cellule, surintensité en charge et en décharge, court-circuit, surchauffe et sous-température, chacune avec ses seuils, ses délais et ses conditions de retour à la normale.
  • Se condamner : une seconde famille de protections, les défauts permanents (PF), coupe définitivement le pack — au besoin en faisant fondre un fusible chimique irréversible — en cas de cellule ouverte, de déséquilibre incorrigible, de transistor grillé ou de trop de surtensions répétées.
  • Équilibrer : pendant la charge, elle décharge légèrement les cellules en avance pour que toutes arrivent pleines ensemble.
  • Se souvenir : compteur de cycles, températures et tensions extrêmes vues au cours de sa vie (lifetime data), et une boîte noire qui enregistre les derniers événements de sécurité avant un défaut permanent — de quoi faire l’autopsie d’un pack mort.
  • Parler : SMBus, tout le standard SBS, plus les commandes du fabricant. Et s’authentifier : un mécanisme cryptographique (SHA-1 avec une clé secrète) permet à l’appareil de vérifier que le pack est d’origine. C’est ce qui bloque les batteries compatibles sur certains appareils.

Ses points forts

  • Complète et documentée. Tout est dans un seul boîtier, et le manuel décrit tout : c’est ce qui a rendu cette enquête possible. Beaucoup de puces concurrentes sont documentées sous accord de confidentialité, ou pas du tout.
  • Précise. Impedance Track reste la référence en jauge grand public ; l’erreur d’estimation descend à 1 % sur un pack bien configuré.
  • Sûre par construction. L’AFE protège même si le logiciel plante ; les défauts permanents ne se négocient pas.
  • Ubiquitaire. Des dizaines de millions d’exemplaires dans des packs de portables : les cartes, les fichiers de configuration et les retours d’expérience abondent.
  • Ouvrable. Le logiciel officiel bqStudio et l’adaptateur EV2400 existent, mais comme on l’a vu, un microcontrôleur à deux euros suffit à lire, et souvent à écrire.

Ses points faibles

  • Complexe à configurer. Plus de 400 paramètres en flash. Faire fonctionner correctement Impedance Track demande une « image de référence » (golden image) construite en laboratoire : identification de la chimie des cellules, calibration, cycle d’apprentissage complet. Un pack DIY mal configuré jauge mal, et l’apprentissage que nous avons choisi prend plusieurs cycles.
  • La sécurité dépend du fabricant du pack. TI fournit les serrures ; c’est l’assembleur qui choisit de les fermer. Le pack Neato a été livré en Full Access. Une batterie de portable de marque, elle, est presque toujours scellée, et sans les clés on ne lit que les registres standards.
  • La sécurité, à l’inverse, peut être un mur. L’authentification SHA-1 et le scellement sont précisément ce qui rend certains packs irréparables : un défaut permanent sur un pack scellé, c’est une poubelle, quel que soit l’état des cellules.
  • Pas plus de 4 cellules en série. Pour un vélo électrique (10 à 13 cellules en série) il faut son grand frère bq40z80 (jusqu’à 7 en série) ou une autre architecture.
  • Difficile à câbler soi-même. Le boîtier QFN se soude au four ou à l’air chaud, pas au fer ; les cartes de développement TI coûtent une centaine d’euros. En pratique, le DIY passe par des cartes récupérées.

Ce qu’on peut en faire, hors Neato

  • Diagnostiquer une batterie de portable avant de la jeter. Un pack Dell, HP ou Lenovo « mort » contient très souvent un bq40z50 (ou un cousin : bq30z55, bq40z80) et six cellules dont trois vont bien. L’ESP32 et le sketch de ce billet lisent l’état de santé, le compteur, les défauts, et disent si ce sont les cellules ou la puce. Sur un pack scellé on lit moins, mais on lit.
  • Réarmer un pack après recellage. Exactement ce billet : compteur, éventuellement défaut permanent (PFStatus se remet à zéro par commande, en Full Access ou avec la clé), puis cycle d’apprentissage.
  • Construire une « batterie intelligente » pour ses propres projets. Une carte BMS de récupération avec son bq40z50, quatre cellules 18650 neuves, et l’on obtient un pack 14,4 V qui s’auto-protège, s’équilibre et annonce son pourcentage : pour un robot DIY, une radio de terrain, un onduleur de secours pour un serveur domestique, une lampe de chantier.
  • Surveiller une batterie à distance. L’ESP32 a le Wi-Fi : le même sketch peut publier tension, courant, température et état de charge en MQTT (un protocole de messages léger, le standard de la domotique) vers Home Assistant ou une base de données. Un pack qui prévient avant de lâcher.
  • Apprendre. Le bq40z50 est un cours complet de gestion de batterie lithium, avec un manuel gratuit et une puce qu’on trouve dans les poubelles. Tout ce que fait un BMS de voiture électrique, il le fait en petit, et il se laisse regarder faire.

Une réserve : tout ceci suppose un pack ouvert (non scellé) ou dont on a les clés. Les fabricants de portables scellent ; les fabricants de packs pour robots, outils et jouets, souvent, oublient. Vérifiez avant de vous lancer — c’est la première lecture, et elle ne coûte rien.

Ce que ça raconte

Je ne crois pas que quelqu’un, chez Neato ou chez son fournisseur de batteries, ait décidé que ce robot mourrait en 2026. Je crois pire : personne n’a décidé qu’il vivrait.

Regardez les couches.

Le cloud. Le robot a été conçu pour ne rien faire sans un serveur. Quand le serveur s’éteint, il ne reste que le bouton. Sur les D3 à D7, une communauté a réussi à brancher un ESP32 sur le port série de la carte mère et à rendre aux robots leur autonomie (vacuula/fang, OpenNeato). Sur les D8 à D10, ce port est verrouillé par mot de passe. Une génération plus tard, la porte a été fermée à clé. Pas pour la sécurité de l’utilisateur — pour rien, apparemment, sinon pour qu’il n’y touche pas.

La batterie authentifiée. Le robot vérifie l’identité du pack. Les forums sont pleins de D5 bloqués après qu’on y a inséré une batterie compatible. Le fabricant appelle ça de la sécurité ; c’est aussi, très concrètement, un péage sur la pièce d’usure numéro un.

Le compteur. 1547 cycles, et une application qui dit « à remplacer ». Non pas parce que la batterie serait hors d’usage — la jauge elle-même la donnait chargée à 97 %, et les cellules d’origine, mesurées depuis, rendent encore 73 à 77 % de leur capacité neuve — mais parce qu’un nombre a franchi un seuil que personne ne vous montre. Le robot a été mis à l’arrêt pour un quart d’autonomie en moins.

Et l’absence de chemin. Une puce parfaitement documentée, laissée en accès total, dont le compteur se remet à zéro en une commande. Aucun chemin, dans le produit, ne mène à cette commande. Le diagnostic livré à l’utilisateur est « batterie déchargée », qui est faux, et la solution proposée est « acheter », qui est chère.

L’obsolescence, ici, n’est pas une bombe à retardement programmée par un ingénieur cynique. C’est une somme de non-décisions : personne n’a budgété la fonction « réinitialiser la batterie », personne n’a écrit le message d’erreur honnête, personne n’a laissé un port ouvert. Chaque choix se justifie individuellement. Leur somme fabrique un déchet de 600 € avec une batterie chargée dedans.

La bonne nouvelle, c’est que les mêmes non-décisions laissent des failles. La puce n’a pas été verrouillée. Le fabricant du pack a laissé ses pastilles de test. TI publie son manuel. Et un microcontrôleur à deux euros, plus une IA qui accepte de lire 17 000 lignes de documentation sans se plaindre, suffisent à s’engouffrer dedans.

À partir du 18 février 2027, l’article 11 du règlement européen sur les batteries (extrait local) imposera que les batteries portables des appareils soient « readily removable and replaceable by the end-user ». C’est un progrès. Mais cette histoire montre que « remplaçable » ne suffit pas : ma batterie était remplaçable, et c’est précisément le remplacement qu’on me vendait comme seule issue. Ce qu’il faudrait exiger, c’est que les objets disent la vérité sur leur état, et qu’ils laissent un chemin pour le corriger. Un bouton « réinitialiser la batterie » dans une application, ça coûte une après-midi de développement. Le silence, lui, coûte une batterie à chaque client.

Pour reproduire

Matériel : un ESP32-C3 Super Mini (ou n’importe quel ESP32/Arduino avec I²C), trois fils, un fer à souder, éventuellement deux résistances de 4,7 kΩ. Le pack doit être ouvert au niveau de sa carte électronique — la gaine est collée, un cutter la fend sans forcer.

Sécurité : les cellules restent connectées pendant toute l’opération. Pas d’outil métallique près des pastilles C+ et C−, qui portent 16 V et plusieurs dizaines d’ampères de court-circuit possible. Pas de bracelet, pas de bague. Les pastilles DA et CL, elles, sont à 3,3 V et ne risquent rien.

L'autre face de la carte du pack : les pastilles de test T1, T3, T6, T7 et HEAT, le fil rouge du plus et le fil noir du moins

L’autre face de la carte : on n’y touche pas, mais elle montre que le fabricant a prévu bien plus de points de test que les deux qui nous intéressent.

Câblage :

Pack (carte BMS) ESP32-C3
Pastille DA GPIO 4 (SDA)
Pastille CL GPIO 5 (SCL)
Fil noir (− cellules) G (GND)

Logiciel : bq40z50-reader.cpp et platformio.ini (PlatformIO est l’outil qui compile et téléverse le programme ; cadre Arduino, cible esp32-c3-devkitm-1). Moniteur série à 115200 bauds. Les registres essentiels, à l’adresse SMBus 0x0B :

Registre Contenu
0x09 / 0x0A tension / courant du pack
0x0D état de charge (RSOC, %)
0x10 / 0x18 capacité à pleine charge / capacité nominale
0x14 / 0x15 courant / tension de charge demandés (0 en veille : normal)
0x17 compteur de cycles
0x3C–0x3F tensions des cellules 4 à 1
0x44 + 0x0054 OperationStatus (sécurité, FETs, PF, SLEEP)
0x44 + 0x0053 PFStatus (défauts permanents)
0x00 ← 0x0041 redémarrage de la jauge
0x44 ← 0x40 0x43 + 2 octets écriture du compteur de cycles (flash 0x4340)
0x44 ← 0x80 0x43 … 0xE0 0x43 lecture des données de vie (flash 0x4380–0x43FF) : compteurs COV/CUV, fins de charge
0x44 ← 0x19 0x4A + 2 octets (×5) tension de charge par cellule (flash 0x4A19…0x4A39)

Dans l’ordre : (1) brancher, lire, vérifier que DeviceType répond 0x4500 et que le niveau de sécurité est Full Access — sinon il faudra les clés du fabricant, et ce billet ne les a pas ; (2) sauvegarder la flash (le sketch le fait au démarrage) et mettre le fichier à l’abri ; (3) lire PFStatus et SafetyStatus — un défaut permanent est une autre histoire ; (4) lire les données de vie (0x4380…) et les comparer à la sauvegarde après quelques jours dans le robot : un compteur COV ou CUV qui grimpe désigne une cellule, pas un compteur ; (5) seulement alors, taper c — et attendre plusieurs jours avant de conclure.

Trois règles, si vous vous y mettez : lire d’abord, tout sauvegarder ensuite, n’écrire qu’en dernier. Une jauge en Full Access se laisse aussi bien réparer que détruire.

Questions fréquentes

Que signifie l’erreur 4202 sur un Neato ?

C’est l’erreur « batterie déchargée » des D8, D9, D10 et D800. L’application (quand elle fonctionnait) précisait que le compteur de charge de la batterie était dépassé et qu’il fallait la remplacer. Elle apparaît même avec des cellules en parfait état : ce qui la déclenche, c’est ce que la puce du pack raconte au robot — en particulier, d’après ce que nous avons observé, un compteur de cycles trop élevé.

Changer les cellules du pack règle-t-il l’erreur 4202 ?

Pas à lui seul. Le compteur de cycles et l’état de santé vivent dans la puce bq40z50 du pack, pas dans les cellules. Après recellage, l’erreur persistait chez moi avec des cellules à 4,1 V.

Faut-il un EV2300/EV2400 et bqStudio pour parler à la jauge ?

Non. Un ESP32 (ou un Arduino) avec deux broches I²C, trois fils et le manuel TI suffisent : la puce est documentée, et sur les packs Neato que j’ai vus elle est laissée en Full Access, sans mot de passe. bqStudio est plus confortable, pas nécessaire.

Une batterie compatible du commerce résout-elle le problème ?

Parfois, et parfois le robot la refuse — les forums documentent des D5 bloqués après l’insertion d’un pack compatible. Avant d’acheter, il coûte une soirée de vérifier que la batterie d’origine n’est pas simplement passée un seuil de cycles.

Est-ce dangereux ?

Les lignes DA et CL sont à 3,3 V et sans risque. Le danger est ailleurs : les pastilles C+/C− et B+/B− à 16 V, capables de dizaines d’ampères en court-circuit. Un seul outil métallique à la fois, pas de bijoux, et on ne touche à rien d’autre que DA, CL et le moins.

Pourquoi la jauge annonce-t-elle 0 mA de courant de charge ?

Parce qu’elle dort. Dès que le courant passe sous 10 mA pendant une trentaine de secondes, elle entre en veille et met ChargingCurrent et ChargingVoltage à zéro. Dans le robot, qui consomme en permanence, elle reste éveillée. Ce n’est pas une panne, et un redémarrage ne « répare » rien : il la réveille trente secondes.

Est-ce que ça marche sur un D3, D4, D5, D6 ou D7 ?

Les packs de ces générations utilisent une puce différente, verrouillée, et les recherches communautaires n’ont pas abouti. En revanche, leur port série est ouvert, et vacuula/fang ou OpenNeato rendent à ces robots leur autonomie sans le cloud.

Peut-on réutiliser la puce bq40z50 d’une vieille batterie dans un autre projet ?

Oui, si le pack n’est pas scellé ou si l’on a ses clés. Une carte BMS de récupération avec ses cellules remplacées fait une batterie intelligente 1S à 4S pour un robot, une radio ou un onduleur DIY ; un ESP32 branché dessus peut publier son état en MQTT vers la domotique. Voir la section « Focus : le bq40z50 ».

Qu’a fait l’IA exactement, et qu’a fait l’humain ?

Claude a lu le manuel de 250 pages, écrit le programme de lecture, décodé les registres, proposé le redémarrage puis l’expérience de comparaison qui a révélé le mode veille, et rédigé ce billet avec moi. J’ai soudé, mesuré, photographié, décidé de ne pas toucher à Qmax, et laissé le robot passer une nuit sur sa base — ce qui a démenti la première conclusion, la sienne comme la mienne.

Le robot est-il réparé ?

Pas encore de façon certaine. La remise à zéro du compteur (30 août) lui a rendu une journée, puis l’erreur 4202 est revenue : la cause réelle était une cellule de récupération plus faible qui déclenchait la protection de surtension à chaque charge. Correctif appliqué le 1er septembre (tension de charge 4100 mV par cellule, réapprentissage de la jauge), en observation. Toujours aucune pièce achetée. Voir Où on en est.

Petit glossaire

  • Cellule : l’accumulateur élémentaire, ici au format 18650 (18 mm × 65 mm). Un pack en assemble plusieurs.
  • BMS (battery management system) : la carte électronique du pack, qui protège, équilibre et jauge les cellules. Ici, elle est construite autour du bq40z50.
  • Jauge (gas gauge) : la puce qui compte ce qui entre et sort de la batterie et en déduit l’état de charge.
  • Puce / circuit intégré : un ordinateur ou un circuit complet gravé sur quelques millimètres de silicium.
  • Microcontrôleur : un petit ordinateur complet sur une puce, programmable ; l’ESP32-C3 en est un.
  • Bus série / SMBus / I²C : deux fils (données et horloge) sur lesquels des puces échangent des messages numériques ; SMBus est la variante utilisée par les batteries.
  • Adresse, registre, commande : le numéro d’une puce sur le bus, une case de mémoire qu’on peut lire, le numéro qui la désigne. 0x… : nombre écrit en hexadécimal.
  • Bit, octet : la case élémentaire (0 ou 1) et le groupe de huit ; un drapeau est un bit qui signale un état.
  • Firmware : le programme gravé dans un appareil. Flash : la mémoire qui survit à l’extinction ; mémoire vive : celle de travail, effacée au redémarrage.
  • Cycle : une décharge cumulée équivalant à 90 % de la capacité (seuil réglable). Le compteur ne fait qu’additionner.
  • RSOC : état de charge relatif, le « pourcentage de batterie » ; FCC : capacité à pleine charge, telle que la jauge l’estime ; Qmax : capacité chimique apprise des cellules ; mAh : milliampère-heure, unité de quantité d’énergie stockée.
  • Résistance interne : la « friction » électrique d’une cellule, en milliohms (mΩ). Plus elle est haute, plus la tension chute sous charge et plus la cellule chauffe ; elle monte avec l’âge et trahit une cellule fatiguée avant que sa capacité ne s’effondre.
  • FET / transistor : interrupteur électronique par lequel la jauge autorise ou coupe la charge et la décharge.
  • Pull-up : résistance qui maintient une ligne de bus à 3,3 V quand personne ne parle.
  • PF (Permanent Failure) : un défaut que la jauge juge irrécupérable ; elle se condamne et rien ne l’efface. Il n’y en avait pas.
  • COV / CUV (Cell Over-/Under-Voltage) : protections de surtension et de sous-tension par cellule. La jauge coupe la charge (COV) ou la décharge (CUV), rouvre quand la tension revient dans la plage, et compte chaque déclenchement dans ses données de vie.
  • Impedance Track : l’algorithme de TI qui apprend la capacité et la résistance des cellules pour jauger précisément.
  • Full Access / Unsealed / Sealed : les trois niveaux d’accès à la puce, du plus ouvert au plus fermé.

Références et copies locales

Pour que ce billet reste utile quand les liens auront disparu, les documents cités sont hébergés ici, avec leur source d’origine.

Photos et mesures : les miennes. Lecture du manuel, code et rédaction : avec Claude. Ce billet est aussi disponible en Markdown brut.