LoginSignup
1
2

More than 3 years have passed since last update.

M5StickCによるジェスチャ認識(3)~Wi-Fi接続と学習データの生成

Last updated at Posted at 2020-07-18

M5StickCによるジェスチャー認識

  • 今回は、学習データを作成することを目標とします。

M5StickC系のプログラム関連記事

  1. M5StickCによるジェスチャ認識(1)~インストールから加速度取得まで
  2. M5StickCによるジェスチャ認識(2)~サンプルコードによるジェスチャ認識
  3. M5StickCによるジェスチャ認識(3)~Wi-Fi接続と学習データの生成(この記事)
  4. M5StickCによるジェスチャ認識(4)~オリジナルデータによるジェスチャ認識
  5. M5StickCによる音声認識 ※現状の予定になります

学習データの作成

  • 前回の記事では「〇」「W」「∠」の3種類のサンプルを認識することができた。
  • 今回は、オリジナルのジェスチャを認識するために、まずは学習データを作成することを考えます。
  • 学習データは、ある一定の長さのジェスチャとなる加速度データをたくさん用意する必要があります。
  • 一般的には学習データが多ければ多いほど精度が良くなります。
  • 前回のプログラムを応用して、シリアル通信で取得した加速度情報をある一定のフレームで取得し、ファイルを生成することもできますが、シリアル通信のためにコードをパソコンに挿したまま行う必要があり、煩わしくなります。
  • そこで、今回はWiFiでデータを飛ばし、学習データを作成することを考えます。
  • 今回の手順は次の通りです。
  1. Wi-Fi通信のプログラムを作成
  2. 受信側で学習データの生成

Wi-Fiデータで加速度データの送信

  • M5StcikCは、通信機能として、Wi-Fiモジュール、Bluetoothモジュールがありますが、今回はWi-Fiを使います。
  • 新しくプロジェクトを作成します。プロジェクトはGitHubにも置いて負います
  • main.cppは次のような形になります
main.cpp
#include <M5StickC.h>
#include <WiFi.h>
#include <WiFiUDP.h>
#include "time.h"

const char* ssid       = "XXXXXXXXXXXX"; // SSID
const char* password   = "XXXXXXXXXXXXXX"; // Password
const char* ntpServer =  "aaa.bbb.jp";

const char* saddr = "XXX.XXX.XXX.XXX"; //taeget PC address

const int sport = 55998;
const int kport = 5556;

RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;

float accX = 0.0F;
float accY = 0.0F;
float accZ = 0.0F;

uint8_t mac3[6];

WiFiUDP Udp;
char packetBuffer[255];


void setup() {
  // put your setup code here, to run once:
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);

  M5.IMU.Init();

  esp_read_mac(mac3, ESP_MAC_WIFI_STA);
  M5.Lcd.setTextSize(1);
  M5.Lcd.setCursor(1, 0, 2);
  M5.Lcd.println("Welcome \n If the connection fails, turn off and on the power again.");

  // connect to WiFi
  M5.Lcd.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    M5.Lcd.print(".");

  }
  M5.Lcd.println("CONNECTED");
  delay(1000);

  // Set ntp time to local
  configTime(9 * 3600, 0, ntpServer);
  // Get local time
  struct tm timeInfo;
  if (getLocalTime(&timeInfo)) {
    // Set RTC time
    RTC_TimeTypeDef TimeStruct;
    TimeStruct.Hours   = timeInfo.tm_hour;
    TimeStruct.Minutes = timeInfo.tm_min;
    TimeStruct.Seconds = timeInfo.tm_sec;
    M5.Rtc.SetTime(&TimeStruct);

    RTC_DateTypeDef DateStruct;
    DateStruct.WeekDay = timeInfo.tm_wday;
    DateStruct.Month = timeInfo.tm_mon + 1;
    DateStruct.Date = timeInfo.tm_mday;
    DateStruct.Year = timeInfo.tm_year + 1900;
    M5.Rtc.SetData(&DateStruct);
  }
  M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(0, 1, 2);
    M5.Lcd.print("Connected \nto ");
    M5.Lcd.println(WiFi.localIP());
   uint8_t mac3[6];
   esp_read_mac(mac3, ESP_MAC_WIFI_STA);
  M5.Lcd.printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac3[0], mac3[1], mac3[2], mac3[3], mac3[4], mac3[5]);
  Udp.begin(kport); 

}

void loop() {
  int mil = millis(); 
  // put your main code here, to run repeatedly:
  M5.Rtc.GetTime(&RTC_TimeStruct);
  M5.Rtc.GetData(&RTC_DateStruct);
  M5.Lcd.setCursor(0, 50);
  M5.Lcd.printf("%04d-%02d-%02d ", RTC_DateStruct.Year, RTC_DateStruct.Month, RTC_DateStruct.Date);
  M5.Lcd.printf("%02d:%02d:%02d\n", RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes, RTC_TimeStruct.Seconds);


  // 加速度データ取得
  M5.IMU.getAccelData(&accX, &accY, &accZ);

  //データを学習用に変換する
  accX *= 1000;
  accY *= 1000;
  accZ *= 1000;

  M5.Lcd.printf("%6.0f, %6.0f, %6.0f\n", accX, accY, accZ);

  //UDP
  Udp.beginPacket(saddr, sport);
  Udp.printf("%5.2f, %5.2f, %5.2f", accX, accY, accZ);
  Udp.endPacket();  
  delay(100);
}
  • platformio.iniは次のように設定しました。
platformio.ini
[env:m5stick-c]
platform = espressif32
board = m5stick-c
framework = arduino
monitor_speed = 115200
build_flags = -DARDUINOSTL_M_H -Ilib/tfmicro/third_party/gemmlowp -Ilib/tfmicro/third_party/flatbuffers/include 
upload_speed = 1500000
  • プログラムの初めのほうの「SSID」「PASSWORD」「PCのIPアドレス」を適宜セットしてください。SSIDとPASSWORDは各自宅のWi-Fiの設定どおりに、「PCのIPアドレス」はコマンドプロンプトなどで「ipconfig」で確認できます。
  • プログラムを書き終えたら「Build」を押して、ビルドする。エラーがなければ、そのまま「Upload」すると、加速度がディスプレイに表示されます。

受信プログラムの作成

  • 今回は、Pythonを使って受信プログラムを作成します。

開発環境

  • python 3.6
  • pyqt

受信プログラム

  • ジェスチャを学習するためのファイルの指定が「output_[LABELNAME]_[PERSON].txt」である。また、ジェスチャーの長さはジェスチャーによって変わるため、それをGUIから操作できるようにした。
  • また、各自の環境によってはIPアドレスなども変わるため、そこもGUIから設定できるようにする。
  • プログラムは、GitHubに公開している。
UDP_GUI.py
from socket import *
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QCoreApplication
import datetime
import time
import csv
import pprint

class Example(QMainWindow):
    SrcIP = "XXX.XXX.XXX.XXX" #M5StickC Address
    outputName = "sample"
    labelName = "wave"
    loop = 100
    n = 0

    #初期化
    def __init__(self):
        super().__init__()
        self.initUI()
        self.dt_now = datetime.datetime.now()

    #UI create
    def setIP(self, msg):
        SrcIP = msg                             # 受信元IP
        SrcPort = 55998                                 # 受信元ポート番号
        self.SrcAddr = (SrcIP, SrcPort)                 # アドレスをtupleに格納

        self.BUFSIZE = 1024                             # バッファサイズ指定
        self.udpServSock = socket(AF_INET, SOCK_DGRAM)  # ソケット作成
        self.udpServSock.bind(self.SrcAddr)             # 受信元アドレスでバインド

    #UI create
    def initUI(self):      

        btn1 = QPushButton("Record", self)
        btn1.move(30, 30)

        btn2 = QPushButton("Quit", self)
        btn2.move(150, 30)

        btn3 = QPushButton('Set IP', self)
        btn3.move(30, 80)        
        self.inputURL = QLineEdit(self)
        self.inputURL.move(150, 80)
        self.inputURL.setText("192.168.1.1")

        btn4 = QPushButton('Set name', self)
        btn4.move(30, 130)
        self.inputFileName = QLineEdit(self)
        self.inputFileName.move(150, 130)
        self.inputFileName.setText("sample")

        btn5 = QPushButton('Set Label', self)
        btn5.move(30, 180)
        self.inputLabelName = QLineEdit(self)
        self.inputLabelName.move(150, 180)
        self.inputLabelName.setText("wave")

        btn6 = QPushButton('Set Length', self)
        btn6.move(30, 230)
        self.inputLength = QLineEdit(self)
        self.inputLength.move(150, 230)
        self.inputLength.setText("100")

        # クリックされたらbuttonClickedの呼び出し
        btn1.clicked.connect(self.recv)            
        btn2.clicked.connect(QCoreApplication.instance().quit)
        btn3.clicked.connect(self.Output)
        btn4.clicked.connect(self.Setfilename)
        btn5.clicked.connect(self.Setlabel)
        btn6.clicked.connect(self.Setlength)

        self.statusBar()

        self.setGeometry(300, 300, 290, 300)
        self.setWindowTitle('Getting accel data')
        self.show()

    #UDP receive
    def recv(self):
        print('\n----------\nIP Adress: ', self.SrcIP)
        print('loop count: ', self.loop)
        print('Output filename: ', self.outputName)
        print('label name:', self.labelName)
        i = 0

        #with open(self.outputName + '_' + self.dt_now.isoformat().replace(':','') + '.txt', 'a', newline='') as f:
        with open('output_' + self.labelName + '_' + self.outputName + '.txt', 'a', newline='') as f:

            f.write('\n\n\n -,-,-\n')
            time.sleep(2)

            self.setIP(self.SrcIP)
            while i < self.loop: # 受信待ち
                i = i + 1
                data, addr = self.udpServSock.recvfrom(self.BUFSIZE) # 受信
                l = data.decode().split(',')
                # 受信データと送信アドレス表示
                print(i, "\t", float(l[self.n]), float(l[self.n+1]), float(l[self.n+2]), addr) 
                s = 'x, y, z = ' + l[self.n] + ', ' + l[self.n+1] + ', ' + l[self.n+2]
                self.statusBar().showMessage(s)

                f.write(str(float(l[self.n])) + ',' + str(float(l[self.n+1])) + ',' + str(float(l[self.n+2])) + '\r\n')
            i = 0
            self.udpServSock.close()

    #ULR set
    def Output(self):
        self.SrcIP = self.inputURL.text()
        print('Change IP Adress:', self.SrcIP)

    #ULR set
    def Setlength(self):
        self.loop = int(self.inputLength.text())
        print('Change loop count:', self.loop)

    #Label set
    def Setlabel(self):
        self.labelName = self.inputLabelName.text()
        print('Change label name:', self.labelName)

    #filename set
    def Setfilename(self):
        self.outputName = self.inputFileName.text()
        print('Change output filename:', self.outputName)

        #時間の取得
        self.dt_now = datetime.datetime.now()

    def buttonClicked(self):

        # ステータスバーへメッセージの表示
        sender = self.sender()
        self.statusBar().showMessage(sender.text() + ' was pressed')


if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())
  • プログラムは、以下のように起動する
> python UDP_GUI.py
  • 起動すると以下のような画面が生成される。

2020-07-18.png

  • それぞれ、数値や文字を入力後にSetボタンを押す
  • Set IP: PCのIPアドレスを設定する
  • Set Name: 取得した人物の名前を登録(特に何でもよい)
  • Set Label: ジェスチャの名前を登録
  • Set Length: ジェスチャーを行っている長さを設定
  • [Record]をクリックすると、M5StickCが起動していれば、受信し、ファイルを生成する。
  • 同じ名前の人で何度も同じジェスチャーのデータを生成する場合は、続けて[Record]すると上書き保存する。
  • すでに同じ名前のファイルがある場合は、上書き保存する設定になっているため、新しく作成しなおす場合は、事前に作成されているテキストファイルを削除する。

2020-07-18 (1).png

1
2
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
1
2