M5StickCの姿勢を検知して施解錠履歴を管理する


概要

  • ドアの施開錠履歴をできるだけ安価な仕組みで取得したい。
  • 既存のものではサムターンに被せるタイプのスマートロックがあるが、高価である。
  • 例えば高齢者の安否確認にスマートロックは必要ない。施開錠履歴のみあれば十分ではないか。

用意するもの

  • M5StickC
  • Arduino IDEが動くPC (Mac/Windows)

環境構築

(1)Arduino IDEをインストール
https://www.arduino.cc/en/main/software
(2)M5StickC関連のライブラリをインストール
 スケッチ→ライブラリをインクルード→ライブラリを管理
 M5StickCを検索

プログラミング

  • M5StickCの6軸センサーを使い、どの軸が上を向いているかを検出する
  • ディスプレイにはOPEN/CLOSEと表示する。
  • Wifi経由でAmbientに送信し可視化する(1:OPEN 0:CLOSE)
lockstate.ino
#include <M5StickC.h>
#include "Ambient.h"

#define POSE_P_X 0
#define POSE_M_X 1
#define POSE_P_Y 2
#define POSE_M_Y 3
#define POSE_P_Z 4
#define POSE_M_Z 5
uint8_t pose = POSE_P_X;
uint8_t prev_pose = POSE_P_X;

WiFiClient client;
Ambient ambient;

const char* ssid = "xxxxxxxxxxxxxx";
const char* password = "xxxxxxxxxxxx";

unsigned int channelId = "xxxxx"; // AmbientのチャネルID
const char* writeKey = "xxxxxxxxxxxxxxxx"; // ライトキー

// 加速度
float accX_g = 0;
float accY_g = 0;
float accZ_g = 0;
float accX_mpss = 0;
float accY_mpss = 0;
float accZ_mpss = 0;

// 角速度
float gyroX_dps = 0;
float gyroY_dps = 0;
float gyroZ_dps = 0;

boolean near_p_g(float value){
  if(8.0 < value && value < 12.0){
    return true;
  }else{
    return false;
  }
}

boolean near_m_g(float value){
  if(-12.0 < value && value < -8.0){
    return true;
  }else{
    return false;
  }
}

boolean near_zero(float value){
  if(-2.0 < value && value < 2.0){
    return true;
  }else{
    return false;
  }
}

void setup() {
  // Initialize the M5StickC object
  M5.begin();
  M5.MPU6886.Init();
  M5.Lcd.setRotation(1);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextSize(1);

      WiFi.begin(ssid, password);  //  Wi-Fi APに接続
    while (WiFi.status() != WL_CONNECTED) {  //  Wi-Fi AP接続待ち
        delay(500);
        Serial.print(".");
    }
    Serial.print("WiFi connected\r\nIP address: ");
    Serial.println(WiFi.localIP());

    ambient.begin(channelId, writeKey, &client); // チャネルIDとライトキーを指定してAmbientの初期化
}

void loop() {

  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextSize(3);

  // 加速度取得
  M5.MPU6886.getAccelData(&accX_g,&accY_g,&accZ_g);
  accX_mpss = accX_g * 9.8;
  accY_mpss = accY_g * 9.8;
  accZ_mpss = accZ_g * 9.8;
  // 角速度取得
  M5.MPU6886.getGyroData(&gyroX_dps,&gyroY_dps,&gyroZ_dps);

  if(near_zero(accX_mpss) && near_p_g(accY_mpss) && near_zero(accZ_mpss)){
    pose = POSE_P_Y;
  }else if(near_p_g(accX_mpss) && near_zero(accY_mpss) && near_zero(accZ_mpss)){
    pose = POSE_P_X;
  }else if(near_zero(accX_mpss) && near_zero(accY_mpss) && near_p_g(accZ_mpss)){
    pose = POSE_P_Z;
  }else if(near_zero(accX_mpss) && near_m_g(accY_mpss) && near_zero(accZ_mpss)){
    pose = POSE_M_Y;
  }else if(near_m_g(accX_mpss) && near_zero(accY_mpss) && near_zero(accZ_mpss)){
    pose = POSE_M_X;
  }else if(near_zero(accX_mpss) && near_zero(accY_mpss) && near_m_g(accZ_mpss)){
    pose = POSE_M_Z;
  }

  // 姿勢に変化があった場合にのみ描画する
  if(prev_pose != pose){
    M5.Lcd.fillScreen(BLACK);
    switch(pose){
      case POSE_M_X:
        M5.Lcd.setRotation(3);
        M5.Lcd.setCursor(56, 16);
        M5.Lcd.print("CLOSE");
        // 施錠の情報をAmbientに送信する
        ambient.set(1, 0);
        ambient.send();
        delay(500);
        break;
      case POSE_P_Y:
        M5.Lcd.setRotation(3);
        M5.Lcd.setCursor(56, 16);
        M5.Lcd.print("OPEN");
        // 解錠の情報をAmbientに送信する
        ambient.set(1, 1);
        ambient.send();
        delay(500);
        break;
        default:
        ;
        }
    }
  prev_pose = pose;
  delay(100);
}

注意点

  • サムターンの操作性を損なわないような取り付け方を工夫する必要がある。
  • 何らかの電源(モバイルバッテリー等)で給電しておく必要がある。

その他

  • 画面表示の明るさ、表示時間を調整すれば節電できる。
  • アプリを構築しAPIに送信するようにすれば複数箇所の対応、アラートメールを送信する等機能を増やせる。
  • ドアの施解錠以外の用途にも応用できるかもしれない。