The Canary

Dual Function Gas Detector

Rob Bell & Mike Hansell

Issue 13, July 2018

This article includes additional downloadable resources.
Please log in to access.

Log in

A useful carbon monoxide and flammable gas alarm.


This project is called “The Canary”, in reference to the phrase “Canary in the Coal Mine” (or other similar variants). In pre-technology practise, miners would take a caged canary into a mine. The canary was more susceptible to dangerous gases, and if the canary went quiet or died, it was a sign to exit the mine immediately! These days, the phrase often refers to any anything providing an early indication of a problem.

The use of canaries as a safety feature in mining dates back to around 1911, before being phased out in the 1980s. We thought “The Canary” was a rather fitting title for this project, given it’s designed to alert you to carbon monoxide or combustible gases!


Recently, there has been an increase in reports of carbon monoxide poisoning, often from leaving vehicles running in an enclosed space (unaware of the danger), faulty gas heaters, and more.

Based around an MQ9 sensor, we can detect carbon monoxide gas, as well as flammable gases, which can also pose serious threats. The benefit of this dual-purpose alarm is the capability for increased alarm states depending on the different causes. For instance, if the flame goes out on a natural gas device, you’ll have combustible gases not carbon monoxide. It will also detect gas leaks from pipes or fittings, which may be improperly fitted or damaged in some way.

This dual-purpose alarm is a powerful utility for home and garage; however, it’s also very useful for boating. Boats with an enclosed cabin can quickly fill with carbon monoxide from the engine or generator, as well as explosive petrol fumes in the engine compartment when using petrol engines. Also potentially at risk are caravans and campers that use LPG for cooking and heating.


Our design is based around the MQ9 gas sensor, which is a dual-range device that detects both carbon monoxide (CO) and combustible gases. Most often, this is notably liquified petroleum gas (LPG) - usually used in BBQs and outdoor gas heaters - but it also works on natural gas, which is piped to many Aussie households too.

The sensor consists of a small heating element and detection semiconductor, which is made from tin dioxide (SnO2). Tin dioxide has a special property where certain gases change the electrical resistivity.

The heating element warms the tin dioxide element up to several hundred degrees, depending on whether it’s in “CO mode” or “combustible gas mode”. You probably figured it out already, but the MQ9 sensor cannot detect both at once. The heating process is required to increase the sensitivity of the tin dioxide, to respond only to particular gases. For this reason, we modify the supply of power to the sensor’s heater, to determine what gas we’re detecting. The heating also helps keep the sensor free from moisture, which would impair its operation and change the outputs.


It’s worth noting that the MQ9 (and much of this series of sensors) are not good at providing hard data; it’s all about relativity. That is, they would not be useful at providing calibrated, digital readouts, as found in expensive CO sensors and metering equipment. However, this device will detect abnormal levels with a fairly high degree of accuracy. We will also set the acceptable background levels during Build 1, where we check what’s going on via serial monitor.

These sensors are also still affected to a small extent by ambient temperatures. So we would need to add a temperature sensor and some compensation in the code.

To completely calibrate the sensor, we would also then need a good known-accurate digital meter, and a room full of CO or combustible gas, to plot and note our sensor outputs and different levels. Overall, this is a little extreme, and well beyond what we actually need this device to do. The sensors have a known tolerance rate also, so it’s best to simply find the background levels, and assert that a substantial increase from background is cause for alarm.


This is a critical step to obtaining reliable operation of your sensor. Depending on the manufacturer of your sensor, and the datasheet you reference, all of these sensors require a specific run-in period. As a result, even if you plan on building the PCB-version to install somewhere, it’s a good idea to fire up the prototyping circuit as a way to run-in your sensor and take your baseline readings.

Some datasheets will say “warm up” time, but in reality this is referencing the run-in period. During this period, readings from the sensor will settle down and the sensor will become more precise overall.

After this time, the baseline readings can be measured from Build 1, and be used to set alarm thresholds for Build 2, using the ATtiny85. At any stage, if you determine they’ve been set too low or high they can, of course, be reprogrammed.

Build 1:

The Prototype

This is the simplest way to get going with an MQ9 sensor, to see how it works, and what you can do with it. Even if you anticipate building the PCB version (Build 2), the prototype has its place for gathering data, and running-in the sensor as previously mentioned.


Parts Required:Jaycar
1 × Arduino UNO or EquivalentXC4410
1 × MQ9 Sensor-
1 × PCB Mount Piezo BuzzerAB3459
1 × Tactile SwitchSP0600
2 × BD681 Darlington TransistorsZT2193
1 × 10µF Electrolytic CapacitorRE6066
1 × 100nF Ceramic CapacitorRC5360
1 × 68Ω 1/4W Resistor*RR0544
1 × 220Ω 1/4W Resistor*RR0566
1 × 1kΩ 1/4W Resistor*RR0572
1 × 2.2kΩ 1/4W Resistor*RR0580
1 × 5mm Red LEDZD0154
1 × 5mm Yellow LEDZD0162
1 × 5mm Blue LEDZD0180

* Quantity shown, may only be available in packs.

You will also need basic prototyping hardware such as a breadboard and jumper wires. Most of this hardware can also be reused for PCB construction if you’re undertaking Build 2 afterwards.

Follow the diagrams to work up your prototype to match. Give special attention to the orientation of the BD681 transistors.

Connect your Arduino UNO (will work on just about any Arduino compatible board), and you’re ready to load the code.

The MQ9 sensor is perhaps the most difficult part here. The pin layout is non-standard, and the pins don't work nicely with prototyping jumper wires.

If you have an Arduino compatible module handy, you'll find connection easier. However since we planned to progress to a PCB with installable hardware, we decided to deal with the raw sensor.

If you are using the raw sensor, trimming the ends off some prototype wires and soldering them to the pins is the easiest way to resolve this challenge.

The MQ9 sensor is not polarised, and can be rotated 180° without any problems. The pins are arranged in two groups of three. The middle left and middle right are for sensor readings, the top and bottom left pins connect to one side of the heater, as do the top right and bottom right pins.

All MQ9 datasheets we found indicate that the two heater pins on are connected internally. We found this was common, but not always the case - even with sensors from the same vendor. We have compensated for this by bridging them on the PCB in Build 2, however you'll have to potentially work around it when prototyping.


We have provided canary_prototype.ino in the digital resources. Load it on to your Arduino via the Arduino IDE, and open serial monitor (115200 baud). You should quickly start to see readings being taken, with their values provided.

You'll also notice that after a quick chirp (indicating self test), the LEDs start cycling. This is because we have commenced our reading process. Each 90-seconds or so, we cycle testing for carbon monoxide, and testing for combustible gases. This is done by varying the heater voltage.

We achieve this by switching on and off our Darlington transistors, which will provide 1.5V, or 5V to the heater element accordingly.

We allow a little time for things to settle, then take readings from the sensor.

If you open Serial Monitor, you will see a stream of readings coming from the sensor. Note the approximate average of these values, as we'll use them later in Build 2 also. We have defaulted these based on our own readings, but sensors and environments can vary.


This unit works fine on breadboard, but the very design of breadboard means it's electrically noisy and not really suitable for long-term operation (though we makers have been known to use it for more than just a prototype, haven't we).

YELLOW LED: Currently testing for combustible gases.

BLUE LED: Currently testing for carbon monoxide.

RED LED: ALARM!!! Gas levels above threshold are detected! The piezo buzzer will also sound when high levels are detected.

The pushbutton can be depressed in an alarm state to silence the alarm until the next cycle. This is handy when you're testing!

Note: Run your prototype for 48hrs (piezo disconnected if you wish) to run in the sensor. Any erratic readings you may experience should be resolved after this time.

Build 2:

Installable Unit

Parts Required:Jaycar
1 × ATtiny85ZZ8721
1 × 74HC595 Shift Register ICZC4895
1 × MQ9 SensorRS5615
1 × PCB Mount Piezo BuzzerAB3459
1 × Tactile SwitchSP0600
2 × BD681 Darlington TransistorsZT2193
1 × 1N4004 DiodeZR1004
1 × 10µF Electrolytic CapacitorRE6066
1 × 100nF Ceramic CapacitorRC5360
1 × 68Ω 1/4W Resistor*RR0544
1 × 220Ω 1/4W Resistor*RR0566
1 × 1kΩ 1/4W Resistor*RR0572
1 × 2.2kΩ 1/4W Resistor*RR0580
1 × 8-Pin IC SocketPI6452
1 × 16-Pin IC SocketPI6456
1 × PCB Mount DC SocketPS0519
1 × 5mm Red LEDZD0154
1 × 5mm Yellow LEDZD0162
1 × 5mm Blue LEDZD0180
6 × M3 × 6mm Screws*HP0440
1 × 5V Mains Power Supply - 500mA or GreaterMP3144

*Quantity shown, may only be available in packs.

After experimenting with a breadboard, it’s practical to move to an installable unit. For this we have developed a PCB for all components including the sensor, and a handy 3D printable case. It ensures better long-term operation than something on breadboard.

We wanted to get this unit nice and compact, and cheap to build. For that reason we have used an ATtiny85, instead of a standard Arduino board. These are incredibly powerful microcontrollers and really simplify deployment in a real world scenario. However one caveat with the ATtiny85 is, we didn’t have enough spare pins to make everything work. That’s easily solved however, with the addition of a 74HC595.

This discrete IC is a powerful shift register, commonly used for seven-segment displays. We have used them for various projects; however, they’re exceptionally useful for driving many outputs (up to eight) from three digital pins. This easily expanded the capabilities of our ATtiny85 to provide all the outputs we desire. The cost of the ATtiny85 and 74HC595 combined is still very little, especially for the amazing power the combination provides.


pcb final
top overlay
Top Overlay.
Bottom Layer
Bottom Layer.
Top Layer
Top Layer.

As with all our PCB-based projects, it is not essential to use the PCB; however, it makes construction easier. The photos of our PCB are an in-house prototype using our Bantam Tools’ DeskMini PCB Mill. If you have purchased a kit from a retailer, there’s a fairly good chance your PCB will be solder masked, and have a handy silk screen for component installation.

The PCB itself is a single-sided design. It measures just 88 x 51mm. We could have condensed it, but since the finished project size wasn’t absolutely critical, we spread things out a little to make construction and debugging easier.

Check your PCB for broken tracks, corrosion, or other manufacturing defects. Give it a good clean with some isopropyl alcohol or circuit board cleaner, to help remove any grease or residue that may exist. This will help reduce the incidence of dry joints and other problems.

Use the lowest temperature possible for the solder you’re using, to help avoid overheating the PCB and components, which can be easily damaged with excessive heat.

As with all PCB builds, we follow a hardware, passives, semiconductors type construction pattern. This means you should install IC sockets (if you’re using them), pin headers for the 5V and digital outputs, DC socket, and tactile switch. Then move on to the resistors and capacitors (take care to orient the electrolytic capacitor correctly). Then insert the LEDs, diode, two transistors, and the sensor itself. Orientation is critical for all of the semiconductors, so take care to follow the orientation marked.

The two transistors are installed with room to lay flat, with their collector facing down (that’s the electrical contact on one side of the case). We have provided provision to put a small bolt through to hold them down, however it’s not really necessary. Do not insert the 74HC595 or the ATtiny85 yet.


The PCB itself does have several accommodations for additional expansion. This includes two additional digital outputs from the 74HC595, as well as a 5V power rail. This would allow you to easily switch a relay or some other device, to switch on an exhaust fan or similar if high CO levels were detected (for example).

This additional provisioning means you don’t have to try and hack about on the PCB to take advantage of the unused outputs. However we’ve left these as empty pads, so if you don’t anticipate using them you can disregard them entirely.


The code for our PCB version is not too dissimilar from our prototype version, however some changes need to be made for the difference in hardware.

In order to programme the ATtiny, you’ll need a USB ATtiny compatible programmer.

We have provided the basic sketch. Check out gas_sensor.ino in the digital resources. This sketch will work “out of the box”, but you really need to update the alarm threshold values you have noted, after running the prototype for a few days to run in the sensor.

We suggest around a 25% margin on your values. Therefore if you have a value of 400 from the prototype, update the code threshold to 500. This gives you some wiggle room for natural fluctuations, while still having an effective alarm state.

Note: you need to confirm values for carbon monoxide and also combustible gas. These values are different for each.

We had good success with a value of 150 for carbon monoxide and 450 for hydrocarbons. It was easily tested with a little butane in the air etc. However as close to the ambient levels you can get, the more sensitive the alarm will be. This is why it's best to test your own sensor and your own installation each time.

#define coThreshold 150
#define hcThreshold 450

Simply update the required values. If you find you are getting too many false alarms, you could easily update it.

We won't go through all the code here, but it's well documented and there are a few things you can modify easily, such as a the test duration.

Around line 105:

for (counter = 0; counter < 90; counter++)

You can easily update the 90 to speed up or slow down the cycle of testing between gases. 90 seconds appeared to be a good compromise between letting the sensor settle down between changes in heater voltage.

We can't see too many scenarios where faster would be more appropriate, but you could feasibly slow it down for more stability.


Take a good look over everything and double-check that your component locations match the overlay. Look for solder that’s bridging things it shouldn’t (component legs or tracks), any solder joints that don’t look perfect, or any other foreign matter such as component leg scraps and things that can easily create short circuits.

Next, apply power without the IC or the ATtiny85 connected. You should see no illuminated LEDs. Take your multimeter and check for 5V across pin 8 and 4 of the ATtiny’s IC socket (as shown).


You should also find 5V between pin 16 and pin 8 of the socket for the 74HC595. Check this carefully also. If the voltage is reversed, too high, or non-existent, you may have a short circuit or other problem with your PCB.


Note: you will not find 5V (or any notable voltage) on the sensor. Power is applied to these by the ATtiny85, which switches on the transistors (one at a time).

Once you have confirmed all of these things, you can insert your 74HC595 (taking care of orientation). Once your ATtiny85 is programmed you can then also insert it.

3d case


We have modelled our case something akin to a typical smoke detector. It has a fairly low profile to make it unobtrusive, but there’s much to be said for familiar design. As humans, most of us will recognise a smoke detector as just that. By modelling our gas sensor in a similar way, even someone who isn’t aware of what it is, may take appropriate action (i.e. get out of the house) if a familiar-shaped object starts making alarming noises at them! There is no need to use our case specifically, but it is a convenient way to mount the PCB and install it.

The case is comprised of three pieces. The mounting plate, the front cover, and the breather cover. The mounting plate can be screwed to your preferred mounting location. The front panel then mounts the PCB, with the LEDs and sensor protruding through the cover (or at least, sitting flush, depending on how you installed them). Finally, the breather cover allows air to flow, while also protecting the sensor from physical damage should it be bumped or poked.

There is also an access hole at the bottom for your power supply. While it may look more aesthetically pleasing to have the cable hidden, most people aren’t going to have mains power / 5V that they can connect in a hidden way. This sensor doesn’t have to be mounted high like a smoke detector. Carbon monoxide in particular has the same density as air, so there’s no need to mount it high or low. In fact studies on the best placement to detect concentrations of CO have determined that any height in a room is suitable.

When it comes to combustible gases however, their density can be more or less than the air we breathe, depending on the type of gas. So some consideration to what you’d like to preferentially detect should be given. LPG (such as for a BBQ or outdoor heater) is heavier than air. Natural gas however is a little lighter than air, so will tend to float higher.

In most enclosed spaces (such as a kitchen or lounge room) however, thermal convection and normal actions of walking around, will stir up these gases enough that a modest concentration will still trigger the sensor. However if your home uses LPG (usually bottled) compared to natural gas (usually piped via infrastructure) then you may like to preference the mounting location based on this information.

Print all three items in your preferred colour (we have gone with white to stay neutral and in line with most smoke detectors).

Use two M3 screws to fasten the breather cover to the front cover. You must do this before you install the PCB. The screws cannot be accessed while the PCB is in place. This provides for a cleaner finished front panel, with no screws visible.

The PCB installs squarely on the custom-positioned mounting holes. The mount is offset purely to allow clearance for all sorts of DC plugs, which you may have on your plugpack. We could have made the case larger, but we already have enough space inside to play with, so it seemed more appropriate to offset it. It’s worth noting that you may have to insert your DC plug into the PCB already (leave it disconnected from mains). The plug must be fed through the hole in the front cover, then plugged into the PCB. You can then fit the PCB face-down into the cover.

The style of DC plug you have on your plugpack will determine whether or not you can insert or remove it while the PCB is fixed in place. Our universal style adaptor required this step.

Before you screw things down, check the height of your sensor and LEDs, and make any modifications before screwing it down. If you’re happy with the height of these items you can use four M3 screws to fasten your PCB to the mounts.

check fit

Now everything mounted, you can mount the back cover to your installation location. However it’s usually worth testing everything first! Check-fit the front cover to ensure everything mates as intended; it’s friction-fit, so there are no screws to worry about.

The PCB is also positioned in such a way that the cover will only go on in one orientation. Align the cable entry point to the narrow gap in the back cover. This should automatically align the large gap in the back cover. This is to accommodate the PCB, which is very close to the inner edge of the front cover.

The sensor is deliberately oriented to the bottom of the PCB to avoid any heat from components affecting the sensor. While it’s unlikely, it was an easy decision to make to help avoid any unexpected issues.

With the case assembled, connect your mains adaptor to power, and everything should spring to life!


As we’ve mentioned previously, we included additional outputs for driving relays or other events. You’ll just need to add these functions into the code.

Using these outputs, you could start up air pumps (to pump in fresh air), shut off petrol engines, trigger safety valves, or all manner of things.

Perhaps it’s a little too simple, and you need more careful analysis of levels? If you’re in a commercial factory that has forklifts buzzing past, maybe you’d prefer to average the readings over time to avoid false alarms?

If you’re monitoring a remote site, you could adapt this for IoT and remotely monitor the readings and alarm status. However for most practical applications, simply having an alarm of some kind is usually sufficient.

The functionality of other MQ-series sensors is also fairly similar, so you may like to use this basic system as a springboard for something more specific that you need.