Writing a protocol for Bpod

What is a Bpod protocol?

To use Bpod, you must first program a behavioral protocol. The following guide is based on the original version for Bpod Matlab.

Protocol example explained

1. Import the modules

First, you will need to import Bpod modules.

1
from pybpodapi.protocol import Bpod, StateMachine

2. Initialize Bpod

Initialize Bpod and provide serial connection.

5
my_bpod = Bpod(serial_port='/dev/ttyACM0')

Instead of hard coding the serial port in your scripts you can configure it using the user_settings.py file.

Create the files __init__.py and user_settings.py in the running directory (check the examples folder on pybpod source code). Now you can instantiate Bpod() without having to pass the serial port as parameter.

5
my_bpod = Bpod()

3. Run several trials

Run several trials in each Bpod execution. In this example, we will use 5 trials where each trial can be of type1 (rewarded left) or type2 (rewarded right).

 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
nTrials = 5
trialTypes = [1, 2]  # 1 (rewarded left) or 2 (rewarded right)

for i in range(nTrials):  # Main loop
    print('Trial: ', i+1)
    thisTrialType = random.choice(trialTypes)  # Randomly choose trial type =
    if thisTrialType == 1:
        stimulus = Bpod.OutputChannels.PWM1  # set stimulus channel for trial type 1
        leftAction = 'Reward'
        rightAction = 'Punish'
        rewardValve = 1
    elif thisTrialType == 2:
        stimulus = Bpod.OutputChannels.PWM3  # set stimulus channel for trial type 1
        leftAction = 'Punish'
        rightAction = 'Reward'
        rewardValve = 3

Now, inside the loop, we will create and configure a state machine for each trial. A state machine has state name, state timer, names of states to enter if certain events occur and output actions. Please see State Machine API for detailed information about state machine design.

Warning

We strongly advise to use the API available labels as described on the examples output actions and input events.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    sma = StateMachine(my_bpod)

    sma.add_state(
        state_name='WaitForPort2Poke',
        state_timer=1,
        state_change_conditions={Bpod.Events.Port2In: 'FlashStimulus'},
        output_actions=[(Bpod.OutputChannels.PWM2, 255)])
    sma.add_state(
        state_name='FlashStimulus',
        state_timer=0.1,
        state_change_conditions={Bpod.Events.Tup: 'WaitForResponse'},
        output_actions=[(stimulus, 255)])
    sma.add_state(
        state_name='WaitForResponse',
        state_timer=1,
        state_change_conditions={Bpod.Events.Port1In: leftAction, Bpod.Events.Port3In: rightAction},
        output_actions=[])
    sma.add_state(
        state_name='Reward',
        state_timer=0.1,
        state_change_conditions={Bpod.Events.Tup: 'exit'},
        output_actions=[(Bpod.OutputChannels.Valve, rewardValve)])  # Reward correct choice
    sma.add_state(
        state_name='Punish',
        state_timer=3,
        state_change_conditions={Bpod.Events.Tup: 'exit'},
        output_actions=[(Bpod.OutputChannels.LED, 1), (Bpod.OutputChannels.LED, 2), (Bpod.OutputChannels.LED, 3)])  # Signal incorrect choice

After configuring the state machine, we send it to the Bpod device by calling the method send_state_machine. We are then ready to run the next trial, by calling the run_state_machine method. On run completion, we can print the data available for the current trial including events and states.

49
50
51
52
53
54
55
    my_bpod.send_state_machine(sma)  # Send state machine description to Bpod device

    print("Waiting for poke. Reward: ", 'left' if thisTrialType == 1 else 'right')

    my_bpod.run_state_machine(sma)  # Run state machine

    print("Current trial info: ", my_bpod.session.current_trial)

Try the example

You can try the full example by installing and running this library.

Full example (function_examples/add_trial_events.py):

# !/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Demonstration of AddTrialEvents used in a simple visual 2AFC session.
AddTrialEvents formats each trial's data in a human-readable struct, and adds to myBpod.data (to save to disk later)
Connect noseports to ports 1-3.

Example adapted from Josh Sanders' original version on Sanworks Bpod repository
"""

import random
from pybpodapi.protocol import Bpod, StateMachine

my_bpod = Bpod()

nTrials = 5
trialTypes = [1, 2]  # 1 (rewarded left) or 2 (rewarded right)

for i in range(nTrials):  # Main loop
	print('Trial: ', i + 1)

	thisTrialType = random.choice(trialTypes)  # Randomly choose trial type
	if thisTrialType == 1:
		stimulus = Bpod.OutputChannels.PWM1  # set stimulus channel for trial type 1
		leftAction = 'Reward'
		rightAction = 'Punish'
		rewardValve = 1
	elif thisTrialType == 2:
		stimulus = Bpod.OutputChannels.PWM3  # set stimulus channel for trial type 1
		leftAction = 'Punish'
		rightAction = 'Reward'
		rewardValve = 3

	sma = StateMachine(my_bpod)

	sma.add_state(
		state_name='WaitForPort2Poke',
		state_timer=1,
		state_change_conditions={Bpod.Events.Port2In: 'FlashStimulus'},
		output_actions=[(Bpod.OutputChannels.PWM2, 255)])
	sma.add_state(
		state_name='FlashStimulus',
		state_timer=0.1,
		state_change_conditions={Bpod.Events.Tup: 'WaitForResponse'},
		output_actions=[(stimulus, 255)])
	sma.add_state(
		state_name='WaitForResponse',
		state_timer=1,
		state_change_conditions={Bpod.Events.Port1In: leftAction, Bpod.Events.Port3In: rightAction},
		output_actions=[])
	sma.add_state(
		state_name='Reward',
		state_timer=0.1,
		state_change_conditions={Bpod.Events.Tup: 'exit'},
		output_actions=[(Bpod.OutputChannels.Valve, rewardValve)])  # Reward correct choice
	sma.add_state(
		state_name='Punish',
		state_timer=3,
		state_change_conditions={Bpod.Events.Tup: 'exit'},
		output_actions=[(Bpod.OutputChannels.LED, 1), (Bpod.OutputChannels.LED, 2), (Bpod.OutputChannels.LED, 3)])  # Signal incorrect choice

	my_bpod.send_state_machine(sma)  # Send state machine description to Bpod device

	print("Waiting for poke. Reward: ", 'left' if thisTrialType == 1 else 'right')

	my_bpod.run_state_machine(sma)  # Run state machine

	print("Current trial info: {0}".format(my_bpod.session.current_trial))

my_bpod.close()  # Disconnect Bpod