Arduino is an open-source electronics platform based on easy-to-use hardware and software. It’s designed for anyone making interactive projects, from artists to engineers to researchers.
Why Arduino?
- Easy to Learn: Simple programming language (C/C++ based)
- Low Cost: Boards start at $20-30
- Versatile: Control LEDs, motors, sensors, displays
- Large Community: Extensive documentation and examples
- Research-Ready: Precise timing for experiments
- Expandable: Shields and modules for any application
Arduino Boards
Arduino Uno (Most Popular)
- Microcontroller: ATmega328P
- Digital I/O: 14 pins (6 PWM)
- Analog Input: 6 pins
- Memory: 32 KB Flash, 2 KB RAM
- Price: ~$25
- Best For: Learning, general projects
Arduino Mega
- More I/O: 54 digital, 16 analog
- More Memory: 256 KB Flash, 8 KB RAM
- Best For: Complex projects, many sensors
Arduino Nano
- Compact: Breadboard-friendly
- Similar to Uno: Same chip, smaller size
- Best For: Permanent installations
Programming Arduino
The Arduino IDE
- Free software from arduino.cc
- Write code, upload to board
- Serial monitor for debugging
- Libraries for sensors and modules
Basic Program Structure
void setup() {
// Runs once at startup
pinMode(13, OUTPUT);
Serial.begin(9600);
}
void loop() {
// Runs repeatedly forever
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);
}
Digital I/O
Digital Output
const int ledPin = 13;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
digitalWrite(ledPin, HIGH); // 5V
delay(1000);
digitalWrite(ledPin, LOW); // 0V
delay(1000);
}
Digital Input
const int buttonPin = 2;
const int ledPin = 13;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}
void loop() {
int buttonState = digitalRead(buttonPin);
if (buttonState == LOW) { // Button pressed (pullup inverts)
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}
}
Analog I/O
Analog Input (0-5V → 0-1023)
const int sensorPin = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(sensorPin);
// Convert to voltage
float voltage = sensorValue * (5.0 / 1023.0);
Serial.print("Value: ");
Serial.print(sensorValue);
Serial.print(", Voltage: ");
Serial.println(voltage);
delay(100);
}
PWM Output (Simulated Analog)
const int ledPin = 9; // Must be PWM-capable pin
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
analogWrite(ledPin, 64); // 25% brightness
delay(1000);
analogWrite(ledPin, 128); // 50% brightness
delay(1000);
analogWrite(ledPin, 255); // 100% brightness
delay(1000);
}
Serial Communication
Sending Data
void setup() {
Serial.begin(9600); // Baud rate
}
void loop() {
int value = analogRead(A0);
Serial.println(value); // Send to computer
delay(100);
}
Receiving Commands
void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop() {
if (Serial.available()) {
char command = Serial.read();
if (command == '1') {
digitalWrite(13, HIGH);
Serial.println("LED ON");
} else if (command == '0') {
digitalWrite(13, LOW);
Serial.println("LED OFF");
}
}
}
Research Applications
TTL Trigger Generation
// Generate precise TTL pulses for experiments
const int triggerPin = 8;
void setup() {
pinMode(triggerPin, OUTPUT);
digitalWrite(triggerPin, LOW);
Serial.begin(115200);
}
void sendTrigger(int duration_us) {
digitalWrite(triggerPin, HIGH);
delayMicroseconds(duration_us);
digitalWrite(triggerPin, LOW);
}
void loop() {
if (Serial.available()) {
char command = Serial.read();
if (command == 'T') {
sendTrigger(100); // 100µs pulse
Serial.println("OK");
}
}
}
Behavioral Task Controller
// Simple two-alternative forced choice task
const int leftLED = 12;
const int rightLED = 11;
const int leftButton = 2;
const int rightButton = 3;
const int rewardPin = 8;
void setup() {
pinMode(leftLED, OUTPUT);
pinMode(rightLED, OUTPUT);
pinMode(rewardPin, OUTPUT);
pinMode(leftButton, INPUT_PULLUP);
pinMode(rightButton, INPUT_PULLUP);
Serial.begin(115200);
randomSeed(analogRead(0));
}
void loop() {
// Wait for trial start command
if (Serial.available() && Serial.read() == 'S') {
// Random stimulus side
bool correctSide = random(2); // 0=left, 1=right
// Show stimulus
if (correctSide == 0) {
digitalWrite(leftLED, HIGH);
} else {
digitalWrite(rightLED, HIGH);
}
// Wait for response
unsigned long startTime = millis();
bool responded = false;
while (!responded) {
if (digitalRead(leftButton) == LOW) {
responded = true;
bool correct = (correctSide == 0);
unsigned long rt = millis() - startTime;
// Reward if correct
if (correct) {
digitalWrite(rewardPin, HIGH);
delay(50);
digitalWrite(rewardPin, LOW);
}
// Send result
Serial.print(correctSide);
Serial.print(",");
Serial.print(correct ? 1 : 0);
Serial.print(",");
Serial.println(rt);
}
if (digitalRead(rightButton) == LOW) {
responded = true;
bool correct = (correctSide == 1);
unsigned long rt = millis() - startTime;
if (correct) {
digitalWrite(rewardPin, HIGH);
delay(50);
digitalWrite(rewardPin, LOW);
}
Serial.print(correctSide);
Serial.print(",");
Serial.print(correct ? 1 : 0);
Serial.print(",");
Serial.println(rt);
}
}
// Clear LEDs
digitalWrite(leftLED, LOW);
digitalWrite(rightLED, LOW);
delay(1000); // ITI
}
}
Sensor Data Logger
// Log multiple sensors to SD card or serial
void setup() {
Serial.begin(115200);
// Print header
Serial.println("time_ms,sensor1,sensor2,sensor3");
}
void loop() {
unsigned long timestamp = millis();
int sensor1 = analogRead(A0);
int sensor2 = analogRead(A1);
int sensor3 = analogRead(A2);
Serial.print(timestamp);
Serial.print(",");
Serial.print(sensor1);
Serial.print(",");
Serial.print(sensor2);
Serial.print(",");
Serial.println(sensor3);
delay(10); // 100 Hz sampling
}
Python Integration
Control Arduino from Python
import serial
import time
# Connect to Arduino
arduino = serial.Serial('COM3', 115200, timeout=1) # Adjust port
time.sleep(2) # Wait for connection
# Send command
arduino.write(b'T')
# Read response
response = arduino.readline().decode().strip()
print(f"Arduino says: {response}")
# Close
arduino.close()
PySerial for Data Acquisition
import serial
import numpy as np
import matplotlib.pyplot as plt
# Connect
ser = serial.Serial('COM3', 115200)
# Collect data
data = []
for i in range(1000):
line = ser.readline().decode().strip()
value = int(line)
data.append(value)
# Plot
plt.plot(data)
plt.xlabel('Sample')
plt.ylabel('Value')
plt.show()
ser.close()
Timing Precision
Microsecond Resolution
void setup() {
pinMode(13, OUTPUT);
}
void loop() {
digitalWrite(13, HIGH);
delayMicroseconds(100); // 100µs HIGH
digitalWrite(13, LOW);
delayMicroseconds(900); // 900µs LOW
// Total: 1000µs = 1ms = 1kHz
}
millis() for Non-Blocking Delays
unsigned long previousMillis = 0;
const long interval = 1000;
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
// Do something every second
digitalWrite(13, !digitalRead(13));
}
// Other code runs without blocking
}
Common Modules & Shields
- LCD Display: Show text and values
- SD Card: Data logging
- RTC (Real-Time Clock): Accurate timekeeping
- WiFi/Ethernet: Network connectivity
- Motor Driver: Control motors
- Relay Module: Switch high-power devices
Best Practices for Research
- Use HIGH baud rate: 115200 for serial communication
- Buffer serial data: Don’t miss incoming bytes
- Non-blocking code: Avoid delay() in time-critical sections
- Timestamp everything: Use millis() or micros()
- Validate timing: Measure with oscilloscope
- Document pin usage: Comment your code
- Use interrupts: For critical timing events
Limitations
- Limited memory: 2KB RAM on Uno
- No real-time OS: Can miss events
- 5V logic: May need level shifters for 3.3V devices
- Single threaded: No parallel processing
- Limited floating point: Slow math operations
When to Use Arduino
Good For:
- Trigger generation
- Simple sensors
- Button/response collection
- LED/display control
- Prototyping
Consider Alternatives For:
- Complex timing requirements (→ Teensy, ESP32)
- High-speed data acquisition (→ DAQ boards)
- Heavy computation (→ Raspberry Pi)
- Many I/O pins (→ Arduino Mega, Teensy)
Learning Resources
- Official Tutorials: https://www.arduino.cc/en/Tutorial/
- Reference: https://www.arduino.cc/reference/
- Forum: https://forum.arduino.cc/
- Project Hub: https://create.arduino.cc/projecthub
Summary
Arduino is ideal for:
- Lab automation: Custom experimental equipment
- Precise timing: Trigger generation
- Sensor integration: Data acquisition
- Behavioral control: Task presentation
Its simplicity and reliability make it a staple in neuroscience and psychology labs worldwide.