Skip to content

Commit c84c302

Browse files
committed
Add emulator support
- Add Emulator object that emulates bpod hardware behavior and reference it in the BpodBase class - Modify bpod classes to accommodate emulator functionality - Add emulator examples to showcase its usage
1 parent 4c9ced5 commit c84c302

36 files changed

Lines changed: 2403 additions & 196 deletions
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from pybpodapi.protocol import Bpod, StateMachine
2+
my_bpod = Bpod(emulator_mode=True)
3+
sma = StateMachine(my_bpod)
4+
sma.add_state(
5+
state_name='State1',
6+
state_timer=1,
7+
state_change_conditions={Bpod.Events.Tup: 'State2'},
8+
output_actions=[])
9+
sma.add_state(
10+
state_name='State2',
11+
state_timer=1,
12+
state_change_conditions={Bpod.Events.Tup: 'State3'},
13+
output_actions=[])
14+
sma.add_state(
15+
state_name='State3',
16+
state_timer=1,
17+
state_change_conditions={Bpod.Events.Tup: 'State4'},
18+
output_actions=[])
19+
sma.add_state(
20+
state_name='State4',
21+
state_timer=1,
22+
state_change_conditions={Bpod.Events.Tup: 'State5'},
23+
output_actions=[])
24+
sma.add_state(
25+
state_name='State5',
26+
state_timer=1,
27+
state_change_conditions={Bpod.Events.Tup: 'State6'},
28+
output_actions=[])
29+
sma.add_state(
30+
state_name='State6',
31+
state_timer=1,
32+
state_change_conditions={Bpod.Events.Tup: 'State7'},
33+
output_actions=[])
34+
sma.add_state(
35+
state_name='State7',
36+
state_timer=1,
37+
state_change_conditions={Bpod.Events.Tup: 'State8'},
38+
output_actions=[])
39+
sma.add_state(
40+
state_name='State8',
41+
state_timer=1,
42+
state_change_conditions={Bpod.Events.Tup: 'State9'},
43+
output_actions=[])
44+
sma.add_state(
45+
state_name='State9',
46+
state_timer=1,
47+
state_change_conditions={Bpod.Events.Tup: 'State10'},
48+
output_actions=[])
49+
sma.add_state(
50+
state_name='State10',
51+
state_timer=1,
52+
state_change_conditions={Bpod.Events.Tup: 'exit'},
53+
output_actions=[])
54+
my_bpod.send_state_machine(sma)
55+
my_bpod.run_state_machine(sma)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from pybpodapi.protocol import Bpod, StateMachine
2+
my_bpod = Bpod(emulator_mode=True)
3+
sma = StateMachine(my_bpod)
4+
sma.add_state(
5+
state_name='State1',
6+
state_timer=1,
7+
state_change_conditions={Bpod.Events.Tup: 'State2'},
8+
output_actions=[])
9+
sma.add_state(
10+
state_name='State2',
11+
state_timer=1,
12+
state_change_conditions={Bpod.Events.Tup: 'State3'},
13+
output_actions=[])
14+
sma.add_state(
15+
state_name='State3',
16+
state_timer=1,
17+
state_change_conditions={Bpod.Events.Tup: 'State4'},
18+
output_actions=[])
19+
sma.add_state(
20+
state_name='State4',
21+
state_timer=1,
22+
state_change_conditions={Bpod.Events.Tup: 'State5'},
23+
output_actions=[])
24+
sma.add_state(
25+
state_name='State5',
26+
state_timer=1,
27+
state_change_conditions={Bpod.Events.Tup: 'State6'},
28+
output_actions=[])
29+
sma.add_state(
30+
state_name='State6',
31+
state_timer=1,
32+
state_change_conditions={Bpod.Events.Tup: 'State7'},
33+
output_actions=[])
34+
sma.add_state(
35+
state_name='State7',
36+
state_timer=1,
37+
state_change_conditions={Bpod.Events.Tup: 'State8'},
38+
output_actions=[])
39+
sma.add_state(
40+
state_name='State8',
41+
state_timer=1,
42+
state_change_conditions={Bpod.Events.Tup: 'State9'},
43+
output_actions=[])
44+
sma.add_state(
45+
state_name='State9',
46+
state_timer=1,
47+
state_change_conditions={Bpod.Events.Tup: 'State10'},
48+
output_actions=[])
49+
sma.add_state(
50+
state_name='State10',
51+
state_timer=1,
52+
state_change_conditions={Bpod.Events.GlobalTimer1_Start: 'exit'},
53+
output_actions=[])
54+
my_bpod.send_state_machine(sma)
55+
my_bpod.run_state_machine(sma)
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from pybpodapi.protocol import Bpod, StateMachine
2+
my_bpod = Bpod(emulator_mode=True)
3+
sma = StateMachine(my_bpod)
4+
# Set global timer 1 for 3 seconds, following a 1.5 second onset delay after
5+
# trigger. Link to LED of port 2.
6+
sma.set_global_timer(timer_id=1, timer_duration=0, on_set_delay=1.5,
7+
channel=Bpod.OutputChannels.PWM2, on_message=255)
8+
sma.add_state(
9+
state_name='State1',
10+
state_timer=1,
11+
state_change_conditions={Bpod.Events.Tup: 'State2'},
12+
output_actions=[])
13+
sma.add_state(
14+
state_name='State2',
15+
state_timer=1,
16+
state_change_conditions={Bpod.Events.Tup: 'State3'},
17+
output_actions=[])
18+
sma.add_state(
19+
state_name='State3',
20+
state_timer=1,
21+
state_change_conditions={Bpod.Events.Tup: 'State4'},
22+
output_actions=[])
23+
sma.add_state(
24+
state_name='State4',
25+
state_timer=1,
26+
state_change_conditions={Bpod.Events.Tup: 'State5'},
27+
output_actions=[])
28+
sma.add_state(
29+
state_name='State5',
30+
state_timer=1,
31+
state_change_conditions={Bpod.Events.Tup: 'State6'},
32+
output_actions=[])
33+
sma.add_state(
34+
state_name='State6',
35+
state_timer=1,
36+
state_change_conditions={Bpod.Events.Tup: 'State7'},
37+
output_actions=[])
38+
sma.add_state(
39+
state_name='State7',
40+
state_timer=1,
41+
state_change_conditions={Bpod.Events.Tup: 'State8'},
42+
output_actions=[])
43+
sma.add_state(
44+
state_name='State8',
45+
state_timer=1,
46+
state_change_conditions={Bpod.Events.Tup: 'State9'},
47+
output_actions=[])
48+
sma.add_state(
49+
state_name='State9',
50+
state_timer=1,
51+
state_change_conditions={Bpod.Events.Tup: 'State10'},
52+
output_actions=[('GlobalTimerTrig', 1)])
53+
sma.add_state(
54+
state_name='State10',
55+
state_timer=1,
56+
state_change_conditions={Bpod.Events.GlobalTimer1_Start: 'exit'},
57+
output_actions=[])
58+
my_bpod.send_state_machine(sma)
59+
my_bpod.run_state_machine(sma)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from pybpodapi.protocol import Bpod, StateMachine
2+
my_bpod = Bpod(emulator_mode=True)
3+
sma = StateMachine(my_bpod)
4+
sma.add_state(
5+
state_name='myState',
6+
state_timer=1,
7+
state_change_conditions={Bpod.Events.Tup: 'exit'},
8+
output_actions=[])
9+
my_bpod.send_state_machine(sma)
10+
my_bpod.run_state_machine(sma)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# !/usr/bin/python3
2+
# -*- coding: utf-8 -*-
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import secrets
2+
from pybpodapi.protocol import Bpod, StateMachine
3+
my_bpod = Bpod(emulator_mode=True)
4+
nTrials = 5
5+
trialTypes = [1, 2] # 1 (rewarded left) or 2 (rewarded right)
6+
for i in range(nTrials): # Main loop
7+
print('Trial: ', i + 1)
8+
thisTrialType = secrets.choice(trialTypes) # Randomly choose trial type
9+
if thisTrialType == 1:
10+
# set stimulus channel for trial type 1
11+
stimulus = Bpod.OutputChannels.PWM1
12+
leftAction = 'Reward'
13+
rightAction = 'Punish'
14+
rewardValve = 1
15+
elif thisTrialType == 2:
16+
# set stimulus channel for trial type 1
17+
stimulus = Bpod.OutputChannels.PWM3
18+
leftAction = 'Punish'
19+
rightAction = 'Reward'
20+
rewardValve = 3
21+
sma = StateMachine(my_bpod)
22+
sma.add_state(
23+
state_name='WaitForPort2Poke',
24+
state_timer=1,
25+
state_change_conditions={Bpod.Events.Port2In: 'FlashStimulus'},
26+
output_actions=[(Bpod.OutputChannels.PWM2, 255)])
27+
sma.add_state(
28+
state_name='FlashStimulus',
29+
state_timer=0.1,
30+
state_change_conditions={Bpod.Events.Tup: 'WaitForResponse'},
31+
output_actions=[(stimulus, 255)])
32+
sma.add_state(
33+
state_name='WaitForResponse',
34+
state_timer=1,
35+
state_change_conditions={
36+
Bpod.Events.Port1In: leftAction, Bpod.Events.Port3In: rightAction},
37+
output_actions=[])
38+
sma.add_state(
39+
state_name='Reward',
40+
state_timer=0.1,
41+
state_change_conditions={Bpod.Events.Tup: 'exit'},
42+
# Reward correct choice
43+
output_actions=[(Bpod.OutputChannels.Valve, rewardValve)])
44+
sma.add_state(
45+
state_name='Punish',
46+
state_timer=3,
47+
state_change_conditions={Bpod.Events.Tup: 'exit'},
48+
# Signal incorrect choice
49+
output_actions=[(Bpod.OutputChannels.LED, 1),
50+
(Bpod.OutputChannels.LED, 2),
51+
(Bpod.OutputChannels.LED, 3)])
52+
# Send state machine description to Bpod device
53+
my_bpod.send_state_machine(sma)
54+
print("Waiting for poke. Reward: ",
55+
'left' if thisTrialType == 1 else 'right')
56+
my_bpod.run_state_machine(sma) # Run state machine
57+
print("Current trial info: {0}".format(my_bpod.session.current_trial))
58+
my_bpod.close() # Disconnect Bpod
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import secrets
2+
from pybpodapi.protocol import Bpod, StateMachine
3+
my_bpod = Bpod(emulator_mode=True)
4+
nTrials = 5
5+
graceTime = 5
6+
trialTypes = [1, 2] # 1 (rewarded left) or 2 (rewarded right)
7+
for i in range(nTrials): # Main loop
8+
print('Trial: ', i + 1)
9+
thisTrialType = secrets.choice(trialTypes) # Randomly choose trial type
10+
if thisTrialType == 1:
11+
# set stimulus channel for trial type 1
12+
stimulus = Bpod.OutputChannels.PWM1
13+
leftAction = 'Reward'
14+
rightAction = 'Punish'
15+
rewardValve = 1
16+
elif thisTrialType == 2:
17+
# set stimulus channel for trial type 1
18+
stimulus = Bpod.OutputChannels.PWM3
19+
leftAction = 'Punish'
20+
rightAction = 'Reward'
21+
rewardValve = 3
22+
sma = StateMachine(my_bpod)
23+
sma.set_global_timer_legacy(
24+
timer_id=1, timer_duration=graceTime) # Set timeout
25+
sma.add_state(
26+
state_name='WaitForPort2Poke',
27+
state_timer=1,
28+
state_change_conditions={Bpod.Events.Port2In: 'FlashStimulus'},
29+
output_actions=[('PWM2', 255)])
30+
sma.add_state(
31+
state_name='FlashStimulus',
32+
state_timer=0.1,
33+
state_change_conditions={Bpod.Events.Tup: 'WaitForResponse'},
34+
output_actions=[(stimulus, 255),
35+
(Bpod.OutputChannels.GlobalTimerTrig, 1)])
36+
sma.add_state(
37+
state_name='WaitForResponse',
38+
state_timer=1,
39+
state_change_conditions={Bpod.Events.Port1In: leftAction,
40+
Bpod.Events.Port3In: rightAction,
41+
Bpod.Events.Port2In: 'Warning',
42+
Bpod.Events.GlobalTimer1_End: 'MiniPunish'},
43+
output_actions=[])
44+
sma.add_state(
45+
state_name='Warning',
46+
state_timer=0.1,
47+
state_change_conditions={Bpod.Events.Tup: 'WaitForResponse',
48+
Bpod.Events.GlobalTimer1_End: 'MiniPunish'},
49+
output_actions=[(Bpod.OutputChannels.LED, 1),
50+
(Bpod.OutputChannels.LED, 2),
51+
(Bpod.OutputChannels.LED, 3)]) # Reward correct choice
52+
sma.add_state(
53+
state_name='Reward',
54+
state_timer=0.1,
55+
state_change_conditions={Bpod.Events.Tup: 'exit'},
56+
# Reward correct choice
57+
output_actions=[(Bpod.OutputChannels.Valve, rewardValve)])
58+
sma.add_state(
59+
state_name='Punish',
60+
state_timer=3,
61+
state_change_conditions={Bpod.Events.Tup: 'exit'},
62+
# Signal incorrect choice
63+
output_actions=[(Bpod.OutputChannels.LED, 1),
64+
(Bpod.OutputChannels.LED, 2),
65+
(Bpod.OutputChannels.LED, 3)])
66+
sma.add_state(
67+
state_name='MiniPunish',
68+
state_timer=1,
69+
state_change_conditions={Bpod.Events.Tup: 'exit'},
70+
# Signal incorrect choice
71+
output_actions=[(Bpod.OutputChannels.LED, 1),
72+
(Bpod.OutputChannels.LED, 2),
73+
(Bpod.OutputChannels.LED, 3)])
74+
# Send state machine description to Bpod device
75+
my_bpod.send_state_machine(sma)
76+
print("Waiting for poke. Reward: ",
77+
'left' if thisTrialType == 1 else 'right')
78+
# Run state machine
79+
my_bpod.run_state_machine(sma)
80+
print("Current trial info: {0}".format(my_bpod.session.current_trial))
81+
my_bpod.close() # Disconnect Bpod

0 commit comments

Comments
 (0)