IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

Séquence de pilotage d'un moteur CC avec asservissement de position


Sujet :

Arduino

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Novembre 2016
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Novembre 2016
    Messages : 29
    Par défaut Séquence de pilotage d'un moteur CC avec asservissement de position
    Bonjour,

    Je galère sur un truc certainement simple mais je n'arrive pas à faire plusieurs séquences d'asservissement sur mon moteur. En gros, je lui demande de faire 1000inc dans un sens puis 500 dans l'autre..
    Ça se joue dans la fonction sequence()?


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    // Ce code permet d'asservir en position angulaire un moteur à courant continu.
     
    #include <SimpleTimer.h>
     
    SimpleTimer timer;                 // Timer pour échantillonnage
    int motorA;
     
    // définition des sorties
    int pwm_mot = 11; // pwm moteur correspond au rapport cycliqe du hacheur : pilotage de la puissance moteur (11 pour le moteur A et 3 pour le moteur B)
    int break_mot = 8; // frein moteur : actionne ou libère le frein avec High et Low (8 pour le moteur A et 9 pour le moteur B)
    int sens_mot = 13; // sens de rotation du moteur : positif ou négatif avec High et Low (12 pour le moteur A et 13 pour le moteur B)
     
    // définition des entrées
    int PinA = 20;//compteur 1
    int PinB = 21;//compteur 2
     
    //init echantillonage
    unsigned int time = 5; // la mesure du temps démarre à 5ms
    const int periode_echantillonnage = 2; // définit la période d'échantillonnage en ms
     
    //init compteur :
    signed int codeur = 0; //position de départ=0 
     
    //consigne
    int consigne=0; // correspond à 1000 pas du codeur
    // initialisation des variables de calcul pour le correcteur PID
    signed int erreur = 0; //erreur
    signed int erreurPrecedente = 0;
    signed int somme_erreur = 0;
     
    //Definition des constantes du correcteur PID
    float kp = 15;               // Coefficient proportionnel
    float ki = 5;          // Coefficient intégrateur
    float kd = 0;       // Coefficient dérivateur
     
     
    /* Routine d'initialisation */
    void setup() {
     
      Serial.begin(115200);         // Initialisation port COM
     
    // Déclaration des ports de sortie
      pinMode(sens_mot, OUTPUT);
      pinMode( pwm_mot, OUTPUT );
      pinMode( break_mot, OUTPUT );
     
    // Déclaration des ports d'entrée
      pinMode(PinA, INPUT);  //sortie encodeur
      pinMode(PinB, INPUT);   //sortie encodeur
     
      // Définition des fonctions nécessaires à la lecture des signaux du codeur
      // Interruption de l'encodeur A en entrée 0 (pin 2) A chaque changement d'état sur le pin concerné on fait tourner la routine codeurA ou codeurB
      attachInterrupt(3, codeurA, CHANGE);
      // Interruption de l'encodeur A en entrée 1 (pin 3)
      attachInterrupt(2, codeurB, CHANGE);
     
      analogWrite(pwm_mot, 0);  // Initialisation sortie moteur à 0 
      delay(300);                // Pause de 0,3 sec pour laisser le temps au moteur de s'arréter si celui-ci tourne
      motorA=timer.setInterval(periode_echantillonnage, asservissement);  // Echantillonage pour calcul du PID et asservissement ; la routine est relancée à chaque période d'échantillonnage
      Serial.print("setup");
      sequence();
    }
     
    void loop()    {
      timer.run();  //on fait tourner l'horloge
      }
     
     
    void sequence(){
      consigne=1000;
      timer.enable(motorA);
      delay(5000);
      timer.disable(motorA);
      consigne=-500;
      timer.enable(motorA);
    }
     
     
     
    // Cette fonction est appelée à chaque période pour calcul du correcteur PID
    void asservissement()
    {
     
     time += periode_echantillonnage;  // on ajoute la période d'échantillonnage à la variable "Time" pour pouvoir tracer des variables en fonction du temps
      erreur = consigne - codeur; // recalcule l'erreur à chaque période d'échantillonnage
      somme_erreur += (erreur*periode_echantillonnage); // permet de calculer l'intégrale de l'erreur par une somme (pour le correcteur intégral)
     
      // Calcul de la commande du hacheur : rapport cyclique
      signed int rapport_cyclique = kp * (erreur/periode_echantillonnage) + kd * ((erreur - erreurPrecedente)/(periode_echantillonnage*periode_echantillonnage)) + ki * ((somme_erreur)/time); //calcul de la sortie du correcteur PID
     
      erreurPrecedente = erreur; // Ecrase l'erreur précedente par la nouvelle erreur
     
        // Permet de saturer le rapport cyclique du hacheur à 255
      if(rapport_cyclique > 255) rapport_cyclique = 255;
      else if (rapport_cyclique < -255) rapport_cyclique = -255;
     
      while (true) { // fonction tant que ... pour limiter la durée de l'asservissement à 2 secondes
                   if (time<5000) {
                               Tourner (rapport_cyclique); // permet de lancer la fonction "tourner" avec la valeur du rapport_cyclique majorée (cf à la fin du programme)
                               Serial.print(" moteur");
                               break; // on sort ensuite de la fonction "while"
     
                                     }
                    else         { 
                               Tourner (0); // permet de lancer la fonction "tourner" avec la valeur 0 (cf à la fin du programme)
                               Serial.print(" stop ");
                               break;
                                     } 
                      }
     
      Serial.print(time);  // affiche sur le moniteur les données voulues
      Serial.print(" , ");
      Serial.println(codeur); // affiche la valeur "codeur" donc la position du chariot (on affiche le nombre de pas du codeur ...)
    }
     
    // Interruption appelée à tous les changements d'état de PinA
    void codeurA(){
      if (digitalRead(PinA)==digitalRead(PinB)) //à chaque changement d'état de PinA, si PinA=PinB alors le sens de déplacement est négatif ; donc on soustrait 1 à la valeur "codeur"
      {codeur--;}
      else {codeur++;} // ... sinon +1
    }
     
    // Interruption appelée à tous les changements d'état de PinB
    void codeurB(){
      if (digitalRead(PinA)==digitalRead(PinB))  //à chaque changement d'état de PinB, si PinA=PinB alors le sens de déplacement est positif ; donc on ajoute 1 à la valeur "codeur"
      {codeur++;}
      else {codeur--;} //... sinon on soustrait 1
    }
     
    // La fonction "tourner" est lancée pour contrôler le moteur : définition du sens de rotation, libération du frein et envoi du rapport cyclique au hacheur
    void Tourner(int rapport_cyclique ){
      if (rapport_cyclique > 0) {
           digitalWrite(8, LOW); //libère le frein moteur (sortie 8)
           digitalWrite(13, HIGH); //indique le sens positif de rotation du moteur (sortie 13)
                                 } 
      else {
           digitalWrite(8, LOW); //libère le frein moteur (sortie 8)
           digitalWrite(13, LOW); //indique le sens de rotation négatif du moteur (sortie 13)
          rapport_cyclique=-rapport_cyclique; //changement de signe de la commande car la puissance moteur ne peut pas être négative
          }
    analogWrite( pwm_mot, rapport_cyclique ); //commande le hacheur avec un rapport cyclique compris entre 0 et 255
                                       }

    Si quelqu'un peut m'apporter de l'aide, merci d'avance!

  2. #2
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 582
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 582
    Par défaut Silence on tourne
    Bonjour,

    Il semble que le programme ait prévu une extension à 2 moteurs mais que seul le moteur A existe. Or, si on en croit les commentaires, la broche 13 prévue pour le sens de rotation du moteur B se trouve déclarée pour A. Par ailleurs, les constantes ne sont pas toujours utilisées (voir Tourner() par exemple). Hors la déclaration de la broche en sortie, sens_mot n'est jamais utilisé. brake_mot semble plus approprié que break_mot.

    Je ne vois pas comment étendre à 2 moteurs donc deux encodeurs ce programme qui utilise les interruptions standards au lieu de pcint.

    Autre problème, l'encodeur est de mode incrémental, il ne donne donc pas d'angle mais des variations d'angle (et il faut espérer qu'il n'est pas mécanique sinon bonjour les rebonds). Comment est fixé le 0 ? En outre, il faut savoir si l'angle est défini au tour près (est ce que 5° == 365° == -355° == ...).

    Pourquoi utiliser la formule avec kd alors qu'il est fixé à 0. Il n'est pas sûr que le compilateur le détecte et fasse l'optimisation adéquate.

    Dans asservissement(), il y a un while(true) qui ne sert à rien puisqu'on en sort à la première occurence (il y a un break dans chaque alternative du if).

    Il semble possible d'inverser le sens de rotation sans arrêt préalable. Si c'est possible, je me demande pourquoi il y a un point mort dans les voitures .

    Je n'ai pas tout analysé mais il y a déjà du pain sur la planche.

    Salutations

Discussions similaires

  1. Réponses: 1
    Dernier message: 07/09/2007, 21h43
  2. Début de moteur 2D avec SDL: Segfault
    Par Kr00pS dans le forum SDL
    Réponses: 3
    Dernier message: 11/06/2007, 15h31
  3. moteur physique avec irrlicht
    Par ->maxoume<-{loul} dans le forum Physique
    Réponses: 2
    Dernier message: 02/04/2007, 13h28
  4. [Projet Jeu] - Moteur 2D avec GLScene / Asphyre
    Par Leobaillard dans le forum Langage
    Réponses: 61
    Dernier message: 06/05/2006, 18h26
  5. Réponses: 27
    Dernier message: 25/08/2004, 22h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo