Arduino
Open-source electronics platform for building interactive projects with microcontrollers
Our View
Arduino makes it easy to create interactive hardware for experiments. Its simple programming interface and vast ecosystem make it ideal for building custom experimental equipment, triggering systems, and data acquisition devices.
Provisional positions are editorial proposals awaiting group review.
Teaching — Recorded in topic offerings; consult the dated event links for availability.
1 topics with recorded teaching · 1 past offerings · 0 upcoming offerings
Related themes: Scientific Computing
Related topics: Programming and Data Acquisition
Common use cases
- Experimental trigger generation
- Behavioral task controllers
- Sensor data acquisition
- Custom lab equipment
Getting started
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.