クリスマスの定番(?) Raspberry Pi と超音波センサーでクリスマスツリーを光らせて SORACOM Harvest Data でデータ収集
こちらは、 “ゆるWeb勉強会@札幌 Advent Calendar 2020” の 25日目の記事です。
メリークリスマス!
アドベントカレンダーも最終日のクリスマス、そしてクリスマスと言えばラズパイですよね!
ということで、 ゆるWeb勉強会@札幌 Advent Calendar 2020 の最後は、超音波センサーを使ってクリスマスツリーを光らせつつ、距離の情報を SORACOM Harvest Data で送信する仕組みを Raspberry Pi で作ってみたいと思います。
- 2020年 / クリスマスの定番(?) Raspberry Pi と SORACOM LTE-M Button で光るクリスマスツリーを作成 [アナザースタイル]
- 2019年 / クリスマスの定番(?) Raspberry Pi と Philips Hue でクリスマスツリーをライティング (Nintendo Switch Joy-Con version)
- 2019年 / クリスマスの定番(?) Raspberry Pi と Philips Hue でクリスマスツリーをライティング [アナザースタイル]
- 2018年 / クリスマスの定番(?) Raspberry PiとAlexaで光るクリスマスツリーを作る【動画あり】
- 2017年 / クリスマスの定番(?) Raspberry Piで光るクリスマスリースを作る【動画あり】
目次
動画
まずはどのような動きになるか、動画をご覧ください。
では、どうやって作ったのか見ていきましょう。
揃えるもの
Raspberry Pi
- Raspberry Pi 3 Model B+
超音波センサー
- HC-SR04
上記2つは、今回は SORACOM さんのストアで購入しました。
このキットの体験ハンズオンをやった記事はこちら。
ツリー関係
- 100均などで適宜購入
各自、好きなように作りましょう。
手順
Raspberry Pi やセンサーの準備など
センサーの接続や動作確認は、先ほどあげたハンズオン体験記事を参照してください。
ツリーの作成手順、 Raspberry Pi のセットアップ、 Node-RED のセットアップについては、アナザースタイルの記事を参照してください。
Node-RED のフロー実装
今回は Node-RED で実装してみました。
最終的なフローはこのような形になります。
センサーからの値(cmで取得できる)が 50cm 以下の場合に点灯、そうでない場合に消灯、というように実装しています。
送信できたデータは、 SORACOM のコンソール上にこのような形で確認できます。
(距離なので、値が小さいところで手をかざしている。)
超音波センサー用のノードの実装
超音波センサーは、原理として「発射した超音波が返ってくるまでの時間」を基に距離を計算することになります。
つまり、かなり短い時間 (ミリ秒よりも小さい単位) で扱えないと良い精度が出せません。
Node-RED は Node.js (JavaScript) で動作しているので、基本はミリ秒での制御となっているように見えます。
そのため、標準のノードの組み合わせではうまく作ることができませんでした。
ということで専用のノードが必要になるので探してみたところ、下記のようなノードが公開されていました。
このノードで距離を取得できたのですが、ある程度離れると情報が返ってこなくなるので「周期的に値を取得する」ということが実現できませんでした。
これができないと、「距離が離れたらライトを消灯する」ということが実現できません。
そこで、上記のノードのコードの作り方と Node-RED の公式情報を基に、 SORACOM のサンプルコード(Python) を使った自作ノードを作成して対応しました。
センサーの値を Python で取得し、 JavaScript からそのコードを呼び出してノードとして動作させる、という形です。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import RPi.GPIO as GPIO
import sys
GPIO.setmode(GPIO.BOARD)
TRIG = 11 # GPIO17
ECHO = 13 # GPIO27
GPIO.setup(TRIG,GPIO.OUT)
GPIO.setup(ECHO,GPIO.IN)
GPIO.output(TRIG, GPIO.LOW)
GPIO.output(TRIG, GPIO.HIGH)
time.sleep(0.00001)
GPIO.output(TRIG, GPIO.LOW)
signaloff = time.time()
while GPIO.input(ECHO) == GPIO.LOW:
signaloff = time.time()
signalon = signaloff
while time.time() < signaloff + 0.1:
if GPIO.input(ECHO) == GPIO.LOW:
signalon = time.time()
break
GPIO.cleanup()
timepassed = signalon - signaloff
distance = timepassed * 17000
print distance
これでセンサーから距離を取得し、標準出力へ出力するようにします。
module.exports = function (RED) {
const execFile = require('child_process').execFile;
const gpioCommand = __dirname + '/gpio.py';
function Ultrasonic(config) {
RED.nodes.createNode(this, config);
const node = this;
node.on('input', function (msg) {
execFile(gpioCommand, [], (err, stdout, stderr) => {
const strData = stdout.trim();
if (strData.length > 0) {
node.send({ topic: node.topic, payload: parseFloat(strData) });
} else {
node.send({ topic: node.topic, payload: 1000 });
}
})
});
}
RED.nodes.registerType("node-red-ultrasonic", Ultrasonic);
}
Node.js の execFile()
を使って Python のファイルを実行し、標準出力から得た結果を使ってノードの出力としています。
こういった感じで、簡単なノードであればすぐに実装できました。
ローカルでの詳しいノードの作成・追加方法は、こちらの公式ドキュメントを参考にしてください。
Harvest への送信方法は、数値をそのままURLへ送るだけでできました。
(SORACOM の SIM を差したドングルが必要です。)
動作させる
ということで、改めて動画を確認してみてください。
うまくできましたね!
まとめ
Node-RED でのセンサーの扱いで少し苦労しましたが、このような形で対応できることがわかりました。
センサーも含め、自分で使う時に欲しいノードがあればかなり手軽に自作ノードとして対応できそうです。
色々な道具を組み合わせることで、かなり手軽に欲しい物が作れますね。
みなさんも、ぜひ色んなものを作ってみてください!