cgnuino
|
Copyright (c) 2020 Kei Mochizuki. All right reserved.
This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this library; if not, see http://www.gnu.org/licenses/.
cgnuino is a library to help cognitive psychologists and neuroscientists to create behavioral tasks using Arduino boards. It provides several (what I hope are) useful functions when you create behavioral tasks with electrical inputs (e.g., button press, lever move, etc) and outputs (e.g., LED light, beep sound, etc). However, right now before getting started, you might be even uncertain whether Arduino is the best option to implement your task. Thus I start with pros and cons of using Arduino in controlling behavioral tasks for cognitive psychology and neuroscience.
First of all, writing programs with Arduino system is definitely easy for beginners compared with other programming languages such as Python, Ruby, C# and so on. Arduino uses classical C and C++ languages in writing program files, which are called Sketches in this platform. Drivers for Arduino boards are distributed with Arduino IDE, which is a useful and easy-to-handle software you can use to write your own Sketch. If you have any experience in writing computer programs with other languages, it should be fairly easy to write Arduino Sketches. And if you are not familiar with programming languages, Arduino can be still a good starting point due to its simplicity.
Standard Arduino boards have general purpose in/out (GPIO) pins, with which you can read or put out high (5V) or low (0V) voltage signal. (Be careful that some Arduino boards use 3.3V for high digital signal instead of 5V.) Using these GPIO pins as digital-out, you are able to directly turn on and off electrical parts using DC 5V power supply (e.g., lighting a LED), as well as to control instruments that have external triggering mechanism (e.g., applying predetermined set of electrical stimulation train at the rising edge of 5V input). Using GPIO pins as digital-in, you can easily monitor the participant's button press or lever manipulation. Arduino boards often have analog input pins, and some also have analog output pins, with which you can read or put out arbitrary voltage ranging from 0V to 5V, instead of binary low or high voltage.
Since these pins are physically implemented on Arduino boards as either pin sockets or soldering holes, using them is quite straightforward; you can simply connect the devise to Arduino. On the other hand, if you use a programming language running on a standard PC to execute your behavioral task, using such digital and analog IOs is not so easy, and you will normally need additional A/D or D/A converter to allow your computer to communicate with external instruments.
In general, Arduino boards are inexpensive. In addition, since Arduino is an open-source project, there are even cheaper Arduino-compatible boards from third parties (although I personally recommend official products). On writing programs with Arduino, you (of course) need a PC. However, it does not require any high performance like high-end CPU, massive RAM memory or gorgeous video card. Just a common PC with ordinary performance will do, with any of Linux, Mac or Windows operating system.
The biggest disadvantage of Arduino must be the absence of graphical display. Yes, you can find several liquid crystal displays and OLED displays that can be used with Arduino, none of which will satisfy the use of graphical display to present visual stimuli in psychological experiments. (i.e., They are not something you, as a normal psychologist or neuroscientist, expect to be by the words of "graphical display".) If you want to use visual stimuli just for the purpose of, for example, instructing timing of actions and telling trial conditions to the participant, then LEDs with different colors may be enough to do the job. However, if you wish to present visual stimuli in a normal sense for psychological experiments, then Arduino is not a suitable option for your task. In this case, you should choose other programming language working on a standard computer with graphical display. One of the popular options for such usage would be Expyriment library working on Python (which I prefer), and Psychophysics Toolbox working on Matlab (which I @#$%!).
After compiling your code (i.e., Sketch) and sending it to the on-board chip, Arduino runs in a "stand alone" way. USB connection is commonly used to power running Arduino, but is not necessary and can be thrown away if external DC supply is provided. When the power supply is out, Arduino stops running and all the temporal values of variables are flushed (except for a few exceptions I don't mention here). Therefore, to record the participant's behavioral performance, you need certain external mechanics to save it on a non-volatile storage in some way.
One of the ways is to use USB serial connection to write task information from Arduino to PC as a text file. Arduino can easily emit text to a serial port (by Serial.println
function) to show it on a serial monitor application running on the connected PC. You may be familiar with this feature through Serial Monitor utility in Arduino IDE. This is useful when you check the behavior of the program, especially during prototyping. However, if you use other serial monitors with automatical saving utility, the same serial interaction mechanism can be used as a "write to a text file" function. Run this kind of application in parallel with a connected Arduino board, and all the text from Arduino's serial connection is automatically save to a text file. I personally use this method for my own experiments and it is working quite well.
Another alternative for data saving is the usage of a SD (or nowadays more common micro-SD) card. Standard Arduino boards do not have SD card slot. But there are several breakout boards (small external boards that can be connected to Arduino) for SD card. Also, Arduino has a library named SD
that provides a simple IO interfaces to SD card. Using these materials, you can save the task performance to a text file on SD card, which is later transported into your PC and analyzed.
There is also another possibility for you to use WiFi connection and save your data to remote server computer. For example, there are some Arduino-compatible boards with a built-in WiFi interface such as ESP-WROOM-02 and ESP-WROOM-32. These will allow you to emit texts from your board to remote computer, enabling non-volatile saving of your data. However, the hardware of these boards is a bit complicated compared with standard genuine Arduino, and working on WiFi network in addition to building a web server should be a bother for beginners. Also, not many people will wish their unpublished data (including confidential information and task performance from the participants) be recorded through the Internet. So I personally do not think that this option is much feasible. Saving data to a local server in a private Local Area Network through WiFi can be a bit conceivable, although it does not seem to have a distinct advantage over just recording data through wired USB serial connection.
In human psychological experiments, variables in the program normally do not require any "manpowered" monitoring during task performance. Constants should remain constant, variables should vary in a way you described in the code. However, especially in animal experiments, there are times one want to change the value of certain variables on-line (i.e., without stopping the task progression). For example, you may want to increase the time length of opening a solenoid that delivers water reward to the animal, when her motivation suddenly starts to collapse during an experiment. In another case, you may want to gradually lengthen the temporal delay in your task during a training session. This is why many commercial specialized systems for behavioral task control in animals have certain on-line mechanism which allow you to modify variables during an experiment.
Because Arduino Sketches are essentially "compiled language", this kind of flexible variable modification is more or less difficult within a standard usage. However, the same is in fact true for Arduino's other counterparts such as Expyriment on Python or Psychophysics Toolbox on Matlab. You may need some uncouth hacks to send commands to running task program through secondary PC or something. In cgnuino, you can get rid of this problem by CgnControl class and embedded conditional branching, but you still need a moderate knowledge on serial communication anyway.
In the previous section, I briefly explained pros and cons in using Arduino for the implementation of behavioral tasks in cognitive psychology and neuroscience. Because you are still continue reading, it is likely that you decided (or at least are interested) to use Arduino for your experiment. Therefore, I now introduce how to create behavioral task on Arduino, and how this library will help your job.
While some of the readers might already have experiences on Arduino programming, others may be completely new to computer programming itself. Since there are many comprehensive tutorials and reviews for Arduino beginners on the internet, here I focus only a brief introduction to Arduino Sketch.
An Arduino Sketch is always composed of two functions: setup
and loop
. The contents of setup
function are executed only once after Arduino is terned on. Afterward, the contents of loop
function are repeatedly executed. In other words, when the execution of loop
function is finished, next loop
function is automatically called and starts to be executed. This means that you are going to carry out necessary settings of variables, pin modes and/or Serial
connections in setup
function. The progress of behavioral task itself (within a trial as well as transitions among trials) will then be controlled by repeating loop
function. The execution of one loop
function can be seen as a time resolution of events that can be detected or determined by Arduino Sketch, which is also called as a "cycle" or "tick" in other occasion. However, according to Arduino's naming basics shown above, I'm going to call it a "loop" from now on.
The other important thing you need to remember is that, the values of local variables in loop
function are NOT maintained through different loops. Therefore, if you want the values of some variables to be taken over through loops, all of these variables must be defined as grobal variables. In other words, define these variables outside any functions, conventionally at the very beginning of your Sketch. This surely sound very silly for users with prior programming experiences, but it is anyway the behavior of Arduino.
Now I finally explain how cgnuino library will help you implement your task on Arduino. Here I just briefly overview how you can create behavioral tasks in Arduino, and which cgnuino class may help each stage of task implementation. Detailed explanation of the classes and methods of the library is available in the linked pages. The list of all classes and files of the library is accessed from Classes and Files tabs on the top menu of this page. Also I prepared a few example Sketches that show the usage of cgnuino classes. These are available in examples
directory or from the menu bar of Arduino IDE after the library is correctly installed, in a way something like File > Examples > cgnuino.
Usually a trial in a behavioral task is composed of several task periods (also called as epochs in some cases). For example, a pre-trial period is followed by a cue period, in which a visual cue is presented. The participant needs to release the button press in a succeeding response period, after which a post-trial period follows. As in this example, a trial is divided into numbers of task periods in which different events occur or different actions are required. Some of them can have temporal limit (e.g., response is required within 800 ms), while others can last unlimitedly (e.g., next trial starts after the participant's voluntary button press). This kind of progression of task periods can be easily managed by CgnPeriod class.
Using Arduino's digitalRead
function, you can read voltage input as high (5V [or 3.3V]) or low (0V) state. This, in addition to pull-up or pull-down mechanism, allows you to record participant's button press and release as boolean (HIGH/LOW
or true/false
) value. However, in order to to detect the timing of button press and release, you need to monitor the change of the acquired value instead of the current state of the button. Therefore, in most cases you need to buffer the value of digital input and compared it with the current value. Also, because of the mechanical noise, the value of digital input can be unstable at the time of button manipulation (a phenomenun known as chattering or ripple). Thus you will sometimes want to ignore changes of digital input, during a short period (a few milliseconds should be enough), right after a change has occured. Using CgnDI class, you can perform a set of these stereotypical processing for digital input, for multiple digital-in pins at a time. The same kind of change monitoring for an arbitral boolean value instead of digital-in signals can be performed via CgnLogger class.
On acquiring participant's actions, you often want to record response times (or reaction times). For this purpose, CgnStopwatch class provides a easy to calculate temporal discrepancy between two events in millisecond order. You can even create multiple CgnStopwatch objects (have multiple stopwatches simultaneously) to calculate two or more response times in parallel.
In some tasks, output from Arduino is required to announce task-related information to the participant. This is normally done by a light stimulus using a LED and digitalWrite
function, or an auditory tone using a piezo buzzer and tone
function. However, these emitted output need to be later turned off manually using digitalWrite
or noTone
functions. CgnDO class provides an easy way to perform such digital output with fixed time length, allowing you an asynchronous task control along with output signals. The same functionality for tone output is provided by CgnTone class.
These are the basic utilities that will be often used in various behavioral tasks. There are some more classes that may help you in somewhat limited situations. By using these functionalities of cgnuino library, I hope your burden in task construction will become a bit lighter.