Raspberry Pi, Arduino, and ESP32 solve different problems. The Raspberry Pi is a full Linux computer. The Arduino is a simple, deterministic microcontroller board. The ESP32 is a cheap, fast microcontroller with built-in Wi-Fi and Bluetooth. Pick the wrong one and you either overpay, drain a battery in a day, or fight a real-time timing bug for a week. This guide gives you the specs, pinouts, logic levels, code, and a decision matrix.
Quick Takeaways
- Raspberry Pi 5: Use it when you need an OS, a camera pipeline, a database, a web server, or a local AI model. It is not a good choice for hard real-time I/O or battery projects.
- Arduino (Uno R4 / Uno R3): Use it when you want predictable timing, 5V logic, shield compatibility, and the simplest learning curve.
- ESP32: Use it for connected, low-power, low-cost projects. It has Wi-Fi, BLE, and a 240MHz dual-core CPU for about $5–$15.
- Combine them. An ESP32 collects sensor data and publishes it over MQTT. A Raspberry Pi stores and visualizes it.
| Feature | Raspberry Pi 5 | Arduino Uno R4 Minima | ESP32-S3 |
|---|---|---|---|
| Type | Single-board computer (SBC) | Microcontroller board | Microcontroller (SoC) |
| CPU | Quad-core Cortex-A76, 2.4GHz | Cortex-M4, 48MHz | Dual-core Xtensa LX7, 240MHz |
| RAM | 2–16GB LPDDR4X | 32KB SRAM | 512KB SRAM (+ optional PSRAM) |
| Storage | microSD / NVMe | 256KB flash | 4–16MB external flash |
| Logic level | 3.3V | 5V | 3.3V |
| Wireless | Wi-Fi 5, BT 5.0 | None (R4 WiFi adds ESP32-S3) | Wi-Fi 4, BLE 5 |
| Typical power | ~3–12W | ~0.2–0.3W | ~0.1–0.5W active |
| Real-time | No (Linux scheduler) | Yes | Yes (FreeRTOS) |
| Price class | $77+ in late 2026 | ~$20 | ~$5–$15 |
Component Overview
Raspberry Pi: A Computer, Not a Controller
The Raspberry Pi 5 runs the BCM2712 SoC with four Cortex-A76 cores at 2.4GHz. It boots Raspberry Pi OS from a microSD card or an NVMe drive on its PCIe connector. You get USB 3.0, dual HDMI, Gigabit Ethernet, and a 40-pin GPIO header.
Because Linux owns the hardware, GPIO timing is not deterministic. A kernel scheduling event can delay a pin toggle by milliseconds. That breaks tight protocols like bit-banged WS2812 timing unless you use the PIO-style hardware or a dedicated driver.
The Pi has no onboard ADC. To read an analog sensor, add an ADS1115 or MCP3008 over I2C or SPI.
Pricing caveat: Memory shortages have pushed Pi prices up repeatedly in 2026. As of November 2026, list prices are roughly $77.50 for 2GB, $110 for 4GB, $180 for 8GB, and $385 for 16GB at approved resellers. Check live prices before you design around a specific model.
Arduino: Simplicity and Determinism
An Arduino board runs one program, with no operating system. The classic Uno R3 uses the 8-bit ATmega328P at 16MHz with 2KB SRAM and 32KB flash. The newer Uno R4 moves to a 32-bit Renesas RA4M1 (Cortex-M4, 48MHz) with 32KB SRAM and 256KB flash. It keeps the 5V logic and the Uno shield footprint.
You get cycle-predictable timing. A digitalWrite() happens when you call it, and an interrupt fires within microseconds. The Uno R4 WiFi adds an ESP32-S3 as a wireless co-processor, but your sketch still runs on the RA4M1, not the ESP32.
ESP32: The Connected Workhorse
The ESP32 family from Espressif integrates the CPU, Wi-Fi, Bluetooth, and dozens of peripherals on one chip. The popular ESP32-S3 has two Xtensa LX7 cores at 240MHz, 512KB SRAM, native USB, and vector instructions for lightweight ML. Variants differ:
| Variant | Core | Wireless | Best for |
|---|---|---|---|
| ESP32 (classic) | Dual Xtensa LX6, 240MHz | Wi-Fi 4, BT Classic + BLE | General IoT, huge community |
| ESP32-S3 | Dual Xtensa LX7, 240MHz | Wi-Fi 4, BLE 5 | Camera, displays, edge AI |
| ESP32-C3 | Single RISC-V, 160MHz | Wi-Fi 4, BLE 5 | Low-cost Wi-Fi nodes |
| ESP32-C6 | Single RISC-V, 160MHz | Wi-Fi 6, BLE 5, 802.15.4 | Matter / Thread devices |
All run 3.3V logic. Pins are not 5V tolerant. Feeding 5V into a GPIO can damage the chip.
Pinout and Logic Level Comparison
Logic voltage is where most mixed-board projects fail.
| Parameter | Raspberry Pi 5 | Arduino Uno R4 | ESP32 DevKit |
|---|---|---|---|
| GPIO logic | 3.3V | 5V | 3.3V |
| Max per-pin current | ~16mA (configurable) | 8mA (R4), 20mA (R3) | ~20mA (40mA absolute max) |
| Onboard ADC | None | 14-bit (configurable) | 12-bit (noisy, nonlinear) |
| Onboard DAC | None | 12-bit (1 channel) | 8-bit (classic ESP32 only) |
| Hardware I2C | 6 buses (via pin mux) | 1–2 | 2 |
| Hardware SPI | 6 buses | 1–2 | 2–3 usable |
| Hardware UART | 5 | 1–2 | 3 |
| PWM channels | 4 hardware | 6 | 8–16 (LEDC) |
Level-shifting rules:
- Arduino 5V output → ESP32/Pi input: use a voltage divider (for example 1kΩ + 2kΩ) or a bidirectional level shifter like the BSS138 module.
- ESP32/Pi 3.3V output → Arduino 5V input: the ATmega328P reads anything above ~3.0V as HIGH, so it usually works. The RA4M1 threshold is similar, but confirm in the datasheet.
- I2C between voltage domains: always use a BSS138-based shifter. Keep the 4.7kΩ pull-ups on the correct side.
Power Consumption and Battery Life
Power draw decides whether a project runs for hours or years.
| Scenario | Raspberry Pi 5 | Arduino Uno R4 | ESP32-S3 |
|---|---|---|---|
| Idle | ~2.5–3W | ~0.15W (board) | ~0.1W (Wi-Fi off) |
| Active, Wi-Fi | ~5–8W (load-dependent) | ~0.4W (R4 WiFi) | ~0.5W peak bursts of 240–350mA |
| Deep sleep | Not supported | Limited (board LEDs, regulator) | ~10µA chip level (higher on dev boards) |
| Power source | 5V/5A USB-C PD recommended | 5–12V barrel / USB | 3.3V from LiPo + LDO |
A dev board’s USB-UART bridge and LDO regulator waste more current than the ESP32 chip does in sleep. For battery builds, use a bare module or a board designed for low quiescent current. Wake the ESP32 from a timer or a GPIO interrupt, send the reading over Wi-Fi, then sleep again.
The Raspberry Pi has no practical deep-sleep mode. If your project must run from a LiPo or a small solar panel, choose the ESP32.
Software and Programming Environment
| Aspect | Raspberry Pi | Arduino | ESP32 |
|---|---|---|---|
| Primary languages | Python, C/C++, Rust, anything on Linux | C/C++ (Arduino framework) | C/C++ (Arduino core, ESP-IDF), MicroPython |
| IDE | Any editor, SSH, VS Code Remote | Arduino IDE 2, PlatformIO | Arduino IDE, PlatformIO, ESP-IDF |
| OS / RTOS | Linux | None (bare metal) | FreeRTOS |
| Debugging | Full (gdb, logs, profilers) | Serial prints, optional SWD | Serial, JTAG (S3 built-in USB JTAG) |
| Learning curve | Moderate | Easiest | Easy (Arduino core) to steep (ESP-IDF) |
Code Example: Raspberry Pi (Python, gpiozero)
# Toggle an LED on GPIO17 when a button on GPIO27 is pressed.
# Pi GPIO is 3.3V. Never connect a 5V signal directly.
from gpiozero import LED, Button
from signal import pause
led = LED(17) # GPIO17 drives LED through a 330-ohm resistor
button = Button(27, pull_up=True) # internal pull-up; button connects pin to GND
button.when_pressed = led.on # runs in a background thread
button.when_released = led.off
pause() # keep the script alive
Code Example: Arduino (C++, analog read and PWM)
// Arduino Uno R4: read a potentiometer on A0 and dim an LED on pin 9.
const int POT_PIN = A0; // analog input, 5V reference
const int LED_PIN = 9; // PWM-capable pin
void setup() {
Serial.begin(115200);
analogReadResolution(12); // R4 supports up to 14-bit; 12-bit shown here
pinMode(LED_PIN, OUTPUT);
}
void loop() {
int raw = analogRead(POT_PIN); // 0..4095 at 12-bit
int duty = map(raw, 0, 4095, 0, 255); // scale to 8-bit PWM
analogWrite(LED_PIN, duty); // write duty cycle
Serial.println(raw);
delay(20); // ~50Hz update rate
}
Code Example: ESP32 (Arduino core, Wi-Fi and deep sleep)
// ESP32: connect to Wi-Fi, report RSSI, then deep sleep for 60 seconds.
#include <WiFi.h>
const char* SSID = "YOUR_SSID";
const char* PASS = "YOUR_PASSWORD";
const uint64_t SLEEP_US = 60ULL * 1000000ULL; // 60 s in microseconds
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA); // station mode, no AP overhead
WiFi.begin(SSID, PASS);
uint32_t start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < 10000) {
delay(200); // wait up to 10 s for association
}
if (WiFi.status() == WL_CONNECTED) {
Serial.printf("IP: %s RSSI: %d dBm\n",
WiFi.localIP().toString().c_str(), WiFi.RSSI());
// ...publish sensor data here (HTTP, MQTT)...
}
esp_sleep_enable_timer_wakeup(SLEEP_US); // wake from RTC timer
esp_deep_sleep_start(); // chip draws microamps; reboots on wake
}
void loop() {} // never reached
Cost and Availability in 2026
| Item | Approx. price (USD) | Notes |
|---|---|---|
| Raspberry Pi 5 (2GB) | $77.50 | Plus PSU, case, cooler, storage |
| Raspberry Pi 5 (8GB) | $180 | Prices moved several times in 2026 |
| Arduino Uno R4 Minima | ~$20 | Official board |
| Arduino Uno R4 WiFi | ~$27.50–$30 | Includes ESP32-S3 co-processor |
| ESP32 DevKit (various) | ~$5–$15 | Clones widely available |
| Raspberry Pi Pico 2 W (alternative) | ~$7 | RP2350 microcontroller with Wi-Fi |
A Raspberry Pi needs a 5V supply, storage, and often a cooler, so the real entry cost is well above the board price. An ESP32 board runs from any USB port.
How to Choose: Decision Matrix
| Your requirement | Best pick | Why |
|---|---|---|
| Run a web server, database, or Home Assistant | Raspberry Pi | Full Linux and networking |
| Camera + computer vision | Raspberry Pi (or ESP32-S3 for light tasks) | CPU and RAM headroom |
| Battery-powered sensor node | ESP32 | µA deep sleep |
| Motor control with tight timing | Arduino | Deterministic loop, 5V drivers |
| Learning electronics for the first time | Arduino | Huge tutorials, shield ecosystem |
| Cheap Wi-Fi/BLE smart device | ESP32 | Built-in radio, lowest cost |
| Retrofit existing 5V shields | Arduino Uno R4 | Pin-compatible footprint |
| Matter / Thread smart-home device | ESP32-C6 | Native 802.15.4 + Wi-Fi 6 |
| Local AI inference (LLM, vision) | Raspberry Pi 5 | CPU/RAM, optional accelerators |
| Audio DSP / simple wake-word | ESP32-S3 | Vector instructions, I2S |
Real-World Project: Build an IoT Weather Station (ESP32 + Raspberry Pi)
This build uses each board where it is strongest. The ESP32 reads a sensor and sleeps. The Raspberry Pi receives the data, stores it, and draws dashboards.
Parts list:
- 1× ESP32 DevKit (classic, GPIO21 = SDA, GPIO22 = SCL by default)
- 1× BME280 sensor (temperature, humidity, pressure over I2C, 3.3V)
- 1× Raspberry Pi running Mosquitto (MQTT broker), InfluxDB, and Grafana
- Jumper wires, 3.7V LiPo (optional)
Wiring:
| BME280 pin | ESP32 pin |
|---|---|
| VIN | 3V3 |
| GND | GND |
| SDA | GPIO21 |
| SCL | GPIO22 |
Most BME280 breakouts include I2C pull-up resistors. Check yours. If SDA/SCL float, add 4.7kΩ resistors to 3V3.
Firmware (ESP32):
// Publish BME280 readings to an MQTT broker, then deep sleep.
#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_BME280.h>
const char* SSID = "YOUR_SSID";
const char* PASS = "YOUR_PASSWORD";
const char* MQTT_HOST = "192.168.1.50"; // Raspberry Pi IP
const uint64_t SLEEP_US = 300ULL * 1000000ULL; // report every 5 min
WiFiClient net;
PubSubClient mqtt(net);
Adafruit_BME280 bme;
void setup() {
Serial.begin(115200);
Wire.begin(21, 22); // SDA=GPIO21, SCL=GPIO22
if (!bme.begin(0x76)) { // common I2C address; try 0x77 if it fails
Serial.println("BME280 not found");
esp_deep_sleep(SLEEP_US);
}
WiFi.begin(SSID, PASS);
while (WiFi.status() != WL_CONNECTED) delay(200);
mqtt.setServer(MQTT_HOST, 1883);
while (!mqtt.connected()) mqtt.connect("esp32-weather");
char payload[96];
snprintf(payload, sizeof(payload),
"{\"t\":%.2f,\"h\":%.1f,\"p\":%.1f}",
bme.readTemperature(), // degrees C
bme.readHumidity(), // percent RH
bme.readPressure() / 100.0F); // hPa
mqtt.publish("home/weather/outdoor", payload);
mqtt.loop();
delay(100); // let the packet flush
esp_sleep_enable_timer_wakeup(SLEEP_US);
esp_deep_sleep_start();
}
void loop() {}
Raspberry Pi side: install Mosquitto, subscribe to home/weather/#, forward the JSON into InfluxDB with Telegraf, and chart it in Grafana.
Why this split works: the ESP32 spends over 99% of its time asleep, so a small LiPo can last months. The Pi stays powered and does the heavy storage and visualization work.
Where an Arduino Fits
Add an Arduino Uno R4 to the same system if you need to drive 5V relays, a stepper motor via an A4988 driver, or an HD44780 LCD with strict timing. Connect it to the Pi over UART or USB serial, and let it handle the real-time actuator work.
Common Mistakes to Avoid
- Feeding 5V into an ESP32 or Pi GPIO. Use a level shifter or a voltage divider.
- Powering servos from a board’s 3.3V or 5V pin. Use a separate supply and share GND.
- Using a Pi for a 6-month battery node. It has no deep-sleep mode, so choose an ESP32.
- Trusting ESP32 ADC readings blindly. The ADC is nonlinear near the rails. Calibrate, or use analogReadMilliVolts(), or add an external ADS1115.
- Powering a Pi from a weak USB charger. Undervoltage causes SD-card corruption. Use a supply that meets the Pi 5 power requirements.
FAQ
Is ESP32 better than Arduino?
Neither is better in general. The ESP32 has more CPU speed, more RAM, and built-in Wi-Fi and Bluetooth, so it suits connected and low-power projects. Arduino boards offer 5V logic, simpler timing, shield compatibility, and the gentlest learning curve, so they suit beginners and real-time control.
Can a Raspberry Pi replace an Arduino?
Sometimes, but not for timing-critical work. A Pi runs Linux, so GPIO timing can jitter by milliseconds. It also lacks an onboard ADC, and its 3.3V pins are less tolerant than an Arduino’s. Use the Pi for computing and networking, and add a microcontroller for hard real-time I/O.
Which is best for IoT: Raspberry Pi, Arduino, or ESP32?
The ESP32 is the best default for IoT sensor nodes. It has built-in Wi-Fi and BLE, µA-level deep sleep, and low cost. Use a Raspberry Pi as the hub that runs the broker, database, and dashboard. Use an Arduino only when the node needs 5V peripherals and no wireless.
Can I use Arduino code on an ESP32?
Yes, in most cases. The ESP32 Arduino core supports the standard digitalWrite(), analogRead(), Wire, and SPI APIs. Libraries that rely on AVR-specific registers will not compile, and you must adjust pin numbers and keep all signals at 3.3V.



