def initTk(expInfo): ## Data host ## if not os.path.exists(edfDataFolder): os.makedirs(edfDataFolder) dataFileName = (expInfo['Subject'] + '.EDF') tk.openDataFile(dataFileName) # add personalized data file header (preamble text) tk.sendCommand("add_file_preamble_text 'Psychopy Waaaaazzzzzzooooo'") tk.sendMessage('Subject_No %s' % expInfo["Subject"]) ## Init parameters genv = EyeLinkCoreGraphicsPsychoPy(tk, WIN) pylink.openGraphicsEx(genv) print("pylink initiated") # For testing tk.setOfflineMode() tk.sendCommand('sample_rate 500') tk.sendCommand("screen_pixel_coords = 0 0 %d %d" % (scnWIDTH - 1, scnHEIGHT - 1)) tk.sendMessage("DISPLAY_COORDS = 0 0 %d %d" % (scnWIDTH - 1, scnHEIGHT - 1)) #tk.sendCommand("hostVer = HV5") tk.sendCommand("recording_parse_type = GAZE") eyelinkVer = tk.getTrackerVersion() if eyelinkVer >= 2: tk.sendCommand('select_parser_configuration 0') hostVer = 0 if eyelinkVer == 3: tvstr = tk.getTrackerVersionString() vindex = tvstr.find("EYELINK CL") hostVer = int(float(tvstr[(vindex + len("EYELINK CL")):].strip())) tk.sendCommand( "file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON,INPUT" ) tk.sendCommand( "link_event_filter = LEFT,RIGHT,FIXATION,FIXUPDATE,SACCADE,BLINK,BUTTON,INPUT" ) if hostVer >= 4: tk.sendCommand( "file_sample_data = LEFT,RIGHT,GAZE,GAZERES,PUPIL,HREF,AREA,STATUS,HTARGET,INPUT" ) tk.sendCommand( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,PUPIL,HREF,AREA,STATUS,HTARGET,INPUT" ) else: tk.sendCommand( "file_sample_data = LEFT,RIGHT,GAZE,GAZERES,PUPIL,HREF,AREA,STATUS,INPUT" ) tk.sendCommand( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,PUPIL,HREF,AREA,STATUS,INPUT" ) return dataFileName
def block(expInfo, practice, block_number): ################ Block structure (after choosing a card) ################ ##Preparing the next trials if not dummyMode: #if not (dummyMode or practice): present_message("calibration") #waitForKey(variables.ser) tk.doTrackerSetup() #Calibrating the eyetracker core.wait(0.5) # io.clearEvents(device_label='all') #Flushing the buffer. In the final experiment to be replaced by the following line variables.ser.reset_input_buffer() ## Presenting the "remember: the instructions are..." message (according to mapping) if variables.Mapping["KeyYes"] == 'r': present_message("explanation_remember_yes_right") else: present_message("explanation_remember_yes_left") core.wait(0.5) waitForKey(variables.ser) variables.ser.reset_input_buffer() ##Creating a randomized List of questions for one block card_number = (card_input['card_selected']) questionlist = Cards[int( card_number )]["questions_asked"] # Getting the List of questions according to the card selected as defined in the dictionary random.shuffle(questionlist) # Randomizing the list print(card_input['card_selected']) #For testing only ## Setting number of initial trial to 1 trial_number = 1 present_message( "start_ready") # "Einrichtung abgeschlossen. Zum STARTEN: RECHTS" waitForKey(variables.ser) variables.ser.reset_input_buffer() wordlist = [] # flushing wordlist used later for intentionality check blockData = [] # For storing data of ALL trials within the block ##Setting up a trial-counter and a loop for a block of 10 trials while trial_number <= trial_max: '''thr1 = Thread(target=readSer) thr1.daemon = True thr1.start()''' ##Defining the word used in the respective trial from the randomized wordlist word_number = questionlist[int( trial_number - 1 )] # Choosing the 1st, 2nd 3rd... word from the (randomized) list. This variable could also be just the variable "word" used below but I defined an extra variable for more clarity. word = Questions[int( word_number )]["text"] # The translation of the words number into actual text (according to the "Questions" dictionary) wordlist.append(word) # print(word) #for testing only core.wait(0.05) tk.setOfflineMode() pylink.pumpDelay(50) err = tk.startRecording(1, 1, 1, 1) pylink.pumpDelay(50) eyeTracked = tk.eyeAvailable() if eyeTracked == 2: eyeTracked = 1 ##Writing information on the trial into a data dictionary trialData = { "Subject_No": expInfo['Subject'], "BlockNumber": block_number, "TrialNumber": trial_number, "ITIoffset": round(variables.ITI500, 4), "CardNumber": card_number, **variables.Mapping # Adds informations concerning the mapping of the keys for yes/no and the colors of the effects (circles) } trialData.update( trial(word, variables.Mapping["DelayEffectLeft"], variables.Mapping["DelayEffectRight"]) ) # Calling trial function and appending data from this trial to data dictionary. trialData.update( { "ResponseCorrect": checkCorrectness(word_number, card_number, trialData, variables.Mapping) } ) # Checking whether response was correct and appending this information (boolean) to data trialData.update({ "TrueResponseWouldBe": checkTrueResponse(word_number, card_number, variables.Mapping) }) trialData.update({ "DelayEffectLeft": variables.Mapping["DelayEffectLeft"], "DelayEffectRight": variables.Mapping["DelayEffectRight"] }) tk.sendCommand('clear_screen 0') if not practice: #sendBehavData(data) # Writing data to the behaviour-file and sending it (if not in dummy mode) to the eyetracker. blockData.append(trialData) tk.stopRecording() tk.sendMessage('TRIAL_RESULT') pylink.pumpDelay(50) trial_number = trial_number + 1 variables.ser.reset_input_buffer() # flush the input buffer #variables.q.queue.clear() # flushing the queue ## sequence of showing the cards image and asking whether it was the correct one ## present_message("card_image") # Your card was probably: core.wait(4) image_presented = show_cardimage(card_number, block_number) # Present image of card core.wait(5) if variables.Mapping['KeyYes'] == 'r': present_message("card_correct_right") else: present_message("card_correct_left") decision = waitForDecision(variables.ser) ''' ## sequence asking whether there were any unintentional reactions and if so which ## if variables.Mapping['KeyYes'] == 'r': present_message("unintentional_response_right") else: present_message("unintentional_response_left") core.wait(0.7) anyUnintentional = checkMeaning(waitForDecision(variables.ser)) if anyUnintentional == True: #whichUnintentional = "TEST123" # for testing ONLY. Must not be activre oin final experiment whichUnintentional = formUnintentional(wordlist) # Present form asking for which responses were unintentional else: whichUnintentional = "None" ''' whichTrue = formTrue( wordlist) # Present form asking for which responses were unintentional WIN.mouseVisible = False if not practice: for storedTrialData in blockData: storedTrialData.update( { "CardImagePresented": image_presented, "CardImageReportedlyCorrect": checkMeaning(decision), # "AnyUnintentionalReactions": anyUnintentional, "whichUnintentionalReactions(form)": whichTrue[blockData.index(storedTrialData)] } ) # Appending information to data on the presented card image (int) and whether participant evaluated it to be the correct card (boolean) sendBehavData( storedTrialData ) # Writing data to the behaviour-file and sending it (if not in dummy mode) to the eyetracker. #sendBehavData("ENDofBLOCK") print(len(blockData)) # For Testing only
def sendBehavData(data): print( data, file=behaviour ) # prints data to the console and appends it to magic_cards_behaviour.txt if not dummyMode: tk.sendMessage('TRIALID') tk.sendCommand("record_status_message 'Block: %s Trial number: %s'" % (data["BlockNumber"], data["TrialNumber"])) tk.sendMessage('!V TRIAL_VAR CardNumber %s' % data["CardNumber"]) tk.sendMessage('!V TRIAL_VAR TooEarly %s' % data["TooEarly"]) tk.sendMessage('!V TRIAL_VAR TooSlow %s' % data["TooLate"]) tk.sendMessage('!V TRIAL_VAR InTime %s' % data["InTime"]) tk.sendMessage('!V TRIAL_VAR Response %s' % data["Response"]) tk.sendMessage('!V TRIAL_VAR Stimulus %s' % data["Stimulus"]) tk.sendMessage('!V TRIAL_VAR RT %s' % data["RTTime"]) tk.sendMessage('!V TRIAL_VAR Correct %s' % data["ResponseCorrect"]) else: pass
def noButtonTrial(word, delayEffectLeft, delayEffectRight): ## setting variables to their initial values tooEarly = False inTime = False tooLate = False key = "" timestamp_reaction = 0 # to make sure the value from the last trial is not carried over if no reaction in this one timestamp_effect = 0 # to make sure the value from the last trial is not carried over if no reaction in this one button_pressed = False durationFixation = random.uniform( *config_experiment.DURATION_SPAN_FIXATION ) # Determining the random fixation period, within the predifined span ##Presenting the fixation cross present_message("blackscreen") # Blackscreen core.wait(config_experiment.DELAY_INITIAL) variables.io.clearEvents(device_label='all') #Flushing the buffer. tk.sendMessage('Fixation_Onset') effects.cross() # Displaying a fixation cross variables.timer.reset(newT=0.0) timestampFixation = variables.timer.getTime() keyInput = [] while True: #i = i + 1 # for testing only keyboardActivity = variables.io.devices.keyboard.getKeys() if keyboardActivity != []: keyInput = keyboardActivity[0].key if keyInput in ['s', 'l'] and variables.timer.getTime() < ( timestampFixation + durationFixation): tk.sendMessage('tooEarly_Onset') WIN.flip() event.clearEvents() present_message("early") # "Too early" tooEarly = True core.wait(config_experiment.DURATION_MESSAGE_TOOEARLY) tk.sendMessage('tooEarly_Offset') #print(i) # For testing only break if variables.timer.getTime() > (timestampFixation + durationFixation): # q.empty(): event.clearEvents() #print(i) # For testing only tk.sendMessage('Fixation_Offset') break if not tooEarly: target = visual.TextStim( WIN, text=word, pos=[0, 0], alignHoriz='center') # stimulus (i.e. the word) target.draw() variables.io.clearEvents(device_label='all') # Flushing the buffer. core.wait(config_experiment.DELAY_TARGET) #q.queue.clear() # flushing the queue variables.timer.reset(newT=0.0) print(word) # for testing only timestamp_target = variables.timer.getTime() tk.sendMessage('%d TargetOnset' % timestamp_target) WIN.flip() # display the stimulus screenRefreshed = False #i = 0 # for testing only keyInput = [] while True: #i = i + 1 # for testing only keyboardActivity = variables.io.devices.keyboard.getKeys() if keyboardActivity != []: keyInput = keyboardActivity[0].key if screenRefreshed == False and variables.timer.getTime() > ( timestamp_target + config_experiment.DURATION_TARGET ): # q.empty(): # Value to be adjusted for final experiment screenRefreshed = True WIN.flip() tk.sendMessage('Target_Offset') event.clearEvents() #print(i) # For testing only pass if keyInput in ['s', 'l']: # If any button is pressed print("button pressed") # For testing button_pressed = True timestamp_reaction = variables.timer.getTime() tk.sendMessage('Reaction') ##If the reaction is so early that no target-specific reaction can be assumed -> "Too early" if keyInput == 's': key = 'l' core.wait(delayEffectLeft) if keyInput == 'l': key = 'r' core.wait(delayEffectRight) #WIN.flip() timestamp_effect = variables.timer.getTime() tk.sendMessage('Effect_Onset') effects.reaction(key) tk.sendMessage('Effect_Offset') inTime = True print(key) # For testing #print(i) # For testing only inTime = True break ##If there is no response within the given timeframe -> "Too late" if variables.timer.getTime() > ( timestamp_target + config_experiment.TIME_TOOLATE ): #and not button_pressed: # q.empty(): event.clearEvents() present_message("late") # "Too late" tk.sendMessage('tooLate_Onset') tooLate = True core.wait(config_experiment.DURATION_MESSAGE_TOOLATE) tk.sendMessage('tooLate_Offset') #print(i) # For testing only break ### writing the data of the trial into the data dictionary ### trial_data = { "Stimulus": word, "Response": key, "RTTime": round((timestamp_reaction - timestamp_target), 4), "ActionEffectOnsetTime": round(timestamp_effect, 4), "TooEarly": tooEarly, "TooLate": tooLate, "InTime": inTime, "DurationFixation": durationFixation } else: # If tooEarly == True ### writing the data of the trial into the data dictionary ### trial_data = { "Stimulus": word, "Response": key, "RTTime": "none", "ActionEffectOnsetTime": "none", "TooEarly": tooEarly, "TooLate": tooLate, "InTime": inTime, "DurationFixation": durationFixation } return trial_data
def main(): ###################Experiment starting sequence########################### tk.sendMessage('%d ITIoffset' % 0) ## Initializing serial connection to Arduino ## initSer() ## stored in variables.ser print(variables.ser) # For testing ## Basic info dialog, defining participants number, dominant eye & hand, basic demografics ## expInfo = variables.infoBuffer print(expInfo, file=behaviour) ## Initializing Eyetracker ## dataFileName = initTk( expInfo ) # inits the eyetracker and returns the name of the eyetracker-data file ## Initializing randomization of response keys and effect colors ## initMapping( ) # Randomized assignment of effect colors and key for yes/no (stored in variables.RandomMapping) print(variables.Mapping) # For testing print("variable mapping defined") # For testing ################################# Experiment ########################################### if not dummyMode: print("tracker setup started") tk.doTrackerSetup() print("tracker setup done") # for testing #######Wellcoming message####### present_message("welcome") core.wait(0.5) waitForKey(variables.ser) #variables.ser.reset_input_buffer() present_message("welcome_2") core.wait(0.5) waitForKey(variables.ser) #variables.ser.reset_input_buffer() present_message("welcome_3") core.wait(0.5) waitForKey(variables.ser) #variables.ser.reset_input_buffer() present_message("welcome_4") core.wait(0.5) waitForKey(variables.ser) #variables.ser.reset_input_buffer() ###### ##Explanations of what to do present_message("explanation_initial_general") core.wait(0.5) waitForKey(variables.ser) #variables.ser.reset_input_buffer() if variables.Mapping["KeyYes"] == 'r': present_message("explanation_initial_yes_right") else: present_message("explanation_initial_yes_left") core.wait(0.5) waitForKey(variables.ser) #variables.ser.reset_input_buffer() ##important present_message("explanation_initial_important") core.wait(0.5) waitForKey(variables.ser) #variables.ser.reset_input_buffer() ##Explanations of what to do present_message("explanation_initial_procedure") core.wait(0.5) waitForKey(variables.ser) #variables.ser.reset_input_buffer() ##Explanations of what to do present_message("explanation_initial_procedure_2") core.wait(0.5) waitForKey(variables.ser) #variables.ser.reset_input_buffer() ###### ###### Practice ##### ##First some questions for practice present_message("practice") waitForKey(variables.ser) variables.ser.reset_input_buffer() ################ Block Structure ################ ## Setting up a block-counter and a loop of 10 blocks ## block_number = 1 while block_number <= block_max: # Set block_max in the config_experiment file in order to run more or less blocks if block_number == 0: practice = True else: practice = False ## Choosing a (new) card and running a block ## if practice: present_message( "practice_ready" ) # "Please advice the researcher when you are ready" else: present_message( "choose_ready" ) # "Choose a new card and advice the researcher when you are ready" core.wait(0.5) waitForKey(variables.ser) variables.ser.reset_input_buffer() ## Presenting a message about some initialization present_message("initialization") chooseCard( ) # At this point the researcher gives input on the chosen card via the Arduino's numpad block(expInfo, practice, block_number) # Runs a block of 10 trials if practice: present_message("practice_finished") core.wait(0.5) waitForKey(variables.ser) #variables.ser.reset_input_buffer() block_number += 1 # raises the block_number after each block by one ## Receiving data from the eyetracker (if not in dummy mode) ## if not dummyMode: receiveData(dataFileName) else: print( "No eyetracker data received because you are running the experiment in dummy mode" ) ################ Thank you message and end sequence ################ present_message("thanks") core.wait(0.5) waitForKey(variables.ser) event.clearEvents() print("experiment completed", file=behaviour) ############################################################################# # make sure everything is closed down behaviour.close() tk.close() variables.ser.close() WIN.close() core.quit()