Où l’on fait un peu de mécanique et un peu d’USB HID sur STM32.

Pour ne pas complètement perdre la face après avoir décidé d’abandonner (provisoirement je l’espère) l’idée de faire un volant complet, je vais tout de même me pencher sur les accessoires, à savoir le levier de frein à main et le levier de vitesse, ainsi qu’un afficheur pour le rapport de boîte - et plus si affinités. Ces accessoires ont de toutes façons le double inconvénient d’être relativement chers et difficile à trouver pénurie, pénurie …) donc les fabriquer moi-même n’est pas totalement absurde.

Avant-propos - USB HID

Avant d’attaquer le vif du sujet, petit détour par le software. Ces accessoires ont un comportement software relativement simple, vu qu’il s’agit de capteurs en tout-ou-rien, et je vais utiliser des interrupteurs fin de course pour identifier les différentes positions. Pour transmettre l’état des leviers au PC, je vais passer par de l’USB “natif”, ce qui aura l’avantage de ne pas nécessiter de passer par un soft intermédiaire (si j’avais par exemple choisi d’utiliser la liaison série VCOM d’un ST-link). Par contre cela signifie qu’il faut utiliser un MCU compatible, et qu’il va falloir configurer la stack USB correctement.

Pour ce qui est du MCU, vu les pénuries actuelles il n’est pas évident de trouver un modèle adapté qui soit disponible. Donc je vais faire avec les moyen du bord. En plus il en faut un dont une carte d’éval est dispo, ça limite fortement. L’idéal ça serait un STM32F0x2, qui a de l’USB natif crystal-less (pas besoin d’avoir un oscillateur dédié pour l’USB). Bien entendu toute cette sous-famille est absolument introuvable, et pas prévue d’être en stock avant perpet’. Donc je vais faire avec ce que j’ai sous la main, dans un premier temps une carte Discovery STM32F469ZI, et potentiellement plus tard une Discovery STM32F746G. L’idée c’est de pouvoir faire de l’affichage et du touchscreen avec, genre plus tard.

Pour ce qui est de la configuration de la stack, plusieurs options sont possibles: - Configurer en HID “classique / bateau” en clavier et faire des appuis de touches, - Configurer en HID “gamepad” et aire des appuis de boutons,

Il est aussi possible de mixer plusieurs comportement en configurant en composite. Pour faire de l’affichage, là c’est une autre histoire. Il n’y a pas de classe dans l’USB qui corresponde “nativement” à un appareil de ce genre (appareil qui fait de l’affichage), donc il va falloir bricoler.

Pour rappel, je vais tout faire avec STM32CubeIDE par fainéantise.

Pour le HID il faut configurer dans CubeMX l’USB et le middleware avec le HID. Ensuite c’est un peu pointu pare qu’il faut aller modifier les fichiers de la stack. Par défaut quand on choisit un HID dans CubeMX ça génère du code correspondant à un dispositif de pointage (souris), et il faut changer le descripteur pour énumérer un clavier.

Un autre souci que j’ai rencontré est le passage en “SUSPEND”. Pour un HID, ne pas avoir d’activité pendant au moins 3ms le pousse en “SUSPEND”, et il faut faire un “remote wakeup” pour en sortir et pouvoir relancer la communication, sinon la commande send_report est masquée. Or, autant cela semble se passer automatiquement sur le STM32F429, ce n’est pas le cas sur le STM32F746 et le device reste en SUSPEND. Je ne suis pas le seul a avoir constaté ça, ceci-dit ça n’a pas l’air d’être ce que je rencontre, car la solution est “déjà implémentée” dans le code de usbd_conf.c. J’ai désactivé les modes basses consommation (LPM - low power mode) pour ne plus avoir le device bloqué en SUSPEND, par contre ça a l’air de flinguer la conf et Windows n’est pas content et indique un “data error” dans le gestionnaire de périphérique.

Note : ne pas oublier qu’à chaque fois que CubeMX re-génère du code, il faut rollback les modifs dans l’USB, qui se font écraser. Et soit ça ne compile plus, soit les actions envoyées au PC ne sont plus les bonnes, genre au lieu d’avoir des appui touches on récupère des mouvements de souris. Ne pas oublier de rollback l’USB !

Levier de frein à main

L’accessoire le plus simple : un bouton, et un levier pour actionner le bouton. j’ai décidé de ne pas m’emmerder et de faire un HID clavier et d’appuyer sur une touche arbitraire, que je mapperai dans les jeux. je pourrais aussi faire du HID gamepad et appuyer sur le bouton correspondant. Ça marcherait aussi et ça permettrait d’être compatible quand on enlève le levier.

Pour la méca j’ai décidé de faire au plus simple, avec juste un levier dont l’axe de rotation est à l’extrémité, et un interrupteur fin de course quelque part sur le milieu pour détecter qu’on actionne le levier. Pour l’axe j’ai trouvé une tige en laiton de \~6mm au Lab, que j’ai découpé pour faire un axe, et taraudé à la filière de chaque côté (et je n’ai pas réussi à tarauder droit, cela va de soi, sinon ça serait trop propre).

Concernant le switch fin de course, il est une bonne pratique de s’arranger pour que le mouvement qui va le déclencher n’aille pas enfoncer un objet dans le switch. Conseil que je n’ai pas respecté par pure fainéantise, cela va de soi.

"handbreak_archi.jpg,

Pour le levier je préfère utiliser de l’alu plutôt que de l’acier, pour éviter d’avoir une sale odeur sur les main après l’avoir utilisé. j’ai commencé avec de la languette avec des perçages oblongs. C’est totalement inadapté (ça gondole violemment, et un trou oblong pour un axe, c’est pas terrible), mais ça m’a permis de tester. Puis j’ai pris du tube carré de 15mm, et là c’était beaucoup mieux niveau rigidité. Pour fignoler j’ai mis du grip pour guidon de vélo de route et j’ai fait une pseudo-poignée. Ça donne un résultat pas mauvais.

Pour tenir tout ça sur la table, j’ai trouvé des serre-joints “de marqueterie”, qui ont l’avantage d’être simples et pas chers, et surtout de fournir des surfaces “plates” pour faire des trous et fixer des choses dessus.

Pour faire une sorte de carter, j’ai pris des coins de fabrication de meubles en acier zingué. Ils sont pré-percés, ce qui est pratique, par contre ya pas deux séries de trous qui sont les uns en face des autres, donc même en suivant les trous existants, si on fait un assemblage il faut re-percer une des deux pièces. Et de toutes façons c’est percé pour du M4 ou M5, donc pour du M6 il faut tout refaire.

Pour les supports “divers”, j’ai pris une languette en alu de 25mm de large et 3mm d’épaisseur, ça permet de faire des petites pièces facilement. A noter quand-même que l’alu a beau être facile à couper et plier, il a une sale tendance à saloper les limes, donc il faut une carde (une brosse métallique au pire) et nettoyer régulièrement, voire extraire les morceaux qui restent coincés. J’ai fait deux supports en “L” pour tenir l’axe du levier. Pour le switch fin de course, j’avais commencé en faisant un seul support avec une forme chelou pour “amener” le switch à un endroit où le levier appuie dessus quand on l’actionne. Ce n’est pas réglable donc ce n’est pas pratique, donc j’ai fait deux pièces en “L”, avec deux rainures pour des vis en M3, pour avoir du réglage. Comme noté précédemment, il est important de ne pas appuyer sur le switch directement. A défaut d’avoir un moyen de “translater” le mouvement du levier avec une pièce ad-hoc, j’ai a minima ajouté une butée mécanique, pour que le switch ne soit pas l’élément de butée mécanique qui se prend tous les efforts quand on actionne le levier.

Pour régler la course du levier, je mets une simple butée. Le plus réaliste serait d’avoir un vérin et une mesure de pression, mais bon, c’est compliqué à mettre en œuvre, et il faut rester raisonnable. Une butée donc, qui sera une rondelle sur une tige filetée, on règle la course en changeant la position de la rondelle qui est bloquée avec des vis.

Levier de boîte séquentielle

Un niveau de difficulté en plus, vu qu’il y a un interrupteur fin de course en plus. Il y a beaucoup de designs différent sur le net, suivant trois architectures possibles : avec deux ressorts en direct sur le levier (genre comme j’ai fait avec le frein à main), avec report sur un axe coulissant et toujours deux ressorts, ou plus rarement avec une étoile comme sur les vraies boîtes séquentielles. J’étais parti à faire une étoile, parce que ça me semblait plus compact, et plus intéressant niveau retour haptique. En pratique, fabriquer l’étoile est une tannée, j’ai voulu la faire dans de l’alu de 0.3, j’ai empilé 3 couches, j’ai percé les trous pour fixer les trois ensemble et avoir les “picots” qui permettent de pousser la roue (à la PF + DRO), et j’ai fait le contour de la roue à la main (plasma cut + lime). Le contour genre engrenage à la main c’est vraiment compliqué, et je me suis bien foiré dessus, ce qui m’a incité à changer d’approche.

Je suis donc parti sur un levier avec report sur un axe coulissant + deux ressorts. Pour faire la connexion entre le levier et l’axe coulissant, j’étais d’abord parti sur une rotule, mais c’est trop libre, et pas dans la bonne direction / dimension, ça ne permet pas d’avoir une translation pure, il y a un degré de rotation qui reste. Pour éviter ça, j’ai fait une pièce d’adaptation dans le tube carré de taille supérieure au levier, que j’ai creusé pour faire rentrer le bout du levier dedans, et j’ai tâché de faire un trou oblong pour l’axe qui relie les deux, de façon que le déplacement vertical de l’extrémité du levier ne se transmette pas à l’axe coulissant.

Pour l’axe coulissant en lui-même je suis parti sur une simple tige filetée en M6. Pour la connecter au levier j’utilise un adaptateur femelle-femelle + une vis. Avec le recul je pense qu’il aurait été plus pertinent de visser la tige filetée en direct dans la pièce (ou avec un boulon) et d’utiliser du tube rond 6mm partout, bref. Donc, adaptation, puis ressort et rondelle + boulon, puis deuxième ressort. Il y a deux “murs” qui enferment les ressorts, et l’axe passe à travers chaque. D’un côté c’est l’adaptateur femelle-femelle qui traverse, et de l’autre j’ai mis un tube rond en 6mm qui recouvre la tige filetée. Pour maintenir j’ai pris deux bouts de plastique pas trop clairement identifié, et j’ai percé / alésé à la PF pour avoir le bon diamètre, puis je les ai vissées sur les “murs”, dont l’ouverture a un diamètre plus élevé.

Pur détecter la position, deux fin de course, et j’ai fabriqué des espèces de plongeurs dans de l’alu de 0.3, que j’ai formé pour qu’ils se vissent sur la tige et appuient sur les switches quand on pousse ou on tire le levier. Pour tenir le tout j’ai pris un bout de rail à placo, c’est suffisamment rigide pour cet usage.

Au final ça donne ça:

Handbreak

Levier de boîte mécanique en H

Le challenge se complique. Ici il faut 8 interrupteurs fin de course, et surtout faire une grille sur deux dimensions. Si on regarde les designs existants, il y a beaucoup de variété, ça va de systèmes simples à base de “chemin” de grille découpé dans une plaque ou fait à l’impression 3D, dans lequel l’extrémité du levier vient se prendre, jusqu’à des systèmes ultra-complexes avec du report d’effort sur un barillet.

Le plus “simple” que j’ai trouvé au niveau mécanique c’est le levier TH8A de chez Trustmaster, qui va détecter la position du levier avec un circuit intégré capteur à effet hall qui détecte en 2 dimensions, dans lequel toute la partie mécanique se résume à des gorges formées dans la façade pour simuler un retour haptique de la mécanique de la boîte. C’est ultra-compact, vraiment très basique, et sûrement pas du tout réaliste, par contre ultra-fiable, vu qu’il n’y a quasiment aucune pièce mécanique, et totalement configurable, vu qu’il suffit de changer des seuils de détection en software pour changer le pattern ou la fonction (on peut l’utiliser en levier séquentiel, ça ajoute deux ressorts pour avoir une position centrale).

Le shifter Logitech “Driving Force” est beaucoup plus rustique, la détection de position est faite avec deux potars, comme un simple joystick. Donc plus simple que le capteur effet hall, mais moins fiable. La mécanique est très simple, mais plutôt bien foutue, il y a des “gorges” dans les “murs” adjacents dans lesquels des pins viennent se caler pour simuler les positions du levier, avec une gorge supplémentaire pour la marche arrière. Une solution simple, je trouve c’est bien trouvé. Par contre, ça limite le nombre de colonnes à 3, donc 6 vitesses max. Ça reste raisonnable, car de ce que j’ai entendu il y a très peu de bagnoles manuelles à plus de 6 vitesses, quelques Porsche, parait-il, donc improbable que je rencontre cette config vu les jeux auxquels je joue.

Perso j’ai envie de faire un truc un peu plus chiadé, mais surtout je n’ai pas vraiment les moyens de faire un retour haptique via des gorges dans des pièces plastiques. J’ai plutôt envide de partir sur un “vrai” truc mécanique.

L’idée sera d’avoir un axe avec une pièce qui fait pivot glissant dessus, sur laquelle se connectera le levier, et le déplacement d’un plongeur en-dessous de ce pivot glissant ira pousser des cales qui iront appuyer sur les interrupteurs fin de course.

UPDATE : Après quelques séances passées à essayer de faire une base mécanique potable, je me rends compte que c’est beaucoup plus compliqué que ce que je peux supporter. Très difficile de faire une base suffisamment rigide. Vu que je n’arrivais pas à progresser raisonnablement, j’ai décidé d’abandonner la mécanique et d’acheter un shifter Logitech. A 50 balles, meilleur rapport qualité / fonctionnalité / prix je trouve. Il se connecte au G29 via un DB9, et les potars sont reliés en direct dessus. Donc il suffit d’avoir le pinout et de faire de la mesure ADC, trivial. Par contre, impossible de trouver le pinout correct sur le net, il a fallu que je l’ouvre pour trouver comment ça se connecte. Voici comment c’est câblé à l’intérieur:

Logitech shifter

Il y a un petit PCB à l’intérieur, et là : surprise !

""

Le circuit est une EEPROM en I²C, donc aucun intérêt pour les commandes en elles-même. A mon avis elle doit contenir les calibrations de la pièce, vu qu’il doit être compliqué de garantir la reproductibilité du positionnement mécanique, ils doivent sûrement mesurer l’écart en fin de chaîne et mettre des valeurs de compensation dans l’EEPROM. Bien entendu on ne va pas l’utiliser, je re-ferai une calib que je stockera dans la carte du dashboard.

""

Sur le “petit” connecteur5 voies, on voit clairement qu’il y a la masse et l’alim aux extrémités en noir et jaune, les deux axes sont en marron et rouge, et le switch de marche arrière est en orange. Sur le switch en lui-même il y a un fil jaune et un fil orange, donc c’est du “open collector” vers l’alim. Par contre, visiblement il va vers une base de transistor, donc visiblement il y a un étage de buffer. Autre remarque : le connecteur côté DB9 n’a que 8 pins. Visiblement la pin d’alim côté PCB est connectée aux pins 7 et 9 du DB9. Par ailleurs, il y a une polarisation intermédiaire, pin 3, il faut y relier à l’alim pour que le deuxième étage fonctionne, et on a alors une sortie en collecteur ouvert avec un pull-up sur la pin 2.

Pin 4 -> X Axis Pin 8 -> Y Axis Pin 2 -> Reverse Button Pin 3 -> Reverse polarisation Pin 7,9 -> Vcc Pin 6 -> Ground

Avec un software de test, j’arrive aux seuils suivants sur mon exemplaire:

En X : 1400 à gauche, 2500 à droite, au milieu 1600-2400 En Y : 2800 en haut, 1000 en bas

Et voili voilà. Un peu de connectique et on est bons :)

Afficheur

Je vais faire un article dédié pour celui-là, vu la complexité du sujet.

- Flax