Last updated on

クリスマスの定番(?) Raspberry Pi と超音波センサーでクリスマスツリーを光らせて SORACOM Harvest Data でデータ収集


[point_maker type=“heading_icon” base_color=“apple_green” title_icon=“info-circle-solid” title_color_background=“true” title_color_border=“false” content_type=“text” content_color_background=“true” content_color_border=“false” block_editor=“true”]

こちらは、 “ゆるWeb勉強会@札幌 Advent Calendar 2020” の 25日目の記事です。

[/point_maker]

メリークリスマス!
アドベントカレンダーも最終日のクリスマス、そしてクリスマスと言えばラズパイですよね!

ということで、 ゆるWeb勉強会@札幌 Advent Calendar 2020 の最後は、超音波センサーを使ってクリスマスツリーを光らせつつ、距離の情報を SORACOM Harvest Data で送信する仕組みを Raspberry Pi で作ってみたいと思います。

動画

まずはどのような動きになるか、動画をご覧ください。

https://youtu.be/cvtfghNCynA

では、どうやって作ったのか見ていきましょう。

揃えるもの

Raspberry Pi

  • Raspberry Pi 3 Model B+

超音波センサー

  • HC-SR04

上記2つは、今回は SORACOM さんのストアで購入しました。

https://soracom.jp/products/kit/sensor_kit/

このキットの体験ハンズオンをやった記事はこちら。

https://blog.tacck.net/archives/1143

ツリー関係

  • 100均などで適宜購入

各自、好きなように作りましょう。

手順

Raspberry Pi やセンサーの準備など

センサーの接続や動作確認は、先ほどあげたハンズオン体験記事を参照してください。

https://blog.tacck.net/archives/1143

ツリーの作成手順、 Raspberry Pi のセットアップ、 Node-RED のセットアップについては、アナザースタイルの記事を参照してください。

https://www.northdetail.co.jp/blog/1505

Node-RED のフロー実装

今回は Node-RED で実装してみました。

最終的なフローはこのような形になります。

Node-RED でフローを実装。

センサーからの値(cmで取得できる)が 50cm 以下の場合に点灯、そうでない場合に消灯、というように実装しています。

送信できたデータは、 SORACOM のコンソール上にこのような形で確認できます。
(距離なので、値が小さいところで手をかざしている。)

SORACOM のコンソールで確認。

超音波センサー用のノードの実装

超音波センサーは、原理として「発射した超音波が返ってくるまでの時間」を基に距離を計算することになります。

つまり、かなり短い時間 (ミリ秒よりも小さい単位) で扱えないと良い精度が出せません。

Node-RED は Node.js (JavaScript) で動作しているので、基本はミリ秒での制御となっているように見えます。

そのため、標準のノードの組み合わせではうまく作ることができませんでした。

ということで専用のノードが必要になるので探してみたところ、下記のようなノードが公開されていました。

https://flows.nodered.org/node/node-red-node-pisrf

https://github.com/node-red/node-red-nodes/tree/master/hardware/PiSrf

このノードで距離を取得できたのですが、ある程度離れると情報が返ってこなくなるので「周期的に値を取得する」ということが実現できませんでした。

これができないと、「距離が離れたらライトを消灯する」ということが実現できません。

そこで、上記のノードのコードの作り方と 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 のファイルを実行し、標準出力から得た結果を使ってノードの出力としています。

こういった感じで、簡単なノードであればすぐに実装できました。

ローカルでの詳しいノードの作成・追加方法は、こちらの公式ドキュメントを参考にしてください。

https://nodered.jp/docs/creating-nodes/

Harvest への送信方法は、数値をそのままURLへ送るだけでできました。
(SORACOM の SIM を差したドングルが必要です。)

動作させる

ということで、改めて動画を確認してみてください。

https://youtu.be/cvtfghNCynA

うまくできましたね!

まとめ

Node-RED でのセンサーの扱いで少し苦労しましたが、このような形で対応できることがわかりました。

センサーも含め、自分で使う時に欲しいノードがあればかなり手軽に自作ノードとして対応できそうです。

色々な道具を組み合わせることで、かなり手軽に欲しい物が作れますね。

みなさんも、ぜひ色んなものを作ってみてください!