背景
M5Stack Grayを使って何かできないかと考え、ふと閃いたのが、防犯センサーです。
M5Stack Grayには、9軸センサー(加速度、ジャイロ、地磁気)とスピーカーが搭載されています。
ジャイロセンサーをトリガーにして、音を鳴らすようにすれば、防犯センサーの完成です。
備忘録に近い内容ですが、ご容赦ください。
M5Stackのセットアップ
M5Cloudから、MicroPythonを使えるようにします。
開発環境
- MacBook Air (13-inch, 2017)
- macOS Mojave 10.14.3
下準備
ここら辺を参考に、MacからM5Stackを認識できるようにします。あと、esptool.pyをインストールしておきます。
https://qiita.com/inachi/items/d23b9e39551836cddb09
https://qiita.com/hmmrjn/items/2b2da09eecffcbdbad85
ファームウェアの書き込み
やり方が悪い可能性が高いのですが、GitHub公式のファームウェアでは、上手くいかなかったです。ファームウェアを書き込んでも、画面に何も表示されなかった...
色々試した結果、Windows環境を使って、M5Burnerに入っているM5Cloud v0.4.0を書き込んだ所、上手くいきました。
というわけで、Macの方で、M5Burner Windows版をダウンロードします。
unzipしてから、M5Burner/firmwares/M5Cloud/v0.4.0/firmware_0x1000.binを、適当な場所にコピー&ペーストします。そして、esptool.pyを使って、ファームウェアを書き込みます。
$ esptool.py --chip esp32 --port /dev/tty.SLAB_USBtoUART erase_flash
$ esptool.py --chip esp32 --port /dev/tty.SLAB_USBtoUART write_flash --flash_mode dio -z 0x1000 firmware_0x1000.bin
M5Cloudの設定
あとは、下記記事を参考に、M5StackがWi-Fiに繋がるよう設定します。
https://qiita.com/cyubachi/items/3481e0697a718b586d09
防犯センサーの詳細
こんな感じの仕様にしました。
仕様
ジャイロセンサーの値が設定値(センサー値で1000)を超えた場合、SDカードに保存したWaveファイルを再生する。
実装したコード
下記のサイトを参考にして、コードを作成しました。
https://qiita.com/cyubachi/items/707f77be425217391aae
http://blog.akanumahiroaki.com/entry/2018/10/27/235000
作成したコードは、以下の通りです。
from m5stack import *
from machine import I2C, I2S, reset
from mpu9250 import MPU9250
import os, time, wave
from math import atan2, cos, sin, sqrt
# -----------------------------------------------------------------------------
# Initialize I2S port
# -----------------------------------------------------------------------------
i2s = I2S(mode = I2S.MODE_MASTER | I2S.MODE_TX | I2S.MODE_DAC_BUILT_IN,
rate = 16000,
bits = 16,
channel_format = I2S.CHANNEL_ONLY_RIGHT,
data_format = I2S.FORMAT_I2S_MSB)
# -----------------------------------------------------------------------------
# This is a DemoClass for 9DOF Sensor(MPU9250).
# -----------------------------------------------------------------------------
class SensorDemo:
def __init__(self):
# Initialize MPU9250(I2C)
i2c = I2C(sda = 21, scl = 22)
self.sensor = MPU9250(i2c)
def acceleration(self):
# Get Acceleration Data(ax, ay, az)
return self.sensor.acceleration
def gyro(self):
# Get Gyro Data(gx, gy, gz)
return self.sensor.gyro
def magnetic(self):
# Get Magnetic Data(mx, my, mz)
return self.sensor.magnetic
def pitch(self, ax, ay, az):
# Calc Pitch
return atan2(ay, sqrt(ax**2 + az**2)) * 57.3
def roll(self, ax, ay, az):
# Calc Roll
return atan2(-ax, sqrt(ay**2 + az**2)) * 57.3
def yaw(self, ax, ay, az, mx, my, mz):
# Calc Yaw from Pitch & Roll
yh = (my * cos(self.roll(ax, ay, az))) - (mz * sin(self.roll(ax, ay, az)))
xh = ( (mx * cos(self.pitch(ax, ay, az))) +
(my * sin(self.roll(ax, ay, az)) * sin(self.pitch(ax, ay, az))) +
(mz * cos(self.roll(ax, ay, az)) * sin(self.pitch(ax, ay, az))) )
return atan2(yh, xh) * 57.3
# -----------------------------------------------------------------------------
# Play Wave file with I2S
# -----------------------------------------------------------------------------
def wav_player(fname):
# Open Wave file
wav = wave.open(fname)
i2s.set_dac_mode(I2S.DAC_RIGHT_EN)
i2s.sample_rate(wav.getframerate())
i2s.bits(wav.getsampwidth() * 8)
i2s.nchannels(wav.getnchannels())
i2s.volume(30)
while True:
# Set buffer size
data = wav.readframes(1024)
if len(data) > 0:
# Play Wave file
i2s.write(data)
print('.', end='')
else:
# Close Wave file and Open Wave file (for Loop sequence)
wav.close()
wav = wave.open(fname)
i2s.set_dac_mode(I2S.DAC_RIGHT_EN)
i2s.sample_rate(wav.getframerate())
i2s.bits(wav.getsampwidth() * 8)
i2s.nchannels(wav.getnchannels())
if buttonB.pressedFor(1.0):
# Run Kill process
wav.close()
i2s.stop()
lcd.clear()
lcd.setCursor(0, 0)
lcd.setColor(lcd.WHITE)
lcd.print('Release Button!', 0, 0, color=lcd.RED)
lcd.print('Please wait a second.', 0, fh * 2)
reset()
# /////////////////////////////////////////////////////////////////////////////
# Main Code starts from here.
# /////////////////////////////////////////////////////////////////////////////
# Initialize Display
lcd.clear()
lcd.setCursor(0, 0)
lcd.setColor(lcd.WHITE)
# Get fontSize
fw, fh = lcd.fontSize()
# Display Labels
lcd.print('Acceleration', 0, 0)
lcd.print('Gyro', 0, fh * 4)
lcd.print('Magnetic', 0, fh * 8)
lcd.print('Pitch, Roll, Yaw', 0, fh * 12)
# Initialize DemoClass
sD = SensorDemo()
while True:
# Get SensorData
ax, ay, az = sD.acceleration()
gx, gy, gz = sD.gyro()
mx, my, mz = sD.magnetic()
# If exceeded the threshold value, break while loop and play Wave file.
if abs(gx) > 1000 or abs(gy) > 1000 or abs(gx) > 1000:
lcd.print(' Motion was detected!', 0, fh * 17, color=lcd.RED)
break
# Display SensorData
lcd.print(' ax: {:+.1f}'.format(ax), 0, fh * 1)
lcd.print(' ay: {:+.1f}'.format(ay), 0, fh * 2)
lcd.print(' az: {:+.1f}'.format(az), 0, fh * 3)
lcd.print(' gx: {:+.1f}'.format(gx), 0, fh * 5)
lcd.print(' gy: {:+.1f}'.format(gy), 0, fh * 6)
lcd.print(' gz: {:+.1f}'.format(gz), 0, fh * 7)
lcd.print(' mx: {:+.1f}'.format(mx), 0, fh * 9)
lcd.print(' my: {:+.1f}'.format(my), 0, fh * 10)
lcd.print(' mz: {:+.1f}'.format(mz), 0, fh * 11)
lcd.print(' pitch: {:+.1f}'.format(sD.pitch(ax, ay, az)), 0, fh * 13)
lcd.print(' roll : {:+.1f}'.format(sD.roll(ax, ay, az)), 0, fh * 14)
lcd.print(' yaw : {:+.1f}'.format(sD.yaw(ax, ay, az, mx, my, mz)), 0, fh * 15)
time.sleep_ms(20)
# Mount SD Card and Play Wave file.
os.mountsd()
wav_player('/sd/(再生するWaveファイルを指定する)')
コードの説明
防犯センサーとは関係ないですが、画面上にセンサーからの情報を表示するようにしました。
表示する内容は、以下の通りです。
表示内容
- 加速度(X軸, Y軸, Z軸)
- ジャイロ(X軸, Y軸, Z軸)
- 地磁気(X軸, Y軸, Z軸)
- ロール(加速度から計算)
- ピッチ(加速度から計算)
- ヨー(ロール・ヨーから計算)
ジャイロセンサーの閾値(センサー値で1000)を超えた場合、whileループを抜けて、wav_player
を実行します。wav_player
の部分では、SDカードに格納されたWaveファイルを読み込み、ループ再生します。
Waveファイルの再生を止めるには、Bボタンを1.0秒以上、長押しします。すると、メッセージを表示した後に、システムが再起動されます。
注意点
M5Stackでは、SDカードしか認識できないみたいです。試した限りでは、32GBのSDHCカードは認識されませんでした。
なお、上記コードの動作確認は、2GBのSDカードで行いました。
使い方
- SDカードに、任意のWaveファイルを書き込む。
- main.pyをM5Stackに書き込む。
- SDカードを、M5Stackに挿入する。
- 平らな場所にM5Stackを置き、電源を入れる。
M5Stackを持ち上げると、音が鳴ります。