Arduino


L'objet de ce post est de détecter différents gaz environnant tel que H2, CO, CH4...

Publié le 13/10/2019



L'objet de ce post est de détecter différents gaz environnant tel que :

* le monoxyde de carbone,

* Le dihydrogène

* Le méthane

* Alcool

* Fumées

* Propane



Pour cela, nous allons utiliser un composant nommé MQ-2.

Il existe différents composants tel que le MQ-7, MQ-135... qui sont des composants plus spécialisés dans une ou deux molécules.



Pour pouvoir retrouver les teneurs des différents gaz, il va falloir se pencher un peu sur la feuille technique de ce composant (que vous trouverez dans le zip du projet).



Le fabriquant nous fourni une jolie "courbe logarithmique" qu'il va falloir étudier pour pouvoir en déduire les valeurs en ppm des différents gaz.



Comme on peut l'apercevoir, cette "courbe logarithmique" représente en fait une droite. Il va donc falloir faire appel à nos années collège pour retrouver différentes informations de cette droite comme:

* Le point de départ

* Le point d'arrivée

* Le coefficient directeur de la droite



Pour rappel le coefficient directeur d'une droite se calcule de la façon suivante: a = (y2-y1)/(x2-x1)



Donc pour chacun des gaz, on va répertorier ces informations. Nous allons prendre pour exemple le gaz CH4:

y1=log(3) sur l'axe Rs/R0 (premier point)

y2=log(0.7) sur l'axe Rs/R0 (dernier point)

x1=log(200) sur l'axe ppm (premier point)

x2=log(10000) sur l'axe ppm (dernier point)



a=(log(0.7)-log(3))/(log(10000)-log(200))=-0.372



On créera donc le tableau suivant pour calculer la concentration de notre gaz CH4: tab = { log(x1), log(y1), a }



Soit tabCH4 = { 2.30, 0.48, -0.372 }



Le module MQ-2 nous renvoie la valeur RS.



En se basant sur le graph, on en déduit la formule:

Y - y1 = m(X-x1)

X = (y-y1)/m + x1

X = (Rs/R0-y1)/m + x1

log X = (log(Rs/R0)-y1)/m + x1

X = 10^((log(Rs/R0)-y1)/m + x1)



On peut ainsi calculer la valeur en ppm correspondante.



Voilà pour la partie Math !!!



Reste à refaire ces calculs pour chacun des autres gaz…



Le câblage quant à lui reste très simple (attention tout de même de ne pas se tromper entre la sortie A0 et D0 du composant MQ-2).



J'ai ajouté un petit buzzer qui sonne dès qu'une concentration d'un des gaz est détectée.












Liste des composants nécessaires pour la réalisation du circuit :

  • MQ-21
  • Buzzer1
  • Arduino Nano1


Schéma du montage électronique :


Pour les amateurs d'impression 3D, j'ai fait quelques templates qui permettent d'imprimer divers boitiers pouvant accueillir les divers composants utilisés dans mes tutoriels.
- Pour un composant PIR, vous trouverez le boitier à imprimer ici.

    Il faut compter environ 4h pour imprimer les composants de ce boitier.


- Pour un relais, vous trouverez le boitier à imprimer ici.
    Il faut compter environ 2h pour imprimer les composants de ce boitier.




L'ensemble des impressions 3D a été réalisé sur une imprimante Creality3D Ender-3 pro avec les réglages standards suivants:

Pour les personnes possédant Fritzing, voici le schéma électronique.


Voici le code à télécharger dans votre Arduino:

/*

__  __           _       _        __  __  ____       ___            
|  \/  |         | |     | |      |  \/  |/ __ \     |__ \ _     
| \  / | ___   __| |_   _| | ___  | \  / | |  | |______ ) (_)      
| |\/| |/ _ \ / _` | | | | |/ _ \ | |\/| | |  | |______/ /       
| |  | | (_) | (_| | |_| | |  __/ | |  | | |__| |     / /_ _      
|_|  |_|\___/ \__,_|\__,_|_|\___| |_|  |_|\___\_\    |____(_)    
                                  (    
                                  )\ )            )              )                   (                            
                                 (()/(     (   ( /(   (       ( /(   (    (   (      )\ )   (    (  (      )      
                                  /(_))   ))\  )\()) ))\  (   )\()) ))\  ))\  )(    (()/(  ))\   )\))(  ( /(  (   
                                 (_))_   /((_)(_))/ /((_) )\ (_))/ /((_)/((_)(()\    ((_))/((_) ((_))\  )(_)) )\  
                                  |   \ (_))  | |_ (_))  ((_)| |_ (_)) (_))(  ((_)   _| |(_))    (()(_)((_)_ ((_) 
                                  | |) |/ -_) |  _|/ -_)/ _| |  _|/ -_)| || || '_| / _` |/ -_)  / _` | / _` ||_ / 
                                  |___/ \___|  \__|\___|\__|  \__|\___| \_,_||_|   \__,_|\___|  \__, | \__,_|/__| 
                                                                                                |___/             
 
 
                                                                         __    ___       ___  _  _  ___  ____  ____  __  __ 
                                                                        (  )  / __) ___ / __)( \/ )/ __)(_  _)( ___)(  \/  )
                                                                         )(__( (_-.(___)\__ \ \  / \__ \  )(   )__)  )    ( 
                                                                        (____)\___/     (___/ (__) (___/ (__) (____)(_/\/\_)
 
 
##############################################################################################################################################

Adapt from source: sandboxelectronics.com
                                                    LG    2019-10-13
************************************************************************************/

/************************Hardware Related Macros************************************/
#define         RL_VALUE                     (5)     //define the load resistance on the board, in kilo ohms
#define         RO_CLEAN_AIR_FACTOR          (9.83)  //RO_CLEAR_AIR_FACTOR=(Sensor resistance in clean air)/RO,
                                                     //which is derived from the chart in datasheet

/***********************Software Related Macros************************************/
#define         CALIBARAION_SAMPLE_TIMES     (50)    //define how many samples you are going to take in the calibration phase
#define         CALIBRATION_SAMPLE_INTERVAL  (500)   //define the time interal(in millisecond) between each samples in the
                                                     //cablibration phase
#define         READ_SAMPLE_INTERVAL         (50)    //define how many samples you are going to take in normal operation
#define         READ_SAMPLE_TIMES            (5)     //define the time interval(in millisecond) between each samples in 
                                                     //normal operation

/**********************Application Related Macros**********************************/
#define         GAS_LPG                      0
#define         GAS_CO                       1
#define         GAS_SMOKE                    2
#define         GAS_CH4                      3
#define         GAS_ALCOHOL                  4
#define         GAS_PROPANE                  5
#define         GAS_H2                       6

/************************PIN Related Macros************************************/
#define         PIN_BUZZER                   10
#define         MQ_PIN                       0     //define which analog input channel you are going to use


/************************Seuil alerte Related Macros************************************/
#define         ALERTE_GAS_LPG 0  // A définir
#define         ALERTE_GAS_CO 0  // A définir
#define         ALERTE_GAS_SMOKE 0  // A définir
#define         ALERTE_GAS_CH4 0  // A définir
#define         ALERTE_GAS_ALCOHOL 0  // A définir
#define         ALERTE_GAS_PROPANE 0  // A définir
#define         ALERTE_GAS_H2 0  // A définir
  
/*****************************Globals***********************************************/
float           LPGCurve[3]     ={2.3,0.21,-0.47};  
float           COCurve[3]      ={2.3,0.72,-0.34};  
float           SmokeCurve[3]   ={2.3,0.53,-0.44};  
float           CH4Curve[3]     ={2.3,0.48,-0.372}; 
float           AlcoholCurve[3] ={2.3,0.46,-0.3823}; 
float           PropaneCurve[3] ={2.3,0.26,-0.4756}; 
float           H2Curve[3]      ={2.3,0.32,-0.4654}; 



float           Ro           =  10;                 //Ro is initialized to 10 kilo ohms

void setup()
{
  Serial.begin(9600);                               //UART setup, baudrate = 9600bps
  
  Serial.println(F(" __  __           _       _        __  __  ____       ___            "));
  Serial.println(F("|  \\/  |         | |     | |      |  \\/  |/ __ \\     |__ \\ _     "));
  Serial.println(F("| \\  / | ___   __| |_   _| | ___  | \\  / | |  | |______ ) (_)      "));
  Serial.println(  F("| |\\/| |/ _ \\ / _` | | | | |/ _ \\ | |\\/| | |  | |______/ /       ")); 
  Serial.println(  F("| |  | | (_) | (_| | |_| | |  __/ | |  | | |__| |     / /_ _      "));     
  Serial.println(  F("|_|  |_|\\___/ \\__,_|\\__,_|_|\\___| |_|  |_|\\___\\_\\    |____(_)    "));
  Serial.print(F("                                "));Serial.println(F(" (    "));                                                                           
  Serial.print(F("                                "));Serial.println(F(" )\\ )            )              )                   (                            "));
  Serial.print(F("                                "));Serial.println(F("(()/(     (   ( /(   (       ( /(   (    (   (      )\\ )   (    (  (      )      "));
  Serial.print(F("                                "));Serial.println(F(" /(_))   ))\\  )\\()) ))\\  (   )\\()) ))\\  ))\\  )(    (()/(  ))\\   )\\))(  ( /(  (   "));
  Serial.print(F("                                "));Serial.println(F("(_))_   /((_)(_))/ /((_) )\\ (_))/ /((_)/((_)(()\\    ((_))/((_) ((_))\\  )(_)) )\\  "));  
  Serial.print(F("                                "));Serial.println(F(" |   \\ (_))  | |_ (_))  ((_)| |_ (_)) (_))(  ((_)   _| |(_))    (()(_)((_)_ ((_) "));
  Serial.print(F("                                "));Serial.println(F(" | |) |/ -_) |  _|/ -_)/ _| |  _|/ -_)| || || '_| / _` |/ -_)  / _` | / _` ||_ / "));
  Serial.print(F("                                "));Serial.println(F(" |___/ \\___|  \\__|\\___|\\__|  \\__|\\___| \\_,_||_|   \\__,_|\\___|  \\__, | \\__,_|/__| "));
  Serial.print(F("                                "));Serial.println(F("                                                               |___/             "));
  Serial.println(F(""));                                                              
  Serial.println(F(""));                                                              
  Serial.print(F("                                                                       "));Serial.println(F(" __    ___       ___  _  _  ___  ____  ____  __  __ "));
  Serial.print(F("                                                                       "));Serial.println(F("(  )  / __) ___ / __)( \\/ )/ __)(_  _)( ___)(  \\/  )"));
  Serial.print(F("                                                                       "));Serial.println(F(" )(__( (_-.(___)\\__ \\ \\  / \\__ \\  )(   )__)  )    ( "));
  Serial.print(F("                                                                       "));Serial.println(F("(____)\\___/     (___/ (__) (___/ (__) (____)(_/\\/\\_)"));
  Serial.println(F(""));                                                              
  Serial.println(F(""));                                                              
  Serial.println(F("##############################################################################################################################################"));                                                              
  Serial.println(F(""));                                                              
  Serial.println(F(""));                                                              
  

  pinMode(PIN_BUZZER, OUTPUT);
  digitalWrite(PIN_BUZZER, LOW);

  tone(PIN_BUZZER, 50, 5000 );
  digitalWrite(PIN_BUZZER, LOW);

  Serial.print(F("Calibrating...\n"));                
  Ro = MQCalibration();                       //Calibrating the sensor. Please make sure the sensor is in clean air 
                                              //when you perform the calibration                    
  Serial.print(F("Calibration is done...\n")); 
  Serial.print("Ro=");
  Serial.print(Ro);
  Serial.print("kohm");
  Serial.print("\n");
}

void loop()
{
  int li_GAS_LPG=0, li_GAS_CO = 0, li_GAS_SMOKE=0, li_GAS_CH4=0, li_GAS_ALCOHOL = 0, li_GAS_PROPANE=0, li_GAS_H2=0;
  float lf_value = MQRead()/Ro;
  
  li_GAS_LPG=MQGetGasPercentage(lf_value,GAS_LPG);
  li_GAS_CO = MQGetGasPercentage(lf_value,GAS_CO);
  li_GAS_SMOKE = MQGetGasPercentage(lf_value,GAS_SMOKE);
  li_GAS_CH4 = MQGetGasPercentage(lf_value,GAS_CH4);
  li_GAS_ALCOHOL = MQGetGasPercentage(lf_value,GAS_ALCOHOL);
  li_GAS_PROPANE = MQGetGasPercentage(lf_value,GAS_PROPANE);
  li_GAS_H2 = MQGetGasPercentage(lf_value,GAS_H2);

  if (li_GAS_LPG>ALERTE_GAS_LPG || li_GAS_CO>ALERTE_GAS_CO || li_GAS_SMOKE>ALERTE_GAS_SMOKE || li_GAS_CH4>ALERTE_GAS_CH4 || li_GAS_ALCOHOL>ALERTE_GAS_ALCOHOL || li_GAS_PROPANE>ALERTE_GAS_PROPANE || li_GAS_H2>ALERTE_GAS_H2)
  {
   Serial.print("Value:"); 
   Serial.print( analogRead(MQ_PIN));
   Serial.print( "ppm" );
   Serial.print("    ");   
   Serial.print("LPG:"); 
   Serial.print( li_GAS_LPG );
   Serial.print( "ppm" );
   Serial.print("    ");   
   Serial.print("CO:"); 
   Serial.print(li_GAS_CO);
   Serial.print( "ppm" );
   Serial.print("    ");   
   Serial.print("SMOKE:"); 
   Serial.print(li_GAS_SMOKE);
   Serial.print( "ppm" );
   Serial.print("    ");   
   Serial.print("CH4:"); 
   Serial.print(li_GAS_CH4);
   Serial.print( "ppm" );
   Serial.print("    ");   
   Serial.print("ALCOHOL:"); 
   Serial.print(li_GAS_ALCOHOL);
   Serial.print( "ppm" );
   Serial.print("    ");   
   Serial.print("PROPANE:"); 
   Serial.print(li_GAS_PROPANE);
   Serial.print( "ppm" );
   Serial.print("    ");   
   Serial.print("H2:"); 
   Serial.print(li_GAS_H2);
   Serial.print( "ppm" );
   Serial.print("\n");
   tone(PIN_BUZZER, 50, 1000 );
   digitalWrite(PIN_BUZZER, LOW);  
  }
  delay(200);
}

/****************** MQResistanceCalculation ****************************************
Input:   raw_adc - raw value read from adc, which represents the voltage
Output:  the calculated sensor resistance
Remarks: The sensor and the load resistor forms a voltage divider. Given the voltage
         across the load resistor and its resistance, the resistance of the sensor
         could be derived.
************************************************************************************/ 
float MQResistanceCalculation(int raw_adc)
{
  return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc));
}

/***************************** MQCalibration ****************************************
Input:   mq_pin - analog channel
Output:  Ro of the sensor
Remarks: This function assumes that the sensor is in clean air. It use  
         MQResistanceCalculation to calculates the sensor resistance in clean air 
         and then divides it with RO_CLEAN_AIR_FACTOR. RO_CLEAN_AIR_FACTOR is about 
         10, which differs slightly between different sensors.
************************************************************************************/ 
float MQCalibration()
{
  int i;
  float val=0;

  for (i=0;i<CALIBARAION_SAMPLE_TIMES;i++) {            //take multiple samples
    val += MQResistanceCalculation(analogRead(MQ_PIN));
    delay(CALIBRATION_SAMPLE_INTERVAL);
  }
  val = val/CALIBARAION_SAMPLE_TIMES;                   //calculate the average value

  val = val/RO_CLEAN_AIR_FACTOR;                        //divided by RO_CLEAN_AIR_FACTOR yields the Ro 
                                                        //according to the chart in the datasheet 

  return val; 
}
/*****************************  MQRead *********************************************
Input:   mq_pin - analog channel
Output:  Rs of the sensor
Remarks: This function use MQResistanceCalculation to caculate the sensor resistenc (Rs).
         The Rs changes as the sensor is in the different consentration of the target
         gas. The sample times and the time interval between samples could be configured
         by changing the definition of the macros.
************************************************************************************/ 
float MQRead()
{
  int i;
  float rs=0;

  for (i=0;i<READ_SAMPLE_TIMES;i++) {
    rs += MQResistanceCalculation(analogRead(MQ_PIN));
    delay(READ_SAMPLE_INTERVAL);
  }

  rs = rs/READ_SAMPLE_TIMES;

  return rs;  
}

/*****************************  MQGetGasPercentage **********************************
Input:   rs_ro_ratio - Rs divided by Ro
         gas_id      - target gas type
Output:  ppm of the target gas
Remarks: This function passes different curves to the MQGetPercentage function which 
         calculates the ppm (parts per million) of the target gas.
************************************************************************************/ 
int MQGetGasPercentage(float rs_ro_ratio, int gas_id)
{
  if ( gas_id == GAS_LPG ) 
  {
     return MQGetPercentage(rs_ro_ratio,LPGCurve);
  } 
  else if ( gas_id == GAS_CO ) 
  {
     return MQGetPercentage(rs_ro_ratio,COCurve);
  }
  else if ( gas_id == GAS_SMOKE ) 
  {
     return MQGetPercentage(rs_ro_ratio,SmokeCurve);
  }  
  else if ( gas_id == GAS_CH4 ) 
  {
     return MQGetPercentage(rs_ro_ratio,CH4Curve);
  } 
  else if ( gas_id == GAS_ALCOHOL ) 
  {
     return MQGetPercentage(rs_ro_ratio,AlcoholCurve);
  }    
  else if ( gas_id == GAS_PROPANE ) 
  {
     return MQGetPercentage(rs_ro_ratio,PropaneCurve);
  }    
  else if ( gas_id == GAS_H2 ) 
  {
     return MQGetPercentage(rs_ro_ratio,H2Curve);
  }    

  return 0;
}

/*****************************  MQGetPercentage **********************************
Input:   rs_ro_ratio - Rs divided by Ro
         pcurve      - pointer to the curve of the target gas
Output:  ppm of the target gas
Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm) 
         of the line could be derived if y(rs_ro_ratio) is provided. As it is a 
         logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic 
         value.
************************************************************************************/ 
int  MQGetPercentage(float rs_ro_ratio, float *pcurve)
{
  return (pow(10,( ((log(rs_ro_ratio)-pcurve[1])/pcurve[2]) + pcurve[0])));
}


Voici le code du projet:

Voici le projet zippé.


Nombre de vue(s): 5068

Forum


Vos avis/remarques...


Veuillez vous connecter pour laisser vos commentaires...