おとといの記事で、酸素を摂るのも大事だが、部屋の中の二酸化炭素を減らすのも重要であると書きました。 ちょうど昨日、二酸化炭素センサ「MH-Z19B」が届いたので、空気中の二酸化炭素値[ppm]を取得してみることにしました。 これより安いものも売っていましたが、安物は届くのに1ヶ月以上かかるらしいので、早く届くものを買いました。
ちなみにppm(=パーツ・パー・ミリオン)とは、0.0001%のことです。二酸化炭素のppmが2,000だと空気中の0.2%が二酸化炭素、ということになります。
1,000ppmを超える辺りから、不調を起こす人もいるらしいです。 また、厚生労働省によると、二酸化炭素濃度が上がらないような設計を促す建築法があるようです*1。
また、気象庁の資料によると、年々大気中の二酸化炭素濃度は上昇しており、現在だと約400ppmを前後しているようです *2。つまりいくら換気しても400ppmが最低値ということになります。
二酸化炭素センサ MH-Z19B
めちゃめちゃゴールデンなんだが。
入力線(5V)、グランド線(0V)、出力信号(PWM)の三端子で二酸化炭素濃度を取得できます。 普通にシンプルで使いやすいと思います。
ハンダ付けしないとブレッドボードに刺せないので、トゲみたいなパーツをつけるのに苦労しました。 ハンダ付けとかするの5年ぶりくらいだ。
内部の仕組みとしては、(1) 赤外線を発するライトと、(2) それを受信するセンサがあります。 そして、(3) 二酸化炭素は特定波長の赤外線スペクトルを吸収しやすいため、受信した(4) 光の減衰度により二酸化炭素濃度を計算するのです。
二酸化炭素を計測する手段は、他には化学反応を用いたものなどがありますが、赤外線を使うタイプが一番手っ取り早いはずです。 (ほこりなどに弱いらしいが)
こんな感じになりました。
PWMについて
PWMに関してざっくり説明すると、1本の導線の電気信号 High(=1)/Low(=0) のみで情報を伝達するための方法です。 たとえば、二酸化炭素濃度[ppm]が薄い場合
High → Low → Low → Low → ... → Low → ... → Low
という表現になります。逆に、二酸化炭素濃度[ppm]が濃い場合、
High → High → High → High → ... → High → ... → Low
のように High が連続して続く感じです。モーターの回転角を制御するために使われたりもします。
プログラムについて
最低限のArduinoプログラムとpythonスクリプトをまとめたものを一旦GitHubに上げておきました。
いくつかのサイトのコードを参考にしたのですが、間違っていたので修正しました。
#define PINPWM 5 #define PINRED 13 long span_high, span_low, lasttime_low, lasttime_high, time_running; long ppm; int val_pwm_prev = LOW; void setup() { Serial.begin(9600); pinMode(PINPWM, INPUT); pinMode(PINRED, OUTPUT); } void loop() { long time_running = millis(); int val_pwm = digitalRead(PINPWM); if (val_pwm == HIGH) { digitalWrite(PINRED, HIGH); if (val_pwm != val_pwm_prev) { lasttime_high = time_running; span_low = lasttime_high - lasttime_low; val_pwm_prev = val_pwm; } } else { digitalWrite(PINRED, LOW); if (val_pwm != val_pwm_prev) { lasttime_low = time_running; span_high = lasttime_low - lasttime_high; val_pwm_prev = val_pwm; /* C_ppm = 2,000 x (T_H - 2[ms])/(T_H + T_L - 4[ms]) T_H: PWM(span high) T_L: PWM(span low) 2[ms]/4[ms]: criterion signal(?) */ ppm = 2000 * (span_high - 2) / (span_high + span_low - 4); int intppm = (int) ppm; Serial.println(ppm); } } if(ppm >= 2000){ val_pwm = 0; } }
(本当はarduino
だがシンタックスハイライトのために.c
扱いにしている)
二酸化炭素センサのマニュアル を読めばだいたい理解できました。
2000ppm以上はスペック上計測不能です。ドライアイスをばらまいたりしなければここまで行かないはずですが。
進捗
グラフ化までたどり着けたので結構満足しています。
換気すると、たしかにゆっくりと400ppmくらいまで下がるのがわかります。
こんな感じでPythonで扱えるようになったので、もうあとは煮るなり焼くなりどうにでもなりそうです。
ハマりどころ
- USB通信
- 1つしか通信のパスが無いらしく、Arduinoのログを見ている状態だとPythonで情報を受け取れない(busy というエラーだけ返ってくる)
- 通信で入ってくる変数の型が違うので、整えるのがめんどい
- やり方: Arduino側で int で送信 → Pythonで UTF-8 にデコード、なぜかこれには改行コードがはいっている str 型のため、改行コードを弾いた上でもう一度 int にキャストする。
- 何故かMac book Airの2つあるUSBポートのうち、片方でArduinoの書き込みが失敗する
- Python
- matplotの「分おきに横軸を刻む」 表示を作るのに90分くらいかかった。オイオイ…
- シリアル通信をするためにimportするのは
import serial
だが、pipで入れるときはpip install pyserial
。話それるけど、PyTorchのapexとかもここら辺間違えるのでちょっとどうにかしてほしい。
おわりに
とりあえず、
CO2センサ → (PWM) → Arduino → (USB通信) → Python
とデータを流すことができたので、あとはAWSのDBに流したり、LambdaからAlexaを喋らせたりできるようにしたいです。 ついでに、Alexa → SwitchBot(リモコンを操作できる)→ エアーサーキュレータ と操作すれば、自動換気も可能かもしれないですね。
Raspberry Pi 使ったほうが携帯性と親和性が高かったかもしれない。ラズパイは今後使うかもしれません。