When you need to program multiple Arduino boards with the same firmware — for production runs, classrooms, or robotics teams — doing it one by one through the Arduino IDE is slow and error-prone. Batch programming multiple Arduino boards via shell script automates the entire process using Arduino CLI (Command Line Interface), letting you flash dozens of boards in sequence with a single command. This tutorial shows Indian makers, teachers, and small manufacturers how to set up automated batch Arduino programming.
Table of Contents
- Why Batch Program Arduino Boards?
- Installing Arduino CLI
- Basic Batch Flash Script
- Auto-Detecting Multiple Boards
- Parallel Programming Multiple Boards
- Verification and Error Handling
- Classroom and Production Use Cases
- Frequently Asked Questions
Why Batch Program Arduino Boards?
Batch Arduino programming is essential for several India-specific scenarios:
- Engineering college labs: Program 30–60 student kits before practicals — saves hours of one-by-one IDE clicking
- Small-scale production: Indian startups making IoT products with Arduino-based designs need efficient programming workflows
- Robotics competitions: Team members with multiple robot boards need identical firmware deployed quickly
- Testing stations: Quality control testing requires programming test firmware, running checks, then programming production firmware
- Firmware updates: Update firmware on multiple installed boards during field service visits
Installing Arduino CLI
Arduino CLI is the command-line version of Arduino IDE — same compilation, same board support, scriptable:
# Linux/macOS - one-line install
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
# On Ubuntu/Debian
sudo apt install arduino-cli
# On macOS with Homebrew
brew install arduino-cli
# Windows - download MSI from arduino.github.io/arduino-cli/
# Or use Windows Subsystem for Linux (WSL2)
# Verify installation
arduino-cli version
# Initial setup - create config file
arduino-cli config init
# Update core index
arduino-cli core update-index
# Install Arduino Uno/Nano/Mega core (AVR)
arduino-cli core install arduino:avr
# Install ESP32 core
arduino-cli core install esp32:esp32 --additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
# List installed cores
arduino-cli core list
Basic Batch Flash Script
#!/bin/bash
# batch_flash.sh - Flash one Arduino board at a specified port
SKETCH_PATH="$HOME/projects/my-firmware"
BOARD_FQBN="arduino:avr:uno" # Fully Qualified Board Name
PORT="$1" # Port passed as argument
if [ -z "$PORT" ]; then
echo "Usage: $0 /dev/ttyUSB0"
exit 1
fi
echo "Compiling firmware..."
arduino-cli compile --fqbn $BOARD_FQBN "$SKETCH_PATH"
if [ $? -ne 0 ]; then
echo "Compilation FAILED"
exit 1
fi
echo "Uploading to $PORT..."
arduino-cli upload --fqbn $BOARD_FQBN --port $PORT "$SKETCH_PATH"
if [ $? -eq 0 ]; then
echo "SUCCESS: Board at $PORT programmed"
else
echo "FAILED: Could not program board at $PORT"
exit 1
fi
Auto-Detecting Multiple Boards
#!/bin/bash
# auto_detect_and_flash.sh
# Finds all connected Arduino Uno boards and flashes each one
SKETCH_PATH="$HOME/projects/my-firmware"
BOARD_FQBN="arduino:avr:uno"
echo "=== Arduino Batch Programmer ==="
echo "Scanning for connected boards..."
# List all connected boards, filter for UNO (USB VID:PID 2341:0043 for genuine Uno)
arduino-cli board list
# Get list of ports with Arduino boards
PORTS=$(arduino-cli board list --format json | python3 -c "
import json, sys
data = json.load(sys.stdin)
ports = []
for port in data.get('detected_ports', []):
for board in port.get('matching_boards', []):
if 'Arduino' in board.get('name', ''):
ports.append(port['port']['address'])
print('
'.join(ports))
")
if [ -z "$PORTS" ]; then
echo "No Arduino boards detected!"
exit 1
fi
COUNT=$(echo "$PORTS" | wc -l)
echo "Found $COUNT Arduino board(s)"
# Compile once (don't recompile for each board)
echo "Compiling firmware..."
arduino-cli compile --fqbn $BOARD_FQBN "$SKETCH_PATH"
if [ $? -ne 0 ]; then
echo "Compilation FAILED - stopping"
exit 1
fi
# Flash each board
SUCCESS=0
FAILED=0
while IFS= read -r PORT; do
echo -n "Programming $PORT... "
arduino-cli upload --fqbn $BOARD_FQBN --port $PORT "$SKETCH_PATH" 2>/dev/null
if [ $? -eq 0 ]; then
echo "OK"
((SUCCESS++))
else
echo "FAILED"
((FAILED++))
fi
done <<< "$PORTS"
echo ""
echo "=== Results ==="
echo "Programmed: $SUCCESS boards"
echo "Failed: $FAILED boards"
Parallel Programming Multiple Boards
#!/bin/bash
# parallel_flash.sh - Flash multiple boards simultaneously
# Requires a USB hub with multiple boards connected
SKETCH_PATH="$HOME/projects/my-firmware"
BOARD_FQBN="arduino:avr:uno"
# Compile first (must be done before parallel jobs)
arduino-cli compile --fqbn $BOARD_FQBN "$SKETCH_PATH"
# Get all ports
PORTS=(/dev/ttyUSB* /dev/ttyACM*)
# Flash all boards in parallel using background jobs
PIDS=()
for PORT in "${PORTS[@]}"; do
if [ -e "$PORT" ]; then
(
arduino-cli upload --fqbn $BOARD_FQBN --port $PORT "$SKETCH_PATH"
echo "$PORT: Exit code $?"
) &
PIDS+=($!)
fi
done
# Wait for all background jobs to complete
for PID in "${PIDS[@]}"; do
wait $PID
done
echo "All boards programmed"
# Windows equivalent (PowerShell)
# $ports = arduino-cli board list --format json | ConvertFrom-Json
# $ports.detected_ports | ForEach-Object -Parallel {
# arduino-cli upload --fqbn arduino:avr:uno --port $_.port.address "C:projectsirmware"
# }
Verification and Error Handling
#!/bin/bash
# verified_flash.sh - Flash with verification via serial communication
# Sends "VERSION" command and checks response
SKETCH_PATH="$HOME/projects/my-firmware"
BOARD_FQBN="arduino:avr:uno"
EXPECTED_VERSION="v1.2.3"
verify_board() {
local PORT=$1
# Wait for board to boot after flash
sleep 2
# Send VERSION query via serial and read response
# stty -F $PORT 115200 cs8 -cstopb -parenb
# timeout 3 bash -c "echo 'VERSION' > $PORT && cat $PORT" | head -1
# Alternative: use Python for serial verification
RESPONSE=$(python3 -c "
import serial, time, sys
try:
ser = serial.Serial('$PORT', 115200, timeout=3)
time.sleep(2) # Wait for Arduino to boot
ser.write(b'VERSION
')
response = ser.readline().decode().strip()
print(response)
ser.close()
except Exception as e:
print('ERROR: ' + str(e))
" 2>&1)
if echo "$RESPONSE" | grep -q "$EXPECTED_VERSION"; then
echo "VERIFIED: $PORT reports $RESPONSE"
return 0
else
echo "VERIFY FAILED: $PORT reports '$RESPONSE' (expected $EXPECTED_VERSION)"
return 1
fi
}
# Flash and verify each board
for PORT in /dev/ttyACM*; do
echo "Programming $PORT..."
if arduino-cli upload --fqbn $BOARD_FQBN --port $PORT "$SKETCH_PATH"; then
verify_board $PORT
else
echo "Upload failed for $PORT"
fi
done
Classroom and Production Use Cases
Classroom Lab Setup (India)
#!/bin/bash
# classroom_setup.sh
# For Indian engineering college practicals
# Each student connects their board via USB hub
# Teacher runs this script to pre-flash lab exercise firmware
LAB_EXERCISE="$1" # e.g., "lab3_adc_reading"
SKETCH_BASE="$HOME/lab-exercises"
case $LAB_EXERCISE in
lab1) SKETCH="$SKETCH_BASE/01_blink" ;;
lab2) SKETCH="$SKETCH_BASE/02_traffic_light" ;;
lab3) SKETCH="$SKETCH_BASE/03_adc_reading" ;;
*) echo "Unknown exercise. Use: lab1, lab2, lab3"; exit 1 ;;
esac
echo "Loading exercise: $LAB_EXERCISE from $SKETCH"
# (continue with auto-detect and flash script above)
Frequently Asked Questions
Can Arduino CLI program ESP32 and ESP8266 boards too?
Yes — Arduino CLI supports all boards that Arduino IDE supports, including ESP32 and ESP8266. Install the appropriate core (arduino-cli core install esp32:esp32) and use the correct FQBN (e.g., esp32:esp32:esp32cam for ESP32-CAM). The same batch scripts work with different FQBN values.
How do I find the correct FQBN for my Arduino board?
Run arduino-cli board listall | grep -i "uno" to search for your board. Or connect the board and run arduino-cli board list to see the detected FQBN. For common Indian boards: Uno=arduino:avr:uno, Nano=arduino:avr:nano, Mega=arduino:avr:mega, NodeMCU=esp8266:esp8266:nodemcuv2.
What USB hub is recommended for programming many Arduino boards simultaneously in India?
Use a powered USB hub (with separate power adapter) — not bus-powered. Programming multiple boards simultaneously draws significant current. A 7-port or 10-port powered USB 2.0 hub (₹500–₹1500) works well. USB 3.0 hubs are backward compatible. Ensure the hub provides at least 500mA per port.
Can I program Arduino boards in Windows using batch (.bat) scripts?
Yes — Arduino CLI runs on Windows and all commands work in PowerShell or CMD. Replace Linux path formats (/dev/ttyACM0) with Windows COM ports (COM3). Use PowerShell’s ForEach-Object for iteration. Windows Subsystem for Linux (WSL2) also works and uses Linux syntax.
How do I handle different board types in one batch run?
Use arduino-cli board list --format json to detect the board type at each port, then match to the appropriate FQBN in your script. This enables heterogeneous setups where some ports have Uno and others have Nano or Mega boards.
Add comment