ESP8266と3軸加速度センサーADXL345を使って振動を測定し、Ambientで可視化します。

3軸加速度センサーADXL345

ADXL345は次のような仕様の3軸加速度センサーです。

  • 設定により±2Gから±16Gまで測定可能
  • 分解能は1ビット当たり3.9mG(設定による)
  • SPIとI2Cでアクセス可能

この他にもタップ、ダブルタップの検出、動きの有無の検出など豊富な機能を持っています。

ADXL345の制御にはESP8266を使います。ESP8266とADXL345はSPIで接続しました。

ADXL345 ESP8266
VDD 3V3 
GND  GND 
SCL  IO14 
SDO   IO12
SDA  IO13
CS  IO5 

プログラム

振動と言っても様々な振動がありますが、今回は建物の振動を測ることにします。振動の周波数は建物によりますが、50Hzぐらいまでを測定することにして、10m秒間隔で加速度センサーの値をサンプリングすることにしました。

センサーのx軸、y軸を水平方向、z軸を鉛直方向になるように設置すると、x軸、y軸はほぼ0G、z軸は重力の約1Gの加速度がかかった状態になります。そこで最初に10m秒間隔で100回、x軸、y軸、z軸の加速度を測定して平均値を求め、これを基準値にします。振動の測定値はセンサーから読んだ値と基準値の差分にします。ADXL345の分解能は1ビット3.9mGなので3.9倍すると加速度が得られます。

プログラムでハマったのはSPIのモード設定でした。ADXL345のデーターシートには、次のように書いてあります。

SCLK はシリアル・ポート・クロックであり、非伝送時にCSがハイレベルの場合、SCLK はハイレベルにしてください。データは、SCLK の立上がりエッジでサンプリングしてください。

この説明はSPI Mode3です。ところが

SPI.setDataMode(SPI_MODE3);

とすると正しそうな値が取得できません。「ESP8266 ( ESP-WROOM-02 ) SPI 通信高速化、その2」というブログに「ESP8266 のSPI ライブラリでは、SPI.setDataMode(SPI_MODE2); は Mode 3 です!!」と書いてあるのを見つけ、

SPI.setDataMode(SPI_MODE2);

としたところ、正しい値を取得することができました。

プログラムはGithubに公開しました。

プログラムをビルドするにはAmbientのArduinoライブラリーが必要です。インストール方法は「Arduino ESP8266で温度・湿度を測定し、Ambientに送ってグラフ化する」をご覧ください。

データー測定

プログラムをビルドして動かしてみました。Wi-Fiに接続し、基準となるx、y、z軸の加速度を測定して表示した後、10秒間、振動を測定します。試しにセンサーを置いた机をx軸方向、y軸方向、z軸(鉛直)方向に、それぞれ3回ずつ軽く叩いて見た時の様子が最初に載せたグラフです。

x軸、y軸、z軸それぞれの方向に叩いた時に対応する方向の振動が検出されているのが分かります。y軸方向に叩いた時はy軸だけでなくx軸にも振動が検出されていますが、これは机がx軸方向に揺れやすかったのかも知れません。

z軸方向のグラフを拡大してみたのが下の図です。

10m秒のサンプリングで振動は測定できているように思います。

測定結果は以下のアドレスで公開しています。

振動データーの周波数成分を調べる

この振動データーを高速フーリエ変換(FFT)処理して、周波数成分を調べます。今回はPythonのFFTライブラリーを使うことにしました。まず、必要なライブラリーをインポートします。

import numpy as np
import scipy.fftpack
from pylab import *
import pandas as pd

Ambientに蓄積したデーターをPythonで読み込むには、Ambientライブラリーを使う方法と、Ambientのデーターをcsvファイルにダウンロードし、Pythonでcsvファイルを読み込む方法があります。今回はcsvファイルから読み込んでみます。

df = pd.read_csv('data/data1475.csv')

こんな感じでpandasのDataFrameとして読み込めます。中身を確認します。

df.head(3)

ここから、z軸加速度のデーターを抜き出し、最大値、最小値を求め、値が-1から1の範囲になるようの正規化します。

x = df.iloc[0:, 3:4].values.flatten()
(np.max(x), np.min(x)) # 結果は(390.0, -253.5)
x = [y / 390.0 for y in x]

データーを確認します。

plot(x[0:1000])
show()

この中から616サンプル目から60サンプル、時間にすると測定開始6.16秒目から0.6秒の振動データーの周波数成分をFFT処理してみます。

start = 616 # サンプリングする開始位置
N = 60 # FFTのサンプル数
fs = 100.0 # サンプリング周波数 100Hz => 10m秒間隔でサンプリング

hanningWindow = np.hanning(N) # ハニング窓
X = scipy.fftpack.fft(hanningWindow * x[start:start+N])

freqList = scipy.fftpack.fftfreq(N, d=1.0/ fs) # 周波数軸の値を計算

amplitudeSpectrum = [np.sqrt(c.real ** 2 + c.imag ** 2) for c in X] # 振幅スペクトル

元の波形と振幅スペクトルを表示します。

# 元の波形
plot(range(start, start+N), x[start:start+N])
axis([start, start+N, -1.0, 1.0])
xlabel("time [sample]")
ylabel("amplitude")
show()

# 振幅スペクトル
plot(freqList, amplitudeSpectrum, marker= 'o', linestyle='-')
axis([0, fs/2, 0, 1])
xlabel("frequency [Hz]")
ylabel("amplitude spectrum")
show()

30Hzあたりにピークのある周波数成分の振動であることが確認できました。

元のデーターは10m秒周期で10秒間サンプリングしています。これを先頭から128サンプルFFT処理し、16サンプルずつずらしながら、最後までFFT処理し、周波数成分の変化を見ると、次のようになりました。

振動データーを継続的に測定し、周波数成分の変化を抽出することで、工場設備の故障予知などにつなげていけそうです。

FFT処理は次のサイトを参考にさせていただきました。