はじめに
前回ご紹介したアナログ・デバイセズ社の加速度センサーADXL362には、”モーション起動スイッチ”という画期的な機能が搭載されています。

ADXL362:AWAKEステータス出力とモーション起動スイッチ機能
一般的なシステムにおいて、振動や静止を判定して何らかの処理を実行するには、常に加速度センサーからデータ値をマイコンへ送信し、マイコンが判定してから処理を行います。そのため、マイコン電源は常時ONである必要がありました。
”モーション起動スイッチ”を使えば、加速度センサーのみで振動や静止を判定できます。つまり、普段はマイコン電源をOFFにしておき、振動を判定したときだけマイコン電源をONし、処理終了後にマイコン電源をOFFするという超低消費電力システムを実現することが可能となります。

概要
今回はこの”モーション起動スイッチ”を活用して、振動を検知したときにクラウドにタイムスタンプをデータとして記録し、メール通知するIoTシステムを作成します。
クラウドへデータを送信するため、今回はWiFiマイコンを使用します。様々なWiFiマイコンがありますが、開発環境不要で低学習コストで開発可能なFlashAirを選択しました。

電源は単3電池2本とし、加速度センサーADXL362には常時電源供給を行い、FlashAirへはMOSFETを介して電源供給します。振動を検知したときだけ、ADXL362のINT端子をアクティブ出力にしてMOSFETをONさせ、FlashAirに電源供給を行います。FlashAirはクラウドへGET送信するというタスクが終了次第、ADXL362へINT端子を非アクティブ出力に戻すようにSPI通信を使って伝えるという流れです。なお、ADXL362はデフォルトで”モーション起動スイッチ”のモードにはなっていないため、一番初めにマイコンからSPIでモード設定を行う必要がありますが、回路とファームウェアに工夫を加え、ユーザーがそれを意識せず使えるようなシステムにしています。
クラウド側のアプリはGoogleスプレッドシートを選択しました。クラウドアプリは通常、AWSやAzure、GCPなどで環境を設定・構築し、そこにアプリをデプロイするということが一般的ですが、開発に慣れていない方にとっては非常に工数がかかります。一方でGUIなどを使って非常に簡単な手順で利用可能なバックエンドサービスもありますが、使い方が特化していたり、カスタマイズが難しかったりします。
GoogleスプレッドシートはExcelライクなクラウド表計算アプリケーションですが、実はプログラムも組めてWebアプリケーションとして動作・公開することが可能です。簡単かつ汎用的に使え、プログラミングで詳細にカスタマイズ可能です。
この後は、以下の流れで実行までをご説明します。

また、最後にADXL362レジスタ設定詳細と性能向上に向けた検討についても解説します。
電子部品
今回使用する電子部品も、すべて電子部品専門の通販サイト等で購入が可能です。

- MEMS 加速度センサー ADXL362搭載モジュール
※第6回記事で使用した部品と同一です - FlashAir W-04 16GB
FlashAirはWiFi付きSDカードというだけでなく、WiFiマイコンとしてプログラミングを用いて開発することが可能です。
※容量は16GB以外でも問題ありません。バージョンは第4世代のW-04を推奨します。 - SDカードスロットモジュール
FlashAirを装着するためのスロットです - Pch MOSFET 2SJ334
ドレイン電流がある程度以上流れることと、低電圧駆動であることが重要です。
PchとNchの2種類がありますが、今回はPchを使います。 - 単3×2本電池ボックス
直列2本です。直列3本以上の場合、FlashAirやADXL362の電源電圧の絶対最大定格を超えて故障する可能性が高いのでご注意ください。
単4型でも問題はありません。検討し易さのため、スイッチ付きにしていますが、スイッチ無しでも問題ありません。 - 単3アルカリ乾電池
アルカリ乾電池を推奨します。エネループなどのニッケル水素電池の場合、1.2Vと電圧が低いため、電源電圧不足になる可能性が高いです。
FlashAirを正常に動作させるのに必要な電源電圧は2.7~3.6Vです。 - ピンソケット 1×4pin
ピンを差し込むためのソケットです。今回はジャンパー線を挿入するために使います。 - 抵抗100kΩ
待機電流を少なくするため、大きめの抵抗値にしています。逆に1MΩなど大きすぎるとMOSFETをオンできなくなるのでご注意ください。 - 抵抗1.2kΩ
※第4回記事で使用した部品と同一です。今回は2本必要です。 - LED
※第4回記事で使用した部品と同一です - ジャンパー線(オス-オス)
※第1回記事で使用した部品と同一です - ブレッドボード
※第1回記事で使用した部品と同一です
電子回路
STEP1:部品のはんだ付け
ADXL362は第6回記事と同様に、5pinのピンヘッダを両端にはんだ付けした状態で使います。

SDカードスロットモジュールのはんだ付けは特殊な付け方をします。
8列と4列ありますが、8列は通常の方向に付属のピンヘッダを付けますが、4列は逆方向に別途用意したピンソケットを付けて下さい。

STEP2:部品の配置と結線
ブレッドボードに部品を配置して回路を作成します。
以下の配線図を参考に部品を接続してください。

※MOSFETの画像は、実物と少し異なります(実物は上半分も黒い樹脂)

電池ボックスのスイッチはOFFにしておいてください。電子部品は誤った電圧を与えると壊れるケースがありますので十分注意しましょう。
配線に間違いがないか確認してください。特にSDスロットモジュールの4pinコネクタに挿した2本のジャンパー線(電源とGND)の結線が合っていることを最終確認してください。
以下に簡易的な回路図を示します。

作成した電子回路を確認しましょう。FlashAirを挿入しない状態で、電池ボックスのスイッチをONにしてみて下さい。LEDが光れば正しい状態です。

APPENDIX:MOSFET
今回新たにMOSFETという部品を使用しています。

MOSFETとはMetal Oxide Semiconductor Field Effect Transistor の略でMOS型の電界効果トランジスタのことです。トランジスタというとラジオやオーディオなどで微弱な信号を増幅させる”アンプ”をイメージするかと思いますが、トランジスタのもう一つの使い方として”スイッチング”があります。
スイッチングとは簡単に言うと、微小な電流で、大電流のON/OFFを制御できるというものです。
例えば、マイコンや加速度センサーなどICのGPIO端子は、最大に流しても数mAが精いっぱいです。一方でFlashAirの電源は100mA以上の電流を必要とします。つまり、加速度センサーからFlashAirへ直接電源供給することはできないということです。そこで、トランジスタのスイッチングを用いて、間接的に大電流を制御するというのが今回の手法になります。
特にMOSFETは電圧駆動型とも呼ばれていて、ある2端子間の電圧が規定以上の電圧であればONするという特性を持ち、ほとんど電流を流さずに制御できるのが特徴です。MOSFETには”ゲート(Gate)”、”ドレイン(Drain)”、”ソース(Source)”の3つの端子があり、3つの端子は導通していませんが、”ゲート”と”ソース”の電圧差が規定以上の電圧になると”ソース”と”ドレイン”が導通するイメージです。今回のケースで説明すると、ゲート電圧が電池電圧と同じときはスイッチOFF、ゲート電圧が0VになるとスイッチONとなります。

動作イメージとしてデジタル的に説明しましたが、実際にはアナログの振る舞いを考慮する必要があります。本格的に実運用する場合は、定量的な検証を行い、バラツキを考慮した設計が必要です。
クラウドアプリケーション
Googleアカウントさえあれば、クレジットカード登録等なしに無料で作成可能です。

ExcelのVBAと似た感覚で、スプレッドシート上でGAS(Google Apps Script)というプログラムを用いて作成できます。プログラミング言語としてはJavaScriptに近いです。
※Googleアカウント登録からスプレッドシート作成までの手順は割愛させていただきます。Web上にたくさん情報がありますので、そちらを参考にお願いします。直感的にすぐできます。
STEP1:プログラムの作成
新規でスプレッドシートを作成し “ツール” から “スクリプト エディタ”を選択します。

以下のようなコードが書いてあると思います。

コードを以下のように書き換えてください。
このコードはGET送信を受信すると、シートに日時と1を追加し、メールを送信するプログラムです。

‘myaddress@example.com’ は実際の送信先メールアドレスに変更してください。
コピー可能なソースコードはGitHubGistで公開しています。
フロッピーアイコンをクリックして上書き保存します。

プロジェクト名を問われると思いますので、適当に入力してOKしてください。

これでクラウドアプリのソースコードは完了です。
STEP2:アプリの公開設定
今作ったアプリをWeb上に公開するために設定を行います。主に自分のアカウントで承認する作業がメインとなります。
“公開”から”ウェブアプリケーションとして導入”を選択します。

“プロジェクト バージョン” が “新規作成” になっていることを確認してください(プログラム修正して再度公開するときはここを常に”新規作成”に変更することを忘れないようにして下さい)
"アプリケーションにアクセスできるユーザー" を “全員(匿名ユーザーを含む)” に変更し、導入ボタンをクリックします。

“承認が必要です”とウィンドウが出るので、”許可を確認”を選択

アカウントを選択します。

“このアプリは確認されていません”と出ますので、左下の”詳細”を選択。

一番下に表示される “adxl362(安全ではないページ)に移動”を選択。

先ほど作ったアプリに対し、Googleアカウントへのアクセスを許可します。

“現在のウェブ アプリケーションのURL” をコピーしておいて下さい。
このURLは後でFlashAirのファームウェアにも使います。
OKボタンを押して完了です。

これでクラウドアプリの公開も完了です。
STEP3:アプリの動作確認
では早速、アプリが正しく動いているか確認してみましょう。
先ほどコピーしたURLをブラウザのアドレスバーに貼り付けてWebページにアクセスしてみてください。
アクセスする度に、スプレッドシートにアクセス日時と1が追記されてメール受信できれば、クラウドアプリは成功です。なお、1を記述している理由は、スプレッドシート上でグラフを作る場合に便利なためです。なくても問題ありません。


スプレッドシートのグラフ機能を使えばExcelと同じ感覚で簡単に作成可能です。
以下はグラフ表示例です。どの時間帯に密にアクセスがあったかが分かり易くなります。

PCのブラウザからだけでなく、スマホアプリやWiFiマイコンからでもGET送信をすれば、そのときのタイムスタンプが追加記録されます。インターネットのクラウド上にありますので、どこからでも送信可能で、どこからでも結果を閲覧することが可能です。
マイコンファームウェア
マイコン側のソフトウェアを作成します。

今回用いるWiFiマイコンはFlashAir W-04 16GBです。
FlashAirはWiFi機能が搭載されたSDカードで、主にWiFiのないデジカメに使うことで、SDカードを抜き挿しせずに無線で画像の受け渡しを可能にする使い方が一般的です。一方で、実はWiFiマイコンとして開発可能なデバイスで、開発者向けのFlashAir公式サイトもあります。
今回はFlashAirにてSPI通信とGET送信を行います。マイコンプログラムは、Luaスクリプトという言語で開発します。普通にPCでSDカードの読み書きさえできればOKで、開発環境ツールのインストールやユーザー登録など一切不要です。ビルドやコンパイルすることもなく、テキストエディタのみを使って開発します。
STEP1:FlashAirのCONFIG設定
CONFIGというファイルをテキストエディタで編集するだけです。
目的通りに使用できるようにFlashAirに以下4つの設定を行います。
- FlashAirを無線LAN自動起動&STAモードに設定(APPMODE)
- WiFiルーターのSSIDとKEYを設定(APPSSID, APPNETWORKKEY)
- SPIを使うためIFMODEモードを有効に設定(IFMODE)
- 電源ON後に自動的に実行させるプログラムファイルの指定(LUA_RUN_SCRIPT)
SDカードをPCに接続して、早速CONFIGファイルを編集しましょう。場所は”/SD_WLAN/CONFIG/”にあります。”SD_WLAN”フォルダは隠しフォルダになっているため、PCの設定によっては見えないようになっています。見えない方は、以下のサイトなどを参考にして、隠しフォルダ表示設定を行ってください。
テキストエディタで開くとこのような記述内容になっているかと思います。

XXXXXX…はカード毎に異なる文字列です。
以下のように書き換えます。
“APPMODE=4”と”APPNETWORKKEY=********”の行を削除して、下に新たな5行を付け足す手順です。

コピー可能なソースコードはGitHubGistで公開しています。
**********にはご自身の環境のWiFiルーターのSSIDとKEYを記入してください。
保存して閉じれば設定完了です。
CONFIGファイルの詳細に関してはこちらを参照してください。
STEP2:スクリプトファイル作成
FlashAirの一番上の階層(ルートディレクトリ)に”adxl362.lua”という名前でファイルを作成し、こちらのソースコード(GitHubGist)を記述し保存してください。
1か所 “https://***********************************************************************" となっている箇所がありますが、ここには、先ほど作成したクラウドアプリのURLを記述してください。
Lua言語では、コメント行を先頭ハイフン2つで表現します。
SPI Init、SPI Write、SPI Readの部分はADXL362とSPI通信をする際に使用する関数です。ADXL362のデータシートに従って記述しています。例えばADXL362のレジスタXにデータYを設定したい場合は、必ず最初に”0x0A”を送信し、その後Xを送信し、その後Yを送信するというようなルールがあります。同様にADXL362のレジスタZのデータを取得したい場合は、必ず最初に”0x0B”を送信し、その後Zを送信し、その後にリードするというルールです。
メインプログラムはMain以下の部分になります。流れは非常にシンプルな5つのブロックで、分岐処理も繰り返し処理もないため、上から下へフローが1回流れるのみです。5つのブロックのそれぞれについて詳細を説明します。
- SPI Initial Setting
SPIの初期設定です。通信周波数の設定(約1.6MHz)とSPIモードの設定(mode=0)をしています。 - ADXL362 Setting
FlashAirからADXL362へSPI送信を通じて、ADXL362の”モーション起動スイッチ”を設定しています。この設定を行うことではじめてADXL362をモーション起動スイッチとして使えるようになります。詳しくは別のセクションで説明します。 - Sleep 10sec
10秒間何もしないという処理です。FlashAirは電源ONしてから約5秒後にスクリプトファイルが実行され、WiFi接続が安定するまでにさらに数秒かかります。WiFi接続がしっかり安定するまで余裕をみて10秒待っています。 - Send HTTP GET request
クラウドアプリへGET送信を行っています。 - ADXL362 INT2 flag clear
FlashAir側での処理が完了した後、ADXL362へ通知します。ADXL362はこれを受けてからFlashAirの電源をOFFにします。
加速度センサーは電池により常時電源ONのため、2のADXL362 Settingは最初に1回だけ行えば良いのですが、このプログラムでは、FlashAirの電源がONされる度に毎回設定しています。
ADXL362のレジスタ値を読み込んで、設定済みかどうかを判別することは可能ですが、プログラムのシンプルさを優先してこのような形にしました。なお、毎回設定にかかる時間の分だけ、無駄に消費電流が流れるような気がしますが、FlashAirのWiFiが安定するまでは結局待つ必要があるため、消費電流に関しては特に弊害はない認識です。
マイコンのファームウェアは以上です。
ライブラリなどは一切不要で、このadxl362.luaファイルのみで完結しています。
実行
電子回路、クラウドアプリ、マイコンファームウェアの全てが完成しました。FlashAirをSDスロットに挿入し、電池ボックスのスイッチをONにしましょう!
LEDが点灯した10秒後くらいに、自動的に消灯します。
消灯したら、ブレッドボードに軽く振動を与えてみて下さい。振動を検知するとLEDが再び点灯します。今度は20秒後くらいに消灯します。
消灯した段階で、スプレッドシートにタイプスタンプが記録され、メール送信されていれば成功です。

ADXL362レジスタ設定詳細
ここでは、FlashAirのファームウェアで記述した以下のレジスタについて詳細に解説します。

全ての情報はADXL362のドキュメントのデータシートを見ることで分かります。以降の解説で使う図や表は、ADXL362のデータシートから抜粋しています。
”モーション起動スイッチ”のモードとして、リンクモードとループモードの2つがあります。どちらも振動検出待ちと静止検出待ちの状態遷移を無限に繰り返すモードです。
リンクモードはマイコンの介入も状態遷移に含むモード、ループモードはマイコンの介入は一切含まないモードです。
今回はWiFiマイコンがGET送信を完了するまでのタイミングが知りたいため、リンクモードを使います。
リンクモードはレジスタ0x27で設定しています。
spi_write(0x27, 0x1F) -- Motion detection, activity/inactivity detection : LINK mode
加速度センサーが振動検出して静止状態待ちになるまでをアクティブ状態、静止検出して振動検出待ちになるまでをインアクティブ状態と呼んでいます。以下の表を見ると、アクティブ状態のときのAWAKEというビットは1、インアクティブ状態のときのAWAKEビットは0であるということが分かります。

今回は、振動検出があった場合にマイコンに電源を供給するため、MOSFETをONにする(別の言い方をするとActiveにする)必要があります。MOSFETのゲートにはINT2端子を接続していますので、INT2にAWAKEビットを割り当てれば良さそうです。また、MOSFETをONするには、ゲートとソース間の電圧を規定値以上にする必要があります。ソースは電池電源に繋がっていますので約3Vです。つまりMOSFETをONするためにはソースを0V(組込みでいうところのLow)にするということです。ActiveにするのがLowなので、ActiveLowという呼び方をします。このINT2にAWAKEビットを割り当ててActiveLowにする設定は0x2Bにて行っています。
spi_write(0x2B, 0xC0) -- INT2 MAP : AWAKE bit, set ActiveLow
図はリンクモードの状態遷移図です。赤枠で囲った箇所がイベント待ちになります。

左上のWAIT FOR ACTIVITY EVENTは静止状態から振動状態を検出する待ちのイベントです。
ある閾値以上の加速度が、ある一定時間以上続いた場合は、ACTIVITY INTERRUPTに移行します。
この閾値を決めているのが0x20と0x21で、時間を決めているのが0x22です。
spi_write(0x20, 0x50) -- Activity threshold Lower : 80
spi_write(0x21, 0x00) -- Activity threshold Upper : 80
spi_write(0x22, 0x00) -- Activity timer (only 1Byte) : 0
閾値0x50(10進数で80)はいくつか値を入れて実際に試してみて決めた値です。時間は0x00で設定しています。0x00を設定すると1回でも検出したら反応するという意味になります。使用する環境によってこれらの値は調整する必要があります。
ACTIVITY INTERRUPTに移行するとAWAKEビットが1になり、WAIT FOR PROCESSORS TO CLEAR INTERRUPTへそのまま移行し、マイコンからの割り込みクリア待ちになります。
割り込みクリアするには、マイコンからSPI通信で0x0BレジスタをReadすることで成立します。FlashAirのソースコードの一番下で行っています。
-- ADXL362 INT2 flag clear
spi_read(0x0B)
マイコンから割り込み待ちクリアが実行されると、右下のWAIT FOR INACTIVITY EVENTは静止検出待ちイベントになります。
振動検出待ちと同様で、ある閾値以下の加速度がある一定時間以上続いた場合は、このイベント待ちを抜けて次の状態に進みます。この閾値と時間を決めているレジスタが0x23~0x26です。時間を決めるレジスタは振動待ちのときは1byteでしたが、静止待ちのときは2Byteあります。
spi_write(0x23, 0xFF) -- Inactivity threshold Lower : MAX(0x07FF)
spi_write(0x24, 0x07) -- Inactivity threshold Upper : MAX(0x07FF)
spi_write(0x25, 0x06) -- Inactivity timer Lower : 1sec
spi_write(0x26, 0x00) -- Inactivity timer Upper : 1sec
今回のシステムでは静止状態を検知したときに行うことは特にありません。ですので、このイベント待ちはそのままスルーする設定にしています。具体的には閾値をMAXにしてどんな振動があってもOKとし、時間を1秒としています。
INACTIVITY INTERRUPTに移行し、AWAKEビットは0になります。その後に再びWAIT FOR PROCESSORS TO CLEAR INTERRUPTがありますが、ここはスルーになります。理由はINT2端子にはAWAKEビットを割り当てており、このときの状態が0であるためです。割込みが発生するのは1のときのみです。
こうして再びWAIT FOR ACTIVITY EVENTに戻り、この状態遷移をずっと繰り返すことになります。
なお、一番初めに全システムの電源をONしたときは右下のWAIT FOR INACTIVITY EVENTから始まります。一番初めの電源ON後、GET送信前にMOSFETがOFFになるのはこのためです。
残りのレジスタ0x2Dは、低消費電力で使うためのWAKEUPとAUTOSLEEP設定、最後に測定を開始するための設定になっています。
spi_write(0x2D, 0x0E) -- Power Control : WAKEUP, AUTOSLEEP, Start measurement
性能向上に向けた検討
これまでに示した回路とファームウェアは、分かり易さと低学習コスト重視で、簡易的なシステムで構成しました。実際には通信に失敗した場合のリトライや電池を出来るだけ長持ちさせて使う工夫が必要です。これらについて対応案を検討します。
通信失敗時のフェールセーフ
状況によってはWiFi通信の調子が悪かったり、GET送信に失敗する場合もあります。こうした状況に対応するために、タイムアウト回数を設けた上でリトライを行うことが有効です。FlashAir W-04ではWiFiのOFF/ON制御及び、WiFiのON/OFF状態を得る関数も用意されています。これらを活用したフェールセーフ込みのプログラム例(GitHubGist)を示します。
初期のプログラムはWiFiが安定するまで決め打ちで10秒スリープさせていましたが、このプログラムの場合は最短で1秒スリープになっているため、WiFi通信の調子が良ければ省電力にも効果があります。
連続使用時間の向上
ADXL362の電源電圧仕様は1.6V~3.5Vですが、FlashAirの電源電圧仕様は2.7~3.6Vです。2.7Vを下回ると正常に動かなくなる場合があります。
アルカリ乾電池の公称電圧は1.5Vで、2本直列で3.0Vです。使用終了の目安となる終止電圧は1.0くらいで、2本直列だと2.0Vです。
つまり、アルカリ乾電池2本の電力最後まで使い尽くす前に、システムが動かなってしまうということです。
また、エネループなどのニッケル水素電池の公称電圧は1.2Vですので、2本直列の2.4Vでは最初から電圧不足で使えないということになります。
この対策として、昇圧DC-DCコンバータICを使う案があります。
昇圧DC-DCコンバータとは、直流電圧の入力電圧を引き上げて一定の電圧で出力するというものです。例えば入力が3.0Vから2.0Vに徐々に減っていっても出力は常に3.3V一定に保つことが可能となります。

昇圧DC-DCコンバータICを常時動作させる構成だとそれ自身の消費電力が大きいため、振動検知時のみ昇圧DC-DCコンバータICを動作させる構成を提案します。
ADXL362は1.6Vまで下がっても動作可能であるため、電池2本からの供給でも終止電圧まで大丈夫です。この構成の場合は、MOSFETではなく昇圧DC-DCコンバータICのEnable端子を制御することになります。Enable端子がHighのときに昇圧動作を行い、Lowのときはシャットダウン状態です。
昇圧DC-DCコンバータICはたくさん種類があります。乾電池レベルの電圧から昇圧可能か、目的の出力電圧を出せるか、流せる電流は十分に足りるかなどを確かめてから選択するようにしましょう。
今回のケースですとADP1607などが良さそうです。
注意点として、DC-DCコンバータICのEnable端子の入力電圧閾値は低いです。確実に閾値を下回るようにするために、ADXL362のINT端子とEnable端子の間にバッファ回路が必要になる場合があります。
また、電池が消耗してくると、ADXL362とFlashAirの電源電圧に差が生じます。異なる電源電圧でSPI通信を行うと不具合や故障の原因になるため、間にロジックレベル変換ICを入れて保護することも検討した方が良いでしょう。
まとめ
今回は加速度センサーADXL362の画期的な機能である”モーション起動スイッチ”について、具体的なIoTシステムを例にご説明しました。
ADXL362は活動量計などのウェアラブルデバイスに活用されていますが、工夫次第では超低消費電力で新しいUI体験ができる製品を生み出せるかもしれません。
この記事に関して
資料
{{modalTitle}}
{{modalDescription}}
{{dropdownTitle}}
- {{defaultSelectedText}} {{#each projectNames}}
- {{name}} {{/each}} {{#if newProjectText}}
-
{{newProjectText}}
{{/if}}
{{newProjectTitle}}
{{projectNameErrorText}}