Arduino + SmartAirFilter 制作智能感应的 PM 空气净化器
先说 SmartAirFilters
知道 SmartAirFilters 源自微博上转发的非常火的那个帖子,和动辄七八千元的商用产品比,几百元的 SmartAirFilters(下面简称电扇) 确实不贵。一次和朋友在清华科技园里附近的咖啡馆聊天,正好遇见他们在那里做 DIY 体验工坊,作为 DIYer 爱好者,理所应当给个赞,就败了个 1.0 试一试。

空气 PM 的监控
空气过滤效果究竟怎样?作为数据控,理所应当必须看数据说话。正好在玩 Arduino Yun,就起意搞个灰尘传感器监控一下。
设备清单
要搞定空气中的 PM 值检測,网上已经有文章珠玉在前, 英文原文 和中文翻译在此。我使用的设备也类似:
- Arduino Yun
- Shinyei 粉尘检測传感器 PPD42NS
- Grove Base Shield(可选)
- Micro USB 电源(输出为 5V 0.5A 左右就可以)

这里须要说明的是,眼下类似 PPD42NS 的这类微型的空气 PM 检測传感器都是利用光学特性,计算一段时间内观測到的粉尘数量,从而推算出每立方米此类粉尘的数量。而严格意义上的 PM 1.0/2.5 是以每立方米此类粉尘的重量计量的。这两个数据具有较大的相关性,对在日常生活中了解 PM 值的须要来说,PPD42NS 已经可以满足要求。
由于有 Grove Base Shield,连接电路非常easy,将 Grove Base Shield 插到 Arduino 上,然后将 PPD42NS 的接口插到 D8 槽就可以。PPD42NS 需竖直放置。

假设您没有 Grove Base Shield,请按下面连接:
| PPD42NS | Arduino |
|---|---|
| Pin 1 (黑线) | GND |
| Pin 3 (红线) | 5VDC |
| Pin 4 (黄线) | D8 |
Arduino 代码
完整代码请參考 Git 上的 dust_check_simple 部分。
/*
# Smart Air Control #
Program by Iasc CHEN,April 2014
## Grove Dust Sensor ##
Use Shinyei Model PPD42NS Particle Sensor
http://www.sca-shinyei.com/pdf/PPD42NS.pdf
JST Pin 1 (Black Wire) => Arduino GND
JST Pin 3 (Red wire) => Arduino 5VDC
JST Pin 4 (Yellow wire) => Arduino Digital Pin 8
*/
#include <Bridge.h>
// dust check
int DUST_PIN = 8;
unsigned long DUST_SAMPLE_MS = 15000;//sampe 15s ;
unsigned long duration, starttime, now, lowpulseoccupancy = 0;
float ratio = 0, concentration = 0;
void setup() {
Bridge.begin();
Console.begin();
// Serial.begin(9600);
pinMode(DUST_PIN, INPUT);
starttime = millis(); //get the current time;
// while(!Console);
Console.println(" Time , PM ");
}
void loop() {
duration = pulseIn(DUST_PIN, LOW);
lowpulseoccupancy = lowpulseoccupancy + duration;
now = millis();
if ((now - starttime) > DUST_SAMPLE_MS) {
ratio = lowpulseoccupancy / (DUST_SAMPLE_MS * 10.0); // Integer percentage 0=>100
concentration = 1.1 * pow(ratio, 3) - 3.8 * pow(ratio, 2) + 520 * ratio + 0.62; // using spec sheet curve
Console.print(now/1000);
Console.print(",");
Console.println(int(concentration/100));
lowpulseoccupancy = 0;
starttime = millis();
}
}
从 Console 中得到未开电扇的一小时输出数据例如以下,数据文件在此 pm_no_filter.csv。
其数据图形例如以下,经过一小时,PM 值缓慢的从平均约 80,降到约 40:

能更 Smarter 一些吗?
在封闭的室内,当空气过滤达到一定水平之后,PM 值基本稳定。此时假设仍然开着净化器,也仅仅是白白耗电。我们能够设定一下阈值,比如,PM 指数高于 50,自己主动打开净化器;低于 20,自己主动关闭净化器,就比 Smart 更 Smarter 了 。
这个功能能够通过 Arduino 控制继电器来实现。
设备清单
- Arduino Yun
- Shinyei 粉尘检測传感器 PPD42NS
- Grove Base Shield(可选)
- Micro USB 电源(输出为 5V 0.5A 左右就可以)
- 继电器模块,可以控制 200V,10A 电路
- 插座

继电器的引脚连接说明例如以下:
| Relay | Arduino |
|---|---|
| Pin 1 (GND) | GND |
| Pin 2 (VSS) | 5VDC |
| Pin 3 (SIG) | D4 |
插座的改造工作是用继电器替换原有的控制开关。详细操作步骤是:
1 将原有的开关盖子取出2 从开关的两极焊接引出两根线(感谢 @我是国宝 帮助焊接)3 将这两根线接到继电器上的控制引脚上

在上图中中间那个插座用于给 Arduino Yun 供电。左側的插座,在其开关位置连出的两根线接到了继电器上,以下的插头是电扇用的。
Arduino 代码
我在 Arduino 代码中添加�了对继电器的控制,代码改动例如以下,完整代码请參考 Git 上的 dust_check 部分。:
/*
# Smart Air Control #
Program by Iasc CHEN,April 2014
## Grove Dust Sensor ##
Use Shinyei Model PPD42NS Particle Sensor
http://www.sca-shinyei.com/pdf/PPD42NS.pdf
JST Pin 1 (Black Wire) => Arduino GND
JST Pin 3 (Red wire) => Arduino 5VDC
JST Pin 4 (Yellow wire) => Arduino Digital Pin 8
## Relay ##
Relay Pin 1 (Black Wire)=> Arduino GND
Relay Pin 2 (Red wire) => Arduino 5VDC
Relay Pin 3 (Green wire)=> Arduino Digital Pin 4
*/
#include <Bridge.h>
float RELAY_ON_VALUE = 5000;
float RELAY_OFF_VALUE = 2000;
// dust check
int DUST_PIN = 8;
unsigned long DUST_SAMPLE_MS = 15000;//sampe 15s ;
unsigned long duration, starttime, lowpulseoccupancy = 0;
float ratio = 0, concentration = 0;
//relay control
int RELAY_PIN = 4;
unsigned long MAX_RELAY_RUNNING_MS = 1200000;// If after 1200s the air filter are still running, send a warning;
bool relay_on = false;
unsigned long now, relay_start_time, relay_running_time = 0;
void setup() {
Bridge.begin();
Console.begin();
//Serial.begin(9600);
pinMode(DUST_PIN,INPUT);
starttime = millis(); //get the current time;
pinMode(RELAY_PIN, OUTPUT);
relay_start_time = millis();
// while(!Console);
Console.println("Time , PM , Status , Running");
}
void loop() {
duration = pulseIn(DUST_PIN, LOW);
lowpulseoccupancy = lowpulseoccupancy + duration;
now = millis();
if ((now - starttime) > DUST_SAMPLE_MS)//if the sampel time == 30s{
ratio = lowpulseoccupancy / (DUST_SAMPLE_MS * 10.0); // Integer percentage 0=>100
concentration = 1.1 * pow(ratio,3) - 3.8 * pow(ratio,2) + 520 * ratio + 0.62; // using spec sheet curve
Console.print(now/1000);
Console.print(" , ");
Console.print(int(concentration/100));
Console.print(" , ");
if (concentration < RELAY_OFF_VALUE){
if(relay_on){
digitalWrite(RELAY_PIN, LOW);
relay_on = false;
}
} else if (concentration > RELAY_ON_VALUE){
if(! relay_on){
digitalWrite(RELAY_PIN, HIGH);
relay_on = true;
relay_start_time = millis();
}
}
if(relay_on){
relay_running_time = now - relay_start_time ;
Console.print(" ON , ");
Console.println( relay_running_time / 1000 );
// if (relay_running_time > MAX_RELAY_RUNNING_MS){
// Console.println(" => Make sure your doors and windows are closed, or Change Filter!");
// }
}
else{
Console.print(" OFF , ");
Console.println( 0 );
}
lowpulseoccupancy = 0;
starttime = millis();
}
}
将
PM 数值记录爱 Log 文件里
前面的 PM 记录都是输出在 Console 中的,让我们添加�上 log 记录,这样就能够长时间记录家里的空气 PM 值了。
以下的代码实验的性质较大,不不过为了写 log 文件,还验证了 Arduino 调用 Shell 命令的过程。这个方案便于将 Arduino Sketch 变成一个能 “推Push“ 的数据源使用,能够将很多其它地工作放到 Python 或 Shell 中去,提升开发效率。
设备清单
设备同上。
Arduino 代码
下面内容是部分相关的代码,完整代码请參考 Git 上的 dust_check_log 部分。
首先,添加�了用于创建所需的 Shell 脚本的部分,在使用时,请依据您的环境改动文件文件夹和名字:
#include <FileIO.h>
void uploadScript() {
File script = FileSystem.open("/mnt/sda1/workspaces/dust_check/dust_log.sh", FILE_WRITE);
script.print("#!/bin/sh\n");
script.print("echo $(date +'%Y-%m-%d %H:%M:%S') , $1 >> /mnt/sda1/workspaces/dust_check/logs/dust.log");
script.close();
Process chmod;
chmod.begin("chmod"); // chmod: change mode
chmod.addParameter("+x"); // x stays for executable
chmod.addParameter("/mnt/sda1/workspaces/dust_check/dust_log.sh");
chmod.run();
}
其次编写了用于运行这个脚本的部分:
void runLogScript(String msg){
Process logscript;
logscript.begin("/mnt/sda1/workspaces/dust_check/dust_log.sh");
logscript.addParameter(msg);
logscript.run();
}
这些代码在 Sketch 中的调用情况例如以下示意:
void setup() {
...
FileSystem.begin();
uploadScript() ;
// runLogScript("Time , PM , Status , Running");
Console.begin();
}
void loop() {
duration = pulseIn(DUST_PIN, LOW);
lowpulseoccupancy = lowpulseoccupancy + duration;
now = millis();
if ((now - starttime) > DUST_SAMPLE_MS){ //if the sampel time == 30s
...
String output = String(int(concentration/100), DEC)
+ " , " + String(relay_on)
+ " , " + String(relay_running_time / 1000, DEC);
Console.println(output);
runLogScript(output);
...
}
}
查看输出 Log
SSH 登陆上 Linino,进入相关路径,可以查看 Log 文件的输出。
$ cd /mnt/sda1/workspaces/dust_check
$ ls
dust_log.sh logs
$ tail -f logs/dust.log
2014-05-12 19:50:06 , 27 , 1 , 421
2014-05-12 19:50:21 , 40 , 1 , 437
2014-05-12 19:50:37 , 31 , 1 , 452
2014-05-12 19:50:52 , 43 , 1 , 468
2014-05-12 19:51:08 , 41 , 1 , 484
2014-05-12 19:51:24 , 46 , 1 , 500
2014-05-12 19:51:40 , 46 , 1 , 516
2014-05-12 19:51:55 , 43 , 1 , 531
2014-05-12 19:52:11 , 43 , 1 , 547
2014-05-12 19:52:26 , 51 , 1 , 562
2014-05-12 19:52:42 , 43 , 1 , 578
获得的日志数据例如以下,dust_log.csv:此数据由于有调试对 Arduino 和数据收集时间等原因,有部分数据缺失,开关阈值为 50 开, 20 关。其数据图形例如以下(绘图代码參见 draw_log.R )。通过数据图形展示了这个智能感应的 PM 空气净化器的执行情况和效果。粉尘吸附情况和房间大小、以及是否关窗有关。红色区间主要是家里做饭的时候,还有就是俺家厨房烟道有露烟,:(
:
:
总之,如今俺的 Smart Air Filter 可以自己主动开关,效果可以通过数据观測验证,看起来还蛮不错,不是吗?
所有成本
刚又去淘宝上查了一下相关设备,有点小贵(主要是买 Arduino 板子和传感器的时候,以兴趣居多,没考虑价格,当然,也不是仅仅干这个用),供各位參考。
- Arduino Yun ¥480
- Shinyei PPD42NS ¥95
- Grove Base Shield ¥59
- 继电器模块 ¥20
- 插座,超市中买的 ¥20
- Smart Air Filter 1.0 ¥200
预计用更便宜的 Arduino 兼容板和较便宜的器件,可以将总成本控制在 ¥400 元以内。
代码地址
https://github.com/iascchen/smarter_air_filter/
玩的开心!
转载请注明出处
Author : iascchen(at)gmail(dot)com
Date : 2014-5-12
Github : https://github.com/iascchen
新浪微博 : @问天鼓
Arduino + SmartAirFilter 制作智能感应的 PM 空气净化器的更多相关文章
- vs中ctrl+w选中智能感应的整个单词
vs中ctrl+w选中智能感应的整个单词
- 利用Arduino快速制作Teensy BadUSB
0×00 介绍 本文想以较简单的方式,叙述Arduino版BadUSB的制作过程.我知道在这之前已经有很多前辈都写过相关的文章,但小白可能还有点迷糊,所以这篇文章是快速带大家入门了解,我也是菜B大神不 ...
- 利用Arduino快速制作Teensy BadUSB, 攻击计算机
BadUsb介绍 BadUSB是计算机安全领域的热门话题之一,该漏洞由Karsten Nohl和Jakob Lell共同发现,并在2014年的BlackHat安全大会上公布. 虽然已隔一两年,但还是有 ...
- 【Python成长之路】从零学GUI -- 制作智能聊天机器人
[写在前面] 鹏哥:最近老惹小燕同学不开心,结果都没人陪我聊天了.哎,好无聊呀! 肥宅男:女朋友什么的最无聊了,还没我的图灵机器人好玩. 鹏哥:图灵?好巧,和我部门同名. [效果如下] [实现过程] ...
- 基于Arduino开发的智能蓝牙小车
基于Arduino的智能蓝牙小车 材料准备: Arduino开发板一块.四驱小车底板及相关配件一套.L298N驱动模块一个.HC-05/06蓝牙模块一块,九伏电源一块(用于主板供电).12V锂电池一块 ...
- Android开发周报:反编译对抗研究、动手制作智能镜子
新闻 <Android Wear落地中国 谷歌增强安卓生态控制力> :9月8日,由摩托罗拉推出的智能手表Moto 360二代作为国内发售的第一款搭载官方Android Wear的设备,正式 ...
- 微信小程序+OLAMI(欧拉蜜)自然语言API接口制作智能查询工具--快递、聊天、日历等
微信小程序最近比较热门,再加上自然语义理解也越来越被人关注,于是我想赶赶潮流,做一个小程序试试.想来想去快递查询应该是一种比较普遍的需求. 如果你也在通过自然语言接口做点什么,希望我的这篇博客能帮到你 ...
- Arduino系列之智能家居蓝牙语音遥控灯(四)
用到的材料 Arduino uno hc-05 蓝牙模块 安卓手机 安卓APP AMR—voice 通过安卓手机连接Arduino的蓝牙模块Hc-05,通过语音识别软件AMR-voice识别语音, ...
- Ajax制作智能提示搜索
一.效果图: 二.实现过程: 思路: 三.部分代码: html: <div id="searchbox"> <div><input type=&quo ...
随机推荐
- HDU - 4420 2013icpc长春A 函数离散化 + st表
思路:我们定义F(x) 为以x点为起点,向后(a - b)个里面有多少个白球,虽然x的范围是LL范围内的,但是白球的 个数只有1e5, 那么我们可以把连续一段相同的离散化到一起, 对于一个确定的长度为 ...
- Django实战(9):实现Product的输入校验
让我们完成上一节中的任务: 1.验证price>0:需要在Form中验证: 2. 验证title唯一:在Model中验证: 3. 验证image_url的扩展名:在Form中验证,还可以顺便在M ...
- tp5总结(四)
数据库 1.数据库配置 1-1.配置文件配置[http://ww:7070/tp5-3/public/] 1-2.Db::connect配置[数组和字符串方式][http://ww:7070/tp5- ...
- 【Java】java.lang.NullPointerException的两个原因
自己写程序时出现过 java.lang.NullPointerException错误的一些原因 (1)自己建立了一个数组,但每个数组元素没单独初始化(单独new一个新对象). (2)在进行if (ar ...
- Dubbo的静态服务
Dubbo中,dubbo可以自动搜索到服务上线,并注册,同时,也可以知道服务下线,自动从注册中心去掉服务. 但是静态服务就可以做到人工管理. 1.场景 有时候希望人工管理服务提供者的上线和下线,此时需 ...
- Dubbo的直接提供者
1.场景 在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,点对点直联方式,将以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点对点,不影响 B 接口从 ...
- 【面试总结】2019校招京东一面二面,及深信服技术面(已拿深信服offer),还有百度一面
百度一面: 1.自我介绍+项目介绍 2.进程和线程的区别 3.常用linux命令列举 4.堆排序 5.快速排序 反问环节. 现在的状态是岗位转推,毕竟百度投的是开发岗. 京东一面: 1.C++三大特性 ...
- web服务端安全之权限漏洞
一.权限漏洞 访问控制是指用户对系统所有访问的权限控制,通常包含水平权限,和垂直权限. 水平越权:同一角色级别的用户之间所产生的问题,如A用户可以未授权访问B用户的数据: 垂直越权:不同角色级别的用户 ...
- 1016 Phone Bills (25)(25 point(s))
problem A long-distance telephone company charges its customers by the following rules: Making a lon ...
- android view surfaceView GLSurfaceView
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 表面视图 SurfaceView 是 视图 的子类, 刷新界面速度比 视图 块, 因为它 ...