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);

}

9 réflexions sur « 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 🙂

  1. Salut ZeSanglier (de Cornouailles ?),

    Merci pour cet article très intéressant 🙂

    L’aspect détection de particules fines m’intéresse mais pas pour de la météorologie : pour l’impression 3D qui génère beaucoup de microparticules.
    Penses-tu que le capteur SDS011 que utilises serait utilisable dans un tel contexte ?

    Le but final serait de pouvoir comparer les taux de particules avant et après utilisation d’un système de filtration et ainsi juger de l’efficacité dudit système.

    Ciao !

    1. Salut,
      Je pense que les particules émises par les impressions 3D sont plus des particules « ultrafines » voir même nanoparticules trop petites pour les capteurs de la série SDS.
      Pour l’impression 3D, outre les nanoparticules, il y a des émissions de composés organiques volatiles qu’il pourrait aussi être intéressant de mesurer 🙂

      Le Sanglier (presque de Cornouailles :D)

  2. Bonjour,

    je magnifie bien les aptitudes du capteur et je voudrais l’utiliser dans un projet pour détecter la Qualité  de l’air avec d’autres capteurs, mais le dispositif sera mobile et je voudrais savoir si elle fonctionne avec d’autres cartes comme GSM ou la technologie Lora

    1. Bonjour,
      Oui ça peut fonctionner avec un autre mode de transmission à la place du NRF24 comme du LoRa ou GSM/LTE. Il suffit d’adapter le programme pour la partie émission.

Laisser un commentaire

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