コンテンツにスキップ
ショップ

低電力にポスト投函検出してLINE通知

ESP32 MCUリーフと4-Sensorsリーフの加速度センサを利用して、ポストの開け閉めを検出します。
バッテリーを長持ちさせるためにESP32は主にDeep Sleep状態で、ポストが開いたときに加速度センサから割り込み信号を生成します。 ESP32が立ち上がってからGoogle Apps Scriptにデータを送信して、そこからLINEに通知を送信します。

実際にこのシステムは東京大学の桜井研究室で利用されています。
その時の開発のポイントや、どのように役立っているのかを動画にまとめました。

{{< youtube TRaQ1SStghw>}}

LINE通知にはLINE Notifyを利用します。

  1. LINE Notifyのトップページから自分のLINE IDを使ってログインしましょう。


  2. メールアドレスとパスワードを入力します。


  3. ログイン後にトップ画面からマイページを開きます。


  4. トークンの新規作成ボタンをクリック。


  5. トークンの名前を入力し、通知を送信するグループを選択する。


  6. トークンが発行されたら、しっかりとコピーして下さい。
    この画面を閉じたらこのトークンの記号列は二度と表示されなくなります。


  7. トークンの生成が完了しました。設定したLINEにもメッセージが届いているはずです。


Google Apps Scriptの設定はGoogle Sheetsを使ったIoTサービスの内容を参照します。
コードはGithubgoogle_scripts_code.jsにアップされています。

  1. Google Sheetsの準備1-3の手順に沿ってスプレッドシートの用意をします。

  2. Google Sheetsの準備4の部分で以下のコードを貼り付けます。
    その際,以下の箇所を適宜修正してください。

    • 3行目: LINE通知サービスの設定6の画面で発行されたトークンの記号列に置き換える
      var token = "line_notify_token"
    • 16-17行目: GoogleスプレッドシートのID
      let id = 'google_sheets_id';
      let sheetName = 'sheet_name';
    • 44行目: LINEに送るテキストメッセージ
      例のように+でテキストと変数を連結できます。
      var lineMessage = "ポストに投函ました\n現在のバッテリーの電圧:" + e.parameter.battery + "[V]";
    // LINEへの送信処理
    function sendToLine(text){
    var token = "line_notify_token";
    var options =
    {
    "method" : "post",
    "payload" : "message=" + text,
    "headers" : {"Authorization" : "Bearer "+ token}
    };
    UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
    }
    function doGet(e) {
    let id = 'google_sheets_id';
    let sheetName = 'sheet_name';
    var result;
    // e.parameter has received GET parameters, i.e. temperature, humidity, illumination
    if (e.parameter == undefined) {
    result = 'Parameter undefined';
    } else {
    var sheet = SpreadsheetApp.openById(id).getSheetByName(sheetName);
    var newRow = sheet.getLastRow() + 1; // get row number to be inserted
    var rowData = [];
    // get current time
    rowData[0] = new Date();
    rowData[1] = e.parameter.UniqueID;
    rowData[2] = e.parameter.temperature;
    rowData[3] = e.parameter.humidity;
    rowData[4] = e.parameter.illumination;
    rowData[5] = e.parameter.battery;
    // 1 x rowData.length cells from (newRow, 1) cell are specified
    var newRange = sheet.getRange(newRow, 1, 1, rowData.length);
    // insert data to the target cells
    newRange.setValues([rowData]);
    result = 'Ok';
    }
    var lineMessage = "ポストに投函されました\n現在のバッテリーの電圧:" + e.parameter.battery + "[V]";
    sendToLine(lineMessage);
    return ContentService.createTextOutput(result);
    }
  3. Google Sheetsの準備6-12の手順に沿ってデプロイします。

Google Sheetsを使ったIoTサービスの以下の項目を参照してください。

ESP32 MCUリーフ4-sensorリーフを重ねます。

ESP32にGithubに上がっている以下のファイルをESP32 MCUリーフに書き込みます。

  • ESP32_Post_Notify.ino
  • MyLIS3DH.cpp
  • MyLIS3DH.h

システム全体の制御フローは以下の図ように設計します。

ESP32_Post_Notify.inoにWi-FiのSSIDやパスワードなどの設定項目があります。 重要な項目を箇条書きにしたので、適当に設定してください。

  • Wi-Fiを使ってネットに接続する場合はUSE_WiFiを定義します。

    #define USE_WiFi
  • 接続先のWi-FiがWPA2 Personal(自宅のルーターなどで利用される認証方式。通常これ)を利用しているときは以下の変数にSSIDとパスワードを格納します。

    const char* SSID = "wifi-ssid"; // WiFi SSID
    const char* PASSWORD = "wifi-pass"; // WiFi Password
  • 特に、接続先のWi-Fiが大学や企業などにあり、EduroamなどのWPA2 Enterpriseを使用しているときのみ、以下を定義します。

    #define USE_WiFi_ENTERPRISE

    Wi-Fi Enterprise用のIDやパスワードは以下に入力してください。

    /////////////////////////////////////////////////////////////////////////////////////////////////////
    // parameters for connecting eduroam enterprise
    /////////////////////////////////////////////////////////////////////////////////////////////////////
    #define EAP_IDENTITY "eap_id" //if connecting from another corporation, use identity@organisation.domain in Eduroam
    #define EAP_PASSWORD "eap_pass" //your Eduroam password
    const char* SSID_ENT = "eduroam"; // Eduroam SSID
    /////////////////////////////////////////////////////////////////////////////////////////////////////

ESP32_Post_Notify.inoで接続先Googleスクリプトの設定を行っています。 Googleクラウドサービスの設定3で設定したGoogle Apps Scriptの固有IDを以下の変数に格納します。

const char* KEY = "google_scripts_key";

Wi-Fiに接続してデータを送った後は,EP32 MCUがDeep Sleepモードに入ることで待機電力を極力減らします。
Deep Sleepモードに入る前にESP32 MCU内のWi-Fiモジュールの電源を切ることを忘れないでください。

WiFi.disconnect(true) // Wi-Fiをオフにするために,trueを明示してください

加速度センサ用の設定パラメータはレポジトリに上がっているMyLIS3DH.cppで修正できます。
実際に身の回りのポストに実装する場合にはパラメータを環境に合わせて設定する必要があります。
今回は例として、以下のように蓋が開閉するポストを考えます。

加速度センサが生成できる割り込み信号は独立に2つ(INT1, INT2)あり、そのうちのINT1を使います。
データシートによると割り込み信号の指定にはCTRL_REG3というレジスタに書き込みます。
CTRL_REG3の説明をデータシートから読んでみます。

データシートから、I1_AOI1ビットを1に設定するとINT1の割り込みが有効になります。
よって、以下のようにプログラムします。

writeRegister8(LIS3DH_REG_CTRL3, 0x40);

割り込み信号を生成するための条件(どのような振動の場合に割り込み信号を生成するのか、等)を設定できるのですが、今回主に設定するパラメータは以下の4つです。

ポストの蓋の裏面にリーフが張り付けると、蓋が傾いた時に、加速度センサからみた重力加速度の向きが変化します。
この加速度の向きを検出することが出来れば、郵便物が投函されたかどうかセンシング出来ます。
いま、実験により、郵便物が投函されるとき蓋が少なくとも10度は傾くことが分かったとします。
そのとき、加速度センサのz軸方向の加速度(図中の緑色の矢印)が0gから0.17gまで増加することが分かるので、この0.17gを閾値に設定してあげれば良さそうです。

一方、加速度センサのLIS3DHはデフォルトでフルスケールが±2gの検出を行います。
(これはESP32_PostNotify.inoで設定されています。)

lis.setRange(LIS3DH_RANGE_2_G); // 2, 4, 8 or 16 G!

データシートによると、使用している加速度センサは軸の正(負)方向に対してそれぞれ128段階の分解能(フルスケールで8-bitの分解能)を持っています。
0.17gが2gに対して、どのレベルなのかを128段階のレベルで表すと、

128 / 2g * 0.17g = 10.88

なので、閾値レベル11(16進数では0x0B)を設定します。
この閾値の情報はINT1THSというレジスタに書き込みます。
一応、レジスタの情報をデータシートから確認してみると、書き込める数値は0~127までだということが分かります。

プログラムでは以下のように記述します。

writeRegister8(LIS3DH_REG_INT1THS, 0x0B);

閾値の項目で考えた通り,今回は加速度の3軸のうち1つの軸のみを使って郵便物の投函を検出します。

軸の選択には、以下の2つのレジスタに書き込みます。

  • CTRL_REG1
    センシングする3軸方向の加速度の有効・無効の設定を行います。
    使用する軸以外は無効にすることで電力を抑えられ、バッテリーが長持ちします。
    また、低電力モード(Low Power Mode)とサンプル周波数の設定もこのレジスタで行います。

  • INT1_CFG
    割り込み用に設定する軸方向の決定を行います。
    また、軸の選択以外に割り込み信号の発生方法も設定出来ます。

CTRL_REG1に関して、今回の用途では、以下のように設定しようと思います。

  • Z軸方向のみで検出を行う
  • 理由は後述するが、10Hzで加速度をサンプリングを行う
  • 低電力モードも使う

よってデータシートから、レジスタはODR3からXenまで順に00101100と設定すればいいので以下のようにプログラムします。

writeRegister8(LIS3DH_REG_CTRL1, 0x2C);

INT1_CFGに関して、上のデータシートに、AOI6Dというよく分からない項目があります。
データシートのTable 48.を見てみると、どうやらAOI6Dを使って割り込み信号を生成する方法を設定できるようです。
ORとANDの条件は各軸それぞれに対して割り込みを発生させるときの条件として考えれば良さそうです。
一方、6 direction movement6 direction position recognitionはここからだとよく分かりません。
それらの説明はアプリケーションノートに以下のように記述されていました。

少し難しいですが簡単にまとめると、こんな感じになります。

  • 6D movement: 指定した閾値を超えたときと、そこから戻るときに一瞬だけ割り込み信号を生成
  • 6D position: 指定した閾値以上になっている間、常に割り込み信号を生成

また、このアプリケーションノートのFigure 12から、X・Y・Z軸の中でも、上方向と下方向で別々に割り込み処理を設定できるということも分かりました。
これらの設定がINT1_CFGのZHIE/ZUPE``ZLIE/ZDOWNE・・・XLIE/XDOWNEの箇所で設定できるようです。
以上のことから、割り込み信号の生成条件としては、

  • Z方向の割り込み信号のみを有効
  • Z方向の指定した閾値を超えたときに一瞬だけ割り込み信号を生成する

以下のようにプログラムすれば良いと分かりました。

writeRegister8(LIS3DH_REG_INT1CFG, 0x70);

サンプリング周波数 (Sampling Rate) & 時間幅 (Duration)

Section titled “サンプリング周波数 (Sampling Rate) & 時間幅 (Duration)”

サンプリング周波数と時間幅は関連しているので、一緒に説明します。はじめにそれぞれを簡単に説明します。

  • サンプリング周波数:センサが加速度を取得する時間間隔を設定できます。周波数が上がるほど,時間分解能は上がりますが,その分センサの消費電力も増加してしまいます。
  • 時間幅:割り込み信号が発生するまでに閾値を何秒間越えなければいけないか、という条件を設定できます。
    ポストの蓋に何かがぶつかってしまったりなど、たまたま環境ノイズを拾ってしまったりしたときに、誤って検知してしまうことを防げます。

郵便物が投函されたときに加速度センサの応答が図のように0.3秒以上閾値を超えるとし、それ以下の場合は環境ノイズとして処理します。
この場合、サンプリング周波数は10Hzで設定すれば問題なさそうです。
検出軸の項で説明した通り、設定レジスタはCTRL_REG1です。
ODR0-ODR3でサンプリング周波数を決定できます。
再掲ですが、以下のようにプログラムします。

writeRegister8(LIS3DH_REG_CTRL1, 0x2C);

時間幅の設定レジスタはINT1_DURATIONです。実際にセンサは連続時間を測っているわけではなく、サンプリング回数で時間間隔を計算しています。

0.3秒以上閾値を超えるようであれば、割り込み信号を生成します。
今回はサンプル周波数を10Hzで設定しており、設定値は以下のように計算します。

0.3 / 0.1 = 3

これは以下のようにプログラムします。

writeRegister8(LIS3DH_REG_INT1DUR, 0x03);

ESP32を傾けたときにスリープから立ち上がり、Wi-Fiに接続してからLINE Notifyに通知を送信します。
LINE Notifyで受け取った画面は以下のようになります。