Python
Our Python scripts allow you to interact dynamically with the Arduino during the experiment. For instance, you can visualize the subject's performance in real time, and use this feedback to send messages to the Arduino to change parameters like inter-trial interval or timeout duration. This can be done manually by a human operator, or automatically by a script.
This approach has the advantage of being more flexible and powerful, because Python is a higher-level language than Processing and there is a much larger community of active developers. However, the disadvantage is that you would have to be comfortable with two languages: Python, and the Arduino language. If you prefer to work only in one language, please see our collection of Processing sketches. And no matter what you choose, remember that you can always contact us for help or advice!
We've tried to keep the algorithms as general as possible, meaning that they should be easy to adapt to different sensory modalities or trial structures. However, we do typically assume that the behavior is "trial-based", that is, that it consists of many repeated trials. Each trial can use different stimuli and parameters, of course, but typically each is scored as "correct" or "incorrect". The most common operant paradigms, such as go/nogo and two-alternative choice, fit this description.
All of the Python code is hosted on a github repository. This is the best place to get started! Individual files are also linked below.
There are several parts to the Python/Arduino architecture that we've provided:
-
An Arduino sketch, which runs on the Arduino and manages the structure of each trial. For instance, this controls the motors or displays that you use to present stimuli, and it measures the subject's behavioral response.
-
A Python-based "chatter" that runs on the host PC and communicates with the Arduino. This mechanism allows you to send and receive messages from the Arduino. All of the chats are stored in a logfile on the hard disk.
-
A Python-based "trial setter" that collects information from the Arduino about the progress on each trial, and uses this information to specify the parameters for the next trial.
-
A Python-based user interface that displays the progress of the experiment and allows the user to input commands to change parameters of the task or send messages directly to the Arduino.
You can mix and match these components to suit your needs. For instance, the chatter can be used as a general solution for communication between a PC and an Arduino. Other components, like the user interface, are pretty specific to each task and will probably need to be edited more substantially for your desired purpose.
The Arduino sketch uses a "finite state machine" design philosophy. (We drew inspiration for this directly from the bcontrol software package, though our implementation ended up rather different.) Briefly, the idea is that at any given point the Arduino is in a specific "state", and that this state determines what outputs it generates and how it treats inputs it receives. For instance, the first state could be "present stimulus" and trigger a motor to move a tactile stimulus into the whisker field. Once the motor reaches its final position, the state changes to "response window", and behavioral responses from the subject are collected. Then, the final state could be "inter-trial interval", during which responses are ignored and the motor returns to its resting state. The exact states depend on your experiment, of course.
If you're not already familiar with this type of design, it may seem initially confusing. However, one advantage of this design is that it allows us to make the most use of the Arduino's processor cycles, and ensure that it can communicate with the PC as quickly as possible without sacrificing fast responses to behavioral events. (For the Arduino afficionados: we achieved this feature by removing all delay statements so that we can alternate calls to the background communication code with calls to the state machine code. Delay statements are a very inefficient use of processor cycles!) If you're interested in knowing more, check out the code! We've tried to provide enough of a framework to get you started on designing your own experiment, even if you haven't previously heard of any of these topics.