MQ-3 Alkoholsensors - Fehler im Datenblatt ?

TEIL1

Hallo Zusammen,

ich arbeite Gerade an der Realisierung eines Atemalkoholtesters, und bin auf eine Ungereimtheit gestoßen. Hier erstmal mein bisheriger Stand:

Die Realisierung der Alkoholmessung erfolgt mittels des MQ-3 Alkoholsensors

Aus der Kennlinie des MQ-3 Alkoholsensors (link) ergibt sich die Konzentration des Alkohols in mg/l durch Ermittlung des Verhältnisses vom Widerstandswert bei einer Alkoholkonzentration von 0.1 mg/l zum gemessenen Widerstandswert bei Zuführung des Messmediums. In diesem Anwendungsfall die Ausgeatmete Luft.

Der Widerstandswert wird über den Arduino Mikrocontroller ermittelt. Über den analogen Eingang des Mikrocontrollers können Spannungen von 0-5 Volt bei einer Auflösung von 1024 Bit gemessen werden. Zur Ermittlung des Widerstandswertes kommt ein Spannungsteiler zum Einsatz.

Die Quellspannung (U) wird mit Konstant 5V zur Verfügung gestellt. Der Widerstand R1 wird mit 10 MOhm festgelegt.

Gemessen wird die Spannung U2 an R2 , da es sich um eine klassische Spannungsteilerschaltung handelt kann über die Formel R2 = R1* (U2/U1) bzw. R2 =R1*(U2/(U-U2)) der Widerstand des MQ-3 Alkoholsensors ermittelt werden

R1 =10 MOhm
R2 = MQ-3 Sensor
U = 5V
U2 = messen

Zur Auswertung werden die Widerstandswerte bei 0% Alkoholkonzentration (eine Messung bei 0,4mg/l haben wir noch nicht durchgeführt, es wird erst einmal der Wert ohne Zuführung des Messmediums als 0 Wert angenommen) in der Umgebungsluft sowie die Ergebnisse der Widerstandsmessung während Atemalkoholmessung

Ermittelt und im Verhältniss R0/RS in der Kennlinie als Bezugspunkt gesetzt. :roll_eyes:

  //###############################################################################################################################################################################################################
	  //Wiederstandsmessung R0
	  //###############################################################################################################################################################################################################

	  Messwert=0;                                                                    //Resetten des Messwertes damit fehler vermieden werden 
	  Serial.print("Kalibrierung...  ");                                             // Ausgabe Kalibrierung läuft....  
	  lcd.write("Kalibrierung...  ");                                                 
	  
		for(int i=0;i<Anzahl_Messungen;i++)                                          // Schleife zum festlegen der Refferenzmessungen
			  {
				delay (Messintervall);                                              // Zeit zwischend den einzelnen Messungen
				Messwert+=analogRead(AnalogPin);                                    // Messwert+letzter Messwert...
			  }   
	  Messwert=trunc(Messwert/Anzahl_Messungen);                                    // Durchschnittswert ermitteln 
	  SpannungR2=(Quellspannung/1024)*Messwert;                                     //Spannung berechnen
	  Widerstand=R1*(SpannungR2/(Quellspannung-SpannungR2));                        //Berechnung: (R2 = R1 * (U2/U1))
	  R0 = Widerstand;             
	  Serial.println(Widerstand);                                                   // Serielle Ausgabe Widerstand

TEIL 2 (leider sind die Zeichen ja begrenzt) :smiling_imp:

//###############################################################################################################################################################################################################
	  //Wiederstandsmessung RS
	  //###############################################################################################################################################################################################################

 zeit_vorher = millis();                                                            //  Zeit seit Start des Arduino Programms vor der Messung
                                                                                                    
  Messwert=0;                                                                        //Resetten des Messwertes damit Fehler vermieden werden 
  Serial.println("Messung laueft...  ");                                             // Ausgabe Kalibrierung läuft....  
	  for(int i=0;i<Anzahl_Messungen;i++)                                              // Schleife zum festlegen der Refferenzmessungen
		{																				// for Schleife Messung läuft auf
		messintervall_kalkuliert=5000/Anzahl_Messungen;                                  // errechnen der Intervallzeit für eine gesammtmessung von ca 5 Sekunden
		delay (messintervall_kalkuliert);
		
		zeit_aktuell =millis();                                                          // aktuelle Zeit seit Start des Arduino Programms
		zeit_berechnet =zeit_aktuell-zeit_vorher;                                        // Vergangene Zeit seit die Messung läuft ermitteln 
																	 //Serial.println(zeit_berechnet);  //testausgabe                                              
			if (zeit_berechnet >= 1000 &&  zeit_berechnet <= 1050)                         // Wenn 1 Sekunde vergangen ist ....   
			{
			Serial.println("Noch 5 Sekunden pusten...");                                      
			digitalWrite(led_Gruen1, HIGH);                                                 // einschalten LEDs während des pustens
			}
		
		
			if (zeit_berechnet >= 2000 &&  zeit_berechnet <= 2050)                          // Wenn 2 Sekunde vergangen ist ....   
			{                                                                               // Zeit zwischend den einzelnen Messungen          
			Serial.println("Noch 4 Sekunden pusten...");
			digitalWrite(led_Gruen2, HIGH);                                                  // einschalten LEDs während des pustens
			}
		
			 if (zeit_berechnet >= 3000 &&  zeit_berechnet <= 3050)                         // Wenn 3 Sekunde vergangen ist ....   
			{ 
			
			Serial.println("Noch 3 Sekunden pusten...");
			digitalWrite(led_orange1, HIGH);                                                // einschalten LEDs während des pustens
			}
		
			 if (zeit_berechnet >= 4000 &&  zeit_berechnet <= 4050)                         // Wenn 4 Sekunde vergangen ist ....   
			{ 
			
			Serial.println("Noch 2 Sekunden pusten...");
			digitalWrite(led_orange2, HIGH);                                               // einschalten LEDs während des pustens
			}
			
			 if (zeit_berechnet >= 4950 &&  zeit_berechnet <= 5050)                       // Wenn 5 Sekunde vergangen ist ....   
			{ 
																
			Serial.println("Noch 1 Sekunden pusten...");
			digitalWrite(led_rot, HIGH);                                                   // einschalten LEDs während des pustens
			Messung_beendet = 1;
			}
		
			if (Messung_beendet == 1)                                                   // Wenn Messung beendet ist....   
			{ 																			// if Messung beendet auf
			delay(1000);
			Serial.println("STTTTTOOOOOOOPPPPP!!!!!...");
			digitalWrite(led_Gruen1, LOW);                                               // ausschalten LEDs während des pustens
			digitalWrite(led_Gruen2, LOW);                                               // ausschalten LEDs während des pustens
			digitalWrite(led_orange1, LOW);                                              // ausschalten LEDs während des pustens
			digitalWrite(led_orange2, LOW);                                              // ausschalten LEDs während des pustens
			digitalWrite(led_rot, LOW);                                                  // ausschalten LEDs während des pustens
		
			delay(1000);
			Serial.println("Bitte warten, Alkoholgehalt wird berechnet...");
			Messung_beendet=0;
	   	…..
…..

    Messwert+=analogRead(AnalogPin);                                              // Messwert+letzter Messwert...
		}   																						// for Schleife Messung läuft auf
  Messwert=trunc(Messwert/Anzahl_Messungen);                                        // Durchschnittswert ermitteln 
  SpannungR2=(Quellspannung/1024)*Messwert;                                            //Spannung berechnen
  Widerstand=R1*(SpannungR2/(Quellspannung-SpannungR2));                            //Berechnung: (R2 = R1 * (U2/U1))
  RS=Widerstand;
  Serial.println(Widerstand);                                                       // Serielle Ausgabe Widerstand 

                                                                                 
   
  Sensorwert = R0/RS;                                                                     // Wiederstand einlesen  und Rechnen RS/RO

  last = 0 ;	                                                                        //letzer Wert des Zählers
  i=0	;	                                                                        // Zähler

  for(i=0;meinArray[i][0] < Sensorwert && i < 22;i++)	;	                      //Solange der Wert für i kleiner als der Sensorwert	 
  {  
    if (last == i)                                                              // Solange die Werte der Zähler nicht gleich sind gibt es noch einen höheren x wert in der Kennlinie 
    {      
      i=last;                                                                     // Zählervariable "last" erhöhen damit nur einmal berechnet wird
    }

    Atemalkohol=0;
    Atemalkohol = meinArray[i][2]*Sensorwert+meinArray[i][3];
    BAC=0;
    BAC = Atemalkohol * 0.21;

Aufgrund der Temperaturabhängigkeit des MQ-3 Alkoholsensors wurde ein Digitaler Temperatursensor eingebaut. Im Späteren Programm soll die Temperatur bei der Messung im Ergebnis mit berücksichtigt werden.

Für die Programtechnische Ermittlung des Atemalkoholgehaltes sowie des Blutalkoholgehaltes (BAC) wurden eine Reihe von Arbeitspunkten mithilfe der Kennlinie ermittelt und in eine Tabelle übertragen und die Achsen getauscht. Diese Wurden dann in folgendes Array übertragen:

/*#######################################################################################################################################################################################

Werte aus der Kennlie des MQ-3 Alkoholsensors Übernommen.
Spalte: 0	1	2	3
        x	y	m	b
#######################################################################################################################################################################################
*/

double meinArray[22][4]= {
  {
    0.1  ,11.0  ,0.0  ,0.0      }
  , {
    0.108  ,10  ,-62.5  ,16.75      }
  , {
    0.124  ,9  ,-125  ,24.5      } 
  , {
    0.132  ,8  ,62.50,  16.25      }
  , {
    0.148  ,7  ,-50.00  ,14.40      }
  , {
    0.164  ,6.2  ,-75.00  ,18.50      }
  , {
    0.18  ,5  ,-40.00  ,12.20      }
  , {
    0.2  ,4.2  ,-22.6415  ,8.728302      }
  , {
    0.253  ,3  ,-11.4943  ,5.908046      }
  , {
    0.34  ,2    ,-6.00  ,4.04      }
  , {
    0.4  ,1.64  ,-4.85714  ,3.582857      }
  , {
    0.47  ,1.3  ,-3.75  ,3.0625      }
  , {
    0.6  ,0.9  ,-2.00  ,2.10      }
  , {
    0.64  ,0.8  ,-2.50  ,2.40      }
  , {
    0.7  ,0.7  ,-1.66667  ,1.866667      }
  , {
    0.8  ,0.6  ,-1.00  ,1.40      }
  , {
    0.9  ,0.5  ,-1.00  ,1.40      }
  , {
    1.00 ,0.4  ,-1.00  ,1.40      }
  , {
    2.28  ,0.3  ,-0.07813  ,0.478125      }
  , {
    2.64  ,0.2  ,-0.27778  ,0.933333      }
  , {
    3.00  ,0.13  ,-0.19444  ,0.713333      }
  , {
    3.20  ,0.1  ,-0.15  ,0.58      }
};

Und zu guter letzt...TIEL3 8)

Im Programm kann nach Ermittlung des zu verwendenden Arbeitspunktes, über das Lineare Gleichungssystem bzw. der Formel f(x)=m*x+b der Schnittpunkt mit der X-Achse ermittelt werden.

Der ermittelte Wert spiegelt die Atemalkoholkonzentration in der Luft wieder.

Dieser Wert kann in den allgemein bekannten Promille wert in Prozent über die Formel, % BAC = breath mg/L * 0.21 umgerechnet werden.

Features des Sensors:

  1. Signal output instructions;
  2. Dual signal output (analog output, and TTL level output);
  3. TTL output valid signal is low, can be connected directly to the microcontroller;
  4. 0 ~ 5V analog output voltage, the higher the concentration the higher the voltage;
  5. Has a high sensitivity and good selectivity to ethanol vapor;
  6. Has a long life and reliable stability;
  7. Rapid response recovery characteristics;

Schaltplan Sensor:

Schaltplan link

So und nun zu meiner Frage:

Aus dem Daten des Sensormoduls kann ich entnehmen das bei steigendem Alkoholgehalt die Spannung steigt.
Das bedeutet auch das der Widerstand größer wird. Wenn ich also zum Beispiel davon ausgehe das der Widerstand bei einer „0 Messung“ also R0 bei 1k Ohm
Liegt und bei einer Messung von RS bei sagen wir mal 5k Ohm dann ergibt sich aus dem im Datenblatt angegebenen verhältniss von RS/R0 ein Wert von 5kOhm/1kOhm = 5
Somit würde der Atemalkoholgehalt ja nie steigen…. Ich habe daraus geschlossen das es eigentlich R0/RS heißen sollte….jedoch diesen Sensor gibt es ja nicht erst seit gestern und ich kann mir kaum vorstellen, dass dies noch niemandem aufgefallen ist.

Vielleicht hab ich auch irgendwo einen Denkfehler gemacht , und mir kann jemand von euch weiterhelfen …

MFG

Hallo,

der Widerstand sinkt, die Leitfähigkeit steigt bei steigendem Gasvolumen in der Luft. Hier noch mal explizit beschrieben.

Sensitive material of MQ-3 gas sensor is SnO2, which with lower conductivity in clean air. When the target alcohol gas exist, The sensor’s conductivity is more higher along with the gas concentration rising.

Also wird das Verhältnis Rs/R0 kleiner bei steigender Gaskonzentration.

Gruß
Reinhard

anderes Problem. Du hast einen belasteten Spannungsteiler. Der Analoge Eingng hat wegen des Sample and Hold Kondensator der in kurzer Zeit geladen werden mu0 einen Ersatzinnenwiderstad von ca 10kOhm. Bei einem so Hochohmigen Spannungsteile verändert dieser den Spannungswert. Abhilfe ein Operationsverstärker als Impedanzwandler geschaltet.

Grüße Uwe

Hat mit der Frage nichts zu tun, aber dennoch:

Über den analogen Eingang des Mikrocontrollers können Spannungen von 0-5 Volt bei einer Auflösung von 1024 Bit gemessen werden.

Nein, der ADC loest mit 10 Bit auf - entsprechend 1024 darstellbaren Werten.

Gruss, Helmuth

Helmuth:
Hat mit der Frage nichts zu tun, aber dennoch:

Nein, der ADC loest mit 10 Bit auf - entsprechend 1024 darstellbaren Werten.

Gruss, Helmuth

Helmuth danke für den Hinweis war einfach mal so runter geschrieben:P

Reinhard genau da liegt mein Problem,
bei versuchen mit dem Sensor sind die Ergebnisse leider genau umgekehrt…

Im Versuchsaufbau Zeigt sich, dass der Sensor bei steigender Alkoholkonzentration die Spannung und somit der Widerstand steigt…

Hier der Code:

double Quellspannung = 5.0;    // Quellspannung
double R3 =4700;                //Widerstand des Spannungsteilers auf dem MQ3 Sensorboard
int sensorPin = A0;            // Analogeingang Sensor
int Messwert = 0;  
double SpannungRS,Widerstand;
void setup() {
     
  Serial.begin(9600); 
}

void loop() {
Messwert = analogRead(sensorPin);    
  Serial.print("Aanlogwert: ");
  Serial.println(Messwert);  

SpannungRS=(Quellspannung/1024)*Messwert;                                            //Spannung berechnen

 Serial.print("Spannung RS ");
 Serial.println(SpannungRS); 
  
Widerstand=R3*(SpannungRS/(Quellspannung-SpannungRS));                            //Berechnung: (R2 = R1 * (U2/U1))


 Serial.print("Widerstand RS ");
 Serial.println(Widerstand); 
 
  Serial.println ("");   
 
delay(1500);  
}

und die Ergebnisse der Messung:

Aanlogwert: 156
Spannung RS 0.76
Widerstand RS 844.70                    //Messung ohne Alkohol (R0)

Aanlogwert: 151
Spannung RS 0.74
Widerstand RS 812.94

Aanlogwert: 148
Spannung RS 0.72
Widerstand RS 794.06

Aanlogwert: 143
Spannung RS 0.70
Widerstand RS 762.88

Aanlogwert: 145
Spannung RS 0.71
Widerstand RS 775.31

Aanlogwert: 446
Spannung RS 2.18
Widerstand RS 3626.64

Aanlogwert: 613
Spannung RS 2.99
Widerstand RS 7009.98

Aanlogwert: 660
Spannung RS 3.22
Widerstand RS 8521.98

Aanlogwert: 625
Spannung RS 3.05
Widerstand RS 7362.16

Aanlogwert: 665
Spannung RS 3.25
Widerstand RS 8706.13

Aanlogwert: 665
Spannung RS 3.25
Widerstand RS 8706.13

Aanlogwert: 652
Spannung RS 3.18
Widerstand RS 8237.63                   //Messung bei gestiegener Alkoholkonzentration (RS)

Wenn ich jetzt mal aus diesen Werten das Verhältnis bilde, RS/R0 dann wäre bei beginn der Messung
R0=RS also der Wert 1 und bei steigender Alkoholkonzentration in der Luft doch RS/RO = 8237,63/844,70 → 9,752 :’(

uwefed:
anderes Problem. Du hast einen belasteten Spannungsteiler. Der Analoge Eingng hat wegen des Sample and Hold Kondensator der in kurzer Zeit geladen werden mit einen Ersatzinnenwiderstad von ca 10kOhm. Bei einem so Hochohmigen Spannungsteiler verändert dieser den Spannungswert. Abhilfe ein Operationsverstärker als Impedanzwandler geschaltet.

Grüße Uwe

Danke für den Tipp Uwe, hiermit würde ich mir natürlich die Genauigkeit erhöhen, wenn jedoch die Grundfunktionalität noch Probleme macht ist das vorerst für mich erstmal zweitrangig, im weiteren verlauf des Projektes wird dein Vorschlag aber sicherlich nochmal ins Auge gefasst werden :slight_smile:

tweak87:
Danke für den Tipp Uwe, hiermit würde ich mir natürlich die Genauigkeit erhöhen, wenn jedoch die Grundfunktionalität noch Probleme macht ist das vorerst für mich erstmal zweitrangig, im weiteren verlauf des Projektes wird dein Vorschlag aber sicherlich nochmal ins Auge gefasst werden :slight_smile:

Du verstehst mich falsch. Der interne Ersatzwiderstand, oder besser gesagt der notwendige Strom um den internen Sample and Hold Kondensator innerhalb der vorgegebenen Ladezeit bis zur angelegten Spannung zu laden belastet den Spannungsteiler so stark, daß die Spannung am hochohmigen Spannungster absackt, sodaß Du nichts sinnvolles messen kannst.

grüße Uwe

Ich glaube ich bin schon selbst drauf gekommen.... :zipper_mouth_face:

Ich hab die ganze Zeit mit einem unbelasteten Spannungsteiler gerechnet....

der Aufbau sollte also so aussehen:


| |
| # RS =?
| #
| |
| |
U0=5V --------------------------
| | | |
| | | |
| # R3=4,7k # RL | U2
| # # |
| | | |
V | | V

RL ist hierbei gemäß Datenblatt der Load Resistance und Variabel. Handelt es sich hierbei dann um das Poti des Sensorboards?

Wenn das so sein sollte könnte ich ja dann mit R1 = R3L/(R3L+U2)*U0 den Widerstand ermitteln...

R3L ist dabei der Ersatzwiderstand von RL und U2

Nein.
Der Sample and Hold Kondensator des ADC wird für eine gewisse Zeit von der Eingengspannung aufgeladen. Die Ladekurve ist eine Expotentialfunktion. Je nach vorheriger Messung ist die Spannungsdifferenz zur jetzigen Messung verschieden und darum ist der Spannungs-Endwert des S&H Kondensator verschiden. Den kannst Du nicht durch einen belasteten Spannungsteiler berechnen. Schalte einen OpAmp als Spannungsfolger dazwischen und Du hast keine Probleme. Als OpAmp kommt ein RAIL-to-Rail Type in frage oder wenn du nicht bis 5V Eingengspannung hast auch ein LM358.
Grüße Uwe

okay , das kann ich nachvollziehen. Da ich den Digitalausgang des Sensorbaords nicht benötige wäre es somit doch am einfachsten den Sensor nicht über das Sensorboard zu nutzen sondern nach Vorgabe des Datenblattes so zu beschalten.

link

oder

link

R0 ist der Widerstand des Sensors bei 0,4mg Alcohol pro l Luft
Rs ist der Widerstand des Sensors bei der Messung

Fig 2 auf Seite 2 von https://www.sparkfun.com/datasheets/Sensors/MQ-3.pdf gibt die Änderung des Verhältnisses von R0 zu Rs bei verschiedenen Konzentrationen von Alkohol und anderen Chiemischen stoffen auf die der Sensor auch noch empfindlich ist.

R0 ist zwischen 1M und 8 MOhm.
Laut Datenblatt geht Ro/RS zwischen ca 2 und 0,1 ((bei 0mg und 10mg/l Alkohol), also zwischen 2-16MOhm und 0,1-0,8MOhm.

RL (der Widerstand der als Spannungsteiler verwendet wird) ist für das Diagram als 200kOhm definiert. Wenn Du einen anderen Widerstandswert für RL verwendest ist das Diagramm nicht mehr gültig und Du mußt dir selbst ein Diagram ermessen/Kalibrierkurve messen.

Der Spannungsteiler ist zu hochohmig als daß mit einem Arduino-Analogeingang etwas significantes gemessen wird.

Nimm einen Impedanzwandler.
Grüße Uwe

Also muss ich das Sensor board auch raus schmeißen und das ganze neu aufbauen mit dem passenden Widerstand

Ok ich versuche das mal so zusammenzufassen wie ich das nach einigen Recherchen verstanden habe.

Wie aus dem Datenblatt des auf meinem Arduino vernbauten AtMega328 zu entnehmen ist, ist also der ADC Eingang des Mikrokontrollers für eine gesamt Impedanz (ohmsche, induktive und kapazitive Widerstände) von kleiner als 10 KOhm optimiert.

Wenn ich jetzt also einen 200KOhm Widerstand als Spannungsteiler für die Sensorschaltung verwenden würden ohne einen R2R OP könnte der R&H Kondensator nicht vollständig aufgeladen werden bevor die Messung bzw. das auslesen des ADC eingangs erfolgt.
Das bedeutet also es käme zu Fehlern…
Über den RAIL TO RAIL OP vor dem ADC Eingang wird das Signal spannungsmäßig nicht verändert. Der R2R Impedanzwandler eine sehr hohe Eingangsimpedanz, so dass er die Spannungsquelle kaum belastet? Der S&H kann aufgrund der geringeren Impedanz also wieder deutlich schneller geladen werden was sich theoretisch auch Berechnen ließe über die Formel zum Ladevorgang einen Kondensators: (1 / e^(RC/t))
Habe ich das so richtig verstanden?

Danke und Gruß Tweak

Mir ist jetzt leider nur nicht mehr ganz klar, wie ich auf Basis dieser Schaltung den Widerstandswert vom Sensor bestimmen soll.

Kann mir da jemand helfen?

So um das Thema mal zum Abschluss zu bringen, ich habe das Problem nun folgendermaßen gelöst:

Aufgrund der fehlenden technischen Möglichkeiten einer Nullmessung bei definierten Bedingungen, hab ich mich entschieden eine Referenzmessung durchzuführen.

Auf Basis dieser Werte konnte ich eine Funktion entwickeln die für mein Projekt ausreichend ist.

Anbei ein Bild von dem Fertigen Gerät :slight_smile: