読者です 読者をやめる 読者になる 読者になる

ブログ

クソブログ

ESP32の開発ボード(DOIT ESP32 Development Board)をArduino IDEで使ってみる

IoT Electronics Arduino ESP32 BLE

2016年末に買って使い方がわからず放置してあったESP32の開発ボードを、ふと思い立って触ってみたらプログラムのアップロードから動作検証までいけたのでメモ。

ESP32開発ボード

github.com

このボードをAliExpressで買った。人類の天敵であるTELECの認証マークが付いているので日本国内で使用しても殺害される危険は少ない。

http://esp32.net/

を見ると、すでに膨大な種類の開発ボードが出回っているが、日本製の良いものはまだ無いようだ。

開発環境準備

Windows上で行う。基本的には解説ページ

github.com

に従えばOK。私はgit clientとしてSourceTreeを使ったが、解説ページに書いてあるようにgitの純正?クライアントを使っても同じだろう。

解説ページに書いてない部分としては、Arduino IDE上でボードを選ぶときは

f:id:XX-Prime:20170312194916p:plain

のようにESP32 Dev ModuleでOK。

もう一つ、プログラムをアップロードするときにBOOTボタンを押しっぱなしにしておく必要がある。ボードの初期リビジョンのバグみたいだが、これはこれでうっかりアップロードを防げるので良い仕組みのような気もする。

BOOTボタンを押さずにアップロードしようとすると

esptool.py v2.0-dev
Connecting...

A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header
A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header

というエラーがでる。ここまで来た人はあとはBOOTボタンを押しっぱなしにするだけなので成功したも同然である。ちなみに私がBOOTボタン押下の必要性に気づくまで試行錯誤や検索を繰り返して数時間を浪費したことは恥ずかしくて書けない。

追記:macarduino IDEではBOOTボタン押下の必要がなかった。

サンプルプログラムを試す

Arduino IDE

ファイル→スケッチ例→Simple BLE→SimpleBleDevice

をアップロードしてみる。BOOTボタンを押すたびに、アドバタイズする文字列(の数値部分)が変わるというもので、デバッグ出力をシリアルモニタで確認できる。シリアルモニタは115200bpsで開く。

このプログラムを動作させた状態でスマートフォンでBLEスキャンをすると

f:id:XX-Prime:20170312200801p:plain

のように、BLE32 at: XX という名でアドバタイズされているのを確認できる。BOOTボタンを押すとXXの部分が増えていく。これでESP32の開発環境からデバイスまで一通りが正常に機能していることを確認できる。ちなみにみんな大好きBlinkプログラムは(そのままでは)エラーが出て動作しないので泣かないように。Blinkは

int ledPin = 2;

と定義してこのピンをON/OFFするようにするとボード上の青いLEDが点滅する。

どっかに配線図ないのかな?

→どうやらこれっぽい:https://www.dropbox.com/s/jefwxxtufgwg0ex/esp32_Schematic%20Prints.pdf?dl=0 

まとめ

ESP32開発ボードを買って使い方がわからずに放置してる人は再挑戦してみてはいかがだろうか。

 

BMP085とNode-REDでM2Xに気圧データを送る

IoT Beaglebone Sensor M2X node.js Node-RED

Node-REDで簡単にI2C接続の気圧センサの取得値をM2Xにアップロードできるだろうとやってみたら、初心者が踏むであろう地雷を余すこと無く踏んでいって手こずったのでメモ。

ハードウェア準備

今回はホストマシンにBeaglebone Blackを、OSに

BeagleBoard.org - latest-images

の Jessie IoT (non-GUI) for BeagleBone via microSD card を選んだ。このイメージは最初からBeaglebone用のNode-REDが動作しているので便利である。BBGでもBBGWでもBBBWでもBBBlueでも同様に動作するはずである。

センサはサインスマート(SainSmart)BMP085 気圧センサーモジュール を使った。選択に積極的な理由は無い。そのへんに転がってたから。

BMP085の配線はI2Cなので

BeagleBoard.org - demo_bmp085

の通りだが、残念ながら新しいOSイメージでは /sys/bus/i2c/drivers/bmp085/ がもはや存在しないのでこのbonescriptデモは動作しない。bme280あたりで動くデモにそろそろ作り直したほうが良いと思う。bonescriptのデモは他にも色々と古くなってて残念な感じである。

bmp085のnode.jsモジュールをインストール

一応、全部をnode.jsで行ってみようと思ったので、読み取りライブラリもnode.jsのを用いた。

www.npmjs.com

の通り、npmでモジュールをインストールする。今回はNode-REDで使いたいので

$ sudo npm -g install bmp085

とグローバルインストールOK。/usr/local/lib/node_modules/bmp085/にモジュールがインストールされる。

気圧と気温を読み取れるかテストする際には、

var BMP085 = require('bmp085'),
barometer = new BMP085({
  'device': '/dev/i2c-2'
});
barometer.read(function (data) {
  console.log("Temperature:", data.temperature);
  console.log("Pressure:", data.pressure);
});

と、I2Cバスの場所として/dev/i2c-2を明示的に指定しないと失敗する(地雷1)。

M2XのNode-REDモジュールをインストール

www.npmjs.com

$ sudo npm -g install node-red-m2x

OK

$ sudo systemctl restart node-red.service

でnode-redを再起動してからNode-REDのwebページを開き、storageカテゴリにM2Xノードが現れていればインストール成功。

f:id:XX-Prime:20170214204619p:plain

M2X準備

M2Xのwebページにログインして、デバイス一つと、その配下にストリーム2つ(気圧用と温度用)を作っておく。

Node-REDフロー構成

一分に一回、気圧と温度データを取得してM2Xにアップロードするフローを構成した。

f:id:XX-Prime:20170214205921p:plain

やることは単純なので直線的でわかりやすいフローである。

測定開始タイマー

injectノードを1分のインターバルでリピート構成した。出力ペイロードは使わないのでデフォルトのタイムスタンプのままにしてある。

f:id:XX-Prime:20170214210659p:plain

気圧測定(BMP085)

問題はここ。functionノードでbmp085モジュールを呼び出して使う部分である。色々あったが動作する状態になったのが以下の図。

f:id:XX-Prime:20170222222823p:plain

topic_idにM2XのDEVICE IDを、sub_topic_idにストリーム名を指定する。

まず、素朴にfunctionノード内でrequireによるbmp085モジュールのロードを試みると

function : (error)
ReferenceError: require is not defined

などと怒られて動かない(地雷2)。

ちょっと調べると、Node-REDで外部モジュールを使う方法が分かった。requireはsettings.jsの中のfunctionGlobalContextに書け、というのが正解である。と言われてもBBB上のnode-redのsettings.jsがどこにあるかがわからんので、/var/logあたりにnode-redの起動ログがあるはずと予想して

root@bbb0001:/var/log# grep -r 'node-red' * | grep 'settings.js'

で探してみたら

daemon.log:Feb 11 11:52:30 bbb0001 Node-RED[2814]: 11 Feb 11:52:30 - [info] Settings file  : /root/.node-red/settings.js

と、あっさり見つかった。このファイルの中を見てみると、

functionGlobalContext: {
// os:require('os'),
// octalbonescript:require('octalbonescript'),
// jfive:require("johnny-five"),
// j5board:require("johnny-five").Board({repl:false})
},

と、外部モジュールのrequire方法がコメントとして例示されている。ありがたい。よって、ここに

bmp085:require("bmp085")

を追加した。functionノード内ではrequireではなく

var BMP085 = global.get('bmp085');

のようにしてグローバルコンテクストの中からロードするとrequireと同様にモジュールを使うことができる。

次に、取得したセンサ値をmsgのペイロードに詰めてreturnで次のノードに送ろうとしたが何も送られなかった(地雷3)。

この問題の原因は、bmp085モジュールのセンサ値取得が非同期で行われるためである。センサの取得値はモジュールのコールバック関数の中でしか触れなく、普通にreturnしてしまうと値の取得が行われない状態でfunctionノードが終了してしまう。node.jsで毎回この手の地雷を踏んでる気がするがいい加減覚えたらどうだ俺。

Node-RED日本ユーザ会 : Functions Nodeの書き方 日本語訳にいくつか誤りがあるので原文を参照したほうが良いかもしれない。いま修正案を作成中。→修正案が受理されてサイトに反映された(2017/02/27)。

の 非同期メッセージ送信 の所に、そのものずばりの答えが書いてあった。node.sendを使えば非同期で呼ばれる関数の中からメッセージを後続のノードに送ることができる。メッセージを複数返せるというのが嬉しい所で、今回は気圧と温度を別のメッセージとして送りたかったので正に2回node.sendを実行している。actionとしてsetStreamValue以外の何かを指定すれば一回で複数ストリームへのputが行えるかもしれないが、もう調べる気力が残ってない。

2017/02/20 追記

functionノード内で、毎回newによるbarometerオブジェクト生成を行っていたが、

Feb 17 09:24:42 bbb0001 Node-RED[11054]: (node) warning: possible EventEmitter memory leak detected. 11 exit listeners added. Use emitter.setMaxListeners() to increase limit.

というエラーがsyslogに出るので、コンテキストを利用して最初の一回だけnewするようにした所、当該エラーが消えた。これも地雷だな(地雷3.5)。Node-REDのノードは実行中に消えずに生き続けるということか。

M2Xへアップロード

M2XノードでAPIキーを指定する。ここは間違いようがない。

f:id:XX-Prime:20170214215216p:plain

Feedの鉛筆ボタンをクリックして

f:id:XX-Prime:20170214215357p:plain

API keyにM2XのデバイスAPI keyを入力してUpdateをクリックする。

確認用出力

このノードは特に要らないが、putされているオブジェクトを見るためにdebugノードを置いている。

出力例

f:id:XX-Prime:20170214215633p:plain

こんな感じで記録されていたら成功。台風の目が近くを通り過ぎると、尖点を持つかなり面白いグラフが得られる。

M2Xは、webサイトに埋め込むためのグラフも自動的に作ってくれるので、自動生成されたimgタグを埋め込むことで以下のように簡単にリアルタイムグラフを表示できる。

二軸までの同時表示が可能。timezoneの指定が出来ないのが残念な所で、UTCのみである。

Node-RED自動起動

デフォルトではnode-redサービスは自動起動しない。webブラウザで1880番ポートにアクセスするとxinetd的な何らかの仕組みでnode-redサービスが立ち上がるようだが、自動起動していると勘違いすると痛い目に会う(地雷4)。

$ sudo systemctl enable node-red.service

自動起動するようにしておかないとリブート後にデータアップロードが途切れて号泣する。

まとめ

Node-REDは大変扱いやすいけど、非同期で動作する外部モジュールを使う時にはここで書いたような地雷を踏まないようにしてね。

Nexus 6P 早期シャットダウン問題(と対処法)

Android

寒いと落ちるNexus 6P

バッテリーの残りが20~30%あるのに、突然Nexus6Pがシャットダウンするという問題が世界中で起こっている。私のも昨年の12月半ばあたりからその症状が出始めて、今では残り60%でも寒いとシャットダウンするという鬼畜仕様になっている。

世界中の叫び

https://code.google.com/p/android/issues/detail?id=227849

大まかにまとめると、寒い場所で落ちやすい、電力消費の大きいときに落ちやすい、優先度smallってフザケンナさっさと直せ、という感じでみんな怒ってる。特に、車で事故って写真撮ったり電話したりしてるときに落ちて困った、という報告はかなり気の毒である。死者がでたらどうすんだゴルァという書き込みもある。

今日は40%くらいまでは持った。本当に、ありがとうございます。

f:id:XX-Prime:20170124220307p:plain

一旦冷えてからスリープ解除すると強制シャットダウンというお馴染みの流れ。寒いと動かなくなるのは爬虫類だけで十分である。

Nexusヘルプセンターに連絡

support.google.com

Nexusヘルプセンターの右上に お問い合わせ というリンクがあり、(昼間だけ)電話での連絡を依頼することができる。これを依頼して症状を説明した所、交換対応という結果になった。保証はすでに切れているが、特別に対応してもらえた。一年後にまた爬虫類状態になる可能性は極めて高いが、このまま使い続けるよりはマシである。

まとめ

同じ問題に苦しんでるかたは連絡を依頼してみてはどうだろうか。向こうから自発的に連絡してくるほどgoogleのサポートは優しくないようだ。

ジャンパケーブルオスメス問題

Electronics

なんか作るときにジャンパケーブルが必要になって

  • オスーメスのケーブルが欲しいのにオスーオスしかない
  • オスーオスのケーブルが欲しいのにメスーメスしかない
  • メスが欲しいのにまわりにオスしかいない

などの問題が生じて発狂することがよくあるが、少なくともケーブルの問題を解決するそこそこうまい方法はある。

ケーブルはメスーメスしか買わない

オスーオス、オスーメス、メスーメスの三種類のジャンパケーブルがあるが、メスーメスだけあれば十分である。

バラ売りされているジャンパケーブルは地味に高価なので、無用なケーブルを用意するのは馬鹿げている。

さらに、

digitalparts.net

のようなリボン状のメスーメスケーブルを買えば比較的安く大量の本数を入手できる。割いて使うこともできるので、I2C用に4本だけまとめて切り離して使う、などバラ売りのケーブルより便利である。

オス化

akizukidenshi.com

のような両端が長いピンヘッダを用意しておく。これも1つずつ割いて使えるので、オスが必要な方に挿せばオスになる。メスからオスが生まれるのは生物界と同じである。

まとめ

オスのジャンパケーブルって要らなくね?

Rの代入演算子 <- をtypoして恐ろしいことが起こった

R

問題

Rで

x <- c(1, 2, 3)

は、xという変数に右辺のベクトルをアサインする式だが、この <- という演算子

y <-- c(1, 2, 3)

と打ち間違えると何が起こるか分かるだろうか?そんな演算子ねーよボケ、とエラーを吐いて停止するだろうと人間なら期待するが、R処理系は世にも恐ろしいことをやってのける。

答え

上の式のアサイン(?)は何の警告もなく完了し、yの値を出力すると

> y
[1] -1 -2 -3

と、各要素を-1倍した反対向きのベクトルがアサインされる。もう少し分かりやすく言うと、パリティ反転されたベクトルがアサインされる。同一文字を2回間違って入力することはたまにあるが、アサイン演算子のマイナス記号を2回入力したのを気づかないまま解析を進めると、この世ではあり得ない結果がどんどん出てきてデバッグに時間を盗られて夜中の2時56分にこのような下らない記事を書く羽目に陥る。

まとめ

この鬼畜仕様は何か意味なり歴史があるのだろうか?

追記

z <--- c(1, 2, 3)

> z
[1] 1 2 3

と、もう一回パリティ反転されてもとに戻ったw

w <-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- c(1, 2, 3)

パリティはどうなるだろうねえ。

Beaglebone Green Wireless (BBGW) とADXL345で振動解析(補足)

IoT Beaglebone Sensor

本当に回転運動か?

前回は、電動歯ブラシの振動を加速度センサで計測して、FFT解析の結果ほぼx-z軸のみにデルタ関数っぽいパワースペクトルが出たので、回転する偏心おもりによって振動が作り出されていると推測した。

FFT解析前のデータを二次元プロットしてみたところ、さらにそれを裏付けるきれいな図が得られた。

f:id:XX-Prime:20161215231944p:plain

RStudioにデータを取り込んで素朴なplot関数でx軸とz軸の加速度データを繋いだ図が上図で、たしかに回転運動をしていることが見て取れる。

上図では時間の情報が圧縮されて消えているため、plot_lyライブラリを使って、時間軸をz軸にとった三次元グラフも確認のために描いてみた。

f:id:XX-Prime:20161215232410p:plain

円筒形の表面に測定点が張り付いているような三次元プロットが得られた。光学の円偏光と同じパターンで、回転運動をしていることがよくわかる。

まとめ

FFT解析の後にやっと生データをプロットするあたりが腐れ外道。

Beaglebone Green Wireless (BBGW) とADXL345で振動解析

IoT Sensor Beaglebone

動機

振動検査システムはかなり高額なものが一般的で、センサ部分だけで10万円以上するものも多い。そこで、なるべく安価に、あまり精度は追求せずに振動を常時監視できるシステムを作りたい。機器の予防保全などの、本当に役に立つ方向への応用が考えられる。愚にもつかないお手軽なゴミデモシステムを作って「これがIoTです」とか言ってる連中が巷に溢れている現状にはため息が出るけど、そういうのは Industries of Trash と呼んであげる。

BBGW

Beaglebone Green WirelessはBeaglebone Black互換機のBeaglebone GreenにWi-FiBluetoothの無線通信機能が追加された最新の派生型である。UDOO NEOと同じ無線チップが実装されているので、うるっせえ技適の問題もない(はず)。

xx-prime.hatenablog.com

Beaglebone Green Wirelessはなぜか日本では販売されていないが、製造元のSeeedStudioから直接購入できる。

https://www.seeedstudio.com/SeeedStudio-BeagleBone-Green-Wireless-p-2650.html

現時点で5115円である。日本国内で外部アンテナをつけるかつけないかは勇気の問題である。

Beaglebone Green WirelessにはGroveコネクタが実装されているので、多種多様なセンサを簡単に確実に接続できる。Groveの振動センサ(加速度センサ)は感度に応じて3種類(±1.5g, ±16g, ±400g)あるようだが、特に要件が定まっていないので真ん中の±16gのものを選んだ。

Grove - 3 Axis Digital Accelerometer(±16g)

Grove - 3 Axis Digital Accelerometer(±16g) - Seeed Wiki

実店舗だと秋葉原のマルツ2号店で入手できた。千石電商は通販で手に入るが実店舗にはなぜか無いので店の中で落胆することになる。

www.marutsu.co.jp

これはAnalog Devicesの3軸加速度センサADXL345を実装しているGroveモジュールで、BBGWのI2Cコネクタに接続するだけでハードウェアの準備はOK。

f:id:XX-Prime:20161206213800j:plain

2つあるGroveコネクタのうち右のコネクタはUARTなので、眠いときに間違って挿して動かないと目が覚める。

ADXL345のスペックシートは以下。

http://www.analog.com/media/jp/technical-documentation/data-sheets/ADXL345_jp.pdf

どうしてもはんだ付けをしないと気がすまないド変態は、ADXL345のブレイクアウトボードを使う手もある。

www.marutsu.co.jp

なぜかGroveモジュールより高い。こっちだとアドレスピンの設定でSPIで通信できたり柔軟に使い倒せるが、スペックシートを読んで設定を理解する必要がある。ろくに読まずに謎の不安定動作で半日程度潰したが、今ではこっちも同じように安定して使えている。

ソフトウェア

ADXL345のライブラリはいろいろな言語で実装されているが、一番使いやすく理解しやすかったのが以下のpythonのものだった。

github.com

きれいで読みやすく、改造もしやすいサンプルコードが同梱されている。さすがadafruit。

BBGWにインストールするには、githubのmdに書いてある通り

sudo apt-get install git build-essential python-dev
cd ~
git clone https://github.com/adafruit/Adafruit_Python_ADXL345.git
cd Adafruit_Python_ADXL345
sudo python setup.py install

でOK。pipでもインストールできるが、サンプルコードがインストールされないので色々わかった人用。読みやすいコメントが入ったサンプルコードこそがADXL345初心者には何よりも貴重である。

サンプルを動かす

Adafruit_Python_ADXL345/examplesにあるsimpletest.pyがサンプルコードで、0.5秒おきに三軸加速度の値がコンソールに出力されるものである。

これをそのまま動作させると残念ながら

IOError: [Errno 2] No such file or directory: '/dev/i2c-1'

と出て動かないが、修正は極めて簡単で、simpletest.pyの

# Create an ADXL345 instance.
accel = Adafruit_ADXL345.ADXL345()

の部分を

accel = Adafruit_ADXL345.ADXL345(busnum=2)

に変えるだけである。この修正方法もサンプルコードの中にヒントとしてコメントされているので誰でも割とすぐ気づくだろう。引数なしでADXL345のインスタンスを作るとbusnum=1になってBBGWのGrove I2Cのバスとは違う所を読みに行ってしまうのが最初のエラーの原因である。なお、サンプルコードのヒントでは address=0x54 とI2Cアドレスの指定方法も書かれているが、Grove ADXL345モジュールのI2Cアドレスは0x53で固定なので、I2Cアドレスを明示的に指定したい場合は引数に(デフォルト値である)address=0x53を書く。

これでセンサの読み取りを実行できる。

$ python simpletest.py
Printing X, Y, Z axis values, press Ctrl-C to quit...
X=0, Y=0, Z=0
X=0, Y=9, Z=285
X=0, Y=8, Z=285
X=1, Y=8, Z=286
X=0, Y=10, Z=287
X=-1, Y=9, Z=286
X=1, Y=8, Z=285
X=0, Y=9, Z=286
X=0, Y=8, Z=286
X=-1, Y=9, Z=286
X=0, Y=9, Z=284
^CTraceback (most recent call last):
File "simpletest.py", line 52, in <module>
time.sleep(0.5)
KeyboardInterrupt

0.5秒ごとに加速度の値がコンソールに表示される。Z方向に重力がかかるように置いたのでXとYは小さい値である。Zの値が不思議であるが、これはADXL345のスペックシートを読むとわかる。引用すると:

最大分解能での出力の各 LSB は、3.9 mg すなわちオフセット・レジスタの LSB の 1/4 です。

mgはミリグラムではなくて、地球表面の重力加速度gの1/1000を意味している。

ライブラリはこれを忠実に守っているので、コンソールへの出力数値1が 3.9mg、つまり地球の重力加速度の 3.9 / 1000 倍を意味している。上のZ出力値の最頻値 Z = 286 に当てはめると

Z = 3.9*286 mg = 1115.4 mg = 1.1154 g

と約1gになり、ここが地球の表面であることを再確認できた。さすがにぴったり1にはならないので、キャリブレーションは自分でやれってことなのだろう。

連続で読み取ってみる

サンプルコードでは無限ループの中で

time.sleep(0.5)

があり、時間的にだいぶ緩やかな読み取りを行っているが、無慈悲にもこれをコメントアウトしてみると、すさまじい勢いで加速度の値がコンソールに出力される。サンプリング周波数がそこそこ大きそうだと期待できる。

生データとFFT解析結果をファイル出力

simpletest.pyにごく僅かに手を加えて、生データとFFT解析結果をcsvファイルとして出力するようにしてみた。データ解析ライブラリpandasが便利すぎて感動した。

gistc6b0aab240190a6e0635b4bd8e2e6d8b

これを実行すると、

Number of samples: 1024
measurement takes 1.351067 sec
FFT takes: 0.02015 sec
Sampling frequency: 757.919481417 Hz

のようにサンプリング周波数がコンソールに出力され、生データとFFT解析結果がそれぞれrawoutput.csv、fftoutput.csvファイルとして出力される。1024サンプルの取得に1.35秒しかかかっておらず、サンプリング周波数は約750Hzである。測定のたびに若干変動するが、この速さなら色々な振動を解析するのに十分な時間分解能だろう。

なお、ファイル中のtimeは、測定開始時刻と測定終了時刻とサンプル数から計算した値であり、正確なサンプリング時間を意味しているものではない。サンプル一回ごとにシステム時刻を取得するのは無駄だと思うのでこうしている。

サンプリング周波数を向上させる

BBGWはデフォルトのI2C通信速度が100kHzだが、最高で400kHzまで上げることができる。基本的なやり方は

Change i2c bus frequency on Beaglebone Black | randymxj的茶馆er

の通りだが、BBGWでは編集するdtbファイルのパスが若干変わっており、

/boot/dtbs/4.4.9-ti-r25/am335x-bonegreen-wireless.dtb

である。I2Cの通信速度を400kHzにしてからadxl345_fft.pyを実行すると

 Number of samples: 1024
measurement takes 0.594841 sec
FFT takes: 0.016457 sec
Sampling frequency: 1721.46842602 Hz

と、2倍強にサンプリング周波数が向上した。すごい。adxl345のサンプリング周波数の限界が3200Hzなので、測定性能の良いレンジを使い切れていると思う。サンプリング定理の制限により、サンプリング周波数の半分の850Hz程度までの振動を解析できる。

測定例

出力csvファイルを(pandasでちょっとした加工の後に)pythonのmatplotlibで図示してみた結果を以下に列記する。FFTの解析結果は値が複素数なので、絶対値と位相をそれぞれ示す。

静止状態

生データ

f:id:XX-Prime:20161207150048p:plain

z軸に地球の重力加速度がかかるように置いた。振幅が100mg程度のノイズが見られる。

FFT 絶対値

f:id:XX-Prime:20161207150328p:plain

これもノイズ成分のみが見られる。後に示す振動状態の結果と比較しやすいようにy軸のスケールを調整してある。中央を境界に左右対称の形になるのは実数値をFFT解析したときに共通の結果であり、サンプリング定理で最高測定周波数の半分までしか意味のある解析ができないことも納得できる。

なお、データ上は周波数ゼロの直流成分に極めて大きなパワーが記録されているが、地球の重力によるものなので図では示していない。平均値からのズレをFFT解析すれば直流成分は消えるはずである。

FFT 位相

f:id:XX-Prime:20161207150913p:plain

位相には特に規則性もなく、ほぼホワイトノイズと見なせる。

電動歯ブラシに押し当てた状態

生データ

f:id:XX-Prime:20161207151434p:plain

x方向とz方向に、振幅1500mg程度の激しい振動が見られる。ヴィ〜〜ン。y軸方向の振動が小さいのは、おそらく電動歯ブラシのモーターの回転軸の方向がy軸に一致していたためだろう。電動歯ブラシの振動は、モーターの回転軸とずれた位置に重心をもつ重りを回転させて作り出している(と思われる)ので、y軸方向の振動は作れない。y軸方向にも振動するように、y軸と直交する方向に軸を向けたモーターを追加するなりすれば全軸が振動して歯垢除去能力が向上するかもしれない。柄が太くなるから無理か。

FFT絶対値

f:id:XX-Prime:20161207151918p:plain

約131Hzのところに鋭いピークがあり、電動歯ブラシの振動(モーターの回転)をうまく捉えることに成功している。これを60倍した値がよく聞く回転数で、7860rpmとなる。近所の薬局で購入した安物の電動歯ブラシなのでこの程度だが、高価な奴で試せばピークの場所や数が変わると推測される。なお、ここでも直流成分の大きなパワーは除外している。

FFT位相

f:id:XX-Prime:20161207152406p:plain

位相に特に規則性はない。

まとめ

Beaglebone Green Wireles と ADXL345 の組み合わせで、比較的安価に振動解析システム(の基本要素)を構成できることを実証した。BBGWのI2C通信のスピードアップを施すことで850Hz程度までの振動を解析可能なので、応用範囲は広そうである。

総額で1万円もかからない安価な測定システムとしては良い結果だと言えるだろう。BBGWにはまだ適切なエンクロージャがないが、タカチのケース加工サービスを利用すれば、発注量にもよるが一つで1000円を切ることも可能であろう。Edisonのエンクロージャを作ってみたときは8個で1万円いかなかった。

温湿度などの単純なデータとは違い、振動データはあっという間にデータ量が莫大になってしまうので、そのままクラウドに送るなどするのは考えにくく、いわゆるエッジコンピューティングで特徴量を計算する必要がある。BBGWの計算能力は振動解析には十分で、1024*3サンプルのFFT解析に0.01秒程度しか要さない。連続的に測定と解析を行って振動を監視することができる。FFT以外にも様々な時系列解析手法があり、BBGW上でそのまま動作するものも多いだろう。

やり残していること

C++のライブラリを使ってサンプリング周波数がどの程度まで向上するか若干興味はあるが、C++でコードを書いていると、そのあまりの非人道的な言語仕様に怒りが込み上げてくるので今はやっていない。クロスコンパイル環境を作ってMac上のEclipseからBBGWで実行ファイルを動かすくらいまではやったが、続きはC++大好きっ子のド変態に代わりにやって頂きたい。

また、BeableboneにはCPUとは独立して動作するPRUというプロセッサがあり、これを使うとOSのタスクスイッチの影響を受けずにリアルタイム処理に近いことができるようである。I2C通信をPRUで行えば、より安定したサンプリングが可能になり、解析結果も正確になるだろう。が、PRUの使い方がよくわからんのでこれも今はやっていない。