How clean is clean air? — DIY air quality gauge.

Smog, by Isengardt

Since I became dad I started paying more attention to health issues. I don’t want to wake up one day and realize my child is ill because of my lack of knowledge or negligence.

It didn’t take long to realize that

I live in one of the most polluted cities in Europe…

That is quite bad. I started thinking what i can do to improve the situation.

First of all i bought the air purifier. This way i can have relatively clean air at home for my family to breathe.

The next natural think to do for me is to verify if the thing really makes any difference. There is really just one way to do that properly — it is to measure the air pollution. Since i don’t have access to any air quiality measuring device, i decided to try and do it myself, so

I just got my shiny new dust sensor!

It is a cheap infrared one with huge error, but i think it will be enough for starters.

So let us begin. What i am planning to do is to hook up the sensor to an Arduino, write me some smart software and figure out ways to get the data in some convenient way. I am new to Arduino development, but had some experience with microcontrollers and electronics a while ago, so i think i will be more than able to get things done.

Lets start with a sensor itself. The one i got is a Sharp GP2Y1010AU0F dust sensor. You can find the documentation here[http://www.waveshare.com/w/upload/0/0a/Dust-Sensor-User-Manual-EN.pdf]. It is relatively easy to work with, so let’s begin

Connecting to Arduino board.

The sensor has 4 pins you need to care about.

There are, of course the mandatory VCC and GND pins. Those are just the power supply and ground respectively. They are just used to provide power for the sensor. Since the sensor’s operating voltage is 5V, it makes it easy for us. We just hook up those to appropriate arduino ports 5V and GND and we’re done with them. To be consistent with general electronics standard i will use black wire for GND and red wire for VCC. I highly recommend getting used to standardised wire colors as they will make it much easier to work with any electronics circuit, especially the more complicated ones.

Now comes the interesting part — plugging the actual data pins.

Let’s start with the ILED pin. Looking in the documentation you can see that this is the toggle for the infrared LED diode that is used to measure the amount of dust in the air. To get any results from our sensor we need to power it up. Setting the HIGH level volatage (which is a digital ‘1’) on this pin will turn the ILED on, while setting LOW (digital ‘0’) will turn it off. It is plain to see now that this pin needs to be connected to a digital output of Arduino board to enable it to control the ILED. I will use yellow wire for that and pin 13 of the Arduino.

Only one pin left now — AOUT. This is the most interesting one. It will provide the actual measurement results. Quick look at the documentation tells me this is the analog output. It will provide the information by setting varying voltage level on this pin. So i connect it via a blue wire to the analog input A1 of Arduino.

The finished setup looks like this:

Now let’s try to get something out of this one by writing a

Simple program to operate the sensor.

Fist of all i will set up my pins like this:

const int iled = 13;
const int aout = A1;
void setup() {
pinMode(iled, OUTPUT);
digitalWrite(iled, LOW); //iled OFF by default
}

This is just mirroring the wiring described earlier. There is also no need to configure analog input pins (A0-A5) in Arduino, as they work in analog input mode by default.

Next, let’s look into the documentation to see how the measurement should be acquired.

Pulse-driven wave (from sensor’s documentation).
Sampling timing of output pulse (from sensor’s documentation).

The graphs above imply that:

  1. In order to get measurement result the ILED has to be set to HIGH.
  2. The ILED pulse should last 0.32 miliseconds.
  3. There need to be a 0.28 miliseconds delay for the infrared LED to “heat up” and for the AOUT voltage to stabilize.
  4. After the delay, the reslut can be acquired by measuring the output voltage of AOUT.
  5. Then ILED should be turned off and left to “cool down” for at least about 10 miliseconds (9.68 to be exact).

That may seem complicated at first, but in reality it turns out to be quite easy to implement.

The 0.28ms delay is super easy to implement, just one function call — delayMicroseconds. I decided i do not need to worry about the rest of the 0.32ms pulse, because there is no need to keep the ILED enabled after the AOUT value has been measured, so i just turn the ILED off right after reading the input.

Also, reading the analog input is trivial in Arduino —again, one simple function: analogRead.

Just one detail to look out for: according to the spec, the output voltage is reduced 11 times, so to get the real results i will just multiply the measured voltage right away.

const int measurementDelay = 280;
int aoutValue = 0;
[...]
void loop() {
digitalWrite(iled, HIGH); //enable ILED
delayMicroseconds(measurementDelay); //AOUT stabilization delay
aoutValue = analogRead(aout) * 11; //read AOUT value
digitalWrite(iled, LOW);
delay(1000);
}

Last thing left to do now is to

Display the results

in some way to the user. For now i will use the serial port to send the formatted text data to the PC and display it on my monitor using the tools that come with Arduino. It just requires three more lines of code. Sending text data through serial port (USB) just requires initialization by Serial.begin function and then we can write anything we want with Serial.print function.

setup() {
[…]
Serial.begin(9600); //initialize serial port
}
loop() {
[…]
Serial.print(aoutValue);
Serial.print("/n"); //add linebreak between measurements
}

and i’m done. With this I am able to read the output using the serial port monitor or draw a graph with serial port plotter. Both tools are available through Arduino IDE in Tools menu.

Seriously that is all you need to run the thing… for now at least.

The whole program looks like this:

const int iled = 13;
const int aout = A1;
const int measurementDelay = 280;
int aoutValue = 0;
void setup() {
pinMode(iled, OUTPUT);
digitalWrite(iled, LOW); //iled OFF by default
  Serial.begin(9600); //initialize serial port
}
void loop() {
digitalWrite(iled, HIGH);
delayMicroseconds(measurementDelay);
aoutValue = analogRead(aout) * 11;
digitalWrite(iled, LOW);

Serial.print(aoutValue);
Serial.print(" "); //add spaces between measurements

delay(1000);
}

Where to now?

But wait! What is this even? The gauge just displays some weird voltage values. How am i supposed to figure out what it means?

Well, it doesn’t mean much in the current form, but you can use this simple contraption to get some valuable data after all. As you can see in the documentation, the AOUT voltage is more or less proportional to the amount of particles pollution in the air. This means i am now able make some measurements and compare the results to each other. If one value is much higher then the other, then i know the air is significantly more polluted. This is enough to determine if the air purifier does anything at all.

Here are some initial results of my measurements. They were collected in the span or about 16 minutes on my balcony (red x’s) and in my room with purifier (green squares). According to official measurements, the air pollution level in my city at that time was about 180% of the norm, which translates to PM5 dust concentration of about 90ug/m3, so i expect my gauge to indicate much higher values for the outside test. Sure enough, the average measured voltage is about 20% higher, but i still don’t know what that means in terms of actual dust concentration, but hopefully i will figure it out soon enough.

First measurements results. Red — outside, green — inside.

For now, it turns out the purifier does something! I am planning on expanding and upgrading my little gauge with various bells and whistles, so stay tuned. I will try to post my adventures here.

Good luck with your own sensor!