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 :

Code asservissement position moteur cc avec encodeur


Sujet :

Arduino

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2021
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2021
    Messages : 5
    Par défaut Code asservissement position moteur cc avec encodeur
    Bonjour tout le monde!
    J'ai un soucis avec un programme arduino conçu pour asservir un moteur cc avec encodeur en position et ce problème me prends la tête depuis 2 bonne semaines maintenant... C'est assez important, c'est pour mon TIPE (projet de prépa équivalent aux TPE de 1re) et on est assez en retard comme ça avec mon collègue...

    Contexte: le motoréducteur sert à faire déplacer un chariot sur un axe linéaire. Un système de poulie-courroie transforme la rotation du moteur en translation du chariot.
    Cependant, quand j'entre une consigne de 10cm, il ne se déplace que de 3cm environ.
    De plus, le moniteur série n'affiche que des valeurs entières de l'angle mesuré en sortie du réducteur (nommé 'angle_tour dans le programme), alors qu'il devrait y avoir des décimales puisque 'angle_tour' est défini comme un float...

    La poulie a un rayon de Rpoul=0.5cm
    Mon moteur a un rapport de réduction de r=1/20
    Le capteur à effet Hall situé à l'extrémité du moteur a une résolution de PPR= 11 impulsions par tour

    Le code est normalement joint en fichier.

    Si même l'un d'entre vous serait d'accord pour se contacter très rapidement par vidéo conférence ce serait topissime!
    Merci d'avance...

    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
    #include <SimpleTimer.h>
     
     
    // asservissement en position angulaire un moteur à courant continu.
     
    SimpleTimer timer; // Timer pour échantillonnage
     
    //definition des entrées
     
    #define pi 3.14
    #define r 20
    #define Rpoul 0.5
    #define PPR 11   //Nombre de ticks par tour de rotor (20*11 ticks par tour d'arbre de sortie)
    #define tourparcm 1/(2*pi*Rpoul)
     
    const int pinInput1 = 6; // Commande de sens moteur, Input 1
    const int pinInput2 = 7; // Commande de sens moteur, Input 2
    const int pinPower = 9; // Commande de vitesse moteur, Output Enabled1
    const int encoderPinA = 2; // compteur 1
    const int encoderPinB = 3; // compteur 2
     
    //init echantillonage
    unsigned int time = 0;
    const int frequence_echantillonnage = 20;
     
    //init compteur :
    int encoder0Pos = 0; //position de départ=0
    int lastReportedPos = 0;
    boolean A_set = false;
    boolean B_set = false;
     
    //consigne
    const double target_cm = -10;
    double target_tour = tourparcm * target_cm;
    int target_ticks; //plus simple d'asservir en ticks car ce sera toujours un nombre entier
     
    // init calculs asservissement PID
    int erreur = 0; //erreur
    float erreurPrecedente = 0;
    float somme_erreur = 0;
     
    //Definition des constantes du correcteur PID
    const float kp = 1; // Coefficient proportionnel (choisis par essais successifs)
    const float ki = 0; // Coefficient intégrateur
    const float kd = 0; // Coefficient dérivateur
     
    /* Routine d'initialisation */
    void setup()
    {
     target_ticks = target_tour * r * PPR ;    //Consigne en ticks
     Serial.begin(9600); // Initialisation port COM
     Serial.println(F("CLEARDATA"));
     Serial.println(F("LABEL, temps, consigne, erreur, encoder0pos, vitesse_moteur, angle_tour, distance"));
     
     pinMode(pinPower, OUTPUT); // Sorties commande moteur
     pinMode(pinInput1, OUTPUT);
     pinMode(pinInput2, OUTPUT);
     pinMode(encoderPinA, INPUT); //sorties encodeur
     pinMode(encoderPinB, INPUT);
     digitalWrite(encoderPinA, HIGH); // Resistance interne arduino ON
     digitalWrite(encoderPinB, HIGH); // Resistance interne arduino ON
     // Interruption de l'encodeur A en sortie 0 (pin 2)
     attachInterrupt(0, doEncoderA, CHANGE);
     // Interruption de l'encodeur A en sortie 1 (pin 3)
     attachInterrupt(1, doEncoderB, CHANGE);
     analogWrite(pinPower, 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 est en marche
     
     // Interruption pour calcul du PID et asservissement appelée toutes les 10ms
     timer.setInterval(1000 / frequence_echantillonnage, asservissement);
    }
    /* Fonction principale */
    void loop()
    {
     timer.run(); //on fait tourner l'horloge
    }
     
    //---- Cette fonction est appelée toutes les 20ms pour calcul du correcteur PID
    void asservissement ()
    {
     time += 20; // pratique pour graphes excel après affichage sur le moniteur
     erreur = target_ticks - encoder0Pos;
     somme_erreur += erreur;
     
     // Calcul de la vitesse courante du moteur
     int vitMoteur = kp * erreur + kd * (erreur - erreurPrecedente) + ki * (somme_erreur);
     erreurPrecedente = erreur; // Ecrase l'erreur précedente par la nouvelle erreur
     
     // Normalisation et contrôle du moteur
     if ( vitMoteur > 255 ) vitMoteur = 255; // on est branché sur un pont en H L293D   ici, il s'agit de la saturation
     else if ( vitMoteur < -255 ) vitMoteur = -255;
     Tourner (vitMoteur);
     float angle_tour = encoder0Pos / PPR / r; //Position angulaire de sortie (ici il s'agit de la sortie du réducteur et non pas de la sortie du moteur)
    // pratique pour comparer avec la consigne d'entrée
     float distance = angle_tour / tourparcm;
     Serial.print(("DATA,TIME"));
     Serial.print(F(","));
     Serial.print(target_cm);
     Serial.print(F(","));
     Serial.print(erreur); // affiche sur le moniteur les données voulues
     Serial.print(F(","));
     Serial.print(encoder0Pos);
     Serial.print(F(","));
     Serial.print(vitMoteur);
     Serial.print(F(","));
     Serial.print(angle_tour);
     Serial.print(F(","));
     Serial.print(distance);
     Serial.println();
    }
     
    //---- Interruption appelée à tous les changements d'état de A
    void doEncoderA()
    {
     A_set = (digitalRead(encoderPinA) == HIGH);
     encoder0Pos += (A_set != B_set) ? -1 : 1 ; //modifie le compteur selon les deux états des encodeurs ( correspond au front montant de A, on compare à B pour déduire le sens de rotation et on en déduit si on incrémente +1 ou -1)
    }
     
    //---- Interruption appelée à tous les changements d'état de B
    void doEncoderB()
    {
     B_set = (digitalRead(encoderPinB) == HIGH);
     encoder0Pos += (A_set == B_set) ? -1 : 1 ; //modifie le compteur selon les deux états des encodeurs
    }
     
     
    //---- Fonction appelée pour contrôler le moteur
    void Tourner( int rapportCyclique )
    {
     if ( rapportCyclique > 0 )
     {
     digitalWrite(pinInput1, LOW);
     digitalWrite(pinInput2, HIGH);
     }
     else
     {
     digitalWrite(pinInput1, HIGH);
     digitalWrite(pinInput2, LOW);
     rapportCyclique = -rapportCyclique;
     }
     analogWrite(pinPower, rapportCyclique);
    }
    Fichiers attachés Fichiers attachés

  2. #2
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 632
    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 632
    Par défaut En vrac
    Bonjour,

    Quelques remarques :
    • Dans le message on parle d'un détecteur à effet hall et dans le source on parle d'un encodeur (même à effet hall il lui faudrait deux capteurs et non un seul).
    • La variable somme_erreur est déclarée float mais ne fait que la somme d'entiers (variable erreur)
    • Le décodage de l'encodeur est en 4 phases A/ A\ B/ B\. Si l'encodeur a n positions il y aura 4n ticks par tour avant réduction. Je ne vois pas comment on peut trouver 11.

    Salutations

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2021
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2021
    Messages : 5
    Par défaut
    [*]Le décodage de l'encodeur est en 4 phases A/ A\ B/ B\. Si l'encodeur a n positions il y aura 4n ticks par tour avant réduction. Je ne vois pas comment on peut trouver 11.

    Merci pour votre réponse. C'est vrai que c'est bizarre mais en réalité, c'est le datasheet du moteur qui m'informait de 11 pulses per revolution
    https://fr.banggood.com/CHIHAI-MOTOR...e=CN&ID=519628
    Peut-être devrais-je donc multiplier 11 par 4 pour plus de rigueur? Même si, dans tous les cas, ça ne résoudra pas le problème d'imprécision...
    Merci d'avance

  4. #4
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 632
    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 632
    Par défaut Décodeur
    Bonjour,

    Les impulsions moteur n'ont a priori rien à voir avec l'encodeur (et elles ne disent pas dans quel sens il tourne). Quel type d'encodeur est-ce ? Optique, magnétique, pas à contact électrique j'espère ? Pour les optiques, le nombre de points est souvent de l'ordre de 200 par tour (800 en décodage 4 phases). A ma connaissance il est toujours pair.

    Un schéma serait utile.

    Salutations

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2021
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2021
    Messages : 5
    Par défaut
    Bonjour, merci pour votre réponse.
    Il s'agit d'un capteur à effet Hall (magnétique donc)

  6. #6
    Membre Expert
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 017
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 017
    Par défaut
    Bonsoir
    Ce type de moteur à réducteur possède un codeur composé d'une roue magnétique qui a 11 "crans" et 2 détecteurs à effet de hall (signal A et B). Cette combinaison permet d'avoir, au plus précis, 44 informations (changements d'état) par tour d'axe de moteur (pas tour de l'axe du réducteur), à multiplier par le rapport de réduction pour avoir le nombre d'informations par tour d'axe du réducteur.

    Cordialement
    jpbbricole

  7. #7
    Invité de passage
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2023
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2023
    Messages : 1
    Par défaut Hello ! Je suis dans la meme panade... serait il possible de te contacter pour mon tipe ?
    Citation Envoyé par Loupote Voir le message
    Bonjour tout le monde!
    J'ai un soucis avec un programme arduino conçu pour asservir un moteur cc avec encodeur en position et ce problème me prends la tête depuis 2 bonne semaines maintenant... C'est assez important, c'est pour mon TIPE (projet de prépa équivalent aux TPE de 1re) et on est assez en retard comme ça avec mon collègue...

    Contexte: le motoréducteur sert à faire déplacer un chariot sur un axe linéaire. Un système de poulie-courroie transforme la rotation du moteur en translation du chariot.
    Cependant, quand j'entre une consigne de 10cm, il ne se déplace que de 3cm environ.
    De plus, le moniteur série n'affiche que des valeurs entières de l'angle mesuré en sortie du réducteur (nommé 'angle_tour dans le programme), alors qu'il devrait y avoir des décimales puisque 'angle_tour' est défini comme un float...

    La poulie a un rayon de Rpoul=0.5cm
    Mon moteur a un rapport de réduction de r=1/20
    Le capteur à effet Hall situé à l'extrémité du moteur a une résolution de PPR= 11 impulsions par tour

    Le code est normalement joint en fichier.

    Si même l'un d'entre vous serait d'accord pour se contacter très rapidement par vidéo conférence ce serait topissime!
    Merci d'avance...

    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
    #include <SimpleTimer.h>
     
     
    // asservissement en position angulaire un moteur à courant continu.
     
    SimpleTimer timer; // Timer pour échantillonnage
     
    //definition des entrées
     
    #define pi 3.14
    #define r 20
    #define Rpoul 0.5
    #define PPR 11   //Nombre de ticks par tour de rotor (20*11 ticks par tour d'arbre de sortie)
    #define tourparcm 1/(2*pi*Rpoul)
     
    const int pinInput1 = 6; // Commande de sens moteur, Input 1
    const int pinInput2 = 7; // Commande de sens moteur, Input 2
    const int pinPower = 9; // Commande de vitesse moteur, Output Enabled1
    const int encoderPinA = 2; // compteur 1
    const int encoderPinB = 3; // compteur 2
     
    //init echantillonage
    unsigned int time = 0;
    const int frequence_echantillonnage = 20;
     
    //init compteur :
    int encoder0Pos = 0; //position de départ=0
    int lastReportedPos = 0;
    boolean A_set = false;
    boolean B_set = false;
     
    //consigne
    const double target_cm = -10;
    double target_tour = tourparcm * target_cm;
    int target_ticks; //plus simple d'asservir en ticks car ce sera toujours un nombre entier
     
    // init calculs asservissement PID
    int erreur = 0; //erreur
    float erreurPrecedente = 0;
    float somme_erreur = 0;
     
    //Definition des constantes du correcteur PID
    const float kp = 1; // Coefficient proportionnel (choisis par essais successifs)
    const float ki = 0; // Coefficient intégrateur
    const float kd = 0; // Coefficient dérivateur
     
    /* Routine d'initialisation */
    void setup()
    {
     target_ticks = target_tour * r * PPR ;    //Consigne en ticks
     Serial.begin(9600); // Initialisation port COM
     Serial.println(F("CLEARDATA"));
     Serial.println(F("LABEL, temps, consigne, erreur, encoder0pos, vitesse_moteur, angle_tour, distance"));
     
     pinMode(pinPower, OUTPUT); // Sorties commande moteur
     pinMode(pinInput1, OUTPUT);
     pinMode(pinInput2, OUTPUT);
     pinMode(encoderPinA, INPUT); //sorties encodeur
     pinMode(encoderPinB, INPUT);
     digitalWrite(encoderPinA, HIGH); // Resistance interne arduino ON
     digitalWrite(encoderPinB, HIGH); // Resistance interne arduino ON
     // Interruption de l'encodeur A en sortie 0 (pin 2)
     attachInterrupt(0, doEncoderA, CHANGE);
     // Interruption de l'encodeur A en sortie 1 (pin 3)
     attachInterrupt(1, doEncoderB, CHANGE);
     analogWrite(pinPower, 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 est en marche
     
     // Interruption pour calcul du PID et asservissement appelée toutes les 10ms
     timer.setInterval(1000 / frequence_echantillonnage, asservissement);
    }
    /* Fonction principale */
    void loop()
    {
     timer.run(); //on fait tourner l'horloge
    }
     
    //---- Cette fonction est appelée toutes les 20ms pour calcul du correcteur PID
    void asservissement ()
    {
     time += 20; // pratique pour graphes excel après affichage sur le moniteur
     erreur = target_ticks - encoder0Pos;
     somme_erreur += erreur;
     
     // Calcul de la vitesse courante du moteur
     int vitMoteur = kp * erreur + kd * (erreur - erreurPrecedente) + ki * (somme_erreur);
     erreurPrecedente = erreur; // Ecrase l'erreur précedente par la nouvelle erreur
     
     // Normalisation et contrôle du moteur
     if ( vitMoteur > 255 ) vitMoteur = 255; // on est branché sur un pont en H L293D   ici, il s'agit de la saturation
     else if ( vitMoteur < -255 ) vitMoteur = -255;
     Tourner (vitMoteur);
     float angle_tour = encoder0Pos / PPR / r; //Position angulaire de sortie (ici il s'agit de la sortie du réducteur et non pas de la sortie du moteur)
    // pratique pour comparer avec la consigne d'entrée
     float distance = angle_tour / tourparcm;
     Serial.print(("DATA,TIME"));
     Serial.print(F(","));
     Serial.print(target_cm);
     Serial.print(F(","));
     Serial.print(erreur); // affiche sur le moniteur les données voulues
     Serial.print(F(","));
     Serial.print(encoder0Pos);
     Serial.print(F(","));
     Serial.print(vitMoteur);
     Serial.print(F(","));
     Serial.print(angle_tour);
     Serial.print(F(","));
     Serial.print(distance);
     Serial.println();
    }
     
    //---- Interruption appelée à tous les changements d'état de A
    void doEncoderA()
    {
     A_set = (digitalRead(encoderPinA) == HIGH);
     encoder0Pos += (A_set != B_set) ? -1 : 1 ; //modifie le compteur selon les deux états des encodeurs ( correspond au front montant de A, on compare à B pour déduire le sens de rotation et on en déduit si on incrémente +1 ou -1)
    }
     
    //---- Interruption appelée à tous les changements d'état de B
    void doEncoderB()
    {
     B_set = (digitalRead(encoderPinB) == HIGH);
     encoder0Pos += (A_set == B_set) ? -1 : 1 ; //modifie le compteur selon les deux états des encodeurs
    }
     
     
    //---- Fonction appelée pour contrôler le moteur
    void Tourner( int rapportCyclique )
    {
     if ( rapportCyclique > 0 )
     {
     digitalWrite(pinInput1, LOW);
     digitalWrite(pinInput2, HIGH);
     }
     else
     {
     digitalWrite(pinInput1, HIGH);
     digitalWrite(pinInput2, LOW);
     rapportCyclique = -rapportCyclique;
     }
     analogWrite(pinPower, rapportCyclique);
    }

  8. #8
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 908
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 908
    Par défaut
    @julesProg
    Hello ! Je suis dans la meme panade... serait il possible de te contacter pour mon tipe ?
    ouvrez votre propre fil de discussion et postez les détails relatif à VOTRE projet y compris ce que vous avez essayé de faire

Discussions similaires

  1. Code CSS (position?) qui bug avec Firefox ?
    Par RinaBK dans le forum Mise en page CSS
    Réponses: 23
    Dernier message: 29/01/2021, 19h02
  2. Réponses: 4
    Dernier message: 13/10/2005, 14h44
  3. Réponses: 7
    Dernier message: 12/09/2005, 11h05
  4. [web] position du logo avec TK
    Par stepha001 dans le forum Interfaces Graphiques
    Réponses: 6
    Dernier message: 20/04/2005, 13h58
  5. Récupérer le code HTML d'une page avec Delphi 7
    Par PsyKroPack dans le forum Web & réseau
    Réponses: 5
    Dernier message: 06/02/2003, 21h56

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