Holcombe:ButtonBox with Photocell
• Alex Holcombe
What is it and what is it used for?
The box is an arduino module connected to: 4 response buttons, a photocell and a usb connector. It can be used to accurately synchronise the onset of a response time clock with the presentation of visual stimuli. This is achieved by attaching the photocell to an area of the monitor that increases in luminance when stimuli are displayed
How does it work?
The button box has 3 modes: A, B and C.
Mode A: When it's plugged into a usb port, it is initially in mode A. In this mode it sends a single string, 'a', to the serial port. This indicates that the box is ready to receive commands.
Mode B: Sending the string 'b' to the box activates mode B. Once in mode B the box waits until the photocell detects an increase in light, at which point it starts a clock. The first button press after the photocell detects a change in light is then sent to the serial port. The incoming signal contains two values: the time (ms) from the change in luminance to the button press, and the number of the button pressed e.g. "1370 2" which indicates 1370ms and button 2. The string returned is in the form "[time]\t[button]\n\r"
Mode C: Sending a string made up of 'c' and some value in milliseconds to the box returns the min and max values of luminance recorded by the photocell in the time interval in the string. For example: 'c3000' produces: ‘temt6000Max 203 temt6000Min 14’ where 'temt6000' is the photocell and ‘203’ and ‘14’ are the max and min luminance values over the period 3000ms
Implementing in PsychoPy
This function is used to initialise the button box:
For info on what's happening here, see the (not great) documentation for pyserial: https://pythonhosted.org/pyserial/
def initialiseButtonBox(): serialPorts = serial.tools.list_ports.comports() devices = [port.description for port in serialPorts] try: boxPortIndex = devices.index('Arduino Uno') buttonBox = serial.Serial(serialPorts[boxPortIndex].device, timeout=5, baudrate = 9600, write_timeout=5) #write and read timeouts are important, without them, #the box hangs indefinitely if you call readline() or write() something without any relevant info to write or retrieve return buttonBox except ValueError: print('Button box not found') return None
To make use of B mode after calling the above function we clear the buffer and send the ASCII value for ‘b’ to the box:
buttonBox = initialiseButtonBox() #Calls the function above buttonBox.reset_input_buffer() #Clears the input buffer buttonBox.write(b'b') #After being sent 'b' the box stops writing to the buffer until the photocell is triggered and a key is pressed
Once the photocell has been triggered and a key pressed the box sends a string in the form '[time]\t[button]\n\r'. This can be returned by using the readline() function:
buttonBox.readline() #Reads the first line in the buffer.
Charlie Ludowici has written a functioning PsychoPy demo for the box, which can be found here on GitHub
The demo counts down from 5 to allow time for the photocell to be covered; after the clock reaches 0 any change in luminance detected by the photocell starts the clock. The clock stops once a button on the box has been pressed. The time period from when the photocell detects a change in luminance to when a button is pressed is then displayed in ms along with the button number that was pressed. The instructions and comments in the demo are very helpful.