diff --git a/components/sensors/gas/MQSensorLIB/CMakeLists.txt b/components/sensors/gas/MQSensorLIB/CMakeLists.txt new file mode 100644 index 000000000..bc4487a65 --- /dev/null +++ b/components/sensors/gas/MQSensorLIB/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS "MQUnifiedsensor.cpp" + INCLUDE_DIRS "include" + REQUIRES driver +) diff --git a/components/sensors/gas/MQSensorLIB/CODE_OF_CONDUCT.md b/components/sensors/gas/MQSensorLIB/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..f4962952f --- /dev/null +++ b/components/sensors/gas/MQSensorLIB/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at cghiordy@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/components/sensors/gas/MQSensorLIB/CONTRIBUTING.md b/components/sensors/gas/MQSensorLIB/CONTRIBUTING.md new file mode 100644 index 000000000..7c09c7396 --- /dev/null +++ b/components/sensors/gas/MQSensorLIB/CONTRIBUTING.md @@ -0,0 +1,26 @@ +# Contributing + +When contributing to this repository, please first discuss the change you wish to make via issue, +email, or any other method with the owners of this repository before making a change. + +Please note we have a code of conduct, please follow it in all your interactions with the project. + +## Pull Request Process + +1. Ensure any install or build dependencies are removed before the end of the layer when doing a + build. +2. Create a new branch with a keyword of your contribution or main issue. +3. Update the README.md with details of changes to the new features or fixed settings done. +4. Commit your additions and deletions, or new files to the branch created previously. +5. When the changes are stable and run effectively, make a pull request to master branch. + +## Review of pull request + +Pull request will be check by three main authors who are linked in +[REAMDE.md](https://github.com/miguel5612/MQSensorsLib/README.md) and they determine to merge to +master branch. Later than assessment and debbuging procedures was completed, the contribution +will be released. + +## Versioning + +When making a pull request, please remember to update the `library.properties` file to reflect the changes you've made. If your change is minor, consider advancing the version by 0.01. If you're adding a new feature, you may want to advance the version by a whole number. \ No newline at end of file diff --git a/components/sensors/gas/MQSensorLIB/LICENSE b/components/sensors/gas/MQSensorLIB/LICENSE new file mode 100644 index 000000000..bc94fc5ff --- /dev/null +++ b/components/sensors/gas/MQSensorLIB/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Miguel Angel Califa Urquiza + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/components/sensors/gas/MQSensorLIB/MQUnifiedsensor.cpp b/components/sensors/gas/MQSensorLIB/MQUnifiedsensor.cpp new file mode 100644 index 000000000..d54df39a9 --- /dev/null +++ b/components/sensors/gas/MQSensorLIB/MQUnifiedsensor.cpp @@ -0,0 +1,293 @@ +#include "MQUnifiedsensor.h" +#include "espidf_adc_helper.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include +#include + +#define retries 2 +#define retry_interval 20 + +MQUnifiedsensor::MQUnifiedsensor(float Voltage_Resolution, int ADC_Bit_Resolution, int pin, const char* type) { + this->_pin = pin; + strncpy(this->_type, type, sizeof(this->_type)-1); + this->_type[sizeof(this->_type)-1] = '\0'; + this->_VOLT_RESOLUTION = Voltage_Resolution; + this->_VCC = Voltage_Resolution; + this->_ADC_Bit_Resolution = ADC_Bit_Resolution; +} +static inline double safePow(double base, double exp){ + if(exp == 0.0) return 1.0; + if(exp == 1.0) return base; + if(exp == 2.0) return base * base; + return pow(base, exp); +} +static inline bool willOverflow(double log_ppm){ + static const double maxLog = log10((double)FLT_MAX); + static const double minLog = log10((double)FLT_MIN); + return (log_ppm > maxLog || log_ppm < minLog); +} + +void MQUnifiedsensor::setA(float a) { + if(isinf(a) || isnan(a)) { + this->_a = 0; + } else if(a > MQ_MAX_A) { + this->_a = MQ_MAX_A; + } else if(a < -MQ_MAX_A) { + this->_a = -MQ_MAX_A; + } else { + this->_a = a; + } +} +void MQUnifiedsensor::setB(float b) { + if(isinf(b) || isnan(b)) { + this->_b = 0; + } else if(b > MQ_MAX_B) { + this->_b = MQ_MAX_B; + } else if(b < -MQ_MAX_B) { + this->_b = -MQ_MAX_B; + } else { + this->_b = b; + } +} +void MQUnifiedsensor::setR0(float R0) { + this->_R0 = R0; +} +void MQUnifiedsensor::setRL(float RL) { + this->_RL = RL; +} +void MQUnifiedsensor::setADC(int value) +{ + this-> _sensor_volt = (value) * _VOLT_RESOLUTION / ((pow(2, _ADC_Bit_Resolution)) - 1); + this-> _adc = value; +} +void MQUnifiedsensor::setVoltResolution(float voltage_resolution) +{ + _VOLT_RESOLUTION = voltage_resolution; +} +void MQUnifiedsensor::setVCC(float vcc) +{ + _VCC = vcc; +} +void MQUnifiedsensor::setPin(int pin) { + this->_pin = pin; +} +void MQUnifiedsensor::setRegressionMethod(int regressionMethod) +{ + //this->_regressionMethod = regressionMethod; + this->_regressionMethod = regressionMethod; +} +float MQUnifiedsensor::getR0() { + return _R0; +} +float MQUnifiedsensor::getRL() { + return _RL; +} +float MQUnifiedsensor::getVoltResolution() +{ + return _VOLT_RESOLUTION; +} +float MQUnifiedsensor::getVCC() +{ + return _VCC; +} +const char* MQUnifiedsensor::getRegressionMethod() +{ + return (_regressionMethod == 1) ? "Exponential" : "Linear"; +} +float MQUnifiedsensor::getA() { + return _a; +} +float MQUnifiedsensor::getB() { + return _b; +} +void MQUnifiedsensor::serialDebug(bool onSetup) +{ + if(onSetup) + { + ESP_LOGI("MQUnifiedsensor", "************************************************************************************************************************************************"); + ESP_LOGI("MQUnifiedsensor", "MQ sensor reading library for ESP32"); + ESP_LOGI("MQUnifiedsensor", "Note: remember that all the parameters below can be modified during the program execution with the methods:"); + ESP_LOGI("MQUnifiedsensor", "setR0, setRL, setA, setB where you will have to send as parameter the new value, example: mySensor.setR0(20); //R0 = 20KΩ"); + ESP_LOGI("MQUnifiedsensor", "Authors: Miguel A. Califa U - Yersson R. Carrillo A - Ghiordy F. Contreras C"); + ESP_LOGI("MQUnifiedsensor", "Contributors: Andres A. Martinez - Juan A. Rodríguez - Mario A. Rodríguez O "); + ESP_LOGI("MQUnifiedsensor", "Contributor for ESP32: Carlos Delfino"); + ESP_LOGI("MQUnifiedsensor", "Sensor: %s", _type); + ESP_LOGI("MQUnifiedsensor", "ADC voltage: %.2f VDC", _VOLT_RESOLUTION); + ESP_LOGI("MQUnifiedsensor", "Sensor supply (VCC): %.2f VDC", _VCC); + ESP_LOGI("MQUnifiedsensor", "ADC Resolution: %d Bits", _ADC_Bit_Resolution); + ESP_LOGI("MQUnifiedsensor", "R0: %.2f KΩ", _R0); + ESP_LOGI("MQUnifiedsensor", "RL: %.2f KΩ", _RL); + ESP_LOGI("MQUnifiedsensor", "Model: %s", _regressionMethod == 1 ? "Exponential" : "Linear"); + ESP_LOGI("MQUnifiedsensor", "%s -> a: %.2f | b: %.2f", _type, _a, _b); + ESP_LOGI("MQUnifiedsensor", "Development board: %s", _placa); + } + else + { + if(!_firstFlag) + { + ESP_LOGI("MQUnifiedsensor", "| ******************************************************************** %s *********************************************************************|", _type); + ESP_LOGI("MQUnifiedsensor", "|ADC_In | Equation_V_ADC | Voltage_ADC | Equation_RS | Resistance_RS | EQ_Ratio | Ratio (RS/R0) | Equation_PPM | PPM |"); + _firstFlag = true; //Headers are printed + } + else + { + ESP_LOGI("MQUnifiedsensor", "| %d | v = ADC*%.2f/%d | %.2f | RS = ((%.2f*%.2f)/%.2f) - %.2f | %.2f | %.2f | %.2f | %s | %.2f |", + _adc, _VOLT_RESOLUTION, (pow(2, _ADC_Bit_Resolution)) - 1, _sensor_volt, + _VCC, _RL, _sensor_volt, _RL, _RS_Calc, _ratio, + _regressionMethod == 1 ? "ratio*a + b" : "pow(10, (log10(ratio)-b)/a)", _PPM); + } + } +} +void MQUnifiedsensor::update() +{ + _sensor_volt = this->getVoltage(); +} +void MQUnifiedsensor::externalADCUpdate(float volt) +{ + _sensor_volt = volt; +} +float MQUnifiedsensor::validateEcuation(float ratioInput) +{ + double ppm; + if(_regressionMethod == 1){ + if(ratioInput <= 0 || _a == 0) return 0; + double logppm = log10((double)_a) + (double)_b * log10((double)ratioInput); + if(willOverflow(logppm)) ppm = (logppm > 0) ? FLT_MAX : 0.0; + else ppm = safePow(10.0, logppm); + } + else + { + if(ratioInput <= 0 || _a == 0) return 0; + double logppm = (log10((double)ratioInput)-(double)_b)/(double)_a; + if(willOverflow(logppm)) ppm = (logppm > 0) ? FLT_MAX : 0.0; + else ppm = safePow(10.0, logppm); + } + if(isinf(ppm) || isnan(ppm)) ppm = FLT_MAX; + _PPM = (float)ppm; + return _PPM; +} +float MQUnifiedsensor::readSensor(bool isMQ303A, float correctionFactor, bool injected) +{ + //More explained in: https://jayconsystems.com/blog/understanding-a-gas-sensor + + float voltRes = _VOLT_RESOLUTION; // preserve global resolution + if(isMQ303A) { + voltRes = voltRes - 0.45; //Calculations for RS using mq303a sensor look wrong #42 + } + _RS_Calc = ((_VCC*_RL)/_sensor_volt)-_RL; //Get value of RS in a gas + if(_RS_Calc < 0) _RS_Calc = 0; //No negative values accepted. + if(!injected) _ratio = _RS_Calc / this->_R0; // Get ratio RS_gas/RS_air + _ratio += correctionFactor; + if(_ratio <= 0) _ratio = 0; //No negative values accepted or upper datasheet recommendation. + double ppm; + if(_regressionMethod == 1){ + if(_ratio <= 0 || _a == 0) return 0; + double logppm = log10((double)_a) + (double)_b * log10((double)_ratio); + if(willOverflow(logppm)) ppm = (logppm > 0) ? FLT_MAX : 0.0; + else ppm = safePow(10.0, logppm); + } + else + { + if(_ratio <= 0 || _a == 0) return 0; + double logppm = (log10((double)_ratio)-(double)_b)/(double)_a; + if(willOverflow(logppm)) ppm = (logppm > 0) ? FLT_MAX : 0.0; + else ppm = safePow(10.0, logppm); + } + if(ppm < 0) ppm = 0; //No negative values accepted or upper datasheet recommendation. + if(isinf(ppm) || isnan(ppm)) ppm = FLT_MAX; + _PPM = (float)ppm; + //if(_PPM > 10000) _PPM = 99999999; //No negative values accepted or upper datasheet recommendation. + return _PPM; +} +float MQUnifiedsensor::readSensorR0Rs(float correctionFactor) +{ + //More explained in: https://jayconsystems.com/blog/understanding-a-gas-sensor + _RS_Calc = ((_VCC*_RL)/_sensor_volt)-_RL; //Get value of RS in a gas + if(_RS_Calc < 0) _RS_Calc = 0; //No negative values accepted. + _ratio = this->_R0/_RS_Calc; // Get ratio RS_air/RS_gas <- INVERTED for MQ-131 issue 28 https://github.com/miguel5612/MQSensorsLib/issues/28 + _ratio += correctionFactor; + if(_ratio <= 0) _ratio = 0; //No negative values accepted or upper datasheet recommendation. + double ppm; + if(_regressionMethod == 1){ + if(_ratio <= 0 || _a == 0) return 0; + double logppm = log10((double)_a) + (double)_b * log10((double)_ratio); + if(willOverflow(logppm)) ppm = (logppm > 0) ? FLT_MAX : 0.0; + else ppm = safePow(10.0, logppm); + } + else + { + if(_ratio <= 0 || _a == 0) return 0; + double logppm = (log10((double)_ratio)-(double)_b)/(double)_a; + if(willOverflow(logppm)) ppm = (logppm > 0) ? FLT_MAX : 0.0; + else ppm = safePow(10.0, logppm); + } + if(ppm < 0) ppm = 0; //No negative values accepted or upper datasheet recommendation. + if(isinf(ppm) || isnan(ppm)) ppm = FLT_MAX; + _PPM = (float)ppm; + //if(_PPM > 10000) _PPM = 99999999; //No negative values accepted or upper datasheet recommendation. + return _PPM; +} +float MQUnifiedsensor::calibrate(float ratioInCleanAir, float correctionFactor) { + //More explained in: https://jayconsystems.com/blog/understanding-a-gas-sensor + /* + V = I x R + VRL = [VC / (RS + RL)] x RL + VRL = (VC x RL) / (RS + RL) + Así que ahora resolvemos para RS: + VRL x (RS + RL) = VC x RL + (VRL x RS) + (VRL x RL) = VC x RL + (VRL x RS) = (VC x RL) - (VRL x RL) + RS = [(VC x RL) - (VRL x RL)] / VRL + RS = [(VC x RL) / VRL] - RL + */ + float RS_air; //Define variable for sensor resistance + float R0; //Define variable for R0 + RS_air = ((_VCC*_RL)/_sensor_volt)-_RL; //Calculate RS in fresh air + if(RS_air < 0) RS_air = 0; //No negative values accepted. + R0 = RS_air/ratioInCleanAir; //Calculate R0 + R0 += correctionFactor; + if(R0 < 0) R0 = 0; //No negative values accepted. + return R0; +} +float MQUnifiedsensor::getVoltage(bool read, bool injected, int value) { + float voltage; + if(read) + { + float avg = 0.0; + for (int i = 0; i < retries; i ++) { + _adc = espidf_analogRead(this->_pin, _ADC_Bit_Resolution); + avg += _adc; + vTaskDelay(retry_interval / portTICK_PERIOD_MS); + } + voltage = (avg/ retries) * _VOLT_RESOLUTION / ((pow(2, _ADC_Bit_Resolution)) - 1); + } + else if(!injected) + { + voltage = _sensor_volt; + } + else + { + voltage = (value) * _VOLT_RESOLUTION / ((pow(2, _ADC_Bit_Resolution)) - 1); + _sensor_volt = voltage; //to work on testing + } + return voltage; +} +float MQUnifiedsensor:: setRsR0RatioGetPPM(float value) +{ + _ratio = value; + return readSensor(false, 0, true); +} +float MQUnifiedsensor::getRS() +{ + //More explained in: https://jayconsystems.com/blog/understanding-a-gas-sensor + _RS_Calc = ((_VCC*_RL)/_sensor_volt)-_RL; //Get value of RS in a gas + if(_RS_Calc < 0) _RS_Calc = 0; //No negative values accepted. + return _RS_Calc; +} + +float MQUnifiedsensor::stringTofloat(const char* str) +{ + return str ? atof(str) : 0.0f; +} diff --git a/components/sensors/gas/MQSensorLIB/README.md b/components/sensors/gas/MQSensorLIB/README.md new file mode 100644 index 000000000..7c9a254c1 --- /dev/null +++ b/components/sensors/gas/MQSensorLIB/README.md @@ -0,0 +1,294 @@ + + +[![DOI](https://zenodo.org/badge/170540207.svg)](https://zenodo.org/badge/latestdoi/170540207) +![Build Status][build-url] +[![Contributors][contributors-shield]][contributors-url] +[![Forks][forks-shield]][forks-url] +[![Stargazers][stars-shield]][stars-url] +[![Issues][issues-shield]][issues-url] +[![MIT License][license-shield]][license-url] +[![LinkedIn][linkedin-shield]][linkedin-url] + +# MQSensorsLib + +We present a unified library for MQ sensors, this library allows to read MQ signals easily from Arduino, Genuino, ESP8266, ESP-32 boards whose references are MQ2, MQ3, MQ4, MQ5, MQ6, MQ7, MQ8, MQ9, MQ131, MQ135, MQ303A, MQ309A. + + +## Table of Contents + +* [Getting Started](#Getting-Started) +* [Wiring](#Wiring) + * [Sensor](#Sensor) + * [Arduino](#Arduino) + * [ESP8266 or ESP-32](#ESP8266-ESP32) +* [User Manual](#Manuals) +* [Sensor manufacturers](#Sensor-manufacturers) +* [Contributing](#Contributing) +* [Authors](#Authors) +* [Be a sponsor 💖](#Sponsor) + +## Getting Started + +### ESP32 Example + +```cpp +// Include the library +#include +/************************Hardware Related Macros************************************/ +#define Board ("ESP-32") +#define Pin (36) // GPIO36 (VP) is ADC1_CH0 on ESP32 +/***********************Software Related Macros************************************/ +#define Type ("MQ-4") //MQ4 +#define Voltage_Resolution (3.3) +#define ADC_Bit_Resolution (12) // ESP32 ADC resolution +#define RatioMQ4CleanAir (4.4) //RS / R0 = 60 ppm +/*****************************Globals***********************************************/ +// Declare Sensor +MQUnifiedsensor MQ4(Board, Voltage_Resolution, ADC_Bit_Resolution, Pin, Type); +// Setup +MQ4.setRegressionMethod("Exponential"); //_PPM = a*ratio^b +MQ4.setA(1012.7); MQ4.setB(-2.786); // Configure the equation to calculate CH4 concentration +MQ4.setR0(3.86018237); // Value obtained on calibration +// Loop +MQ4.init(); +MQ4.update(); +float ppmCH4 = MQ4.readSensor(); +``` + +Para outros exemplos, consulte a pasta `examples/ESP32/` do repositório original. + +## Wiring +### Sensor +#### Important points: +##### Points you should identify +* VCC -> 5V Power supply (+) wire +* GND -> GND Ground (-) wire +* AO -> Analog Output of the sensor +##### Data of board that you should have +* RL Value in KOhms +* If the sensor uses a different supply voltage than the ADC reference, call `yourSensor.setVCC();` +##### Graph +![Wiring_MQSensor](https://raw.githubusercontent.com/miguel5612/MQSensorsLib_Docs/master/static/img/Points_explanation.jpeg) +#### RS/R0 value (From datasheet of your sensor) +* RS/R0 (Clean air - English) -> (Aire puro - Spanish) +* **Note**: RS/R0 is equal to Ratio variable on the program +![Graph from datasheet](https://raw.githubusercontent.com/miguel5612/MQSensorsLib_Docs/master/static/img/Graph_Explanation.jpeg) +### Arduino +![Arduino_Wiring_MQSensor](https://raw.githubusercontent.com/miguel5612/MQSensorsLib_Docs/master/static/img/MQ_Arduino.PNG) +#### MQ-7 / MQ-309A +** Note ** [issue](https://github.com/miguel5612/MQSensorsLib/issues/26): MQ-7 and MQ-309 needs two different voltages for heater, they can be supplied by PWM and DC Signal controlled by your controller, another option is to use two different power sources, you should use the best option for you, next i will show the PWM option and on the examples this will be the way . +![MQ-7_MQ-309](https://raw.githubusercontent.com/miguel5612/MQSensorsLib_Docs/master/static/img/MQ-309_MQ-7.PNG) +### ESP32 Wiring + +![ESP32_Wiring_MQSensor](https://raw.githubusercontent.com/miguel5612/MQSensorsLib_Docs/master/static/img/MQ_ESP32.PNG) + +#### Typical ESP32 Connection +- **A0** (sensor analog output) → **GPIO36 (VP)** on ESP32 +- **VCC** (sensor) → **3.3V** on ESP32 +- **GND** (sensor) → **GND** on ESP32 + +> The ESP32 WROOM 32D does not need an external power supply. For more details and troubleshooting, check the folder `ESP2/ESP32_WROOM_32`. + +### Manuals +#### User Manual (v1.0) 12.2019 +[Manual](https://drive.google.com/open?id=1BAFInlvqKR7h81zETtjz4_RC2EssvFWX) +#### User Manual (v2.0) 04.2020 +[Manual](https://github.com/miguel5612/MQSensorsLib_Docs/blob/master/Docs/MQSensorLib_2.0.pdf) + +### Serial debug (optional) +If your sensor is an **MQ2** (Same for others sensors): +* To enable on setup wrote +``` +MQ2.serialDebug(true); +``` +* And on Loop Wrote +``` +MQ2.serialDebug(); +``` +* Result: + +![Serial debug output](https://github.com/miguel5612/MQSensorsLib_Docs/blob/master/static/img/Serial_Mon_Explanation.jpeg?raw=true) + +**Note**: +* ![#c5f015](https://placehold.it/15/c5f015/000000?text=+) `Yellow -> Calibration status.` +* ![#008000](https://placehold.it/15/008000/000000?text=+) `Green -> Hardware and software characteristics.` +* ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) `Red -> Headers of the library calculations.` +* Only valid for **1** gas sensor readings. + +**Usage** +* Quick troubleshooting, since it shows everything the library does and the results of the calculations in each function. + +### Prerequisites + +You'll need Arduino desktop app 1.8.9 or later. + +### Sensor manufacturers: +| Sensor | Manufacture | URL Datasheet | +|----------|----------|----------| +| MQ-2 | HANWEI Electronics| [datasheet](https://www.pololu.com/file/0J309/MQ2.pdf) | +| MQ-3 | HANWEI Electronics | [datasheet](https://www.sparkfun.com/datasheets/Sensors/MQ-3.pdf) | +| MQ-4 | HANWEI Electronics | [datasheet](https://www.sparkfun.com/datasheets/Sensors/Biometric/MQ-4.pdf) | +| MQ-5 | HANWEI Electronics | [datasheet](https://www.parallax.com/sites/default/files/downloads/605-00009-MQ-5-Datasheet.pdf) | +| MQ-6 | HANWEI Electronics | [datasheet](https://www.sparkfun.com/datasheets/Sensors/Biometric/MQ-6.pdf) | +| MQ-7 | HANWEI Electronics | [datasheet](https://www.sparkfun.com/datasheets/Sensors/Biometric/MQ-7.pdf) | +| MQ-8 | HANWEI Electronics | [datasheet](https://dlnmh9ip6v2uc.cloudfront.net/datasheets/Sensors/Biometric/MQ-8.pdf) | +| MQ-9 | HANWEI Electronics | [datasheet](http://www.haoyuelectronics.com/Attachment/MQ-9/MQ9.pdf) | +| MQ-131 | HANWEI Electronics | [datasheet](http://www.sensorsportal.com/DOWNLOADS/MQ131.pdf) | +| MQ-135 | HANWEI Electronics | [datasheet](https://www.electronicoscaldas.com/datasheet/MQ-135_Hanwei.pdf) | +| MQ-136 | HANWEI Electronics | [datasheet](https://github.com/miguel5612/MQSensorsLib_Docs/blob/master/Datasheets/MQ136%20-%20Hanwei.pdf) | +| MQ-303A | HANWEI Electronics | [datasheet](http://www.kosmodrom.com.ua/pdf/MQ303A.pdf) | +| MQ-309A | HANWEI Electronics | [datasheet](http://www.sensorica.ru/pdf/MQ-309A.pdf) | + +### Info of datasheets + +Review WPDigitalizer [folder](https://github.com/miguel5612/MQSensorsLib_Docs/tree/master/WPDigitalizer) [website](https://automeris.io/WebPlotDigitizer/) + +### Installing + +Clone este repositório em sua máquina local: + +``` +git clone https://github.com/RapportTecnologia/MQSensorsLib-FW-Free.git +``` + + +## Running the tests + +Use calibration systems if you have several sensors that read the same gas. + +### Break down into end to end tests + +These tests can re-adjust values defined previously and you can contribute to improve conditions or features obtained from particular scenes. + +``` +Examples/MQ-3 +``` + +### And coding style tests + +These tests may generate statistics validation using descriptive tools for quantitative variables. + +``` +Examples/MQ-board.ino +``` + +## Built With + +* [Data sheets](https://github.com/miguel5612/MQSensorsLib_Docs/tree/master/Datasheets) - Curves and behavior for each sensor, using logarithmic graphs. +* [Main purpose](https://github.com/miguel5612/MQSensorsLib_Docs/blob/master/static/img/bg.jpg) - Every sensor has high sensibility for a specific gas or material. + +## Issues + +Consulte [docs/issues.md](docs/issues.md) para un resumen de los problemas abiertos y sus soluciones. + +## Contributing + +Please read [CONTRIBUTING.md](https://github.com/miguel5612/MQSensorsLib/blob/master/CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us. + +## Reviewers + +* **PhD. Jacipt A Ramón V.** - [*GitHub*]() - [CV](https://scienti.minciencias.gov.co/cvlac/visualizador/generarCurriculoCv.do?cod_rh=0000512702) + +## Authors + +* **Miguel A. Califa U.** - [*GitHub*](https://github.com/miguel5612) - [CV](https://scienti.colciencias.gov.co/cvlac/visualizador/generarCurriculoCv.do?cod_rh=0000050477) +* **Ghiordy F. Contreras C.** - [*GitHub*](https://github.com/Ghiordy) - [CV](https://scienti.colciencias.gov.co/cvlac/visualizador/generarCurriculoCv.do?cod_rh=0000050476) +* **Yersson R. Carrillo A.** - [*GitHub*](https://github.com/Yercar18/Dronefenix) - [CV](https://scienti.colciencias.gov.co/cvlac/visualizador/generarCurriculoCv.do?cod_rh=0001637655) + +## Collaborators + +* **Andres A. Martinez.** - [*Github*](https://github.com/andresmacsi) - [CV](https://www.linkedin.com/in/andr%C3%A9s-acevedo-mart%C3%ADnez-73ab35185/?originalSubdomain=co) +* **Juan A. Rodríguez.** - [*Github*](https://github.com/Obiot24) - [CV]() +* **Mario A. Rodríguez O.** - [*GitHub*](https://github.com/MarioAndresR) - [CV](https://scienti.colciencias.gov.co/cvlac/visualizador/generarCurriculoCv.do?cod_rh=0000111304) +* **Carlos Delfino** - [*GitHub*](https://github.com/carlosdelfino) - [LinkedIn*](https://www.linkedin.com/in/carlosdelfino) + +See also the list of [contributors](https://github.com/miguel5612/MQSensorsLib/contributors) who participated in this project. + +## License + +This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details + +## Cite as + +* Plain text: Califa Urquiza, Miguel Angel, Contreras Contreras, Ghiordy, & Carrillo Amado, Yerson Ramiro. (2019, September 3). miguel5612/MQSensorsLib: Arduino Preview V1.03 (Version 1.0.3). Zenodo. http://doi.org/10.5281/zenodo.3384301 +* CSL: { + "publisher": "Zenodo", + "DOI": "10.5281/zenodo.3384301", + "title": "miguel5612/MQSensorsLib: Arduino Preview V1.03", + "issued": { + "date-parts": [ + [2019, 9, 3] + ] + }, + "abstract": "

Publishing on Zenodo platform as software in order to extend its applications for other works allowing to recognize MQSensorLib's Authors this work into scientific community using Digital Object Identifier System (DOI).

", + "author": [ + {"family": "Califa Urquiza, Miguel Angel"}, + {"family": "Contreras Contreras, Ghiordy"}, + {"family": "Carrillo Amado, Yerson Ramiro"} + ], + "version": "1.0.3", + "type": "article", + "id": "3384301" +} +* BibTeX: +@misc{califa_urquiza_miguel_angel_2019_3384301, + author = {Califa Urquiza, Miguel Angel and + Contreras Contreras, Ghiordy and + Carrillo Amado, Yerson Ramiro}, + title = {miguel5612/MQSensorsLib: Arduino Preview V1.03}, + month = sep, + year = 2019, + doi = {10.5281/zenodo.3384301}, + url = {https://doi.org/10.5281/zenodo.3384301} +} + +### Cite as (Carlos Delfino) + +* Plain text: Carlos Delfino. ORCID: https://orcid.org/0000-0003-0385-264X +* CSL: { + "author": [ + {"family": "Delfino", "given": "Carlos"} + ], + "URL": "https://orcid.org/0000-0003-0385-264X", + "type": "software", + "id": "carlosdelfino-orcid" +} +* BibTeX: +@misc{carlosdelfino_orcid, + author = {Carlos Delfino}, + title = {Carlos Delfino - ORCID Profile}, + url = {https://orcid.org/0000-0003-0385-264X} +} + + +## Sponsor + +* [Paypal](https://www.paypal.com/paypalme/miguel5612) + +or for Carlos Delfino Studies support: + + * [PIX](nubank@carlosdelfino.com) + + + + +[contributors-shield]: https://img.shields.io/github/contributors/miguel5612/MQSensorsLib.svg?style=flat-square +[contributors-url]: https://github.com/miguel5612/MQSensorsLib/graphs/contributors +[forks-shield]: https://img.shields.io/github/forks/miguel5612/MQSensorsLib.svg?style=flat-square +[forks-url]: https://github.com/miguel5612/MQSensorsLib/network/members +[stars-shield]: https://img.shields.io/github/stars/miguel5612/MQSensorsLib.svg?style=flat-square +[stars-url]: https://github.com/miguel5612/MQSensorsLib/stargazers +[issues-shield]: https://img.shields.io/github/issues/miguel5612/MQSensorsLib.svg?style=flat-square +[issues-url]: https://github.com/miguel5612/MQSensorsLib/issues +[license-shield]: https://img.shields.io/github/license/miguel5612/MQSensorsLib.svg?style=flat-square +[license-url]: https://github.com/miguel5612/MQSensorsLib/blob/master/LICENSE.txt +[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555 +[build-url]: https://travis-ci.org/dwyl/esta.svg?branch=master +[linkedin-url]: https://www.linkedin.com/in/miguel5612 +[product-screenshot]: images/screenshot.png diff --git a/components/sensors/gas/MQSensorLIB/docs/issues.md b/components/sensors/gas/MQSensorLIB/docs/issues.md new file mode 100644 index 000000000..7b2aa1216 --- /dev/null +++ b/components/sensors/gas/MQSensorLIB/docs/issues.md @@ -0,0 +1,33 @@ +# Issues y soluciones + +Este documento resume los problemas reportados en el repositorio y las soluciones propuestas o implementadas. + +## Abiertos + +### #75 MQ-3 sensor and CH4 gas reading 'ovf' failure +**Estado:** resuelto en la rama `main` + +El usuario reporta desbordamiento ("ovf") al utilizar valores muy altos en `setA` y `setB` para leer CH4 con un sensor MQ-3. La solución propuesta es revisar los valores utilizados en `setA` y `setB`, ya que `2*10^31` en C++ no corresponde a `2e31`. Se recomienda usar notación exponencial (`2e31`) o `pow(10,31)` y comprobar que los parámetros no excedan el rango de `float`. + +**Actualización:** se añadieron validaciones de entrada, predicción de desbordamiento mediante logaritmos y verificación del resultado final para evitar valores "ovf" incluso con coeficientes muy altos. Las nuevas funciones limitan `setA` y `setB` y emplean cálculos en doble precisión. + +### #74 possible error in the calculation formula for `_RS_Calc` +**Estado:** resuelto en la rama `work` + +Se detectó que la resistencia del sensor se calculaba con `_VOLT_RESOLUTION` en lugar del voltaje de alimentación real. Se añadieron los métodos `setVCC` y `getVCC` y se modificaron las ecuaciones para usar `VCC`. Esta corrección se refleja en la versión 3.0.1 de la biblioteca. + +### #70 Parameters to model temperature and humidity dependence +**Estado:** resuelto en la rama `work` + +Se añadieron variables opcionales de "correction factor" en todos los ejemplos y se extendieron las funciones `calibrate` y `readSensorR0Rs` para aceptar este parámetro opcional. Así, el usuario puede ajustar las lecturas en función de temperatura y humedad cuando el datasheet lo permita. Los coeficientes deben consultarse para cada sensor. + +### #67 Sensor won't finish the Calibration process if done in clean air +**Estado:** abierto + +Se reporta que la calibración se detiene mostrando un mensaje de "Conection issue" cuando se intenta calibrar el sensor MQ-135 en aire limpio. La recomendación del mantenedor es revisar la conexión física y probar el sensor con un programa básico para asegurar su correcto funcionamiento antes de usar la librería. Aún no se ha implementado un cambio en el código. + + +## Cerrados destacados + +Para obtener más información sobre todos los issues cerrados, consulte la página de [Issues en GitHub](https://github.com/miguel5612/MQSensorsLib/issues?q=is%3Aissue+is%3Aclosed). + diff --git a/components/sensors/gas/MQSensorLIB/include/MQUnifiedsensor.h b/components/sensors/gas/MQSensorLIB/include/MQUnifiedsensor.h new file mode 100644 index 000000000..bd88f865c --- /dev/null +++ b/components/sensors/gas/MQSensorLIB/include/MQUnifiedsensor.h @@ -0,0 +1,74 @@ +#ifndef MQUnifiedsensor_H +#define MQUnifiedsensor_H + +#include +#include +#include + +// Maximum coefficients allowed for the regression model +#define MQ_MAX_A 1e30 +#define MQ_MAX_B 100.0 + +/***********************Software Related Macros************************************/ + +class MQUnifiedsensor +{ + public: + MQUnifiedsensor(float Voltage_Resolution = 5, int ADC_Bit_Resolution = 10, int pin = 1, const char* type = "CUSTOM MQ"); + + //Functions to set values + void init(); + void update(); + void externalADCUpdate(float volt); + void setR0(float R0 = 10); + void setRL(float RL = 10); + void setA(float a); + void setB(float b); + void setRegressionMethod(int regressionMethod); + void setVoltResolution(float voltage_resolution = 5); + void setVCC(float vcc = 5); + void setPin(int pin = 1); + void serialDebug(bool onSetup = false); //Show on serial port information about sensor + void setADC(int value); //For external ADC Usage + void setType(const char* type); + void setBoard(const char* placa); + + //user functions + float calibrate(float ratioInCleanAir, float correctionFactor = 0.0); + float readSensor(bool isMQ303A = false, float correctionFactor = 0.0, bool injected=false); + float readSensorR0Rs(float correctionFactor = 0.0); + float validateEcuation(float ratioInput = 0); + + //get function for info + float getA(); + float getB(); + float getR0(); + float getRL(); + float getVoltResolution(); + float getVCC(); + const char* getRegressionMethod(); + float getVoltage(bool read = true, bool injected = false, int value = 0); + float stringTofloat(const char* str); + + // functions for testing + float getRS(); + float setRsR0RatioGetPPM(float value); + + private: + /************************Private vars************************************/ + uint8_t _pin = 1; + bool _firstFlag = false; + float _VOLT_RESOLUTION = 5.0; // if 3.3v use 3.3 + float _VCC = 5.0; // Sensor supply voltage + float _RL = 10; //Value in KiloOhms + uint8_t _ADC_Bit_Resolution = 10; + uint8_t _regressionMethod = 1; // 1 -> Exponential || 2 -> Linear + + float _adc, _a, _b, _sensor_volt; + float _R0, RS_air, _ratio, _PPM, _RS_Calc; + + char _type[16]; + char _placa[20]; +}; + +#endif //MQUnifiedsensor_H diff --git a/components/sensors/gas/MQSensorLIB/include/espidf_adc_helper.h b/components/sensors/gas/MQSensorLIB/include/espidf_adc_helper.h new file mode 100644 index 000000000..ddb96bd7f --- /dev/null +++ b/components/sensors/gas/MQSensorLIB/include/espidf_adc_helper.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Simple ADC read wrapper for ESP-IDF +static inline int espidf_analogRead(int pin, int bit_width) +{ + adc1_channel_t channel; + // Map pin to ADC1 channel (example for GPIO36-39,32-35 on ESP32) + switch(pin) { + case 36: channel = ADC1_CHANNEL_0; break; + case 37: channel = ADC1_CHANNEL_1; break; + case 38: channel = ADC1_CHANNEL_2; break; + case 39: channel = ADC1_CHANNEL_3; break; + case 32: channel = ADC1_CHANNEL_4; break; + case 33: channel = ADC1_CHANNEL_5; break; + case 34: channel = ADC1_CHANNEL_6; break; + case 35: channel = ADC1_CHANNEL_7; break; + default: return -1; // unsupported pin + } + adc1_config_width(bit_width == 12 ? ADC_WIDTH_BIT_12 : (bit_width == 11 ? ADC_WIDTH_BIT_11 : (bit_width == 10 ? ADC_WIDTH_BIT_10 : ADC_WIDTH_BIT_9))); + adc1_config_channel_atten(channel, ADC_ATTEN_DB_11); // 0-3.6V + return adc1_get_raw(channel); +} + +#ifdef __cplusplus +} +#endif