Table of Contents

Author: Dumitru-Razvan Dinu

Email: dumitru_razvan.dinu@stud.acs.pub.ro

Master: SRIC

Acohol Breath Test 

Introducere

Proiectul constă în realizarea unui test de alcoolemie portabil și accesibil, folosind un microcontroler ESP32, un senzor de alcool MQ-3 și un senzor de temperatură și umiditate DHT11. Scopul acestui proiect este de a dezvolta un dispozitiv compact și eficient care să ofere o estimare rapidă și convenabilă a concentrației de alcool din aerul expirat al utilizatorului.

Desciere generala

Senzorii de temperatura DHT11, impreuna cu senzorul MQ-3 colecteaza pe o fereastra de timp date, ce mai apoi sunt procesate de catre ESP32, ce comunica cu ecranul LCD si aplicatia mobila.

Hardware Design

Componente folosite:

  1. ESP32
  2. MQ-3
  3. Senzor temperatura si umiditate DHT11
  4. Ecran LCD
  5. Buzzer
  6. Breadboard
  7. Fire

Schema electrica:

Transferul de date se realizeaza atat analogic, pentru Senzorul MQ-3, cat si digital, pentru celelalte componente. Compunicare cu aplicatia mobila se ralizeaza prin Bluetooth.

Software Design

Programarea placutei s-a realizat in Arduino IDE, si am folosit biblioteci precum LiquidCrystal sau DHT.h, in vederea comunicarii cu componentele. Aplicatia mobila a fost realizata pe platforma MIT App Inventor, Si prezinta umatoarele functii:

#include <DHT.h>
#include <Wire.h>
#include "BluetoothSerial.h"
#include <LiquidCrystal.h>


#define MQ3_PIN 35
#define DHT_PIN 4
#define DHT_TYPE DHT11
#define BUZZER_PIN 14 

#define rs 16
#define E 17
#define D4 18
#define D5 19
#define D6 21
#define D7 22
#define V0 23

LiquidCrystal lcd(rs, E, D4, D5, D6, D7);

BluetoothSerial SerialBT;
DHT dht(DHT_PIN, DHT_TYPE);

char received;
const float RL = 10.0;   
const int NUM_READINGS = 100;  
const int COLLECTION_PERIOD = 10000;  

float R0;

bool startCollection = false;

void setup() {
  SerialBT.begin("ESP32_Alcohol_Test");
  Serial.begin(115200);
  pinMode(MQ3_PIN, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  digitalWrite(BUZZER_PIN, LOW);
  dht.begin();

  lcd.begin(16, 2);
  lcd.print("Initializing...");

  pinMode(V0, OUTPUT);
  analogWrite(V0, 100);
}

void loop() {
  if (SerialBT.available()) {
    received = SerialBT.read();
    if (received == 'C') { 
      R0 = calibrateMQ3();
    } else if (received == 'S') {
      startCollection = true;
    }
  }

  if (startCollection) {
    collectAndSendSensorData();
    startCollection = false;
  }
}

float calibrateMQ3() {
  R0 = readRS();
  Serial.print("R0 in clean air: ");
  Serial.print(R0);
  Serial.println(" kOhm");

  lcd.clear();
  lcd.print("Calibrated");

  SerialBT.println("Ready to use!");
  return R0;
}

float readRS() {
  long totalReadings = 0;

  for (int i = 0; i < NUM_READINGS; i++) {
    totalReadings += analogRead(MQ3_PIN);
    delay(100);  
  }

  int avgReading = totalReadings / NUM_READINGS;
  float sensorVoltage = avgReading * (3.3 / 4095.0);  
  float RS = ((3.3 * RL) / sensorVoltage) - RL;       

  return RS;
}

void collectAndSendSensorData() {
  digitalWrite(BUZZER_PIN, HIGH);
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();

  Serial.println("temperature:  " + String(temperature));
  Serial.println("humidity:  " + String(humidity));
  
  float mq3_value = readRS();

  if (isnan(temperature) || isnan(humidity)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  
  float alcohol_concentration;

  float dif = R0 - mq3_value;

  if (dif < 2) {
   alcohol_concentration = 0;
  } else {
    float compensated = dif / (1 + (0.02 * (temperature - 20)) + (0.05 * (humidity - 65)));  
    alcohol_concentration = calculateAlcoholConcentration(compensated);
      Serial.println("compensated:  " + String(compensated));

  }
  
  Serial.println("R0:  " + String(R0));
  Serial.println("Mq-3:  " + String(mq3_value));
  Serial.println("dif:  " + String(dif));
  

  String alcohol_concentration_str = "Alcohol Concentration: " + String(alcohol_concentration) + " mg/L";

  Serial.println(alcohol_concentration_str);

  lcd.clear();
  lcd.print(String(alcohol_concentration) + " mg/L");

  SerialBT.println(alcohol_concentration_str);
  digitalWrite(BUZZER_PIN, LOW);

}

float calculateAlcoholConcentration(float ratio) {
  float m = 45;  
  float b = -0.77;   
  double alcohol_ppm = (log10(ratio) - b) / m ;  
  double alcohol_mg_per_l = alcohol_ppm * 1.25; 
  return alcohol_mg_per_l;
}

Mod de functionare

In prima faza este transmis un semnal in vederea calibrarii senzorului de alcool cu o valoare de referinta din aerul curat, la momentul respectiv. Pentru acest lucru se realizeaza media valorilor intr-o fereastra de timp de 10 secunde. Dupa calibrarea rezistentei, are loc momentul de testare ce dureaza, de asemenea tot 10 secunde. Pe toata perioada testarii, a fost folosit un buzzer ce avertizeaza constant cat timp trebuie sa suflii. Dupa colectarea datelor, se calculeaza valoarea medie ce este procesata, avand loc un proces de compensare in felul urmator: se foloseste un factor de corectie pentru temperatura, astfel incat pentru fiecare grad celsius peste 20 de grade, valoarea citita de senzor se ajusteaza cu 2%., intrucat o temperatura mai mare tinde sa creasca valoarea citita de senzor. La fel si in cazul umiditatii, orice procent peste 65%, valoarea citita de la senzor se ajusteaza cu 5%. Dupa realizarea acestui proces, se stabileste alcoolemia pe baza unei functii liniare ce ia in calcul doua variabile de corectie ce sunt ajustate in faza de testare.

Rezultate obtinute

Proiect:

Aplicatie:

Concluzii

Un proiect mai mult de cat interesant si placut de creat :)

Bibliografie/Resurse

https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4850983/
https://www.dfrobot.com/blog-903.html
https://ocw.cs.pub.ro/courses/pm/prj2022/arosca/senzorgaze
https://app.diagrams.net/
https://www.alldatasheet.com/datasheet-pdf/pdf/1148034/ESPRESSIF/ESP-WROOM-S2.html
https://drive.google.com/drive/folders/1q7VWBEJq7-LWyp2zIYuVQmyR7q3-Pdx6