<h3 class="post-title entry-title" itemprop="name" style="margin: 0.75em 0px 0px; position: relative; font-variant-numeric: normal; font-variant-east-asian: normal; font-weight: normal; font-stretch: normal; font-size: 22px; line-height: normal; font-family: &quot;Trebuchet MS&quot;, Trebuchet, Verdana, sans-serif; color: #666666; background-color: #ffffff;">Cheap CO2 meter using the MQ135 sensor with AVR ATmega</h3>
<div class="post-header" style="line-height: 1.6; margin: 0px 0px 1.5em; font-size: 10.8px; color: #666666; font-family: &quot;Trebuchet MS&quot;, Trebuchet, Verdana, sans-serif; background-color: #ffffff;">
   <div class="post-header-line-1">
      <div class="post-share-buttons goog-inline-block" style="position: relative; display: inline-block; margin-top: 0.5em; vertical-align: middle;">&nbsp;</div>
      <span class="post-icons"></span></div>
   </div>
<div class="post-body entry-content" id="post-body-4722799349967621343" itemprop="description articleBody" style="width: 546px; font-size: 13.2px; line-height: 1.4; position: relative; color: #666666; font-family: &quot;Trebuchet MS&quot;, Trebuchet, Verdana, sans-serif; background-color: #ffffff;"><b>MQ135</b>&nbsp;is an&nbsp;<b>Air Quality Sensor</b>&nbsp;suitable for detecting of NH3, Alcohol, Benzene and other gases.<br /><br />
   <div class="separator" style="clear: both; text-align: center;"><a href="http://2.bp.blogspot.com/-xqvZeI9HXTQ/UuPyblIDjjI/AAAAAAAAD_8/IKy93OyU3Qk/s1600/mq135_pinout.jpg" imageanchor="1" style="text-decoration-line: none; color: #888888; margin-left: 1em; margin-right: 1em;" target="_blank"><img border="0" height="91" src="https://2.bp.blogspot.com/-xqvZeI9HXTQ/UuPyblIDjjI/AAAAAAAAD_8/IKy93OyU3Qk/s1600/mq135_pinout.jpg" width="400" style="border: 1px solid rgb(238, 238, 238); position: relative; padding: 5px; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; box-shadow: rgba(0, 0, 0, 0.1) 1px 1px 5px;" /></a></div>
   <br />The description below, is what i derive from the poor datasheet of this sensor, it may be uncorrect, so if you have suggestions please leave me a feedback.<br /><br /><span style="color: orange;">update -&nbsp;</span><span style="color: orange;">Here you can find a way to estimate the correlation function of MQ sensors, and&nbsp;</span><span style="color: orange;">extrapolate coefficients from the datasheet curves</span><span style="color: orange;">:</span><br /><a href="http://davidegironi.blogspot.com/2017/05/mq-gas-sensor-correlation-function.html" style="text-decoration-line: none; color: #888888;" target="_blank">http://davidegironi.blogspot.com/2017/05/mq-gas-sensor-correlation-function.html</a><br /><span style="color: orange;">update -&nbsp;</span><span style="color: orange;">Here a temperature and humidity correlation method for the MQ sensors;</span><br /><a href="http://davidegironi.blogspot.com/2017/07/mq-gas-sensor-correlation-function.html" style="text-decoration-line: none; color: #888888;" target="_blank">http://davidegironi.blogspot.com/2017/07/mq-gas-sensor-correlation-function.html</a><br /><br />The "<i>sensitivity characteristics of the MQ-135</i>" figure of the datasheet, you can see it below, it is used to convert the output of the sensor to the related ppm physical physical charateristic&nbsp;for the gas under test.<br /><br />
   <div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-fjA7HqHs3ZM/UuPydeWHiOI/AAAAAAAAEAU/wk8l7zRa3_E/s1600/mq135_sensitivity_characteristics.jpg" imageanchor="1" style="text-decoration-line: none; color: #888888; margin-left: 1em; margin-right: 1em;" target="_blank"><img border="0" height="382" src="https://4.bp.blogspot.com/-fjA7HqHs3ZM/UuPydeWHiOI/AAAAAAAAEAU/wk8l7zRa3_E/s1600/mq135_sensitivity_characteristics.jpg" width="400" style="border: 1px solid rgb(238, 238, 238); position: relative; padding: 5px; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; box-shadow: rgba(0, 0, 0, 0.1) 1px 1px 5px;" /></a></div>
   <br />The graphic above seems a power function<br /><i>y = a*x^b</i><br />so<br /><i>ppm = a*(Rs/Ro)^b</i><br />using power regression, we can obtain scaling factor (a), and exponent (b), for the gas we would like to measure<br /><br />Then<br /><i>Ro = Rs * sqrt(a/ppm, b) = Rs * exp( ln(a/ppm) / b )</i><br />
   <div><br /></div>
   <div>So, if we want to calibrate a sensor, we "just" need a know amount of a certain gas, then we can read the resistance output value from the sensor (Rs), and we can compute the calibrated Ro value.<br />We know the current amount of&nbsp;<b>CO2 gas in atmosphere</b>&nbsp;<a href="http://co2now.org/" style="text-decoration-line: none; color: #888888;" target="_blank">http://co2now.org/</a>, we can use this as a reference for calibration.</div>
   <div><br /></div>
   <div>Datasheet tell us even detecting concentration scope for a certain gas, so we can compute the limit for Rs/Ro.</div>
   <div><br /></div>
   <div><i>Rs/Ro_limit = (ppm/a) ^ (1/b)</i></div>
   <div><br /></div>
   <div>Now, because i want to build a CO2 meter, let's try to calibrate this sensor for measure CO2.</div>
   <div><br /></div>
   <div>For CO2, if we measure points graph and do power regression we can obtain the function</div>
   ppm = 116.6020682 (Rs/Ro)^-2.769034857<br />we also know that the current amount of CO2 gas in atmosphere is (unfortunately) 392ppm, so, heating the sensor for 24 hours, and leaving it in open air, if we measure 26954ohm as the resistance output we can Ro should be&nbsp;41763.<br />Datasheet does not tell us much for detecting concentration scope for this gas, the figure is from 10 to 200ppm, but we can suppose a limit from 10 to 2000ppm.<br /><br />The above derivation seems to works quite well, but for estimating the scaling factor, and exponent in a more precise way, i've logged raw adc data from MQ135 and correlated to a MHZ14 NDIR infrared sensor.<br /><br />Data was logged on a xively datastream.<br /><br />
   <div class="separator" style="clear: both; text-align: center;"><a href="http://3.bp.blogspot.com/-w_hY6hGNolk/UuPycyTAVNI/AAAAAAAAEAQ/FWf09sFVpos/s1600/mq135_co2_correlation.jpg" imageanchor="1" style="text-decoration-line: none; color: #888888; margin-left: 1em; margin-right: 1em;" target="_blank"><img border="0" height="210" src="https://3.bp.blogspot.com/-w_hY6hGNolk/UuPycyTAVNI/AAAAAAAAEAQ/FWf09sFVpos/s1600/mq135_co2_correlation.jpg" width="400" style="border: 1px solid rgb(238, 238, 238); position: relative; padding: 5px; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; box-shadow: rgba(0, 0, 0, 0.1) 1px 1px 5px;" /></a></div>
   <br />You can see the correlation results above.<br />Correlation is done by a matlab script using power regression and polynomial curve fitting.<br />We have to convert raw value to calculated resistance.<br />And then, because we will later use a Ro, we "impose" a arbitrary Ro, such that scaling factor and exponent can be used in the math of our microcontroller.<br />Imposing a Ro of 41000, obtained scaling factor in my experiment is: 56.0820, and exponent is -5.9603.<br />Using this parameters now we should obtain a better response for our sensor.<br />The Ro calibration is again important because one sensor can differ from other.<br />The previous reading of 26954ohm return, using those new correlated scaling factor and exponet values, &nbsp;us a value of&nbsp;683ppm, without any calibration of the Ro.<br /><br />I've checked the xively datastream with the new correlated function, and it seams to repond a little better than the datasheet one, even if reading does not always respond as is expected.<br /><br />I've checked this method against 5 sensors, 4 of them, after the Ro has been calibrated, seems to fit the same response curve, 1 not.<br />Because MQ135 are electro-chemical sensor, i do not expect all the sensors has the same curve.<br /><br />With the code you can find the&nbsp;<b>matlab script</b>, and the&nbsp;<b>speadsheet helper</b>&nbsp;for computations.<br /><br />
   <div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-0FYTzIz5EeA/VC04-fQo-nI/AAAAAAAAExU/xUfW7lC2wkY/s1600/atmega_mq135_sample.png" imageanchor="1" style="text-decoration-line: none; color: #888888; margin-left: 1em; margin-right: 1em;" target="_blank"><img border="0" height="287" src="https://4.bp.blogspot.com/-0FYTzIz5EeA/VC04-fQo-nI/AAAAAAAAExU/xUfW7lC2wkY/s1600/atmega_mq135_sample.png" width="400" style="border: 1px solid rgb(238, 238, 238); position: relative; padding: 5px; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; box-shadow: rgba(0, 0, 0, 0.1) 1px 1px 5px;" /></a></div>
   <br /><b>ChangeLog</b><br />
   <ul style="padding: 0px 2.5em; margin: 0.5em 0px; line-height: 1.4;">
      <li style="padding: 0px; margin: 0px 0px 0.25em;">01b: fixed inconsistent value of the R3 resistor between schematics and code (thanks to&nbsp;<i>Emmanuel Pierre</i>&nbsp;for reporting this bug)&nbsp;</li>
      <li style="padding: 0px; margin: 0px 0px 0.25em;">01: first version.</li>
      </ul>
   <br /><b>Code</b><br />
   <ul style="padding: 0px 2.5em; margin: 0.5em 0px; line-height: 1.4;">
      <li style="padding: 0px; margin: 0px 0px 0.25em;"><a href="https://sourceforge.net/projects/davidegironi/files/avr-lib/avr_lib_mq135_01b.zip/download" target="_blank" style="text-decoration-line: none; color: #888888;">avr_lib_mq135_01b.zip</a></li>
      <li style="padding: 0px; margin: 0px 0px 0.25em;"><strike><a href="https://sourceforge.net/projects/davidegironi/files/avr-lib/avr_lib_mq135_01.zip/download" target="_blank" style="text-decoration-line: none; color: #888888;">avr_lib_mq135_01.zip</a></strike></li>
      </ul>
   </div>