Station météo : capteur de particules fines (SDS011)

Station météo : capteur de particules fines (SDS011)

Pour poursuivre la conception d’une station météo sans fil, on s’attaque cette fois ci à un capteur de particules fines PM10 et PM2,5. PM signifie Particulate Matter, suivi de la taille des particules en µm, donc en millièmes de millimètre.

A gauche le capteur de température, à droite le capteur de particules.

Ce sont des particules en suspension dans l’atmosphère de taille microscopique : leur diamètre est inférieur à 10µm pour les PM10 et inférieur à  2.5µm pour les PM2,5. Pour référence, un cheveux a un diamètre compris entre 50 et 100µm.

La mesure des particules est assurée par le SDS011 et un module radio nrf24l01+ gère la transmission sans fil. Le cœur est un  atmega328p qui peut être programmé avec arduino.

Le SDS011

Le module SDS011 permet la mesure de particules fines PM10 et PM2.5 en µg/m³. Le principe de fonctionnement est la diffusion de la lumière émise par un laser lorsque des particules traversent la zone de détection. Un ventilateur assure la circulation d’air dans cette zone. La valeur est retournée soit via un port série (uart) soit en pwm.

Spécifications du module SDS011

 

Schéma du circuit

Le circuit s’articule autour d’un Atmega328p comme dans la plupart des circuits présentés sur ce blog. C’est le même que celui présent sur l’Arduino Uno. La partie sans fil est assurée par un module Nrf24l01+. Le SDS011 est utilisé avec le mode série via un SoftSerial. Le circuit est alimenté sous 5V actuellement par un chargeur USB, mais un autre article traitera d’une alimentation via cellule solaire pour être totalement autonome.

 

C1, C2, C3, C5, C6, C9 100nF
C4 470µF
C7, C8 10µF
Q1 AO3401
IC1 ATMEGA328P-P + Support
R1 2MΩ
R2 470kΩ
R3 100kΩ
D1 LED
R8 1kΩ
U1 nRF24L01 + Support 2×4
U2 AMS1117-3.3
J1 ALIM 5v
J2 SDS011
P2 Serial prog (pin header)

 

Le boitier

Le boitier protège le capteur de la pluie tout en assurant une prise d’air sur le dessous. Il est réalisé à l’imprimante 3D, pour l’instant en PLA pour le prototype, mais l’ASA (acrylonitrile styrene acrylate) sera plus résistant aux UV et aux intempéries. Il est réalisé avec OpenScad.

Il est prévu pour être fixé sur le même support que le capteur de température.

Le matériel nécessaire pour le boitier :

  • 2x Boulon M4x60  ou M4x80
  • 2x écrous M4
  • 3x Boulon M3x16
  • 3x écrous M3

Les écrous sont noyés dans le plastique, ainsi il est nécessaire de mettre l’impression en pause après la dernière couche des emplacements des écrous.

 

L’assemblage

 

Le programme

L’interface avec le capteur se fait avec la librairie https://github.com/ricki-z/SDS011

#include <LowPower.h>
#include <nRF24L01.h>
#include <printf.h>
#include <RF24.h>
#include <RF24_config.h>
#include <Wire.h>
#include <stdint.h>
#include <SDS011.h>

/* -------CONFIG---------*/
#define LOGDEBUG  0
/* --------------------- */

#define RF24_CH   25
/* --------------------- */


#define SLEEP_DATA   37    //5min , 8s par cycle
#define SLEEP_VOLT   450  //1h
/* --------------------- */


#define VT_PIN    14  //A0
#define SDS_ON    8   //PB0
#define LED_PIN   17  //PC3
/* --------------------- */

//DEBUG 
#if LOGDEBUG==1
#define DEBUG_PRINT(x)       Serial.print(x)
#define DEBUG_PRINTDEC(x)    Serial.print(x, DEC)
#define DEBUG_PRINTLN(x)     Serial.println(x)
#define DEBUG_RADIO()        radio.printDetails()
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTDEC(x)
#define DEBUG_PRINTLN(x)
#define DEBUG_RADIO()
#endif
/* --------------------- */

uint16_t  nodeId = NODE_ID;
uint8_t   node_address[5]         = {"1Node"};
uint8_t   server_address[5]       = {"2Node"};
/* --------------------- */


SDS011 	  my_sds;
RF24      radio(9,10);

uint8_t   radioBuffer[32]    = {0};

uint16_t  cntDATA = SLEEP_DATA;
uint16_t  cntVOLT = SLEEP_VOLT;

float     p10            = 0;
float     p25            = 0;
float     pressure       = 0;
float     voltage        = 0;
int       error          = 0;


void radioSetup(){
  radio.begin();
  radio.setChannel(RF24_CH);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_MAX);
  radio.setCRCLength(RF24_CRC_16);
  radio.setRetries(10, 15);  
  radio.setAutoAck(1);
  radio.openReadingPipe(1, node_address);
  radio.openWritingPipe(server_address);

  DEBUG_RADIO();
}

void setup() {
  delay(500);

  #if LOGDEBUG==1
  Serial.begin(115200);
  printf_begin();
  #endif

  pinMode(SDS_ON, OUTPUT);
  digitalWrite(SDS_ON, HIGH);

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

  //flash led
  digitalWrite(LED_PIN, HIGH);
  delay(250);
  digitalWrite(LED_PIN, LOW);
  
  //1.1V internal voltage reference
  analogReference(INTERNAL);

  radioSetup();

  digitalWrite(SDS_ON, LOW);
  delay(250);
  my_sds.begin(6, 7); //RX, TX
  delay(250);
  my_sds.sleep();
  
  //flash led
  delay(500);
  digitalWrite(LED_PIN, HIGH);
  delay(1000);
  digitalWrite(LED_PIN, LOW);
}

void loop() {
  DEBUG_PRINTLN(">");

  if( (cntDATA >= SLEEP_DATA) || (cntVOLT >= SLEEP_VOLT)){

    if(cntDATA >= SLEEP_DATA){
      //Power on SDS011 and wait a little
      my_sds.wakeup();

      //wait for air flow
      delay(5000);

      uint8_t  counter = 0;
      float    sumP25  = 0;
      float    sumP10  = 0;
     

      for(uint8_t i = 0; i < 5; i++){
         error = my_sds.read(&p25, &p10);
         if (!error) {
            sumP25 += p25;
            sumP10 += p10;
            DEBUG_PRINTLN(counter);
            ++counter;
         }
         else{
            DEBUG_PRINTLN("Error");
         }
         delay(1000);
      }

      my_sds.sleep();

      if(counter >= 3){
         sumP25 /= counter;
         sumP10 /= counter;

         DEBUG_PRINT("P25=");
         DEBUG_PRINT(sumP25);
         DEBUG_PRINT(", P10=");
         DEBUG_PRINTLN(sumP10);
	  
	  
	     memcpy(radioBuffer,     &nodeId,             2);
         memcpy(radioBuffer+2,   "DATA",              4);
    
         memcpy(radioBuffer+6,   &sumP25,             4);
         memcpy(radioBuffer+10,  &sumP10,             4);

         memset(radioBuffer+14,  0,                  18);    

		 if(radio.write(radioBuffer, 32)){
		   cntDATA = 0;
		 }
		 else{
		   if(cntDATA >= (SLEEP_DATA+5)){
		     //retry up to 5 cycles of 8s.
			 cntDATA = 0;
		   }
		 }
	  }
    }

    delay(250);
    radio.flush_tx();

    if(cntVOLT >= SLEEP_VOLT){
      voltage = analogRead(VT_PIN);
      voltage = voltage * 1.1 * ((2470000.0)/470000.0) / 1024.0;
    
      DEBUG_PRINT("V=");
      DEBUG_PRINTLN(voltage);

     
      memcpy(radioBuffer,     &nodeId,           2);
      memcpy(radioBuffer+2,   "VOLT",            4);
    
      memcpy(radioBuffer+6,   &voltage,          4);

      memset(radioBuffer+10,  0,                 22);
    

      if(radio.write(radioBuffer, 32)){
        cntVOLT = 0;
      }
      else{
        if(cntVOLT >= (SLEEP_VOLT+5)){
          //retry up to 5 cycles of 8s.
          cntVOLT = 0;
        }
      }
    }   

    delay(50);

  }
  
   
  ++cntDATA;
  ++cntVOLT;
  
  //flash led
  digitalWrite(LED_PIN, HIGH);
  delay(1);
  digitalWrite(LED_PIN, LOW);

  DEBUG_PRINTLN("."); 

  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);

}

2 réactions au sujet de « Station météo : capteur de particules fines (SDS011) »

    1. Bonjour, désolé mais ce sont des créations qui ne sont pas produites en série donc rien n’est à vendre. Les schémas sont justes partagés avec les makers afin de le réaliser chez eux ou de s’en inspirer 🙂

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *