t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

Arduino Pro MicroとラズパイとAmbientで空気モニター(温度、湿度、気圧、PM2.5、CO2)

今回は以前プロトタイプを作成した環境センサーを普段使いできる形に整えていく。

以前の記事はこちら。
thom.hateblo.jp

作成するもの

前回のハード

f:id:t-hom:20201108113845p:plain
前回はこんな感じでブレッドボードにセンサー類を挿していただけなのですべてむき出し。
普段使いするにも邪魔になる。

今回のハード

f:id:t-hom:20201129122733p:plain
今回はケースに収めて壁に設置した。見た目にもスッキリしてとても良い。

前回のソフト

f:id:t-hom:20201108114614p:plain
前回はArduinoのシリアルモニタに表示させただけ。PCで常にシリアルモニターを開いていないと見えない。

今回のソフト

f:id:t-hom:20201129123252p:plain
今回はラズパイ経由でAmbientというクラウドサービスに連携することでデータをグラフ化することにした。

材料

センサー類

センサー類は前回の記事と変更ないので説明を省略する。

Arduino

PS4コントローラーの記事では3.3V版だったが、今回は5V版のPro Microを使用した。
二酸化炭素センサーとホコリセンサーが5Vで動作するためである。
※温湿度気圧センサーはレギュレーターが入っているので入力は5Vでも3.3Vでもどちらでも動作するらしい。

ミニブレッドボード

これはArduino Pro Microを差し込む用のブレッドボード。
裏が両面テープになっているのでケースに張りつけられる。

あと、名刺くらいのサイズのブレッドボードの電源ラインだけ分離させて、電源集約用の材料として使っている。

ケース

タカチ電機工業の「PF15-5-15W」というケースを選択。
これ、型番で検索してもドンピシャでヒットせず、シリーズのページにたどり着くので割と困る。
写真と商品が違ってたりするので、同じ物を購入する場合は型番とサイズに注意。
f:id:t-hom:20201129125027p:plain

あとPFとPPFは似てるけど形状が違うのでそこも注意。

ケースのサイドパネル

サイドパネルは付属しているが、穴あけ加工に失敗すると取り返しがつかないため最初から3Dプリンターで作成することにした。
f:id:t-hom:20201129125648p:plain

寸法はこちらのサイトで確認できる。
https://jp.misumi-ec.com/vona2/detail/222005614912/?HissuCode=PF15-5-15W

接着式基盤スタンド

サンハヤトのSPT-300を使用した。
https://www.sunhayato.co.jp/material2/afp03/item_1115

これはセンサー類をケースに固定するパーツである。
両面テープでケースに貼り付けることで、取り付け用のネジ穴になる。

センサーケーブル類

センサ類のケーブルが長いとごちゃっとするので圧着端子と圧着工具を買ってきて自分でジャンプワイヤーを作った。

ワイヤ

ワイヤストリッパー(被膜を剥く工具)

コネクタ

圧着工具

あと埃センサーは日本圧着端子のEHコネクター5ピンで接続されてたのでそちらも購入。
http://www.jst-mfg.com/product/pdf/jpn/EH.pdf

既存のケーブルを切っても良かったけどもったいない気がして。。これは上記のコネクタとはサイズが違う為EHコネクタ用の圧着端子が別途必要である。大阪のシリコンハウス(実店舗)でケーブルに圧着済のものが売られていたので、コネクタと圧着済ケーブルを購入した。

USB

ケースにUSB差し込み口を作りたいのでUSB Micro-DIP化基盤も準備

基盤からケース内部でUSBケーブルに戻してArduino Pro Microに接続するためのアダプタケーブル

ケースファン

ケースファンは冷却の為ではなく、ケース外の空気を取り込んで埃センサーを正しく反応させるためのもの。

ホットボンド

これはケースのサイドパネルにケースファンとUSB基盤を取り付けるのに使用した。
本当は3Dプリンターで固定用の機構まで出力できれば良いのだが、そんな技術力がないのでホットボンドで代用。

配線図

f:id:t-hom:20201129132516p:plain

ピン番号等はほとんど前回と同じであるが、Arduino Pro MicroはSDA、SCLが2番・3番に割り当てられているので、そこだけ違う。
ピンアサインは以下のサイトで調べられる。
qiita.com

実際の配線

f:id:t-hom:20201129140746p:plain

まずケース内にパーツを仮配置してブレッドボード・接着式基盤スタンドを貼り付けてからセンサー類を固定。
その後、ケーブルの長さを決めて圧着し接続。
ケースファンとUSB受け口の基盤はそれぞれホットボンドで固定すれば完成。

サイドパネルの3Dモデリング

Autodesk Fusion 360は非商用ならも無償で利用できる。
本格的な解説はしないけど、雰囲気だけ紹介する。

まず、スケッチ作成ボタンをクリックする。
f:id:t-hom:20201129141716p:plain

次にスケッチする面を選択。ここでは低面をクリック
f:id:t-hom:20201129141822p:plain

線分を選択
f:id:t-hom:20201129141930p:plain

てきとうな台形を書く。書いてる途中で寸法も一応出るけど無視して超テキトーな形でOK。ただし底辺と上辺の平行は出しておきたい。
f:id:t-hom:20201129142023p:plain

寸法ボタンをクリック。
f:id:t-hom:20201129142159p:plain

角度や寸法を入れていく。
f:id:t-hom:20201129142418p:plain

フィレットボタンをクリック。
f:id:t-hom:20201129142534p:plain

フィレットを上辺の隅に設定する。
f:id:t-hom:20201129142634p:plain

スケッチを終了すると視点が斜めにもどる。
f:id:t-hom:20201129142730p:plain

押し出しツールを選択する。
f:id:t-hom:20201129142812p:plain

矢印が現れるので、上に引っ張る。
f:id:t-hom:20201129142844p:plain

最後に寸法を手入力して立体の完成。
f:id:t-hom:20201129142924p:plain

あとは穴ツールでファン用の穴を空けたりするだけ。
f:id:t-hom:20201129143050p:plain

実際にはもう少しだけ複雑なスケッチを書いてるけど雰囲気はこんな感じである。

完成したらSTL形式でエクスポートし、さらにUltimaker Curaというソフトで3Dプリンター用のデータに変換する。
Curaは基本的にSTLを読み込んでそのまま3Dプリンター用データをSDカードに書き込んでるだけなので、特に説明することはない。本当はここで材料設定とかサポートとか密度とかを設定するらしいんだけど、知識不足のためほぼデフォルトでしか使ったことがない。

Arduino側のコーディング

前回との変更点は、データ取得タイミングをまとめて最後にスペース区切りのデータとしてシリアル送信するようにしたことである。他は特に変わっていない。書き込みはArduino Leonardoボードを選択する。ただし、このあとPCからラズパイに接続しなおす再に結構トラブルがあって、データが来てるのかどうか良く分からない事象が発生したので、私の場合はラズパイ自体にArduino IDEをインストールしてそこから書き込むようにした。

//for CO2
#include <SoftwareSerial.h>

//for BME
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define SEALEVELPRESSURE_HPA (1013.25)

//for CO2
SoftwareSerial swSer(8, 7);
uint8_t cmd[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
uint8_t reset[9] = {0xFF,0x01,0x87,0x00,0x00,0x00,0x00,0x00,0x78};
uint8_t res[9] = {};
uint8_t idx = 0;
bool flag = false;
uint16_t co2=0;

//for BME
Adafruit_BME280 bme;

//for DustSensor
int pin = 9;
unsigned long t0;
unsigned long ts = 30000; // 30000ms
unsigned long lowOc = 0;
float ratio = 0;
float concent = 0;

void setup() {
  //for Common
  Serial.begin(9600);

  //for CO2
  swSer.begin(9600);
  //swSer.write(reset,9);//calib
  //delay(60000UL);

  //for BME
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

  //for DustSensor
  pinMode(9,INPUT);
  t0 = millis();
}

void loop() {
  uint16_t val=0;
  float t;
  float temperature;
  float pressure;
  float humidity;
  swSer.write(cmd,9);

  //BME
  temperature = bme.readTemperature();
  pressure = bme.readPressure() / 100.0F;
  humidity = bme.readHumidity();

  //DustSensor
  t0 = millis();
  lowOc = 0;
  while((millis() -t0) <= ts) {
    lowOc += pulseIn(pin, LOW);
  }
  ratio = lowOc/(ts*10.0);
  concent = 1.1 * pow(ratio,3) - 3.8 * pow(ratio,2) + 520 * ratio + 0.62;
  
  delay(30000);

  //CO2
  while(swSer.available()==0){
    Serial.println("bad com");
  }
  while(swSer.available()>0){
    res[idx++]=swSer.read();
    flag=true;
  }
  idx = 0;
  if(flag){
    flag=false;
    co2 = 0;
    //delay(100);
    co2 += (uint16_t)res[2] <<8;
    //delay(100);
    co2 += res[3];
    t = res[4];
  }

  Serial.println("data: " +
    String(temperature) + " " +
    String(pressure) + " " +
    String(humidity) + " " +
    String(co2) + " " +
    String(concent));
}

Ambientの登録

Ambientにアカウント登録をしておく。個人利用なら無償のプランで十分である。
チャネルIDとライトキー(書き込み用のID)が入手できれば準備OK。
ambidata.io

ラズパイ側のコーディング

コードの前にラズパイのpythonにambient用のライブラリを導入しておく。

sudo pip install git+https://github.com/AmbientDataInc/ambient-python-lib.git

詳細はAmbientサイトのリファレンスにラズパイでの使用方法が書かれているのでうまくいかなければそちらを参照して欲しい。

ラズパイ側で作成するコードはこちら。ファイル名は任意で良い。
一部可変の箇所があるので後述する。

import ambient
import time
import serial

def pcs2ugm3(pcs):
    pi = 3.14159
    density = 1.65 * pow (10,12)
    r25 = 0.44 * pow(10, -6)
    vol25 = (4/3) * pi * pow (r25, 3)
    mass25 = density * vol25
    K = 3531.5
    return pcs * K * mass25

ser = serial.Serial('/dev/ttyACM0', 9600)
ambi = ambient.Ambient(★チャネルID★, ★"ライトキー"★)

while True:
    if(ser.in_waiting > 0):
        line = ser.readline().split()
        print(line)
        if line[0] == b'data:':
            try:
                r = ambi.send({ \
                    "d1": float(line[1]), \
                    "d2": float(line[2]), \
                    "d3": float(line[3]), \
                    "d4": float(line[4]), \
                    "d5": pcs2ugm3(float(line[5])), \
                    })
            except:
                print("Connection Error")
        else:
            print("Error")
    time.sleep(1)

可変の箇所

以下の2行は環境によって可変となる

ser = serial.Serial('/dev/ttyACM0', 9600)
ambi = ambient.Ambient(★チャネルID★, ★"ライトキー"★)

まずUSBのデバイス名が「/dev/ttyACM0」としているが、これを調べるにはまずUSBを抜いた状態で「ls /dev/tty*」コマンドを実行する。するとデバイスの一覧が出てくる。次にUSBを指した状態で「ls /dev/tty*」を再実行する。ここで出てきたデバイスの一覧と先ほどの実行結果を比べて、増えたデバイスが今挿したUSBである。

まぁ通常は順番に振られるのでArduinoを1台だけ繋いでいたら/dev/ttyACM0になるはず。

次に★チャンネルID★と★"ライトキー"★の部分は自分のチャンネルIDとライトキーに書き換える。
★は目立つようにしただけなので実際には書いてはいけない。

チャンネルIDは整数なのでそのまま記載、ライトキーは文字列なのでダブルクォートで囲む。

実行

Arduino上のセンシングデータはUSBを繋いだ時点で随時ラズパイに送られてるので、あとはラズパイ側で上記のプログラムを動かすだけである。私の場合はコマンド画面を立ち上げっぱなしにしているけど、バックグラウンド実行でも良いかと思う。デーモン化までは面倒なのでやっていない。

Ambient側のグラフ作成は直感的に分かると思うので説明は割愛する。

トラブルシューティング

接続があってるのにArduinoがデータをよこさないことがある。
切り分けとしては、ラズパイ側にArduino IDEを入れてそこでシリアルモニターでデータが来ているか確認する。
ttyデバイス名が合ってるかどうかも再確認。

あとは、電源つないだまま配線いじったりするとプログラムの挙動がおかしくなることが多い。書き込みなおすとうまく動いたりする。USBのつなぎ直しでプログラムがおかしくなるケースにも遭遇したので、やはりラズパイにArduino IDEを入れてしまってそっちから書き込んでしまうのが早いかもしれない。

ちなみに、Arduino Pro Microではそもそも私のPCでは書き込み不可トラブルが発生することがあった。これはNZXTのCAMというソフトを終了させたら改善したので、類似のトラブルが発生した場合は稼働中のソフトウェアとの競合を疑うのも手だと思う。特にCAMのようなハードウェア連携するツールは怪しい。

Ambientのグラフに関してもちょっと変だなと思う挙動がある。最初のグラフ配置はページの左上に収まっていたのにグラフをドラッグしたら左上にマージンができてしまい、元の位置には戻せなくなる。これは気にせずそういうもんだと思ってそのまま使うことにした。

あとがき(余談)

思ったよりボリューム満載の記事になってしまった。モノを作るのって結構大変。
さて、今回はArduinoとラズパイとクラウドサービスAmbientを連携させたが、ラズパイの役割って単にネットワーク機器としてArduinoのデータをAmbientに橋渡ししてるだけなので、無線LAN付きのArduinoを使えばラズパイをかまさなくても同じことができると思う。

そう思って一旦ESP8266という無線付きのマイコンを買ったんだけど、3.3V動作なのでどうもホコリセンサーの信号がうまく拾えず断念した。電圧変換とか色々試したけど今のところうまくいかず。

ただ、最終的には空気の質が落ちたときにアラートを出したりと色々機能を持たせたいのでArduinoはセンシングに専念してラズパイ上でPythonで色々処理できる今回の構成が、ある意味正解かもしれない。

ちなみに技適のことをよく分かってなかったんだけど、そもそも私が買ったESP8266は日本国内で使っちゃダメみたいで、数時間だけ検証したものの廃棄予定である。Amazon.co.jpで売っちゃまずいだろこれ。。

別途技適マーク取得済のESP-WROOM-02というモジュールを買ってきたのでArduino+無線で何かやりたいときはそっちを使うことにする。

参考サイト

概ね前回と同じであるが、今回はラズパイ側でダストセンサーの値をpcs/0.01cfからug/m^3へ変更するのに以下のサイトの関数を使用させていただいた。
algorithm.joho.info

以下は前回と同じ。
algorithm.joho.info
lastminuteengineers.com

以上

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。