Partage
  • Partager sur Facebook
  • Partager sur Twitter

Arduino, commande PWM de moteur CC non linéaire

Objectif asservissement en position et identification

    13 avril 2021 à 11:54:39

    Bonjour,

    Je suis un faux débutant en Arduino et je l'utilise avec un pont en H pour commander un moteur à courant continu en vitesse, par variation de la PWM. Partout où j'ai pu glaner des informations sur cette commande, il est dit en substance :

    "Comme le moteur est très lent devant la fréquence de la PWM, il "voit" un signal continu à ses bornes, de tension égal à la tension moyenne issue de la PWM et du hacheur. Comme un moteur CC adopte une vitesse en régime permanent fonction linéaire de la tension à ses bornes, on peut en déduire une relation du type : Omega = k1*PWM - k2*CR, avec CR, le couple résistant de frottement sec"

    Voilà ce que j'obtiens en faisant varier le PWM sur la broche En du pont :

    Les Tick/s sont le nb de fronts du codeur par seconde...

    Avez-vous déjà constaté ce phénomène, qui ruine toute tentative d'identification en vue d'un asservissement en position :

    pas linéaire, alors que l'on va utiliser le PWM de 0 à PWMmax, pour revenir à zéro. A noter que la constante de temps est une constante pour un niveau de PWM donné, et quelle que soit la tension d'alimentation de puissance utilisée, mais ...

    A noter que les asservissements de vitesse et de position sont fonctionnels mais totalement incalculables. Les constantes des correcteurs ont été réglées par tâtonnement. On arrive a avoir un truc précis et rapide sans trop de dépassement, mais ça, c'est du à la robustesse de toute structure asservie.

    Si vous avez des explications du phénomène (non linéarité), je suis preneur. Si vous avez des solutions pour retrouver un comportement linéaire, encore mieux !!

    Cordialement

    • Partager sur Facebook
    • Partager sur Twitter
      15 avril 2021 à 16:31:04

      Le schéma :

      Le matériel : Carte arduino + kit de chez Digilent : PModHB5 et moteur CC Sha YanYe : IG220053X00041R avec codeur à 3 paires de pôles.

      Le programme :

      #define pin_AIN1 5
      #define pin_AIN2 6
      #define pin_SensorA 3
      #define pin_SensorB 2
      
      int compteur_time=0;
      const int time_all=10;  // cycle de 10 increments de 1 s soit 10 mesures toutes les secondes sur un temps total de 10 s
      const int vit_Mot=250;
      
      int i=0;
      int inc=0;
      const int nombre_increment=12; //nombre de mesures à partir de vit_Mot et un decrément de 20
      
      unsigned long moyenneTick=0;
      unsigned long temps_init=0;
      unsigned long temps_initf=0;
      unsigned long vartick=0;
      
      volatile unsigned long tick=0;
      
      void setup() {
        Serial.begin(115200); // initialise communication série
        while(!Serial);
        
        pinMode(pin_SensorA, INPUT_PULLUP); // broche en entrée 3
        pinMode(pin_SensorB, INPUT_PULLUP); // broche en entrée 2
        attachInterrupt(0, comptage, CHANGE ); // Attache l'interruption 0 (broche 2) à la fonction
        attachInterrupt(1, comptage, CHANGE ); // Attache l'interruption 1 (broche 3) à la fonction
          // change changement d'état : détection sur front montant
          
        //Configuration du Canal A
        pinMode(pin_AIN1, OUTPUT); // Broche Arduino réservée pour le sens de rotation du moteur A
        pinMode(pin_AIN2, OUTPUT);
        digitalWrite(pin_AIN1,LOW); // sens positf pin_AIN1=0 et pin_AIN2=PWM -sens négatif pin_AIN1=PWM et pin_AIN2=0
        analogWrite(pin_AIN2,0); // mode ARRET
        Serial.flush();
      }
      
      void loop(){
        if (inc<nombre_increment) {
          if(compteur_time<=time_all){
            digitalWrite(pin_AIN1,LOW);
            analogWrite(pin_AIN2,vit_Mot-20*inc);
            temps_init=millis();
            moyenneTick=moyenneTick+tick-vartick;
            vartick=tick;
            compteur_time++;
            delay(1000);
          }
          else{
            Serial.print(vit_Mot-20*inc);
            Serial.print("\t");
            Serial.println(float(moyenneTick)/time_all);
            analogWrite(pin_AIN2,0); // Arret
            delay(3000);
            inc++;
            compteur_time=0;
            moyenneTick=0;
            tick=0;
            vartick=0;
            temps_initf=temps_init;
            Serial.flush();
          }
        }
      }
      
      void comptage() {
      tick=tick+1; // incrémente variable comptage
      }

      Dans le programme, AIn1 et AIn2 sont intervertis par rapport au montage, car l'image date un peu.

      Les relevés ont bien été faits avec un montage cohérent avec les Pins Arduino...

      Cordialement

      ChC

      -
      Edité par ChC68 15 avril 2021 à 16:35:49

      • Partager sur Facebook
      • Partager sur Twitter
        16 avril 2021 à 8:11:30

        Tu n'auras jamais quelque chose de complètement linéaire avec un moteur CC puisque la vitesse dépend de la résistance mécanique et de la tension.

        Par exemple, si tu mets ta PWM à 50% et que le moteur est à vide, tu auras une vitesse élevée alors que tu auras une vitesse bien plus faible si le moteur force beaucoup (pour entrainer une charge lourde par exemple).

        C'est justement le rôle de l'asservissement de compenser cette non proportionnalité de la vitesse par rapport à la commande.

        Si ton moteur ne tourne pas assez vite, ton asservissement doit s'en rendre compte et compenser en augmentant le PWM jusqu'à atteindre la vitesse souhaitée.

        Bien sûre, cette compensation sera plus ou moins importante suivant l'endroit de ta courbe non linéaire (pour les vitesse faible, ta courbe est plus pentue) mais aussi suivant la charge du moteur (si le moteur force beaucoup, il faudra compenser beaucoup plus que lorsqu'il est à vide).

        A toi de trouver les bons coefficients pour que cette compensation reste fonctionnelle sur toute la plage d'utilisation du moteur.

        -
        Edité par lorrio 16 avril 2021 à 8:12:26

        • Partager sur Facebook
        • Partager sur Twitter
          17 avril 2021 à 14:39:42

          Salut Lorrio,

          Merci pour cette réponse, mais mon problème de non linéarité est constaté à vide. Ce qui m'intéresse, c'est de comprendre pourquoi dans ce cas on n'est pas linéaire.

          Les modèles habituellement utilisés pour prendre en compte sont : un frottement sec (couple résistant constant Cr0) et un frottement fluide (couple résistant proportionnel à la vitesse de rotation f.Omega). Vue la très faible évolution de l'intensité avec la vitesse, ce modèle devrait suffire à calculer la vitesse d'un système qui serait par ailleurs linéaire. Avec un tel modèle, on obtient une vitesse en régime permanent qui est fonction linéaire de la tension d'alimentation. Le coefficient de frottement fluide f intervient au dénominateur des coefficients de U et de Cr0.

          Il semblerait donc que, contre toute attente, la tension moyenne délivrée par le pont en H ne soit pas proportionnelle au rapport cyclique imposé par la sortie de l'Arduino. Comment expliquer cela ?

          Les asservissements réalisés sont fonctionnels, mais ce n'est pas satisfaisant pour l'esprit de ne pas pouvoir donner un modèle de comportement, même grossier, du pont en H, que je supposais jusqu'à présent "parfaitement proportionnel".

          Cordialement

          • Partager sur Facebook
          • Partager sur Twitter
            17 avril 2021 à 18:08:30

            Malheureusement, aucun système n'est parfait dans la vie donc tu auras forcément des non linéarités à des moments.

            Mais puisque tu as la courbe de réaction à vide, tu pourrais très bien t'en servir pour faire une linéarisation.

            Pour cela, on va reprendre le même graphique mais en changeant l'axe Y par une valeur entre 0 et 255, en considérant que le 1650 correspond à 255.

            Du coup, avec une règle de 3, on aurait ceci :

            Et maintenant, on va chercher à linéariser quelque points.

            Voici ce que ça donne pour les vitesses hautes :

            Si tu veux tourner à 1450 tr/min, soit un équivalant PWM de 224 sur un système 100% linéaire, on se rend compte que ce n'est pas 224 que tu dois utiliser mais plutôt 190.

            Donc on va linéariser ces 2 points en disant que tout l'intervalle [224;255] devra finalement être l'intervalle [190;255].

            On poursuit avec un autre point :

            Ici, on voit que pour faire des vitesse entre 193 et 224, ce n'est pas l'interval [193;224] qu'il faut envoyer en PWM moteur mais l'interval [135;190].

            Et ainsi de suite, tu fais ça pour toute l'échelle, et tu retranscrit ça en code avec la fonction map.

            Ce qui donnerait un truc de ce genre :

            void linearize ( int pwm ) {
            
                if ( (pwm >= 0) && (pwm <= ...) ) {
                    return ...
                }
            
                if ( (pwm >= 193) && (pwm <= 224) { // Le [193;224] devient [135;190]
                    return map(pwm, 193, 224, 135, 190);
                }
            
                if ( (pwm >= 224) && (pwm <= 255) { // Le [224;255] devient [190;255]
                    return map(pwm, 224, 255, 190, 255);
                }
            
                return 0;
            
            }

            Et du coup, plutôt que de faire analogWrite(val);, tu devras faire analogWrite(linearize(val));

            Et voila :)

            Si tu retrace ta courbe pour toutes les valeurs de analogWrite(linearize(val)), tu devrais avoir un système bien plus linéaire.

            Plus tu auras pris de points de linéarisation, plus ce sera précis, mais ça demandera plus de calcul à l'arduino pour tester tous les if.

            Je te conseille de prendre 4 ou 5 points biens placés sur ta courbe, ça devrait être suffisant.

            -
            Edité par lorrio 17 avril 2021 à 18:12:45

            • Partager sur Facebook
            • Partager sur Twitter
              18 avril 2021 à 12:20:02

              Si tu compares ta courbe avec les courbes de cette page, pour différents moteur, où la vitesse semble corrélée linéairement à la tension moyenne pour une fréquence PWM de 1600Hz mais a la même forme que ta courbe pour une fréquence plus faible, je ne sais pas si ça indique que la fréquence PWM que tu utilises (490Hz sur un arduino UNO si on ne change rien aux registres) n'est pas assez élevée pour ton moteur.

              • Partager sur Facebook
              • Partager sur Twitter
                20 avril 2021 à 17:31:57

                Salut alexisdm,

                Effectivement, très bonne remarque !

                En modifiant la fréquence du PWM, on obtient quelque chose de linéaire, mais pour la fréquence la plus élevé de la broche 9. Je modifie un diviseur, et si je n'ai pas fait de bêtises, les fonctions millis et micros ne sont pas perturbées. 31250Hz, sinon, ça reste non linéaire...

                On est loin de l'image idéale du hacheur, dupliquant servilement le signal rectangulaire (en tension) de la PWM de l'arduino, tout en fournissant le courant appelé par le moteur :

                En bleu, 0-5V pour la PWM, en rouge 0-6V pour la tension aux bornes du moteur, i.e. en sortie du hacheur.

                Merci Lorrio pour ces pistes de linéarisation (d'inversion ?) de la caractéristique vitesse/PWM. Très intéressant !

                Malheureusement, on constate aussi une très forte dépendance de la constante de temps à la valeur du PWM... Ce qui en fait une constante... variable, ce qui n'est vraiment pas cool pour faire coïncider calculs et résultats expérimentaux.

                Je pense que je vais devoir utiliser la fréquence PWM max pour pouvoir réaliser une identification du système moteur+hacheur, puis calculer ce que ça doit donner théoriquement dans une boucle d'asservissement en position, pour enfin mesurer ce que ça donne expérimentalement.

                Avec un peu (beaucoup ?) de bol, on devrait avoir des résultats proches. En fait, c'est le but, mais peut être que le modèle linéaire n'est pas réaliste. ça m'embarrasserait beaucoup, car c'est ce qu'on m'a appris, et ... c'est ce que je dis à mes élèves !

                Pour info, quand même, les résultats de mesure de la relation entre vitesse en régime permanent d'un moteur CC (un autre), en fonction de la tension d'alimentation, contrôlée directement avec une alim ajustable. C'est linéaire, ouééé !

                Voilà pourquoi j'étais aussi étonné d'avoir l'autre courbe en modulant avec la PWM, d'autant que la notice du PmodHB5 dit que pour 2kHz (quand même), la sortie du hacheur est conforme (en tension, forme rectangulaire, pas de retard, pas de distorsion) à l'entrée en PWM, et annonce une tension moyenne égale à la tension d'alimentation fois le rapport cyclique - Point barre -

                Bon, avec une charge de type moteur, ça a l'air plus compliqué !

                Merci pour vos contributions, ça avance

                -
                Edité par ChC68 20 avril 2021 à 17:34:12

                • Partager sur Facebook
                • Partager sur Twitter
                  20 avril 2021 à 19:09:48

                  Il ne faut pas oublier qu'un moteur est très inductif et que le comportement d'une inductance dépend de la fréquence : ZL = j * 2 * PI * F * L.

                  Avec la tension continue d'une alimentation de laboratoire, la fréquence est nulle (F=0Hz), donc ZL=0 et ce coté inductif s’efface, d'où le fait que cela devienne bien plus linéaire.

                  Avec un hacheur, il y a beaucoup d'autres choses qui rentrent en jeux à cause de la fréquence de hachage.

                  Augmenter la fréquence permet d'améliorer les choses mais il ne faut pas non plus trop en abusé car à partir d'un certain seuil, les hautes fréquences apportent plus inconvénients que d'avantages.

                  Un bon compromis consiste à découper aux alentours de 20 kHz voir légèrement au dessus, ce qui permet de ne pas être audible (en dessous de 20 kHz, on peut entendre le moteur siffler), tout est apportant de bon résultats (comportement du moteur OK, pas trop de chauffe du pont, etc...)

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Arduino, commande PWM de moteur CC non linéaire

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                  • Editeur
                  • Markdown