オリジナル課題の追加9(レバー)
※レバーモジュールを使わない方はこの章を読む必要はありません。
この章では課題92をさらに改良してタッチパネルではなく、レバーを用いた課題を作成します。
作る課題は左右レバーを提示し、正解レバーを押すと水が貰えるという課題です。正解レバーは右か左に固定され、セッション中に入れ替わりません。
ではまず初めに
7章と同じやり方で課題93の課題ボタンを作り、その後課題92のコードをコピーして課題93として追加してください。
def Task93(): # Test task 4
global Phase
Phase0_Init = 0
Phase1_Init = 0
Phase2_Init = 0
while EndFlag == 0:
OperantHouseUpdate() # Run house keeping function (This must be executed once per frame)
if GetBackButtonStat()==1: # If "Back" button is clicked
break # Back to the task select phase
if Phase == 0: # Parameter inputs
if Phase0_Init == 0: # Make GUI for the setting of the parameters for this task
RemoveMainRightWidget() # Remove task buttons
PutStartBackButton() # Put "start" and "back" buttons
ColumnWidth = 14 # Width of input columns
Row = 0
Column = 0
mMaxCorrectNum = ttk.Label(MainWindowRightFrame, text='MaxCorrectNum', width=ColumnWidth).grid(row=Row,column=Column, sticky=W) # Put label
MaxCorrectNumVar = IntVar(MainWindowRoot) # Declare a variable for input column
iMaxCorrectNum = ttk.Entry(MainWindowRightFrame, textvariable=MaxCorrectNumVar, width=ColumnWidth).grid(row=Row + 1, column=Column) # Create input column and link it with the variable
Column += 1
mMaxTrialNum = ttk.Label(MainWindowRightFrame, text='MaxTrialNum', width=ColumnWidth).grid(row=Row, column=Column, sticky=W)
MaxTrialNumVar = IntVar(MainWindowRoot) # Declare a variable for input column
iMaxTrialNum = ttk.Entry(MainWindowRightFrame, textvariable=MaxTrialNumVar, width=ColumnWidth).grid(row=Row + 1,column=Column)
Column += 1
mTimeLimit = ttk.Label(MainWindowRightFrame, text='TimeLimit(min)', width=ColumnWidth).grid(row=Row, column=Column, sticky=W)
TimeLimitVar = IntVar(MainWindowRoot)
iTimeLimit = ttk.Entry(MainWindowRightFrame, textvariable=TimeLimitVar, width=ColumnWidth).grid(row=Row + 1,column=Column)
Column += 1
mPunishDur = ttk.Label(MainWindowRightFrame, text='PunishDur(s)', width=ColumnWidth).grid(row=Row, column=Column, sticky=W)
PunishDurVar = IntVar(MainWindowRoot)
iPunishDur = ttk.Entry(MainWindowRightFrame, textvariable=PunishDurVar, width=ColumnWidth).grid(row=Row + 1,column=Column)
Column += 1
mLickDur = ttk.Label(MainWindowRightFrame, text='LickDur(s)', width=ColumnWidth).grid(row=Row, column=Column,sticky=W)
LickDurVar = IntVar(MainWindowRoot)
iLickDur = ttk.Entry(MainWindowRightFrame, textvariable=LickDurVar, width=ColumnWidth).grid(row=Row + 1, column=Column)
Column += 1
mNextTask = ttk.Label(MainWindowRightFrame, text='NextTask#', width=ColumnWidth).grid(row=Row, column=Column,sticky=W) # The task number indicated here will be the next task if the correct rate exceeds "NextTaskTh"
NextTaskVar = IntVar(MainWindowRoot)
iNextTask = ttk.Entry(MainWindowRightFrame, textvariable=NextTaskVar, width=ColumnWidth).grid(row=Row + 1, column=Column)
Column += 1
mNextTaskTh = ttk.Label(MainWindowRightFrame, text='NextTaskTh%', width=ColumnWidth).grid(row=Row, column=Column, sticky=W) # Correct rate threshold to switch to the next task
NextTaskThVar = IntVar(MainWindowRoot)
iNextTaskTh = ttk.Entry(MainWindowRightFrame, textvariable=NextTaskThVar, width=ColumnWidth).grid(row=Row + 1,column=Column)
Row += 2 # Begin a new line
Column = 0
mPanelType = ttk.Label(MainWindowRightFrame, text='PanelType', width=ColumnWidth).grid(row=Row, column=Column,sticky=W) # Type of panel, Normal: white rectangle panel, Blink: white rectangle bilnking panel, Textured: User custom image (Canbe upload at "MainWindow -> Setting -> Panel* texture")
PanelTypeVar = StringVar(MainWindowRightFrame)
tPanelType = OptionMenu(MainWindowRightFrame, PanelTypeVar, "Normal", "Blink", "Textured").grid(row=Row + 1,column=Column, sticky=W)
mCorrectPos = ttk.Label(MainWindowRightFrame, text='CorrectPos', width=ColumnWidth).grid(row=Row, column=Column, sticky=W) # Position of correct lever
CorrectPosVar = StringVar(MainWindowRightFrame)
tCorrectPos = OptionMenu(MainWindowRightFrame, CorrectPosVar, "Left", "Right").grid(row=Row + 1, column=Column, sticky=W)
左右レバーのどちらが正解か、課題パラメータとして指定できるよう選択欄を作ります。
Column += 1
mWaterCueType = ttk.Label(MainWindowRightFrame, text='WaterCueType', width=ColumnWidth).grid(row=Row, column=Column, sticky=W) # If chose blink, reward cue will blink
WaterCueTypeVar = StringVar(MainWindowRightFrame)
tWaterCueType = OptionMenu(MainWindowRightFrame, WaterCueTypeVar, "Normal", "Blink").grid(row=Row + 1, column=Column, sticky=W)
Column += 1
mAwsOn = ttk.Label(MainWindowRightFrame, text='AWS', width=ColumnWidth).grid(row=Row, column=Column, sticky=W) # If ON, complemental water supply is applied after end of each session
AwsOnVar = StringVar(MainWindowRoot)
tAwsOn = OptionMenu(MainWindowRightFrame, AwsOnVar, "ON", "OFF").grid(row=Row + 1, column=Column, sticky=W)
Str = "ParametersForTask" + str(GetTaskID())
if os.path.exists(Str + '/MaxCorrectNum.dat') == True: # If save file named "MaxCorrectNum.dat" exist:
with open(Str + '/MaxCorrectNum.dat', 'rb') as PickleInst[GetTaskID()]:
MaxCorrectNumVar.set(pickle.load(PickleInst[GetTaskID()])) # Substitute loaded data into the variable of thisprogram
else: # If save file doesn't exist
MaxCorrectNumVar.set(80) # Substitute 80 into the variable
if os.path.exists(Str + '/MaxTrialNum.dat') == True:
with open(Str + '/MaxTrialNum.dat', 'rb') as PickleInst[GetTaskID()]:
MaxTrialNumVar.set(pickle.load(PickleInst[GetTaskID()]))
else:
MaxTrialNumVar.set(110)
if os.path.exists(Str + '/TimeLimit.dat') == True:
with open(Str + '/TimeLimit.dat', 'rb') as PickleInst[GetTaskID()]:
TimeLimitVar.set(pickle.load(PickleInst[GetTaskID()]))
else:
TimeLimitVar.set(600)
if os.path.exists(Str + '/PunishDur.dat') == True:
with open(Str + '/PunishDur.dat', 'rb') as PickleInst[GetTaskID()]:
PunishDurVar.set(pickle.load(PickleInst[GetTaskID()]))
else:
PunishDurVar.set(10)
if os.path.exists(Str + '/LickDur.dat') == True:
with open(Str + '/LickDur.dat', 'rb') as PickleInst[GetTaskID()]:
LickDurVar.set(pickle.load(PickleInst[GetTaskID()]))
else:
LickDurVar.set(2)
if os.path.exists(Str + '/NextTask.dat') == True:
with open(Str + '/NextTask.dat', 'rb') as PickleInst[GetTaskID()]:
NextTaskVar.set(pickle.load(PickleInst[GetTaskID()])) # Load
else:
NextTaskVar.set(93) # Default value
if os.path.exists(Str + '/NextTaskTh.dat') == True:
with open(Str + '/NextTaskTh.dat', 'rb') as PickleInst[GetTaskID()]:
NextTaskThVar.set(pickle.load(PickleInst[GetTaskID()])) # Load
else:
NextTaskThVar.set(80) # Default value
if os.path.exists(Str + '/PanelType.dat') == True:
with open(Str + '/PanelType.dat', 'rb') as PickleInst[GetTaskID()]:
PanelTypeVar.set(pickle.load(PickleInst[GetTaskID()])) # Load
else:
PanelTypeVar.set('Blink') # Default value
if os.path.exists(Str + '/CorrectPos.dat') == True:
with open(Str + '/CorrectPos.dat', 'rb') as PickleInst[GetTaskID()]:
CorrectPosVar.set(pickle.load(PickleInst[GetTaskID()])) # Load
else:
CorrectPosVar.set('Left') # Default value
if os.path.exists(Str + '/WaterCueType.dat') == True:
with open(Str + '/WaterCueType.dat', 'rb') as PickleInst[GetTaskID()]:
WaterCueTypeVar.set(pickle.load(PickleInst[GetTaskID()])) # Load
else:
WaterCueTypeVar.set('Blink') # Default value
if os.path.exists(Str + '/AwsOn.dat') == True:
with open(Str + '/AwsOn.dat', 'rb') as PickleInst[GetTaskID()]:
AwsOnVar.set(pickle.load(PickleInst[GetTaskID()])) # Load
else:
AwsOnVar.set('ON') # Default value
PutRoiGui(0, 1, 1, 0) # Put setting GUI of the indicated ROI on ROI window (ROI number, Detection mode, Thresholddirection, ShowSymbol or not)
PutRoiGui(1, 1, 1, 0)
タッチパネルは使わないのでタッチ検出に使用していたROIを削除します。
PutRoiGui(19, 0, 0, 1) # Put setting GUI of the indicated ROI on ROI window (ROI number, Detection mode, Thresholddirection, ShowSymbol or not)
RemoveAllDigitalOutGui() # Remove all GUIs on the Digital out window
PutDigitalOutGui(10) # Put the digital output GUI for channel 10 on Digital ouput window
PutDigitalOutGui(12)
PutDigitalOutGui(13)
DigitalInOn(7) # Set the indicated channel as Digital input channel (Receive input from the lever module)
DigitalInOn(8)
レバープレスはDigital input - ground間の通電という形で検出するので、digital I/OのCh7,8を入力モードにします。
RemoveAllServoGui() # Remove all GUI on the Servo GUI
PutServoGui(3) # Put a servo GUI for channel 3 on the Servo GUI
PutServoGui(5)
PutServoGui(6)
レバーモジュールを出し入れするサーボのGUIをServoGUIウィンドウに追加します。
Phase0_Init = 1 # Set a flag which indicating phase0 initialization has done
if GetSaveTrgStat() == 1: # If save trigger is activated
# Parameters will be saved into a folder named "ParametersForTask90"
Str="ParametersForTask"+str(GetTaskID()) # Substitute save folder path
if os.path.exists(Str) == False: # If save folder doesn't exist
os.mkdir(Str) # Create the folder
with open(Str+'/MaxCorrectNum.dat', 'wb') as PickleInst[GetTaskID()]:
pickle.dump(MaxCorrectNumVar.get(),PickleInst[GetTaskID()]) # Save a value of "MaxCorrectNumVar" as "MaxCorrectNum.dat" file
with open(Str+'/MaxTrialNum.dat', 'wb') as PickleInst[GetTaskID()]:
pickle.dump(MaxTrialNumVar.get(),PickleInst[GetTaskID()])
with open(Str+'/TimeLimit.dat', 'wb') as PickleInst[GetTaskID()]:
pickle.dump(TimeLimitVar.get(),PickleInst[GetTaskID()])
with open(Str+'/PunishDur.dat', 'wb') as PickleInst[GetTaskID()]:
pickle.dump(PunishDurVar.get(), PickleInst[GetTaskID()])
with open(Str+'/LickDur.dat', 'wb') as PickleInst[GetTaskID()]:
pickle.dump(LickDurVar.get(), PickleInst[GetTaskID()])
with open(Str + '/NextTask.dat', 'wb') as PickleInst[GetTaskID()]:
pickle.dump(NextTaskVar.get(), PickleInst[GetTaskID()])
with open(Str+'/NextTaskTh.dat', 'wb') as PickleInst[GetTaskID()]:
pickle.dump(NextTaskThVar.get(), PickleInst[GetTaskID()])
with open(Str+'/PanelType.dat', 'wb') as PickleInst[GetTaskID()]:
pickle.dump(PanelTypeVar.get(), PickleInst[GetTaskID()])
with open(Str+'/CorrectPos.dat', 'wb') as PickleInst[GetTaskID()]:
pickle.dump(CorrectPosVar.get(), PickleInst[GetTaskID()])
with open(Str+'/WaterCueType.dat', 'wb') as PickleInst[GetTaskID()]:
pickle.dump(WaterCueTypeVar.get(), PickleInst[GetTaskID()])
with open(Str+'/AwsOn.dat', 'wb') as PickleInst[GetTaskID()]:
pickle.dump(AwsOnVar.get(), PickleInst[GetTaskID()])
if Phase == 1: # Waiting phase (Task will start when the set time arrives)
if Phase1_Init == 0: # If the initialization for phase1 has not done
PutPreTaskButton() # Put "StartNow" and "Back" button on Main window
mStatusVar = StringVar(MainWindowRoot) # Create a variable for status display
mStatus = ttk.Label(MainWindowRightFrame, textvariable=mStatusVar) # Create label object and link it with Mainwindow
mStatus.place(x=10, y=0) # Place label object on the Main window
mOngoingResultVar = StringVar(MainWindowRoot) # Create a variable for progress display
Phase1_Init = 1 # Flat that phase1 has done
mStatusVar.set('Test4 task(' + str(GetTaskID()) + ') Waiting...') # Show current status of the Operant House
if IsStartTime() == 1: # Check whether task start time arrives
StartNow() # Start task (Phase number will be "2")
if Phase == 2: # If it is during task
if Phase2_Init == 0: # Initialization of the task
PutEndTaskNowButton() # Put "TaskEnd" button on Main window
mStatusVar.set('Test4 task(' + str(GetTaskID()) + ') Start time ' + str(TaskStartedMonth) + '/' + str(TaskStartedDay)+ ' ' + str(TaskStartedHour) + ':' + str(TaskStartedMinute) + ' Running') # Substitute latest information about current task into"mStatusVar"
mOngoingResult = ttk.Label(MainWindowRightFrame, textvariable=mOngoingResultVar)
mOngoingResult.place(x=10, y=18)
# Substitute task parameter values in StringVars into integer or string variable (to make the cord easeir to read)
MaxCorrectNum = int(MaxCorrectNumVar.get()) # Get the value of "MaxCorrectNumVar" and convert it from stringto integer and substitute into variable named "MaxCorrectNum"
MaxTrialNum = int(MaxTrialNumVar.get())
TimeLimit = int(TimeLimitVar.get())
PunishDur = int(PunishDurVar.get())
LickDur = int(LickDurVar.get())
NextTask = int(NextTaskVar.get())
NextTaskTh = int(NextTaskThVar.get())
PanelType = PanelTypeVar.get()
CorrectPos = CorrectPosVar.get()
WaterCueType = WaterCueTypeVar.get()
AwsOn = AwsOnVar.get()
# Declar local variables for this task
TrialNum = 0 # Current trial number
CorrectNum = 0 # Current correct trial number
IncorrectNum = 0 # Current incorrect trial number
CorrectRate = 0.0 # Current correct rate
TaskDur = 0 # This will keep the elapsed time during of task
NowDrinking = 0 # Use as trigger
CorrectPanelID = 0 # ID number of current correct panel (0 or 1)
AWS_Latency = 20 # Latency to start AWS (sec)
StartRecording() # Start camera capture / TTL signal output
StartLickRecording() # Start an entry of lick log
LightCycleControlOff() # Deactivate automatic Light/Dark cycle illumination
RoofLightOff() # Turn off the lights on roof (Digital output Ch13)
InfraredLightOn() # Turn on the infrared LED illumination (Digital output Ch12)
if WaterCueType == 'Normal':
DigitalOutOn(10) # Turn on cue LED connected to Ch10
if WaterCueType == 'Blink':
DigitalOutBlinkOn(10) # Start blinking of cue LED connected to Ch10
ServoPosInside(3) # Change the angle of water arm servo connected to Ch3 to inside position
if PanelType == 'Normal':
CreateNormalPanel(0) # Create a white-filled square panel as panel #0
CreateNormalPanel(1)
if PanelType == 'Blink':
CreateBlinkPanel(0) # Create a white-filled square blinking panel #0
CreateBlinkPanel(1)
if PanelType == 'Textured':
CreateTexturedPanel(0,0) # Create a user uploaded image panel #0
CreateTexturedPanel(1,0)
タッチパネル関連の変数は皆削除します。
Writer_TouchEventTxt = open(Path + "/" + str(TimeNow.year) + "_" + str(TimeNow.month) + "_" + str(TimeNow.day) +" " + str(TimeNow.hour) + "h" + str(TimeNow.minute) + "m Task" + str(GetTaskID()) + " Touch.txt", 'w') # Initialize the textexporter for a result file
Writer_TouchEventTxt.write('TrialNum\tResult\t\t\tyyyy/mm/dd\th:m\ts\n') # Write item name on the result file
Writer_TouchEventCsv = open(Path + "/" + str(TimeNow.year) + "_" + str(TimeNow.month) + "_" + str(TimeNow.day) +" " + str(TimeNow.hour) + "h" + str(TimeNow.minute) + "m Task" + str(GetTaskID()) + " Touch.csv", 'w')
print("Task #" + str(GetTaskID()) + " is started at " + str(GetTaskStartedMonth()) + '/' + str(GetTaskStartedDay()) + ' '+ str(GetTaskStartedHour()) + ':' + str(GetTaskStartedMinute()) + ':' + str(GetTaskStartedSecond())) # Enter the start time in theconsole window of Pycharm
Timer_Start(5) # Start a timer #5 to measure the duration of the task
Phase2 = 2 # Start task from the reward phase
Phase2_Init = 1 # Flag indicating that initialization of Phase2 has done
if Phase2 == 0: # Initiation of new trial
TaskDur = Timer_GetSec(5)
CorrectPanelID = int(random.random()*2) # Determine which panel will be assigned as "correct"
print('CorrectPanelID: ' + str(CorrectPanelID))
ShowPanel(CorrectPanelID) # Display panel #0
ServoPosInside(5) # Insert the indicated lever
ServoPosInside(6)
試行開始時に左右のレバーを挿入します。
Phase2 = 1
if Phase2 == 1: # Lever choice
TouchedPanelID = DetectRoiNosepoke() # Examine which panel is touched (return panel ID. If none of the panelstouched, return -1)
if TouchedPanelID != -1 and TouchedPanelID != 19: # If mouse touches the panel
TrialNum += 1
if TouchedPanelID == CorrectPanelID: # If touched panel is assigned as correct
LeftLeverStat = DetectLeverPress(7) # Return 1 if current in digital input Ch7 is detected (Check input from left lever)
RightLeverStat = DetectLeverPress(8) # Return 1 if current in digital input Ch8 is detected (Check input from rightlever)
#TouchedPanelID = DetectRoiNosepoke() # Examine which panel is touched (return panel ID. If none of the panelstouched, return -1)
if LeftLeverStat==1 or RightLeverStat==1: # If mouse touches the panel
TrialNum += 1
if CorrectPos=="Left" and LeftLeverStat==1 or CorrectPos=="Right" and RightLeverStat==1: # If touchedcorrect lever
ServoPosInside(3) # Move the water nozzle into inside position
if WaterCueType == 'Normal':
DigitalOutOn(10) # Turn on cue LED connected to Ch10
if WaterCueType == 'Blink':
DigitalOutBlinkOn(10) # Start blinking of cue LED connected to Ch10
HidePanel(0) # Turn off panel #0
HidePanel(1) # Turn off panel #1
ServoPosOutside(5) # Pull the indicated lever back
ServoPosOutside(6)
NowDrinking = 0
CorrectNum += 1 # Increase the number of correct response
Writer_TouchEventTxt.write(str(TrialNum)+'\tLeverPressed(Correct)\t'+ str(TimeNow.year)+"/"+str(TimeNow.month)+"/"+str(TimeNow.day)+"\t"+str(TimeNow.hour)+":"+str(TimeNow.minute)+"\t"+str(TimeNow.second)+"."+str(TimeNow.microsecond//1000)+"\n") # Write the response on the text file
Writer_TouchEventCsv.write(str(TrialNum) + ',1,' + str(TimeNow.year) + "," + str(TimeNow.month) + "," + str(TimeNow.day) + "," + str(TimeNow.hour) + "," + str(TimeNow.minute) + "," + str(TimeNow.second) + "." + str(TimeNow.microsecond//1000)+"\n") # Write the response on the csv file
Phase2 = 2 # Start reward phase
if TouchedPanelID != CorrectPanelID: # If touched panel is assigned as incorrect
if CorrectPos=="Left" and RightLeverStat==1 or CorrectPos=="Right" and LeftLeverStat==1: # If touchedincorrect lever
ServoPosOutside(3) # Move the water nozzle into inside position
HidePanel(0)
HidePanel(1)
ServoPosOutside(5) # Pull the indicated lever back
ServoPosOutside(6)
レバーの状態はDetectLeverPress()で取得できます。それを変数で保持し押されたレバーが正解か否か判断します。またレバーが押されると両レバーは引っ込みます。
RoofLightOn() # Turn on the ceiling illumination
IncorrectNum += 1 # Increase the number of correct response
Writer_TouchEventTxt.write(str(TrialNum)+'\tLeverPressed(Incorrect)\t'+ str(TimeNow.year)+"/"+str(TimeNow.month)+"/"+str(TimeNow.day)+"\t"+str(TimeNow.hour)+":"+str(TimeNow.minute)+"\t"+str(TimeNow.second)+"."+str(TimeNow.microsecond//1000)+"\n") # Write the response on the text file
Writer_TouchEventCsv.write(str(TrialNum) + ',2,' + str(TimeNow.year) + "," + str(TimeNow.month) + "," + str(TimeNow.day) + "," + str(TimeNow.hour) + "," + str(TimeNow.minute) + "," + str(TimeNow.second) + "." + str(TimeNow.microsecond//1000)+"\n") # Write the response on the csv file
Timer_Start(0) # Start punishment timer
Phase2 = 3 # Start punish phase
mOngoingResultVar.set('CorrectNum: ' + str(CorrectNum) + ' IncorrectNum: ' + str(IncorrectNum) + ' TrialNum: ' +str(TrialNum))
if Timer_GetSec(5) >= TimeLimit * 60: # If time limit of the task comes
TaskDur = Timer_GetSec(5)
print("Time limit elapsed")
Timer_End(5) # Stop the timer
Phase2 = 5
if Phase2 == 2: # Reward phase
if DetectRoiNosepoke() == 19 and NowDrinking == 0: # If the mouse initiates nose poking
NowDrinking = 1
Timer_Start(0) # Start lick timer
if NowDrinking == 1: # If the nose poke has begun
if Timer_GetSec(0) >= LickDur: # If the nosepoke duration exceeds the lick duration
Timer_End(0) # End timer for measuring lick duration
ServoPosMiddle(3) # Move water nozzle back to the middle position
DigitalOutOff(10) # Turn off the cue LED
NowDrinking = 0
Phase2 = 4 # Go to After trial phase
if Phase2 == 3: # Punishment phase
if Timer_GetSec(0) >= PunishDur: # If punishment time is passed
Timer_End(0) # End punishment timer1
RoofLightOff()
ServoPosMiddle(3) # Move water nozzle to the intermediate position
Phase2 = 4 # Go to After trial phase
if Phase2 == 4: # After trial phase
if CorrectNum < MaxCorrectNum and TrialNum < MaxTrialNum: # If the touch number doesn't exceed the maximumnumber
Phase2 = 0
if CorrectNum >= MaxCorrectNum or TrialNum >= MaxTrialNum: # If the touch number exceeds the maximum number
TaskDur = Timer_GetSec(5) # Keep the task time
Phase2 = 5
if Phase2 == 5:
HideAllPanel()
ServoPosOutside(5) # Pull the indicated lever back
ServoPosOutside(6)
セッションが終了したので両レバーは引き込ませます。
if CorrectNum < MaxCorrectNum and AwsOn == 'ON': # If mouse didn't achieved the max correct response
Timer_Start(0)
Phase2 = 6
if CorrectNum == MaxCorrectNum or AwsOn == 'OFF': # If mouse achieved the max correct response
Phase2 = -1
if Phase2 == 6: # Wait until complemental water supply is started
if Timer_GetSec(0) >= AWS_Latency: # If it past indicated latency to start complemental water supply
Timer_End(0)
ArbitaryWaterSupplyDur = (MaxCorrectNum - CorrectNum) * LickDur * 1000 # Calculate the duration ofcomplemental water supply
if WaterCueType == 'Normal':
StartArbitaryWaterSupply(3, 10, 0, ArbitaryWaterSupplyDur) # Start complemental water supply
if WaterCueType == 'Blink':
StartArbitaryWaterSupply(3, 10, 1, ArbitaryWaterSupplyDur)
print("Arbitrary water supply start")
Phase2 = 7 # Start AWS
if Phase2 == 7: # Keep checking until complemental water supply is finished
if GetArbitaryWaterSupplyStat() == 1: # If the complemental water supply is finished
Phase2 = -1
if Phase2 == -1 or GetEndTaskNowButtonStat() == 1: # If the flag is set to finish the task
LightCycleControlOn() # Activate automatic light/dark cycle
ServoPosMiddle(3) # Moze servo nozzle into middle position
DeleteAllPanel() # Remove a panel on touch screen
ServoPosOutside(5) # Pull the indicated lever back
ServoPosOutside(6)
"EndTask"ボタンでセッションを終了させた場合に備えて、ここにもレバー引き込みコマンドを入れておきます。
InfraredLightOff() # Turn off the infrared LED
if GetRecordingStat() == 1: # If camera is capturing
SetEndRecordingTimer(60) # Onset a timer to finish video recording after 60 frames (correspond about 2sec)from now
# Add summary of results into the result file
if CorrectNum > 0 or IncorrectNum > 0:
CorrectRate = int(CorrectNum * 100.0 / TrialNum)
Writer_TouchEventTxt.write('TotalNum:' + str(TrialNum) + ' CorrectNum:' + str(CorrectNum) + ' IncorrectNum:' + str(IncorrectNum) + ' CorrectRate:' + str(CorrectRate) + '%\n')
Writer_TouchEventTxt.write('SessionStartTime: ' + str(GetTaskStartedMonth()) + '/' + str(GetTaskStartedDay()) + ' ' +str(GetTaskStartedHour()) + ':' + str(GetTaskStartedMinute()) + ':' + str(GetTaskStartedSecond()) + "\n")
Writer_TouchEventTxt.write('SessionEndTime: ' + str(TimeNow.month) + '/' + str(TimeNow.day) + ' ' + str(TimeNow.hour) + ':' + str(TimeNow.minute) + ':' + str(TimeNow.second + (TimeNow.microsecond // 1000) / 1000) + "\n")
Writer_TouchEventTxt.write('TaskDuration(sec): ' + str(TaskDur) + "\n")
# Add experimental conditions into the result file
Writer_TouchEventTxt.write('MaxCorrectNum: '+str(MaxCorrectNum)+"\n")
Writer_TouchEventTxt.write('MaxTrialNum: ' + str(MaxTrialNum) + "\n")
Writer_TouchEventTxt.write('TimeLimit: ' + str(TimeLimit) + "\n")
Writer_TouchEventTxt.write('PunishDur: ' + str(TimeLimit) + "\n")
Writer_TouchEventTxt.write('LickDur: ' + str(LickDur)+"\n")
Writer_TouchEventTxt.write('NextTask: ' + str(NextTask) + "\n")
Writer_TouchEventTxt.write('NextTaskTh: ' + str(NextTaskTh) + "\n")
Writer_TouchEventTxt.write('PanelType: ' + str(PanelType) + "\n")
Writer_TouchEventTxt.write('CorrectPos: ' + CorrectPos + "\n")
Writer_TouchEventTxt.write('WaterCueType: ' + WaterCueType + "\n")
Writer_TouchEventTxt.write('AwsOn: ' + AwsOn + "\n")
Writer_TouchEventTxt.write('RecordFPS: ' + str(GetRecordFps()) + "\n") # Recorded frame number per second
Writer_TouchEventTxt.write(GetRoiSensitivity() + "\n") # Settings of each ROI
Writer_TouchEventTxt.write(GetServoAngle() + "\n") # Set angles of each servo
Writer_TouchEventTxt.close() # Close the text exporter for the result file
Writer_TouchEventCsv.close()
EndLickRecording() # End lick log recording
SendMail(DeviceNameVar.get()+' finished task '+str(GetTaskID())+'. TrialNum:'+str(TrialNum)+' Correct:'+str(CorrectNum)+' Incorrect:'+str(IncorrectNum)+' Rate:'+str(CorrectRate)+'% Dur:'+str(round(Timer_GetSec(5) / 60,1))+' min','Thetask is finished.') # Send a email (correct number and task duration are added to email title)
if IsHousingAnalysis == 1 and Phase2 == -1: # If it is housing analysis
if CorrectRate >= NextTaskTh: # If the score exceed the criteria to switch to the next task
SwitchTask(NextTask) # Onset the task switching trigger
print("Task was switched to task#" + str(NextTask) + " " + str(GetTaskStartedMonth()) + '/' + str(GetTaskStartedDay()) + ' ' + str(GetTaskStartedHour()) + ':' + str(GetTaskStartedMinute()) + ':' + str(GetTaskStartedSecond()))
if IsHousingAnalysis == 0:
RoofLightOn()
Phase = 1 # Go back to the task-waiting phase
Phase2 = 0
Phase2_Init = 0
SetDispVariable(0, 'Phase2', str(Phase2)) # Display "Phase2" value on the bottom of main window
return
これで完了です。
課題を実行してみてちゃんと動くか試してみて下さい。
なお、論文にも書いていますが、レバープレスのshaping初日にマウスの動ける範囲をレバー付近に限局すると飼育解析であるか否かに関わらず早くshapingが完了します。