controle PID via Xbee + chaine de caractère

Bonjour a tous!

explication du projet :

le but est de réaliser une boucle PID avec asservissement en position pour un moteur CC. Le tout en utilisant une arduino uno et des encodeur optique.

encodeur optique dit "commande" => arduino uno => double pont H => moteur CC => encodeur optique => retour info sur arduino.

se système marche très bien. mais le but est de passer en HF a l'aide de deux modules Xbee et la sa ne marche plus. pourtant les Xbee communiquent bien entre eux.

la chaine réaliser ressemble a ça :

encodeur1 => arduino1 => Xbee -----> Xbee => arduino2 => pont H => encodeur0 => retour info sur arduino2 pour calcule PID

alors voila ma question : quelqu'un sait-il comment "couper" le programme (qui marche très bien) pour un émetteur et un récepteur?

/* read a rotary encoder with interrupts
   Encoder hooked up with common to GROUND,
   encoder0PinA to pin 2, encoder0PinB to pin 4 (or pin 3 see below)
   it doesn't matter which encoder pin you use for A or B  

   uses Arduino pullups on A & B channel outputs
   turning on the pullups saves having to hook up resistors 
   to the A & B channel outputs 

*/ 

#define encoder0PinA  2
#define encoder0PinB  4

#define encoder1PinA  3
#define encoder1PinB  5

#define boutonA      6
#define boutonB      7

#define SpeedPin     9
#define DirectionPin 8
#define DirectionPin2 10

volatile long encoder0Pos = 0;
volatile long encoder1Pos = 0;

long target = 0;
long posmax = 600;
long posmin = -600;

//correction = Kp * error + Kd * (error - prevError) + kI * (sum of errors)
//PID controller constants
float KP = 2.25; //position multiplier (gain)
float KI = 0.5; // Intergral multiplier (gain)
float KD = 1; // derivative multiplier (gain)

int lastError = 0;
int sumError = 0;

//Integral term min/max (random value and not yet tested/verified)
int iMax = 100;
int iMin = 0;

long previousTarget = 0;
long previousMillis = 0;        // will store last time LED was updated
long interval = 5;           // interval at which to blink (milliseconds)

void setup() { 

  pinMode(encoder0PinA, INPUT); 
  pinMode(encoder0PinB, INPUT); 
    
  pinMode(encoder1PinA, INPUT);   
  pinMode(encoder1PinB, INPUT); 
  
  pinMode(DirectionPin, OUTPUT); 
  pinMode(SpeedPin, OUTPUT); 
  
  pinMode(boutonA, INPUT);
  pinMode(boutonB, INPUT);

  attachInterrupt(0, doEncoderMotor0, FALLING);  // encoder pin on interrupt 0 - pin 2
  attachInterrupt(1, doEncoderMotor1, CHANGE);  
  
  Serial.begin (115200);
  Serial.println("start");                // a personal quirk

} 

void loop(){
  
  
  // do some stuff here - the joy of interrupts is that they take care of themselves  
  if (millis() - previousTarget > 1000)
  {
      Serial.print ( encoder1Pos );
      Serial.print ( " , " );
      Serial.print ( encoder0Pos );
      Serial.print ( " , " );
      Serial.println ( target );
      
      previousTarget = millis();
           
      //target += 1024; //for single ch
      //target += 2048; //for dual ch
  }

    
 target =  3 * encoder1Pos;
  docalc();
}

void docalc() {
  
  if (millis() - previousMillis > interval) 
  {
    previousMillis = millis();   // remember the last time we blinked the LED
    
    long error = encoder0Pos - target ; // find the error term of current position - target    
    
    //generalized PID formula
    //correction = Kp * error + Kd * (error - prevError) + kI * (sum of errors)
    long ms = KP * error + KD * (error - lastError) +KI * (sumError);
       
    lastError = error;    
    sumError += error;
    
    //scale the sum for the integral term
    if(sumError > iMax) {
      sumError = iMax;
    } else if(sumError < iMin){
      sumError = iMin;
    }
    
    if(ms > 0){
      digitalWrite ( DirectionPin ,HIGH );
digitalWrite ( DirectionPin2 ,LOW );      
    }
    if(ms < 0){
      digitalWrite ( DirectionPin , LOW );
 digitalWrite ( DirectionPin2 ,HIGH );     
      ms = -1 * ms;
    }

    int motorSpeed = map(ms,0,1024,0,255); 
    //analogWrite ( SpeedPin, (255 - motorSpeed) );
    analogWrite ( SpeedPin,  motorSpeed );
  }  
}

void doEncoderMotor0(){
  if (digitalRead(encoder0PinA) == HIGH) {   // found a low-to-high on channel A
    if (digitalRead(encoder0PinB) == LOW) {  // check channel B to see which way
                                             // encoder is turning
      encoder0Pos = encoder0Pos - 1;         // CCW
    } 
    else {
      encoder0Pos = encoder0Pos + 1;         // CW
    }
  }
  else                                        // found a high-to-low on channel A
  { 
    if (digitalRead(encoder0PinB) == LOW) {   // check channel B to see which way
                                              // encoder is turning  
      encoder0Pos = encoder0Pos + 1;          // CW
    } 
    else {
      encoder0Pos = encoder0Pos - 1;          // CCW
    }

  }


}


void doEncoderMotor1(){

  // look for a low-to-high on channel B
  if (digitalRead(encoder1PinB) == HIGH) {   

    // check channel A to see which way encoder is turning
    if (digitalRead(encoder1PinA) == LOW) {  
      encoder1Pos = encoder1Pos - 1;         // CCW
    } 
    else {
      encoder1Pos = encoder1Pos + 1;         // CW
    }
  }

  // Look for a high-to-low on channel B

  else { 
    // check channel B to see which way encoder is turning  
    if (digitalRead(encoder1PinA) == LOW) {   
      encoder1Pos = encoder1Pos + 1;          // CW
    } 
    else {
      encoder1Pos = encoder1Pos - 1;          // CCW
    }
  }
 if (encoder1Pos > posmax){
   encoder1Pos = posmax;
 }
 else {
   if (encoder1Pos < posmin){
     encoder1Pos = posmin;
   }
 }
}

merci d'avance.

bonjour

je ne suis pas expert en asservissement, et encore moins en liaison radio, mais il me semble que la liaison va induire un délai dans la boucle d'asservissement, et ça risque fort de provoquer des oscillations assez délicates à supprimer, non ? Un peu comme lorsqu'il y a un jeu mécanique entre me moteur et le codeur.

En effet il y aura surement du retard... mais si il ne dépasse pas quelques millisecondes cela ne me gène pas .

depuis quelques jours je fais plain de test et le problème se précise:

il faudrait juste arriver a envoyer des nombres entre -6000 et 6000 (jusque la tout va bien) et a les recevoir et surtout décoder correctement. En effet des que le signe moins intervient le récepteur ne semble pas l'interpréter comme il faut ( apparition de chiffres incorrecte ) .

quelqu'un saurait-il comment remédier a ça?

Bin +6000 d'un coté et -6000 de l'autre :o

avec un programme tout simple j'arrive a envoyer des chiffres positif mais pour les négatifs sa marche pas. par exemple un "-30" envoyer arrive en "-330" , y a t-il une solution?

bonjour, mon projet:

encodeur => arduino => xbee ---->xbee2 => arduino2 => moteur =>encodeur2 => vers arduino2 pour calcul PID

le problème se pose entre les deux arduino, en effet la variable a envoyer (dis-on entre 1 et 4000) doit être envoyer, reçus et interprété comme un seul et même chiffre ("une chaine de caractère" en langage arduino) et je ne trouve pas comment programmer ça. quelqu'un a une idée?

d'avance merci.

B@tto: Bin +6000 d'un coté et -6000 de l'autre :o

Ce que veux dire Batto, c'est que tu ajoutes 6000 à ton chiffre avant de l'envoyer et lors de la réception ,tu lui retranches 6000....

Autrement , c'est inutile de refaire un autre sujet avec la même question .... j'ai fusionné les deux topics

Merci. en effet sans nombre négatif ça marche déjà mieux .

reste encore un problème: la partie émetteur envoi "1000" et le récepteur lui "comprend" : 1 puis 0 puis 0 ...ce qui en terme de position de codeur et calcule PID n' est pas du tout la même chose. y a-t-il un moyens pour qu'une variable soit envoyer, reçus et traiter dans son intégralité et non bout par bout?

d'avance merci.

Faire le calcul : 1*1000 + 0*100 + 0*10 + 0*1