Aller au contenu


Photo
- - - - -

Mon premier robot Arduino


83 réponses à ce sujet

#21 inovasong

inovasong

    Membre

  • Membres
  • 56 messages

Posté 24 avril 2012 - 08:06

Bonsoir,

Bon voila ou j'en suis j'ai adapté un code (toujours merci Black Templar) pour l'asservissement de mes deux moteurs voir le résultat ci dessous,
Mais la est le problème les commandes moteurs envoyé ressembler a çà est-ce normal ou bien mon code a un problème ?


G - D

0 - 0
6 - 6
6 - 6
0 - 0
6 - 6
6 - 6
0 - 0
6 - 6
6 - 6
6 - 6
0 - 0
6 - 6
0 - 6
5 - 6
6 - 0
6 - 6
0 - 6
6 - 0
6 - 6
0 - 6
5 - 6
6 - 0



#include <SimpleTimer.h>
#define GAUCHE 0
#define DROITE 1
SimpleTimer timer;
unsigned int tick[] = { 0, 0 };     // Compteur de tick de la codeuse


int cmd[] = { 0, 0 };                       // Commande du moteur
const int frequence_echantillonnage = 20;  // Fréquence d'exécution de l'asservissement
const int rapport_reducteur = 1;          // Rapport entre le nombre de tours de l'arbre moteur et de la roue
const int tick_par_tour_codeuse = 20;      // Nombre de tick codeuse par tour de l'arbre moteur
 
float consigne_moteur_nombre_tours_par_seconde[] = { 1.3 , 1.3 };  //  Nombre de tours de roue par seconde
 
float erreur_precedente[] = { consigne_moteur_nombre_tours_par_seconde[GAUCHE] , consigne_moteur_nombre_tours_par_seconde[DROITE] };
float somme_erreur[] = { 0 , 0 };   // Somme des erreurs pour l'intégrateur
float kp = 300;           // Coefficient proportionnel
float ki = 5;           // Coefficient intégrateur
float kd = 0;           // Coefficient dérivateur

/* Routine d'initialisation */
void setup() {
  Serial.begin(9600);         // Initialisation port COM
  Serial2.begin(115200);// Initialisation port COM 2
  attachInterrupt(GAUCHE, compteur_gauche, CHANGE);    // Interruption sur tick de la codeuse (interruption 0 = pin2 arduino mega)
  attachInterrupt(DROITE, compteur_droite, CHANGE);    // Interruption sur tick de la codeuse (interruption 1 = pin3 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_gauche(){
  tick[GAUCHE]++;  // On incrémente le nombre de tick de la codeuse
}
void compteur_droite(){
  tick[DROITE]++;  // On incrémente le nombre de tick de la codeuse
}


void asservissement()
{
    // Réinitialisation du nombre de tick de la codeuse
    int nb_ticks[] = { tick[GAUCHE], tick[DROITE]};
     tick[DROITE]=0;
     tick[GAUCHE]=0;
 
    // Calcul des erreurs
    int frequence_codeuse[] = { frequence_echantillonnage*nb_ticks[GAUCHE] , frequence_echantillonnage*nb_ticks[DROITE] };
    float nb_tour_par_sec[] = { (float)frequence_codeuse[GAUCHE]/(float)tick_par_tour_codeuse/(float)rapport_reducteur , (float)frequence_codeuse[DROITE]/(float)tick_par_tour_codeuse/(float)rapport_reducteur };
    float erreur[] = { consigne_moteur_nombre_tours_par_seconde[GAUCHE] - nb_tour_par_sec[GAUCHE] , consigne_moteur_nombre_tours_par_seconde[DROITE] - nb_tour_par_sec[DROITE] } ;
    somme_erreur[GAUCHE] += erreur[GAUCHE];
    somme_erreur[DROITE] += erreur[DROITE];
    float delta_erreur[] = { erreur[GAUCHE]-erreur_precedente[GAUCHE] , erreur[DROITE]-erreur_precedente[DROITE] } ;
    erreur_precedente[GAUCHE] = erreur[GAUCHE];
    erreur_precedente[DROITE] = erreur[DROITE];
 
    // PID : calcul de la commande
    cmd[GAUCHE] = kp*erreur[GAUCHE] + ki*somme_erreur[GAUCHE] + kd*delta_erreur[GAUCHE];
    cmd[DROITE] = kp*erreur[DROITE] + ki*somme_erreur[DROITE] + kd*delta_erreur[DROITE];
 
    // Normalisation et contrôle du moteur
    if(cmd[GAUCHE] < 0) cmd[GAUCHE]=0;
    else if(cmd[GAUCHE] > 255) cmd[GAUCHE] = 255;
    cmd[GAUCHE]= cmd[GAUCHE]/25.5;
        if(cmd[DROITE] < 0) cmd[DROITE]=0;
    else if(cmd[DROITE] > 255) cmd[DROITE] = 255;
    cmd[DROITE]= cmd[DROITE]/25.5;
    
    Serial2.write('2');

    Serial2.write('r');
    Serial2.write(int_char(cmd[GAUCHE])); 
    Serial2.write('\r');
    delay(10);
        Serial2.write('1');

    Serial2.write('r');
    Serial2.write(int_char(cmd[DROITE])); 
    Serial2.write('\r');
    delay(10);
    // DEBUG
    
Serial.print(cmd[GAUCHE]);
Serial.print(" - ");
Serial.println(cmd[DROITE]);
    
}

char int_char(int n){
  char resultat='0';
  if(n < 1) resultat='0';
  else if (n < 2) resultat='1';
  else if (n < 3) resultat='2';
  else if (n < 4) resultat='3';
  else if (n < 5) resultat='4';
  else if (n < 6) resultat='5';
  else if (n < 7) resultat='6';
  else if (n < 8) resultat='7';
  else if (n < 9) resultat='8';
  else if (n >= 9) resultat='9';
  return resultat;

}


Pourquoi j'ais des commandes a 0 en permanence ?

#22 Black Templar

Black Templar

    Membre

  • Membres
  • PipPipPipPipPip
  • 1 430 messages
  • Gender:Male
  • Location:Lille

Posté 24 avril 2012 - 09:09

Salut !

Plutôt que d'afficher les commandes, essaye d'afficher le nb_tour_par_seconde pour voir ce que ça donne.
Et aussi, augmente le baudrate du port série Serial :)


Ton moteur, il fait bien environ 1.3 tours à la seconde ? (à vu de nez ?)

Mon site internet : http://ferdinandpiette.com/


#23 inovasong

inovasong

    Membre

  • Membres
  • 56 messages

Posté 25 avril 2012 - 02:12

Salut !

Plutôt que d'afficher les commandes, essaye d'afficher le nb_tour_par_seconde pour voir ce que ça donne.
Et aussi, augmente le baudrate du port série Serial :)


Ton moteur, il fait bien environ 1.3 tours à la seconde ? (à vu de nez ?)


Le problème est le même, quand je mesure nb_tour_par_seconde j'obtiens uniquement les valeurs 0 et 25.

25.00
0.00
25.00
25.00
25.00
25.00
0.00
25.00
25.00
25.00
0.00
25.00


Je pense que j'ai un probblème de calcule de vitesse non ?

Modifié par inovasong, 25 avril 2012 - 02:30 .


#24 inovasong

inovasong

    Membre

  • Membres
  • 56 messages

Posté 25 avril 2012 - 04:29

Voila ou j'en suis, il me semble avec mes maigres connaissances qu'il est difficile de mesurer la vitesse avec précision au delà de 4 Hz car si je dépasse cette valeur je me retrouve avec des erreurs de mesures.

Pourquoi ? <_<
#include <SimpleTimer.h>
SimpleTimer timer;

float codeuse = 0;
float measured_tick  = 0;
int frequence = 4;

void setup(){
  Serial.begin(115200);
  Serial2.begin(115200);
  attachInterrupt(0, compteur, CHANGE);
  timer.setInterval(1000/frequence , vitesse );
  
}

void loop(){
  Serial2.write('2');
  Serial2.write('r');
  Serial2.write('9'); 
  Serial2.write('\r'); 
  timer.run();

}

void compteur(){
  codeuse++;
}

void vitesse(){
  measured_tick = codeuse;
  Serial.println((float)measured_tick/20*(float)frequence);
  codeuse = 0; 
}


#25 Black Templar

Black Templar

    Membre

  • Membres
  • PipPipPipPipPip
  • 1 430 messages
  • Gender:Male
  • Location:Lille

Posté 25 avril 2012 - 06:10

Hello !

J'allais te répondre en début d'après, mais je suis parti bossé sans repasser sur le forum...
Voici mon début de message :


Le problème est le même, quand je mesure nb_tour_par_seconde j'obtiens uniquement les valeurs 0 et 25.


Ok, je viens de comprendre le problème.

Tu as
nb_tour_par_sec = frequence_echantillonnage*nb_ticks/tick_par_tour_codeuse/rapport_reducteur
Tu as rapport_reducteur qui vaut 1, frequence_echantillonage et tick_par_tour_codeuses qui vallent tous les deux 20 !
Ce qui te fait :
nb_tour_par_sec = nb_ticks
En gros, asservir à 1 tour par seconde signifie que ta codeuse doit avoir fait un tick en 20ms. Du coup, des fois la codeuse a fait 1 tick, des fois 0 (vu que ça oscille autour de la consigne)
Pour (peut-être) résoudre le problème, il faudrait prendre une fréquence d'échantillonnage plus faible. Par exemple, du 1Hz te permettrait de comptabiliser 20 ticks de codeuse pour un tour de roue/seconde.


(par contre, ce que je n'ai pas bien compris, c'est pourquoi tu as soit 25, soit 0 quand tu affiches la variable mb_tour_par_sec. Mais quoi qu'il en soit, ça a bien l'air d'être quelque chose de binaire.






Voila pour le message de ce midi.
Ce que tu as dit entre deux confirmes donc un peu ce que j'ai constaté.

il me semble avec mes maigres connaissances qu'il est difficile de mesurer la vitesse avec précision au delà de 4 Hz


La réponse au dessus : parce que en dessous de 4Hz, pour 1tours/seconde, tu n'as que 4 ou 5 ticks !!

++
Black Templar

Mon site internet : http://ferdinandpiette.com/


#26 inovasong

inovasong

    Membre

  • Membres
  • 56 messages

Posté 25 avril 2012 - 06:40

Bon pour résumer,

Avec ce code ci j'utilise une fréquence de 4 j’obtiens ca

1.20
1.20
1.20
1.00
1.00
1.20
1.20
1.20
1.20
1.20
1.00
...

Mais si j'utilise une fréquence de 30 j’obtiens ca

1.50
0.00
1.50
1.50
1.50
1.50
0.00
0.00
1.50
1.50
1.50
1.50
1.50
...


Malgré tes explications je ne comprends pas, plus je diminue la fréquence moins j'ai d'erreurs de mesures



#include <SimpleTimer.h>
SimpleTimer timer;

float codeuse = 0; //nombre ticks
float measured_tick  = 0; //nombre ticks mesuré
int frequence = 4;

void setup(){
  Serial.begin(115200);
  Serial2.begin(115200);
  attachInterrupt(0, compteur, CHANGE);
  timer.setInterval(1000/frequence , vitesse ); // set timer a 1s / par la frequence 
  
}

void loop(){
  Serial2.write('2'); //  selection moteur gauche
  Serial2.write('r'); // sens de rotation
  Serial2.write('2'); // vitesse
  Serial2.write('\r'); // fin de commande 
  timer.run();

}

void compteur(){
  codeuse++;
}

void vitesse(){
  measured_tick = codeuse;
  Serial.println((float)measured_tick/20*(float)frequence); // nbr de ticks a chaque mesures / par le nbr de ticks par tours de roue * fréquence
  codeuse = 0; // réinitialisation pour la prochaine mesure
}


#27 Black Templar

Black Templar

    Membre

  • Membres
  • PipPipPipPipPip
  • 1 430 messages
  • Gender:Male
  • Location:Lille

Posté 25 avril 2012 - 10:21

Salut !

Les résultats me paraissent très bien :)
Petite remarque : réinitialise la variable codeuse AVANT de faire un Serial.println. Car si tu as un tick de codeuse qui se produit pendant l'envoi du message, tu ne le comptabiliseras pas.

Malgré tes explications je ne comprends pas, plus je diminue la fréquence moins j'ai d'erreurs de mesures

Plus tu augmentes la fréquence et moins tu as de tick entre 2 calculs de l'asservissement.
Imagines que tu augmentes la fréquence fortement. Arrivé à un moment, à chaque phase de calcul, la roue n'aura fait que 1 ou 2 ticks (par exemple) !! Du coup, tu es moins précis car avec 1 ou 2 tick, tu ne sais pas si ta roue a parcouru juste 1/20ème de tour ou alors 2,9/20ème. Si en plus tu ramènes ça à la seconde, tu as une erreur potentielle énorme ! Imagine que la fréquence est de 20Hz et que tu ne détecte que 1 ou 2 ticks par période. Tu ne sais pas si ta roue à fait 1 tours, 2 tours ou presque 3 tours par seconde par seconde !
Tu es donc super pas précis... (erreur potentielle de 100% !)

Maintenant, diminue cette fréquence. Pour l'exemple, on prend une fréquence de 1Hz.
Là, imaginons que tu comptabilises 20 ou 21 ticks par période, ça nous fait aussi 20 ou 21 ticks par seconde, soit 1 tour de roue ou 1,05 tour de roue !!
Là, pour le coup, tu es super précis :D (erreur potentielle : 5%)



Moralité : si tu as peu de tick par tour de roue et si le moteur doit faire peu de tour de roue par seconde, il faut réduire la fréquence d'échantillonnage.
ça te permettra d'être plus précis, le moteur sera plus simple à asservir (tu auras moins d'oscillations) mais en contre partie, le moteur se stabilisera en un temps plus important.


++
Black Templar

Mon site internet : http://ferdinandpiette.com/


#28 geek maxou

geek maxou

    Membre chevronné

  • Membres
  • PipPipPipPip
  • 663 messages
  • Gender:Male
  • Location:Pas-de-Calais 62

Posté 26 avril 2012 - 10:45

j'ai une questions avec les encodeurs est ce que le robot peut se déplacer dans une piece sans retourner ou il est déja passer ?
cordialement Maxou

A.R.M.I

Autonomous Robotics Mechanics Intelligent


#29 Black Templar

Black Templar

    Membre

  • Membres
  • PipPipPipPipPip
  • 1 430 messages
  • Gender:Male
  • Location:Lille

Posté 26 avril 2012 - 10:59

Salut !

j'ai une questions avec les encodeurs est ce que le robot peut se déplacer dans une piece sans retourner ou il est déja passer ?


Je ne comprend pas bien ta question.
Les encodeurs servent à connaitre le nombre de tour de roue que tu as fait.
Du coup, avec cette information, tu peux calculer ta position et ton orientation.
Ensuite à l'aide d'algorithmes, tu peux planifier une trajectoire afin que ton robot ne repasse pas deux fois au même endroit.

Les codeuses sont juste un moyen de localisation de ton robot et/ou d'asservissement de tes moteurs.


++
Black Templar

Mon site internet : http://ferdinandpiette.com/


#30 geek maxou

geek maxou

    Membre chevronné

  • Membres
  • PipPipPipPip
  • 663 messages
  • Gender:Male
  • Location:Pas-de-Calais 62

Posté 26 avril 2012 - 11:12

Salut !



Je ne comprend pas bien ta question.
Les encodeurs servent à connaitre le nombre de tour de roue que tu as fait.
Du coup, avec cette information, tu peux calculer ta position et ton orientation.
Ensuite à l'aide d'algorithmes, tu peux planifier une trajectoire afin que ton robot ne repasse pas deux fois au même endroit.

Les codeuses sont juste un moyen de localisation de ton robot et/ou d'asservissement de tes moteurs.


++
Black Templar

merci c'est tous ce que je voulais savoir :)

A.R.M.I

Autonomous Robotics Mechanics Intelligent


#31 inovasong

inovasong

    Membre

  • Membres
  • 56 messages

Posté 26 avril 2012 - 11:54

Avant tous merci Black Templar pour ces explication précises et simple, pour résumer la PID ca marche et ce n’est pas si compliqué que ça. Mais pour faire un asservissement moteur il faut avoir une bonne résolution sur les encodeurs, dans mon cas un asservissement précis et rapide ne sera pas possible (tu m'arête si je dis une bêtise) car seulement 20 ticks par tour d'essieux et seulement 10 vitesses possible sur les moteurs.

Pour rebondir sur la question de geek maxou le but premier de faire un asservissement de vitesse étais de faire avancer mon robot droit mais avec aussi peux de précision, impossible d'avoir des réactions assez rapide sur de petites distances , j'ai avec un autre programme réussi sans problème a déterminer l'angle du robot en degré est il possible a partir de cette information de contraindre le robot a avancer droit et pourquoi pas aussi déterminer (sans grande précision je me doute ) la distance parcouru ?

#32 Mike118

Mike118

    Staff Robot Maker

  • Administrateur
  • PipPipPipPipPip
  • 9 963 messages
  • Gender:Male
  • Location:Anglet

Posté 26 avril 2012 - 12:09

Avant tous merci Black Templar pour ces explication précises et simple, pour résumer la PID ca marche et ce n’est pas si compliqué que ça. Mais pour faire un asservissement moteur il faut avoir une bonne résolution sur les encodeurs, dans mon cas un asservissement précis et rapide ne sera pas possible (tu m'arête si je dis une bêtise) car seulement 20 ticks par tour d'essieux et seulement 10 vitesses possible sur les moteurs.

Pour rebondir sur la question de geek maxou le but premier de faire un asservissement de vitesse étais de faire avancer mon robot droit mais avec aussi peux de précision impossible d'avoir des réactions assez rapide sur de petites distances , j'ai aves un autre programme réussi sans problème a déterminer l'angle du robot en degré est il possible a partir de cette information de contraindre le robot a avancer droit et pourquoi pas aussi déterminer (sans grande précision je me doute ) la distance parcouru ?



Oui c'est possible ;) c'est le principe qui permet de grader un cap si tu vois que tu t'en écarte tu va te remettre droit ^^

un exemple simple : je veux un angle de 0° ( si je tourne vers la gauche mon angle deviens positif si je tourne vers la droite il devient négatif )

si l'angle que je mesure est supérerieur à 0° ( je suis trop à gauche ) j'augment la vitesse de ma roue gauche ( ou je diminue celle de la roue droite ) pour me rapprocher du 0°
inversement si l'angle mesuré est inferieur à 0 j'augment la vitesse de ma roue roue droite ( ou je diminue celle de la roue gauche )

par contre bien regler le gain voir mettre en place un correcteur pour limiter les oscillation ;)

Si mon commentaire vous a plus laissez nous un avis  !  :thank_you:

Nouveau sur Robot Maker ? 

Jetez un oeil aux blogs, aux tutoriels, aux ouvrages, au robotscope  aux articles,  à la boutique  et aux différents services disponible !
En attendant qu'une bibliothèque de fichiers 3D soit mise en place n'hésitez pas à demander si vous avez besoin du fichier 3D d'un des produits de la boutique... On l'a peut être ! 
Si vous souhaitez un robot pilotable par internet n'hésitez pas à visiter www.vigibot.com et à lire le sous forum dédié à vigibot!

 

Les réalisations de Mike118  

 

 

 


#33 Black Templar

Black Templar

    Membre

  • Membres
  • PipPipPipPipPip
  • 1 430 messages
  • Gender:Male
  • Location:Lille

Posté 26 avril 2012 - 12:16

j'ai avec un autre programme réussi sans problème a déterminer l'angle du robot en degré est il possible a partir de cette information de contraindre le robot a avancer droit et pourquoi pas aussi déterminer (sans grande précision je me doute ) la distance parcouru ?


Oui, tu peux tout à fait mettre en place un asservissement (P, PI ou PID), non plus sur la vitesse du moteur, mais sur l'angle. Le principe reste exactement le même. La seule différence réside dans le calcul de l'angle qui ira remplacer le calcul de la vitesse.

Mon site internet : http://ferdinandpiette.com/


#34 inovasong

inovasong

    Membre

  • Membres
  • 56 messages

Posté 26 avril 2012 - 12:42

Parfait alors je me lance dans un PID sur l'angle du robot, la pour le moment j'arrive à mesurer sans problème l'angle et la position du robot avec ce petit code avec la précision qu'on connait c'est à dire 20 tick par tours de roue soit 1 ticks pour 1 cm parcouru.

#include <SimpleTimer.h>

SimpleTimer timer_position; // Timer pour échantillonnage
const int frequence_echantillonnage = 10;
#define LEFT 0
#define RIGHT 1
#define FORWARD 1
#define REVERS 0
long coder[] = {0,0};
long sens_moteur[2] = {FORWARD, FORWARD};
float dalpha = 0;
float ddelta = 0;

void setup(){
  Serial.begin(9600);
  attachInterrupt(LEFT, roueCodeuseL, CHANGE);    //init the interrupt mode for the digital pin 2
  attachInterrupt(RIGHT, roueCodeuseR, CHANGE);   //init the interrupt mode for the digital pin 3
  timer_position.setInterval(1000/frequence_echantillonnage, position_funct);
}

void loop(){
  timer_position.run();
  Serial.print("Rotation: ");
  Serial.print(dalpha);
  Serial.print(" degres - Distance: ");
  Serial.print(ddelta);
  Serial.println(" cm");
}

void position_funct(){
  dalpha = ((float)coder[RIGHT]-(float)coder[LEFT])/14;
  dalpha = 180 * (dalpha) / 3.14159265 ;
  ddelta = ((float)coder[RIGHT]+(float)coder[LEFT])/2;
  
}

void roueCodeuseL()
{
  if (sens_moteur[LEFT] == FORWARD) coder[LEFT] ++;
  else if (sens_moteur[LEFT] == REVERS) coder[LEFT] --;

}
void roueCodeuseR()
{
  if (sens_moteur[RIGHT] == FORWARD) coder[RIGHT] ++;
  else if (sens_moteur[RIGHT] == REVERS) coder[RIGHT] --;
}


#35 Mike118

Mike118

    Staff Robot Maker

  • Administrateur
  • PipPipPipPipPip
  • 9 963 messages
  • Gender:Male
  • Location:Anglet

Posté 26 avril 2012 - 12:45

Parfait alors je me lance dans un PID sur l'angle du robot, la pour le moment j'arrive à mesurer sans problème l'angle et la position du robot avec ce petit code avec la précision qu'on connait c'est à dire 20 tick par tours de roue soit 1 ticks pour 1 cm parcouru.




par contre je te préviens tout de suite je ne peux pas encore t'aider pour la programmation ! je ne fais qu'à peine commencer à apprendre à programmer de mon coté en suivant les tuto du site du 0 ^^

Si mon commentaire vous a plus laissez nous un avis  !  :thank_you:

Nouveau sur Robot Maker ? 

Jetez un oeil aux blogs, aux tutoriels, aux ouvrages, au robotscope  aux articles,  à la boutique  et aux différents services disponible !
En attendant qu'une bibliothèque de fichiers 3D soit mise en place n'hésitez pas à demander si vous avez besoin du fichier 3D d'un des produits de la boutique... On l'a peut être ! 
Si vous souhaitez un robot pilotable par internet n'hésitez pas à visiter www.vigibot.com et à lire le sous forum dédié à vigibot!

 

Les réalisations de Mike118  

 

 

 


#36 inovasong

inovasong

    Membre

  • Membres
  • 56 messages

Posté 26 avril 2012 - 01:00

par contre je te préviens tout de suite je ne peux pas encore t'aider pour la programmation ! je ne fais qu'à peine commencer à apprendre à programmer de mon coté en suivant les tuto du site du 0 ^^


Pas de soucis je devrais m'en sortir merci

#37 inovasong

inovasong

    Membre

  • Membres
  • 56 messages

Posté 26 avril 2012 - 06:17

Voila les premiers résultats à vide (donc roue libre) le système PID fonctionne bien on retrouve bien les caractéristiques de la courbe, pour le moment j'utilise juste un capteur US pour changer l'angle de commande brutalement évidement je pense que quand j'aurais reçu le nouveau contrôleur (j’ai craqué pour un contrôleur PWM) la réponse sera plus rapide et stable, je me trompe ?

Image IPB
Passage de 90° a 0°
Courbe de correction de commande

#38 Black Templar

Black Templar

    Membre

  • Membres
  • PipPipPipPipPip
  • 1 430 messages
  • Gender:Male
  • Location:Lille

Posté 26 avril 2012 - 07:00

Bien joué :D

je pense que quand j'aurais reçu le nouveau contrôleur (j'ai craqué pour un contrôleur PWM) la réponse sera plus rapide et stable, je me trompe ?


Non, je ça ne sera pas plus rapide, juste plus stable.
Pour la rapidité, c'est principalement la résolution des codeuses (d'où l'intérêt d'avoir la codeuse sur l'arbre moteur et non après le réducteur)

Mon site internet : http://ferdinandpiette.com/


#39 inovasong

inovasong

    Membre

  • Membres
  • 56 messages

Posté 29 avril 2012 - 10:26

Bonjour la communauté,

Bon j'ai reçu le nouveau contrôleur et fait mes premier test pas de soucis mais au moment de faire de l'asservissement ca devient catastrophique,
J’ai plusieurs questions à vous poser:

- Quand je fais un asservissement sur l'angle du robot je verrouille l'objectif sans problèmes uniquement aves un système P car si j’introduis le I ou le D la c'est la catastrophe (idem pour l'asserv sur la distance) d'ou viens le problème du code ou de ces foutu roues codeuse ?

- Comment utiliser deux système PID en mm temps car quand j'utilise les deux systèmes la c'est n'import quoi le robot arrive a son objectif mais avec beaucoup de mal.

- Quel moteur et encodeur acheter pour obtenir un système d'asservissement acceptable pour budget de 80 a 100 € (impératif encombrement max avec encodeur est de 5cm par moteurs)?

- avez vous des liens pour me permettre de progresser dans le domaine de l'odométrie car la je rame ?



Voici le code que j'utilise pour le moment.


#include <SimpleTimer.h>

//__________ Definition Broches __________// 

#define IRl_R A0
#define IRl_C A1
#define IRl_L A2
#define IR_R A1
#define IR_L A1
#define US 7
#define BUMP_R 18
#define BUMP_L 19
#define CODER_L 2
#define CODER_R 3
#define V_MOT_R 4
#define V_MOT_L 5
#define SENS_AR_R 30
#define SENS_AV_R 31
#define SENS_AV_L 32
#define SENS_AR_L 33

//__________ Odometrie __________//
#define RIGHT 0
#define LEFT 1
boolean sens_moteur[] = { 
  true , true };
int tick[] = { 
  0 , 0 };
float angle = 0;
float angle_cmd = 0;
float distance = 0;
float distance_cmd = 0;
SimpleTimer timer_asservissement;
float erreur_angle_precedente = angle_cmd;
float somme_erreur_angle = 0;   //
float kp_angle = 8;
float ki_angle = 0;
float kd_angle = 0;
float erreur_distance_precedente = distance_cmd;
float somme_erreur_distance = 0;   //
float kp_distance = 0.06;
float ki_distance = 0;
float kd_distance = 0;

  float V_moteur[] = {0,0};






////////////////////// Setup //////////////////////

void setup(){
  Serial.begin(115200);
  attachInterrupt(LEFT , coder_L, CHANGE); // interuption broche 2
  attachInterrupt(RIGHT , coder_R , CHANGE); // interuption broche 3
  timer_asservissement.setInterval(1000/200, asservissement);
  pinMode(BUMP_R, INPUT);
  pinMode(BUMP_L, INPUT);
}

////////////////////// Loop //////////////////////

void loop(){




  timer_asservissement.run();

}

////////////////////// Fonctions //////////////////////





// Fonction Codeur
void coder_L(){
  if (sens_moteur[LEFT]) tick[LEFT]++;
  else if (!sens_moteur[LEFT]) tick[LEFT]--;
}
void coder_R(){
  if (sens_moteur[RIGHT]) tick[RIGHT]++;
  else if (!sens_moteur[RIGHT]) tick[RIGHT]--;
}

// Commande moteur Gauche
void moteur_L(int V){
  if (V>0 && V<=255){
   sens_moteur[LEFT] = true;
    digitalWrite(SENS_AR_L, LOW);
    digitalWrite(SENS_AV_L, HIGH);
  }
  else if (V<0 && V>=-255){
    sens_moteur[LEFT] = false;
    digitalWrite(SENS_AR_L, HIGH);
    digitalWrite(SENS_AV_L, LOW);
    V = V * -1;
  }
  else {
    digitalWrite(SENS_AR_L, LOW);
    digitalWrite(SENS_AV_L, LOW);
  }
  analogWrite(V_MOT_L, V);
}

// Commande moteur Droite
void moteur_R(int V){
  if (V>0 && V<=255){
    sens_moteur[RIGHT] = true;
    digitalWrite(SENS_AR_R, LOW);
    digitalWrite(SENS_AV_R, HIGH);
  }
  else if (V<0 && V>=-255){
    sens_moteur[RIGHT] = false;
    digitalWrite(SENS_AR_R, HIGH);
    digitalWrite(SENS_AV_R, LOW);
    V = V * -1;
  }
  else {
    digitalWrite(SENS_AR_R, LOW);
    digitalWrite(SENS_AV_R, LOW);
  }
  analogWrite(V_MOT_R, V);
}


void asservissement(){

  
  if (!digitalRead(BUMP_R)){
    angle_cmd = (-90*PI)/180;
    distance_cmd = 20;
  }
if (!digitalRead(BUMP_L)){
    angle_cmd = 0;
    distance_cmd = 0;
  }
  angle = ((float)tick[LEFT]-(float)tick[RIGHT])/13.6;
//  angle = 180 * (angle) / 3.14 ;
  distance = ((float)tick[RIGHT]+(float)tick[LEFT])/2;

  float erreur_distance = distance_cmd - distance;
  somme_erreur_distance += erreur_distance;
  float delta_erreur_distance = erreur_distance - erreur_distance_precedente;
  erreur_distance_precedente = erreur_distance;
   float nouvel_cmd_distance = kp_distance*erreur_distance + ki_distance*somme_erreur_distance + kd_distance*delta_erreur_distance;
  
  float erreur_angle = angle_cmd - angle;
  somme_erreur_angle += erreur_angle;
  float delta_erreur_angle = erreur_angle-erreur_angle_precedente;
  erreur_angle_precedente = erreur_angle;
   float nouvel_cmd_angle = kp_angle*erreur_angle + ki_angle*somme_erreur_angle + kd_angle*delta_erreur_angle;
  
//    if (nouvel_cmd_distance > 0){
//      
//   V_moteur[LEFT] =V_moteur[LEFT]+ nouvel_cmd_distance;
//   V_moteur[RIGHT] =V_moteur[RIGHT]+ nouvel_cmd_distance;
//   if (V_moteur[LEFT] > 50) V_moteur[LEFT]=50;
//   if (V_moteur[RIGHT] > 50) V_moteur[RIGHT]=50;
// 
//
//  }
//      if (nouvel_cmd_distance < 0){
//   V_moteur[LEFT] = V_moteur[LEFT]+ nouvel_cmd_distance;
//   V_moteur[RIGHT] = V_moteur[RIGHT]+ nouvel_cmd_distance;
//   if (V_moteur[LEFT] < -50) V_moteur[LEFT]= -50;
//   if (V_moteur[RIGHT] < -50) V_moteur[RIGHT]= -50;
//  }
//  
  
  if (nouvel_cmd_angle > 0){
   V_moteur[LEFT] =V_moteur[LEFT]+ nouvel_cmd_angle;
   V_moteur[RIGHT] =V_moteur[RIGHT]- nouvel_cmd_angle;
   if (V_moteur[LEFT] > 50) V_moteur[LEFT]=50;
   if (V_moteur[RIGHT] < -50) V_moteur[RIGHT]=-50;
  }
  if (nouvel_cmd_angle < 0 ){
    nouvel_cmd_angle = nouvel_cmd_angle*-1;
    V_moteur[RIGHT] =V_moteur[RIGHT]+ nouvel_cmd_angle;
    V_moteur[LEFT] =V_moteur[LEFT]- nouvel_cmd_angle;
    if (V_moteur[RIGHT] > 50) V_moteur[RIGHT]=50;
    if (V_moteur[LEFT] < -50) V_moteur[LEFT]=-50;
  }
//  if (V_moteur[LEFT] >-5 && V_moteur[LEFT] < 5) V_moteur[LEFT] = 0;
//  if (V_moteur[RIGHT] >-5 && V_moteur[RIGHT] < 5) V_moteur[RIGHT] = 0;
//  
//  Serial.print("distance = ");
//  Serial.print(distance);
//  Serial.print(" correction = ");
//  Serial.print(nouvel_cmd_distance);
//  Serial.print(" Distance cmd = ");
//  Serial.println(distance_cmd);
Serial.println(V_moteur[LEFT]);
  moteur_L(V_moteur[LEFT]);
  moteur_R(V_moteur[RIGHT]);


}






#40 Black Templar

Black Templar

    Membre

  • Membres
  • PipPipPipPipPip
  • 1 430 messages
  • Gender:Male
  • Location:Lille

Posté 29 avril 2012 - 12:43

Bonjour la communauté,

Bon j'ai reçu le nouveau contrôleur et fait mes premier test pas de soucis mais au moment de faire de l'asservissement ca devient catastrophique,
J’ai plusieurs questions à vous poser:

- Quand je fais un asservissement sur l'angle du robot je verrouille l'objectif sans problèmes uniquement aves un système P car si j’introduis le I ou le D la c'est la catastrophe (idem pour l'asserv sur la distance) d'ou viens le problème du code ou de ces foutu roues codeuse ?

- Comment utiliser deux système PID en mm temps car quand j'utilise les deux systèmes la c'est n'import quoi le robot arrive a son objectif mais avec beaucoup de mal.

- avez vous des liens pour me permettre de progresser dans le domaine de l'odométrie car la je rame ?


Salut !

Alors le premier problème qui me vient à l'esprit en regardant ton code, c'est la fréquence d'échantillonnage !
Il faut t'assurer que ta fonction asservissement s'exécute bien plus rapidement que la fréquence à laquelle elle est appelé !
J'ai eu quelques problèmes avec Arduino, je n'ai pas réussi à dépassé des fréquences de 80Hz.
Pour tester cette hypothèse, il te faut allumer une LED au démarrage de la fonction asservissement et l'éteindre à la fin. Ensuite, il te suffit de visualiser à l'aide d'un oscillo la PWM généré : la fréquence te donne la fréquence réelle d'échantillonnage et le rapport cyclique, le temps que prend la fonction à s'exécuter...
C'est là qu'on voit les limitation d'Arduino...


Si tu veux exécuter deux asservissements en même temps, il faut faire attention que le temps d’exécution des 2 fonctions soit inférieur à la période d'échantillonnage !


Si tu changes les fréquences d'échantillonnage, fait attention, car du coup, tes coefficients I et D changent par la même occasion.

Pour l'odométrie, ce site est bien foutu : http://clubelek.insa-lyon.fr/joomla/fr/base_de_connaissances/informatique/asservissement_et_pilotage_de_robot_auto_2.php


++
Black Templar

Mon site internet : http://ferdinandpiette.com/




Répondre à ce sujet



  


0 utilisateur(s) li(sen)t ce sujet

0 members, 0 guests, 0 anonymous users