Wrong sensor resistance calculation
Opened this issue · 8 comments
It seems that formula for calculating sensor resistance in getResistance() has an error, 5.0 multiplier (probably analog reference voltage) is unnecessary. The formula should read:
((1023./(float)val) - 1.)*RLOAD
Why should it be unnecessary? If you have a look at the official web site you can see that they use the same formula
https://www.arduino.cc/en/Tutorial/ReadAnalogVoltage
The formula in the tutorial is for the voltage on the analog pin, but we are calculating resistance (of the one member of the voltage divider):
Sensor resistance and Rload
form a voltage divider, which can be described with the following formula:
Rload/Vadc = (Rsensor+Rload)/Vref
where Vref
is our 5 V reference voltage, Vadc
is the voltage on the ADC pin. To find our sensor resistance:
Rsensor = Rload * (Vref/Vadc - 1)
We can replace Vref/Vadc
relation with ADCmaxvalue/ADCvalue
relation (where ADCmaxvalue
is usually 1023 for Arduino and always represents ADC value when Vadc = Vref
, ADCvalue
is proportional to Vadc
), so we get:
Rsensor = Rload * (ADCmaxvalue/ADCvalue - 1)
or
Rsensor = Rload * (1023/ADCvalue - 1)
The formulas for a voltage divider are described e.g. here.
Very good explanation, thank you! I wonder why this issue is open for over one year!?
After recalculation I agree, the 5V should vanish. Even simpler: Dimension analysis reveals, that within the bracket there should be no units.
Are there any another well-known mistakes in the GeorgeK’s code?
Do you know the best fork?
Probably, https://github.com/Gazz-yniere/MQ135, isn’t?
UPD: Hm, @Gazz-yniere’s code had lorf’s fix, but currently it looks wrong again:
https://github.com/Gazz-yniere/MQ135/blob/master/MQ135.cpp#L63-L67
Are there any another well-known mistakes in the GeorgeK’s code?
Do you know the best fork? Probably, https://github.com/Gazz-yniere/MQ135, isn’t? UPD: Hm, @Gazz-yniere’s code had lorf’s fix, but currently it looks wrong again: https://github.com/Gazz-yniere/MQ135/blob/master/MQ135.cpp#L63-L67
I am also trying this code and using the following formula:
return ((1023./(float)val) * 5. - 1.)*RLOAD;
I get between 330 and 410ppm in the office where I am working.
If I remove the * 5.
, I get kind of weird 75000 to 86000+ values!
I'm not sure any more about the correct formula!
I get between 330 and 410ppm in the office where I am working.
If I remove the* 5.
, I get kind of weird 75000 to 86000+ values!
I'm not sure any more about the correct formula!
I'm also currently maintaining a fork. Is there any consensus yet on how the correct formula should look like? Unfortunately, I don't have a sensor module here to test it (ironically). @lorf's explanation definitely makes sense though. Another point that has bothered me for quite some time is that the ADC resolution is hard-coded here and thus only works if you use a 10-bit ADC. I don't think there is a way to read the used ADC resolution set via analogReadResolution()
, is there?
the ADC resolution depends of you VCC value, because analogReadResolution() return the tension depending of VCC. In my project I use 5volts.
And if you want to have a good value of RS, the sensor needs to be ready after some time.
You have some informations on the datasheet https://www.olimex.com/Products/Components/Sensors/Gas/SNS-MQ135/resources/SNS-MQ135.pdf
other very useful informations for the sensor https://www.codrey.com/electronic-circuits/how-to-use-mq-135-gas-sensor/