5
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

M5Stackで防犯センサーを作ってみた

Last updated at Posted at 2019-03-09

背景

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

作成したコードは、以下の通りです。

main.py
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カードで行いました。

使い方

  1. SDカードに、任意のWaveファイルを書き込む。
  2. main.pyをM5Stackに書き込む。
  3. SDカードを、M5Stackに挿入する。
  4. 平らな場所にM5Stackを置き、電源を入れる。

M5Stackを持ち上げると、音が鳴ります。

5
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?