先說 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,連接電路很簡單,將 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
新浪微博 : @問天鼓