Vélo électrique, épisode 2 : une trouvaille inespérée

Déçu des performances du système “à la Solex”, je laisse tomber un peu le projet : je pense avoir fait le tour des possibilités offertes par la trottinette. Cependant, je n’aurai utilisé que du matériel de récupération, je n’ai donc rien déboursé.

Quelques mois plus tard, je suis chez un ami et aborde le sujet de ma tentative d’électrification de vélo et de l’échec associé. Ce dernier me regarde alors avec des yeux écarquillés en me disant quelque chose comme :

— Ah, mais tu sais, si tu veux te fabriquer un vélo électrique, je peux peut-être t’aider car j’en ai un au garage depuis un bon moment, mais sans batterie et avec l’électronique cramée. Si tu le veux je te le donne !

A mon tour d’écarquiller les yeux :

— Ben oui, carrément, mais c’est que maintenant que tu me le dis ???

— Ben, comment voulais-tu que je sache que ça t’intéressait ?

Bref, une invitation à un barbecue plus tard en guise de remerciement, je repars avec une épave cette fois de vélo électrique –bien plus intéressante que la trottinette– dans la voiture. Ce dernier est vieux et lourd. De plus, il n’a qu’un plateau avec un développement relativement court, assez inadapté à mes trajets : je cherche de la vitesse sur le plat, mais je dois aussi pouvoir monter des côtes plutôt raides. Le moteur est intégré au moyeu arrière et je décide de ne conserver que cette roue. Je démonte donc tout ce qui peut être intéressant et apporte le reste à la déchetterie.

Je suis ravi de cette découverte inespérée : que demander de mieux qu’une roue de vélo déjà motorisée ? Je n’ai qu’à remplacer la roue arrière du mien par celle-ci pour arriver à mes fins. Il n’y a qu’un problème : autant le moteur DC était simple à piloter, autant c’est un moteur brushless que je dois désormais faire tourner. Je n’ai pas le matériel nécessaire et j’avoue être un peu frustré face à cette roue prometteuse mais désespérément immobile.

De plus, je n’ai jamais touché à ce type de moteur et ne connait que sa théorie grâce à des infos glanées ici et là. Puisque l’électronique d’origine est HS, je vais devoir créer moi-même le contrôleur. Assez intimidant pour mon “moi” de l’époque, mais aussi terriblement challengeant.

En effet, contrairement aux moteurs DC qui ne nécessitent qu’une tension continue pour tourner, les moteurs brushless exigent trois signaux idéalement sinusoïdaux déphasés de 120°. Autrement dit, il faut intercaler un onduleur triphasé entre la batterie et le moteur, nettement plus complexe que mon hacheur PWM précédent.

Petite parenthèse sur le fonctionnement d’un moteur brushless. Il peut paraître complexe à première vue, mais c’est tout bête lorsque que l’on a eu le déclic. Dans un moteur à courant continu, le bobinage est sur le rotor et un collecteur associé à des balais lui fournissent l’énergie électrique :

Le rôle du collecteur et des balais est essentiel, mais oublions-le dans un premier temps et supposons que l’on alimente directement les bobinages. Le rotor baigne dans un champ magnétique constant, souvent réalisé par des aimants permanents. Le champ magnétique créé par le rotor engendre alors une force à l’origine de la rotation, le pôle Nord du rotor étant attiré par le pôle Sud du stator et inversement :

Le rotor fait donc un demi-tour jusqu’à ce que ses pôles magnétiques arrivent en face de leurs homologues opposés du stator. Le mouvement s’arrête. Pour qu’il continue, il faut inverser la polarité du rotor pour réaliser le demi-tour restant, avant de recommencer le cycle.

C’est le rôle du collecteur et des balais. Sur les schémas ci-dessus, le moteur n’a qu’une paire de pôles et le collecteur est divisé en deux : un demi-cercle pour une polarité, l’autre demi-cercle pour l’autre. La polarité du rotor dépend donc uniquement de sa position relativement au stator et s’inverse automatiquement à chaque demi-tour. Ainsi, la polarité du rotor est en permanence telle qu’un couple s’y exerce.

Le moteur brushless est en tout point identique à un moteur DC habituel, hormis qu’il ne possède pas de collecteur et de balais responsable de l’inversion forcée de la polarité du rotor. C’est donc au système électronique de le faire pour lui, exactement au bon moment. Pour cela, des capteurs Hall détectent la position du rotor et indiquent au contrôleur quand il est temps de le faire. Certains moteurs n’en disposent pas, on peut alors détecter le moment venu le mesurant la variation de f.c.é.m induite (“back EMF” en anglais), mais je ne m’y intéresserai pas dans cet article.

Bref, pour piloter mon moteur brushless, la solution la plus simple serait d’utiliser un ESC du commerce, dédié normalement au pilotage des moteurs de modélisme. Toutefois, ces ESC n’utilisent pas de capteurs à effet Hall mais la f.c.é.m. induite pour déterminer la position du rotor. Or cette tension est proportionnelle à la vitesse de rotation, et les moteurs de modélisme tournent bien plus vite que ma roue de vélo : j’ai peur que la f.c.é.m. générée par ma roue ne soit pas suffisante pour la rendre détectable. Si j’en avais dans un tiroir, il aurait suffi que j’essaie, mais ce n’est malheureusement pas le cas. De plus, le vélo engendre un couple résistant qui peut être très important à l’arrêt et le moteur doit quand même pouvoir démarrer dans ce cas : je n’ai donc pas le choix que d’oublier les ESC de modélisme et d’utiliser à la place un contrôleur recourant aux capteurs Hall intégrés au moteur.

J’achète donc sur eBay pour une quinzaine d’euros un contrôleur chinois prometteur :

Sur les bornes de gauche se connecte la partie puissance. De haut en bas : le positif de la batterie, le négatif puis les trois phases du moteur. Sur la partie de droite se trouve la partie commande : on voit un connecteur sur lequel arrivent notamment un signal 0/5V pour la vitesse de rotation et un signal logique pour le sens de rotation. L’illustration ci-haut ne montre pas exactement le circuit que j’ai acheté car le mien possède en plus un connecteur à 5 points pour les 3 capteurs Hall ainsi que leur alimentation.

Je monte les transistors sur un dissipateur (je vous laisse imaginer la difficulté rencontrée, compte tenu de la position dans laquelle ils se trouvent…) et commence les essais. Le moteur possède 5 fils de petite section que je devine utilisés par les capteurs Hall de couleurs rouge, noir, vert, bleu et jaune. Je suppose que le rouge et le noir correspondent à l’alimentation, les trois autres couleurs aux signaux des 3 capteurs. Après alimentation sous 5V à travers une résistance de 100 ohms pour limiter la casse au cas où ce câblage ne soit pas le bon, j’obtiens bien 3 signaux de type collecteur ouvert sur les fils jaune, vert et bleu. Le câble de moteur possède également trois fils de plus forte section et de couleurs identiques aux signaux des capteurs Hall : c’est l’alimentation triphasée du moteur lui-même.

Sur le contrôleur apparaît une sérigraphie A, B et C côté moteur tout comme côté capteurs Hall. Je n’ai aucune documentation sur les signaux attendus par le contrôleur au niveau de ces capteurs, je connecte donc naïvement chaque couleur en face de chaque lettre. Après une mise sous tension à travers un bloc secteur possédant une protection en courant à quelques ampères, déception : le moteur bouge erratiquement, mais ne tourne pas. Je tente à nouveau ma chance en croisant des fils, en changeant les lettres associées aux couleurs… Rien n’y fait. Je suis déçu d’avoir patienté plusieurs semaines que le colis arrive pour rien : j’espérais voir enfin cette roue tourner.

Je n’ai pas le schéma électrique et le vendeur n’a aucune information supplémentaire ni aucune aide à m’apporter. De plus, cette carte semble pouvoir fonctionner avec ou sans capteurs Hall : il y a en effet un quadruple comparateur LM339 utilisé, je suppose, pour détecter la f.c.é.m. sur l’enroulement non alimenté. Par contre, je ne sais même pas s’il y a une configuration à faire pour choisir le mode de contrôle avec ou sans capteurs Hall. Je tente donc plusieurs choses :

  • Je n’ai aucune idée des types de signaux attendus par le contrôleur pour les entrées Hall. Je convertis donc les signaux à collecteur ouvert en push-pull, au cas où…
  • J’inverse également leur polarité, en version collecteur ouvert comme push-pull.
  • Le tout avec toutes les combinaisons de couleurs et de lettres…

Rien n’y fait, je n’ai que quelques petits mouvements saccadés et aucun couple. Je suis assez découragé et laisse tomber le projet pendant plusieurs mois.

Je pars alors 7 mois au Canada pour réaliser mon projet de fin d’études. A mon retour, je retombe sur cette roue de vélo qui traîne dans le garage. Ayant un peu de temps libre à cette période, je replonge dans le projet. J’essaie à nouveau de faire fonctionner le contrôleur acheté sur eBay avec un regard neuf, au cas où j’aurais loupé quelque chose un an auparavant. Malheureusement, je reviens au même constat. Je décide alors d’abandonner cette interface et de créer mon propre circuit de contrôle. Néanmoins, il y a déjà sur la carte 6 MOSFET N de puissance avec leurs drivers associés ainsi qu’un régulateur 12V pour leur commande et 5V pour la logique. Je me suis de plus embêté à usiner et fixer un dissipateur, ce serait dommage de perdre cela. Je décide donc de conserver la partie interface de puissance de la carte, mais de recréer le système de contrôle.

Pour cela, je dessoude la puce jouant ce rôle. Elle est marquée JY01A et est ici :

On remarque en bas à droite le quadruple comparateur LM339 dont j’ai parlé plus haut ainsi que les trois drivers de demi-ponts IR2101S. Un shunt de mesure de courant est visible tout en bas, à gauche.

Je déssoude donc le composant en question et soude à la place une nappe terminée par un connecteur HE10. Cette nappe de 9 conducteurs transporte donc l’alimentation +5V, la masse, les 6 signaux de commande des demi-ponts (un pour chaque transistor) ainsi que la tension mesurée par le shunt.

Je n’ai malheureusement pas de photo de la nappe soudée à la place de la puce de contrôle.

De l’autre côté, je fabrique avec du Veroboard une carte embarquant un Arduino Nano et un AOP MCP602 pour amplifier la tension issue du shunt :

La carte est donc plutôt simple. On voit au premier plan le connecteur HE10 mâle qui accueille la nappe allant à l’interface de puissance. A droite, le connecteur blanc monte au guidon jusqu’à un interrupteur 3 positions pour activer le moteur ou non, avec deux vitesses possibles. En position grande vitesse, les deux fils sont directement reliés. En petite vitesse, une résistance est présente entre les deux et à l’arrêt, ils sont isolés. J’utilise donc une entrée analogique de l’Arduino pour discriminer ces 3 états différents. A gauche, le bornier débrochable vert alimente en 5V un feu avant blanc et un feu arrière rouge. La puissance est limitée et le feu avant sert seulement à rendre le vélo plus visible, et n’a pas vocation d’éclairer la route. Ces feux sont en permanence éclairés, de jour comme de nuit : je ne suis pas à quelques centaines de milliwatts près.

Je peux donc commencer à écrire le programme. J’ai donc besoin au minimum :

  • De six sorties numériques pour piloter les trois demi-ponts
  • De trois entrées numériques pour les capteurs à effet Hall
  • D’une entrée analogique pour lire l’interrupteur du guidon

J’ajoute également, pour plus de confort :

  • Une entrée analogique pour lire le courant moteur (non utilisée pour le moment)
  • Une entrée numérique pour détecter le mouvement du vélo grâce à un ILS et un aimant fixée sur une roue.

A chaque instant, le courant circule dans deux demi-ponts (aussi appelés bras) parmi les trois, le dernier étant bloqué. Deux transistors sont donc traversés par le courant à tout moment. Le schéma ci-dessous représente un pont en H monophasé, que l’on peut assimiler à un pont en H triphasé possédant à tout moment un bras désactivé :

Parmi les six sorties numériques utilisées pour commander le pont triphasé, trois seulement ont donc besoin d’être capables de générer un signal PWM. En effet, pour hacher le courant circulant dans le moteur, il faut donc :

  • Soit que les deux transistors commutent simultanément au rythme du signal PWM
  • Soit laisser l’un en permanence passant (à l’échelle de la fréquence du PWM) et laisser le second hacher le courant.

La première solution n’apporte selon moi aucun avantage par rapport à la deuxième qui ne monopolise qu’une sortie PWM par bras d’onduleur au lieu de deux.

J’attire l’attention sur une erreur couramment réalisée : appliquer deux signaux PWM sur les deux transistors sans prendre garde à les maintenir en phase (par exemple, en appelant la fonction Arduino analogWrite() sur les grilles de chaque transistor sans se poser plus de questions). Le courant ne circulant dans le moteur que lorsque les DEUX transistors conduisent simultanément, appliquer un rapport cyclique de 25% sur les deux n’est pas une condition suffisante pour que le moteur reçoive également un rapport cyclique de 25%. Dans le pire cas, si le premier transistor conduit lorsque le second est bloqué et réciproquement, aucun courant ne circule dans le moteur malgré les deux rapports cycliques non nuls. Utiliser la seconde solution résout ce problème. On obtient donc un chronogramme de ce type :

La rotation du moteur se fait en 6 étapes (appelées sectors sur le graphique ci-haut). Par exemple, durant la première étape, le bras vert à son transistor du haut qui reçoit le signal PWM tandis que le bras bleu a son transistor du bas en permanence passant. Le courant circule donc, dans cette phase, entre les bras vert et bleu dans le sens vert -> bleu.

Le transistor du haut étant un NMOS bootstrappé, il n’est pas possible de le garder passant en statique (ou sur une longue durée). J’ai donc choisi d’appliquer les 3 signaux PWM sur les transistors du haut. Les transistors du bas, qui peuvent être pilotés en statique sans problème, ont la commande constante relativement à la fréquence du PWM.

Entrons maintenant dans le vif du sujet. La première chose à faire est de modifier le prescaler des timers de l’ATmega328p générant les signaux PWM. En effet, la fréquence par défaut de 490Hz est bien trop faible. Comme on le voit sur le chronogramme, la période du PWM doit être très courte devant la durée de chaque étape. Or, sur mon moteur, lorsqu’il tourne à pleine vitesse, chacune ne dure environ qu’une milliseconde. La fréquence du PWM serait donc plus lente que celle des étapes. Je modifie le prescaler pour obtenir un PWM à 4kHz environ, ce qui est mieux mais reste le strict minimum : à vitesse maximale, seules 4 périodes de PWM ont lieu durant chaque étape. Les essais montrent toutefois que c’est suffisant.

C’est la première fois que j’utilise un moteur brushless et je n’ai aucune idée de la correspondance entre l’état des capteurs Hall et celui du pont en H. Je ne sais pas non plus dans quel ordre piloter les transistors de l’onduleur afin de créer un cycle complet. Pour remédier à cela, j’alimente chaque enroulement en DC, évidemment sous tension réduite car le courant n’est limité que par le résistance du cuivre, puis je mesure l’angle que prend le rotor. Ainsi, après avoir mesuré les angles correspondant aux 6 étapes, il est aisé de savoir dans quel ordre les appliquer.

A ce stade, j’ai donc un moteur qui se comporte comme un moteur synchrone (ou un moteur pas-à-pas, c’est à peu près pareil), et donc avec les mêmes défauts :

  • Si la fréquence de pilotage est trop faible, le rotor “s’arrête” entre les différentes étapes ce qui conduit à l’augmentation du courant dans les enroulements, qui là encore ne devient limité que par la résistance du cuivre.
  • Le mouvement n’est donc pas régulier et le moteur engendre des grondements et des vibrations.
  • Si la fréquence de pilotage est trop élevée par rapport au couple résistant, le rotor n’a pas le temps d’atteindre son point d’arrivée lorsque l’étape suivante arrive, ce qui engendrera son décrochage.

Il devient alors nécessaire d’asservir les transitions entre chaque étape en fonction de la position réelle du rotor plutôt que de passer à la suivante après un délai fixé : c’est le rôle des capteurs Hall. Le contrôleur doit donc attendre que le rotor ait atteint la position finale de l’étape en cours tout en passant sans retard à la suivante le moment venu. Pour obtenir la correspondance entre le changement d’état des capteurs et la transition à effectuer, j’alimente à nouveau chaque enroulement en DC en mesurant l’angle pris par le moteur. Cette fois, je scrute parallèlement l’état de chaque capteur pour regarder lequel a changé durant la transition entre chaque étape. J’obtiens le cycle suivant :

  • Au front descendant de C, mettre le bras B en haute impédance et C à l’état bas.
  • Au front montant de B, mettre le bras B à l’état haut et A en haute impédance.
  • Au front descendant de A, mettre le bras C en haute impédance et A à l’état bas.
  • Au front montant de C, mettre le bras C à l’état haut et B en haute impédance.
  • Au front descendant de B, mettre le bras A en haute impédance et B à l’état bas.
  • Au front montant de A, mettre le bras A à l’état haut et C en haute impédance.

Comme je ne savais pas si tous les moteurs suivaient le même cycle, j’ai ainsi préféré faire les mesures sur le mien plutôt que me baser sur la littérature. Mais je retrouve bien le chronogramme habituel des moteurs brushless :

Mon programme fonctionne sur fronts et attend le changement d’état d’un capteur Hall pour piloter le pont en H en conséquence. Cela fonctionne bien hormis au démarrage : tant que le moteur ne tourne pas, il n’y a pas de fronts et le moteur ne tourne donc pas (c’est un cercle vicieux !). Il faut donc un autre mécanisme pour le lancer. Pour cela, j’ajoute une durée maximale à l’attente des fronts : si le front attendu n’arrive pas dans les 100ms, je passe quand même à l’étape suivante. Ainsi, à l’arrêt ou presque, le moteur est mis en rotation en boucle ouverte, à la manière d’un moteur synchrone, avec une étape toutes les 100ms. Il ne tourne alors pas très “rond”, mais ce n’est pas gênant : au bout de quelques étapes, lorsqu’il a pris suffisamment de vitesse, les fronts arrivent avant les 100ms imparties et le moteur fonctionne alors en boucle fermée.

Au démarrage, la séquence commence toujours par une étape arbitraire qui est très certainement différente de celle attendue par le rotor. Ce n’est pas gênant non plus : il n’y a que 6 étapes en tout, le programme passant par chacune, il y aura forcément un moment où ce sera la bonne. Le moteur démarre alors à ce moment-là. Avant, il fonctionne bien sûr erratiquement, mais cela ne dure que 500ms au maximum avec un PWM faible : ce n’est pas gênant.

Le code ressemble donc à quelque chose comme :

etape = 1;
while(1)
{
    if(etape == 1 && digitalRead(HALL_B))
        etape = 2;
    else if(etape == 2 && !digitalRead(HALL_A))
        etape = 3;
    else if(etape == 3 && digitalRead(HALL_C))
        etape = 4;
    else if(etape == 4 && !digitalRead(HALL_B))
        etape = 5;
    else if(etape == 5 && digitalRead(HALL_A))
        etape = 6;
    else if(etape == 6 && !digitalRead(HALL_C))
        etape = 1;

    if(millis() - dernierChangement > TIMEOUT)
    {
        etape++;
        if(etape == 7)
            etape = 1;

        valeur_pwm = PWM_MINIMUM; // Tant que l'on a des timeouts, on réinitialise la valeur du PWM au minimum afin qu'il n'y ait pas de rampe d'accélération tant que des timeouts ont lieu
    }

    if(etape != ancienneEtape)
    {
      dernierChangement = millis();
      ancienneEtape = etape;
    }

    
    if(etape == 1)
    {
        setPhase(PH_B, ETAT_X);
        setPhase(PH_C, ETAT_B);
    }
    else if(etape == 2)
    {   
        setPhase(PH_A, ETAT_X);
        setPhase(PH_B, ETAT_H);
    }
    else if(etape == 3)
    {    
        setPhase(PH_A, ETAT_B);
        setPhase(PH_C, ETAT_X);
    }
    else if(etape == 4)
    {    
        setPhase(PH_B, ETAT_X);
        setPhase(PH_C, ETAT_H);
    }
    else if(etape == 5)
    {   
        setPhase(PH_A, ETAT_X);
        setPhase(PH_B, ETAT_B);
    }
    else if(etape == 6)
    {    
        setPhase(PH_A, ETAT_H);
        setPhase(PH_C, ETAT_X);
    }
}

Il peut paraître plus simple de réaliser une commande sur états plutôt que sur fronts. Autrement dit, ne pas chercher à imposer le cycle dans le programme en passant à l’étape suivante le moment venu mais lire en permanence l’état des 3 capteurs et piloter à tout instant les phases adaptées.

Cela permet d’avoir du couple même à l’arrêt et de résoudre le problème du démarrage. Néanmoins, le moteur ne tourne pas très “rond” avec cette méthode, comme s’il y avait des rebonds dans les signaux issus des capteurs Hall et qu’au moment des transitions, le moteur avait tendance à revenir en arrière. Je reste donc sur la première méthode.

En bonus, j’ai finalement trouvé, un jour presque par hasard, le schéma le mon contrôleur chinois. Je l’ai trouvé trop tard pour en avoir l’utilité, mais je le poste ici au cas où cela serve à quelqu’un :

Cet article (un peu plus théorique que le précédent, je le conçois) est désormais terminé. J’ai enfin réussi à faire tourner cette roue, il n’y a plus qu’à l’intégrer sur le vélo !

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *