Vous êtes sur la page 1sur 22

Sciences et Techniques

FROM CHAOS TO CONTROL

Accueil Les Dossiers A propos de moi... Rechercher

Kicad : Raccorder deux pistes en plaçant des vias Amplificateur opérationnel VS comparateur Les mots clefs

Transformée de Fourier Filtre


de Kalman
Fusion de données Arduino Comparatif
Avr
Asservissement en vitesse d'un moteur avec Arduino Projet PCB Algèbre Logique Prédiction
22 État de l'art Domaines discrets Programmation
2012
Robotique Commenter
Mathématiques Kicad
Bonjour à tous ! Traitement
Asservissement
du signal Capteur Transformée en Z
J'ai rédigé, il y a quelques temps déjà, un article expliquant comment implémenter un asservissement de type Logique floue Automatique
PID sans faire de calculs ! Après plusieurs retours de lecteurs, je me suis rendu compte que cet article, qui se Montage Electronique
voulait simple et compréhensible, n'était pas assez pratique. Il manquait un exemple concret ! C'est donc pour Filtre numérique Planification de trajectoire

remédier à ce manque que je rédige l'article suivant. Estimation Centrale inertielle


Intelligence artificielle Java
Je me baserai donc sur ce que j'ai écrit dans l'article Implémenter un PID sans faire de calculs pour implémenter Algorithmique Jeux Robotique
réellement l'asservissement d'un moteur à courant continu à l'aide d'une Arduino.
Qui est en ligne

Présentation du moteur et de sa codeuse 3 visiteur(s) en ligne actuellement


3 visiteur(s), 0 robots, 0 membre(s)
Le moteur que je vais utilisé est un motoréducteur 29:1 avec une roue codeuse monté sur l'arbre moteur. La
documentation est consultable ici.

Les caractéristiques intéressantes à noter sont :

350 tours de roue minutes


10150 tours d'arbre moteur minute (environ 170 par seconde)
32 transitions montante et descendante de la codeuse par tour d'arbre moteur
928 transitions montante ou descendante de la codeuse par tour de roue

Câblage du moteur à l'Arduino


Comme je n'ai pas à disposition de shield Arduino pour contrôler un moteur à courant continue, j'ai donc refait
une petite interface de puissance très basique, avec les composants à ma disposition, pour les besoins de
l'article.

Le transistor Q2 vient driver le MOSFET de puissance. Lorsque la sortie 9 de l'arduino est à l'état haut, Q1 est
bloqué et le moteur ne tourne pas. A l'inverse, lorsque la sortie 9 de l'arduino est à l'état bas, alors Q1 devient
passant et le moteur tourne à plein régime. Le moteur se contrôle donc en "tout ou rien", ce qui tombe bien, car
la sortie "analogique" de l'Arduino est en réalité une sortie PWM de rapport cyclique ajustable.
Au niveau du câblage, j'utilise une Arduino Mega. La sortie 9 commande mon moteur. La codeuse (je n'utilise
qu'une seule des deux sorties de la codeuse) est branché sur la pin 2 de l'arduino mega (pin qui correspond à
l'interruption 0).

Si vous voulez utiliser une autre Arduino, pensez à brancher la codeuse, non plus sur la pin 2, mais sur la pin qui
correspond à une pin d'interruption !

Récupération des informations codeuses


Je souhaite connaitre le nombre de tours de l'arbre moteur grâce à la codeuse. Comme nous l'avons vu dans une
première partie, il y a 32 transitions montantes ET descendante qui s'opèrent pendant un seul tour de l'arbre
moteur.

Ainsi, il suffit de mettre une interruption qui se déclenche à chaque transition de la codeuse et qui exécute une
fonction qui viendra simplement incrémenter un compteur.

1 const int _MOTEUR =  9;            // Digital pin pour commande moteur


2 unsigned int tick_codeuse = 0;     // Compteur de tick de la codeuse
3  
4 /* Routine d'initialisation */
5 void setup() {
6     pinMode(_MOTEUR, OUTPUT);   // Sortie moteur
7     analogWrite(_MOTEUR, 255);  // Sortie moteur à 0
8     delay(5000);                // Pause de 5 sec pour laisser le temps au mo
9  
10     attachInterrupt(0, compteur, CHANGE);    // Interruption sur tick de la c
11 }
12  
13 /* Fonction principale */
14 void loop(){
15     delay(10);
16 }
17  
18 /* Interruption sur tick de la codeuse */
19 void compteur(){
20     tick_codeuse++;  // On incrémente le nombre de tick de la codeuse
21 }

Création de la fonction d'asservissement


Pour mettre en place un asservissement numérique, il faut que les calculs de la commande du moteur se
fassent à un intervalle de temps régulier. Pour cela, j'ai utilisé un timer qui permet d'exécuter une fonction
précise tous les x millisecondes. Le timer n'est pas un objets inclut de base à Arduino, j'ai donc installé une
bibliothèque externe,  SimpleTimer, qui remplit cette tâche. Vous pourrez trouver cette bibliothèque sur cette
page.

1 #include <SimpleTimer.h>           // http://arduino.cc/playground/Code/Simpl


2  
3 SimpleTimer timer;                 // Timer pour échantillonnage
4 const int _MOTEUR =  9;            // Digital pin pour commande moteur
5 unsigned int tick_codeuse = 0;     // Compteur de tick de la codeuse
6 int cmd = 0;                       // Commande du moteur
7 const int frequence_echantillonnage = 50;  // Fréquence d'exécution de l'asse
8  
9 /* Routine d'initialisation */
10 void setup() {
11     Serial.begin(115200);         // Initialisation port COM
12     pinMode(_MOTEUR, OUTPUT);   // Sortie moteur
13     analogWrite(_MOTEUR, 255);  // Sortie moteur à 0
14  
15     delay(5000);                // Pause de 5 sec pour laisser le temps au mo
16  
17     attachInterrupt(0, compteur, CHANGE);    // Interruption sur tick de la c
18     timer.setInterval(1000/frequence_echantillonnage, asservissement);  // In
19 }
20  
21 /* Fonction principale */
22 void loop(){
23     timer.run();
24     delay(10);
25 }
26  
27 /* Interruption sur tick de la codeuse */
28 void compteur(){
29     tick_codeuse++;  // On incrémente le nombre de tick de la codeuse
30 }
31  
32 /* Interruption pour calcul du PID */
33 void asservissement()
34 {
35     // DEBUG
36     Serial.println(tick_codeuse);
37  
38     // Réinitialisation du nombre de tick de la codeuse
39     tick_codeuse=0;
40 }
Ici, la fonction asservissement() est exécutée toutes les 20ms (50Hz) et la fonction compteur() est exécuté à
chaque fois que la codeuse change d'état.

Mise en place d'un asservissement P


Essayons maintenant de mettre en place un asservissement proportionnel. Pour cela, il nous faut trois choses.

D'abord, la consigne, qui correspondra, dans notre exemple, au nombre de tours de roue par seconde. Je vais
fixer cette consigne à 5, ce qui veut dire que je souhaite que le moteur effectue 5 tours de roue par seconde.

Ensuite, il nous faut le nombre de tour de roue qu'a effectué le moteur durant les dernière 20ms. Rien de bien
compliqué. On a notre variable tick_codeuse qui compte le nombre de changement d'état de la codeuse durant
les 20 dernières millisecondes. On sait qu'il y a 32 changements d'état de la codeuse par tour de l'arbre moteur.
On sait qu'il faut 29 tours d'arbre moteur pour faire un tour de roue.

On en déduit donc que la roue à fait tick_codeuse/32/29 tours de roues durant les 20 dernières milliseconde, et
donc 50*tick_codeuse/32/29 tours de roue par seconde !

Avec cette information, on peut donc calculer l'erreur qui est la différence entre la consigne (le nombre de tour
de roue par seconde voulu) et la réponse à cette consigne (le nombre de tours de roue par seconde réalisé).

Il ne nous reste plus qu'a trouver notre coefficient de proportionnalité de notre régulation, ce qui nous donne la
fonction d'asservissement suivante :

1 /* Interruption pour calcul du P */


2 void asservissement()
3 {
4     // Calcul de l'erreur
5     int frequence_codeuse = frequence_echantillonnage*tick_codeuse;
6     float nb_tour_par_sec = (float)frequence_codeuse/(float)tick_par_tour_cod
7     float erreur = consigne_moteur_nombre_tours_par_seconde - nb_tour_par_sec
8  
9     // Réinitialisation du nombre de tick de la codeuse
10     tick_codeuse=0;
11  
12     // P : calcul de la commande
13     cmd = kp*erreur;
14  
15     // Normalisation et contrôle du moteur
16     if(cmd < 0) cmd=0;
17     else if(cmd > 255) cmd = 255;
18     analogWrite(_MOTEUR, 255-cmd);
19  
20     // DEBUG
21     /*
22     Serial.print(nb_tour_par_sec,8);
23     Serial.print(" : ");
24     Serial.print(erreur,4);
25     Serial.println();
26     //*/
27 }

Notons que lors de l'envoie du signal de commande au transistor, il faut inverser le résultat trouvé avec notre
asservissement proportionnel car dans notre cas, le moteur tourne pour une commande de 0 et s'arrête pour
une commande de 255 ! (d'où la ligne analogWrite(_MOTEUR, 255-cmd); )

Il faut donc maintenant définir le coefficient de proportionnalité. J'ai tracé, ci-dessous, différentes réponses de
mon moteur en fonction du temps pour des coefficients de proportionnalité différents. On remarque bien que
quand kp augmente, la réponse se rapproche de plus en plus à la consigne voulu, mais que quand kp est trop
grand, la réponse oscille fortement autour de la consigne.
Amélioration PI
D'après les résultats précédent, j'ai décidé de prendre un coefficient de proportionnalité kp égal à 300. Ainsi,
l'erreur statique sera  d'environ 5%. Pour améliorer le comportement de notre asservissement et pour annuler
notre erreur statique, j'ai décidé de rajouter un terme intégrateur afin d'obtenir un asservissement PI.

Pour cela, je vais garder en mémoire la somme de toutes les erreurs de mon système. Plus cette somme des
erreurs est importante et plus j'essaye de corriger ma commande. Ainsi, il faut que j'ajoute ce nouveau terme
intégrale à la ligne calculant la commande.

1 somme_erreur += erreur;
2 // PI : calcul de la commande
3 cmd = kp*erreur + ki*somme_erreur;

Dans cette seconde phase, nous avons donc à régler ce coefficient intégrateur ki.

Plus on augmente le coefficient d'intégration ki, est plus le système répond vite, mais en contre partie, le
système devient de plus en plus instable. Le but est donc de trouver un compromis entre temps de réponse et
stabilité. On voit que pour des ki trop grand, le système part en oscillation.

D'après ces graphiques, un coefficient proportionnel de 300 et un coefficient intégrateur de 5 ou 6 nous permet
d'atteindre une réponse quasiment optimale, avec un dépassement très faible et un temps de réponse d'envirion
120 milliseconde. Le système se stabilise donc après 6 exécutions de la fonction asservissement.

Asservissement final PID


Afin de mettre en place un asservissement PID complet, je vais maintenant rajouté le terme dérivateur, bien que
dans notre cas, celui-ci n'ai pas beaucoup d'influence car un simple asservissement PI nous permet d'atteindre
une réponse quasi parfaite.

1 float delta_erreur = erreur-erreur_precedente;


2 erreur_precedente = erreur;
3 // PID : calcul de la commande
4 cmd = kp*erreur + ki*somme_erreur + kd*delta_erreur;
Il faut faire attention de ne pas prendre un coefficient dérivateur kd trop grand car le temps de réponse
augmente.

Après plusieurs essais, je suis arrivé à un triplet assez performant. Voici l'allure de la réponse :

Et voici le programme final :

1 /**
2 * Asservissement d'un moteur à l'aide d'un régulateur PID
3 * Avril 2012 - Ferdinand Piette
4 */
5  
6 #include <SimpleTimer.h>           // http://arduino.cc/playground/Code/Simpl
7 #define _DEBUG false
8  
9 SimpleTimer timer;                 // Timer pour échantillonnage
10 const int _MOTEUR =  9;            // Digital pin pour commande moteur
11 unsigned int tick_codeuse = 0;     // Compteur de tick de la codeuse
12 int cmd = 0;                       // Commande du moteur
13  
14 const int frequence_echantillonnage = 50;  // Fréquence du pid
15 const int rapport_reducteur = 29;          // Rapport entre le nombre de tour
16 const int tick_par_tour_codeuse = 32;      // Nombre de tick codeuse par tour
17  
18 float consigne_moteur_nombre_tours_par_seconde = 5.;  //  Nombre de tours de
19  
20 float erreur_precedente = consigne_moteur_nombre_tours_par_seconde;
21 float somme_erreur = 0;   // Somme des erreurs pour l'intégrateur
22 float kp = 300;           // Coefficient proportionnel
23 float ki = 5.5;           // Coefficient intégrateur
24 float kd = 100;           // Coefficient dérivateur
25  
26 /* Routine d'initialisation */
27 void setup() {
28     Serial.begin(115200);         // Initialisation port COM
29     pinMode(_MOTEUR, OUTPUT);     // Sortie moteur
30     analogWrite(_MOTEUR, 255);    // Sortie moteur à 0
31  
32     delay(5000);                  // Pause de 5 sec pour laisser le temps au
33  
34     attachInterrupt(0, compteur, CHANGE);    // Interruption sur tick de la c
35     timer.setInterval(1000/frequence_echantillonnage, asservissement);  // In
36 }
37  
38 /* Fonction principale */
39 void loop(){
40     timer.run();
41     delay(10);
42 }
43  
44 /* Interruption sur tick de la codeuse */
45 void compteur(){
46     tick_codeuse++;  // On incrémente le nombre de tick de la codeuse
47 }
48  
49 /* Interruption pour calcul du PID */
50 void asservissement()
51 {
52     // Réinitialisation du nombre de tick de la codeuse
53     int tick = tick_codeuse;
54     tick_codeuse=0;
55  
56     // Calcul des erreurs
57     int frequence_codeuse = frequence_echantillonnage*tick;
58     float nb_tour_par_sec = (float)frequence_codeuse/(float)tick_par_tour_cod
59     float erreur = consigne_moteur_nombre_tours_par_seconde - nb_tour_par_sec
60     somme_erreur += erreur;
61     float delta_erreur = erreur-erreur_precedente;
62     erreur_precedente = erreur;
63  
64     // PID : calcul de la commande
65     cmd = kp*erreur + ki*somme_erreur + kd*delta_erreur;
66  
67     // Normalisation et contrôle du moteur
68     if(cmd < 0) cmd=0;
69     else if(cmd > 255) cmd = 255;
70     analogWrite(_MOTEUR, 255-cmd);
71  
72     // DEBUG
73     if(_DEBUG)  Serial.println(nb_tour_par_sec,8);
74 }

Publié par Ferdinand Piette à 21:49 Taggué avec : Arduino, Asservissement, Automatique, Capteur, Electronique, Montage, Robotique

79 commentaires à “Asservissement en vitesse d'un moteur avec Arduino”

1. Ulysse2 dit :
9 août 2012 à 11:01

Super ! Les explications sont ultra claires ! Merci infiniment !

Répondre

2. TeRRy dit :
22 octobre 2012 à 21:26

Bonjour,

J'ai une question. La variable somme_erreur ne risque pas un dépassement? Ne devrait elle pas etre remis a zero, tous
les n boucles? sinon le tuto est une bonne application du tuto, le PID sans calculs.

TeRRy

Répondre

Ferdinand Piette dit :


24 octobre 2012 à 15:40

Bonjour,

Normalement, si le PID est bien fait, il n'y aura pas de dépassement vu que la somme des erreurs oscillera
autour de 0 🙂
EDIT : Sinon, on pourrait imaginer "brider" cette valeur dans un intervalle et que si la somme des erreurs
dépasse une des borne de l’intervalle, on la ramène toujours à la borne.

double borne_min = -50, borne_max = 50;


if(somme_erreur > borne_max) somme_erreur = borne_max;
if(somme_erreur < borne_min) somme_erreur = borne_min;

Répondre

3. bastof dit :
1 novembre 2012 à 09:22

bonjour,

Je ne comprends pas le delay(10) dans void loop() { ...


Merci beaucoup

Bastof

Répondre

Ferdinand Piette dit :


4 novembre 2012 à 17:31

Bonjour,
C'est pour éviter de consommer du CPU inutilement.

Répondre

4. Jean dit :
5 février 2013 à 16:49

Bonjour, j'ai une question concernant Ki.

Pour moi Ki dépend des conditions initiales. Sauriez vous m'expliquer pourquoi si ce n'est pas le cas ?

Par exemple :
Le moteur tourne à 20 tours de roue par minute. Je lui demande d'aller à 100 tours. la somme des écarts au moment de
la stabilisation vaudra l'aire sous (et sur) la consigne mettons x.
Le moteur tourne à 40 tous de roue par minute. Je lui demande d'aller à 100 tours. la somme des écarts au moment de
la stabilisation vaudra à nouveau l'aire sous (et sur) la consigne mettons y.

Partant d'un écart plus grand, x sera supérieur à y. Un unique Ki introduira un surplus différent dans ma commande pour
x et y. L'état stable ne sera donc pas à la même "hauteur" en fonction de mes conditions initiales.

Je pense avoir raté quelquechose. Quand vous dites que la somme va osciller autour de 0, je ne suis pas d'accord, elle va
osciller autour d'une valeur constante. La somme serait nulle soit en la faisant sur une fenetre soit en ayant un régulateur
qui passe autant de "temps * amplitude" sous la consigne que sur la consigne. Et si c'est le cas, ce terme intégrateur ne
compense pas l'erreur statique puisqu'il est nul.

Je ne sais pas suis je suis clair dans l'explication de mon problème. J'espère que vous saurez m'aider à comprendre.

Merci d'avance

Jean

Répondre

Ferdinand Piette dit :


5 février 2013 à 17:49

Pour moi Ki dépend des conditions initiales. Sauriez vous m'expliquer pourquoi si ce
n'est pas le cas ?

Non non, Ki est bien indépendant des conditions initiales. Ki ne dépend que des caractéristiques du moteur.

Partant d'un écart plus grand, x sera supérieur à y.

Non, c'est bien y qui est supérieur à x puisque y est la somme de x plus un terme d'erreur (qui ici est de même
signe).
L'erreur grandit donc.

Un unique Ki introduira un surplus différent dans ma commande pour x et y. L'état


stable ne sera donc pas à la même "hauteur" en fonction de mes conditions initiales.

Le terme d'intégration sert à dire "Si je reste longtemps avec une erreur importante, alors je modifie
violemment la commande pour essayer de me stabilisé".
Dit autrement : "Avoir une petite erreur pendant un laps de temps important équivaut à avoir une grande
erreur pour un laps de temps cours".

Je pense avoir raté quelquechose. Quand vous dites que la somme va osciller autour
de 0, je ne suis pas d'accord, elle va osciller autour d'une valeur constante.

Hum... en effet, il semble que je me sois quelque peu fourvoyé dans mes explications. La somme va osciller
autour d'une valeur constante qui vaudra l'erreur statique du système P. C'est l'erreur qui oscille autour de
zéro.

Répondre
Jean dit :
6 février 2013 à 16:23

Non, c'est bien y qui est supérieur à x puisque y est la somme de x plus un
terme d'erreur (qui ici est de même signe).
L'erreur grandit donc.

Je ne suis pas d'accord. ^^


Si je commence à 20 tour et que je veux aller à 100, j'ai plus de "chemin" à faire que si je
commence de 40, j'aurais donc une somme d'écart plus faible vu que mon écart initial est plus
faible.

Je vois plus le terme d'intégration par son effet : compenser l'erreur statique. C'est peut être là
que je me fourvoie.
Mon objectif est d'atteindre la consigne sans écart statique quelque soit la consigne et quelque
soit T0 sans changer Kp, Ki(, et Kd). Ce n'est pas possible avec un Ki constant, c'est ce que je
retiens de mes expérimentations.

Par exemple :
T0 = 24°C, C = 50°, Ki = 0.0001 -> Somme = 3500 environ
T0' = 28°C, C = 50°, Ki = 0.0001 -> Somme' = 3700 environ
Du coup ma température de stabilisation est différente entre T0 et T0'
Ce qui est logique, mais ne m'arrange pas. ^^

C'est surtout pour le cas où je dois descendre en température que ça ne m'arrange pas vu que la
somme oscille autour d'une constante négative ce qui augmente encore plus mon écart statique.
^^

Je réfléchis actuellement à transformer la constante Ki en une fonction de quelques paramètres


(écart, commande précédente, somme, peut être d'autres ...).

Merci de votre aide.

Répondre

Ferdinand Piette dit :


19 février 2013 à 17:52

Je ne suis pas d'accord. ^^


Si je commence à 20 tour et que je veux aller à 100, j'ai plus de
"chemin" à faire que si je commence de 40, j'aurais donc une
somme d'écart plus faible vu que mon écart initial est plus faible.

En effet, mais les constantes Kp, Ki et Kd sont définies afin d'obtenir une réponse ayant
toujours la même forme, quelque soit la consigne de départ et l'état initial du système.

Ce qu'on cherche, c'est bien d'avoir une forme toujours identique pour la réponse.
Si vous changez dynamiquement le terme intégrateur, la forme de la réponse changera
aussi et dans certains cas, vous aurez un système oscillant et dans d'autre, un
système apériodique... ce qui peut être dangereux dans certaines situations (exemple,
asservir un bras pour écrire sur une feuille de papier. Dans ce cas, la réponse doit
toujours être apériodique, sinon, s'il y a un léger dépassement, la pointe s'écrase sur la
table (ou transperce la feuille))

Répondre

5. Goligo dit :
26 février 2013 à 02:12

MERCI !
Je crois que j'ai enfin compris comment mettre simplement en place un asservissement PID avec un Arduino, un moteur
et une roue codeuse.

En revanche, comment avez-vous obtenu vos courbes pour déterminer les constantes kp, ki et kd ? (Processing ?)

Répondre

Ferdinand Piette dit :


26 février 2013 à 11:27

En revanche, comment avez-vous obtenu vos courbes pour déterminer les constantes
kp, ki et kd ? (Processing ?)
Non, j'ai activé le mode débug, ce qui m'a permis d'envoyer sur le port série le nombre de tours par seconde
du moteur à chaque fois que je recalcule la commande.
#define _DEBUG true

[...]

void asservissement()
{

[...]

if(_DEBUG) Serial.println(nb_tour_par_sec,8);
}

Ensuite, un simple copier/coller dans Excel.

Attention néanmoins à bien régler le baudrate pour que la vitesse de transmission soit suffisamment rapide
afin de ne pas perturber la boucle d'asservissement !

Répondre

Goligo dit :
27 février 2013 à 01:31

Ah oui, tout simplement !


Merci beaucoup !

Répondre

6. loow dit :
29 avril 2013 à 14:28

comment avez vous tracez les graphiques??

Merci.

Répondre

Ferdinand Piette dit :


29 avril 2013 à 14:54

Cf commentaire du dessus 😉
Répondre

7. loow dit :
30 avril 2013 à 10:34

Merci de m'avoir répondu si vite.

Mais qu'avez-vous copier-coller dans votre graphique et comment avez vous fait?

Merci de votre réponse.

Répondre

Ferdinand Piette dit :


30 avril 2013 à 16:13

J'ai copié les valeurs que j'obtiens sur le port série en mode debug dans un tableur Excel.
if(_DEBUG) Serial.println(nb_tour_par_sec,8);

Ces valeurs représentent le nombre de tours de roues par seconde estimé toutes les 50ms.
Je trace ensuite le graph.

Répondre

emily dit :
8 mai 2017 à 19:45

j'ai pas trouvé les valeurs vous pouvez m'indiquer comment ça marche

Répondre

8. Clément dit :
4 juin 2013 à 02:39
Salut,

Tout d'abord merci beaucoup pour ces 2 tutos sur l'asservissement en vitesse c'est vraiment utile.
J'ai essayé aujourd'hui de le mettre en oeuvre sur mon robot mais j'ai un problème (Mon moteur avec encodeur intégré).
En fait quand je lit la réponse de mon encodeur avec analogueWrite, il me donne soit 0 soit 5, or 5 avec analogueWrite ça
veut bien dire 5/1024*5 Volt non ?
Ensuite j'ai quand même réussi a lire les tick de mon codeur avec analogueWrite :
if(analogRead(54) == 5 && verif == 0)
{
tickCodeuseG++;
//Serial.println(tickCodeuseG);
verif = 1;
}

if(analogRead(54) == 0 && verif == 1)


{
verif = 0;
}
Mais j'ai l'impression qu'il saute des tick, genre quand mon moteur tourne très vite il me dit qu'il y a autant que tick par
senconde que lorsque qu'il tourne a moitier de puissance mais pour d'autre vitesse il me répond d'autre nombres de tick
par seconde et ça semble a peu près cohérent.
Je sais que je suis pas très clair car c'est pas très clair dans ma tête non plus le fonctionnement d'un encodeur ><, je
récapitule :

_ Est t'il normale que la réponse de mon encodeur soit si faible en tension ?
_ Faut-il absolument utiliser la fonction attachInterrupt ? (Elle a un meilleur temps de réaction peut-être et elle capte
tous les tick elle)
_ Faut-il absolument utiliser la fonction attachInterrupt sur les pin Interrupt de la arduino ?

J'te remercie d'avance pour ton aide.


A bientot😉
Répondre

Ferdinand Piette dit :


4 juin 2013 à 23:31

Bonsoir,

_ Est t'il normale que la réponse de mon encodeur soit si faible en tension ?

Non, ce n'est pas normal. Déjà, sur une Arduino Méga, les entrées analogiques sont les pin 0 à 15. La pin 54
n'existe pas.

Sinon, pourquoi utiliser une entrée alors qu'un tick codeuse est un signal numérique ? Autant utiliser une
entrée numérique.

_ Faut-il absolument utiliser la fonction attachInterrupt ? (Elle a un meilleur temps de


réaction peut-être et elle capte tous les tick elle)

Oui, l'interruption se déclenchera à chaque fois que tu auras un tick (montant, descendant ou les deux). Ainsi,
tu n'en louperas pas.

_ Faut-il absolument utiliser la fonction attachInterrupt sur les pin Interrupt de la


arduino ?

Uniquement sur les pins 2 (interrupt 0), 3 (interrupt 1), 18 (interrupt 5), 19 (interrupt 4), 20 (interrupt 3), et 21
(interrupt 2) pour l'arduino méga : http://arduino.cc/en/Main/arduinoBoardMega

Répondre

Clément dit :
5 juin 2013 à 05:51

Bonjour, merci pour ta réponse très rapide :).


J'essaye ça cet aprem j'te tiens au courant.

Répondre

Clément dit :
7 juin 2013 à 00:33

Salut,
Merci pour ton aide maintenant ça marche très bien !
J'ai mis les réponses des encodeurs sur les bon pin (20 et 21) avec la bonne fonction
attachInterrupt et ça marche très bien.

Merci encore !

Répondre

9. T-Chou dit :
27 août 2013 à 14:14

Bonjour,

j'ai grasse a votre tutorial réussi a implémenter un PID pour des tètes de lecture HDD avec capteur optique.
Entre mon code de gestion d'erreurs et cette technique, c'est le jour et la nuit (un angle bien propre !)

J'avais quasiment implémenter un PID sans m'en rendre compte, une sorte de PD agissant comme suit :

cmd += kp*erreur + kd*delta_erreur;


Comme si en quelque sorte, la consigne "corrigé" un delta sur la commande.

Précis, stable, mais temps de réponse extrêmement long....

Ceci dit, j'ai quelques questions :

cmd = kp*erreur + ki*somme_erreur + kd*delta_erreur;

Ce ne devrait pas etre

cmd = kp*erreur + ki*somme_erreur + kd*delta_erreur +128;

Pour la phase de test, ki et kd ==0:


En sachant qu'erreur tend vers -inf lorsque la mesure est trop haute , cmd (avant
// Normalisation et contrôle du moteur), cmd est négatif.
donc, dans votre code, si l'erreur est négative, cmd vas être automatiquement ==0.
Afin de profiter d'un ralentissement, (a l'inverse d'un stop moteur si l'erreur est un tant soit peu négative) ne devrait ton
pas ajouter (255/2) a cmd avant normalisation ?

Est-ce assez clair? Ai-je loupé quelque chose ?

Répondre

Ferdinand Piette dit :


27 août 2013 à 16:28

Bonjour.

En sachant qu'erreur tend vers -inf lorsque la mesure est trop haute

Justement non. L'erreur ne tend jamais vers -inf. C'est la somme des erreurs qui peut potentiellement tendre à
l'infinie si l'asservissement se fait mal.

Ici, une commande à 0 signifie que le moteur n'est pas alimenté. Une commande positive signifie que le
moteur est alimenté pour tourner dans un sens. Une commande négative signifierai que le moteur puisse
tourner dans le sens inverse, ce qui est impossible dans mon exemple.
Ici, si l’erreur est négative, on n'alimente plus le moteur. Ce n'est pas un stop moteur : ne pas alimenter le
moteur ne signifie pas que celui-ci ne tourne pas !

Répondre

10. L-Buntha dit :


30 octobre 2013 à 17:59

Bonjour Ferdinand Piette !

D'abord je tiens à vous dire que je suis nouveau dans arduino. Je voudrais compiler votre code PID complet avec arduino
uno r3. Le compilateur me dit erreur :(SimpleTimer Timer 😉
does not the name type.
Et donc je sais pas quoi faire ? S'il vous plait, pouvez vous m'aider comment il faut faire pour résoudre cette problème,
je vous mercis infiniment.

Répondre

Ferdinand Piette dit :


6 novembre 2013 à 20:15

Bonjour,
Il suffit d'installer la bibliothèque SimpleTimer. Le lien est dans le code :
http://arduino.cc/playground/Code/SimpleTimer
Répondre

11. L-Buntha dit :


9 novembre 2013 à 17:12

Bonjour monsieur Ferdinant !


J'ai crée la bibliothèque dans sketche arduino comme la recommandation, et j'ai enregistré deux fichiers nommés
SimpleSimtimer.h et SimpleTimer.ccp. Et voilà le résultat comme le text en dessous :

C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-


sections -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=154 -DARDUINO_AVR_UNO -
DARDUINO_ARCH_AVR -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino -IC:\Program Files
(x86)\Arduino\hardware\arduino\avr\variants\standard
C:\Users\VX7\AppData\Local\Temp\build2312663445330094959.tmp\sketch_nov09a.cpp -o
C:\Users\VX7\AppData\Local\Temp\build2312663445330094959.tmp\sketch_nov09a.cpp.o

sketch_nov09a:9: error: 'SimpleTimer' does not name a type


sketch_nov09a.ino: In function 'void setup()':
sketch_nov09a:35: error: 'timer' was not declared in this scope
sketch_nov09a.ino: In function 'void loop()':
sketch_nov09a:40: error: 'timer' was not declared in this scope

S'il vous plais je ne sais pas comment il faut faire ?

Répondre

12. L-Buntha dit :


10 novembre 2013 à 00:45

Rebonjour encore monsieur Ferdinand !


Oubliez le text précédent au dessus, j'ai finalement réussir à compiler le programme car j'ai fait erreur en enregistrment
SimpleTimer.ccp au lieu de SimpliTimer.cpp.
Merci à vous pour me dirigez vers bibliothèque SimpleTimer. A la suite

Répondre

13. cyril dit :


16 mars 2014 à 03:09

Salut, super détaillé, excellent site 😉


Répondre

14. Alban dit :


10 mai 2014 à 22:05

Les explications sont claires.j'aime.

Répondre

15. Rémy dit :


15 mai 2014 à 13:39

Bonjour Ferdinand.
Je développe actuellement un fauteuil roulant électrique pour personne handicapée.
Mon cahier des charges: autonomie supérieure à 6 heures, capacité de franchissement de marches de 16 cm, et donc
des trottoirs, et fonction tout terrain, l'ensemble devant rester dans les dimensions d'un fauteuil roulant, et à un prix
abordable.
J'ai un moteur 24v, DC par roue, soit 4 moteurs. Tous les contrôleurs pilotés par joystick que j'ai trouvés à ce jour ne
peuvent contrôler que 2 moteurs. Je pensais coupler les moteurs droits ensembles et gauches ensembles, mais je
risque d'avoir une vitesse différente entre les deux moteurs, et donc un comportement chaotique du fauteuil. J'ai donc
pensé à asservir le moteur arrière droit au moteur avant droit afin qu'il tourne à la même vitesse de manière
automatique, et idem à gauche, et ainsi je pourrais utiliser le joystick. Pourriez-vous m'aider à réaliser cette partie
électronique que je ne maitrise absolument pas. A quel coût?
Voila. Si cela retient votre attention, merci de m'envoyer un email pour poursuivre.
Merci, Cordialement
Rémy

Répondre

jean dit :
8 août 2014 à 19:38

excellentes explications du PID,


j'avais deja mis en oeuvre des asservissements, mais pas aussi efficace.

bonjour Rémy
avez vous trouvé quelqu'un pour vous aider?
Jean

Répondre

16. BKD dit :


20 août 2014 à 10:16

Tout simplement excellent Ferdinand...


Supers explications du PID pour tous !
Merci.
Bruno.

Répondre

17. Etroplus dit :


19 septembre 2014 à 15:09

Merci, c'est très utile!

Répondre

18. LEDEUX dit :


14 janvier 2015 à 10:04

Bonjour,

Très beau travail!

Je veux réaliser une pompe à eau en fonction d'une consigne de débit. Pour cela je dispose d'un pompe dc12v et d'un
débitmètre qui me sort un signal sinusoïdal à fréquence variable. n'ayant pas de roue codeuse puis je me servir des
informations fournis par le débitmètre pour réaliser un asservissement PID?

Si c'est réalisable pouvez vous m'expliquer les grandes lignes SVP?

Merci de votre aide.

Répondre

Ferdinand Piette dit :


14 janvier 2015 à 11:57

Bonjour,

Cela me semble tout à fait réalisable.


Pour cela, il suffit de convertir la fréquence du signal en sortie du débitmètre en débit (à l'aide des
informations contenues dans la datasheet du capteur où grâce à un calibrage).

Il faut donc réaliser le PID sur cette information de débit : il faut calculer l'erreur et la somme des erreurs par
rapport à un débit de consigne. Le résultat du PID servira à commander le moteur.

Répondre

19. Sebastien dit :


10 février 2015 à 09:54

Merci du temps passé !!! Tres utile ! 😛


Répondre

20. kioub dit :


25 mars 2015 à 22:44

Bonjour et merci pour les explications.


Je débute en essayant de fabriquer un robot gyropode. J'ai testé votre programme sur un motoréducteur et bien sur :
cela fonctionne parfaitement.

Du coup, j'ai essayé de le modifier pour faire tourner 2 moteurs avec la même consigne et là... problème. Le deuxième
moteur tourne à pleine vitesse. Apparemment, les interruptions sur la broche 3 (int1) ne fonctionne pas.

Vous accepteriez de jeter un petit coup d’œil à mon sketch ?

Répondre

21. kioub dit :


27 mars 2015 à 18:47
C'est encore moi... En fait le programme était bon mais j'avais un faux contact. Merci encore

Répondre

22. bat dit :


14 mai 2015 à 14:55

Bonjour , j'aurais 2 questions . C'est lorsque j'essaie de compiler le code , j'ai une erreur dans arduino : "class simple
timer has no menber named 'set interval'", j''ai donc un problème de compilation sachant que j'ai bien inclu la
bibliotheque simpletimer .
Utilisie-tu simplement ta carte arduino et ton moteur codeur ou tu utilise à la place une carte romeo ?. Car j'ai fait des
recherche , le codeur incrémentale delivre bcp trop d'impulsions pour la carte arduino donc elle est incapable de gerer
toutes et ces impusions , il faut donc utiliser une carte romeo qui inclus une sorte de diviseur de frequence qui a pour
but de diminuer la frequence des impulsions et donc d'avoir une frequence plus basse pour que arduino puisse la gérer
correctement , merci d'avance

Répondre

Ferdinand Piette dit :


15 mai 2015 à 15:10

Bonjour,

Pour la première question, je ne sais pas. La bibliothèque contient toujours un membre setInterval
(http://playground.arduino.cc/Code/SimpleTimer#F_setInterval). Il doit y avoir un problème dans le code :
avez-vous bien fait l'include ? avez vous bien instancié un objet timer ?

Pour la seconde question, oui, j'ai testé mon code sur une arduino uno et mega et ça marche parfaitement.
La uno est tout à fait capable de gérer les quelques 5500 impulsions par secondes que peut délivrer la
codeuse lorsque le moteur est à plein régime.
Pas besoin de "diminuer la fréquence des impulsions". Ce n'est d'ailleurs possible qu'en utilisant une codeuse
moins précise ou en mettant la codeuse après le réducteur et non sur l'arbre moteur. Mais dans les deux cas,
on perd en précision.

Répondre

bat dit :
17 mai 2015 à 10:24

Merci de m'avoir répondu aussi rapidement , j'ai donc laisser tomber le diviseur de frequence ,
mais aurait-tu une idée de la capacité de la carte arduino à recevoir des données , peut-elle gérer
plus de 6000 impulsions par sec(en moyenne)? J'ai tester ton code , j'ai bien inclus le fichier
SimpleTimer.h et SimpleTimer.cpp , le code marche mais mon problème concernant le 'set
interval' et 'run'(dans le loop)persiste , le code se compile très bien sans ces deux lignes , arduino
ne semble pas les connaitre . Aurait -tu une idée ? cordialement

Répondre

23. dakito dit :


4 juin 2015 à 20:08

Bonjour M ferdinand , je tiens tous d'abord à vous remercier pour le travail que vous avez réalisé . Mais si je vous envoie
ce message , c'est parce que j'ai un véritable problème qui me bloque complètement .
Je précise tous d'abord que mon moteur à un régime nominal de 6v , une reduction de 1/53 et 48 impulsions pour
chaque tour de moteur effectuer .
Lorsque je lance le programme , et que j'essaie d'afficher les impulsions stoker dans la variable compteur , il m'affiche
300 impulsions alors que moteur en sortie de reducteur n'a fait que 1 tour (il devrait m'afficher environ 2544 impulsion
car 53 * 48 =2544)
2)Comment pouvons nous déterminer les coeficients kp , ki , kd ?
merci

Répondre

MajorLee dit :
18 septembre 2015 à 16:31

Je me permet ce petit commentaire car je suis confronté en ce moment au même genre de problèmes.
Tout d'abord un grand merci à M.Piette pour ses tutoriaux.
@dakito : Attention quand un fabricant/fournisseur donne un codeur à 48 impulsions par tour cela sous
entend 2 fronts (montant et descendant) sur chacune des voies A et B (cas d'un encodeur à 2 voies en
quandrature). Si on n’échantillonne seulement un des 2 signaux et seulement un seul front, on se retrouve
avec 4 fois moins d'impulsions. Cela peut être une piste dans votre cas.

Répondre

24. Jonathan dit :


5 juin 2015 à 08:57
Bonjour,

Si je ne me trompe pas, c'est l’asservissement I qui permet d'avoir un système précis, et non l'asservissement P, pour un
système d'ordre 0.

Répondre

25. haifa dit :


25 juin 2015 à 16:34

est ce ke j peux avoir votre compte personnel parce que je veux que tu m'aide dans mon projet

Répondre

26. roger dit :


8 octobre 2015 à 13:20

bonjour. je suis un novice et je m'intéresse à tout ce qui touche le handicap. je me bat pour comprendre le langage et la
programmation. pour le côté matériel hardware et mécanique ce là devrait aller pour moi. à la lecture des commentaires
aux quels j'arrive à comprendre. une idée me viens:pourquoi ne pas utiliser un moteur pas à pas . avec réducteur devant
un différentiel des deux arbre de roues. y aurait-il un problème de puissance pour ne pas utiliser un pas a pas.
merci par avance de votre reponse
cordialement
Roger

Répondre

Ferdinand Piette dit :


8 octobre 2015 à 13:46

Bonjour,
Oui, c'est possible, mais dans ce cas là, la régulation PID et la roue codeuse ne sert plus à rien.
Le propos de l'article était justement d'illustrer l'utilisation d'un PID.
L'utilisation d'un moteur à courant continue ou pas à pas dépend de l'application.

Répondre

27. Michel dit :


5 novembre 2015 à 14:10

Bonjour,

Je ne comprend pas à quoi servent les résistances R1 et R2 exactement. Comment elles ont été choisies ? Il s'agit de
limiter la tension ? le courant ?

Je ne comprend pas non plus pourquoi on a besoin d'un transistor Bipolaire ? pourquoi ne pas directement utiliser le
transistor MOFSET ? Pourquoi passer par l’intermédiaire d'un transistor bipolaire avant ?

La diode est une diode de roue libre ? pour eviter les surtensions sur le moteur ?

Je ne comprend pas exactement le choix des composants sur le circuit electrique.

Cordialement

Michel

Et Merci pour se site !

Répondre

Ferdinand Piette dit :


5 novembre 2015 à 14:45

Bonjour,

J'avais réalisé à l'époque l'interface de commande rapidement avec les composants à ma disposition.
Il y a donc surement moyen de faire mieux (notamment, cette interface ne peut pas faire tourner le moteur
dans les deux sens). Néanmoins, compte tenu de mes besoins, celle-ci est plus que suffisante.

R1 est juste une résistante de pull-up pour commander le MOFSET à 12V lorsque le bipolaire est bloqué.
Lorsque le bipolaire est passant, la gate du MOFSET est forcé à 0V et R1 sert à éviter un court-circuit (il y a
seulement 12mA qui passent dans R1 et dans le bipolaire du coup).
La valeur de R1 a été choisi au pifomètre, mais on pourrait l'augmenter encore afin de limiter le courant
traversant le bipolaire (aucun courant ne passe dans la gate du MOFSET qui est un transistor commandé en
tension et non en courant comme le bipolaire).

R2, quant à elle, sert à limiter le courant entrant à la base du bipolaire (vu que c'est un transistor commandé
en courant cette fois).
Lorsque la pin9 de l'Arduino est en état haut (5V), le bipolaire conduit. Sa base est donc environ à 0.7V, ce qui
fait que le courant de commande du bipolaire est de (5-0.7)/1000 soit 4.3mA environ.

On ne peut pas commander directement le MOFSET via l'Arduino car celle-ci délivre du 5V alors que le
MOFSET doit être commandé en 12V.
Le bipolaire permet donc de passer d'une commande 0-5V à une commande 12V-0V (ici, la commande est
inversée, mais on pourrait imaginer une interface qui n’inverse pas la commande).
Donc l'Arduino, R1, R2 et le bipolaire forment la partie commande alors que le MOFSET et D1 forment la
partie puissance.

La diode D1 est en effet une diode de roue libre afin d'évacuer le courant du moteur lorsque le MOFSET se
coupe. Le moteur étant composé d'une bobine et donc une inductance, on ne peut pas avoir de discontinuité
dans le courant sous peine de sur-tension au moment où l'on active ou coupe le MOFSET.
En théorie le MOFSET inclut déjà une diode de roue libre, mais en pratique elle est souvent sous
dimensionnée.

Répondre

Michel dit :
16 novembre 2015 à 22:41

Merci pour cette réponse, c'est très clair !

Répondre

28. Bandit972 dit :


24 décembre 2015 à 09:48

Bonjour
Je souhaite mettre en place une surveillance de mon regulateur Pid vitesse afin d'eviter tout emballement en cas de
panne-panne encodeur par exemple.en surveillant que ma composante integrale (sur consigne elevee)ne depasse pas
un seuil pendant plus de 2sec jarrive a empecher cette survitesse. Oui mais voila ,des que je rentre une consigne tres
petite et que je simule de nouveau cette panne d'encodeur le systeme de secu ne se declenche que 3 min apres le debut-
le robot ayant deja pris beaucoup de vitesse....je cherche une idee donc pour que la surveillance soit efficace aussi bien
en consigne haute quant consigne basse...si vous avez une idee?!CDT

Répondre

29. Lombard dit :


15 janvier 2016 à 17:29

Bonjour
Les explications sont très claires . Je suis un projet de construction de gyropode (type segway) à base d accelometre et
gyroscope sous arduino et j ai pu lire certains projets sur le net mais en anglais
Il y a la notion de pid par rapport à la mesure de l angle d inclinaison et la vitesse moteur associée
Pouvez m aider sur ces notions ?
Merci et encore bravo !

Répondre

30. Phil dit :


5 février 2016 à 22:47

Bonjour,

merci pour votre article tres interressant et tres clair. Pour illustrer celui ci vous avez des graphes, pouvez vous
mexpliquer comment vous les avez obtenus car pour le projet que je développe j'ai besoins de tracer les sorties
obtenues.
Cordialement.

Répondre

Ferdinand Piette dit :


22 février 2016 à 18:16

Bonjour,

J'ai récupéré les valeurs affiché dans la console Arduino et je les ais importés dans Excel.

Répondre

31. Leo dit :


9 février 2016 à 18:43

Bonjour,
Je suis désolé de vous poser la question ici car elle n'a pas forcément un très grand rapport avec le sujet du dessus.
J'aurais préféré vous contacter autrement ... Veuillez m'en excuser.

Je cherche à contrôler avec un Arduino si c'est possible plusieurs multiplexeurs. Je vous explique le contexte:

Je veux réaliser une mesure 4 fils de faible résistance à l'aide d'un ohmmètre que je pense acheter. Le problème est que
j'ai une bonne centaine de résistance à mesurer et j'aimerai bien automatiser la chose... ( La valeur des résistances
varient au cours du temps ).

J'aimerais donc pouvoir aiguiller mes pistes de façon à ce que mon ohmmètre mesure la résistance 1 puis la résistance
2 ainsi de suite ...

j'aimerais savoir si vous avez déjà réalisé un montage arduino avec un multiplexeur. Si cela vous semble possible car il
me faut plusieurs multiplexeur et que en tout j'aurais je pense avoir au moins 200 pistes à gérer. Ce qui me ferait utiliser
au moins 8 sorties numériques de l'arduino pour coder la positions des multiplexeurs ? je pense que 8 sorties
numériques c'est vraiment un minimum ... Sachant qu'il y 13 sorties numériques sur l'arduino dont 6 qui sont des PWM .
Bon après rien ne m'empèche d'utiliser des PWM en guise de sortie numérique non ?

Voila merci beaucoup ! Si vous avez des idées à me suggérer, n'hésitez pas 🙂
Encore une fois désolé de m'adresser sur un sujet qui parle d'asservissement.

Répondre

32. saoudi dit :


20 février 2016 à 17:17

comment faire commande 5 moteurs a courant continu dans des deffernts sens a l'aide d'un clavier pour donner l'angle
et un ecrant LCD 😕
Répondre

33. Bruno dit :


24 février 2016 à 22:05

Salut

Déja , beau boulot pour tes différentes explications sur la régul PID .
Je suis entrain d'essayer de régler la mienne pour le chauffage d'une pièce (salle de bain de 5m2).
En commençant mes tests de Kp , j'arrive à trouver une valeur qui me satisfait , sans trop de d'oscillations mais en étant
un peu éloigné de ma consigne (env. 0,5 °C) , du coup j'ai voulu faire intervenir le Kd mais le soucis est que la pièce a une
certaine inertie et donc elle met un peu de temps à atteindre une tempêrature proche de ma consigne et que pendant ce
temps ma somme d'erreurs augmente tout le temps ... Et donc une fois la consigne dépassée, avec l'inertie , elle met du
temps à revenir proche de zéro . Je me suis dit que j'allais augmenter le Kd , sauf que ça fait s'emballer le système et si à
l'inverse je le diminue .. bah il me sert plus à rien ^^ !

Aurais tu une piste pour éviter ce phénomène ? Je pensais imposer des limites au produit Kd*somme_erreurs ou alors
commencer à compter la somme d'erreurs "le plus tard possible" et non dès le début ...

Merci

Répondre

Ferdinand Piette dit :


24 février 2016 à 22:57

Bonjour,

Après Kp, tu as essayé d'intégrer Ki je suppose (et non Kd) ?


Dans un système avec beaucoup d'inertie, en effet, le Ki peut faire très rapidement osciller la réponse.
Normalement, le fait de rajouter le Kd permet justement d'anticiper ces dépassements.
Dans mon exemple avec le moteur, Kd ne servait quasiment à rien (le système étant très réactif).
Par contre, dans un système avec beaucoup d'inertie comme le tiens, Kd devrait être très utile. C'est étrange
que le système s'emballe avec du coup...

Répondre

34. Pierrick dit :


12 mars 2016 à 14:05

Bonjour,

Tout d’abord merci pour ce tuto,

Je viens solliciter votre aide car cela fait 3 mois que mes neurones surchauffe sur mon projet et là je sature....

Pour faire vite, j'ai un plateau tournant actionner par un petit moteur mais la partie réducteur ce fait avec une vis sans fin.
Ce plateau est fixé à la vertical avec un bras en porte à faux ce qui entraîne un freinage en monté et donc une
accélération en descente...
Le problème que je rencontre, contrairement à votre projet c'est que quand le moteur n'est pas alimenté, il s'arrête quasi
instantanément.
Ceci entraîne donc une rotation saccadée qui ne permet pas de régler le PID correctement.
J'ai chercher à commander le plateau en degré par minute car cela correspond plus à la vitesse rechercher qui est au
maximum de 3 où 4 tours par minute.

Auriez vous une piste pour créé un asservissement angulaire qui ne coupe pas complètement le moteur en cas de
dépassement de la consigne ??

Je suis novice mais je ne cherche pas de solution "toute faite" mais juste un p'tit coup pouce pour ne pas finir de
m'arracher les cheveux 🙂
Merci d'avance pour votre aide

Cordialement,
Pierro

Ps : Je vous met à dispo l'ébauche de de mon programme


[PHP]
#include // http://arduino.cc/playground/Code/SimpleTimer

SimpleTimer timer; // Timer pour echantillonnage

const int potar = A1; //la broche pour regler la vitesse


int cmd = 0 ;

const int LED = 3; // Constante pour la broche 3

const int _MOTEUR = 10; // Digital pin en PWM pour commande moteur

unsigned int tick_codeuse = 0; // Compteur de tick de la codeuse

const int frequence_echantillonnage = 200; // Frequence du pid


const int rapport_reducteur = 468; // Rapport entre le nombre de tours de l'arbre moteur et de la roue
const int tick_par_tour_codeuse = 2; // Nombre de tick codeuse par tour de l'arbre moteur

// gestion vitesse angulaire


float consigne_vitesse_angulaire = analogRead(potar);

float erreur_precedente = (float) consigne_vitesse_angulaire;


float somme_erreur = 0; // Somme des erreurs pour l'integrateur
float kp = 200; // Coefficient proportionnel
float ki = -1; // Coefficient integrateur
float kd = 300; // Coefficient derivateur

/* Routine d'initialisation */
void setup() {
Serial.begin(250000); // Initialisation port COM
pinMode(_MOTEUR, OUTPUT); // Sortie moteur
analogWrite(_MOTEUR, 255); // Sortie moteur a 0

delay(1000); // Pause de 1 sec pour laisser le temps au moteur de s'arreter si celui-ci est en marche

attachInterrupt(0, compteur, RISING); // Interruption sur tick de la codeuse (interruption 0 = pin2 arduino mega)
timer.setInterval(1000/frequence_echantillonnage, asservissement); // Interruption pour calcul du PID et asservissement
}

/* Fonction principale */
void loop() {
timer.run();
delay(10);
}

/* Interruption sur tick de la codeuse */


void compteur() {
tick_codeuse++; // On incremente le nombre de tick de la codeuse
}

/* Interruption pour calcul du PID */


void asservissement()
{
// Réinitialisation du nombre de tick de la codeuse
int tick = tick_codeuse;
tick_codeuse = 0;

// Calcul des erreurs


float frequence_codeuse = frequence_echantillonnage*tick;
float nb_degre_par_sec = (float)frequence_codeuse/(float)tick_par_tour_codeuse/(float)rapport_reducteur*360;
float erreur = consigne_vitesse_angulaire - nb_degre_par_sec;
somme_erreur += erreur;
float delta_erreur = erreur - erreur_precedente;
erreur_precedente = erreur;
// PID : calcul de la commande
cmd = kp * erreur + ki * somme_erreur + kd * delta_erreur;

// Normalisation et controle du moteur


if (consigne_vitesse_angulaire 500) cmd = 255;
consigne_vitesse_angulaire = analogRead(potar); // mesure tension du potar
consigne_vitesse_angulaire = map(consigne_vitesse_angulaire, 510, 750, 0, 500); // adaptation echelle valeur

analogWrite(_MOTEUR, 255 - cmd);

// affiche sur le moniteur les données voulues


Serial.print("Erreur : "); Serial.print(erreur,5);
Serial.print(" ");
Serial.print("consigne vitesse ang. : ");Serial.print(consigne_vitesse_angulaire,3);
Serial.print(" ");
Serial.print("Commande : "); Serial.print(cmd,3);
Serial.print(" ");
Serial.print("nb_degre_par_sec : ");Serial.print(nb_degre_par_sec,6);
Serial.print(" ");
Serial.print("erreur precedente : ");Serial.print(erreur_precedente,5);
Serial.print(" ");
Serial.print("Freq. Codeuse : ");Serial.println(frequence_codeuse,6);

[/PHP]

Répondre

Ferdinand Piette dit :


1 mai 2016 à 13:21

Bonjour,

Je n'ai pas de solution qui me vient à l'esprit.


Mis à part déterminer les coefficient kp ki et kd afin qu'il n'y ait jamais de dépassement !

Répondre

35. EL BAKKALI dit :


22 mars 2016 à 15:01

salut,
j'ai un mini projet sur asservissement en vitesse linéaire , si et possible donnez-moi quelques exemples de vitesse
linéaire! je trouve des machines en vitesse angulaire mais je ne trouve pas en vitesse linéaire!!

Répondre

36. Olivier dit :


19 avril 2016 à 12:22

Bonjour,

Merci et bravo pour ces deux articles clairs et qui expliquent simplement les PID et leurs mise en oeuvre pratique.
M'amusant beaucoup avec des drones je m'explique mieux leurs comportement et cela facilite grandement les réglages.

Répondre

37. BOURSIN dit :


21 août 2016 à 18:59

Merci pour votre cours, mais quelles sont les puissances des résistances et quel type de diode ?

Répondre

38. william dit :


13 septembre 2016 à 08:04

Salut,

ton article est vraiment très intéressant et à du en aider plus d'un 🙂


J'essais pour ma part de l'utiliser pour l'asservissement d'un moteur Brushless avec un signal en Spwm.
La vitesse de rotation varie avec la fréquence d’exécution de la fonction loop dans laquelle on fait varier la valeur des
sorties PWM.

Ma roue codeuse fait 2400 tick par tour et j'essai d'avoir une vitesse constante de 137 ticks toutes les 100 ms.
c'est ce que j'obtiens quand ma fréquences de boucle est à 13µs environ. delayMicroseconds(cmd);
Ce que je ne comprends pas c'est que les valeurs de CMD issue du cacul de PID sont bien au dessus du chiffre 13 ce qui
fait que mon moteur se retrouve aux vitesses de seuil fixés. Soit vitesse maxi, soit à l'arret.

Pour info voici ma fonction, je n'ai pas à traduire les tick en frequence de rotation car ma consigne est le nombre de tick
lui même sur 100ms

void asservissement()
{

int tick = ticksCodeur;


ticksCodeur = 0;

// Calcul de l'erreur
int erreur = consnbticks - tick;
somme_erreur += erreur;
float delta_erreur = erreur - erreur_precedente;
erreur_precedente = erreur;

// PID : calcul de la commande


cmd = 500 - kp*erreur + ki*somme_erreur + kd*delta_erreur;

// Normalisation et contr�le du moteur


if (cmd 200) cmd = 500;

Serial << tick << ";" << erreur << ";" << somme_erreur << ";" << delta_erreur << ";" << cmd << endl;
}

Merci de votre aide si vous suivez toujours ce poste 🙂


Répondre

39. feten dit :


19 septembre 2016 à 16:40

Bonjour, est ce que vous pouvez me donner une methode pour convertir la commande calculée par le PID en des signaux
PWM? quelle relation entre cette commande et les rapports cycliques des Timers?

Répondre

40. William dit :


21 septembre 2016 à 15:34

Bonjour,

en fait c'est la question que je me pose aussi... une mise à l'échelle entre le résultat du pid et la commande moteur est
obligatoire en fait non ?

Par exemple cela fonctionnerait t'il si on souhaitait avoir comme consigne le nombre de tick codeur par 100ms ?

l'échelle n'est pas la même et il n'y a pas de rapport précis entre le dutycycle du pwm et la vitesse de rotation.

Répondre

41. Domi22 dit :


29 octobre 2016 à 05:16

Bonjour et simplement merci pour ces démonstrations et ces aides que vous nous apportez.
Je reconnais que j'avais oublié ces notions et donc abandonné un projet mais ces petits rappels me donnent l'envie de
m'y remettre : donc MERCI Ferdinand.

Répondre

42. Mouad dit :


5 février 2017 à 15:02

Bonjour,
Est que vous pouvez m'aider a faire un organigramme pour ce programme. Merci

Répondre

43. AIT AHMED WASSIMA dit :


18 février 2017 à 23:12

Bonsoir
Je trouve votre tuto très intéressant merci beaucoup , en fait je voulais demander autre chose , les graphes vous les
obtenez comment ? est ce un logiciel ou bien vous les tracez vous même ?
Merci

Répondre
44. DD_ard_56 dit :
22 février 2017 à 23:23

Bonjour, un grand merci pour ce super tuto.

Répondre

45. Mouad dit :


26 mars 2017 à 22:22

J'arrive pas a faire un logigramme pour ce programme

Répondre

46. Lombard dit :


21 juin 2017 à 21:27

Bonsoir
J ai un projet de construction d un gyropode type "segway" , et je pense que la mise en place d'un pid indispensable au
sujet du calcul angulaire de la plate forme et faire réagir les moteurs en conséquence
Par contre je ne sais pas comment déterminer les consignes !
Pourriez.vous m'aider sur le sujet ?
Merci d avance
Giloris

Répondre

47. Herman dit :


29 juin 2017 à 02:55

Bonjour, je travaille actuellement sur une maquette d'ascenseur et je suis bloquer au niveau de sin asservissement en
vitesse svp faite un schéma complet qui marche avec le programme final de ferdinand. Merci

Répondre

48. peter dit :


6 mars 2018 à 18:26

bonjour
je ne comprends pas comme fonctionne cet asservissement de vitesse, si il s'agit bien d'un asservissement de vitesse?
Pour faire simple on va se placer dans le cas ou on ne fait que du proportionnel (donc pas de Ki et pas de Kd)
j'ai donc cmd qui vaut : Kp * erreur
la commande qui est envoyée avec analogwrite est : analogwrite(broche, 255-cmd)

Lorsque la vitesse réelle est égale à la consigne j'ai cmd=0 car erreur =0 donc une valeur de 255 est envoyée ce qui
correspond à la vitesse max indépendamment de ma valeur de consigne. Il n'y a donc pas d'asservissement par rapport
à la consigne de vitesse? ou alors il y a quelque chose de gros qui m'échappe...

Répondre

49. ayoub dit :


30 avril 2018 à 16:07

mrc pour les eplication j ai an dynamotachemitrique a la place de l encodeur j'arrive pas a faire son asservissement

Répondre

50. Ismael dit :


7 juin 2018 à 21:34

Bonsoir, moi j'essaie d'utiliser ce code mais j'ai besoin du schéma si possible

Répondre

51. Philippe dit :


18 novembre 2018 à 21:42

Bonsoir,

Merci pour ce processus détaillé de mise en œuvre d'une régul PID sur ARDUINO, avec un moteur cc pour actionneur.
Retraité de la pétrochimie en centrale thermique, j'étais toujours en admiration devant les personnes en charge de régler
les boucles de régulation avec la phase identification, et réglages. C'était quelques fois du PI seul.
Je vais peut-être mettre en œuvre ce code pour une appli de rotation de tube en phase de soudure pour un ami
ferronnier. L'entrainement du tube en rotation devant se faire à vitesse constante et stable, l'actionneur serait un moteur
d'essuie-glace via un réducteur 50:1.
Merci à vous pour ce brillant développement sur un cas concret, aboutissant à du code directement applicable, sous
réserve de trouver les coefficients appropriés.

Bonne continuation!!

Répondre

52. Sofo dit :


8 janvier 2019 à 20:05

Salut,

je ne comprends pas comment tu calcules la vitesse de rotation en tours/s a partir du nombre d impulsions.

( ligne 57 et 58 du code )

A partir de ma roue codeuse je peux directement obtenir la vitesse de rotation en tours par seconde , et je pourrais
directement passer a la ligne du code 59 . est ce possible?

Merci de votre reponse

Répondre

53. Joeffrey dit :


28 mars 2019 à 16:03

bonjour,
c'est étrange mais je ne vois à aucun moment l'utilisation de la codeuse O_o.
Comment faites vous pour mesurez quoi que ce soit sans même l'instancier?

Répondre

Laisser un commentaire

Your Comment

bilink href=""b-quotecode ;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :lol:
:idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!:?
Apercu

Vous pouvez utiliser ces tags et attributs HTML&nsbp;: <a href="" title=""> <abbr title=""> <acronym
title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s>
<strike> <strong>

Name (required)

E-mail (required)

URI

Soumettre le commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

© 2011-2012 Ferdinand Piette

Vous aimerez peut-être aussi