Sense HATを使ってドアの開閉検知を行う

Sense HATというRaspberry Pi用のHAT(拡張基板)があります。とても便利なHATで、以下のような機能があります。

  • 8×8、16ビットLEDディスプレイ
  • 慣性測定ユニット(加速度、ジャイロ、磁力)
  • 気圧センサ
  • 温度センサ
  • 湿度センサ
  • 4 + 1ジョイスティック(上下左右 + 押し込み)

今回はこのSense HATを使い、ドアの開閉検知を行うプログラムを作ってみます。

Sense HATの注意点

Sense HATはとても高機能なHATで、高精度な加速度センサーが組み込まれています。このセンサーは、ただ置いておくだけでも常に値が揺れてしまいます。そのため、今回は小数点以下2桁までを対象としています。

acceleration = sense.get_accelerometer_raw()
x = acceleration['x']
# 他に acceleration['y']、acceleration['z']があります
x = round(x, 2)

ただし、2桁にしても値が 0.01と0.02を揺れてしまうので、ある程度の範囲(±0.01)の範囲は誤差として開閉検出しないようにしています。

# 開閉していないかチェックする関数
# 開閉を開始している場合(moving = True)はさらに誤差が大きくなるので ±0.08 としています
def acceleration_range(old, num, moving):
  if moving:
    r = 0.08
  else:
    r = 0.01
  if num == old:
    return True
  if num >= old + r:
    return True
  if num <= old - r:
    return True
  return False

この辺りは実際に動かしながら試してみるのが良いでしょう。

窓(引き戸)の場合

まず試したのが窓です。左右方向に動くだけの動きを検出するパターンになります。単純にデータをグラフ化すると次のようになります。これは最初閉まっていて、窓を開けた後、戻した場合です。

このグラフを見て分かる通り、閉めるときに最後強い衝撃が加わっています。開けるときにはあまり大きな数字の動きにはなっていません。

では実際のコードです。まずSense HATを用意します。これはRaspberry OSに標準で組み込まれています。

#!/usr/bin/env python
from sense_hat import SenseHat
import time
sense = SenseHat()

次に変数を準備します。old_x は1つ前のX座標の値を保存しています。 moving は開閉が開始されたら True にします。 is_open は True だったら開ける動作、 False だったら閉める動作を意味しています。

try:
  old_x = 0
  moving = False
  is_open = False
  while True:
    # この中に処理を書いていきます
    # 古い値を保存
    old_x = x
except KeyboardInterrupt:
  # Ctrl + Cで終了した場合
  sense.clear()

Sense HATからのデータ取得は先ほども書きましたが sense.get_accelerometer_raw() で行います。これで x/y/z軸それぞれの値が返ってきます。今回はX軸のみ扱います。

acceleration = sense.get_accelerometer_raw()
x = acceleration['x']
x = round(x, 2) # 小数点以下2桁まで対象

そして先ほど紹介した値のブレを吸収するための acceleration_range 関数が False 、つまり窓の開閉動作を検知したら moving を True にします。また、ここからは実行時間を0.04秒遅らせています。これは実際に試してみたのですが、あまり頻繁に加速度を検知すると、開いている最中でも動作が止まったと判断されてしまうためです。この辺りも皆さんの環境ごとに試しながら確認してください。

if acceleration_range(old_x, x, moving) == False:
  moving = True
  time.sleep(0.4)
else:
  # この後説明

開閉しきった際には上記のelseに処理が移ります。 moving がTrueだったならば、開閉フラグ is_open の状態によって窓を開いたか閉じたかを出力しています。

if moving:
  moving = False
  is_open = not is_open
  if is_open:
    print("Open")
  else:
    print("Close")

今回は標準出力しているだけですが、クラウドの保存したり、メールやSlack通知すると言った動作につなげるのは簡単でしょう。

ドアの場合

続いてドアの場合です。こちらもデータをグラフ化してみました。

これを見て分かるのは、飛び抜けて高い(または低い)値(+0.04以上または-0.01以下)を検知した時が閉める、または開ける動作と言えそうです。先ほどのコードを参考に、同じように実装したのが次のコードになります。

from sense_hat import SenseHat
sense = SenseHat()
def acceleration_range(old, num, moving):
  if moving:
    r = 0.08
  else:
    r = 0.01
  if num == old:
    return True
  if num >= old + r:
    return True
  if num <= old - r:
    return True
  return False
try:
  old_x = 0
  moving = False
  is_open = False
  while True:
    acceleration = sense.get_accelerometer_raw()
    x = acceleration['x']
    x = round(x, 2)
    if x >= 0.04:
      # 開ける動作
      is_open = True
      moving = True
    elif x <= -0.01:
      # 閉める動作
      is_open = False
      moving = True
    elif acceleration_range(old_x, x, moving) == False: # 停止状態の判定
      # 開閉中であれば、メッセージを出す
      if moving:
        moving = False
        if is_open:
          print("Open")
        else:
          print("Close")
        is_open = not is_open
    old_x = x
except KeyboardInterrupt:
    sense.clear()

これでドアを開けた時、閉めた時を検知できるようになります。

まとめ

Sense HATの値が常に動き続けるので、どこを閾値にするかは試してみないと分かりません。恐らくドアの種類や開閉方向などによって異なるはずです。一度データをグラフ化してみて、閾値を判定するといいでしょう。

入退室の検知や会議室の利用状態、自宅の防犯など開閉検知が使える場面は多そうです。ぜひSense HATを活用してください。

Raspberry Pi Sense Hat

]]>

上部へスクロール