Browse Source

Feat: refine training process

liudkun15@gmail.com 1 year ago
parent
commit
9230f19a52
3 changed files with 82 additions and 121 deletions
  1. 3 30
      backend/general_grasp_training.psyexp
  2. 77 89
      backend/general_grasp_training.py
  3. 2 2
      backend/pages/2_train.py

File diff suppressed because it is too large
+ 3 - 30
backend/general_grasp_training.psyexp


+ 77 - 89
backend/train_1.py → backend/general_grasp_training.py

@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 """
 This experiment was created using PsychoPy3 Experiment Builder (v2023.2.3),
-    on 十一月 13, 2023, at 16:29
+    on 十一月 14, 2023, at 14:23
 If you publish work using this script the most relevant publication is:
 
     Peirce J, Gray JR, Simpson S, MacAskill M, Höchenberger R, Sogo H, Kastman E, Lindeløv JK. (2019) 
@@ -34,13 +34,11 @@ import psychopy.iohub as io
 from psychopy.hardware import keyboard
 
 # Run 'Before Experiment' code from config
-import sqlite3
 import os
 import datetime
 from time import sleep
 import argparse
 
-from db.models import train
 from device.sig_chain.sig_receive import Receiver
 from device.sig_chain.device.connector_interface import Device
 from device.sig_chain.trigger_box import TriggerNeuracle
@@ -189,7 +187,7 @@ def setupData(expInfo, dataDir=None):
     thisExp = data.ExperimentHandler(
         name=expName, version='',
         extraInfo=expInfo, runtimeInfo=None,
-        originPath='C:\\Users\\dkunl\\kraken\\backend\\train.py',
+        originPath='C:\\Users\\dkunl\\kraken\\backend\\general_grasp_training.py',
         savePickle=True, saveWideText=True,
         dataFileName=dataDir + os.sep + filename, sortColumns='time'
     )
@@ -405,37 +403,29 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
         languageStyle='LTR',
         depth=0.0);
     instruction = visual.TextStim(win=win, name='instruction',
-        text='静息态采集\n请保持放松,注视十字准星',
+        text='准备进行一般抓握训练,\n按回车键继续',
         font='Open Sans',
         pos=(0, 0), height=0.05, wrapWidth=None, ori=0.0, 
         color='white', colorSpace='rgb', opacity=None, 
         languageStyle='LTR',
         depth=-1.0);
-    img_reststate = visual.ImageStim(
-        win=win,
-        name='img_reststate', 
-        image='C:/Users/zhengyan/myWork/py_work/Kraken/Albatross/backend/static/images/reststate.png', mask=None, anchor='center',
-        ori=0.0, pos=(0, 0), size=(0.5, 0.5),
-        color=[1,1,1], colorSpace='rgb', opacity=None,
-        flipHoriz=False, flipVert=False,
-        texRes=128.0, interpolate=True, depth=-2.0)
+    key_resp = keyboard.Keyboard()
     
     # --- Initialize components for Routine "mi_prepare" ---
-    img_prepare = visual.ImageStim(
-        win=win,
-        name='img_prepare', 
-        image='C:/Users/zhengyan/myWork/py_work/Kraken/Albatross/backend/static/images/reststate.png', mask=None, anchor='center',
-        ori=0.0, pos=(0, 0), size=(0.5, 0.5),
-        color=[1,1,1], colorSpace='rgb', opacity=None,
-        flipHoriz=False, flipVert=False,
-        texRes=128.0, interpolate=True, depth=0.0)
+    text = visual.TextStim(win=win, name='text',
+        text='请准备开始尝试运动',
+        font='Open Sans',
+        pos=(0, 0), height=0.05, wrapWidth=None, ori=0.0, 
+        color='white', colorSpace='rgb', opacity=None, 
+        languageStyle='LTR',
+        depth=-1.0);
     
     # --- Initialize components for Routine "mi_begin" ---
     img_right = visual.ImageStim(
         win=win,
         name='img_right', 
-        image='C:/Users/zhengyan/myWork/py_work/Kraken/Albatross/backend/static/images/right.png', mask=None, anchor='center',
-        ori=0.0, pos=(0, 0), size=(0.5, 0.5),
+        image='static/images/hand_move.jpg', mask=None, anchor='center',
+        ori=0.0, pos=(0, 0), size=None,
         color=[1,1,1], colorSpace='rgb', opacity=None,
         flipHoriz=False, flipVert=False,
         texRes=128.0, interpolate=True, depth=0.0)
@@ -455,8 +445,8 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
     img_rest = visual.ImageStim(
         win=win,
         name='img_rest', 
-        image='C:/Users/zhengyan/myWork/py_work/Kraken/Albatross/backend/static/images/rest.png', mask=None, anchor='center',
-        ori=0.0, pos=(0, 0), size=(0.5, 0.5),
+        image='static/images/rest.jpg', mask=None, anchor='center',
+        ori=0.0, pos=(0, 0), size=None,
         color=[1,1,1], colorSpace='rgb', opacity=None,
         flipHoriz=False, flipVert=False,
         texRes=128.0, interpolate=True, depth=0.0)
@@ -485,8 +475,11 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
     continueRoutine = True
     # update component parameters for each repeat
     thisExp.addData('before_mi.started', globalClock.getTime())
+    key_resp.keys = []
+    key_resp.rt = []
+    _key_resp_allKeys = []
     # keep track of which components have finished
-    before_miComponents = [train_position, instruction, img_reststate]
+    before_miComponents = [train_position, instruction, key_resp]
     for thisComponent in before_miComponents:
         thisComponent.tStart = None
         thisComponent.tStop = None
@@ -545,7 +538,7 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
         # *instruction* updates
         
         # if instruction is starting this frame...
-        if instruction.status == NOT_STARTED and tThisFlip >= 3-frameTolerance:
+        if instruction.status == NOT_STARTED and tThisFlip >= 2-frameTolerance:
             # keep track of start time/frame for later
             instruction.frameNStart = frameN  # exact frame index
             instruction.tStart = t  # local t and not account for scr refresh
@@ -562,51 +555,33 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
             # update params
             pass
         
-        # if instruction is stopping this frame...
-        if instruction.status == STARTED:
-            # is it time to stop? (based on global clock, using actual start)
-            if tThisFlipGlobal > instruction.tStartRefresh + 2-frameTolerance:
-                # keep track of stop time/frame for later
-                instruction.tStop = t  # not accounting for scr refresh
-                instruction.frameNStop = frameN  # exact frame index
-                # add timestamp to datafile
-                thisExp.timestampOnFlip(win, 'instruction.stopped')
-                # update status
-                instruction.status = FINISHED
-                instruction.setAutoDraw(False)
-        
-        # *img_reststate* updates
+        # *key_resp* updates
+        waitOnFlip = False
         
-        # if img_reststate is starting this frame...
-        if img_reststate.status == NOT_STARTED and tThisFlip >= 6.5-frameTolerance:
+        # if key_resp is starting this frame...
+        if key_resp.status == NOT_STARTED and tThisFlip >= 2-frameTolerance:
             # keep track of start time/frame for later
-            img_reststate.frameNStart = frameN  # exact frame index
-            img_reststate.tStart = t  # local t and not account for scr refresh
-            img_reststate.tStartRefresh = tThisFlipGlobal  # on global time
-            win.timeOnFlip(img_reststate, 'tStartRefresh')  # time at next scr refresh
+            key_resp.frameNStart = frameN  # exact frame index
+            key_resp.tStart = t  # local t and not account for scr refresh
+            key_resp.tStartRefresh = tThisFlipGlobal  # on global time
+            win.timeOnFlip(key_resp, 'tStartRefresh')  # time at next scr refresh
             # add timestamp to datafile
-            thisExp.timestampOnFlip(win, 'img_reststate.started')
+            thisExp.timestampOnFlip(win, 'key_resp.started')
             # update status
-            img_reststate.status = STARTED
-            img_reststate.setAutoDraw(True)
-        
-        # if img_reststate is active this frame...
-        if img_reststate.status == STARTED:
-            # update params
-            pass
-        
-        # if img_reststate is stopping this frame...
-        if img_reststate.status == STARTED:
-            # is it time to stop? (based on global clock, using actual start)
-            if tThisFlipGlobal > img_reststate.tStartRefresh + 10-frameTolerance:
-                # keep track of stop time/frame for later
-                img_reststate.tStop = t  # not accounting for scr refresh
-                img_reststate.frameNStop = frameN  # exact frame index
-                # add timestamp to datafile
-                thisExp.timestampOnFlip(win, 'img_reststate.stopped')
-                # update status
-                img_reststate.status = FINISHED
-                img_reststate.setAutoDraw(False)
+            key_resp.status = STARTED
+            # keyboard checking is just starting
+            waitOnFlip = True
+            win.callOnFlip(key_resp.clock.reset)  # t=0 on next screen flip
+            win.callOnFlip(key_resp.clearEvents, eventType='keyboard')  # clear events on next screen flip
+        if key_resp.status == STARTED and not waitOnFlip:
+            theseKeys = key_resp.getKeys(keyList=['return'], ignoreKeys=["escape"], waitRelease=False)
+            _key_resp_allKeys.extend(theseKeys)
+            if len(_key_resp_allKeys):
+                key_resp.keys = _key_resp_allKeys[-1].name  # just the last key pressed
+                key_resp.rt = _key_resp_allKeys[-1].rt
+                key_resp.duration = _key_resp_allKeys[-1].duration
+                # a response ends the routine
+                continueRoutine = False
         
         # check for quit (typically the Esc key)
         if defaultKeyboard.getKeys(keyList=["escape"]):
@@ -641,6 +616,14 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
     path = utils.create_data_dir(subject, args.train_id)  # owner_name, train_id
     filename = f"{subject}_{datetime.datetime.now().strftime('%H%M%S')}.bdf"
     receiver.connector.saver.set_edf_header(subject, filename, 5, path)
+    # check responses
+    if key_resp.keys in ['', [], None]:  # No response was made
+        key_resp.keys = None
+    thisExp.addData('key_resp.keys',key_resp.keys)
+    if key_resp.keys != None:  # we had a response
+        thisExp.addData('key_resp.rt', key_resp.rt)
+        thisExp.addData('key_resp.duration', key_resp.duration)
+    thisExp.nextEntry()
     # the Routine "before_mi" was not non-slip safe, so reset the non-slip timer
     routineTimer.reset()
     
@@ -680,7 +663,7 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
         # Run 'Begin Routine' code from initialize_buffer
         decision_buffer = []
         # keep track of which components have finished
-        mi_prepareComponents = [img_prepare]
+        mi_prepareComponents = [text]
         for thisComponent in mi_prepareComponents:
             thisComponent.tStart = None
             thisComponent.tStop = None
@@ -703,38 +686,38 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
             frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
             # update/draw components on each frame
             
-            # *img_prepare* updates
+            # *text* updates
             
-            # if img_prepare is starting this frame...
-            if img_prepare.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
+            # if text is starting this frame...
+            if text.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
                 # keep track of start time/frame for later
-                img_prepare.frameNStart = frameN  # exact frame index
-                img_prepare.tStart = t  # local t and not account for scr refresh
-                img_prepare.tStartRefresh = tThisFlipGlobal  # on global time
-                win.timeOnFlip(img_prepare, 'tStartRefresh')  # time at next scr refresh
+                text.frameNStart = frameN  # exact frame index
+                text.tStart = t  # local t and not account for scr refresh
+                text.tStartRefresh = tThisFlipGlobal  # on global time
+                win.timeOnFlip(text, 'tStartRefresh')  # time at next scr refresh
                 # add timestamp to datafile
-                thisExp.timestampOnFlip(win, 'img_prepare.started')
+                thisExp.timestampOnFlip(win, 'text.started')
                 # update status
-                img_prepare.status = STARTED
-                img_prepare.setAutoDraw(True)
+                text.status = STARTED
+                text.setAutoDraw(True)
             
-            # if img_prepare is active this frame...
-            if img_prepare.status == STARTED:
+            # if text is active this frame...
+            if text.status == STARTED:
                 # update params
                 pass
             
-            # if img_prepare is stopping this frame...
-            if img_prepare.status == STARTED:
+            # if text is stopping this frame...
+            if text.status == STARTED:
                 # is it time to stop? (based on global clock, using actual start)
-                if tThisFlipGlobal > img_prepare.tStartRefresh + 1.5-frameTolerance:
+                if tThisFlipGlobal > text.tStartRefresh + 1.5-frameTolerance:
                     # keep track of stop time/frame for later
-                    img_prepare.tStop = t  # not accounting for scr refresh
-                    img_prepare.frameNStop = frameN  # exact frame index
+                    text.tStop = t  # not accounting for scr refresh
+                    text.frameNStop = frameN  # exact frame index
                     # add timestamp to datafile
-                    thisExp.timestampOnFlip(win, 'img_prepare.stopped')
+                    thisExp.timestampOnFlip(win, 'text.stopped')
                     # update status
-                    img_prepare.status = FINISHED
-                    img_prepare.setAutoDraw(False)
+                    text.status = FINISHED
+                    text.setAutoDraw(False)
             
             # check for quit (typically the Esc key)
             if defaultKeyboard.getKeys(keyList=["escape"]):
@@ -976,6 +959,11 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
         continueRoutine = True
         # update component parameters for each repeat
         thisExp.addData('mi_feedback.started', globalClock.getTime())
+        # Run 'Begin Routine' code from code
+        if feedback_time == 10:
+            feedback.text = '恭喜!'
+        else:
+            feedback.text = '继续努力!'
         # keep track of which components have finished
         mi_feedbackComponents = [feedback]
         for thisComponent in mi_feedbackComponents:

+ 2 - 2
backend/pages/2_train.py

@@ -30,8 +30,8 @@ def _create_train(conn, subjects):
                          "virtual_feedback_rate": float(virtual_feedback_rate),
                          "model_path": model_path.name if model_path is not None else None}
             train_id = train.create_train(conn, train_new)
-            # TODO: pass params through command line
-            os.system(f'python train_1.py --subj {owner_name} --train-id {train_id} --finger-model {finger_model}, --virtual-feedback-rate {virtual_feedback_rate} --model-path {model_path}')
+            # run psychopy process
+            os.system(f'python general_grasp_training.py --subj {owner_name} --train-id {train_id} --finger-model {finger_model}, --virtual-feedback-rate {virtual_feedback_rate} --model-path {model_path}')
             return owner_name
 
 def render():

Some files were not shown because too many files changed in this diff