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 :

Améliorer la précision du postionnement d'un moteur avec un encodeur


Sujet :

Arduino

  1. #1
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2019
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Vosges (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2019
    Messages : 69
    Points : 58
    Points
    58
    Par défaut Améliorer la précision du postionnement d'un moteur avec un encodeur
    Bonsoir à tous,

    je suis actuellement en train d'essayer d'asservir un moteur DC 12V (moteur d'essuie glace de voiture) avec une roue codeuse d'imprimante

    cependant je n'arrive pas a avoir suffisamment de fidélité dans le positionnement du moteur
    en effet lorsque je demande au moteur de réaliser un tour (donc 600 incrément) j’obtiens 4 fois sur 5 le bon résultat mais des fois le moteur réalise 45° de plus ou de moins

    voici mon code :

    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
    void ActionMoteur(int sens) {
    	if (sens == 0) //Stop
    	{
    		digitalWrite(pinFermetureVanne, LOW);
    		digitalWrite(pinOuvertureVanne, LOW);
    	}
    	else if (sens < 0) //Fermeture
    	{
    		digitalWrite(pinFermetureVanne, HIGH);
    		digitalWrite(pinOuvertureVanne, LOW);
    	}
    	else if (sens > 0) //Ouverture
    	{
    		digitalWrite(pinFermetureVanne, LOW);
    		digitalWrite(pinOuvertureVanne, HIGH);
    	}
    }
    void Asservissement() {
    	int erreur = consigne - detectionA;
    	consigne = consigne - detectionA;
     
    	if (erreur > 0)
    	{
     
    		ActionMoteur(sensMoteur);
    	}
     
    	else {
    		ActionMoteur(0);
     
    	}
    	detectionA = 0;
    	detectionB = 0;
    }
    void encodeurA() {
    	if (millis() - previousdetectionA >intervalledetection)
    	{
    		previousdetectionA = millis();
    		detectionA++;
    		if (sensMoteur > 0)
    		{
    			positionVanne++;
    		}
    		else if (sensMoteur < 0)
    		{
    			positionVanne--;
    		}
     
    	}
     
    	//return true;
    }
    void encodeurB() {
    	if (millis() - previousdetectionB > intervalledetection)
    	{
    		previousdetectionB = millis();
    		detectionB++;
    	}
    }
    // the setup function runs once when you press reset or power the board
    void setup() {
    	//Heltec.begin(true /*DisplayEnable Enable*/, true /*Heltec.LoRa Disable*/, true /*Serial Enable*/, BAND);
    	//Wire.begin(SDA_OLED, SCL_OLED);
    	//Heltec.display->clear();
     
     
    	//Moteur
    	pinMode(pinOuvertureVanne, OUTPUT);
    	pinMode(pinFermetureVanne, OUTPUT);
     
    	//Fin de course
    	pinMode(pinVanneFerme, INPUT);
    	pinMode(pinVanneOuverte, INPUT);
     
    	//roue encodeuse
    	pinMode(pinEncodeurA, INPUT);
    	attachInterrupt(pinEncodeurA, encodeurA, RISING); //RISING FALLING CHANGE
     
    #ifdef pinEncodeurB
    	Serial.println("Config encodeurB");
    	pinMode(pinEncodeurB, INPUT);
    		attachInterrupt(pinEncodeurB, encodeurB, RISING);
    #endif // pinEncodeurB
     
     
     
     
     
    	detectionA = 0;
    	detectionB = 0;
    }
     
    void loop() {
     
     
    	endstopClosed = digitalRead(pinVanneFerme);
    	endstopOpen = digitalRead(pinVanneOuverte);
    	if (Serial.available()) {
    		//Serial.println(Serial.readString());
    		sensMoteur = 1;
    		consigne = 0;
    		while (Serial.available())
    		{
    			byte_read = Serial.read();
    			if (byte_read == 45)
    			{
    				sensMoteur = -1;
    			}
    			if (is_a_number(byte_read))
    			{
    				consigne = ascii2int(consigne, byte_read);
    			}
     
     
     
    		}
    		Asservissement();
     
    	}
    j'aurais aimé savoir qu'est qui ne fonctionne pas dans mon code et comment le rendre meilleur
    Cordialement Baptiste

  2. #2
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    Bonsoir

    Postez tout le code et expliquez le câblage

  3. #3
    Expert confirmé

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 329
    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 329
    Points : 4 146
    Points
    4 146
    Par défaut
    Bonjour,

    Comme dit Jay M, il faut plus d'informations.

    J'ai quand même regardé la portion de code et l'ai un peu densifié.
    Code C : 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
    void ActionMoteur(int sens) {
    	digitalWrite(pinFermetureVanne, sens < 0);
    	digitalWrite(pinOuvertureVanne, sens > 0);
    }
    void Asservissement() {
    	consigne -= detectionA;
    	ActionMoteur(consigne > 0 ? sensMoteur : 0);
    	detectionA = 0;
    	detectionB = 0;
    }
    void encodeurA() {
    	if (millis() - previousdetectionA <= intervalledetection) return;
    	previousdetectionA = millis();
    	detectionA++;
    	if (sensMoteur > 0) positionVanne++; else if (sensMoteur < 0) positionVanne--;
    }
    void encodeurB() {
    	if (millis() - previousdetectionB <= intervalledetection) return;
    	previousdetectionB = millis();
    	detectionB++;
    }
    // the setup function runs once when you press reset or power the board
    void setup() {
    	//Moteur
    	pinMode(pinOuvertureVanne, OUTPUT);
    	pinMode(pinFermetureVanne, OUTPUT);
    	//Fin de course
    	pinMode(pinVanneFerme,   INPUT);
    	pinMode(pinVanneOuverte, INPUT);
    	//roue encodeuse
    	pinMode(pinEncodeurA, INPUT);
    	attachInterrupt(pinEncodeurA, encodeurA, RISING); //RISING FALLING CHANGE
    #ifdef pinEncodeurB
    	Serial.println("Config encodeurB");
    	pinMode(pinEncodeurB, INPUT);
    	attachInterrupt(pinEncodeurB, encodeurB, RISING);
    #endif // pinEncodeurB
    	detectionA = 0;
    	detectionB = 0;
    }
     
    void loop() {
    	endstopClosed = digitalRead(pinVanneFerme);
    	endstopOpen   = digitalRead(pinVanneOuverte);
    	if (Serial.available()) {
    		//Serial.println(Serial.readString());
    		sensMoteur = 1;
    		consigne   = 0;
    		while (Serial.available())
    		{
    			byte_read = Serial.read();
    			if (byte_read == 45) sensMoteur = -1;
    			if (is_a_number(byte_read)) consigne = ascii2int(consigne, byte_read);
    		}
    		Asservissement();
    	}
    }

    Je suis un peu surpris que l'on utilise les deux impulsions d'un décodeur (optique ? magnétique ? pas mécanique j'espère comme le traitement anti rebond le laisse penser) sans en tirer le moyen de vérifier que le sens de rotation détecté est conforme. Sauf erreur de ma part, la détection B ne sert à rien (les variables modifiées ne sont pas utilisées).
    En revanche mettre la détection A activée sur CHANGE doublerait la résolution (il faudrait certainement modifier les constantes de temps).

    Avec un moteur à courant continu, l'inertie risque de ne pas arrêter le moteur quand on lui dit de le faire. Dans ce cas, il va générer au moins une impulsion de plus. Mais comme detectionA a été remis à 0 dans Asservissement, il recommence un cycle.

    Il y a asynchronisme entre détection et les ordres donnés au moteur. Cela ne pourra marcher que si la boucle loop tourne sensiblement plus vite que n'arrivent les impulsions (Shannon sort de ce corps ). C'est à dire que Asservissement() ne doit être appelé que si detectionA vaut 0 ou 1. Si c'est 2 ou plus, il fera avancer le moteur ni plus ni moins qu'avec une seule impulsion (toujours le problème de la remise à 0 de detectionA dans Asservissement).

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  4. #4
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2019
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Vosges (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2019
    Messages : 69
    Points : 58
    Points
    58
    Par défaut
    Bonsoir,

    merci pour vos retour, voici un peu plus de detail sur ce que j'ai fait

    j'utilise actuellement :
    -> un encodeur rotatif d'imprimante avec 4 fils( GND - 5V - PisteA et pisteB) avec 600 incrément par tour , j'ai utilisé la deuxième uniquement pour savoir si j’obtenais le même nombre de détection (c'est le cas)
    -> un moteur DC12V commandé par deux relais afin de pouvoir piloté les 2 sens de rotation avec 2 sorties digitales


    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
    143
    144
    145
    146
     
    int intervalleasserv = 0;
    int intervalledetection = 0;
     
    String string_read;
     
    int sensMoteur = 0;
     
     
     
    unsigned long previousdetectionA = 0;
    unsigned long previousdetectionB = 0;
    unsigned long previousMillisAsserv = 0;
    unsigned long previousMillis = 0;
     
     
     
     
     
    #define pinOuvertureVanne 12
    #define pinFermetureVanne 13
     
    #define pinEncodeurA  36
    //#define pinEncodeurB 37
     
    int NbIncCodeuse = 600; //nombre d'increment de la roue codeuse par tour
    float consigne = 600;
     
    int detectionA = 0;
    int detectionB = 0;
     
    boolean is_a_number(int n)
    {
      return n >= 48 && n <= 57;
    }
    int ascii2int(int n, int byte_read)
    {
      return n * 10 + (byte_read - 48);
    }
    int consigneDeg(int Deg) {
     
      return Deg * NbIncCodeuse / 360;
    }
     
     
     
     
    void ActionMoteur(int sens) {
      if (sens == 0) //Stop
      {
        digitalWrite(pinFermetureVanne, LOW);
        digitalWrite(pinOuvertureVanne, LOW);
      }
      else if (sens < 0) //Fermeture
      {
        digitalWrite(pinFermetureVanne, HIGH);
        digitalWrite(pinOuvertureVanne, LOW);
      }
      else if (sens > 0) //Ouverture
      {
        digitalWrite(pinFermetureVanne, LOW);
        digitalWrite(pinOuvertureVanne, HIGH);
      }
    }
    void Asservissement() {
      int erreur = consigne - detectionA;
      consigne = consigne - detectionA;
     
      if (erreur > 0)
      {
     
        ActionMoteur(sensMoteur);
      }
     
      else {
        ActionMoteur(0);
     
      }
      detectionA = 0;
      detectionB = 0;
    }
    void encodeurA() {
      if (millis() - previousdetectionA >intervalledetection)
      {
        previousdetectionA = millis();
        detectionA++;
     
     
      }
     
     
    }
    void encodeurB() {
      if (millis() - previousdetectionB > intervalledetection)
      {
        previousdetectionB = millis();
        detectionB++;
      }
    }
    // the setup function runs once when you press reset or power the board
    void setup() {
     
     
      //Moteur
      pinMode(pinOuvertureVanne, OUTPUT);
      pinMode(pinFermetureVanne, OUTPUT);
     
      //Fin de course
      pinMode(pinVanneFerme, INPUT);
      pinMode(pinVanneOuverte, INPUT);
     
      //capteur roue encodeuse
      pinMode(pinEncodeurA, INPUT);
      attachInterrupt(pinEncodeurA, encodeurA, CHANGE); //RISING FALLING CHANGE
     
    #ifdef pinEncodeurB
      Serial.println("Config encodeurB");
      pinMode(pinEncodeurB, INPUT);
      attachInterrupt(pinEncodeurB, encodeurB, CHANGE);
    #endif // pinEncodeurB
     
     
     
      detectionA = 0;
      detectionB = 0;
    }
     
     
     
      void loop() {
     
        if (Serial.available())
        {
          string_read = Serial.readStringUntil('\r');
          Serial.println(string_read);
     
          consigne = string_read.toInt();
        }
      if (millis() - previousMillisAsserv > intervalleasserv)
      {
        previousMillisAsserv = millis();
        Asservissement();
     
      }
     
    }
    Images attachées Images attachées  

  5. #5
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    mettez vos variable detectionA (et detectionB) en volatile pour éviter tout risque et quand vous les accédez dans la loop ce doit être en section critique (interruptions bloquées) à la lecture et la remise à 0 puisque les valeurs ne sont pas sur un seul octet

    tel que c'est codé une seule interruption dans la même ms est prise en compte. tout dépend donc aussi à quelle vitesse ça tourne

  6. #6
    Expert confirmé

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 329
    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 329
    Points : 4 146
    Points
    4 146
    Par défaut Temps et tant
    Bonjour,

    Utiliser millis induit effectivement une limitation. De plus cette mesure de temps paraît inutile pour éviter des rebonds qui n'existent pas avec le capteur optique qui semble apparaître sur la photo.

    En outre j'ai l'impression que le réducteur du moteur d’essuie-glace est conservé (photo) ce qui devrait se traduire par un rythme d'impulsions assez faible et un risque d'inertie diminué d'autant (ce qui mettrait à mal mes premières hypothèses). Ordre de grandeur du nb de tours / minutes ou secondes ?

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  7. #7
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2019
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Vosges (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2019
    Messages : 69
    Points : 58
    Points
    58
    Par défaut
    Bonsoir,

    j'ai refait complétement le code de mon système avec vos remarque
    la fonction Asservissement n'est plus soumise à un intervalle (millis())
    la variable DetectionA est passée en volatile

    la précision est meilleure

    Mon moteur d'essuie glace avec réducteur semble tourner entre 1 et 2 tours par seconde

    merci pour vos retour d'informations

    Cordialement Baptiste

Discussions similaires

  1. Réponses: 1
    Dernier message: 27/05/2014, 09h34
  2. Réponses: 24
    Dernier message: 16/02/2012, 18h27
  3. [Débutant] Améliorer la précision des fonctions trigo
    Par candrau dans le forum MATLAB
    Réponses: 3
    Dernier message: 12/01/2012, 10h10
  4. Réponses: 0
    Dernier message: 23/11/2011, 13h14
  5. Réponses: 2
    Dernier message: 12/12/2006, 16h33

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