Création d'un Convoyeur de tri avec Arduino

Bonjour,
je cherche à créer un convoyeur pour trier des pièces de longueurs différentes.
ARDUINO + LASER + CAPTEUR LASER + RELAIS PNEUMATIQUE
J’obtiens de bon résultat avec ce code pour definir la taille des pièces

const byte btnPin = 2;        // Bouton sur pin 2...
const byte btnIrq = 0;       // Bouton sur pin 2, soit INT0 sur arduino UNO.
unsigned long tFall = 0;     // Valeur de millis() lors du front descendant
unsigned long tRise = 0;    // Valeur de millis() lors du front montant
unsigned long tDiff =0;     //Valeur appuie Bp
void onRise(void);
void onFall(void);
void setup(void);
void loop(void);
void onFall() {                                     // Interruption lors d'un front descendant
tFall = millis();                                // On sauvegarde la valeur de millis dans tFall
attachInterrupt(btnIrq, onRise, RISING);        // Puis on passe la détection d'interruption sur front montant
}
void onRise() {                                     // Interruption lors d'un front montant
tRise = millis();                                // On sauvegarde la valeur de millis dans tRise
attachInterrupt(btnIrq, onFall, FALLING);       // Puis on passe la détection d'interruption sur front descendant
}
void setup(void) {                                  // Setup:
attachInterrupt(btnIrq, onFall, FALLING);        // Détection d'interruption sur front descendant au départ
Serial.begin(115200);                           // Serial à 11500 bauds
}
void loop(void) {
if ( ( tRise != 0 ) && ( tFall != 0 ) ) {
tDiff= tRise - tFall;
Serial.println(tDiff);
tFall=0;tRise=0;tDiff=0;
/*Serial.print("tRise=");
Serial.println(tRise);
Serial.print("tFall=");
Serial.println(tFall);                   // Si les 2 fronts ont été détectés, alors on affiche tout
Serial.print("tDiff=");*/
}
}

Cependant je n’arrive pas à donner un déclenchement sur le Pin 8 en fonction de la valeur de tDiff ( compris entre deux valeurs )

Le pin 8 Active un relais ( AIR ).

Pouvez vous m’aider ?

Voici mon script, il fonctionne mais une pièce sur deux ( quelque soit l’intervalle de temps de passage )
A l’oscilloscope, chaque passage de pièce est bien présent ( le capteur OK )

// DECLARATION DES CAPTEURS
int air = 8; // vers relais AIR
const byte cap = 2; // vers CAPTEUR LASER
const byte btnIrq = 0;

// DETECTION DES FRONTS

static unsigned long tFall = 0;         // Valeur de millis() lors du front descendant
static unsigned long tRise = 0;        // Valeur de millis() lors du front montant
unsigned long tDiff = 0;       //Valeur appuie Bp
unsigned long mem;            //Variable mémoire

//SETUP
void onRise(void);
void onFall(void);
void setup(void);
void loop(void);
 
void onFall()
{                                     // Interruption lors d'un front descendant
  tFall = millis();                                // On sauvegarde la valeur de millis dans tFall
  attachInterrupt(btnIrq, onRise, RISING);        // Puis on passe la détection d'interruption sur front montant

}

void onRise()
{                                     // Interruption lors d'un front montant
tRise = millis();                                // On sauvegarde la valeur de millis dans tRise
attachInterrupt(btnIrq, onFall, FALLING);       // Puis on passe la détection d'interruption sur front descendant
 
}
 
void setup(void)
{
// PULLUP  
pinMode(cap, INPUT_PULLUP);

//
pinMode(air, OUTPUT);
attachInterrupt(btnIrq, onFall, FALLING);         // Détection d'interruption sur front descendant au départ
///////////////////
Serial.begin(115200);                              // Serial à 9600 bauds
}
void loop(void) {

digitalWrite(air, LOW);
noInterrupts();

///////////////0  
if ( ( tRise != 0 ) && ( tFall != 0 ) )
{
        tDiff = ( tRise - tFall );
        mem = tDiff;        
}
interrupts();

if ( mem > 150 && mem < 300  )
{            
Serial.println(tDiff);
//  Serial.println(tDiff);
//Serial.println(tFall);
//Serial.println(tRise);
digitalWrite(air, HIGH);
delay(300); // EXPULSION DE LA PIECE
//   digitalWrite(air, LOW);
mem = 0; tFall = 0; tRise = 0; tDiff = 0; // REMISE A ZERO 


}}

idéalement les variables utilisées dans les interruptions devraient être volatile (pas besoin de static puisqu’elle sont globales) et vos pins pourraient porter des noms plus clairs.

on évite aussi de coder le N° d’interruption en dur, on utilise digitalPinToInterrupt()

dans la loop - même si ici ce n’est pas un pb - il vaut mieux prendre l’habitude de travailler sur des copies des valeurs obtenues en désactivant les interruptions plutôt que de faire des maths avec les interruptions désactivées car ça prend du temps en on risque de rater des trucs.

Que doit-il vraiment se passer si vous avez une détection ? pour le moment vous avez une attente active avec un delay() de 300ms pour “souffler” mais le convoyeur continue d’avancer et donc potentiellement de déclencher des interruptions que vous recevrez immédiatement après avoir réactivé les interruptions.

Si c’est envisageable, il faudrait souffler les pièces et se mettre à nouveau en attente d’une nouvelle pièce en ayant “oublié” les interruptions en cours pour partir d’un état ‘propre’ et ne pas rater un cycle. effacer le flag d’interruption dépend du type de carte que vous avez, pour l’interruption 0 (pin D2 sur UNO) ça se fait en effectuant un EIFR = bit(INTF0);  // efface le drapeau d'interruption 0 (pin D2 sur UNO).

Un bon article de Nick G. à lire sur les interruptions

mais ça dépend de l’espacement des pièces sur le tapis et de ce que vous voulez faire pendant ces 300ms

le code pourrait ressembler alors à ça: (tapé ici d’après votre code, non testé)

// DECLARATION DES PINS 
const byte airPin = 8; // vers relais AIR
const byte capteurLaserPin = 2; // vers CAPTEUR LASER

// VARIABLES UTILISEES DANS LES INTERRUPTIONS
volatile unsigned long tFall;       // Valeur de millis() lors du front descendant
volatile unsigned long tRise;       // Valeur de millis() lors du front montant


// Interruptions
void onRise();
void onFall();

// Interruption lors d'un front descendant
void onFall()
{
  tFall = millis();  // On sauvegarde la valeur de millis dans tFall
  attachInterrupt(digitalPinToInterrupt(capteurLaserPin), onRise, RISING);        // Puis on passe la détection d'interruption sur front montant
}

// Interruption lors d'un front montant
void onRise()
{
  tRise = millis();   // On sauvegarde la valeur de millis dans tRise
  attachInterrupt(digitalPinToInterrupt(capteurLaserPin), onFall, FALLING);       // Puis on passe la détection d'interruption sur front descendant
}

void attentePiece()
{
  noInterrupts();
  tRise = 0;
  tFall = 0;
  attachInterrupt(digitalPinToInterrupt(capteurLaserPin), onFall, FALLING);         // Détection d'interruption sur front descendant au départ
  EIFR = bit(INTF0);  // efface le drapeau d'interruption 0 (pin D2 sur UNO) -->  au cas où il y en ait eu une en attendant
  interrupts();
}

void setup(void)
{
  Serial.begin(115200);
  pinMode(capteurLaserPin, INPUT_PULLUP);
  pinMode(airPin, OUTPUT);
  attentePiece();
}

void loop(void)
{
  // on effectue une copie locale de travail des variables utilisées dans les interruptions
  unsigned long copieTRise, copieTFall, deltaT;
  noInterrupts();
  copieTRise = tRise;
  copieTFall = tFall;
  interrupts();

  if ((copieTRise != 0 ) && (copieTFall != 0)) {
    deltaT = copieTRise - copieTFall;
      Serial.println(deltaT);
    if ((deltaT > 150) && (deltaT < 300)) {
      digitalWrite(airPin, HIGH);
      delay(300); // EXPULSION DE LA PIECE
      digitalWrite(airPin, LOW);
    }
    attentePiece();
  }
}

Il se peut aussi que votre laser ‘rebondisse’ - je ne sais pas si c’est quelque chose que vous devez prendre en considération - ça va créer des micros detections.

cela dit - si vos objets mettent au moins 150ms pour passer et que votre code ne fait que ça, vous n’avez pas besoin vraiment d’utiliser les interruptions - une petite machine à état dans la loop suffit pour surveiller les pièces qui passent et activer le relais pneumatique