Programme asservissement en position d'un chariot

Bonjour, j'aimerai réaliser un programme permettant l'asservissement en position d'un chariot grace à un moteur à CC disposant d'un codeur incrémental et d'un système poulie-courroie.

// Ce code a pour but d'asservir en position le chariot sur le rail

#include<SimpleTimer.h>
SimpleTimer timer; //Timer pour échantillonage
const int Frequence_Echantillonage = 100; //Fréquence d'exécution de l'asservissement

//Définition des entrées

const int DIR_IN1 = 9; //Commande direction sens rotation 1 moteur
const int DIR_IN2 = 8; //Commande direction sens rotation 2 moteur
const int PWM = 7; //Commande vitesse du moteur
const int PIN_A_ENCODEUR = 2;
const int PIN_B_ENCODEUR = 3;

//---------------------------------------------------------
//                 Initialisation
//---------------------------------------------------------

//Initialisation compteur

int Encodeur0Pos = 0; //Position de départ
int Encodeur0Pos_Precedente = 0;
boolean A_set = false;
boolean B_set = false;
unsigned int time = 0;
long debut = 0;

//Initialisation moteur

int Rapport_Reduction = 1 / 131;
int Rayon_Poulie = 15.93e-3;
int Resolution = 16; //Nombre de tickks par tour du moteur

//Initialisation paramètres de l'asservissement

float Consigne_en_m = 0.05;
float Angle_Consigne = Consigne_en_m * (1 / (Rapport_Reduction*Rayon_Poulie));
float Angle_Mesure;
float Epsilon = Angle_Consigne;
float Epsilon_ini;
int Rapport_Cyclique;
float Moyenne_Epsilon;
float Delta_Epsilon = 0.1; //Critere d'arret du moteur

//Initialisation parametres boucle while

int Compteur;
float Somme;

//--------------------------------------------------------
//                  Routine d'utilisation
//--------------------------------------------------------

void setup() {

  Serial.begin(9600);
  pinMode(PWM, OUTPUT); //Sortie commande moteur
  pinMode(DIR_IN1, OUTPUT);
  pinMode(DIR_IN2, OUTPUT);
  pinMode(PIN_A_ENCODEUR, INPUT); //Sortie encodeur
  pinMode(PIN_B_ENCODEUR, INPUT);

  digitalWrite(PIN_A_ENCODEUR, HIGH); //Resistance interne arduino ON
  digitalWrite(PIN_B_ENCODEUR, HIGH); //Resistance interne arduino ON

  attachInterrupt(0, doEncoderA, RISING); //Interruption de l'encodeur A en sortie 0 (pin 2)
  attachInterrupt(1, doEncoderB, RISING); //Interruption de l'encodeur B en sortie 1 (pin 3)

}

//----------------------------------------------------------
//              Fonction principale
//----------------------------------------------------------

void loop() {

  Compteur = 0;
  Somme = 0;
  Angle_Mesure = Encodeur0Pos * ((2 * PI) / 16);
  Epsilon_ini = Angle_Mesure + Angle_Consigne;
  Moyenne_Epsilon = Angle_Consigne;
  Serial.println(Moyenne_Epsilon);
  while (Moyenne_Epsilon >= Delta_Epsilon) {
    Angle_Mesure = Encodeur0Pos * ((2 * PI) / 16);
    Epsilon = Epsilon_ini - Angle_Mesure;
    Rapport_Cyclique = (abs(Epsilon) * 255) / Angle_Consigne;
    Somme = Somme + Epsilon;
    Compteur = Compteur + 1;
    if (Epsilon > 0) {
      digitalWrite(DIR_IN1, LOW);
      digitalWrite(DIR_IN2, HIGH);
      analogWrite(PWM, Rapport_Cyclique);
    }
    if (Epsilon <= 0) {
      digitalWrite(DIR_IN1, HIGH);
      digitalWrite(DIR_IN2, LOW);
      analogWrite(PWM, -Rapport_Cyclique);
    }
    if (Compteur == 100) {
      Moyenne_Epsilon = Somme / 100;
      Compteur = 0;
      Somme = 0;
    }
    Serial.println(String(millis()) + ';' + String((Angle_Mesure * (Rapport_Reduction * Rayon_Poulie))));
  }

}

//-----------------------------------------------------------
//              Routine incrementation des codeurs A et B
//-----------------------------------------------------------

void doEncoderA() {

  B_set = digitalRead(PIN_B_ENCODEUR) == HIGH;
  if (B_set) {
    Encodeur0Pos = Encodeur0Pos + 1;
  }
  else {
    Encodeur0Pos = Encodeur0Pos - 1;
  }

}

void doEncoderB() {

  A_set = digitalRead(PIN_A_ENCODEUR) == HIGH;
  if (A_set) {
    Encodeur0Pos = Encodeur0Pos - 1;
  }
  else {
    Encodeur0Pos = Encodeur0Pos + 1;
  }

}

Cependant quand je l'exécute rien ne s'affiche dans le shell, je ne comprends pas d'ou vient le problème... Si vous pouvez m'aider je vous remercie d'avance, bonne soirée à vous

les variables qui sont utilisées dans les ISR doivent être déclarées volatiles

volatile int Encodeur0Pos = 0; //Position de départ
volatile boolean A_set = false;
volatile boolean B_set = false;

dans la loop vous devriez travailler sur une copie de Encodeur0Pos effectuée en zone critique

void loop() {
  int Encodeur0PosCopie;

  noInterrupts();
  Encodeur0PosCopie = Encodeur0Pos;
  interrupts();

...

car les octets peuvent être modifiés pendant que vous faites des maths dessus.

Attention un int ça ne compte pas très loin. Prenez peut-être un long

// Ce code a pour but d'asservir en position le chariot sur le rail

#include<SimpleTimer.h>
SimpleTimer timer; //Timer pour échantillonage
const int Frequence_Echantillonage = 100; //Fréquence d'exécution de l'asservissement

//Définition des entrées

const int DIR_IN1 = 9; //Commande direction sens rotation 1 moteur
const int DIR_IN2 = 8; //Commande direction sens rotation 2 moteur
const int PWM = 7; //Commande vitesse du moteur
const int PIN_A_ENCODEUR = 2;
const int PIN_B_ENCODEUR = 3;

//---------------------------------------------------------
//                 Initialisation
//---------------------------------------------------------

//Initialisation compteur

volatile int Encodeur0Pos = 0; //Position de départ
volatile int Encodeur0Pos_Precedente = 0;
volatile boolean A_set = false;
volatile boolean B_set = false;
unsigned int time = 0;
long debut = 0;

//Initialisation moteur

int Rapport_Reduction = 1 / 131;
int Rayon_Poulie = 15.93e-3;
int Resolution = 16; //Nombre de tickks par tour du moteur

//Initialisation paramètres de l'asservissement

float Consigne_en_m = 0.05;
float Angle_Consigne = Consigne_en_m * (1 / (Rapport_Reduction*Rayon_Poulie));
float Angle_Mesure;
float Epsilon = Angle_Consigne;
float Epsilon_ini;
int Rapport_Cyclique;
float Moyenne_Epsilon;
float Delta_Epsilon = 0.1; //Critere d'arret du moteur

//Initialisation parametres boucle while

int Compteur;
float Somme;

//--------------------------------------------------------
//                  Routine d'utilisation
//--------------------------------------------------------

void setup() {

  Serial.begin(9600);
  pinMode(PWM, OUTPUT); //Sortie commande moteur
  pinMode(DIR_IN1, OUTPUT);
  pinMode(DIR_IN2, OUTPUT);
  pinMode(PIN_A_ENCODEUR, INPUT); //Sortie encodeur
  pinMode(PIN_B_ENCODEUR, INPUT);

  digitalWrite(PIN_A_ENCODEUR, HIGH); //Resistance interne arduino ON
  digitalWrite(PIN_B_ENCODEUR, HIGH); //Resistance interne arduino ON

  attachInterrupt(0, doEncoderA, RISING); //Interruption de l'encodeur A en sortie 0 (pin 2)
  attachInterrupt(1, doEncoderB, RISING); //Interruption de l'encodeur B en sortie 1 (pin 3)

}

//----------------------------------------------------------
//              Fonction principale
//----------------------------------------------------------

void loop() {

  int Encodeur0PosCopie;
  noInterrupts();
  Encodeur0PosCopie = Encodeur0Pos;
  interrupts();
  Compteur = 0;
  Somme = 0;
  Angle_Mesure = Encodeur0Pos * ((2 * PI) / 16);
  Epsilon_ini = Angle_Mesure + Angle_Consigne;
  Moyenne_Epsilon = Angle_Consigne;
  while (Moyenne_Epsilon >= Delta_Epsilon) {
    Angle_Mesure = Encodeur0Pos * ((2 * PI) / 16);
    Epsilon = Epsilon_ini - Angle_Mesure;
    Rapport_Cyclique = (abs(Epsilon) * 255) / Angle_Consigne;
    Somme = Somme + Epsilon;
    Compteur = Compteur + 1;
    if (Epsilon > 0) {
      digitalWrite(DIR_IN1, LOW);
      digitalWrite(DIR_IN2, HIGH);
      analogWrite(PWM, Rapport_Cyclique);
    }
    if (Epsilon <= 0) {
      digitalWrite(DIR_IN1, HIGH);
      digitalWrite(DIR_IN2, LOW);
      analogWrite(PWM, -Rapport_Cyclique);
    }
    if (Compteur == 100) {
      Moyenne_Epsilon = Somme / 100;
      Compteur = 0;
      Somme = 0;
    }
    Serial.println(String(millis()) + ';' + String((Angle_Mesure * (Rapport_Reduction * Rayon_Poulie))));
  }

}

//-----------------------------------------------------------
//              Routine incrementation des codeurs A et B
//-----------------------------------------------------------

void doEncoderA() {

  B_set = digitalRead(PIN_B_ENCODEUR) == HIGH;
  if (B_set) {
    Encodeur0Pos = Encodeur0Pos + 1;
  }
  else {
    Encodeur0Pos = Encodeur0Pos - 1;
  }

}

void doEncoderB() {

  A_set = digitalRead(PIN_A_ENCODEUR) == HIGH;
  if (A_set) {
    Encodeur0Pos = Encodeur0Pos - 1;
  }
  else {
    Encodeur0Pos = Encodeur0Pos + 1;
  }

}

J'ai donc changé la partie du code comme vous l'avez conseillé mais rien ne se passe. Rien ne s'affiche dans le shell même quand je lui demande par exemple de print l'angle consigne

quel shell?

vous avez bien rajouté la copie (Encodeur0PosCopie) mais vous continuez d'utiliser Encodeur0Posdans les calculs de la loop... A quoi sert la copie selon vous ?...

ensuite je n'ai pas lu le code en entier, vous n'avez pas décrit le montage exactement, je ne sais pas où vous regardez l'affichage, etc... Il peut donc y avoir 2000 sources de soucis.

faites un code simple qui affiche simplement dans la loop le compteur (la copie) à chaque fois qu'il change. Vous aurez bien le temps de rajouter tout le reste plus tard

Je fais référence à ce shell là.

Quand au montage, il est composé d'une carte arduino mega, un hacheur L298N, d'un MCC avec le codeur incremental qui est relié au chariot par un système de poulie, courroie.

Si vous le souhaitez je peux vous donner plus d'informations en privé par téléphone ou visio ça sera plus simple sûrement si vous avez de temps.

Non postez tous les détails ici que ça profite à tous

Le Shell s’appelle le moniteur série :wink:

Pourquoi ajouter == HIGH ?

Parce que c’est sémantiquement correct de mettre un résultat booléen dans une variable booléenne plutôt que de dépendre d’effet de bords sur le fait que vous savez que HIGH vaut 1 et que le compilateur fera la promotion automatique en true.

Mais il n'y a pas de comparaison, alors ce n'est pas requis . Je comprend que le compilateur vas remplacé HIGH par 1 mais je ne vois pas la nécessité d'ajouter == HIGH?

digitalRead Retourne un entier

Il met dans la variable B_set qui est de type Boolean (valeur de vérité) le résultat de la comparaison (test d’égalité qui rend une valeur de vérité) (digitalRead(PIN_B_ENCODEUR) == HIGH)

C’est cohérent et sémantiquement correct et indépendant de la valeur arbitraire de HIGH.

Je lis ceci dans le code:

pour moi Rapport_Reduction et Rayon_Poulie valent donc 0 et je ne souviens plus ce qui se passe quand on fait une division par 0 dans

float Angle_Consigne = Consigne_en_m * (1 / (Rapport_Reduction*Rayon_Poulie));

Il me semble que cela fait -1 mais je n'en suis pas sûr. Mais si c'est cela, Moyenne epsilon vaut -1 et le while n'est jamais exécuté; il n'y aura pas d'affichage. Jamais.

Pour moi, il y a plein de variables dont je ne connais pas l'utilité. Le code m'est obscur, et souvent comme c'est ainsi, je passe mon chemin, ou j'attends que les choses éclaircissent. Pour avoir plus de réponses, il vaut mieux expliquer ce que l'on fait. Si moyenne_Epsilon est clair pour vous, je ne sais pas ce que cela représente.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.