Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NiusCam

A production-minded Arduino camera library for ESP32 camera modules.

Arduino-ESP32 3.x Version 0.2.0 License Apache-2.0 Hardware verified

NiusCam provides a small, typed C++ interface for camera capture, sensor control, microSD storage, browser streaming, and low-latency UDP delivery. It uses the esp32-camera driver already bundled with Arduino-ESP32, then adds board-aware configuration, safe frame ownership, capability checks, recovery, an optional NiusCam-managed direct-PSRAM DMA mode for the verified OV5640/S3 path, and optional modules that are removed by the linker when unused.

The library is designed for common e-commerce camera boards and for projects that need to move beyond a one-file camera demo without inheriting a large web application or a second camera-driver package.

Highlights

  • Simple Camera camera; and camera.method() workflow
  • Automatic board profile selection for the supported targets
  • Move-only Frame objects that return frame buffers automatically
  • Eco, Balanced, and Turbo starting profiles plus complete custom configuration
  • Typed controls for exposure, gain, white balance, image tuning, orientation, test patterns, frame format, resolution, clocks, buffers, and PSRAM DMA
  • Sensor detection, capability checks, profile mismatch protection, diagnostics, controlled reconfiguration, and recovery
  • Optional OV5640 single-shot and continuous autofocus control
  • Optional OV2640 datasheet-based automatic low-light frame-rate control
  • Optional validated OV5640 direct-to-PSRAM DMA at full resolution
  • Optional atomic JPEG storage with progress, throughput, and ETA reporting
  • Optional HTTP snapshots and MJPEG browser streaming
  • Optional versioned UDP framing with sequence metadata and CRC32
  • No bundled credentials, cloud service, telemetry, or copied camera HAL

Supported camera hardware

Camera module / board Camera sensor Maximum native sensor size microSD interface Status
ESP32-S3-CAM N16R8 OV2640, standard 66-degree lens 1600 x 1200 SD_MMC, 1-bit Camera and storage verified
ESP32-S3-CAM N16R8 OV5640 fixed-focus, 130-degree lens 2592 x 1944 SD_MMC, 1-bit Focused 2560 x 1920 scene and optional direct-PSRAM DMA verified
AI-Thinker ESP32-CAM OV2640, 160-degree lens, seller-declared visible + 850 nm dual-pass filter 1600 x 1200 SD_MMC, 1-bit Capture and wide-angle output verified; optical passband unverified
AI-Thinker ESP32-CAM OV5640 fixed-focus, 65-degree lens 2592 x 1944 SD_MMC, 1-bit Sensor and sharp decoded 2560 x 1920 JPEG verified
Seeed Studio XIAO ESP32-S3 Sense OV3660, standard 66-degree lens 2048 x 1536 SPI Camera and storage verified
Seeed Studio XIAO ESP32-S3 Sense OV2640, 160-degree lens, seller-declared 650 nm IR-cut filter 1600 x 1200 SPI Capture and wide-angle output verified; optical cutoff unverified

Sensor support

Sensor Support level Notes
OV2640 Hardware verified JPEG, grayscale, RGB565, YUV422, and RGB888 capability paths; sharpness and denoise are not exposed by the bundled sensor driver
OV3660 Hardware verified JPEG and grayscale through 2048 x 1536; capability-gated RGB modes; sharpness and denoise available
OV5640 Hardware verified on two DVP boards Fixed-focus capture verified at 2560 x 1920; sensor native array is 2592 x 1944; optional AF controller requires compatible actuator hardware

Different view angles, focal lengths, fixed-focus lenses, IR-cut filters, and night-vision assemblies normally do not require a different software driver if the sensor model and electrical pinout are unchanged. A module with different wiring needs a custom BoardProfile.

Warning

The tested 50 mm DC-5640 autofocus flex is a two-lane MIPI CSI-2 module, despite being sold alongside ESP32 camera products. Its pins 12-22 carry MIPI differential lanes rather than the DVP pixel bus required by the ESP32-S3. SCCB can still identify the sensor, but this module cannot deliver frames through an ESP32-S3-CAM DVP connector. Use an explicitly documented 24-pin DVP OV5640 module; connector size and sensor name alone are not enough. Compare the vendor's complete table with the supported 24-pin DVP layout before powering the module; voltage rails and AF power must match as well as signal names.

Lens angle and optical-filter type are descriptive module metadata. The seller's 650 nm option is an IR-cut daylight filter; its 850 nm night option is a visible-light + 850 nm dual-pass filter, not an IR emitter. A decoded RGB image can verify field of view and low-light sensitivity, but cannot prove the exact filter wavelength. OV2640 automatic low-light timing preserves color and extends exposure by reducing frame rate; it does not create IR illumination.

Note

NiusCam supports Arduino-ESP32 3.x. All examples were compiled with 3.0.7 and 3.3.10; physical hardware results use 3.3.10. Arduino-ESP32 2.x is not a supported target.

Install Arduino-ESP32 and NiusCam

1. Add Espressif's board-package URL

In Arduino IDE, open File > Preferences (Windows/Linux) or Arduino IDE > Settings (macOS). Add this URL to Additional boards manager URLs:

https://espressif.github.io/arduino-esp32/package_esp32_index.json

If the field already contains another URL, click its list button and add the Espressif URL on a new line. Do not remove package URLs used by other boards.

2. Install the ESP32 board package

  1. Open Tools > Board > Boards Manager.
  2. Search for esp32.
  3. Install esp32 by Espressif Systems, version 3.x.
  4. Restart Arduino IDE if the new boards do not immediately appear.

No separate esp32-camera library is needed. Installing another copy can cause header or linker conflicts because the camera component is included in the Espressif board package. Espressif also maintains the official Arduino-ESP32 installation guide.

3. Install NiusCam

For a release ZIP:

  1. Open Sketch > Include Library > Add .ZIP Library.
  2. Select the NiusCam ZIP without extracting it first.
  3. Confirm that File > Examples > NiusCam contains the bundled examples.

See Arduino's library installation guide for IDE-specific screenshots and alternative installation methods.

For a source checkout, place the repository in the Arduino sketchbook as:

<Arduino sketchbook>/libraries/NiusCam/

The directory containing library.properties, src, and examples must be named NiusCam; avoid an extra nested directory such as NiusCam-main/NiusCam.

4. Select the board and memory options

Hardware Arduino IDE board Required/recommended options
ESP32-S3-CAM N16R8 ESP32S3 Dev Module Flash Size: 16MB, PSRAM: OPI PSRAM; choose a partition scheme large enough for the application
AI-Thinker ESP32-CAM AI Thinker ESP32-CAM Use the board defaults; connect the required USB-to-serial adapter and stable 5 V supply
XIAO ESP32-S3 Sense XIAO_ESP32S3 PSRAM: OPI PSRAM; ensure the Sense expansion board and camera ribbon are fully seated

Then choose the upload port under Tools > Port. Enabling PSRAM is strongly recommended for JPEG camera use and required for larger frames or multiple frame buffers.

5. Upload the first capture example

  1. Open File > Examples > NiusCam > BasicCapture.
  2. Upload the sketch.
  3. Open Tools > Serial Monitor at 115200 baud.
  4. Confirm that the detected sensor, free heap, free PSRAM, resolution, and JPEG byte count are printed.

If initialization fails, follow the checks in Troubleshooting before changing pin definitions.

Quick start

The default Config is Balanced, and the correct built-in board profile is selected from the Arduino board target:

#include <NiusCam.h>

using namespace NiusCam;

Camera camera;

void setup() {
  Serial.begin(115200);

  Result result = camera.begin();
  if (!result) {
    Serial.print("Camera initialization failed: ");
    Serial.println(result.message());
  }
}

void loop() {
  Frame frame = camera.capture();
  if (!frame) {
    Serial.println("Capture failed");
    delay(1000);
    return;
  }

  Serial.print(frame.width());
  Serial.print('x');
  Serial.print(frame.height());
  Serial.print(" JPEG, ");
  Serial.print(frame.size());
  Serial.println(" bytes");
  delay(1000);
}

Frame owns one camera frame buffer. It is move-only and automatically returns that buffer when the object leaves scope. Call frame.release() before a long wait, reconfiguration, suspension, or any operation that needs the same PSRAM.

Performance profiles

Profiles are safe, documented starting points—not hidden modes. Every field can be changed after applying a profile.

Setting Eco Balanced (default) Turbo
Pixel format JPEG JPEG JPEG
Frame size QVGA, 320 x 240 VGA, 640 x 480 VGA, 640 x 480
JPEG quality value 16 12 14
Frame buffers 1 2 3
Buffer memory PSRAM PSRAM PSRAM
Grab mode When empty Latest frame Latest frame
Camera XCLK 10 MHz 20 MHz 20 MHz
DMA mode Staged Staged Staged
Primary goal Lower clock/buffer use General capture and stability Delivered frame rate and low latency

JPEG quality follows the Espressif sensor convention: lower values request higher image quality and usually create larger files. Valid values are 0-63, but useful values for these sensors are commonly around 10-20.

Object-style configuration keeps sketches readable:

Config config;
config.useTurbo();
config.frameSize = FrameSize::SVGA;
config.jpegQuality = 10;
config.frameBuffers = 2;

Result result = camera.begin(config);

The requested format and frame size are checked against the selected sensor before camera startup. All profiles use the broadly compatible staged path; direct PSRAM DMA is an explicit opt-in with stricter validation. See Configuration and profiles for every field, enum, and sensor constraint.

Use OV5640 direct DMA

On the verified ESP32-S3/OV5640 path, direct mode writes QSXGA JPEG data from the camera peripheral into PSRAM without the staged CPU copy:

Config config;
config.useBalanced();
config.frameSize = FrameSize::QSXGA;
config.useDirectDma();

Result result = camera.begin(config);

useDirectDma() selects the verified clock, JPEG quality floor, two-buffer Latest configuration, and direct backend. Other OV5640 resolutions continue to use staged DMA. Direct mode is optional and is intended to reduce camera-copy CPU work; it is not guaranteed to increase sensor-limited FPS. See Configuration and profiles.

Common tasks

Tune the sensor

SensorControls sensor = camera.sensor();
sensor.brightness(1);
sensor.contrast(0);
sensor.automaticExposure(true);
sensor.automaticGain(true);
sensor.automaticWhiteBalance(true);
sensor.horizontalMirror(false);
sensor.verticalFlip(false);

All controls return Result; production code should check the result when a control is required. Sensor-specific features remain available through sensor.native().

Focus an OV5640 autofocus module

#include <NiusCamAutofocus.h>

Autofocus autofocus;
Result result = autofocus.begin(camera, AutofocusMode::SingleShot);
if (result)
  result = autofocus.trigger();

AutofocusStatus focusInfo;
if (result)
  result = autofocus.wait(focusInfo);

Autofocus is optional and linked only when its header is included. See the autofocus guide for modes, status values, and electrical requirements.

Save an atomic JPEG to microSD

#include <NiusCamStorage.h>

Storage storage;

Result result = storage.begin();
Frame frame = camera.capture();
if (result && frame)
  result = storage.saveJpeg(frame, "/photo.jpg", true);

The atomic mode writes /photo.jpg.part, flushes it, and renames it only after the complete JPEG is stored. The SaveToSD example adds a progress bar, throughput, ETA, and explicit error messages. See Storage guide.

Stream to a browser

#include <NiusCamHttp.h>

HttpStreamServer server;
Result result = server.begin(camera);

The application owns Wi-Fi setup. The server provides /, /snapshot.jpg, and /stream. The bundled example creates a local SoftAP with no personal network credentials. See Streaming guide.

Send low-latency UDP frames

#include <NiusCamUdp.h>

UdpFrameSender sender;
sender.begin(IPAddress(192, 168, 4, 2));

Frame frame = camera.capture();
if (frame)
  sender.send(frame);

UDP frames use a documented versioned header, 1200-byte payload chunks, sequence information, total size, and complete-frame CRC32. Receivers must drop incomplete frames. See the streaming guide and UDP protocol.

Included examples

Example Purpose
BasicCapture Initialize, identify the sensor, inspect memory, and capture JPEG frames
FullControl Customize a profile and apply portable sensor controls
Autofocus Run an OV5640 single-shot autofocus cycle and capture focused frames
Ov2640LowLight Apply OmniVision's documented automatic low-light frame-rate timing
Ov5640DirectDma Opt into validated full-resolution direct-to-PSRAM DMA on ESP32-S3
SaveToSD Mount the correct storage bus and save an atomic JPEG with progress reporting
PowerModes Release a frame, suspend the camera, and restore capture safely
HttpStream Create a SoftAP and serve snapshots plus browser MJPEG
UdpStream Create a SoftAP and send CRC-protected, chunked JPEG frames over UDP

Documentation

  • Documentation home — choose a guide by task or experience level
  • Getting started — installation, board setup, first upload, and validation
  • Supported hardware — boards, sensors, storage buses, custom modules, and compatibility boundaries
  • Configuration and profiles — every configuration field, profile defaults, formats, frame sizes, memory, and tuning guidance
  • OV5640 autofocus — initialization, single-shot and continuous modes, status, and module compatibility
  • OV2640 low-light timing — documented 50/60 Hz automatic frame-rate controls and measured dark-scene behavior
  • API reference — lifecycle, frames, controls, diagnostics, storage, HTTP, UDP, errors, and native access
  • Storage guide — card preparation, progress reporting, atomic files, sequences, recording, and failure handling
  • Streaming guide — SoftAP/station setup, HTTP routes, MJPEG, UDP, ownership, and transport selection
  • UDP protocol v1 — binary packet format and receiver requirements
  • Troubleshooting — camera, PSRAM, microSD, build, upload, and network diagnostics
  • Verified results — reproducible hardware observations, limits, and benchmark scope

Design and dependency policy

NiusCam does not copy or fork a third-party camera driver. It uses Espressif's Apache-2.0 esp32-camera component distributed with Arduino-ESP32 because that component contains the SoC camera HAL and sensor implementations. NiusCam adds a consistent public API and optional application-facing services around it.

Only include the modules a sketch uses:

  • <NiusCam.h> — camera core and controls
  • <NiusCamAutofocus.h> — optional OV5640 autofocus controller
  • <NiusCamOv2640.h> — optional OV2640 low-light timing controls
  • <NiusCamStorage.h> — microSD operations
  • <NiusCamHttp.h> — HTTP snapshots and MJPEG
  • <NiusCamUdp.h> — UDP frame sender

Unused optional modules are not linked into the final firmware.

License

NiusCam is licensed under the Apache License 2.0. It uses, but does not vendor, Espressif's Apache-2.0 esp32-camera component supplied by Arduino-ESP32. See LICENSE and NOTICE.

About

Typed camera capture, control, microSD storage, HTTP MJPEG, and CRC-protected UDP streaming for ESP32 camera modules.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages