아두이노프로세싱 프로그래밍

아두이노 NodeMCU GP2Y1010A 미세먼지 신호 디지털 저주파 필터링

coding art 2017. 10. 31. 18:15
728x90

미세먼지 센서 GP2Y1010A 의 측정 신호의 변동성이 극히 높음을 예전에 지적하였다. 이러한 현상은 비단 먼지센서 뿐만 아니라 드론 제어를 위해 사용하는 MPU6050 가속도/자이로 센서나 L3G4200D 자이로센서도 마찬가지이다.
이와 같이 변동성이 극히 높은 센서의 측정값을 보다 안정적으로 관찰하기 위해서는 적절한 범위의 저주파 필터링 (Low Pass Filtering) 작업이 필수적이다.




아두이노나 호환 보드인 NodeMCU 또는 weMos 보드를 사용할 경우에는 아래와 같이 간단한 알고리듬으로 소프트웨어적인 디지털 저주파 필터링이 가능하다.




즉 미세먼지 신호 값 즉 dustDensity를 측정하여 사용한 후에 이 값을 previous_dustDensity 로 두어 위의 공식에서처럼 가중 평균하여 사용하는 것이다. 이미 드론에서 검증된 0.2에서 0.3 사이의 α 값을 사용해 본 결과 적절한 저주파 필터링이 이루어진다고 판단되며 미세먼지에서도 0.8을 사용하여 출력한 결과가 상기 그래프이다.


Webserver_html_svg_realtime_PM_LF_01


#include <ESP8266WiFi.h>
#include <DHT11.h>
 
 const char* ssid = "android1234";//무선 공유기 id로 수정
 const char* password = "dddddddddd";//무선 공유기 비빌번호

 int ledPin = 2; //빌트인
 int pin = D5; //온습도센서 GPIO 14번
 int measurePin = 0; //Connect PM sensor to Arduino A0 pin
 int ledPower = 16;   //GPIO 16번

 int samplingTime = 280;
 int deltaTime = 40;
 int sleepTime = 9680;

 float voMeasured = 0;
 float calcVoltage = 0;
 float previous_dustDensity = 0;
 float dustDensity = 0;
 float alpha =0.8;
 
 WiFiServer server(80);
 DHT11 dht11(pin);
 
 void setup() {
   Serial.begin(115200);
   delay(10);

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

   pinMode(ledPower,OUTPUT);// 미세먼지 센서 내부 LED

   // Set WiFi to station mode and disconnect from an AP
   WiFi.mode(WIFI_STA);
   WiFi.disconnect();
   delay(100);

   Serial.println("Setup done");

   // Connect to WiFi network
   Serial.println();
   Serial.println();
   Serial.print("Connecting to ");
   Serial.println(ssid);

   WiFi.begin(ssid, password);

   while (WiFi.status() != WL_CONNECTED) {
     delay(500);
     Serial.print(".");
   }
   Serial.println("");
   Serial.println("WiFi connected");

   // Start the server
   server.begin();
   Serial.println("Server started");

   // Print the IP address
   Serial.print("Use this URL to connect: ");
   Serial.print("http://");
   Serial.print(WiFi.localIP());
   Serial.println("/");

 }

 void loop() {
   // Check if a client has connected
   WiFiClient client = server.available();
   if (!client) {
     return;
   }

   // Wait until the client sends some data
   Serial.println("new client");
   while(!client.available()){
     delay(1);
   }

//미세먼지 루틴
     dustDensity = particleSensing();
     Serial.print("P ");
     Serial.println((int)dustDensity);
 
 // Temperature & Humidity Sensing
   int err;
   float temp, humi;
   if((err=dht11.read(humi, temp))==0)
   {
//     Serial.print("temperature:");
     Serial.print("C ");
     Serial.println((int)temp);
//     Serial.print(" humidity:");
     Serial.print("H ");
     Serial.print((int)humi);
     Serial.println();
   }
   else                              
   {
     Serial.println();
     Serial.print("Error No :");
     Serial.print(err);
     Serial.println();   
   }

   // Read the first line of the request
   String request = client.readStringUntil('\r');
   Serial.println(request);
   client.flush();

   // Match the request
   int value = LOW;
   if (request.indexOf("/LED=ON") != -1)  {
     digitalWrite(ledPin, LOW);
     value = HIGH;
   }


 // Return the response
   client.println("HTTP/1.1 200 OK");
   client.println("Content-Type: text/html");
   client.println(""); //  do not forget this one
   client.println("<!DOCTYPE HTML>");
   client.println("<html>");
  
   //배경 색 문자 색 사이즈 HTML CSS 설정  
   client.println("<head>");
   client.println("<style>");
   client.println("body {");
   client.println("background-color: yellow;");
   client.println("}");
   client.println("p {");
   client.println("color:red;");
   client.println("font-size:150%;");
   client.println("}");
    client.println("</style>"); 
    client.println("<title>Page Title</title>");
    client.println("<h2> Arduino WiFi PM Scope</h2>"); 
    client.println("</head>");
     client.println("<body>");
   client.println("<p>");
     client.print(" Temperature = ");
     client.print((int)temp);
     client.print(" C ");
     client.println("<br>");
     client.print(" Humidity    = ");
     client.print((int)humi);
     client.println(" % ");
     client.println("</p>");
     client.println("</body>");
    
     client.println("<body>");
     client.println("<svg height='300' width='500'>");
     client.println("<rect height='300' width='500' style='fill:rgb(120,250,40);stroke-width:8;stroke:rgb(0,0,0)' />");
     client.println("<rect height='250' width='500' style='fill:rgb(0,220,230);stroke-width:8;stroke:rgb(0,0,0)' />");
     int val = (1.0-alpha)*previous_dustDensity+alpha*dustDensity;
     int y1 = 300-val; 
     for(int i=2;i<500;i++){
     int x1 = (i-1);
     int x2 = i;
     dustDensity = particleSensing();
     if( dustDensity > 300.0 )  {
       dustDensity = 300.0;
     }
     val = (1.0-alpha)*previous_dustDensity+alpha*dustDensity;
     int y2 = 300-val;
     client.println("<line x1='");
     client.println(x1);
     client.println("' y1='");
     client.println(y1);
     client.println("' x2='"); 
     client.println(x2);
     client.println("' y2='");
     client.println(y2);
     client.println("'");
     client.println("' style='stroke:rgb(255,0,0);stroke-width:2' />");
     client.println("Sorry, your browser does not support inline SVG.");
     y1 = y2;
     client.println("<rect height='40' width='70' style='fill:rgb(0,220,230);stroke-width:2;stroke:rgb(255,255,255)' />");
     client.print("<text x='15' y='29' font-size='150%' fill='black' > ");
     client.print(val);
     client.print("</text>");
     }
     client.println("</svg>");
     client.flush();
     client.println("<br><br>");
 
//버튼 HTML CSS 설정  
    client.println("<head>");
    client.println("<style>");
    client.println(".button {");
//    client.println("background-color: #4CAF50;");
    client.println("background-color: green;");
    client.println("border: none;");
    client.println("color: white;");
    client.println("padding: 15px 32px;");
    client.println("text-align: center;");
    client.println("text-decoration: none;");
    client.println("display: inline-block;");
    client.println("font-size: 10px;");
    client.println("margin: 14px 20px;");
    client.println("cursor: pointer;");
    client.println("}");   
    client.println("</style>");
    client.println("</head>");
   
  // client.println("<a href=\"/on\"\"><button>Data Refresh </button></a><br />");
      client.println("<a href=\"/on\"\" class='button'>Data Refresh </button></a>");
   client.println("</body>");          
   client.println("</html>");
  
  
   delay(1);
   Serial.println("Client disonnected");
   Serial.println("");


 }//loop문 끝

float particleSensing() {

  digitalWrite(ledPower,LOW); // power on the LED
  delayMicroseconds(samplingTime);
   voMeasured = analogRead(measurePin);
 
  delayMicroseconds(deltaTime);
  digitalWrite(ledPower,HIGH); // turn the LED off
  delayMicroseconds(sleepTime);
  
  // 0 - 5V mapped to 0 - 1023 integer values
  calcVoltage = voMeasured * (5.0 / 1024.0);
  if( calcVoltage > 0.6 ) {
  dustDensity =1000.0*( 0.172 * calcVoltage - 0.1);
 
//  Serial.print("Digital Value(0-1023): ");
//  Serial.print(voMeasured);
 
//  Serial.print(" - V: ");
//  Serial.print(calcVoltage);
 
  Serial.print(" - Density: ");
  Serial.println(dustDensity); // unit: ug/m3
//  delay(1000);
  delay(190);
  }
  return dustDensity;
}//끝