Датчики серии MQ-* и библиотека TroykaMQ

Тема в разделе "Схемотехника, компоненты, модули", создана пользователем Андрей Новичок, 20 сен 2018.

Метки:
  1. Реализация для MQ-4 с учётом модели влажности и температуры.
    Это для таких извращенцев как я :)
    Код (C++):
    //For users MQ-4 sensors
    //This example using model "value dependence on temperature and humidity"
    //Data sheet - https://www.winsen-sensor.com/d/files/PDF/Semiconductor%20Gas%20Sensor/MQ-4%20(Ver1.4)%20-%20Manual.pdf
    //mq4_schematic - http://wiki.amperka.ru/_media/%D0%BF%D1%80%D0%BE%D0%B4%D1%83%D0%BA%D1%82%D1%8B:mq4:troyka-mq4_schematic.png
    //Pre-heating MQ-4 sensor done early (at 168 hours)
    //The stand contains one MQ-4 sensor and one DHT-11 sensor for simpe example using MQ-4.

    //Value dependence on temperature and humidity
    // 1. Bounds.
    //Humidity 0.0 ... 1.0 (0% ... 100% relative humidity)
    //Temperature -10 deg. Cel. to 50 deg. Cel. But, when we using DHT-11, bounds shifting from 0 deg. Celcius to 50 deg. Celcius.
    //ppm 200 ... 10000 ppm
    // 2. Digitalized model from Data sheet, "Fig4. Typical temperature/humidity characteristics"
    //k_hum = 0.00672096284322792*Hum + (-0.0159038179354688);
    //b_hum = -0.741244323718154*Hum + 1.77535862501753;
    // Model "dependence on temperature and humidity" RsR0 = RsR0_getting*(k_hum*temp + b_hum);
    // 3. Constants.
    //U0 in the clean air previously obtained concrete instance of the sensor MQ-4. Its value U0=92 from 1024 on analog pin.
    //When Rs/R0 = ((1024/Us)-1)/((1024/U0)-1), then Rs/R0 = ((1024/Us)-1)*U0_const_clean_air.
    //U0_const_clean_air = 1/((1024/U0)-1) = 0,0987124463519313
    //For concrete instance of the sensor MQ-4 in the middle temperature and middle humidity was obtained shifting value Rs/R0 in clean air was getting from "U0_const_clean_air" with using model "value dependence on temperature and humidity"
    //RsR0_clean_air = 1,31848506314236

    #include <DHT.h> //For get actual temperature and humidity.
    #define DHT_PIN 2
    #define PIN_MQ4  A1

    //Constants for MQ-4
    #define Tconfidential_interval 3600000 //3600000 = One hour pre-heating needs for get stable value; your may using 40 minites or more every time after turn on the controller
    #define U0_const_clean_air 0.09871245 // 1/((1024/U0)-1) = 0,0987124463519313, then ADC value = 92.
    #define RsR0_clean_air_model_coefficient 1.318485 // Error of model then was getting Rs/R0 in clean air: Rs/R0 on data sheet = 1, then we using model Rs/R0 = 1.318485 (~32%): http://forum.amperka.ru/attachments/%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C-%D1%87%D0%B8%D1%81%D1%82%D0%BE%D0%B3%D0%BE-%D0%B2%D0%BE%D0%B7%D0%B4%D1%83%D1%85%D0%B0-%D1%82%D0%B5%D0%BC%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D1%83%D1%80%D0%B0-%D0%B8-%D0%B2%D0%BB%D0%B0%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D1%8C-png.16701/
    #define Refresh_H_n_T_period 20000 //300000 = 5 minutes. In millis, its for your choice, min - about 20000 ms. But better - minimum time reaction as a minimum time reaction of all components: DHT reaction - 2-5 minutes.
    #define Output_period 20000 //60000 - One minute

    //Humidity and temperature variables
    float Hum=0.0;
    float temp=0.0;

    DHT dht; //dht init.
    void setup() {
      Serial.begin(9600); Serial.println("------------ Starting ------------");
      dht.setup(DHT_PIN);
    }


    void loop() {
      String DataMessage;
      int Uadc;

      Refresh_Hum_n_Temp_values();

      if (millis()<Tconfidential_interval){
        delay(2000);
        Uadc = analogRead(PIN_MQ4);
        DataMessage+="Current value ADC = "; DataMessage+=String(Uadc); Serial.print(DataMessage);
        DataMessage ="; Heating is performed on "; DataMessage+=String((millis()/float(Tconfidential_interval))*100); DataMessage +="%; Minutes left: "; DataMessage+=String((float(Tconfidential_interval)-millis())/60000);Serial.println(DataMessage);Serial.println("--------------------------------------------------------------------------------");
      }
      else{
        Uadc = analogRead(PIN_MQ4);
        delay(Output_period);
        Serial.println("-------------------------");
        ppm_model(Uadc);
        ppm_model_hum_n_tepm(Uadc);
      }
    }

    void Refresh_Hum_n_Temp_values(){
      //This is not real-time timer, only for this example
      static unsigned long previousMillis;
      if (millis() - previousMillis > Refresh_H_n_T_period){
        previousMillis=millis();
        //Get humidity and temperature variables from DHT-11
        delay(dht.getMinimumSamplingPeriod());
        temp = dht.getTemperature();
        Hum = (dht.getHumidity())/100;
      }
    }

    void ppm_model(int ADC_value){
      //Get ppm by model free from humidity and tempereature
      unsigned int MyPPM=(23.99428*pow(((1024/(float(ADC_value)-1)*U0_const_clean_air)/RsR0_clean_air_model_coefficient),-1.659292));//http://forum.amperka.ru/attachments/formula5-png.16324/
      Serial.print("PPM_MODEL free hum and temp = ");Serial.println(MyPPM);
    }

    void ppm_model_hum_n_tepm(int ADC_value){
      float RsR0=((1024/(float(ADC_value)-1)*U0_const_clean_air)); Serial.print("--- RsR0, not corrected =  ");Serial.println(RsR0,6);
      float Correction_hum_n_temp; Serial.print("--- Hum = "); Serial.print(Hum*100,0);Serial.print(", temp = ");Serial.print(temp,0);Serial.print(", ");

      if(Hum <= 0 or Hum >= 0.95 or temp <=0 or temp >=60 ){
        Correction_hum_n_temp = 1.0;
        Serial.println("Out of limit, using typical values: Correction_hum_n_temp = 1");
      }else{
        float k_hum = 0.00672096284322792*Hum + (-0.0159038179354688);
        float b_hum = -0.741244323718154*Hum + 1.77535862501753;
        //Serial.print("k_hum = ");Serial.print(k_hum);Serial.print(", b_hum =");Serial.println(b_hum);
        Correction_hum_n_temp = (k_hum*temp + b_hum)/RsR0_clean_air_model_coefficient;
        Serial.print("Correction_hum_n_temp =");Serial.println(Correction_hum_n_temp,6);
      }

      RsR0 = RsR0*Correction_hum_n_temp; Serial.print("--- RsR0 corrected =  ");Serial.println(RsR0,6);
      float MyPPM=(23.99428*pow(RsR0,-1.659292)); Serial.print("PPM_MODEL hum and temp correction = ");Serial.println(MyPPM);
    }
    Теперь давайте посмотрим, что эта модель нам даёт. Измерения проводились по-быстрому, вместе с подготовкой измерения заняли где-то час. Правильно, конечно, измерять в течении длительного времения, так, чтобы захватить несколько периодов длиной в сутки с их периодичность тепмературы и влажности. Но и того что было сделано для демонстрации должно быть достаточно.
    Пример применения модели влажности и температуры по-быстрому.png
    Чисто теоретически нормированные графики должны были почти совпасть, и это "почти", т.е. небольшая разница и должна была стать результатом сравнения моделей с учётом температуры и влажности, а также без их учёта. Но поскольку, я делал всё по-быстрому, вылезли дополнительные погрешности в виде несовершенных датчиков DHT-11 с их инертностью, которая составляет 2-5 минут + конденсат.
    Модель то, конечно, работает, но посмотрим какой у нас результат? Ха-ха-ха, - всего 1% разницы. С учётом других погрешностей в районе 30% не бог весть что.
    Это не означает, что следует пренебрегать компенсацией температуры и влажности. На длинных дистанциях, таких, как "сезон" (зима, весна, лето, осень) очень может пригодиться. Для кратковременных измерений - точно нет. Если говорим о сезонах, то с учётом того, что датчик MQ-XX служит максимум 5 лет, получаем кол-во сезонов в количестве 20 штук. Надо заморачиваться с температурой и влажностью или нет здесь решает каждый сам.
    Потом, датчик работает в комнатных условиях, во всяком случае под крышей/навесом, в сарае, котельной и т.п. Если, скажем, в комнате 8 кв. метров (Data sheet) находятся 2 человека с температурой 36,6, то каждый из них выдыхает СО2, пукает, потеет, осуществляет какую-то деятельность. Не знаю, какая поверхность кожи у человека, но по-любому она больше, чем у вашего маслянного нагревателя, используемого в межсезонье. Если прилетят инопланетяне, посмотрят на нас в нашей среде обитания, то сразу испугаются и улетят обратно в свою далёкую галактику :). Это я к тому, что деятельность Человека на объекте измерения не поддаётся анализу и мы можем получить вообще странные показания, даже если они правдивые. Поэтому я, лично, вижу возможность использования датчиков MQ-XX с учётом температуры и влажности на удалённых объектах без Человека.
    В общем, я поделился своим мнением, а как поступать каждый решает сам.

    ------------------------------------------------------------------------------------------------------------------------
    ДОБАВЛЕНО 12.05.2019. Ошибки в модели.
    Была допущена ошибка в определении ppm:
    ppm_model()
    БЫЛО не правильно:
    СТАЛО правильно:
    ppm_model_hum_n_tepm()
    БЫЛО не правильно:
    СТАЛО правильно:
    Ошибка уже исправлена в коде выше, можно пользоваться. Приношу извинения :(.
     

    Вложения:

    Последнее редактирование: 12 май 2019
  2. В принципе, я получил, что хотел. Остался пока один вопрос: что такое "Power of Sensitivity body"?
    Выдержка из Data sheet Power of Sensitivity body (Ps): Ps=Vc^2×Rs/(Rs+RL)^2
    Где Vc - измеряемое нами напряжение, Rs - измеренное нами сопротивление, а RL - сопротивление установленное на датчик.
    Размерность этой Ps есть Вольт квадрат на Ом. Чем ниже RL, тем выше "сила чувствительности". Это и дураку понятно, смысл какой в этом?
    Со значениями RL я разобрался - проще простого. Может так задаются потенциально возможные значения АЦП (диапазон)? Может мне кто грамотно объяснить?
     
  3. Так задаются потенциально возможные значения АЦП.
     
  4. Здравствуйте, товарищи.
    Итоги.
    Данный пост был сформирован в результате политики газовых компаний, которые по указанию государства действительно снизили цену на подключение газа, но монетизировали свой недополученный доход в виде дополнительных услуг, от которых, как оказалось, не возможно отказаться :). Я был злой и решил рассмотреть альтернативные варианты. Выбор пал на проекты ARDUINO, и на самую, как мне кажется, лучшую компанию в своём сегменте - Амперку.
    В процессе изучения библиотеки для датчиков MQ-XX выявилось много косяков, с чего, собственно пост и начинается.
    К сожалению, изысканиями пришлось заниматься совершенно самостоятельно, т.к. на формуе я техподдержки не получил (ну может быть несколько лайков от приятных собеседников).
    Результаты все могут увидеть выше. Они не очень презентабельные, скажем так. Но зато совершенно бесплатные. Даже если я где-то накосясил, то всё равно, общий подход считаю верным.
    Использованные материалы:

    До того, как я ещё не стал злым от реакции на суровую действительность об ARDUINO не знал вообще ничего, кроме каких-то упоминаний в некоторых статьях. Мои проблемы давно решены, дело было в вентиляции, что кстати, не только по наитию, но и по результатам измерений удалось зафиксировать, и, в дальнейшем, решить. Так что закупленные компоненты для мини-проекта себя финансово точно "отбили". И самое главное, - я получил удовольствие от такой работы. Всех агитирую заниматься проектами ARDUINO!

    В общем всё, я кончил! :)
     
    parovoZZ нравится это.