生産現場IoTへの挑戦 #06　～いろいろなデータを採取する～

#1.はじめに
久しぶりの更新です。
[前回の記事](https://camo.qiitausercontent.com/7b569869305cc1aa9871a92b72c9a96723de3a3e/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3439363137392f35373263376439662d616439612d653633352d353831332d3630323065303936396432362e706e67)でRPiにmariaDBをインストールして記録用のDBを作るところまで書きましたが、その後いろいろ試行錯誤してセンサデータを採取できるようになりました。素人仕事で始めたプロジェクトでしたが、なんとか実用レベルに近づいてきました。
今回と次回の記事で、データの記録とGrafanaを使った可視化についてご紹介します。
ちなみに、完成するとこんな感じの出力が得られます。![dashboard 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/8690516a-9d69-66d4-69eb-1e193b38b6ae.png)

#2.システム全景
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/8958851d-818c-6146-ac76-de69f2c94d3b.png)
今回はこのシステムの内、BMP280とADS1115Sの接続部分です。
リアルタイムクロックのDS3231と合わせると以下の様にI2C接続します。

| ラズパイ | DS3231 | BMP280 | ADS1115 |
|:-:|:-:|:-:|:-:|
|3V3(Pin1)|VCC|VIN|VDD|
|GND(Pin9)|GND|GND|GND|
|GPIO2(Pin3)|SDA|SDA|SDA|
|GPIO3(Pin5)|SCL|SCL|SCL|

実際に接続した状況は次の様になりました。
<img width="500" alt="board.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/4709fb6a-391b-0810-c507-368cc017a9fc.png">

基板は2枚に分けていますが、RPiから引き出したI2C Busを一枚目のI2C分配基板に接続し、この基板にはDS3231、BME280（とSSD1306というディスプレイ）を接続しています。
I2C Busはさらにアナログ入力用の基板に接続して、この基板上でADS1115に接続しています。さらに別の基板を接続したい場合にはI2C Busを使ってデイジーチェーンします。



#3.データの採取
センサデータの採取方法はいろいろありますが、ここでは代表的な採取先として、BME280による温度・湿度・気圧データの採取、ADS1115によるアナログデータの読み取りの例について取り上げます。
実行環境はRPi 4B + RPi OS + python3.8です。

##3-1.BME280を adafruit circuitpythonライブラリで動かす
BME280は気温、湿度、気圧のセンサーが一つにパッケージされています。似たセンサーにBMP280というセンサーもあり、これは気温、湿度のみのセンサーです。生産現場に気圧が大きな影響を与えるケースは少ないと思いますが、これからの季節、台風接近に伴い急激に気圧が低下する様子を見えるかすると結構わくわくするのでBME280をお勧めします。

アマゾンだと、BMP280をBME280として出品されているケースがありますのでご注意ください。詐欺というより、単純に間違えている気がするのですが、一向に修正される気配はありませんね。
ちなみに左がBME280、右がBMP280です。
<img width="200" alt="419keCde-kL._AC_SX466_.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/b9d0c20a-f4b5-1086-4ad7-da8058bc3add.jpeg"><img width="200" alt="61jxaYY-q8L._AC_UL320_.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/ff836a11-17dc-a4f1-b9b0-0b3d90601bc5.jpeg">

最近BME280が値下がりしていて、BMEもBMPも3個900円前後で販売されていますが、これらは中国発送だと思われます。お急ぎの方は、少々高いですが納期を確認してお高い（3個1500円くらい）のものを選んだ方が良いでしょう。中国発送品を買うならAliexprssで買うのもありです（私はAliexpressを良く使用します）

###3-1-1.ライブラリインストール
BME280もいろいろな方法で動かせますが、Adafruitのcircuitpython用ライブラリで動かします。
Adafruitのライブラリ群はとても充実していて使いやすいので最近よく使っています。
ただし、現バージョンのBME280ライブラリはインストールがうまくいかないので次の方法で手動インストールします。

①githubにアクセス


https://github.com/adafruit/Adafruit_CircuitPython_BME280

②「code」→「Download ZIP」でダウンロード
③解凍して「adafruit_bme280」フォルダを/usr/local/lib/python3.7/dist-packages/に移動する

また、circuitpython系のライブラリもインストールしておきます。

```sh
$ sudo pip3 install --upgrade adafruit-python-shell
$ wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/raspi-blinka.py
$ sudo python3 raspi-blinka.py
$ sudo pip3 install adafruit-circuitpython-bme280
```


###3-1-2.テストコード
※2021/9/21動かなくなっていたので一部修正

```python
import board
import time
from adafruit_bme280 import basic as adafruit_bme280

i2c = board.I2C()
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c,address = 0x76)

while True:
    print("\nTemperature: %0.1f C" % bme280.temperature)
    print("Humidity: %0.1f %%" % bme280.relative_humidity)
    print("Pressure: %0.1f hPa" % bme280.pressure)
    time.sleep(5)
```

これで、5秒おきに温度、湿度、気圧が表示されます。

#3-2.ADS1115を adafruit circuitpythonライブラリで動かす
ADS1115はアナログ信号をデジタル信号に変換してくれるADC(Analog Digital Converter)です。開発用ボードが安く販売されていますのでそれを利用します。amazonで1000円/2個ぐらいで販売しています。
ADS1115一枚当たり4chの入力端子を持っています。私が作成したアナログ入力用ボードにはADS1115を2枚載せて、8chまで入力可能としています。必要であればこのボードを2枚接続し、最大16ch入力可能です。
ASD1115とRPiはI2C通信しますが、ADS1115は0x48,0x49,0x4A,0x4Bの四つのアドレスを選択できるため、一つのI2C Busに4枚まで同時接続できます。16ch以上の入力が必要な場合は複数I2C Busを使用するか、IOエキスパンダーなどを用いましょう。

ADS1115はADCだと書きましたが、その働きを簡単に説明すると電圧を測定して数値化する装置です。
ADS1115は16bitのADCですので、入力端子の電圧を測定し、0～5Vの電圧を0～65535の数値に変換します。デジタルに変換された数値が10000だとすると、入力された電圧は、

5[V] × 10000/65535 ≒ 0.763[V]

だったことが判ります。
また、そのとき使用しているセンサが0～100[℃]の温度を0～5[V]の電圧に変換して出力するセンサであったとすると、

(100[℃] - 0[℃]) / 5[V] × 0.763[V] + 0[℃] = 15.26[℃]

が、センサの感知した温度として求められます。

###3-2-1.ライブラリインストール
これもcircuitpythonライブラリを利用します。
terminalから次のコマンドでインストールできます。

```sh
$ pip3 install adafruit-circuitpython-ads1x15
```

###3-2-2.センサ接続回路
センサとの接続は、センサの仕様により回路を考えなくてはなりません。
一例として24V動作のセンサ3種類を接続した場合の回路図です。
回路図の書き方は間違ってるかもしれませんので、間違っていたら優しく指摘して下さい。

<img width="800" alt="sch.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/0b3c2de6-e2c9-6ee9-0fef-385ac20d5dd8.png">

ポイントは以下の通りです。
①ADS1115は3.3V駆動しているため、入力は3.3Vまでしか正しく変換できません。信号は3.3V以下の電圧に変換してから入力します。
②センサが24V系のため、外部の24V電源をセンサに入力しています。GNDは共通です。
③Flow/Tempとあるセンサは、水の流量/温度センサです。24V、GNDのほかに信号用の2本を接続しています。信号は4-20mAのアナログ信号です。150Ωのシャント抵抗で0.6-3Vの電圧信号に変換してから入力しています。
④AirPressとあるのは、エア圧センサです。24V、GND、信号の3線駆動です。信号は0-5Vですので、3.9k、2kの抵抗で分圧し0-3.3Vに変換してから入力します。
⑤OilPressは油圧センサです。24V、GND/信号共通ラインの2線駆動です。4-20mAの電流信号ですので、GND側に150Ωのシャント抵抗をいれて0.6-3Vの電圧信号に変更しています。

###3-2-3.アドレス設定
先にも述べた通り、ADS1115は四つのアドレスを切り替えることで、一つのI2C Busの上に4個まで同時に動作させることが可能です。
アドレスの切り替えは、ADS1115のADDRピンをVDD/GND/SCL/SDAのいずれかに接続することで行います。それぞれアドレスは0x48/49/4A/4Bとなります。

###3-2-4.テストプログラム

```sh
import time
import board
import busio
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn

#i2c busのインスタンス作成
i2c = busio.I2C(board.SCL, board.SDA)

#ads1115のインスタンス作成、アドレス0x48を指定
ADS0 = ADS.ADS1115(i2c,address = 0x48)

#アナログ入力チャンネルのインスタンス作成、ADS0のP0ピン。
chan1 = AnalogIn(ADS0, ADS.P0)

#表示項目
print("{:>5}\t{:>5}".format('raw', 'v'))

while True:
    #5秒おきに、チャンネル番号、電圧を表示
    print("{:>5}\t{:>5.3f}".format(chan1.value, chan1.voltage))
    time.sleep(5)
```


#4.まとめ
上のテストプログラム２個を組み合わせると、5秒おきに、気温、湿度、気圧、アナログセンサの値を取ることができます。
次回は、これをmariaDBに記録し、Grafanaで可視化してみます。