Build an ESP32-CAM QR Scanner
The Story
ESP32-CAM QR Code Scanner solves a real beginner problem: turning an ESP32 reading into a useful physical or networked result. Build this after the basic camera server because QR scanning adds focus, lighting, decoding, and serial debugging challenges.
The tutorial focuses on the engineering path: prove the input, understand the circuit, write readable code, then test the output under real conditions.
Explain Like I'm 12
A QR scanner is a camera plus a translator. The camera sees a square pattern, and the decoding library turns that pattern into text the ESP32 can use.
Safety Standards
- Unplug USB before changing jumper wires. Recheck 3.3 V, 5 V, and GND before reconnecting power.
- Do not power motors, pumps, LED strips, or servos from the ESP32 3.3 V pin. Use a suitable external supply and common ground.
- Breadboards are for low-current prototypes. Move high-current or unattended builds to proper terminals, enclosure, strain relief, and fusing.
What You Will Build
An ESP32-CAM scanner that captures frames and decodes QR codes for access demos, inventory labels, or classroom identification projects.
Learning Objectives
- Program and boot an ESP32-CAM correctly.
- Capture frames suitable for QR decoding.
- Understand why lighting and focus affect recognition.
- Print decoded text to Serial Monitor.
- Plan safe next steps for access or inventory projects.
Components List
- 1× ESP32-CAM module (AI-Thinker)OV2640 camera
- 1× FTDI USB-to-serial adapterProgramming and Serial Monitor
- 1× 5 V 2 A power supplyRequired for this build
- 1× Printed QR code or phone screenFor testing
- Breadboard and jumper wiresFor safe low-voltage prototyping
Bill of Materials
| Part | Qty | Estimated Cost | Notes |
|---|---|---|---|
| 1× ESP32-CAM module (AI-Thinker) | 1 | Varies | OV2640 camera |
| 1× FTDI USB-to-serial adapter | 1 | Varies | Programming and Serial Monitor |
| 1× 5 V 2 A power supply | 1 | Varies | Required for this build |
| 1× Printed QR code or phone screen | 1 | Varies | For testing |
| Breadboard and jumper wires | 1 set | Varies | For safe low-voltage prototyping |
Wiring
Wire the input hardware first, confirm readings in Serial Monitor, then connect the output hardware. The ESP32-CAM uses its onboard OV2640 camera.
-
1
Unplug USB before changing wires.
-
2
Connect FTDI TX/RX/GND/5V to U0R/U0T/GND/5V (Standard ESP32-CAM flash wiring).
-
3
Connect IO0 to GND (During upload only; remove for run).
-
4
Reconnect USB, upload the sketch, and open Serial Monitor at 115200 baud unless the code says otherwise.
GPIO Mapping
| Signal | ESP32 Pin | Direction | Notes |
|---|---|---|---|
| FTDI TX/RX/GND/5V | U0R/U0T/GND/5V | Ground | Standard ESP32-CAM flash wiring |
| IO0 | GND | Signal | During upload only; remove for run |
Circuit Explanation
The ESP32-CAM uses its onboard OV2640 camera. Programming requires FTDI serial wiring and IO0-to-GND only during upload. A printed QR code or phone screen becomes the target. Good lighting and correct focus matter as much as code.
Engineering Explanation
QR decoding is sensitive to image clarity. Low light, glare, motion blur, high resolution memory pressure, and poor focus can all prevent decoding. A reliable scanner starts with simple Serial output, fixed lighting, and a known QR code before adding actions such as relays or web requests.
Libraries
- Arduino ESP32 coreInstall ESP32 board support in Arduino IDE.
Code
Copy into Arduino IDE. Install any libraries noted in the component guides first.
// ESP32-CAM QR Code Scanner - Beginner
// Library: https://github.com/zbar/zbar or Quirc port for ESP32
// Use: ESP32-CAM-QR library by martinius96
#include "esp_camera.h"
#include <quirc.h>
// AI-Thinker pin map
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
struct quirc *qr;
void setup() {
Serial.begin(115200);
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM; config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 10000000;
config.pixel_format = PIXFORMAT_GRAYSCALE; // Quirc needs grayscale
config.frame_size = FRAMESIZE_QVGA; // 320x240 for speed
config.jpeg_quality = 12;
config.fb_count = 1;
if (esp_camera_init(&config) != ESP_OK) {
Serial.println("Camera init failed"); return;
}
qr = quirc_new();
quirc_resize(qr, 320, 240);
Serial.println("QR Scanner ready — point at a QR code");
}
void loop() {
camera_fb_t *fb = esp_camera_fb_get();
if (!fb) { delay(100); return; }
uint8_t *qr_buf = quirc_begin(qr, NULL, NULL);
memcpy(qr_buf, fb->buf, fb->len);
quirc_end(qr);
esp_camera_fb_return(fb);
int count = quirc_count(qr);
for (int i = 0; i < count; i++) {
struct quirc_code code;
struct quirc_data data;
quirc_extract(qr, i, &code);
if (quirc_decode(&code, &data) == QUIRC_SUCCESS) {
Serial.print("QR Decoded: ");
Serial.println((char*)data.payload);
}
}
delay(200);
}
Code Explanation
The sketch starts Serial Monitor, defines readable pin constants, configures input and output pins in setup(), then repeats the measurement and decision logic in loop(). Camera setup selects the correct ESP32-CAM pin map, initializes the OV2640, then captures frames. Keep the first test simple: prove the camera initializes before adding storage, scanning, or network actions.
Expected Output
Serial Monitor should print live readings or status messages. The output should change only when the tested condition for esp32-cam qr code scanner is reached.
Build Photos
- Breadboard overviewShow ESP32, module, output device, and power rails.
- Close-up wiringShow signal pins clearly enough for learners to compare.
- Working outputShow Serial Monitor, LEDs, display, or dashboard after the condition changes.
Troubleshooting
- QR code is never decoded Use a larger printed QR code, improve lighting, and test at 10-20 cm distance.
- Camera init fails Check board selection, camera model, ribbon cable, and power supply.
- Decoded text is inconsistent Hold the code still and reduce glare.
- Board resets during scanning Use a stable 5 V supply with enough current.
Common Mistakes
- Testing with a tiny QR code too close to the camera.
- Using glossy phone screens with glare.
- Leaving IO0 grounded after upload.
- Running high camera resolution that leaves too little memory for decoding.
- Adding door-lock hardware before QR decoding is reliable.
Testing Checklist
- Upload a simple Blink sketch first to confirm the board and USB cable work.
- Wire only power and ground, then confirm the board still boots.
- Connect the input signal and print raw readings before using thresholds.
- Trigger the real-world condition slowly and watch Serial Monitor.
- Connect the output only after the input reading is believable.
- Power-cycle the project and confirm it starts in a safe state.
Engineering Tips
- Prove camera capture before QR decoding.
- Use matte printed codes for testing.
- Keep the first decoded action harmless, such as Serial output.
- Do not connect locks or relays until false reads are handled.
- Add a timeout so the same QR code does not trigger repeatedly.
Performance Tips
- Use modest resolution to preserve RAM.
- Decode only when a new frame is ready.
- Avoid unnecessary Wi-Fi while decoding if memory is tight.
- Use simple payload strings in QR codes.
Upgrade Ideas
- Add an OLED display to show decoded QR content without a computer
- Add a buzzer beep on successful decode
- Log decoded URLs to Serial and open them automatically via a companion app
- Add a green LED that lights for 1 second after a successful decode
Real-World Applications
- Inventory label scanner
- Classroom attendance demo
- Prototype access control input
- Museum exhibit information trigger
Downloads
- ESP32-CAM QR Code Scanner Arduino sketchUse the code section as the source sketch.
- Bench test checklistFollow the testing checklist before permanent installation.
FAQs
Why does QR scanning fail in low light?
The decoder needs a sharp, high-contrast camera frame. Improve lighting, reduce glare, and hold the QR code still before changing the code.
What QR code size works best at close range?
Start with a larger printed QR code at about 10-20 cm, matching the troubleshooting guidance, then adjust distance after the scanner decodes reliably.
Why does the ESP32-CAM reset during scanning?
Camera capture can draw enough current to expose a weak 5 V supply. Use the stable supply listed in the project and remove IO0 from GND after uploading.
Review, Testing, and References
Author: Abdul Mubeen and the ESP32 Engine editorial team. Last updated: 2026-07-05. Reviewed: wiring logic, Arduino code structure, beginner safety, and learning sequence.
Educational level: Intermediate. Estimated completion time: 90-130 min. This project is for learning and prototyping; production or unattended hardware needs additional engineering review.
Project Complete!
You completed ESP32-CAM QR Code Scanner as a real ESP32 engineering build, not just a wiring demo. You now know how to test the input, protect the circuit, explain the code, and improve the project safely.
- Read and verify project input hardware
- Map signals to safe ESP32 GPIO pins
- Debug with Serial Monitor
- Apply safety and performance checks
- Plan the next learning step
