Asservissement position

Bonsoir tout le monde !

Dans le but d’un TIPE, je souhaiterai réaliser un pendule inversé. Le but étant de faire tenir un pendule à la verticale vers le haut via un asservissement en position
Je dispose pour cela d’un capteur angulaire et d’un linéaire, et d’une imprimante (+ carte arduino, shield et alim externe de 32V)

Le chariot de mon imprimante se déplace sur un axe d’une quarantaine de centimètres et je souhaiterai pouvoir le déplacer d’une distance précise. Le capteur mesure en nombre de jour/nuit, il y en a 3100 au total sur toute la course du chariot. Je met mon chariot avant la lancée du programme, et je souhaiterai qu’il se déplace de 500 positions par exemple

J’ai donc d’abord réalisé un asservissement proportionnel, mais selon la vitesse donnée, je me retrouve un peu plus loin ou beaucoup plus loin (si je met une pwm de 255, je me retrouve a quasiment 1000 pour une consigne de 500, et si je met 100 en pwm, je me retrouve vers les 580).

J’ai donc tenté de réaliser un Proportionnel Intégral Dérivé, mais j’ai plusieurs problèmes. Le fait est que quelques soient les gains K, Ki, Kd (proportionnel, intégral et dérivé respectivement), je me retrouve avec mon chariot qui oscille indéfiniement autour de ma position demandée

Je précise que je suis assez novice sur Arduino (je code en python au lycée, et j’apprend au fur et a mesure de mon projet Arduino)

int pwm_b = 9;  //PWM pour le moteur
int dir_b = 8;  //Direction (sens) du moteur

const int clkPinA=2;
const int dirPinA=4;
volatile int encoderAcount_lineaire = 0;
volatile boolean changeFlag=false;

const float K=10; //Constante gain proportionnel
const float Ki=5; //Constante gain intégral
const float Kd=20; //Constante gain dérivé
int pos_1; 
int pos_2;

int dt=10; //On définit la variable de temps

void setup()
{
  Serial.begin(9600);
  pinMode(clkPinA,INPUT);
  pinMode(dirPinA,INPUT);
  attachInterrupt(0,encoderIntA, RISING);
  
  pinMode(pwm_b, OUTPUT);
  pinMode(dir_b, OUTPUT);
  
  analogWrite(pwm_b, 0);
  
}
  
void loop()
{
  
  if (changeFlag){
    changeFlag=false;
    //Serial.println(encoderAcount_lineaire);
  }
  //dt=millis(); //On initialise le temps à 0 ici

  pos_1=0;
  pos_2=5;
  
  while((pos_2-pos_1)!=0){
    
    pos_1=pos_2;
    if (pos_1<500){
      digitalWrite(dir_b,HIGH);
    }
    else if (pos_1>500){
      digitalWrite(dir_b,LOW);
    }
    pos_2=encoderAcount_lineaire;
    //dt=(millis()-dt);
    analogWrite(pwm_b,min(255,K*pos_1 + Ki*(pos_2-pos_1)*dt + Kd*(pos_2-pos_1)/dt));
    Serial.println(encoderAcount_lineaire);
    Serial.print("diff : ");
    Serial.println(pos_2-pos_1);    
  }
  analogWrite(pwm_b,0);
}

void encoderIntA(){
  if (digitalRead(dirPinA) == HIGH)
    encoderAcount_lineaire++;
  else
  encoderAcount_lineaire--;
  changeFlag=true;
}

Voilà, les boucles pour lire les valeurs de codeurs ont été simplement copiées collées, elles fonctionnent très bien ^^

Donc un de mes problèmes (comme on le voit sur le script) est de savoir comment gérer ma notion de temps. Soit je prend des intervalles réguliers comme ici, soit j’utilise le “millis()” pour prendre les intervalles de temps correspondants aux intervalles entre les mesures de positions
Autre problème, c’est le lancement de ma boucle. Je savais pas trop comment la lancer, donc j’ai pris deux valeurs de positions distintes (0 et 10), et tant que l’écart entre ces deux valeurs n’est pas nul, je rentre dans la boucle (le problème vient probablement d’ici, mais comment gérer ca ?)

Voilà, merci beaucoup de l’aide apportée, j’en suis très reconnaissant
Bonne soirée tout le monde :slight_smile:

Bonsoir Julo, tout d’abord, c'est pas un sujet facile, la régulation/asservissement c'est niveau bac +2/+3

Pourquoi n'as tu pas utiliser la librairie PID, elle fonctionne très bien; au niveau sortie PID tu gère comme ça: entre 0 et 127 => sens 1 entre 128 et 255 => sens 2 et tu recalcule la vitesse comme ça: si sens 1 : vitesse = sortiePID*2 si sens 2 : vitesse = (sortiePID-128)*2

pour l'échantillonnage tu as le SetSampleTime()

Il existe même une librairie Auto-tune, qui permet de déterminer tes actions.... enfin sur le genre de système, ça risque d’être galère.

Bon courage pour la suite

Salut ! Oui je suis en BAC+2 (en deuxième année de prépa scientifique, Physique Science de l'Ingénieur)

Pour ce que tu m'as dis, c'est du tout ou rien non ?

Je vais jeter un coup d'oeil à la librairie que tu m'as indiquée :)

Je viens de remarquer que j'avais pas précisé. Mais pour le moment le but du programme que je vous ai donné est de faire une Prise Origine Machine en faite. Je me met en butée au début, le chariot se place au centre, et il sait que c'est le centre

Bonjour, au début je pensais que tu était en bac.... enfin bref

non la régulation que je te propose est une régulation a double sens: -si sortie régulateur PID :entre 0 et 127 (soit entre 0 et 50%) => sens 1, avec comme sortie pwm= (sortie régulateur PID*2), (soit variable de 0 à 254)

-si sortie regulateur PID :entre 128 et 255 (soit entre 50 et 100%) => sens 2, avec comme sortie pwm=(sortie régulateur PID-128)*2 , (soit variable de 0 à 254)

Pour info je suis titulaire d'un BTS CIRA et d'une licence SARI, donc n’hésite pas à demander.

D'accord, merci pour ton aide qui va m'être très précieuse ^^

Ce que tu appelles régulateur PID, c'est la variable qui sort de la fonction PID (de la librairie arduino donc ?)

Ce que tu appelles régulateur PID, c'est la variable qui sort de la fonction PID

oui c'est tout à fait ça !

après pour attaquer la sortie pwm, il a quelques modif a faire dessus, comme je te l'ai présenté.

Ok, je regarde d’abord les exemples de base que propose Arduino pour cette librairie. Je suis la dessus :

/********************************************************
 * PID Basic Example
 * Reading analog input 0 to control analog PWM output 3
 ********************************************************/

#include <PID_v1.h>

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

void setup()
{
  //initialize the variables we're linked to
  Input = analogRead(0);
  Setpoint = 100;

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop()
{
  Input = analogRead(0);
  myPID.Compute();
  analogWrite(3,Output);
}

Dans mon cas, “Input”, c’est ma position lineaire (que je dois définir avant comme “double pos;” par exemple c’est bien cela ? Ensuite “Output”, c’est ma vitesse, donc pareil “double vitesse;” si j’avais compris pour celle d’avant ^^. Setpoint c’est la constante cible “double Setpoint = 500.00”, mes gains je met ce que je veux, positifs

Je me retrouve avec des affectations initiales de

double K=20; //Constante gain proportionnel
double Ki=30; //Constante gain intégral
double Kd=50; //Constante gain dérivé
double pos;
double vitesse;
double setpoint;
PID myPID(&pos,&vitesse,&setpoint, K, Ki,Kd, DIRECT);

Et je n’ai pas bien compris la fin. Le “Input = analogRead(0);” correspond à ma valeur de capteur dans mon cas ? Pour moi c’est donc “pos=encoderAccount_lineaire”
Et “analogWrite(3,Output);”, je n’ai pas compris. 3 c’est le pin où est branché mon moteur, dans mon cas je suis sur le 9 (j’ai bien “int pwm_b = 9;” dans mes affectations de départ), et Output est la valeur qui sort de la fonction PID c’est bien celà ?

Oui input correspond à la position linéaire (attention aux échelles) elle doit être identique à setpoint.

Concernant , Output tu peux pas l'utiliser sur ta sortie pwm directement,

D'accord, il faut que je l'utilise comment ?

Pour commencer il faudrait définir les valeur pleines échelles, mesures, consigne.

Le sens de ton régulateur DIRECT, INVERSE ?

J'ai un doute sur le fonctionnement correct de la librairie PID avec des consignes négatives, comme tu me l'a évoquer en MP.

Post réglé, un énorme merci a ptitnitro62000 qui m'a fait une bonne part du boulot

Bonjour,

Je fais un projet similaire (pendule inversé TIPE) mais en equilibre sur deux roues. J'ai un probleme avec l'utilisation de la librairie PID avec une consigne négative, apparament vous avez résolu le problème!

la consigne input de PID doit elle être comprise dans un intervalle particulier (0-255) ou peut elle prendre n'importe quelle valeur ?

Merci d'avance