Arduino Based Air Quality Monitor

The air quality is a pretty big problem in my city. We have a monitoring station but it’s quite far from where I live so I decided to build myself a local, simple and nice-looking air quality monitor. You can learn more about the whole project and how I made it in this video:

Below you can find all the files and code for the project. And here are the parts that I used:

PartLink
Arduino Nanohttps://bit.ly/32xGF06
Air Quality Sensorhttps://bit.ly/36jWXLj
NeoPixel Ringhttps://bit.ly/3lhRM4O

Code

#include <Adafruit_NeoPixel.h>
#include <SoftwareSerial.h>

#define LED_PIN 6 
#define SLEEP_PIN 5
#define MAX_PM1_LEVEL 50
#define MAX_PM25_LEVEL 30
#define MAX_PM10_LEVEL 40
#define NUMPIXELS 24 
Adafruit_NeoPixel pixels(NUMPIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);

// 0 - green, 1 - blue, 2- orange, 3 - red
int last_color = 5;

#define LENG 31   //0x42 + 31 bytes equal to 32 bytes
unsigned char buf[LENG];

SoftwareSerial SoftSerial(10, 11); // RX, TX


void setup() {
  SoftSerial.begin(9600);
  Serial.begin(9600);
  pixels.begin(); 
  pinMode(5, OUTPUT);
}

void loop() {

digitalWrite(SLEEP_PIN, HIGH);
delay(1000L * 60L);
int pm01_level = 0;
int pm25_level = 0;
int pm10_level = 0;

int air_quality[3];

CheckAirQuality(air_quality);

pm01_level = air_quality[0];
pm25_level = air_quality[1];
pm10_level = air_quality[2];


if(pm01_level < MAX_PM1_LEVEL && pm25_level < MAX_PM25_LEVEL && pm10_level < MAX_PM10_LEVEL){
  if(last_color != 0){
  SetColor(0,30,0);
  }
  last_color = 0;
}else if((pm01_level > MAX_PM1_LEVEL && pm25_level < MAX_PM25_LEVEL && pm10_level < MAX_PM10_LEVEL) || (pm01_level < MAX_PM1_LEVEL && pm25_level > MAX_PM25_LEVEL && pm10_level < MAX_PM10_LEVEL) || (pm01_level < MAX_PM1_LEVEL && pm25_level < MAX_PM25_LEVEL && pm10_level > MAX_PM10_LEVEL)){
  if(last_color != 1){
  SetColor(0,0,30);
  }
  last_color = 1;
}else if((pm01_level > MAX_PM1_LEVEL && pm25_level > MAX_PM25_LEVEL && pm10_level < MAX_PM10_LEVEL) || (pm01_level > MAX_PM1_LEVEL && pm25_level < MAX_PM25_LEVEL && pm10_level > MAX_PM10_LEVEL) || (pm01_level < MAX_PM1_LEVEL && pm25_level > MAX_PM25_LEVEL && pm10_level > MAX_PM10_LEVEL)){
  if(last_color != 2){
  SetColor(30,10,0);
  }
  last_color = 2;
}else if(pm01_level > MAX_PM1_LEVEL && pm25_level > MAX_PM25_LEVEL && pm10_level > MAX_PM10_LEVEL){
  if(last_color != 3){
  SetColor(30,0,0);
  }
  last_color = 3;
}
Serial.print("PM01: ");
Serial.println(pm01_level);
Serial.print("PM2.5: ");
Serial.println(pm25_level);
Serial.print("PM10: ");
Serial.println(pm10_level);

digitalWrite(SLEEP_PIN, LOW);
delay(1000L * 60L * 3L);

}


void SetColor(int r, int g, int b){
  
  for(int a = 255; a > 0; a--){
    pixels.setBrightness(a);
    pixels.show();
    delay(20);
  }
pixels.clear();
pixels.setBrightness(255);
pixels.show();
  for(int i = 0; i < NUMPIXELS; i++) { 
    pixels.setPixelColor(i, pixels.Color(r, g, b)); 
    pixels.show();   
    delay(50); 
  }
  
  

}

void CheckAirQuality(int* air_quality){
  if(SoftSerial.find(0x42)){    //start to read when detect 0x42
    SoftSerial.readBytes(buf,LENG);

    if(buf[0] == 0x4d){
      if(checkValue(buf,LENG)){
        air_quality[0] = transmitPM01(buf); //count PM1.0 value of the air detector module
        air_quality[1] = transmitPM2_5(buf);//count PM2.5 value of the air detector module
        air_quality[2] = transmitPM10(buf); //count PM10 value of the air detector module
      }
    }
  }
}


char checkValue(unsigned char *thebuf, char leng)
{
  char receiveflag=0;
  int receiveSum=0;

  for(int i=0; i<(leng-2); i++){
  receiveSum=receiveSum+thebuf[i];
  }
  receiveSum=receiveSum + 0x42;

  if(receiveSum == ((thebuf[leng-2]<<8)+thebuf[leng-1]))  //check the serial data
  {
    receiveSum = 0;
    receiveflag = 1;
  }
  return receiveflag;
}

int transmitPM01(unsigned char *thebuf)
{
  int PM01Val;
  PM01Val=((thebuf[3]<<8) + thebuf[4]); //count PM1.0 value of the air detector module
  return PM01Val;
}

//transmit PM Value to PC
int transmitPM2_5(unsigned char *thebuf)
{
  int PM2_5Val;
  PM2_5Val=((thebuf[5]<<8) + thebuf[6]);//count PM2.5 value of the air detector module
  return PM2_5Val;
  }

//transmit PM Value to PC
int transmitPM10(unsigned char *thebuf)
{
  int PM10Val;
  PM10Val=((thebuf[7]<<8) + thebuf[8]); //count PM10 value of the air detector module
  return PM10Val;
}

It’s hard to create a nice schematic for this project as there is no Fritzing library for PM2.5 sensor, and I have no idea how to create one 🙂 That’s why below you can find a text only explanation on connection, definitely not a perfect option but at the same time better than nothing:

DevicesArduino
Air Sensor RXPIN 10
Air Sensor TXPIN 11
Air Sensor 5V5V
Air Sensor GNDGND
Air Sensor SLEEPPIN 5
LED Ring DIPIN 6
LED Ring 5V3.3V
LED Ring GNDGND

As you can see in the table above I connected LED ring 5V to the 3.3V on the Arduino, that’s because there is only one 5V pin on Arduino Nano and it has to be used for Air quality sensor because it doesn’t work with 3.3V.

Thanks a lot for reading and happy making! I hope my air quality sensor will serve you well! And don’t forget to check out my other projects:

Object Tracking Robot – FollowBot V2

This is a second version of original FollowBot made in 2015. This one uses Maix Sipeed board with a camera and LCD screen. With 2 micro servo motors I made a small pan-tilt mechanism. Here you can read some more about how I made this project.

I decided to use new Maix Sipeed board, it’s quite powerful, has build in camera and you can program that in python so I though it should be quite easy to make such project with this board. I was right. If you have at least a little bit of experience with Python and electronics you can do some really cool stuff.

Firstly I had to develop a simple program for tracking red objects. I started by using blob detection algorithm. Basically it searches for all red blobs on the image and store that in a table. Then I had to find the biggest blob as that’s most likely what I want to track (simple for loop with one if statement and one variable can do it). And that’s it, within 40 lines of code you can detect simple single color objects. You can read more about that and find some examples here:

https://maixpy.sipeed.com/en/libs/machine_vision/image.html

https://github.com/sipeed/MaixPy_scripts

Parts

PartLink
Maix Sipeedhttps://bit.ly/31BwNCA
Robot Chassishttps://bit.ly/31zBVXK
Motor Driverhttps://bit.ly/31yPs1V
Servohttps://bit.ly/2EqHQ96
Batteryhttps://bit.ly/3jrPVJr
[mailerlite_form form_id=2]

There is no servo library for this board so that’s a downside because you need to figure out on your own how to control a servo (later I noticed that there is a servo example on github linked above). Servo is controlled with 50Hz PWM signal, high signal should be between 1 ms – 2 ms so that’s a duty of 5-10% (5% * 1/50s = 1 ms, 10%*1/50s = 2 ms). With a timer I was able to set up such PWM signal, a simple servo example can be found in all of the files (you can download them at the bottom of the page).

I also designed my own minimal pan and tilt mechanism in Fusion360. STL files are also at the bottom of this page.

I made my own functions to control DC motor driver but that was obviously very easy. Here is how I connected the motor driver and servos to the board.

Connection

Maix SipeedDC Motor Driver/Servo
PIN 0Pan Servo Signal
PIN 1Tilt Servo Signal
PIN 9Motor Driver ENA
PIN 10Motor Driver IN1
PIN 11Motor Driver IN2
PIN 12Motor Driver IN3
PIN 13Motor Driver IN4
PIN 14Motor Driver ENB
GNDMotor Driver and Servo GND
5VMotor Driver and Servo 5V

After that I simply connected all small programs that I wrote and put everything on my robot chassis. And it was time for the final test that you can see on the video below.

Here you can find a ZIP archive with all the files including my small subprograms, main followbot.py and all STL files that you can print. Feel free to edit those and customize this project to make it work for you. Don’t forget to share your work with others and link to my project 🙂

Thanks for reading this short project description, it’s definitely not a full tutorial but I hope it will be helpful for some of you!

How to build 3D printed Dremel CNC?

Try typing Dremel CNC to Google or Youtube, the internet is filled with my videos and tutorials about building 3D printed Dremel CNC. I kind of feel just like repeating over and over the same content and that is creatively hard for me because I like creating new stuff the most and not focusing on past projects.

At the same time, I understand that a lot of people want to build DIY Dremel CNC because it’s simple, cheap, and inexpensive, totally understandable! A CNC machine that can be easily 3D printed and assembled with easy to buy components, that was the goal of this project, and looking at reviews of hundreds of makers all around the world I think the project turned out perfectly! I am more than happy that such a simple idea of mine can help so many makers, businesses and people. As you may know, I am working on a new bigger CNC machine called IndyMill, that’s why I created this website to share all the info about this machine, release files, and maybe even create a small business out of that! But I don’t want to forget about Dremel CNC and I know there is still a lot of people that want to build it but don’t know where to start. That’s why I made this post, actually, the first one on indystry.cc, I hope to make some more in the near future 🙂 Let’s start!

Continue reading “How to build 3D printed Dremel CNC?”