瀧田の卒業研究

目的 

生体・環境センサを用い、数値からストレス値を計測.行動識別から現時点での場所,状態を取得しストレス値を検知したらコーピングを実施する.コーピングは状況に応じた内容を被験者に指示を出し,実行させることで実現させる.コーピング指示はスマートグラスにARオブジェクトを表示させて知らせる.この流れを通じ人間の精神的身体的負担削減を目指す


開発ツールの決定 (ARを作る場合) 

主に使用するデバイスによってツールをインストールする。

使用端末androidiOS
ARCoreArToolkit

使用端末がEPSON開発・MOVERIO-BT300の場合 

ARグラスとして扱いやすいものを選んだ。
この端末はARCoreをサポートしていないのでVuforiapositionも使用できない。
なのでARの使用範囲がかなり狭いです

スマートグラスを用いた行動アシスト 

以降は生態環境情報の取得する方法を習得している前提で記録する

センサとマイコン(Arduino, Raspberry Pi)による行動分類 


ここでprocessing_data.py,newsensa_all.pyが正常に動いて
デンドログラムが表示され、センサ数値が取れているようなったら次行けます

1.データ取得 

以降はproscessing_data.pyのデンドログラム表示関数に書き加えていきます
表示用に取得,算出するデータ

コード変数now_timelocationsituationtotal_timestress_datastatecopefigure
htmlToday場所状況経過時間ストレス予測値状態指令画像

1.1 音声入力による現在地と状況(location,situation) 

csvファイルに保存,デンドログラム作成に関しては先行研究あんので省略
ラベリングは一回しか行わないので最新がどのラベルの行動分析と一致するかを探る.
今回は場所と状態の2単語をマイクで入力する

マイク入力のコツ! 

1.「Okgoogle」のあと1秒待ってマイクをオフ。最短で入力できる
2.「机」(1秒待つ)「パソコン」(1秒待つ)マイクオフで確実に入る
3.processing_data.pyのラベル同期の部分で秒数が指定してあるからセンサの間隔と合わせる
4.「鬼滅の刃」とかは入らない「千の風になって」は全部入った

#ref(): File not found: "12241.JPG" at page "引継ぎ事項"

このデンドログラムからわかるように、同じ行動=色でラベルは一つしかないしラベルされてない色もある.
縦軸の関連度を表すユーグリッド距離を指定し,色付けされている.約2000で場所ごとに分けられることが分かっている.(吟味する必要あり)
そこで最新地を識別するには色別に分ける必要がある

#leaf_rotation=0がラベルの向き、orientation="top"がクラスタリングの図の方向
   #color_threshold=xでユークリッド平方距離がx以上を同色で表示
   #above_threshold_color="color"でユークリッド平方距離がx以上を"color"色に染める
   ##最新ラベルとラベルされているデータの距離が2000以内の場合同じ場所として判別#####
   dendrogram(Z, labels=df_label,leaf_rotation='vertical',leaf_font_size=16,color_threshold=2000,above_threshold_color='gray')
   #各データのクラスター番号出力
   group = fcluster(Z, 2000, criterion='distance')

groupリストには時系列でクラスター番号が格納される.つまり色ごとに番号が与えられた。
つづいてcsvファイルから必要なデータをコード内にリストで出力する

   df['時間'] = pd.to_datetime(df['時間'],format='%Y%m%d %H:%M:%S')
       frame_time = pd.to_datetime(df['時間'],format='%Y%m%d %H:%M:%S')
   gsr=df['GSR'].to_list()
   snp=df['心拍数'].to_list()
   loc_label=df['mic'].to_list()
   list_time=frame_time.to_list()

このリストからラベルとクラスター番号を関連付けるためにリストをつくる

   
   loc_c = []    //入力した分だけのラベルの配列
   loc_d = []  //入力した分だけのラベルのクラスター番号の配列
   loc_b = []    //クラスター番号とラベルの合体配列.サイズはデータ数
   loc_label     //リスト型のラベル配列
   loc_num = []  //リスト型のクラスター番号配列 
   for num in group:
       loc_num.append(num)
   loc_b = list(zip(loc_num, loc_label))

このloc_bリストにクラスター番号とそのラベルがセットになって格納されているが、ラベルはほとんどがnanというflort形の空データなので除外する。

   for i in loc_label: 
       if  isinstance(i, str):
           loc_c.append(i)
   print(loc_c)        
   for j,k in zip(loc_num, loc_label) :
       if isinstance(k,str):
           loc_d.append(j)
   print(loc_d)
   print("合体")
   print(list(zip(loc_c,loc_d)))

#ref(): File not found: "12021.JPG" at page "引継ぎ事項"

上からloc_c,loc_d,ラベルとその番号がセットになったリスト

ラベルにはマイクで「机 勉強中」などつづけて入力するのでこの入力を(場所)と(状況)に分ける必要がある

nowpoint =  group[length-1]   //最新のクラスター番号
#最新地のクラスター番号を調べ、それに対応している場所を特定
   if not nowpoint in loc_d:
       location = '不明 不明'
   else:
       for s,t in zip(loc_d, loc_c):  //最新のクラスター番号がラベリングリストにあったら場所が特定
           if nowpoint == s:
               location = t

#マイクで場所と状況を一度に入れているので分割
   loc_sp = location.split()
   #print(loc_sp)
   location=loc_sp[0]
   situation=loc_sp[1]

この(location)が場所、(situation)を状況、としてhtmlに書き込む


1.2 現在地による行動経過時間(today,total_time) 

1.1でクラスター番号とラベリングした場所を関連付けられたので,最新と同じ状況をどれだけ続いているかを調べる.

#ref(): File not found: "1201.JPG" at page "引継ぎ事項"

これはクラスター番号のリストを表示しているが,時系列で表示されている.
最新は最後なので最新=現在のクラスター番号は3とわかる.そして3が4つ続いているので12~16秒この行動が続いていると思われる.(カメラ取得は5秒で設定しているが3秒や4秒など薔薇薔薇で記録されることが多い)
この時間を取得し,どう行動経過時間を求める.

#場所が変わったかの判断と経過時間の算出
   #前回と今回の値が一緒だったら時間を加算、違ったら計測しなおす
   #start_timeを用意しnow_timeと引き算して分を出す.行動変化したらそれをstaretimeに変更する
   
   if lastpoint != nowpoint:
       print("行動変化")
       start_time = now=time
   else :
       print("継続中")
       #start_timeの算出、一個ずつ戻っていって行動変化したときの時刻をstart_timeとする
       for g in range(len(group)):
           if nowpoint != group[length -2-g]:
               start_time = list_time[length -1-g]
               break
   #行動経過時間の算出
   total_time=now_time-start_time 
   #total_time = total_time.strftime("%H:%M:%S")...0dayを消したい
   print('START ' , start_time)
   print('NOW   ' , now_time)
   print("TOTAL " , total_time)

まずnowpoint=最新のクラスター番号とlastpoint=そのひとつ前のクラスター番号を比較.
同じなら同じ行動が続いている、違ったら行動が変わったということになる.
その2つに応じてstart_time=計測開始時刻を設定する.行動が継続されていると判断された場合は一つ戻って比較,を繰り返す.
時間の演算はdatatimeを使えば簡単な引き算で求められる.

#ref(): File not found: "12011.JPG" at page "引継ぎ事項"

1.3 生体センサによるストレス予測:その1 (stress_data) 

残念ながらストレス値代表LF?HFは出せなかったのでGSR,心拍の数値をストレス状態で予測させることにした
初期の学習データはマイク入力により決める
ラベリング同様に数字だけを入力しそれを主観ストレス値とする(1~10か1,5,8の3つか、のどちらかにしたい)
マイク入力は一桁の数字は入らないので「ゼロ いち」と言えばスプレッドシートには「1」と記録される
そしてprocessing_data.pyのマイクラベルの「nan」を排除する処理でストレスラベルだけの配列を作成しておく
(ラベル要素の長さとかで)
そのラベルが入力された時(直前)の心拍とGSRセンサ数値、ストレスラベルをまとめて配列を作り上げる.
そのストレスラベル配列を新たなcsvファイル(koo.csv)に書き込んだら
決定木分析アルゴリズムにかける(平松初期研究をまるぱくりした)

#ref(): File not found: "tree.PNG" at page "引継ぎ事項"

GSR、心拍、ストレス値のデータがいっぱいたまったらコードを関数型にして
processing_data.pyで予測値を出力させる
この際csvファイルが毎回更新されないようにする

   #ストレス計測
   #マイクが数字だったら=ストレスアンケートだったらその時のGSRと心拍を表示
   #最新のGSR、心拍、ストレス入力の多次元配列制作
   for a,b,c in zip(gsr,snp,loc_label): 
       if isinstance(c, str) :
           if len(c.split()) == 1: 
               h = [a,b,int(c)]
               H.insert(len(H),h)
   
   #koo.csvに書き込む。最後のデータがひたすら書き込まれるんだけどどうしよう…
   #長さを比較して差分だけ書き込もう,イエア!
   ds = pd.read_csv("koo.csv",encoding="SHIFT-JIS")
   if len(H)>len(ds):
        leng = len(H)+1-len(ds)
        with open('koo.csv', 'a') as f:
            writer = csv.writer(f)
            for i in range(leng+1):
               writer.writerow(H[-i])
   
   #決定木プログラムにぶっこみ
   text =list(gssn[length-1])
   stress_data = decision_tree.tre_s(text[0],text[1])~

「stress_data」をストレス値として表示

1.3 生体センサによるストレス予測:その2(stress_data,state) 

数の微調整のため、ラズパイにarduinoIDEをインストールしておくと楽
王道:心拍からストレス値を出す
1.心電図からRRI間隔を出す
  さんざん悩んだけどよく考えたらRRIって心拍じゃん… 1/心拍ででるやん…
2.パワースペクトル密度を算出
  詳しい理論は木下先生のの実験でも思い返して。データ数は1024はいるから心拍を配列にためてたまってから求める
3.高周波(HF)と低周波(LF)の面積を求める。LF/HFでストレス数値
4.個人差はあるけど2以上がやばい、5以上がかなりやばいと言われている

処理はラズパイのnewsensa_all.pyのメインのところ、cnt<=5になっていると思うが、このcntを心拍配列にしておけばいいんでねーの?

行動時間はtotal_secondsで経過時間を秒に直し、規定値と比べる
processing_data.pyのstate決定するとこ,ついでにここでコーピングしない場合の図と指令も定義する(コーピング発動しない場合)

#発動しない場合
   if total_second_time < 2700 and stress_data <6.0:
       if stress_data <=2.0:
           state = '良好'
           figure='1.png'
           cope = 'No'

       else :
           state = '注意'
           figure='2.jpg'
           cope = '警告 : 危機が迫っている'

   #発動する場合
   else:#コーピング内容をだらだらかく


#ref(): File not found: "newsensaall.py" at page "引継ぎ事項"

1.4 3つの要素からコーピング内容決定 (cope,figure) 

ストレスが検知されたらコーピングを発動させる
まず行動経過時間から長時間か短時間化を判別。
今回は60分(1,2時間)同じ行動だと判断されたら場所に応じた内容、短かったら行動自体に問題があるので行動切り替えを促す
(本人が気づかぬうちに長時間行動で身体的負担が増すことを防止する)
また想定される場所に応じて、(ストレス感じる内容を把握)適度なコーピングを示したい。
いろいろ調べてもコーピング内容はほぼ一緒だったので、その行動が可能かを踏まえた。
(会議中だったら休憩には入れないなど)

#ref(): File not found: "1131.JPG" at page "引継ぎ事項"


  #スプレッドシートの単語から
       #if ('computer' and 'monitor') in camera11:
       #とりあえずPC操作にしておいた
       #    cope2 = 'コンピューター操作により'
        #   cope3 = '休憩に入り、目を休め'
    
       #行動識別から
       if 'パソコン' in situation:
           cope2 = 'コンピューター操作により'
           cope3 = '休憩に入り、目を休め'
       elif '会議'in situation:
           cope2 = '会議中なので'
           cope3 = 'ちょっと休め、耐えろ'
       elif '休'in situation:
           cope2 = '休憩でも'
           cope3 = '止めなさい'
       elif '天井'in location:
           cope2 = 'お前'
           cope3 = '休みすぎ'
       elif 'kichen'in location:
           cope2 = '打ち合わせより'
           cope3 = '止めた方がいいんじゃない'
       else:
           cope2 = 'その他の行動により'
           cope3 = '気分展開しよう'
    
   #とりあえす経過時間が長かった(90分以上,30分以上,それ以下)ら
       if int(total_time.total_seconds()) > 2400:
           print("長すぎ")
           cope1 = '長時間行動より'
       elif int(total_time.total_seconds()) > 1800:
           print("長時間行動")
           cope1 = '長時間行動と'
       else:
           print("短時間労働")
           cope1 = '行動は短いが'
           #cope3 = '行動を止めたほうがいい'
       state = '要注意、コーピングを実行'
       figure = '5.jpg'
       cope= cope1+cope2+cope3

2.ウェブ表示法アシスト:GooGle経由の場合 

追記:pyにhtml直書きにしてテキストファイル経由しないようにした 今回は取得したデータを用いて行動アシスト表示の制作に入る
データをドライブに保存し,自身のPCでcsvファイルにログを備蓄したあと,データをもとにhtmlを作成する.
流れはcsvファイルを編集するコード(py),表示されるウェブページ(html),MOVERRIO(グラス)の順で表示する

#ref(): File not found: "87.JPG" at page "引継ぎ事項"

1.収集したデータをもとに表示する文字を作成(選択)
2.processing_data.py内で編集、htmlファイルの文字を書き直す形で編集する
3.htmlふぁいるができる
4.PC(Windowsの場合)htmlがある📁のパスを通す.
  Internet Information service (IIS)のDefault WebSiteの「機能ビュー」の「詳細設定」で📁物理パスを設定.
  さらに「既定のドキュメント」に追加.
5.こうするとPCと同一Wi-Fi内でのみ「http://(PCの物理アドレス)」でグラスにhtmlが表示される.

・py内のhtmlファイル編集
・ストレスの変化を確かめる記録を作成

   #コーピング発動html
   opendata = r"C:/Users/wasaza/Desktop/nana/nan.html"
   
   with open(opendata, mode='w+', encoding="utf_8") as f:
       data_line4=('<!DOCTYPE html>\n<head>\n<meta http-equiv="content-type" charset="utf-8">\n</head>\n<body>\n<div style="font-size:small">\n')
       data_line5=('<br>\n</div>\n</body>\n<img src=' + figure + ' width="60"></html>')
       data_lines=('場所 :' + location + '<br>\n状況 :' + situation + '<br><br>\n\n経過時間 :' + str(total_time) + '<br>\n')
       data_lines2 = ('ストレス予測値 :' + str(stress_data) + ' / 状態 :'+ state+'<br>\n指令 :'+cope)
       data_lines3=('Today :' + str(now_time) + '<br>\n')
       f.write(data_line4)
       f.write(data_lines3)
       f.write(data_lines)
       f.write(data_lines2)
       f.write(data_line5)
       
   #記録
   with open('foo.csv', 'a') as f:
            writer = csv.writer(f)
            G =  [now_time,datetime.now().strftime("%H:%M:%S"),stress_data,copen,situation]
            writer.writerow(G)


GooGleスプレッドシート云々はIoTのページ見ろ
ラズパイ,グラス,実行PC(個人のノーパソで十分)を同一Wi-Fiに接続し,表示する.ただしコーピング処理を行う実行PCは,スペック低いノーパソは勧めん。

ストレス値の記録 

じっさいにコーピングを実行したらストレス値は下がるのか記録する
記録するのはデータ取得した時刻,html更新した時刻、LF/HF値、コーピング発動したか(0,1)、場所、コーピング実行したか(0,1)
それらからストレス値の経緯をみる

・IISの設定

#ref(): File not found: "11102.JPG" at page "引継ぎ事項"

・実際表示されたhtml

#ref(): File not found: "13.JPG" at page "引継ぎ事項"

winscpのミラーリング機能を使ったら時間限定で
パソコンで変更しても研究室のサーバーから発信できたので
学外のスマートグラスでも見れるようになった


3.ウェブ表示法アシスト:Google経由しない場合 

MOVERIOがAndroidなのをいいことにデザリングして同一wifi外でもやれるようにする。
研究室のサーバーにラスパイからデータを送信する。
送信した段階でエクセルファイルに書き込む。processing_data.pyでスプレッドシートのデータ搾取をそのエクセル配流に置き換える
めんどい

#ref(): File not found: "arg2.JPG" at page "引継ぎ事項"

データの流れ 

0.サーバー側のserver.pyと、ラズパイ側のsendata.pyをソケット通信
1.newsensa_all.pyでマイク以外のセンサデータを30秒毎取得しjsonファイルを作成、gasmic.pyで音声データを任意のタイミングで取得しjsonファイルを作成
2.sendata.pyでjsonファイルが生成されたらサーバーに送信。その後送ったファイルは消す。
3.送られてきたデータサイズでセンサデータかマイクデータか識別、各々のxlsxファイルに保存
4.processing_data.pyでxlsxファイルにアクセス、新規データ含めライフログ作成、クラスター分析しhtml作成
5.コーピングしたか(1,0)とかLH/HFとかをストレスログに保存
6.同フォルダにあるhttps通信設定したhtmlファイルが更新される。(htmlのhttps設定は横井さんがやってくれたから全然わかんない)


MOVERIOにhtmlを映す方法 

1.htmlをhttps通信で公開
2.何らかのスマホ(デザリングしたスマホ?)で開く
3.そのスマホにAuto Refreshアプリをダウンローそしてchromeを30秒で更新
4.そのスマホとMOVERIOをミラキャスト。スマホはAndroidがいい?iPhoneは分からん
5.つまりMOVERIOにスマホ画面を表示させる。


使ったコード全部 

江崎のドライブに全部ある、はず 江崎のドライブに全部ある、はず
・raspberry pi (python)

graph_maker.py
new_sensaall_esk.py
gasmic_esk.py
他importしたモジュールなど

・PC(python)

processing_data.py
client_secret.json
decision_tree.py
koo.csv
fordend.csv
graf.py(?)
graph_maker.py
make.@y(?)
map.html
model.bin
-html-
winscp
nan.html
opendata.txt
textwinscp.txt
web.config
5.png

トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS