PID moteur dc pour levier articulé

Bonjour,

je commence la programmation avec Arduino et me lance dans un premier projet.

Je souhaite commander un bras sur pivot, permettant l'ouverture précise d'une vanne suivant la demande d'un opérateur.
L'ensemble sera équipé d'un système de recopie pour obtenir une correction de la position par PID.
Un interrupteur devra permettre d'ouvrir la vanne à 90° soit 100% pendant un temps donné.

Je dispose donc:

  • d'un moteur électrique 12V avec réducteur à pignons
  • d'un module de commande avec pont en H
  • d'un potentiomètre 90° pour la commande
  • d'un potentiomètre de recopie identique à celui de commande
  • d'un interrupteur permettant d'outrepasser les autres conditions et d'ouvrir la vanne en grand
  • d'un Arduino méga et du nécessaire de câblage

Voilà le code sur lequel je travail et a propos duquel je souhaiterai un avis avant essai:

Merci d'avance pour le retour d'informations, au plaisir de vous lire

int outputValue = 5;

int DIRA = 3;
int DIRB = 4;

float analogPin = A0;
float analogPin2 = A1;

int shift = 8;

float valec;
float valrec; 
float erreur;
float errprec;
float deltaerr;
float sommerr;
float pilotage;
float commande;
float correction;

  
void setup() 
{

Serial.begin (9600);
  pinMode(outputValue,OUTPUT);
  pinMode(DIRA,OUTPUT);
  pinMode(DIRB,OUTPUT);
  pinMode(analogPin,INPUT);
  pinMode(analogPin2,INPUT);
  pinMode (shift, INPUT_PULLUP);

  valec=0;
  valrec=0;
  erreur=0;
  errprec=0;
  deltaerr=0;
  sommerr=0;
  pilotage=0;
  commande=0;
  correction=0;
  
}

void loop() 
  
{
  digitalWrite(DIRA,LOW);
  digitalWrite(DIRB,HIGH); 
  valec = analogRead (analogPin);
  valrec = analogRead (analogPin2);
  
erreur = valec - valrec;
sommerr += erreur;
deltaerr = erreur - errprec;
errprec = erreur;
  
  analogWrite(outputValue,pilotage);
  commande = map (analogPin,0,1023,0,255);



 if (erreur == 0)
 {
  pilotage = commande;
}

 
 if (erreur > 0)
 {
 correction = (3*(erreur)) + (2*(sommerr)) + (5*(deltaerr));
 pilotage = commande + correction;
   analogWrite (outputValue,pilotage); 
 }


if (erreur < 0)
 {
 correction = (0.01*(erreur)) + (0.02*(sommerr)) + (0.03*(deltaerr));
 pilotage = commande - correction;
   analogWrite (outputValue,pilotage); 
 }


 if (digitalRead (shift) == 0)
 {
  analogWrite (outputValue,255);
  delay (500);
  analogWrite (outputValue,pilotage); 
}
 
}

premier avis: vous n'avez pas lu les règles du forum... faites le et corrigez le post ci dessus...

sinon ce truc là ne sent pas très bon :slight_smile:  commande = map (analogPin,0,1023,0,255);(vous avez eu la bonne idée d'appeler les N° de pins par un petit nom, ça devrait vous mettre la puce à l'oreille...)

Ok c'est fait, désolé…

J'ai oublié de précisé que le rappel du mécanisme est assuré par un ressort spirale ce qui explique l'unidirectionnalité de la commande…

…mais ce n'était surement pas ça que tu voulais souligné en citant la fonction:

commande = map (analogPin,0,1023,0,255);

je pense aussi pouvoir simplifier le code par:

 if (erreur != 0)
 {
 correction = (3*(erreur)) + (2*(sommerr)) + (5*(deltaerr));
 pilotage = commande + correction;
   analogWrite (outputValue,pilotage); 
 }

je suis vraiment débutant, il y a peut être des "absurdités" ou non sens dans mon code...

Merci d’avoir utilisé les Balises. Pas la peine de vous excuser, on a tous commencé par là :slight_smile:

Dans ce codecommande = map (analogPin,0,1023,0,255);combien vaut analogPin ? Êtes vous bien sûr que c’est ce que vous voulez « mapper » ?

Petit indice:

float analogPin = A0;
....
valec = analogRead (analogPin);

====

Donc pour avancer un peu

  • Un numéro de pin se déclare sous forme d’un nombre entier positif constant tenant sur un octet (type byte ou plus standard uint8_t)const uint8_t analogPin = A0;le N° de pin ne va pas changer, la tension sur cette pin, éventuellement...

  • la représentation numérique de la tension sur cette pin à un instant est obtenue en appelant digitalRead() ou analogRead()

Donc....

Ok je vais corriger ça et essayer d'avancer.

Merci

Bonjour,
suivant votre conseil, j'ai modifié le code tel que:

//affectation des pins aux entrées et sorties
const uint8_t  outputValue = 5;

const uint8_t  DIRA = 3;
const uint8_t  DIRB = 4;

const uint8_t analogPin = A0;
const uint8_t analogPin2 = A1;

const uint8_t  shift = 8;

et:

 commande = map (valec,0,1023,0,255);

comprenant que, la première partie du code servant à affecter les pins aux entrées et sorties,
il est nécessaire de les déclarer:

  • en "const" car de fait et correspondant au branchement, ça ne varie pas
  • en "int"car les numéros de pins sont entiers...
  • sur 8bits pour prendre moins de place qu'un simple "int" qui est sur 16bits

Pour la fonction "map" c'est "valec" qui varie de 0 à 1023 et effectivement pas "analogPin" qui est le nom que j'ai donné à mon entrée.

Qu'il n'y a "que" lors de la déclaration des variables qu'il faut les "typer" (int, float, char, …) suivant le type de variable attendu.

Je suis sur la bonne route?

Merci encore pour votre aide.

Vous êtes tout à fait sur la bonne route pour la compréhension des déclarations des types et l'usage de map() ! bravo

idéalement trouvez un autre nom que analogPin et analogPin2 pour le nom des variables. Qu'est-ce qui est connecté au bout des pins ? est-ce que ce sont les potentiomètres ? si oui par exemple vous pourriez les appeler pinPotentiometreCommande et pinPotentiometreRecopie, ce serait plus parlant ensuite dans le code.

de même DIRA et DIRB sont des pins, donc autant mettre pin dans le nom de la constante et A et B ça n'est pas parlant. si ça pilote quelque chose de particulier autant le mettre dans le nom de la variable, le fait que ce soit connecté sur A ou B peut être mis en commentaire pour documentation (je dis n'importe quoi mais c'est pour l'exemple);

const uint8_t  pinDirectionFermeture = 3; // connecté sur port A
const uint8_t  pinDirectionOuverture = 4; // connecté sur port B

Bonjour,

Voilà le code complet et retravaillé suivant vos indications (noms des variables, annotations, ...).
Je vais l'essayer dans la semaine pour voir s'il n'y a pas d'erreurs à trainer et régler les coefficients P,I,D, pour la régulation.

//affectation des pins aux entrées et sorties
const uint8_t  outputValue = 5;//sortie PWM pour commande moteur

const uint8_t  DIRECTIONNEG = 3;//connecté à la borne A du pont en H IBT-2, si - sens de rotation +
const uint8_t  DIRECTIONPOS = 4;//connecté à la borne B du pont en H IBT-2, si + sens de rotation +

const uint8_t potcom = A0;//mesure potentiomètre de commande
const uint8_t potrec = A1;//mesure potentiomètre de recopie

const uint8_t  shift = 8;//entrée par interrupteur 0/1

//declaration des variables
float valec;
float valrec; 
float erreur;
float errprec;
float deltaerr;
float sommerr;
float pilotage;
float commande;
float correction;
int8_t full;
  
void setup() 

{
Serial.begin (9600);
  pinMode(outputValue,OUTPUT);
  pinMode(DIRECTIONNEG,OUTPUT);
  pinMode(DIRECTIONPOS,OUTPUT);
  pinMode(potcom,INPUT);
  pinMode(potrec,INPUT);
  pinMode (shift, INPUT_PULLUP);

//initialisation des variables
  valec=0;
  valrec=0;
  erreur=0;
  errprec=0;
  deltaerr=0;
  sommerr=0;
  pilotage=0;
  commande=0;
  correction=0;
  full=1;
}


void loop() 
  
{
//commande en PWM du moteur fonction de la valeur de lecture du potentiomètre de commande
  
  digitalWrite(DIRECTIONNEG,LOW);
  digitalWrite(DIRECTIONPOS,HIGH); 
  valec = analogRead (potcom);
  valrec = analogRead (potrec);
  full = digitalRead (shift);
  
erreur = valec - valrec;
sommerr += erreur;
deltaerr = erreur - errprec;
errprec = erreur;
  
  analogWrite(outputValue,pilotage);
  commande = map (valec,0,1023,0,255);


//régulation de la position de l'actuateur par PID fonction de la valeur de lecture du potentiomètre de recopie

 if (erreur == 0)
 {
  pilotage = commande;
}

 
 if (erreur != 0)
 {
 correction = (3*(erreur)) + (2*(sommerr)) + (5*(deltaerr));
 pilotage = commande + correction;
   analogWrite (outputValue,pilotage); 
 }

if (pilotage <0)    //limite le PWM à sa valeur minimale
{
  pilotage = 0;
  }

if (pilotage > 255)    // limite le PWM à sa valeur maximale
{
  pilotage = 255;
}

//commande par mise à la masse, si l'entrée shift est à l'état bas, le PWM est max pdt 500ms quelque soit la commande

 if (digitalRead (shift) == 0)
 {
  analogWrite (outputValue,255);
  delay (500);
  analogWrite (outputValue,pilotage); 
}
 
}

Une foi cette base de code terminée je souhaite ajouter deux modes de calibration:

  • un pour le potentiomètre de commande, de façon à régler la proportionnalité entre commande et réactions de l'actuateur, que mon échelle "0-1023" corresponde à 30, 40, 60, ... degré de rotation potentiomètre

  • un pour le potentiomètre de recopie, en effet se dernier étant fixe sur l'axe de vanne, il sera nécessaire de le paramétrer suivant la position initiale de la vanne. Autrement dit, pour que le "0 mesure" corresponde à la position "repos de la vanne". Position repos pouvant être réglée par vis de buté à une valeur comprise entre 0 et 15°.

Je vais déjà essayer le code de base avant de rajouter des difficultés supplémentaires...

Merci des conseils