【Python学習】IMU振る方向を学習させるサンプルプログラム動いた<2日がかり>

Pythonの学習、実際にIMU加速度出力を機械学習させるサンプルプログラムを動作させて勉強しました。
●Pythonを始める経緯
【Python学習】BTシリアル受信してCSVファイル保存<Pythonのメリット・デメリット>

【コト作り】AI調査で機械学習の練習例題その1<IMUを使った機械学習の事例>

【コト作り】2024年のテーマ模索期間2023Nov-2024Mar<いろいろいじってみたい>

●学習方法
サンプルプログラムの単語の調査とその意味と機能を検索しまくりました。
Pythonの文法系の検索=>良い解説サイトが無いので、1個1個別のサイトで探しまくって中途半端になった
ライブラリー系の検索=>ライブラリー系は、詳しい解説ブログが多いです。
と2日のうちのほとんどが検索、読解時間でした。
=>広告の大きいブログはまとまりが悪く、中途半端なものが多い Python関係ブログ広告多すぎる
判ったこと「Pythonが機械学習に適しているのは、ライブラリーを使うのに、オブジェクトの定義や条件指定が
非常にシンプルなので、膨大なデータを扱う統計処理ライブラリーを使うのが他の言語より楽である点です」
●pycharm便利
Pythonは、ライブラリーの塊でできてます。本体にデフォルトで付属しているものから目的のライブラリーを
importしながらプログラムを作っていきますので、ライブラリーのインストールが多数回繰り返します。
IDEをpycharmで使っているので、import  ライブラリー名 を右クリックして、install できるので、
コマンドラインでpipでinstallしなくても、pycharmのマウス操作だけで全て完結できるので便利です。
表紙のように import xxx というライブラリなら右クリックして、show context action クリックすると
install するメニューがでてくるので、クリックすれば自動でinstall が開始されます。画面下端にinstall進行状態が表示されますので、長いライブラリーでも進捗がわかるので、便利です。

●検索したリスト
単語がわからないので、単語と意味と内容を検索しまくりました。

サンプルプログラム
(QIITA)

魔法の杖のジェスチャーを機械学習で判定させてみた

IMUを振るジェスチャー3種類で学習させてMODELファイルをつくって、実際に振ったジェスチャーが何番のジェスチャーであったか判定
pycharm使い方

コピーして移動のリファクタリング

サンプルプログラムをコピペした元のプロジェクトをコピーして改造プログラムを作る操作をリファクタリングと呼んでいる。プロジェクト名を右クリックでrefactorでフォルダー指定
統計処理ライブラリ
scikit-learnの分類機能

scikit-learnでSVMを実装する

SVM(サポートベクターマシン)とは、データを分類して境界線を引くためのアルゴリズムです。「教師あり学習」と呼ばれる手法を用い、正解データを「教師からの助言」として学習し、学習結果をもとに境界線を定めた「分類器」を作成します。

その分類器を活用して、新しいデータ(未知のデータ)を入力した時に、そのデータがどちらに分類されるかどうかを区別することができるようになります。

scikit-learnのサンプルデータirisでの分類
(QIITA)
[機械学習] iris データセットを用いて scikit-learn の様々な分類アルゴリズムを試してみた iris ユリの花びらの特徴を4水準で測定したデータ3個体x=150データあってそれをscikit-learnで分類する サンプルプログラムを走らせみて、分類というものを実感した

Irisデータセット

Irisデータセット

scikit-learnの学習

fit()で学習、predict()で予測【scikit-learn】

pandas入門 pandas入門 データを前処理してデータフレームを作るライブラリ
seaborn入門 seaborn入門 グラフプロット ライブラリmatlabplotlibより色が綺麗にできる
pickeles使い方 picklesで保存して復元する方法 ファイル書き込みライブラリーで
解析結果の保存 復元が簡単

 ●プログラム
ソースはGISTにあります。
https://gist.github.com/dj1711572002/fd62c6ed9f0a19ebd42a01c8cf4d0b27
原典は2個のプログラムになっているが、本プログラムでは2個を1本のmain.pyに収納してある
起動して、キーボードでcを押すとMODELファイル作りをするプログラムに入って、MODELファイルを作成する、次にキーボードでgを押すとIMUを振って、MODELの分類の何番ジェスチャーで振ったのか、ジェスチャー番号を表示してくれる。原典では、マイコン側にボタンを用意して、ボタンを押している時だけとりこみを行う仕様になっているが、ボタンを作成するのが手間なので、本プログラムでは、aキーを押すとサンプリングが開始されるので、左手でaを押したら右手のIMUを振るという仕様で、データを学習させたりジェスチャーテストできる。

#coding utf-8
import datetime
import pickle  # モデルをファイルとして使用する用

import keyboard
import numpy as np  # numpyで2次元配列を扱うため
import serial  # シリアル通信を行うため
from sklearn.svm import SVC  # 学習用

length = 20 #ジェスチャの長さ(連続で受信するデータの個数)
gestures = 3 #ジェスチャの種類の数
times = 1 #各ジェスチャを行う回数
#====================================================
now = datetime.datetime.now()
name = now.strftime('%Y%m%d_%H%M%S')
filename = 'model_' + name + '.sav'  # 入力した名前の学習モデルのファイル名
print('Connecting...')
ser = serial.Serial('COM19',115200,timeout=None) #ポート番号19からシリアル受信
while True:
        print("-----Input  c:CreateModel,g:Gesture Measuring +ENTER")
        keys=input()
        if keys=='c':
        #------------------------Create Model BLOCK--------------------


            print("File name="+filename)
            X = []
            Y = []

            for i in range(gestures * times):
                cnt = 0 #受信したデータのカウント用
                mx = [] #各軸ごとの配列を初期化
                my = []
                mz = []
                gesture_num = i % gestures + 1 #ジェスチャ番号を指定

                print('Push a then Do gesture No.', gesture_num)

                while True:
                    line=ser.readline()#Binary
                    linestr= line.decode('utf8')
                    #print(linestr)
                    strarr=linestr.split(',')
                    x=strarr[1]
                    y=strarr[2]
                    z=strarr[3]
                    switch=''
                    if keyboard.is_pressed('a'):
                        print("key hit")
                        switch = "a"
                    if switch =='a' and cnt == 0: #クリックされたらカウント開始
                        print("cnt=1")
                        cnt = 1
                    if cnt != 0: #ジェスチャ中a
                        print("In gesture cnt="+str(cnt))
                        mx.append(x.rstrip('\r\n'))  # シリアルから受け取ってたデータのゴミを取って配列へ追加
                        my.append(y.rstrip('\r\n'))
                        mz.append(z.rstrip('\r\n'))
                        cnt += 1
                        if cnt == length: #lengthまでいったら次のジェスチャ待ちへ
                            print("length Up")
                            break

                m = mx + my + mz #三軸の加速度を横一列にする
                X.append(m) #学習データ用リストへ追加
                print(X)
                Y.append(str(gesture_num)) #学習ラベル用リストへ追加
                #print("serial closed")
                #ser.close() #シリアルを閉じる

            model = SVC(kernel = 'linear', C=1, gamma=1) #学習モデルのパラメータを指定
            model.fit(X,np.ravel(Y)) #学習を行う

            with open(filename, 'wb') as fp_model: #学習モデルを保存するためのファイルを開く
                pickle.dump(model, fp_model) #モデルを保存

            print('Model created.')
        #-----------------------------start gesture measuring-----------------------------------------------
        elif keys=='g':
            length = 20  # ジェスチャの長さ(連続で受信するデータの個数)
            print('-----------Start Gesture Measuring------------')
            #ser = serial.Serial('COM19', 115200, timeout=None)  # ポート番号19からシリアル受信

            #print('Input your name:')
            #name = input()
            #filename = 'models/model_' + name + '.sav'  # 入力した名前の学習モデルのファイル名

            print('Loading...')
            with open(filename, 'rb') as fp_model:  # 学習モデルファイルを開く
                loaded_model = pickle.load(fp_model)  # モデルをロード
            print('Do any gesture!')

            try:
                while True:
                    cnt = 0  # 受信したデータのカウント用
                    mx = []  # 各軸ごとの配列を初期化
                    my = []
                    mz = []
                    print("push a  measuring start")
                    while True:
                        line = ser.readline()  # Binary
                        linestr = line.decode('utf8')
                        # print(linestr)
                        strarr = linestr.split(',')
                        x = strarr[1]
                        y = strarr[2]
                        z = strarr[3]

                        switch=''
                        if keyboard.is_pressed('a'):
                            #print("key hit")
                            switch = "a"
                        if switch == 'a' and cnt == 0:  # クリックされたらカウント開始
                            print("gesture cnt=1")
                            cnt = 1

                        if cnt != 0:  # ジェスチャ中
                            mx.append(x.rstrip('\r\n'))  # シリアルから受け取ってたデータのゴミを取って配列へ追加
                            my.append(y.rstrip('\r\n'))
                            mz.append(z.rstrip('\r\n'))
                            cnt += 1
                            if cnt == length:  # lengthまでいったら次のジェスチャ待ちへ
                                break

                    m = mx + my + mz  # 三軸の加速度を横一列にする
                    m2 = []  # リスト型にするため
                    m2.append(m)  # リストへ追加

                    pre = loaded_model.predict(m2)  # ジェスチャの判定
                    print('This gesture is No.', pre[0][0])

            except KeyboardInterrupt:  # Ctrl-C を捕まえたら終了
                print('Close!')

            #ser.close()  # シリアルを閉じる

●実行画面

●python文法メモ
①変数の型定義がないので、今この変数が何型になっているのかわからなくてバグになることが多い
シリアル受信したときのデータは、バイト配列で収納されるので、そのままでプリントするとバイト単位のASCII表示になる、データを加工するには、バイト配列を文字列に変換してから、各種処理を行う。

②システムで使う予約文字を変数名に使ってはいけない。

[‘False’, ‘None’, ‘True’, ‘and’, ‘as’, ‘assert’, ‘async’, ‘await’, ‘break’, ‘class’, ‘continue’, ‘def’, ‘del’, ‘elif’, ‘else’, ‘except’, ‘finally’, ‘for’, ‘from’, ‘global’, ‘if’, ‘import’, ‘in’, ‘is’, ‘lambda’, ‘nonlocal’, ‘not’, ‘or’, ‘pass’, ‘raise’, ‘return’, ‘try’, ‘while’, ‘with’, ‘yield’]

●以後
今まで多数のグラフをEXCELで書くのが大変でできなかったのですが、pythonライブラリーを使って大量のグラフを書くことができるので、今までのデータ解析が進歩できると感じました。
pythonは、データを統計処理するエンジニア向けの言語です。

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です