重量センサーデータをRaspberryPi3で取得して、GCP Cloud IoT Core/BigQueryに送る方法

#はじめに
重量センサーを使って得たデータを、RaspberryPi3をGatewayとしてGoogle Cloud IoT Core経由でBigQueryに保存してみました。
RaspberryPi3での重量センサーの使い方を把握したかったことと、GCP連携してデータ格納まですることで、一連のIoTシナリオを動作確認したかったことがモチベーションです。

あと、この記事を見て触発をされました。
[ラズパイでコーヒーポットIoT（朝日ネット in 歌舞伎座タワー）](https://shirouzu.jp/tech/coffeepot-iot.md)


こんなユーザが対象です。

* 重量センサーをラズパイと連携させて実際に使ってみたい
* IoTシナリオを実際のシミュレータでなく実際のデバイスを利用して動かしてみたい
* クラウドはGCPを使いたい

##環境

* RaspberryPi3 (Python2.7)
* 重量センサー(ロードセル、ADコンバータHX711)
* GCP Cloud IoT Core(pubsub)
* GCP Dataflow/BigQuery


##簡易構成図と簡単な構築の流れは、以下です。
1. ロードセルを準備します
2. ラズパイとロードセルを接続します。
3. 簡単に動作確認（重量センサーのデータ取得できるか）
4. ロードセルを組み立て実際に、荷重計を作ります。
5. データ転送の準備をします。(CloudIoTCore/pubsub/Dataflow/BigQuery)
6. 実際に動かしてみます。


![GCP構成図](https://storage.googleapis.com/permanent_koizumi/20181228_GCP_kousei.png "GCP構成図")

最終的な接続状況は以下です。
![全体接続状況](https://storage.googleapis.com/permanent_koizumi/20181228_all.jpg "全体接続状況")

## 1. ロードセルとADコンバータを準備します

ロードセルとADコンバータを準備します。実際に買ったものは以下。
取り扱い説明書に従って組み立てます。（はんだ付け必須）

* [ＨＸ７１１使用　ロードセル用ＡＤコンバータ　モジュール基板](http://akizukidenshi.com/catalog/g/gK-12370/)
* [ロードセル　シングルポイント（ビーム型）　ＳＣ１３３　２０ｋｇ](http://akizukidenshi.com/catalog/g/gP-12034/)

一点、HX711の[取り扱い説明書](http://akizukidenshi.com/download/ds/akizuki/ae-hx711_rev1_20180129.pdf)で、
「Ｊ３、Ｊ４は、Ｂチャンネル入力を使用しない場合にＧＮＤに接続する半田ジャンパーです。通常はＢチャンネル入力を使用しませんので、はんだジャンパーしてください。」と書いているのですが、はんだ初心者（中学の時以来）の身としては、半田ジャンパーの意味が分からず、苦悩しました。
結果、J3とJ4にそれぞれ、はんだ付けすることで、正常に動いており、問題なさそうです。


## 2.ラズパイとロードセルを接続します
先人の方の力を借りて、接続しました。結果、以下のような構成になります。
HX711の基盤の色が赤になっていますが、本当は緑です。アイコンが見つからなかったのでご容赦ください。


![接続図](https://storage.googleapis.com/permanent_koizumi/20181228_LoadCell_board.png "接続図")


* VCC to Raspberry Pi Pin 2 (5V)
* GND to Raspberry Pi Pin 6 (GND)
* DT to Raspberry Pi Pin 29 (GPIO 5)
* SCK to Raspberry Pi Pin 31 (GPIO 6)

ブレッドボードの図は、[fritzing](http://fritzing.org/home/)という、ツールを使って書きました。
使ったことはなかったのですが、感覚的に書けるくらい素敵なツールでした。


## 3. 簡単に動作確認（重量センサーのデータ取得できるか）

接続ができたら、簡単に動作確認します。
今回は、[RaspberryPiチュートリアルサイト](https://tutorials-raspberrypi.com/digital-raspberry-pi-scale-weight-sensor-hx711/)を参考にして、
[このgithubをコピーして](https://github.com/tatobari/hx711py)、HX711の動作を確認します。

まず、example.pyを編集用にコピーして

```Python:console
git clone https://github.com/tatobari/hx711py
cd hx711py
cp example.py example20181228.py
nano example20181228.py
```

下記のようにコメントアウトをして、かつ、valの値を、hx.get_weight(5)に変更します。

```Python:example20181228.py
#hx.set_reference_unit(1)

# val = hx.read_long()
val = hx.get_weight(5)
```

実行(python example20181228.py)し、何かしらデータが取れて、ロードセルを曲げると値が変動することを確認します。
ただし、この状態だと変動値に対する荷重（グラム数）を調整できていないので、４の工程で調整します。

値が正常に取れない、もしくは値が取れても、曲げても値が変動しないときなどは、ADコンバータ(HX711)の接触が悪い可能性もあるので、ADコンバータに接続しているコードを抜き差しすると解決する可能性があります。



## 4.ロードセルを組み立て実際に、荷重計を作ります。
動作が確認出来たら、本格的にロードセルを組み立ててます。
以下のように、全ねじ等を利用して取り付けます。

![ロードセル取り付け](https://storage.googleapis.com/permanent_koizumi/20181228%E2%80%97loadcell.jpg "ロードセル取り付け")

ちなみに、木板は近くのホームセンターの端材売り場で１枚３０円で購入しました。
全ねじ、ナット(M4*2/M5*2)、ワッシャーなども、含めても１００円くらいだったと思います。木板に計４か所穴をあけて１つの穴につき80円だったので、加工費240円でした。

出来上がったら、３の工程で未実施だった、変動値の調整を行います。

①重みを乗せずに、５０個ほど値のサンプルを取って平均値を取得します。
②重量物を乗せて、変動値をそのグラム数で割ります
③プログラムを修正します。

具体的に、私の場合は以下のような形になりました。
①重みのない状態：37856（木の重み等はあります）
②116.5gのものを乗せると、50038程度になりました。つまり差分は、12182となり、116.5で割ると、約105となります。
③exapmle20181228.pyのなかの以下のコードを修正します。

```Python:example20181228.py
hx.set_reference_unit(105)
```

さらに、この状態で何も乗せていない状態だと、361くらいの値が残ってしまっていたため、valの値を以下のように修正・調整しました。

```Python:example20181228.py
val = max(0,int(hx.get_weight(5))-361)
```

結果的にほぼ、正常な値が取得できました。

ちなみに、重量を計測する際に利用したものは、手元にあったウコンドリンクでｗ、計量器で測って116.5gであることを調べました。
![重量測定](https://storage.googleapis.com/permanent_koizumi/20181228_weight.jpg "重量測定")


## 5.データ転送の準備をします。(CloudIoTCore/pubsub/Dataflow/BigQuery)

センサー側のデータ取得ができるようになったので、
次は、データを受けるクラウド側GCP Cloud IoT Coreの設定を進めます。
参考のサイトは、以下です。
[https://qiita.com/h-sakano/items/8a4960595e3359ad9ea4](https://qiita.com/h-sakano/items/8a4960595e3359ad9ea4)


| トピック名             | 端末ID   |
|:-----------------------|:---------|
| iot-core-weight-sensor | sensor01 |

証明書の発行や、Cloud IoT Coreでの端末IDを作成します。詳細は、上記のサイトを参考ください。

![IoT Core 設定](https://storage.googleapis.com/permanent_koizumi/20181228_IoTCore.png "IoT Core 設定")

また、今回は、データをBQ(BigQuery)へ保存するため、事前にtableを作っておきます。


| フィールド名 | タイプ   |  モード   |
|:-------------|:---------|:----------|
| timestamp    | TIMESTAMP|  NULLABLE |
| weight       | INTEGER  |  NULLABLE |


pubsubが受け取ったデータをBQにストリーム送信するためのDataflowも作成しておきます。
テンプレートで作成すると簡単です。

| 項目                     | 内容                     |
|:-------------------------|:-------------------------|
| テンプレート             | Cloud Pub/Sub to BigQuery|
| リージョン エンドポイント| asia-east1               |
| pubsub topic             | 上記で指定したもの       |
| BQ table                 | 上記で指定したもの       |
| 一時的なロケーション     | 適当なGCSフォルダ        |




## 6. 実際に動かしてみます。

以下のgithubサンプル(cloudiot_mqtt_example.py)を利用しつつ、3項のセンサーデータ取得コードを合わせて、動作させます。（編集用に作ったものは、iot-sample.pyです。）

[https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/iot/api-client/mqtt_example](https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/iot/api-client/mqtt_example)

いくつか修正しましたが、一番大きなポイントはmain関数内での以下の修正です。

```Python:iot-sample.py
now = datetime.datetime.now()

timestamp = now.strftime("%Y-%m-%d %H:%M:%S")
val = max(0, int(hx.get_weight(5))-361)
payload = '{{\"timestamp\": \"{}\" ,\"weight\": {} }}'.format(timestamp,val)

print('{}'.format(payload))
```


```Python:console
$python iot-sample.py --registry_id=weight-sensor01 --project_id=sandbox-koizumi --device_id=sensor01 --algorithm=RS256 --private_key_file=./rsa_private.pem --cloud_region=asia-east1

/home/pi/koizumi/weight_app/hx711py/hx711.py:13: RuntimeWarning: This channel is already in use, continuing anyway.
  Use GPIO.setwarnings(False) to disable warnings.
  GPIO.setup(self.PD_SCK, GPIO.OUT)
Creating JWT using RS256 from private key file ./rsa_private.pem
Subscribing to /devices/sensor01/commands/#
{"timestamp": "2018-12-28 15:58:44" ,"weight": 116 }
{"timestamp": "2018-12-28 15:58:46" ,"weight": 116 }
{"timestamp": "2018-12-28 15:58:48" ,"weight": 116 }
{"timestamp": "2018-12-28 15:58:50" ,"weight": 116 }
{"timestamp": "2018-12-28 15:58:51" ,"weight": 116 }
{"timestamp": "2018-12-28 15:58:53" ,"weight": 116 }
```

BigQueryにも、正常に伝送できていることを確認できました。

![BQ結果](https://storage.googleapis.com/permanent_koizumi/20181228_BIgQueryResult.png "BQ結果")


## おわりに
かなり高い精度で、重量を計測できました。重量センサーを皮切りに、他のセンサーも利用できるように、いくつか触ってみたいと思いました。
ソフトより、どちらかというと、ハードの作業のほうが時間を要しましたが、意外に楽しめたので良しとします。