<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>BNO085 | Antoine Weill--Duflos</title>
    <link>https://antoine.weill-duflos.fr/fr/tag/bno085/</link>
      <atom:link href="https://antoine.weill-duflos.fr/fr/tag/bno085/index.xml" rel="self" type="application/rss+xml" />
    <description>BNO085</description>
    <generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>fr-fr</language><lastBuildDate>Sat, 30 May 2026 00:00:00 +0000</lastBuildDate>
    <image>
      <url>https://antoine.weill-duflos.fr/media/icon_hu_d686267daab28486.png</url>
      <title>BNO085</title>
      <link>https://antoine.weill-duflos.fr/fr/tag/bno085/</link>
    </image>
    
    <item>
      <title>Une pierre qui roule de poche, partie 1 : une illusion haptique de 2006, un ESP32-C6 et un ampli I2S</title>
      <link>https://antoine.weill-duflos.fr/fr/post/esp32-rolling-stone/</link>
      <pubDate>Sat, 30 May 2026 00:00:00 +0000</pubDate>
      <guid>https://antoine.weill-duflos.fr/fr/post/esp32-rolling-stone/</guid>
      <description>&lt;p&gt;















&lt;figure  id=&#34;figure-la-pièce-qui-rend-ce-montage-crédible--des-actionneurs-titan-haptics-ce-premier-montage-restitue-la-bille-virtuelle-en-audio-et-pilote-lun-deux-plus-de-détails-sur-eux-et-sur-ashley-huffman-qui-me-les-a-fait-parvenir-plus-bas&#34;&gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;Un boîtier en plastique transparent tenu dans une main, avec quatre petits actionneurs cylindriques noirs TITAN Haptics logés dans des découpes de mousse, chacun avec de fins fils rouge et noir&#34; srcset=&#34;
               /fr/post/esp32-rolling-stone/featured_hu_5845204be01c0e90.webp 400w,
               /fr/post/esp32-rolling-stone/featured_hu_d1077f3167290f3a.webp 760w,
               /fr/post/esp32-rolling-stone/featured_hu_cb24e0e4817501a0.webp 1200w&#34;
               src=&#34;https://antoine.weill-duflos.fr/fr/post/esp32-rolling-stone/featured_hu_5845204be01c0e90.webp&#34;
               width=&#34;573&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;figcaption&gt;
      La pièce qui rend ce montage crédible : des actionneurs TITAN Haptics. Ce premier montage restitue la bille virtuelle en audio et pilote l&amp;rsquo;un d&amp;rsquo;eux. Plus de détails sur eux, et sur Ashley Huffman qui me les a fait parvenir, plus bas.
    &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Celui-là m&amp;rsquo;accompagne depuis plusieurs années, pas depuis un week-end. L&amp;rsquo;idée est simple à énoncer et étonnamment difficile à arrêter de peaufiner : construire un petit objet à tenir en main qui vous laisse &lt;strong&gt;sentir une bille rouler et glisser dans un tube qui n&amp;rsquo;existe pas physiquement&lt;/strong&gt;. Vous inclinez le boîtier, et une bille virtuelle court d&amp;rsquo;un bout à l&amp;rsquo;autre, cogne la paroi, repart en arrière. Aucune masse mobile à l&amp;rsquo;intérieur. Toute la sensation est synthétisée.&lt;/p&gt;
&lt;p&gt;Tout a commencé au &lt;a href=&#34;https://eurohaptics.org/events/workshop-in-memoriam-of-vincent-hayward/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;colloque tenu en mémoire de Vincent Hayward&lt;/a&gt;, l&amp;rsquo;un des deux auteurs de l&amp;rsquo;article qui sert de base à ce projet. Assis là, j&amp;rsquo;ai réalisé que de cette belle démonstration il ne restait, autant que je sache, qu&amp;rsquo;un seul exemplaire en état de marche dans le monde. Ça m&amp;rsquo;a dérangé. J&amp;rsquo;étais à peu près sûr de connaître un bon actionneur capable aussi de produire un impact net, et qu&amp;rsquo;un matériel très minimal suffirait à ramener l&amp;rsquo;illusion à la vie. Ce qui me manquait, pendant des années, c&amp;rsquo;était le temps : entre un travail à plein temps et les devoirs de parent, la construction ne se faisait jamais. Ce qui a fini par tout débloquer, c&amp;rsquo;est d&amp;rsquo;utiliser Claude Code pour avancer vite dans les petites fenêtres dont je dispose, et c&amp;rsquo;est comme ça que le firmware, les deux chemins matériels et l&amp;rsquo;application compagnon ont vraiment pris forme.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est toujours en cours. J&amp;rsquo;ai deux chemins matériels qui fonctionnent dans le firmware, la physique continue d&amp;rsquo;être affinée, et le boîtier est petit, destiné à rester un objet à tenir en main. Cet article est la partie 1 : l&amp;rsquo;idée, la physique, le firmware, et le premier des deux montages, celui qui restitue la bille sous forme de &lt;strong&gt;son via un amplificateur I2S&lt;/strong&gt;. Une petite note d&amp;rsquo;honnêteté d&amp;rsquo;entrée : ce montage audio, je l&amp;rsquo;ai validé sur l&amp;rsquo;établi, les cartes branchées en vrac, mais je ne l&amp;rsquo;ai jamais refermé dans un boîtier fini. L&amp;rsquo;unité que j&amp;rsquo;ai réellement assemblée et que je trimballe, c&amp;rsquo;est le montage à pont en H de la &lt;a href=&#34;../esp32-rolling-stone-hbridge/&#34;&gt;partie 2&lt;/a&gt;, qui pilote un moteur directement. Les deux chemins font tourner exactement la même simulation.&lt;/p&gt;
&lt;h2 id=&#34;lillusion-à-la-base-de-tout-ça&#34;&gt;L&amp;rsquo;illusion à la base de tout ça&lt;/h2&gt;
&lt;p&gt;L&amp;rsquo;ensemble est une reproduction d&amp;rsquo;un joli petit article : Hsin-Yun Yao et Vincent Hayward, &lt;em&gt;An Experiment on Length Perception with a Virtual Rolling Stone&lt;/em&gt;, Eurohaptics 2006, pages 325 à 330. Le &lt;a href=&#34;https://cim.mcgill.ca/~haptic/pub/HY-VH-EH-06.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PDF est hébergé sur la page du laboratoire d&amp;rsquo;haptique de McGill&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Le dispositif décrit dans l&amp;rsquo;article est élégant. On donne aux gens un tube à tenir en main avec un seul actionneur vibrotactile à l&amp;rsquo;intérieur, et on synthétise la sensation d&amp;rsquo;une bille roulant le long de l&amp;rsquo;intérieur du tube à mesure qu&amp;rsquo;on l&amp;rsquo;incline. Pas de vraie bille. L&amp;rsquo;actionneur joue une vibration dont la hauteur suit la vitesse de la bille virtuelle, plus un transitoire net à chaque fois que la bille touche une paroi de bout. Ensuite on demande : les gens peuvent-ils estimer la &lt;strong&gt;longueur&lt;/strong&gt; du tube virtuel uniquement à partir de cette sensation ? La réponse est oui, mieux que le hasard, et le plus intéressant est que les gens semblent utiliser un modèle interne de la &lt;strong&gt;gravité&lt;/strong&gt; pour le faire. Ils ne chronomètrent pas un son, ils font mentalement rouler une bille sous gravité et lisent jusqu&amp;rsquo;où elle est allée.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est une illusion haptique au sens le plus pur : la perception de quelque chose de physique (une bille, un tube, une longueur) créée entièrement à partir d&amp;rsquo;un signal de vibration à une dimension. Cela se place juste à côté d&amp;rsquo;un thème dont j&amp;rsquo;ai déjà parlé, à savoir &lt;a href=&#34;../haptic-illusions/&#34;&gt;qu&amp;rsquo;on a des musées pour les illusions d&amp;rsquo;optique mais presque rien pour le toucher&lt;/a&gt;, et du projet connexe d&amp;rsquo;&lt;a href=&#34;../../project/3dprintedillusions/&#34;&gt;illusions haptiques imprimées en 3D&lt;/a&gt; de mes années de labo, dont tout l&amp;rsquo;intérêt était qu&amp;rsquo;on peut fabriquer une illusion haptique pour pas cher et la mettre dans la main de quelqu&amp;rsquo;un. Ce projet est le cousin motorisé et programmable de ceux-là : au lieu d&amp;rsquo;une géométrie astucieuse, l&amp;rsquo;illusion vit dans le firmware.&lt;/p&gt;
&lt;h2 id=&#34;ce-que-fait-le-boîtier&#34;&gt;Ce que fait le boîtier&lt;/h2&gt;
&lt;p&gt;Le matériel est volontairement minimal :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un &lt;strong&gt;ESP32-C6&lt;/strong&gt; (RISC-V, 160 MHz, un seul cœur). Pas cher, BLE intégré, et largement assez rapide.&lt;/li&gt;
&lt;li&gt;Une centrale inertielle &lt;strong&gt;BNO085&lt;/strong&gt; 9 axes pour mesurer l&amp;rsquo;inclinaison du boîtier.&lt;/li&gt;
&lt;li&gt;Une sortie haptique. C&amp;rsquo;est là que les deux montages divergent : un &lt;strong&gt;amplificateur audio I2S pilotant un actionneur TITAN Haptics&lt;/strong&gt; (cet article), ou un &lt;strong&gt;pont en H pilotant un moteur&lt;/strong&gt; (&lt;a href=&#34;../esp32-rolling-stone-hbridge/&#34;&gt;partie 2&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le firmware lit l&amp;rsquo;inclinaison, fait tourner une petite simulation physique de la bille, et transforme le mouvement de la bille en vibration en temps réel. Inclinez le boîtier et la bille accélère vers le bas. Remettez-le à plat et la bille roule en roue libre, ralentie par le frottement. Inclinez de l&amp;rsquo;autre côté et la bille repart, court vers la paroi opposée, et la cogne avec un choc dont l&amp;rsquo;intensité dépend de sa vitesse.&lt;/p&gt;
&lt;p&gt;Il y a en fait trois modes de simulation dans le firmware aujourd&amp;rsquo;hui, sélectionnables à l&amp;rsquo;exécution :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Roulement&lt;/strong&gt; : la bille roule comme une sphère pleine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Glissement&lt;/strong&gt; : la bille glisse avec un frottement de Coulomb, donc elle peut rester collée sur les pentes douces.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Billes&lt;/strong&gt; : une boîte 3D avec trois billes de masse et de taille différentes qui rebondissent les unes sur les autres et sur les parois. Celui-là est arrivé pendant que je jouais, et il est vraiment amusant.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;la-physique-en-bref&#34;&gt;La physique, en bref&lt;/h2&gt;
&lt;p&gt;Les modes roulement et glissement sont à une dimension. La seule entrée venant du monde réel est &lt;code&gt;sin(α)&lt;/code&gt;, le sinus de l&amp;rsquo;angle d&amp;rsquo;inclinaison du tube, que je lis directement sur le vecteur gravité de la centrale. À partir de là, c&amp;rsquo;est de la mécanique de manuel.&lt;/p&gt;
&lt;p&gt;Pour une sphère pleine qui roule sans glisser, le moment d&amp;rsquo;inertie vole une partie de l&amp;rsquo;accélération, donc :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ẍ = (g / 1,4) · sin(α)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Le &lt;code&gt;1,4&lt;/code&gt; est le facteur &lt;code&gt;1 + 2/5&lt;/code&gt; d&amp;rsquo;une sphère pleine. Dans le firmware cela se réduit à une seule constante &lt;code&gt;G_FACTOR = 7,0&lt;/code&gt; m/s².&lt;/p&gt;
&lt;p&gt;Pour le mode glissement j&amp;rsquo;ajoute le frottement de Coulomb, avec une zone morte où la pente est trop douce pour vaincre le frottement statique et la bille reste simplement immobile :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ẍ = g · sin(α) − g · µ · sgn(sin(α)) · cos(α)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;J&amp;rsquo;intègre ça avec un pas trapézoïdal à 1 kHz, en gardant l&amp;rsquo;accélération précédente pour que l&amp;rsquo;intégration reste stable. La bille est contrainte dans &lt;code&gt;[0, cavité]&lt;/code&gt;. Quand elle atteint une paroi en se déplaçant encore vers elle, c&amp;rsquo;est un &lt;strong&gt;impact&lt;/strong&gt; : j&amp;rsquo;enregistre la vitesse, je fais rebondir la vélocité avec un coefficient de restitution de 0,5, et je signale l&amp;rsquo;événement à la couche haptique. Un petit bout d&amp;rsquo;état de détection de front empêche l&amp;rsquo;impact de se redéclencher tant que la bille repose contre une paroi sous la gravité, ce qui produirait sinon un bourdonnement désagréable.&lt;/p&gt;
&lt;p&gt;La boîte à billes est le même esprit en 3D : chaque bille reçoit l&amp;rsquo;accélération de la boîte et la gravité dans le référentiel non inertiel du boîtier, entre en collision avec les six parois, et entre en collision avec les autres billes avec une vraie impulsion à masses inégales le long de la normale de contact. Le signal haptique est piloté par la plus grande impulsion de collision à chaque pas, donc une lourde bille d&amp;rsquo;acier qui claque la paroi ne se sent pas comme la légère bille en plastique.&lt;/p&gt;
&lt;h2 id=&#34;la-forme-du-firmware&#34;&gt;La forme du firmware&lt;/h2&gt;
&lt;p&gt;L&amp;rsquo;ESP32-C6 n&amp;rsquo;a qu&amp;rsquo;un cœur, donc je m&amp;rsquo;appuie sur FreeRTOS pour garder un timing propre. Trois tâches :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;taskIMU&lt;/code&gt;&lt;/strong&gt; (priorité 3) lit le BNO085 aussi vite que l&amp;rsquo;I2C le permet et met à jour un ensemble de variables globales &lt;code&gt;volatile&lt;/code&gt;. L&amp;rsquo;I2C est la partie lente, donc elle a sa propre tâche et est découplée du reste.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;taskPhysics&lt;/code&gt;&lt;/strong&gt; (priorité 5) tourne à exactement 1 kHz via &lt;code&gt;vTaskDelayUntil&lt;/code&gt;. À chaque pas elle récupère la dernière inclinaison, fait avancer la physique, appelle la couche haptique, et publie un instantané de télémétrie.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;taskComms&lt;/code&gt;&lt;/strong&gt; (priorité 1) gère les commandes série et BLE et diffuse la télémétrie à environ 58 Hz, avec un état d&amp;rsquo;une ligne une fois par seconde.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Un détail petit mais nécessaire : sur le C6 la tâche Arduino &lt;code&gt;loopTask&lt;/code&gt; est surveillée par le chien de garde, et mon &lt;code&gt;loop()&lt;/code&gt; se contente de se garer sur &lt;code&gt;vTaskDelay(portMAX_DELAY)&lt;/code&gt; à l&amp;rsquo;infini. Donc je retire la tâche loop du chien de garde dans &lt;code&gt;setup()&lt;/code&gt;, sinon la carte se réinitialise toutes les dix secondes. La vie en embarqué.&lt;/p&gt;
&lt;p&gt;Un seul drapeau de compilation &lt;code&gt;#define HBRIDGE&lt;/code&gt;, défini par environnement dans &lt;code&gt;platformio.ini&lt;/code&gt;, bascule tout le code spécifique au matériel. La physique est identique octet pour octet entre les deux montages. C&amp;rsquo;était un objectif délibéré : je voulais la &lt;strong&gt;même bille&lt;/strong&gt; dans les deux boîtiers, pour que toute différence ressentie vienne de l&amp;rsquo;étage de sortie, pas de la simulation.&lt;/p&gt;
&lt;h2 id=&#34;montage-un--restituer-la-bille-en-audio&#34;&gt;Montage un : restituer la bille en audio&lt;/h2&gt;
&lt;p&gt;Le premier montage traite la bille comme un &lt;strong&gt;son&lt;/strong&gt;, ce qui se révèle un choix très naturel pour l&amp;rsquo;haptique. Un actionneur à bobine mobile et un petit haut-parleur sont mécaniquement la même bête : une bobine qui pousse une masse. Si vous savez synthétiser un son de roulement crédible, vous savez le faire sentir.&lt;/p&gt;
&lt;p&gt;















&lt;figure  id=&#34;figure-le-montage-i2s-avant-assemblage-la-carte-bleue-est-un-amplificateur-class-d-i2s-adafruit-max98357a-la-carte-noire-est-une-adafruit-esp32-c6-feather-la-sortie-de-lampli-va-vers-lactionneur-titan-haptics-au-lieu-dun-haut-parleur-cest-aussi-loin-que-ce-montage-est-allé-physiquement--validé-sur-létabli-jamais-mis-en-boîtier&#34;&gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;Sur un bureau en bois, un petit ampli I2S Adafruit MAX98357A bleu avec un bornier à vis vert à gauche, et une carte Adafruit ESP32-C6 Feather noire plus grande à droite, avec deux barrettes de connecteurs au-dessus&#34; srcset=&#34;
               /fr/post/esp32-rolling-stone/feather-max98357a_hu_8cec9694ee62d2f.webp 400w,
               /fr/post/esp32-rolling-stone/feather-max98357a_hu_3144dfb912ec271.webp 760w,
               /fr/post/esp32-rolling-stone/feather-max98357a_hu_97b93c80f4c067db.webp 1200w&#34;
               src=&#34;https://antoine.weill-duflos.fr/fr/post/esp32-rolling-stone/feather-max98357a_hu_8cec9694ee62d2f.webp&#34;
               width=&#34;760&#34;
               height=&#34;573&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;figcaption&gt;
      Le montage I2S, avant assemblage. La carte bleue est un amplificateur Class-D I2S Adafruit MAX98357A. La carte noire est une Adafruit ESP32-C6 Feather. La sortie de l&amp;rsquo;ampli va vers l&amp;rsquo;actionneur TITAN Haptics au lieu d&amp;rsquo;un haut-parleur. C&amp;rsquo;est aussi loin que ce montage est allé physiquement : validé sur l&amp;rsquo;établi, jamais mis en boîtier.
    &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;La carte est une &lt;strong&gt;Adafruit ESP32-C6 Feather&lt;/strong&gt; et l&amp;rsquo;amplificateur est un &lt;strong&gt;Adafruit MAX98357A&lt;/strong&gt;, un ampli Class-D I2S. Le BNO085 se branche sur le connecteur STEMMA QT, donc aucune soudure pour le capteur. Les trois broches I2S de l&amp;rsquo;ampli (horloge de bit, sélection de mot, données) sortent des broches du connecteur SPI de la Feather, et la sortie, qui irait normalement vers un haut-parleur, va plutôt vers l&amp;rsquo;actionneur.&lt;/p&gt;
&lt;h3 id=&#34;nomenclature-montage-i2s&#34;&gt;Nomenclature (montage I2S)&lt;/h3&gt;
&lt;p&gt;Tout ici est du standard du commerce. Les prix sont approximatifs, début 2026.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Pièce&lt;/th&gt;
          &lt;th&gt;Référence complète&lt;/th&gt;
          &lt;th&gt;Où l&amp;rsquo;acheter&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Carte MCU&lt;/td&gt;
          &lt;td&gt;Adafruit ESP32-C6 Feather, STEMMA QT. Réf. Adafruit 5933, module ESP32-C6-MINI-1&lt;/td&gt;
          &lt;td&gt;&lt;a href=&#34;https://www.adafruit.com/product/5933&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;adafruit.com/product/5933&lt;/a&gt;, environ 15 USD. Aussi distribuée par Digikey et Mouser sous Adafruit 5933&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Amplificateur I2S&lt;/td&gt;
          &lt;td&gt;Breakout amplificateur Class-D I2S 3W Adafruit MAX98357A. Réf. Adafruit 3006, puce Analog Devices MAX98357A&lt;/td&gt;
          &lt;td&gt;&lt;a href=&#34;https://www.adafruit.com/product/3006&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;adafruit.com/product/3006&lt;/a&gt;, environ 6 USD. La puce nue est MAX98357AETE+T chez Digikey et RS&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Centrale inertielle&lt;/td&gt;
          &lt;td&gt;Adafruit BNO085 9 axes, STEMMA QT. Réf. Adafruit 4754, capteur CEVA Hillcrest BNO085&lt;/td&gt;
          &lt;td&gt;&lt;a href=&#34;https://www.adafruit.com/product/4754&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;adafruit.com/product/4754&lt;/a&gt;, environ 20 USD&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Actionneur haptique&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;TITAN Haptics TacHammer Drake LFi&lt;/strong&gt; (la variante optimisée pour l&amp;rsquo;impact de leur actionneur à bobine mobile LMR large bande ; la pièce qui rend l&amp;rsquo;ensemble réellement palpable, voir le coup de chapeau plus bas)&lt;/td&gt;
          &lt;td&gt;&lt;a href=&#34;https://titanhaptics.com/drake/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;titanhaptics.com/drake&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Câble STEMMA QT&lt;/td&gt;
          &lt;td&gt;Câble Qwiic / STEMMA QT JST-SH 4 broches, 50 mm. Réf. Adafruit 4399&lt;/td&gt;
          &lt;td&gt;&lt;a href=&#34;https://www.adafruit.com/product/4399&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;adafruit.com/product/4399&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Alimentation&lt;/td&gt;
          &lt;td&gt;LiPo 3,7 V avec connecteur JST-PH 2 broches (la Feather la charge en interne), plus un câble USB-C&lt;/td&gt;
          &lt;td&gt;n&amp;rsquo;importe quel distributeur de LiPo&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Boîtier&lt;/td&gt;
          &lt;td&gt;Coque imprimée en 3D, une bande de mousse acoustique, du ruban kapton&lt;/td&gt;
          &lt;td&gt;à fournir soi-même&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;La Feather a la charge LiPo intégrée et un port STEMMA QT, donc la centrale ne demande aucune soudure et le seul câblage est les trois lignes I2S plus l&amp;rsquo;alimentation et la masse vers l&amp;rsquo;amplificateur.&lt;/p&gt;
&lt;h3 id=&#34;synthétiser-le-son-de-roulement&#34;&gt;Synthétiser le son de roulement&lt;/h3&gt;
&lt;p&gt;La vibration de roulement est une &lt;strong&gt;table d&amp;rsquo;onde indexée par position&lt;/strong&gt;. La table est une période d&amp;rsquo;une arche de sinus négative, longue de 30 échantillons, et j&amp;rsquo;y accède avec la position de la bille en millimètres modulo 30. Ça paraît une façon étrange de faire un son, mais elle a une belle propriété : comme la table est indexée par la &lt;em&gt;position&lt;/em&gt;, et non par le temps, la hauteur entendue monte automatiquement avec la vitesse de la bille. Va vite, balaie vite la table, hauteur plus élevée. Ralentis, hauteur plus basse. Ça tombe gratuitement de la géométrie, et ça correspond au comportement « la hauteur suit la vitesse » de l&amp;rsquo;article d&amp;rsquo;origine. L&amp;rsquo;amplitude monte aussi avec la vitesse, et en dessous d&amp;rsquo;un petit seuil de vitesse je la coupe entièrement pour qu&amp;rsquo;une bille au repos soit silencieuse.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;impact est séparé : une courte salve rectangulaire dont l&amp;rsquo;amplitude monte avec la vitesse d&amp;rsquo;impact et dont la durée s&amp;rsquo;étire de 2 ms pour une tape jusqu&amp;rsquo;à 9 ms pour un choc violent.&lt;/p&gt;
&lt;h3 id=&#34;alimenter-li2s-à-exactement-22050-hz-depuis-une-boucle-à-1-khz&#34;&gt;Alimenter l&amp;rsquo;I2S à exactement 22050 Hz depuis une boucle à 1 kHz&lt;/h3&gt;
&lt;p&gt;Voici la partie dont je suis discrètement fier. La physique tourne à 1 kHz, mais l&amp;rsquo;audio doit sortir à 22050 Hz. Cela fait 22,05 échantillons par pas physique, ce qui n&amp;rsquo;est pas un entier. Si j&amp;rsquo;écrivais simplement 22 échantillons à chaque pas, je ferais tourner l&amp;rsquo;audio légèrement lentement (22000 Hz), et la hauteur serait subtilement fausse pour toujours.&lt;/p&gt;
&lt;p&gt;Alors je tiens un accumulateur fractionnaire. À chaque pas j&amp;rsquo;y ajoute 0,05, et j&amp;rsquo;écris 22 échantillons, sauf que chaque fois que l&amp;rsquo;accumulateur dépasse 1,0 j&amp;rsquo;écris 23 échantillons à la place et je soustrais 1,0. Sur 1000 pas cela fait 950 pas de 22 plus 50 pas de 23, soit exactement 22050 échantillons par seconde. La fréquence d&amp;rsquo;échantillonnage à long terme est pile bonne, sans dérive, et l&amp;rsquo;appel &lt;code&gt;i2s_channel_write&lt;/code&gt; vers le tampon DMA cadence naturellement la boucle. Pas cher, exact, et ça marche.&lt;/p&gt;
&lt;p&gt;Le montage Feather a aussi une NeoPixel qui sert de voyant d&amp;rsquo;état : blanc faible au démarrage, rouge bloqué si la centrale n&amp;rsquo;est pas trouvée, vert une fois que ça tourne.&lt;/p&gt;
&lt;h2 id=&#34;lactionneur-titan-haptics-ou-ce-qui-a-rendu-ce-projet-si-simple-à-construire&#34;&gt;L&amp;rsquo;actionneur TITAN Haptics, ou ce qui a rendu ce projet si simple à construire&lt;/h2&gt;
&lt;p&gt;Un haut-parleur vous laisse &lt;em&gt;entendre&lt;/em&gt; la bille, mais pour la &lt;em&gt;sentir&lt;/em&gt; correctement il faut un actionneur haptique conçu pour ça. C&amp;rsquo;est précisément là que le travail d&amp;rsquo;origine était difficile : en 2006, Yao et Hayward ont dû &lt;strong&gt;fabriquer leur propre actionneur&lt;/strong&gt; pour obtenir une vibration avec un impact assez net pour que l&amp;rsquo;illusion fonctionne. Vingt ans plus tard, je n&amp;rsquo;ai pas eu à le faire. J&amp;rsquo;ai contacté &lt;strong&gt;TITAN Haptics&lt;/strong&gt;, et il se trouve qu&amp;rsquo;ils fabriquent exactement ce qu&amp;rsquo;il faut : le &lt;strong&gt;TacHammer Drake LFi&lt;/strong&gt;, la variante optimisée pour l&amp;rsquo;impact de leur actionneur à bobine mobile large bande. Il est particulièrement doué pour restituer des &lt;strong&gt;impacts&lt;/strong&gt;, des coups nets et discrets plutôt qu&amp;rsquo;un simple bourdonnement, ce qui est exactement ce dont la pierre qui roule a besoin chaque fois que la bille cogne une paroi, et c&amp;rsquo;est ce qui rend ce montage si simple et si efficace.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;utilise donc un &lt;strong&gt;TacHammer Drake LFi&lt;/strong&gt; (photographié en haut de cet article), piloté directement par la sortie de l&amp;rsquo;amplificateur I2S. C&amp;rsquo;est un actionneur à bobine mobile LMR à plage de fonctionnement ultralarge (TITAN annonce environ 5 à 300 Hz et un pic de 19 G), donc le même signal qui ferait un son fait une sensation, et il produit un impact net à la demande. Le plus joli : la &lt;a href=&#34;https://titanhaptics.com/drake/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;fiche technique du Drake&lt;/a&gt; de TITAN liste à la fois les amplificateurs audio Class-D et les pilotes de moteur à pont en H parmi les façons compatibles de le piloter, ce qui correspond exactement aux deux montages de cette série. C&amp;rsquo;est la seule pièce qui fait passer le projet de « jolie démo de traitement du signal » à « attends, je sens vraiment la bille », donc elle a mérité sa propre ligne dans la nomenclature ci-dessus et sa propre section ici.&lt;/p&gt;
&lt;p&gt;Un grand coup de chapeau chaleureux à mon amie &lt;strong&gt;Ashley Huffman&lt;/strong&gt; et à toute l&amp;rsquo;équipe de &lt;strong&gt;TITAN Haptics&lt;/strong&gt;. Ashley est une véritable figure du domaine : elle anime le podcast &lt;a href=&#34;https://thehapticsclub.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Haptics Club&lt;/a&gt; et écrit la newsletter &lt;a href=&#34;https://haptics.substack.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;All Things Haptics&lt;/a&gt;. Elle s&amp;rsquo;est enthousiasmée pour mon idée et m&amp;rsquo;a aidé à obtenir le matériel rapidement pour faire fonctionner tout ça. Ash, t&amp;rsquo;es la reine ! C&amp;rsquo;est un vrai plaisir de construire sur du matériel fait par des gens qui se soucient vraiment du toucher, et c&amp;rsquo;est encore mieux quand l&amp;rsquo;une d&amp;rsquo;elles est une amie.&lt;/p&gt;
&lt;h2 id=&#34;voir-la-bille--lapplication-compagnon&#34;&gt;Voir la bille : l&amp;rsquo;application compagnon&lt;/h2&gt;
&lt;p&gt;Comme tout l&amp;rsquo;intérêt est une chose qu&amp;rsquo;on ne peut pas voir, j&amp;rsquo;ai écrit une application compagnon en Python qui se connecte en USB série ou en BLE et dessine ce que le firmware ressent. C&amp;rsquo;est l&amp;rsquo;outil que j&amp;rsquo;utilise réellement pour régler la physique.&lt;/p&gt;
&lt;p&gt;















&lt;figure  id=&#34;figure-lapplication-compagnon-en-mode-roulement-en-direct-via-usb-le-tube-incliné-et-la-bille-à-gauche-lhistorique-de-position-et-de-vélocité-à-droite-et-le-panneau-de-télémétrie-en-direct-en-bas-la-carte-rapporte-une-boucle-physique-stable-à-1000-hz&#34;&gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;Capture de l&amp;rsquo;application compagnon montrant une interface sombre intitulée Virtual Rolling Stone, ESP32-C6, Yao et Hayward Eurohaptics 2006. Un tube gris est incliné vers le bas à gauche à moins 6,9 degrés avec une bille orange à mi-chemin et un éclat rouge sur la paroi gauche. À droite, un tracé d&amp;rsquo;historique de position montre une onde triangulaire et un tracé de vélocité montre la bille qui oscille. Un panneau indique mode ROLLING, cavité 1000 mm, position 548 mm, vélocité plus 1,4 m par s, physique 1000 sur 1000 Hz&#34; srcset=&#34;
               /fr/post/esp32-rolling-stone/viz-rolling_hu_13e405a38069a73f.webp 400w,
               /fr/post/esp32-rolling-stone/viz-rolling_hu_ca995601256eb4c5.webp 760w,
               /fr/post/esp32-rolling-stone/viz-rolling_hu_d354f1c1785d795c.webp 1200w&#34;
               src=&#34;https://antoine.weill-duflos.fr/fr/post/esp32-rolling-stone/viz-rolling_hu_13e405a38069a73f.webp&#34;
               width=&#34;760&#34;
               height=&#34;485&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;figcaption&gt;
      L&amp;rsquo;application compagnon en mode roulement, en direct via USB. Le tube incliné et la bille à gauche, l&amp;rsquo;historique de position et de vélocité à droite, et le panneau de télémétrie en direct en bas. La carte rapporte une boucle physique stable à 1000 Hz.
    &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Elle montre le tube incliné avec la bille animée à sa position réelle, colorée par la vitesse, qui fait flasher la paroi à l&amp;rsquo;impact. À droite se trouvent des tracés défilants de position et de vélocité. Le panneau du bas est la télémétrie en direct : mode, longueur de cavité, position, vélocité, fréquence physique mesurée. Elle peut aussi rejouer la synthèse du son de roulement dans les haut-parleurs de l&amp;rsquo;ordinateur avec exactement le même modèle de table d&amp;rsquo;onde que le firmware, ce qui est un moyen rapide de comparer le ressenti sans reflasher la carte.&lt;/p&gt;
&lt;p&gt;Passer en mode billes bascule la vue principale vers une boîte 3D :&lt;/p&gt;
&lt;p&gt;















&lt;figure  id=&#34;figure-le-mode-billes-une-boîte-3d-avec-trois-billes-de-masse-et-de-rayon-différents-le-vecteur-gravité-en-direct-dessiné-en-flèche-et-lhistorique-de-position-par-axe-le-panneau-montre-laccéléromètre-brut-en-g-et-lénergie-dimpact-courante&#34;&gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;Capture de l&amp;rsquo;application compagnon en mode billes montrant une boîte 3D rouge inclinée dans l&amp;rsquo;espace avec une flèche de gravité et de petites billes à l&amp;rsquo;intérieur, étiquetées lourde 1,5 mm, moyenne 1,0 mm, légère 0,7 mm, avec des tracés d&amp;rsquo;historique de position X et Y à droite et un panneau affichant les lectures d&amp;rsquo;accéléromètre en g et une valeur d&amp;rsquo;impact&#34; srcset=&#34;
               /fr/post/esp32-rolling-stone/viz-marbles_hu_4df3ff5384fa7777.webp 400w,
               /fr/post/esp32-rolling-stone/viz-marbles_hu_c2181fac9f4bf17.webp 760w,
               /fr/post/esp32-rolling-stone/viz-marbles_hu_d9e0560a205920ca.webp 1200w&#34;
               src=&#34;https://antoine.weill-duflos.fr/fr/post/esp32-rolling-stone/viz-marbles_hu_4df3ff5384fa7777.webp&#34;
               width=&#34;760&#34;
               height=&#34;485&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;figcaption&gt;
      Le mode billes. Une boîte 3D avec trois billes de masse et de rayon différents, le vecteur gravité en direct dessiné en flèche, et l&amp;rsquo;historique de position par axe. Le panneau montre l&amp;rsquo;accéléromètre brut en g et l&amp;rsquo;énergie d&amp;rsquo;impact courante.
    &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;La boîte 3D, la flèche de gravité qui suit la façon dont je tiens le boîtier, les trois billes de masse différente : tout cela est de la donnée en direct venant de la carte à 58 Hz via le lien série. C&amp;rsquo;est une petite chose, mais regarder la simulation et la sentir dans sa main en même temps, c&amp;rsquo;est ce qui rend la boucle de réglage rapide.&lt;/p&gt;
&lt;h2 id=&#34;où-ça-en-est&#34;&gt;Où ça en est&lt;/h2&gt;
&lt;p&gt;Ce qui marche aujourd&amp;rsquo;hui : la physique, le firmware pour les deux chemins de sortie, l&amp;rsquo;application compagnon, et la télémétrie BLE et série. Ce chemin audio, je l&amp;rsquo;ai validé sur l&amp;rsquo;établi, avec la Feather, l&amp;rsquo;amplificateur et l&amp;rsquo;actionneur TITAN Haptics câblés en vrac. Je ne l&amp;rsquo;ai jamais refermé dans un boîtier fini. L&amp;rsquo;unité que j&amp;rsquo;ai réellement assemblée, avec la mousse et le kapton, c&amp;rsquo;est le montage à pont en H de la &lt;a href=&#34;../esp32-rolling-stone-hbridge/&#34;&gt;partie 2&lt;/a&gt;, parce que la carte tout-en-un faisait un boîtier plus petit. Donc le montage audio est une approche qui marche plus qu&amp;rsquo;un objet fini, et c&amp;rsquo;est son état honnête.&lt;/p&gt;
&lt;p&gt;La suite, en gros : un &lt;strong&gt;tube plus long&lt;/strong&gt;. Le boîtier reste un objet à tenir en main, mais l&amp;rsquo;illusion d&amp;rsquo;origine vit dans la sensation de longueur, et un corps plus long donne plus de place à la bille virtuelle pour courir et rend l&amp;rsquo;illusion plus convaincante. Ensuite, une &lt;strong&gt;batterie embarquée&lt;/strong&gt; pour le rendre autonome, et un petit test utilisateur dans l&amp;rsquo;esprit de l&amp;rsquo;article d&amp;rsquo;origine pour voir si les gens arrivent à lire la longueur du tube virtuel à partir de ma version de l&amp;rsquo;illusion.&lt;/p&gt;
&lt;p&gt;Il y a une direction qui m&amp;rsquo;enthousiasme particulièrement. Lors de ce même colloque en mémoire de Vincent Hayward, l&amp;rsquo;un des fils conducteurs était &lt;a href=&#34;https://cim.mcgill.ca/~haptic/pub/LM-ET-AL-NAT-18.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Miller et coll., &lt;em&gt;Sensing with tools extends somatosensory processing beyond the body&lt;/em&gt;, Nature 2018&lt;/a&gt; : quand vous tenez une tige et que quelque chose la frappe, votre système nerveux sait dire &lt;em&gt;où&lt;/em&gt; le long de la tige l&amp;rsquo;impact a eu lieu, uniquement à partir de la vibration qui remonte l&amp;rsquo;outil. La pierre qui roule synthétise déjà un impact quand la bille virtuelle cogne une paroi. L&amp;rsquo;étape suivante naturelle est de synthétiser un impact &lt;em&gt;localisable&lt;/em&gt;, en façonnant le transitoire pour que vous sentiez non seulement que la bille a cogné, mais où le long du tube elle a cogné. Cela ferait passer le boîtier d&amp;rsquo;une illusion de longueur à une illusion de position le long d&amp;rsquo;un outil, ce qui est exactement le genre de chose vers quoi tendait cette lignée de travaux.&lt;/p&gt;
&lt;p&gt;Le code est sur GitHub à &lt;a href=&#34;https://github.com/Leicas/esp32-ball&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;github.com/Leicas/esp32-ball&lt;/a&gt;. La &lt;a href=&#34;../esp32-rolling-stone-hbridge/&#34;&gt;partie 2&lt;/a&gt; prend la même bille et la pilote via un pont en H à la place, sur une carte sans aucun amplificateur, ce qui est un tout autre jeu de compromis.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Une pierre qui roule de poche, partie 2 : piloter la bille avec un pont en H sur un CodeCell ESP32-C6</title>
      <link>https://antoine.weill-duflos.fr/fr/post/esp32-rolling-stone-hbridge/</link>
      <pubDate>Sat, 30 May 2026 00:00:00 +0000</pubDate>
      <guid>https://antoine.weill-duflos.fr/fr/post/esp32-rolling-stone-hbridge/</guid>
      <description>&lt;p&gt;















&lt;figure  id=&#34;figure-lunité-à-pont-en-h-terminée-cest-le-montage-que-jai-réellement-assemblé-et-que-je-garde-sous-la-main--une-codecell-c6-drive-emballée-bien-compacte-avec-un-câble-usb-c-pour-lalimentation-et-le-flashage-le-montage-audio-de-la-partie-1-na-jamais-été-mis-en-boîtier-comme-ça-il-est-resté-sur-létabli&#34;&gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;Un petit bloc rectangulaire noir entouré de ruban, tenu dans une main, avec un câble USB-C branché à une extrémité&#34; srcset=&#34;
               /fr/post/esp32-rolling-stone-hbridge/featured_hu_55609ed5e5d778d1.webp 400w,
               /fr/post/esp32-rolling-stone-hbridge/featured_hu_51bd6e9e4f3cc1cd.webp 760w,
               /fr/post/esp32-rolling-stone-hbridge/featured_hu_1438624f51795477.webp 1200w&#34;
               src=&#34;https://antoine.weill-duflos.fr/fr/post/esp32-rolling-stone-hbridge/featured_hu_55609ed5e5d778d1.webp&#34;
               width=&#34;573&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;figcaption&gt;
      L&amp;rsquo;unité à pont en H terminée. C&amp;rsquo;est le montage que j&amp;rsquo;ai réellement assemblé et que je garde sous la main : une CodeCell C6 Drive emballée bien compacte, avec un câble USB-C pour l&amp;rsquo;alimentation et le flashage. Le montage audio de la partie 1 n&amp;rsquo;a jamais été mis en boîtier comme ça, il est resté sur l&amp;rsquo;établi.
    &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Dans la &lt;a href=&#34;../esp32-rolling-stone/&#34;&gt;partie 1&lt;/a&gt; j&amp;rsquo;ai construit un boîtier à tenir en main qui vous fait sentir une bille virtuelle rouler dans un tube, d&amp;rsquo;après l&amp;rsquo;&lt;a href=&#34;https://cim.mcgill.ca/~haptic/pub/HY-VH-EH-06.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;expérience de perception de longueur de Yao et Hayward (2006)&lt;/a&gt;, et j&amp;rsquo;ai restitué la bille en audio via un amplificateur I2S pilotant un actionneur TITAN Haptics. Voici l&amp;rsquo;autre moitié du projet : la &lt;strong&gt;même bille, la même physique, sans amplificateur&lt;/strong&gt;. Ici la sortie haptique est un moteur de vibration piloté directement par un &lt;strong&gt;pont en H&lt;/strong&gt;. C&amp;rsquo;est aussi le montage que j&amp;rsquo;ai réellement terminé et que je garde sous la main, parce que la carte tout-en-un fait tenir l&amp;rsquo;ensemble dans un boîtier plus petit que la Feather plus l&amp;rsquo;amplificateur.&lt;/p&gt;
&lt;p&gt;Si vous n&amp;rsquo;avez pas lu la partie 1, la version courte est : un ESP32-C6 lit l&amp;rsquo;inclinaison d&amp;rsquo;une centrale BNO085, fait tourner une simulation physique à 1 kHz d&amp;rsquo;une bille qui roule et glisse dans un tube (plus un mode boîte à billes en 3D), et transforme le mouvement de la bille en vibration en temps réel. Un seul drapeau de compilation &lt;code&gt;#define HBRIDGE&lt;/code&gt; dans &lt;code&gt;platformio.ini&lt;/code&gt; bascule entre les deux étages de sortie, et le code de physique est identique entre eux. Donc tout ici porte sur la sortie.&lt;/p&gt;
&lt;h2 id=&#34;pourquoi-un-second-montage&#34;&gt;Pourquoi un second montage&lt;/h2&gt;
&lt;p&gt;Le montage I2S est très bien, mais il embarque un amplificateur audio, et on n&amp;rsquo;en a en fait pas besoin pour piloter un actionneur haptique. Une approche très courante et plus simple est le &lt;strong&gt;pont en H&lt;/strong&gt; : deux demi-ponts qui laissent pousser le courant dans l&amp;rsquo;actionneur dans un sens ou dans l&amp;rsquo;autre, avec la tension moyenne réglée par le rapport cyclique du PWM. Le TacHammer Drake se laisse piloter ainsi sans problème ; TITAN liste d&amp;rsquo;ailleurs les pilotes de moteur à pont en H parmi les façons recommandées de le faire fonctionner.&lt;/p&gt;
&lt;p&gt;Donc la question pour ce montage était : puis-je obtenir la même sensation convaincante de pierre qui roule en pilotant le même Drake LFi directement depuis un pont en H, sans aucun chemin audio ? En grande partie, oui, et pour nos besoins cela donne une solution bien plus simple et compacte. Avec la bonne carte, il n&amp;rsquo;y a aucune soudure du tout.&lt;/p&gt;
&lt;h2 id=&#34;le-matériel--codecell-drive-et-drivecell&#34;&gt;Le matériel : CodeCell Drive et DriveCell&lt;/h2&gt;
&lt;p&gt;Ce montage tourne sur une carte &lt;strong&gt;CodeCell ESP32-C6 Drive&lt;/strong&gt; de &lt;a href=&#34;https://microbots.io&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Microbots&lt;/a&gt;. C&amp;rsquo;est une petite carte bien rangée pour exactement ce genre de chose :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ESP32-C6, la même puce que le montage Feather, donc la physique ne change pas.&lt;/li&gt;
&lt;li&gt;Une centrale &lt;strong&gt;BNO085 intégrée&lt;/strong&gt;, câblée en interne sur l&amp;rsquo;I2C (SDA sur IO8, SCL sur IO9) et gérée par la bibliothèque CodeCell. Pas de capteur externe, pas de câble STEMMA.&lt;/li&gt;
&lt;li&gt;Un pont en H &lt;strong&gt;DriveCell&lt;/strong&gt; intégré, exposé dans la bibliothèque sous les noms &lt;code&gt;Drive1&lt;/code&gt; et &lt;code&gt;Drive2&lt;/code&gt;. J&amp;rsquo;utilise &lt;code&gt;Drive1&lt;/code&gt; (IN1 sur IO22, IN2 sur IO21) comme actionneur haptique et je laisse &lt;code&gt;Drive2&lt;/code&gt; en réserve.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Une belle conséquence du tout-intégré est que le montage est physiquement plus petit que la Feather plus l&amp;rsquo;ampli plus la centrale séparée. Pour un boîtier à tenir en main, ça compte.&lt;/p&gt;
&lt;p&gt;















&lt;figure  id=&#34;figure-un-angle-antérieur-avant-de-tout-refermer-au-ruban--la-carte-et-la-mousse-de-rembourrage-nichées-dans-la-coque-imprimée-en-3d-une-fois-fermée-elle-devient-le-petit-bloc-noir-de-la-photo-en-haut&#34;&gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;Une coque noire imprimée en 3D tenue dans une main, avec une bande de mousse foncée sur le dessus et du kapton, la carte et le rembourrage nichés à l&amp;rsquo;intérieur avant la fermeture du boîtier&#34; srcset=&#34;
               /fr/post/esp32-rolling-stone-hbridge/assembled-internals_hu_7d6dd65a917418e.webp 400w,
               /fr/post/esp32-rolling-stone-hbridge/assembled-internals_hu_1a2061d719fc69c7.webp 760w,
               /fr/post/esp32-rolling-stone-hbridge/assembled-internals_hu_2dbb5aca3cbb1831.webp 1200w&#34;
               src=&#34;https://antoine.weill-duflos.fr/fr/post/esp32-rolling-stone-hbridge/assembled-internals_hu_7d6dd65a917418e.webp&#34;
               width=&#34;573&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;figcaption&gt;
      Un angle antérieur, avant de tout refermer au ruban : la carte et la mousse de rembourrage nichées dans la coque imprimée en 3D. Une fois fermée, elle devient le petit bloc noir de la photo en haut.
    &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;nomenclature-montage-pont-en-h&#34;&gt;Nomenclature (montage pont en H)&lt;/h3&gt;
&lt;p&gt;L&amp;rsquo;intérêt de ce montage est la brièveté de la liste, et c&amp;rsquo;est exactement pour ça que c&amp;rsquo;est la version que j&amp;rsquo;ai terminée. La CodeCell C6 Drive a déjà la centrale et le pont en H à bord.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Pièce&lt;/th&gt;
          &lt;th&gt;Référence complète&lt;/th&gt;
          &lt;th&gt;Où l&amp;rsquo;acheter&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Carte tout-en-un&lt;/td&gt;
          &lt;td&gt;Microbots CodeCell C6 Drive. Module ESP32-C6-MINI-1-H8 (8 Mo de flash), avec une centrale BNO085 intégrée, un capteur de lumière et de proximité VCNL4040, et un double pont en H&lt;/td&gt;
          &lt;td&gt;&lt;a href=&#34;https://microbots.io/products/codecell-c6-drive&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;microbots.io/products/codecell-c6-drive&lt;/a&gt;, 32,99 €&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Actionneur haptique&lt;/td&gt;
          &lt;td&gt;Un TITAN Haptics TacHammer Drake LFi, piloté depuis le pont en H&lt;/td&gt;
          &lt;td&gt;&lt;a href=&#34;https://titanhaptics.com/drake/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;titanhaptics.com/drake&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Alimentation&lt;/td&gt;
          &lt;td&gt;LiPo 3,7 V avec connecteur JST, plus un câble USB-C&lt;/td&gt;
          &lt;td&gt;n&amp;rsquo;importe quel distributeur de LiPo&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Boîtier&lt;/td&gt;
          &lt;td&gt;Coque imprimée en 3D, mousse acoustique, ruban kapton&lt;/td&gt;
          &lt;td&gt;à fournir soi-même&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;C&amp;rsquo;est toute la nomenclature. Pas d&amp;rsquo;amplificateur séparé, pas de centrale externe, pas de carte de pilotage. Pour une unité bon marché et autonome qu&amp;rsquo;on peut vraiment refermer et glisser dans une poche, c&amp;rsquo;est exactement l&amp;rsquo;intérêt.&lt;/p&gt;
&lt;h2 id=&#34;générer-le-signal-avec-le-pwm-ledc&#34;&gt;Générer le signal avec le PWM LEDC&lt;/h2&gt;
&lt;p&gt;Il n&amp;rsquo;y a pas de flux audio par DMA ici. À la place je pilote les deux broches d&amp;rsquo;entrée du pont en H avec le périphérique &lt;strong&gt;LEDC&lt;/strong&gt; de l&amp;rsquo;ESP32 : une porteuse PWM à 20 kHz avec une résolution de rapport cyclique de 8 bits. 20 kHz est au-dessus de l&amp;rsquo;audition, donc la porteuse elle-même est silencieuse, et l&amp;rsquo;actionneur ne répond qu&amp;rsquo;à l&amp;rsquo;enveloppe que j&amp;rsquo;impose au rapport cyclique.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;astuce de la partie 1 se reporte directement. La vibration de roulement est la même &lt;strong&gt;table d&amp;rsquo;onde indexée par position&lt;/strong&gt;, une période d&amp;rsquo;une arche de sinus négative, indexée par la position de la bille en millimètres. Comme elle est indexée par la position plutôt que par le temps, la hauteur perçue monte automatiquement avec la vitesse de la bille, exactement comme dans le montage audio, alors qu&amp;rsquo;ici je ne mets à jour le rapport cyclique qu&amp;rsquo;une fois par pas physique à 1 kHz au lieu de diffuser 22050 échantillons par seconde. La mise à jour à 1 kHz est assez rapide pour porter la texture de roulement et les transitoires d&amp;rsquo;impact qui intéressent la peau.&lt;/p&gt;
&lt;h3 id=&#34;routage-unipolaire--grondement-sur-une-broche-impact-sur-lautre&#34;&gt;Routage unipolaire : grondement sur une broche, impact sur l&amp;rsquo;autre&lt;/h3&gt;
&lt;p&gt;Le montage audio avait la tâche facile : un échantillon I2S est signé, donc une forme d&amp;rsquo;onde bipolaire qui oscille en positif et en négatif est la chose naturelle. Le rapport cyclique d&amp;rsquo;un PWM est non signé. On ne peut pas écrire un rapport cyclique négatif.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;astuce que j&amp;rsquo;ai retenue est de &lt;strong&gt;séparer le signal par signe entre les deux broches du pont en H&lt;/strong&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le grondement de roulement utilise la table d&amp;rsquo;onde en arche négative, qui est toujours inférieure ou égale à zéro. Je route ça sur la broche &lt;strong&gt;moins&lt;/strong&gt; (IN2) : rapport cyclique proportionnel à l&amp;rsquo;amplitude.&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;impulsion d&amp;rsquo;impact est une courte salve positive. Je route ça sur la broche &lt;strong&gt;plus&lt;/strong&gt; (IN1).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;À un pas donné, exactement une broche est active et l&amp;rsquo;autre est maintenue à rapport cyclique nul. Donc l&amp;rsquo;actionneur reçoit un grondement propre dans une polarité et un coup d&amp;rsquo;impact net dans l&amp;rsquo;autre, le tout depuis un unique signal signé calculé exactement comme le montage audio le calcule. La valeur signée est le langage commun entre les deux montages, et chaque étage de sortie la restitue à la manière que veut son matériel.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;impact, comme dans la partie 1, fait varier l&amp;rsquo;amplitude et la durée avec la vitesse d&amp;rsquo;impact : d&amp;rsquo;un pas de 2 ms pour un effleurement doux jusqu&amp;rsquo;à un coup de 9 ms pour un choc violent contre la paroi.&lt;/p&gt;
&lt;h2 id=&#34;pièges-embarqués-à-noter&#34;&gt;Pièges embarqués à noter&lt;/h2&gt;
&lt;p&gt;Quelques choses m&amp;rsquo;ont mordu sur cette carte et valent la peine d&amp;rsquo;être notées, parce que c&amp;rsquo;est le genre de truc qui vous fait perdre une soirée.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Le maintien des GPIO pendant la veille profonde.&lt;/strong&gt; Le CodeCell peut entrer en veille profonde, et l&amp;rsquo;ESP32 peut verrouiller les états des GPIO à travers la veille avec une fonction de maintien. Si une broche était maintenue depuis un cycle d&amp;rsquo;alimentation précédent, la reconfigurer ne fait rien tant qu&amp;rsquo;on ne libère pas explicitement le maintien. Donc au démarrage j&amp;rsquo;appelle &lt;code&gt;gpio_hold_dis&lt;/code&gt; sur les broches du pont en H, la broche d&amp;rsquo;alimentation du capteur, et les broches I2C avant de les configurer. Sans ça, le premier démarrage après une veille peut revenir avec un actionneur mort ou un bus capteur mort, par intermittence, ce qui est le pire genre de bug.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Les broches d&amp;rsquo;activation du capteur et de la LED.&lt;/strong&gt; Sur cette carte le capteur et la LED d&amp;rsquo;état sont derrière des broches d&amp;rsquo;activation (IO18 et IO20). Il faut les mettre à l&amp;rsquo;état haut tôt dans &lt;code&gt;setup()&lt;/code&gt;, avant le scan I2C, sinon le BNO085 n&amp;rsquo;est tout simplement pas là.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Le chien de garde mono-cœur.&lt;/strong&gt; Comme pour le montage Feather : le C6 n&amp;rsquo;a qu&amp;rsquo;un cœur, mon &lt;code&gt;loop()&lt;/code&gt; se gare à l&amp;rsquo;infini, donc je retire la tâche loop d&amp;rsquo;Arduino du chien de garde sinon la carte se réinitialise toutes les dix secondes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Éviter les broches JTAG.&lt;/strong&gt; Les GPIO 4 à 7 sont du JTAG sur l&amp;rsquo;ESP32-C6. Facile d&amp;rsquo;en attraper une par accident pour une sortie et de se demander ensuite pourquoi le débogage est bizarre. Je les laisse libres sur les deux cartes.&lt;/p&gt;
&lt;h2 id=&#34;comparaison-avec-le-montage-i2s&#34;&gt;Comparaison avec le montage I2S&lt;/h2&gt;
&lt;p&gt;Côte à côte, les deux montages se sentent différents de façons instructives.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bande passante.&lt;/strong&gt; Le montage audio fait tourner la sortie à 22050 Hz et peut restituer une texture fine et des transitoires nets. Le montage à pont en H se met à jour à 1 kHz. Pour le grondement de roulement et les impacts c&amp;rsquo;est amplement suffisant, et honnêtement l&amp;rsquo;essentiel de ce que la peau résout dans cette bande passe très bien. Le montage audio garde l&amp;rsquo;avantage sur le détail le plus net et le plus haut en fréquence.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplicité et taille.&lt;/strong&gt; Le montage à pont en H est plus petit et a moins de pièces : pas d&amp;rsquo;amplificateur, centrale intégrée, pont en H intégré. C&amp;rsquo;est le montage vers lequel j&amp;rsquo;irais pour faire une unité bon marché et autonome.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Le modèle de signal est partagé.&lt;/strong&gt; C&amp;rsquo;est la partie que je préfère. La même table d&amp;rsquo;onde indexée par position, le même modèle d&amp;rsquo;impact, la même enveloppe signée pilotent les deux. Le montage audio la diffuse en échantillons, le montage à pont en H la sépare entre deux broches. La bille est la même bille.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L&amp;rsquo;application compagnon se moque de quel montage est à l&amp;rsquo;autre bout du fil. Elle parle le même protocole série et BLE dans les deux cas, donc je peux observer et régler les deux :&lt;/p&gt;
&lt;p&gt;















&lt;figure  id=&#34;figure-la-même-application-compagnon-que-dans-la-partie-1-ici-en-train-dobserver-la-physique-de-roulement-le-protocole-est-identique-entre-les-deux-montages-donc-loutillage-est-partagé&#34;&gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;Capture de l&amp;rsquo;application compagnon en mode roulement : une interface sombre avec un tube gris incliné vers le bas à gauche avec une bille orange dessus et un éclat rouge sur la paroi, des tracés d&amp;rsquo;historique de position et de vélocité à droite, et un panneau de télémétrie montrant mode ROLLING, position, vélocité, et une fréquence physique de 1000 Hz&#34; srcset=&#34;
               /fr/post/esp32-rolling-stone-hbridge/viz-rolling_hu_13e405a38069a73f.webp 400w,
               /fr/post/esp32-rolling-stone-hbridge/viz-rolling_hu_ca995601256eb4c5.webp 760w,
               /fr/post/esp32-rolling-stone-hbridge/viz-rolling_hu_d354f1c1785d795c.webp 1200w&#34;
               src=&#34;https://antoine.weill-duflos.fr/fr/post/esp32-rolling-stone-hbridge/viz-rolling_hu_13e405a38069a73f.webp&#34;
               width=&#34;760&#34;
               height=&#34;485&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;figcaption&gt;
      La même application compagnon que dans la partie 1, ici en train d&amp;rsquo;observer la physique de roulement. Le protocole est identique entre les deux montages, donc l&amp;rsquo;outillage est partagé.
    &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;où-ça-va&#34;&gt;Où ça va&lt;/h2&gt;
&lt;p&gt;Les deux montages fonctionnent et produisent tous deux une sensation convaincante de pierre qui roule, ce qui me surprend encore un peu vu qu&amp;rsquo;il n&amp;rsquo;y a rien qui bouge à l&amp;rsquo;intérieur. Le projet est en cours : le boîtier est un prototype, le boîtier reste à tenir en main (il est petit), et les prochaines étapes sont un tube plus long pour rendre l&amp;rsquo;illusion de longueur plus convaincante, une batterie embarquée pour couper le fil, et un petit test de perception de longueur dans l&amp;rsquo;esprit de l&amp;rsquo;article d&amp;rsquo;origine.&lt;/p&gt;
&lt;p&gt;Si vous voulez en construire un, le firmware pour les deux cibles est sur GitHub à &lt;a href=&#34;https://github.com/Leicas/esp32-ball&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;github.com/Leicas/esp32-ball&lt;/a&gt;, avec les deux environnements PlatformIO (&lt;code&gt;feather&lt;/code&gt; pour le montage I2S, &lt;code&gt;hbridge&lt;/code&gt; pour celui-ci) et l&amp;rsquo;application compagnon en Python. Commencez par la &lt;a href=&#34;../esp32-rolling-stone/&#34;&gt;partie 1&lt;/a&gt; pour la physique et le chemin audio, puis basculez le drapeau de compilation et sentez la différence.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
