In this tutorial you will learn how to use the Dust Sensor DSM501a with an Arduino to assess air quality.
The DSM501 dust sensor module combined with an Arduino projects allows you to monitor air quality. With its ability to detect particles as small as 1 micron, this module is great for measuring concentrations of house dust, pollen, mite, germ, and cigarette smoke that are known causes for respiratory diseases and allergies.
Let’s get started with the required parts.
Required Parts
Apart from the DSM501 you will need an Arduino or other microcontroller with 5V logic. I used an Arduino Uno but any other Arduino board with 5V logic will work just as well.
Dust Sensor DSM501a
Arduino Uno
Dupont Wire Set
Breadboard
USB Cable for Arduino UNO
Makerguides.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to products on Amazon.com. As an Amazon Associate we earn from qualifying purchases.
Basics of the DSM501 Dust Sensor
The DSM501 is a sensor module for measuring particle concentrations. The sensor can detect particle as small as 1µm and can measure the quantity of floating particles in a room with a size of up to 30m3. The picture below shows the back and front of the sensor module.
Function
The sensor works by using a heating element to generate an inflow of air. The particles in the inflow are illuminated by an IR diode (LED) and the amount of reflected light is measured by an Infrared sensor (PT). This measurement is then converted to q PWM output signal. The picture below shows the location of the components and the functional principle of the sensor.
And here is a picture of the interior of the DSM501. You can see the resistor that works as a heating element at the bottom, the IR Photodetector at the right, and the IR LED at the left.
Installation
The sensor should be installed in the “vertical” position depicted below. Only in this orientation will the heated air flow upwards, passed the LED and detector element. Make sure to keep the sensor away from other artificial airflows (fans) and sources of moisture.
The lens in front of the IR detector (PT) is coated with an anti static and anti dust polymer. But it still should be cleaned every six months for office environments and every three months for industrial environments.
The module has a VR trimmer for sensitivity adjustment but it is pre-set and you should not change it.
Pinout
The following picture shows the pinout of the DSM501. The control pin you can ignore for now. Vout1 and Vout2 are the PWM outputs. Vout2 detects particles > 1µm and Vout1 detects particles > 2.5µm. VCC and GND are the power supply pins. The sensor module operates on 5V.
Note that the DSM501 module usually come with a prefabricated connecter and cable that has the wrong color coding! Don’t get fooled by it. Black is NOT ground and red is NOT VCC. See the picture below and watch out for this.
Now, a quick word about control pin. You can adjust the particle size sensitivity of Vout1 by adding a resistor between the control pin and ground. But we are not going to use it and go with the defaults: Vout2 (> 1µm) and Vout1 (> 2.5µm). For more details see the datasheet. The picture below shows how the PWM signal of the Vout pins changes, depending on the particle sizes detected.
Specification
Below you will find the specification of the DSM501. The most important part to take note of is the 5V supply voltage and the fairly high power consumption of 90mA due to the heating element.
- Supply voltage: DC5V±10%
- Power consumption : 90mA
- Operating temperature range : -10~ +65℃
- Operating humidity range: 95%RH or less
- Recommend storage condition: -20~ +80℃
- Dimension: W59 * H45 * D20 (mm)
- Detectable particle size: approx. 1µm (minimum)
- Detectable range of concentration: 0 ~ 1.4mg/m3
- Output signal: PWM (pulse width modulation)
- Time for stabilization: 1 minute after power turned on
For more details have a look at the data sheets. There are several slightly different versions. I listed the two, most comprehensive ones below
Connecting the DSM501 to Arduino
Connecting the DSM501 to an Arduino is easy. Start by connecting GND to GND and VCC to 5V. Then connect Vout1 to Pin 7 of the Arduino and Vout2 to Pin 8. The specific GPIO pins are not critical and you can pick others if you like. The control pin of the DSM501 remains unconnected (open). The diagram below shows the complete wiring.
With the wiring finished let’s talk about how we are going to measure particle concentrations before we write any code.
Measuring particle concentrations
The Vout pins of the DSM501 produce a pulse-width-modulated (PWM) signal, where the pulse length depends on the amount of particles detected. To convert this signal into a particle concentration we first have to calculate the so called low pulse ratio, as described below.
The low pulse ratio is simply the percentage of the time the pulse is low during the measurement time t, whereby a typical measurement time is between 5 to 30 seconds. For instance, in the example above the low pulse ratio would be calculated as
Low Pulse Ratio (%) = (t1 + t2 + t3) / t x 100
Particle concentration in mg/m3
Once we we have the low pulse ratio we have to look up the corresponding particle concentration in mg/m3 in the following chart. The red curve describes the typical sensor characteristics, while the blue and red curves are the upper and lower limits.
Obviously, we want to convert the low pulse ratio to a particle concentration programmatically via a formula and don’t consult the graph. You can find various formulas in various blog posts but they tend to be slightly wrong. I therefore picked a few points of the red curve above to replicated the graph and computed a second order polynomial fit. The image below shows the points and the fitted curve.
The coefficients and formula for the polynomial fit are as follows:
c_mgm3 = 0.00258425*r**2 +0.0858521*r – 0.01345549
With this formula we can now compute the the particle concentration in mg/m3 for a given low pulse ratio r.
Particle concentration in pcs/283ml
Similarly, the datasheet provides a second characteristic sensor curve for measuring particle concentrations as pcs/283ml.
This graph shows a linear relationship between the low pulse ratio r and the pcs/283ml concentration up to a concentration of 12000 pcs/283ml, where the sensor saturates. The linear part can be described by the following equation:
c_pcs283ml = 625*r
With these two formulas we have all we need to compute particle concentrations in mg/m3 or in pcs/283ml from a measured low pulse ratio r.
Code for measuring dust concentrations with DSM501
The following code shows you how to measure particle concentrations in mg/m3 and in pcs/283ml for particles of sizes >1µm (PM1) or >2.5µm (PM2.5). Have a quick look at the complete code first before we dive into its details.
const int pinPM25 = 7; const int pinPM1 = 8; const unsigned long sampleTime = 5000; // mSec -> 5..30 sec float calc_low_ratio(float lowPulse) { return lowPulse / sampleTime * 100.0; // low ratio in % } float calc_c_mgm3(float lowPulse) { float r = calc_low_ratio(lowPulse); float c_mgm3 = 0.00258425 * pow(r, 2) + 0.0858521 * r - 0.01345549; return max(0, c_mgm3); } float calc_c_pcs283ml(float lowPulse) { float r = calc_low_ratio(lowPulse); float c_pcs283ml = 625 * r; return min(c_pcs283ml, 12500); } void setup() { Serial.begin(9600); pinMode(pinPM25, INPUT); pinMode(pinPM1, INPUT); Serial.println("Warming up..."); // delay(60000); // 1 minute warm-up } void loop() { static unsigned long t_start = millis(); static float lowPM25, lowPM1 = 0; lowPM25 += pulseIn(pinPM25, LOW) / 1000.0; lowPM1 += pulseIn(pinPM1, LOW) / 1000.0; if ((millis() - t_start) >= sampleTime) { Serial.print("low_% PM25 : "); Serial.println(calc_low_ratio(lowPM25)); Serial.print("c_mgm3 PM25 : "); Serial.println(calc_c_mgm3(lowPM25)); Serial.print("c_pcs283ml PM25: "); Serial.println(calc_c_pcs283ml(lowPM25)); Serial.print("low_% PM1: "); Serial.println(calc_low_ratio(lowPM1)); Serial.print("low_% PM1 : "); Serial.println(calc_c_mgm3(lowPM1)); Serial.print("c_pcs283ml PM1: "); Serial.println(calc_c_pcs283ml(lowPM1)); Serial.println(); lowPM25 = 0; lowPM1 = 0; t_start = millis(); } }
The code starts by defining constants for the input signal pins from the DSM501 and the sample time. The sample time is the time the code spends to make one complete measurement of the particle concentrations.
const int pinPM25 = 7; const int pinPM1 = 8; const unsigned long sampleTime = 5000; // mSec -> 5..30 sec
The datasheets recommends a value between 5 and 30 seconds. A longer sample time gives you more stable but less frequent measurements.
Helper functions
Next we define a helper function to compute the low pulse ratio. It simply divides the accumulated low pulse time by the sample time and multiplies it by 100 to make it a percentage.
float calc_low_ratio(float lowPulse) { return lowPulse / sampleTime * 100.0; // low ratio in % }
The calc_c_mgm3()
function computes the particle concentration in mg/m3. It uses the formula described above. We limit the minimum concentration to zero by calling max(0, c_mgm3)
, since negative particle concentrations do not make sense.
float calc_c_mgm3(float lowPulse) { float r = calc_low_ratio(lowPulse); float c_mgm3 = 0.00258425 * pow(r, 2) + 0.0858521 * r - 0.01345549; return max(0, c_mgm3); }
If you look closely at the sensor characteristics curve you can see that for very low low pulse ratios the computed concentration could become negative.
Similarly, the calc_c_pcs283ml()
function computes the particle concentration in pcs/283ml but limits the maximum concentration to 12500 pcs/283ml, where the sensor is saturates and the characteristic curve is not linear anymore.
float calc_c_pcs283ml(float lowPulse) { float r = calc_low_ratio(lowPulse); float c_pcs283ml = 625 * r; return min(c_pcs283ml, 12500); }
Setup function
The setup()
function initiates serial communication and sets the modes of the pins that read data from the DSM501. The datasheet says the sensor needs about 1 minute of warming-up time until readings become stable. You can enable the corresponding delay
here.
void setup() { Serial.begin(9600); pinMode(pinPM25, INPUT); pinMode(pinPM1, INPUT); Serial.println("Warming up..."); // delay(60000); // 1 minute }
Loop function
Finally we have the loop()
function. It used the pulseIn()
function to measure the low time of each of the two inputs. Note that pulseIn returns the durations in microseconds, which we convert to milliseconds by multiplication with 1000.
void loop() { static unsigned long t_start = millis(); static float lowPM25, lowPM1 = 0; lowPM25 += pulseIn(pinPM25, LOW) / 1000.0; lowPM1 += pulseIn(pinPM1, LOW) / 1000.0; if ((millis() - t_start) >= sampleTime) { Serial.print("low_% PM25 : "); ... Serial.println(); lowPM25 = 0; lowPM1 = 0; t_start = millis(); }
The low times are accumulated until we reach the end of the sample time. Then we calculate the different particle concentrations based on the low pulse ratio and print them out.
Output example
If you run this code, you should see an output similar to the one below on your Serial monitor. The reported concentrations should be close to zero until you expose the sensor to some smoke or dust, as I did.
In the next section, we refine the system and build ourselves a simple Air quality warning system.
Air quality warning system with DSM501
Prolonged exposure to small, airborne particles can cause health issues. A common method to measure the quality of the surrounding air is by counting the concentration of fine particle matter (PM) with a diameter less than 2.5µm. The health risk with PM2.5 is that they can travel deep into the respiratory tract, reaching the lungs and entering the blood stream.
There are various scales to rank the health risk of different concentrations of PM2.5. The following table of Air Quality Categories is from the Victorian Government in Australia.
You can see that the categories ranging from Good to Extremely poor and depend on the concentration of PM2.5 averaged over one or 24 hours. Note that these categories are based on PM2.5 concentrations measured in µg/m3 and not in in mg/m3, which is the unit we have used before. For more detailed information on these levels and their potential impact on health have a look at Air quality categories and general health advice.
We are going to build a simplified Air quality warning system by using only the first three levels (Good to Poor). Depending on the measured PM2.5 concentration the system will switch on a green LED (Good), yellow LED (Fair) or red LED (Poor or worse).
Wiring for Air Quality Warning System
We can use the same circuit as before, with no change to the wiring of the DSM501, and just add the three LEDs with their current limiting resistors. The green LED will be connected to pin 4, the yellow one to pin 3 and the red one to pin 2. The picture below shows the complete wiring.
Code for Air Quality Warning System
The code below is very similar to the code we’ve seen before. The main differences are that we are now switching three LEDs, and that we are measuring PM2.5 concentrations in µg/m3.
const int pinPM25 = 7; const int pinPM1 = 8; const int pinGreen = 4; const int pinYellow = 3; const int pinRed = 2; const unsigned long sampleTime = 30000; // 30 sec float calc_low_ratio(float lowPulse) { return lowPulse / sampleTime * 100.0; // low ratio in % } float calc_c_ugm3(float lowPulse) { float r = calc_low_ratio(lowPulse); float c_mgm3 = 0.00258425 * pow(r, 2) + 0.0858521 * r - 0.01345549; return max(0, c_mgm3) * 1000; } void setup() { pinMode(pinPM25, INPUT); pinMode(pinPM1, INPUT); pinMode(pinGreen, OUTPUT); pinMode(pinYellow, OUTPUT); pinMode(pinRed, OUTPUT); // delay(60000); // 1 minute } void loop() { static unsigned long t_start = millis(); static float lowPM25 = 0; lowPM25 += pulseIn(pinPM25, LOW) / 1000.0; if ((millis() - t_start) >= sampleTime) { float c_ugm3 = calc_c_ugm3(lowPM25); digitalWrite(pinGreen, c_ugm3 <= 25 ? HIGH : LOW); digitalWrite(pinYellow, c_ugm3 > 25 && c_ugm3 <= 50 ? HIGH : LOW); digitalWrite(pinRed, c_ugm3 > 50 ? HIGH : LOW); lowPM25 = 0; t_start = millis(); } }
First we define constants for the pins of the DSM501, the LED pins and the sample time.
Note that we using a sample time of 30 seconds. You could change the sample time to one hour, as used by the Air Quality Categories definition, but that would get you only one reading per hour. The better option, would be to use a sliding window but to keep the code simple, I didn’t implement this.
The calc_low_ratio()
function is the same function as before and the new calc_c_ugm3()
is essentially the same as the old calc_c_mgm3()
function. We just multiply by 1000 to convert from mg/m3 to µg/m3.
In the setup function we set the pin modes and in the loop function we measure the PM2.5 concentration and switch on or off one of the three LEDs depending on the level.
... digitalWrite(pinGreen, c_ugm3 <= 25 ? HIGH : LOW); digitalWrite(pinYellow, c_ugm3 > 25 && c_ugm3 <= 50 ? HIGH : LOW); digitalWrite(pinRed, c_ugm3 > 50 ? HIGH : LOW); ...
For PM2.5 concentration < 25 µg/m3 (Good), we switch on the green LED. For concentration between 25 µg/m3 and 50 µg/m3 (Fair), we switch on the yellow LED and over 50 µg/m3 (Poor), we switch on the red LED.
The following short video clip shows the system in action. You can see the red LED switching on when the sensor is exposed to the dust produced by the moving duster.
And that is your own, little Air Quality Warning System!
Conclusions
The DSM501 is a cheap and easy to use sensor for measuring PM1 and PM2.5 particle concentrations. In combination with an Arduino it allows you to build a simple Air Quality Warning System.
The disadvantage of the sensor is that documentation is somewhat lacking. I had to derive the formulas to measure particle concentrations from the sensor characteristics curves in the data sheet, which is somewhat imprecise. You will find that different articles use slightly different formulas.
I don’t know how accurate the DSM501 is, and without a known particle source, you can’t really calibrate the sensor. However, for approximate estimates of air quality it should be sufficient.
Finally, if you want a sensor that can detect smaller particles, consumes less power and works with an ESP32 have a look at the GP2Y1010AU0F Dust Sensor.
Links
Here some links that I found useful when looking up information on air quality, particle sizes and pollen.
- PM2.5
- Particulate matter (PM10 and PM2.5)
- Particle size matters
- Air pollution – How to convert between mg/m3, µg/m3 and ppm, ppb
- A systematic literature review on indoor PM2.5 concentrations and personal exposure in urban residential buildings
- Recent Insights into Particulate Matter (PM2.5)-Mediated Toxicity in Humans: An Overview
- Characterization of sub-pollen particles in size-resolved atmospheric aerosol using chemical tracers
FAQ
What are health and unhealthy levels of dust density when measured in µg/m3?
Healthy levels of dust density are typically below 50 µg/m3, while unhealthy levels are above 150 µg/m3.
What is the relationship between dust density measured in µg/m3 and Particulate matter PM, specifically PM2.5 and PM10?
Dust density measured in µg/m3 is directly related to particulate matter (PM), including PM2.5 and PM10. PM2.5 refers to particles with a diameter of 2.5 µm or smaller, while PM10 refers to particles with a diameter of 10 µm or smaller. Higher dust density indicates higher levels of PM2.5 and PM10 in the air.
Why is PM2.5 pollution bad for your health?
Of all air pollution measures, PM2.5 pollution poses the greatest health threat. Due to its small size, PM2.5 can remain suspended in the air for long periods of time and can be absorbed deep into the bloodstream upon inhalation.
What are the main sources of PM2.5 pollution?
Common sources of PM2.5 pollution are motor and combustion, industrial processes stoves, fireplaces, and home wood burning, smoke from fireworks and wildfires, smoking, dust and pollen particles.
Can a PM2.5 or PM10 sensor measure pollen?
Most pollen particles are larger than PM2.5 and PM10 particles and would be ignored by a PM2.5 or PM10 sensor. However, while Pollen particles are usually over 10 µm they can break into smaller particles in the PM2.5 range, which can be measured.
Stefan is a professional software developer and researcher. He has worked in robotics, bioinformatics, image/audio processing and education at Siemens, IBM and Google. He specializes in AI and machine learning and has a keen interest in DIY projects involving Arduino and 3D printing.