Skip to main content

Seeed Studio XIAO ESP32S3 Senseでのカメラ使用方法

tip

このチュートリアルの内容は、Seeed Studio XIAO ESP32S3 Senseにのみ適用されます。

このチュートリアルでは、XIAO ESP32S3 Senseのカメラモジュールの使用方法について説明します。このチュートリアルは以下の部分に分かれています。まず、ESP32が提供するカメラ機能とその機能について説明します。次に、写真撮影と動画録画の2つの側面からカメラの使用方法をご紹介し、最後に写真撮影と動画録画を中心とした興味深いプロジェクトを作成します。

Seeed Studio XIAO ESP32S3 Sense

はじめに

このチュートリアルでは、microSDカード、カメラ、アンテナなどの使用が含まれる場合があります。以下の材料を準備し、プロジェクトのニーズに応じて正しくインストールしてください。

アンテナの取り付け

XIAO ESP32S3の前面左下に、独立した「WiFi/BTアンテナコネクタ」があります。より良いWiFi/Bluetoothシグナルを得るために、パッケージ内のアンテナを取り出してコネクタに取り付ける必要があります。

アンテナの取り付けには少しコツがあります。直接強く押し込もうとすると、非常に押しにくく、指が痛くなることがあります!正しいアンテナの取り付け方法は、まずアンテナコネクタの片側をコネクタブロックに入れ、次に反対側を少し押し下げると、アンテナが取り付けられます。

拡張ボードの取り付け(Sense用)

拡張ボードの取り付けは非常に簡単です。拡張ボードのコネクタをXIAO ESP32S3のB2Bコネクタに合わせ、強く押して「カチッ」という音が聞こえれば、取り付け完了です。

現在、XIAO ESP32S3 Senseと完全に互換性のある強力な新しいカメラ、OV5640を販売しており、購入された場合はカメラを交換して使用できます。

OV5640の詳細なパラメータ情報が必要な場合は、以下のチャートを参照してください。

tip

Wikiのカメラに関するすべてのプログラムは、OV5640とOV2640の両方のカメラと互換性があります。

microSDカードの準備

XIAO ESP32S3 Senseは最大32GBのmicroSDカードをサポートしているため、XIAOのためにmicroSDカードを購入する予定の場合は、この仕様を参照してください。microSDカードを使用する前に、microSDカードをFAT32形式でフォーマットしてください。

フォーマット後、microSDカードをmicroSDカードスロットに挿入できます。挿入方向に注意してください。金色の接点がある面を内側に向けてください。

拡張ボード用カメラスロット回路設計

XIAO ESP32S3 Senseカードスロットは、ESP32-S3の14個のGPIOを占有し、占有するピンの詳細は以下の表に示されています。

ESP32-S3 GPIOCameraESP32-S3 GPIOCamera
GPIO10XMCLKGPIO11DVP_Y8
GPIO12DVP_Y7GPIO13DVP_PCLK
GPIO14DVP_Y6GPIO15DVP_Y2
GPIO16DVP_Y5GPIO17DVP_Y3
GPIO18DVP_Y4GPIO38DVP_VSYNC
GPIO39CAM_SCLGPIO40CAM_SDA
GPIO47DVP_HREFGPIO48DVP_Y9

PSRAMオプションを有効にする

ESP32のPSRAMは、ESP32チップ上の外部PSRAM(Pseudo Static Random Access Memory)を指し、追加のメモリ空間を提供してESP32システムの利用可能メモリを増加させます。ESP32システムにおいて、PSRAMには以下の主な用途があります:

  1. 利用可能RAMの拡張:ESP32の内蔵RAMは限られており、特に画像処理、音声処理など大量のメモリを必要とするアプリケーションでは、内蔵RAMでは不十分な場合があります。PSRAMを使用することで、ESP32の利用可能RAMを拡張し、これらのアプリケーションのニーズを満たすことができます。

  2. メモリアクセスの高速化:PSRAMは外部メモリであるため、アクセス速度は内部RAMより遅くなりますが、キャッシュや一時メモリとして使用することで、メモリアクセスとデータ処理を高速化できます。

  3. ストレージバッファ:ネットワークバッファ、オーディオバッファなど大きなバッファを必要とするアプリケーションでは、PSRAMが十分なストレージ空間を提供し、メモリ不足の状況を回避できます。

このチュートリアルの内容では、カメラが正常に動作することを保証するために、Arduino IDEのPSRAM機能を有効にする必要があります

カメラライブラリの概要

開始する前に、一般的なカメラ機能を理解するためにこの章を読むことをお勧めします。これにより、これらの機能を使用して独自のプロジェクト開発を完了したり、プログラムをより簡単に読むことができるようになります。

パート I: esp_camera.h

  1. カメラ初期化用の設定構造体。

以下は設定の例で、実際のピン状況に応じて記入してください。

static camera_config_t camera_example_config = {
.pin_pwdn = PWDN_GPIO_NUM,
.pin_reset = RESET_GPIO_NUM,
.pin_xclk = XCLK_GPIO_NUM,
.pin_sccb_sda = SIOD_GPIO_NUM,
.pin_sccb_scl = SIOC_GPIO_NUM,
.pin_d7 = Y9_GPIO_NUM,
.pin_d6 = Y8_GPIO_NUM,
.pin_d5 = Y7_GPIO_NUM,
.pin_d4 = Y6_GPIO_NUM,
.pin_d3 = Y5_GPIO_NUM,
.pin_d2 = Y4_GPIO_NUM,
.pin_d1 = Y3_GPIO_NUM,
.pin_d0 = Y2_GPIO_NUM,
.pin_vsync = VSYNC_GPIO_NUM,
.pin_href = HREF_GPIO_NUM,
.pin_pclk = PCLK_GPIO_NUM,

.xclk_freq_hz = 20000000, // The clock frequency of the image sensor
.fb_location = CAMERA_FB_IN_PSRAM; // Set the frame buffer storage location
.pixel_format = PIXFORMAT_JPEG, // The pixel format of the image: PIXFORMAT_ + YUV422|GRAYSCALE|RGB565|JPEG
.frame_size = FRAMESIZE_UXGA, // The resolution size of the image: FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
.jpeg_quality = 12, // The quality of the JPEG image, ranging from 0 to 63.
.fb_count = 2, // The number of frame buffers to use.
.grab_mode = CAMERA_GRAB_WHEN_EMPTY // The image capture mode.
};
  1. カメラドライバーを初期化します。

上記の形式で camera_example_config を設定した後、この関数を使用してカメラドライバーを初期化する必要があります。

esp_err_t esp_camera_init(const camera_config_t* config);
  • 入力パラメータ: カメラ設定パラメータ

  • 出力: 成功時にESP_OK

note

現在、この関数は一度だけ呼び出すことができ、このモジュールを初期化解除する方法はありません。

  1. フレームバッファへのポインタを取得します。
camera_fb_t* esp_camera_fb_get();

カメラフレームバッファのデータ構造:

typedef struct {
uint8_t * buf; /*!< Pointer to the pixel data */
size_t len; /*!< Length of the buffer in bytes */
size_t width; /*!< Width of the buffer in pixels */
size_t height; /*!< Height of the buffer in pixels */
pixformat_t format; /*!< Format of the pixel data */
struct timeval timestamp; /*!< Timestamp since boot of the first DMA buffer of the frame */
} camera_fb_t;
  1. Return the frame buffer to be reused again.
void esp_camera_fb_return(camera_fb_t * fb);
  • 入力パラメータ: フレームバッファへのポインタ
  1. 画像センサー制御構造体へのポインタを取得します。
sensor_t * esp_camera_sensor_get();
  • 出力: センサーへのポインタ
  1. カメラ設定を不揮発性ストレージ(NVS)に保存します。
esp_err_t esp_camera_save_to_nvs(const char *key);
  • 入力パラメータ: カメラ設定用の一意のnvsキー名
  1. 不揮発性ストレージ(NVS)からカメラ設定を読み込みます。
esp_err_t esp_camera_load_from_nvs(const char *key);
  • 入力パラメータ: カメラ設定用の一意のnvsキー名

パート II: img_converters.h

  1. 画像バッファをJPEGに変換する。
bool fmt2jpg_cb(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, jpg_out_cb cb, void * arg);
  • 入力パラメータ:

    • src: RGB565、RGB888、YUYV、またはGRAYSCALE形式のソースバッファ
    • src_len: ソースバッファの長さ(バイト単位)
    • width: ソース画像の幅(ピクセル単位)
    • height: ソース画像の高さ(ピクセル単位)
    • format: ソース画像の形式
    • quality: 結果画像のJPEG品質
    • cp: 出力JPEGのバイトを書き込むために呼び出されるコールバック
    • arg: コールバックに渡されるポインタ
  • 出力: 成功時にtrue

  1. カメラフレームバッファをJPEGに変換します。
bool frame2jpg_cb(camera_fb_t * fb, uint8_t quality, jpg_out_cb cb, void * arg);
  • 入力パラメータ:

    • fb: ソースカメラフレームバッファ
    • quality: 結果画像のJPEG品質
    • cp: 出力JPEGのバイトを書き込むために呼び出されるコールバック
    • arg: コールバックに渡されるポインタ
  • 出力: 成功時にtrue

  1. 画像バッファをJPEGバッファに変換します。
bool fmt2jpg(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, uint8_t ** out, size_t * out_len);
  • 入力パラメータ:

    • src: RGB565、RGB888、YUYV、またはGRAYSCALE形式のソースバッファ
    • src_len: ソースバッファの長さ(バイト単位)
    • width: ソース画像の幅(ピクセル単位)
    • height: ソース画像の高さ(ピクセル単位)
    • format: ソース画像の形式
    • quality: 結果画像のJPEG品質
    • out: 結果バッファのアドレスを格納するポインタ。使用後は必ずポインタを解放してください。
    • out_len: 出力バッファの長さを格納するポインタ
  • 出力: 成功時にtrue

  1. カメラフレームバッファをJPEGバッファに変換します。
bool frame2jpg(camera_fb_t * fb, uint8_t quality, uint8_t ** out, size_t * out_len);
  • 入力パラメータ:

    • fb: ソースカメラフレームバッファ
    • quality: 結果画像のJPEG品質
    • out: 結果バッファのアドレスで設定されるポインタ
    • out_len: 出力バッファの長さで設定されるポインタ
  • 出力: 成功時にtrue

  1. 画像バッファをBMPバッファに変換します。
bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t ** out, size_t * out_len);
  • 入力パラメータ:

    • src: RGB565、RGB888、YUYV、またはGRAYSCALE形式のソースバッファ
    • src_len: ソースバッファの長さ(バイト単位)
    • width: ソース画像の幅(ピクセル単位)
    • height: ソース画像の高さ(ピクセル単位)
    • format: ソース画像の形式
    • quality: 結果画像のJPEG品質
    • out: 結果バッファのアドレスを格納するポインタ
    • out_len: 出力バッファの長さを格納するポインタ
  • 出力: 成功時にtrue

  1. カメラフレームバッファをBMPバッファに変換します。
bool frame2bmp(camera_fb_t * fb, uint8_t ** out, size_t * out_len);
  • 入力パラメータ:

    • fb: ソースカメラフレームバッファ
    • quality: 結果画像のJPEG品質
    • cp: 出力JPEGのバイトを書き込むために呼び出されるコールバック
    • arg: コールバックに渡されるポインタ
  • 出力: 成功時にtrue

Part III: app_httpd.cpp

note

このライブラリ紹介の部分は、動画保存端末の作成 -- Based WebServerセクションに基づいています。このライブラリは主にWebサーバーの画像取得と顔認識機能を実行するために使用されます。ESP のオンボードパッケージには直接含まれていません。

  1. 顔認識機能。
static int run_face_recognition(fb_data_t *fb, std::list<dl::detect::result_t> *results)
  • 入力パラメータ:
    • fb: 画像データを含むフレームバッファを表す構造体へのポインタ。
    • results: 検出された顔の結果のリストへのポインタ。
  1. BMP画像ファイルのHTTPリクエストを処理します。
static esp_err_t bmp_handler(httpd_req_t *req)
  • 入力パラメータ: HTTP リクエストを表す構造体へのポインタ。
  1. JPEG 画像データをストリーミング方式でエンコードします。
static size_t jpg_encode_stream(void *arg, size_t index, const void *data, size_t len)
  • 入力パラメータ:
    • arg: 関数に渡されるユーザー定義引数へのポインタ。
    • index: 画像データ内の現在位置を示すインデックス値。
    • data: エンコードされる画像データを含むバッファへのポインタ。
    • len: データバッファの長さ。
  1. カメラからの画像キャプチャとストリーミングのHTTPリクエストを処理します。
static esp_err_t capture_handler(httpd_req_t *req)
  • 入力パラメータ: HTTP リクエストを表す構造体へのポインタ。
  1. カメラからのストリーミング動画の HTTP リクエストを処理します。
static esp_err_t stream_handler(httpd_req_t *req)
  • 入力パラメータ: HTTP リクエストを表す構造体へのポインタ。
  1. ビデオをキャプチャして HTTP 経由でストリーミングするカメラサーバーを初期化して開始します。
void startCameraServer()

カメラで写真を撮る

次に、カメラの最も基本的な使用方法から始めます。例えば、まずカメラを使用して画像取得を完了します。最初のプロジェクトではmicroSDカードを使用し、このプログラムの主なタスクは毎分カメラの映像を取得し、その映像をmicroSDカードに保存することです。

開始する前に、私が行ったようにmicroSDカードとカメラを取り付けてください。

以下のリンクから完全なプログラムコードと必要な依存ファイルを見つけることができます。

以下がこのプロジェクトのArduinoプログラムです。

#include "esp_camera.h"
#include "FS.h"
#include "SD.h"
#include "SPI.h"

#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM

#include "camera_pins.h"

unsigned long lastCaptureTime = 0; // Last shooting time
int imageCount = 1; // File Counter
bool camera_sign = false; // Check camera status
bool sd_sign = false; // Check sd status

// Save pictures to SD card
void photo_save(const char * fileName) {
// Take a photo
camera_fb_t *fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Failed to get camera frame buffer");
return;
}
// Save photo to file
writeFile(SD, fileName, fb->buf, fb->len);

// Release image buffer
esp_camera_fb_return(fb);

Serial.println("Photo saved to file");
}

// SD card write file
void writeFile(fs::FS &fs, const char * path, uint8_t * data, size_t len){
Serial.printf("Writing file: %s\n", path);

File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
if(file.write(data, len) == len){
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}

void setup() {
Serial.begin(115200);
while(!Serial); // When the serial monitor is turned on, the program starts to execute

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 = 20000000;
config.frame_size = FRAMESIZE_UXGA;
config.pixel_format = PIXFORMAT_JPEG; // for streaming
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12;
config.fb_count = 1;

// if PSRAM IC present, init with UXGA resolution and higher JPEG quality
// for larger pre-allocated frame buffer.
if(config.pixel_format == PIXFORMAT_JPEG){
if(psramFound()){
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
// Limit the frame size when PSRAM is not available
config.frame_size = FRAMESIZE_SVGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}
} else {
// Best option for face detection/recognition
config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
config.fb_count = 2;
#endif
}

// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}

camera_sign = true; // Camera initialization check passes

// Initialize SD card
if(!SD.begin(21)){
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();

// Determine if the type of SD card is available
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}

Serial.print("SD Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}

sd_sign = true; // sd initialization check passes

Serial.println("Photos will begin in one minute, please be ready.");
}

void loop() {
// Camera & SD available, start taking pictures
if(camera_sign && sd_sign){
// Get the current time
unsigned long now = millis();

//If it has been more than 1 minute since the last shot, take a picture and save it to the SD card
if ((now - lastCaptureTime) >= 60000) {
char filename[32];
sprintf(filename, "/image%d.jpg", imageCount);
photo_save(filename);
Serial.printf("Saved picture:%s\n", filename);
Serial.println("Photos will begin in one minute, please be ready.");
imageCount++;
lastCaptureTime = now;
}
}
}
note

このプログラムのコンパイルとアップロードには他に2つの依存関係が必要です。GitHubにアクセスして完全にダウンロードしてください。

XIAO ESP32S3用のプログラムをアップロードしてください。プログラムのアップロードが成功したら、シリアルモニターを開き、撮影したいオブジェクトにカメラを向けて調整し、1分間待ってください。撮影された写真はSDカードに保存されます。その後、XIAOは1分ごとに写真を撮影します。

microSDカードを取り外し、カードリーダーを使用して、カード内に保存された写真を確認できます。

プログラムの注釈

プログラムは、使用する必要があるカメラとSDカードのライブラリ、およびXIAO ESP32S3用に定義したピン依存ファイルのインポートから始まります。

次に、読みやすくするために、2つの関数を順次定義します。1つは撮影した画像をSDカードに保存する関数photo_save()で、もう1つはファイルを書き込む関数writeFile()です。

// Save pictures to SD card
void photo_save(const char * fileName) {
// Take a photo
camera_fb_t *fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Failed to get camera frame buffer");
return;
}
// Save photo to file
writeFile(SD, fileName, fb->buf, fb->len);

// Release image buffer
esp_camera_fb_return(fb);

Serial.println("Photo saved to file");
}

microSDカードに画像を保存する関数では、2つの主要なタスクが実行されます。1つ目は画像の取得で、2つ目はファイルを書き込む関数の呼び出しです。

画像の取得はesp_camera_fb_get()で行うことができ、画像情報はポインタfbに保存され、その後fbbufをSDカードに書き込むことができます。

Setup()関数では、プログラムの大部分がカメラピンの設定とカメラの初期化を行っており、デフォルトでそのまま適用できます。カメラのピクセルや品質に要件がある場合は、Camera Library Overview章で説明されている機能に従って内部の値を調整できます。

loop()関数で最後に行うことは、1分ごとに写真を撮影するように制御し、撮影した写真のファイル名サフィックスとして増分番号を付けることです。

if(camera_sign && sd_sign){
// Get the current time
unsigned long now = millis();

//If it has been more than 1 minute since the last shot, take a picture and save it to the SD card
if ((now - lastCaptureTime) >= 60000) {
char filename[32];
sprintf(filename, "/image%d.jpg", imageCount);
photo_save(filename);
Serial.printf("Saved picture:%s\n", filename);
Serial.println("Photos will begin in one minute, please be ready.");
imageCount++;
lastCaptureTime = now;
}
}

loop()を実行する前に、2つのフラグチェックcamera_signsd_signを設定します。これにより、写真の撮影と保存のタスクは、Setup()でカメラとSDカードのチェックが正常に実行された後に実行されることが保証されます。

プロジェクト I: ハンドヘルドカメラの製作

次に、上記の理論的知識を使用して、超小型の写真撮影デバイスを作成します。このプロジェクトの最終結果は、ライブカメラフィードがSeeed Studio Round Display for XIAOに表示され、撮影したいオブジェクトにロックオンしたときに、画面をタッチして写真を撮影し、microSDカードに記録することです。

事前準備

このプロジェクトを開始する前に、以下のハードウェアを事前に準備する必要があります。

Seeed Studio XIAO ESP32S3 SenseSeeed Studio Round Display for XIAO

このプロジェクトではXIAO用のRound Displayを使用するため、このプロジェクトのルーチンを実行する前に、**ディスプレイ拡張ボードのWiki環境設定**の内容を読み、必要なライブラリをインストールしてTFT環境を設定してください。

XIAO EPS32S3 SenseはSDカードスロットに接続された3つのプルアップ抵抗R4〜R6で設計されており、ラウンドディスプレイにもプルアップ抵抗があるため、両方を同時に使用するとSDカードを読み取ることができません。この問題を解決するには、XIAO ESP32S3 Sense拡張ボードのJ3を切断する必要があります。

tip

ただし、XIAO ESP32S3 SenseのmicroSDカードスロットを同時に使用する新しい方法を提供してくれたエンジニアMjrovaiに感謝する必要があります。これはソフトウェアレベルでも可能です。**彼の方法と手順**を参照できます。

J3を切断した後、XIAO ESP32S3 SenseのSDカードスロットは正常に動作しなくなるため、Round DisplayのSDカードスロットにmicroSDカードを挿入する必要があります。

次に、microSDカード、XIAO ESP32S3 Sense、Round Displayを順番にインストールしてください。

tip

ブレードでJ3接続を切断する際にカメラを傷つけないよう、最初にカメラモジュールを取り外すことをお勧めします。

具体的な操作

以下のリンクから完全なプログラムコードと必要な依存ファイルを見つけることができます。

以下がこのプロジェクトのArduinoプログラムです。

#include <Arduino.h>
#include <TFT_eSPI.h>
#include <SPI.h>
#include "esp_camera.h"
#include "FS.h"
#include "SD.h"
#include "SPI.h"

#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM
#define TOUCH_INT D7

#include "camera_pins.h"

// Width and height of round display
const int camera_width = 240;
const int camera_height = 240;

// File Counter
int imageCount = 1;
bool camera_sign = false; // Check camera status
bool sd_sign = false; // Check sd status

TFT_eSPI tft = TFT_eSPI();

// SD card write file
void writeFile(fs::FS &fs, const char * path, uint8_t * data, size_t len){
Serial.printf("Writing file: %s\n", path);

File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
if(file.write(data, len) == len){
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}

bool display_is_pressed(void)
{
if(digitalRead(TOUCH_INT) != LOW) {
delay(3);
if(digitalRead(TOUCH_INT) != LOW)
return false;
}
return true;
}

void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
// while(!Serial);

// Camera pinout
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 = 20000000;
// config.frame_size = FRAMESIZE_UXGA;
config.frame_size = FRAMESIZE_240X240;
// config.pixel_format = PIXFORMAT_JPEG; // for streaming
config.pixel_format = PIXFORMAT_RGB565;
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12;
config.fb_count = 1;

// if PSRAM IC present, init with UXGA resolution and higher JPEG quality
// for larger pre-allocated frame buffer.
if(config.pixel_format == PIXFORMAT_JPEG){
if(psramFound()){
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
// Limit the frame size when PSRAM is not available
config.frame_size = FRAMESIZE_SVGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}
} else {
// Best option for face detection/recognition
config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
config.fb_count = 2;
#endif
}

// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
Serial.println("Camera ready");
camera_sign = true; // Camera initialization check passes

// Display initialization
tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_WHITE);

// Initialize SD card
if(!SD.begin(D2)){
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();

// Determine if the type of SD card is available
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}

Serial.print("SD Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}

sd_sign = true; // sd initialization check passes

}

void loop() {
if( sd_sign && camera_sign){

// Take a photo
camera_fb_t *fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Failed to get camera frame buffer");
return;
}

if(display_is_pressed()){
Serial.println("display is touched");
char filename[32];
sprintf(filename, "/image%d.jpg", imageCount);
// Save photo to file
writeFile(SD, filename, fb->buf, fb->len);
Serial.printf("Saved picture:%s\n", filename);
imageCount++;
}

// Decode JPEG images
uint8_t* buf = fb->buf;
uint32_t len = fb->len;
tft.startWrite();
tft.setAddrWindow(0, 0, camera_width, camera_height);
tft.pushColors(buf, len);
tft.endWrite();

// Release image buffer
esp_camera_fb_return(fb);

delay(10);
}
}

プログラムをXIAO ESP32S3 Senseにアップロードします。アップロードが成功した後に画面が点灯しない場合は、XIAOのリセットボタンをクリックする必要があるかもしれません。その後、Round Displayにリアルタイムで監視画面が表示されます。画面上の任意の場所をクリックすると、画像が記録されてmicroSDカードに保存されます。

プログラムの注釈

カメラとmicroSDカードの設定は前の内容なので、ここでは繰り返しません。microSDカードの使用については、XIAO ESP32S3 SenseファイルシステムのWikiを参照して使用方法を学ぶことができます。

// Take a photo
camera_fb_t *fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Failed to get camera frame buffer");
return;
}

...

// Release image buffer
esp_camera_fb_return(fb);

delay(10);

上記のプログラムは、カメラを呼び出すための基本的なコードブロックであり、画面キャプチャ、例外終了、写真バッファの解放の3つの部分に分かれています。

if(display_is_pressed()){
Serial.println("display is touched");
char filename[32];
sprintf(filename, "/image%d.jpg", imageCount);
// Save photo to file
writeFile(SD, filename, fb->buf, fb->len);
Serial.printf("Saved picture:%s\n", filename);
imageCount++;
}

上記のプログラムは、画面がタッチされているかどうかをチェックするために使用されます。タッチされている場合、コードはキャプチャした画像をmicroSDカード上のファイルに保存します。

// Decode JPEG images
uint8_t* buf = fb->buf;
uint32_t len = fb->len;
tft.startWrite();
tft.setAddrWindow(0, 0, camera_width, camera_height);
tft.pushColors(buf, len);
tft.endWrite();

このコードの部分は、キャプチャした画像を画面に表示します。まず、camera_fb_t構造体から画像バッファとその長さを取得します。次に、画像データを受信するように画面を設定し、pushColors()関数を使用して画面に画像を表示します。

短い動画を録画してmicroSDカードに保存する

note

MCU上での動画エンコード出力は推奨しません。現在サポートされているエンコードライブラリのリソースが少なすぎて、操作が非常に複雑で面倒だからです。

この例では動画エンコードは含まれておらず、出力される動画はフレームごとのAVIのMJPG合成であるため、動画録画は特に良好で満足のいくものではない可能性があります。このチュートリアルの目的は、短い動画を録画するための簡単な方法とアイデアを提供することであり、より良いソリューションを持つパートナーからのPR提出を歓迎します。

前の章では、カメラを使用して画像をキャプチャする方法を習得しました。単一の画像を繋ぎ合わせて動く動画画像を作ることができることを知っています。この理論に基づいて、この章のプロジェクトでは、1分ごとに10秒間の動画を録画し、microSDカードに保存するプログラムの書き方をガイドします。

以下のリンクから完全なプログラムコードと必要な依存ファイルを見つけることができます。

以下がこのプロジェクトのArduinoプログラムです。

#include "esp_camera.h"
#include "FS.h"
#include "SD.h"
#include "SPI.h"
#include "esp_timer.h"

#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM

#include "camera_pins.h"

const int SD_PIN_CS = 21;

File videoFile;
bool camera_sign = false;
bool sd_sign = false;
unsigned long lastCaptureTime = 0;
unsigned long captureDuration = 10000; // 10 seconds
int imageCount = 0;

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

// Initialize the camera
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 = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
config.frame_size = FRAMESIZE_SVGA;
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12;
config.fb_count = 1;

// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}

camera_sign = true;

// Initialize the SD card
if (!SD.begin(SD_PIN_CS)) {
Serial.println("SD card initialization failed!");
return;
}

uint8_t cardType = SD.cardType();

// Determine if the type of SD card is available
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}

Serial.print("SD Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}

sd_sign = true;

Serial.println("Video will begin in one minute, please be ready.");
}

void loop() {
// Camera & SD available, start taking video
if (camera_sign && sd_sign) {
// Get the current time
unsigned long now = millis();

//If it has been more than 1 minute since the last video capture, start capturing a new video
if ((now - lastCaptureTime) >= 60000) {
char filename[32];
sprintf(filename, "/video%d.avi", imageCount);
videoFile = SD.open(filename, FILE_WRITE);
if (!videoFile) {
Serial.println("Error opening video file!");
return;
}
Serial.printf("Recording video:%s\n", filename);
lastCaptureTime = now;

// Start capturing video frames
while ((millis() - lastCaptureTime) < captureDuration) {
camera_fb_t *fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Error getting framebuffer!");
break;
}
videoFile.write(fb->buf, fb->len);
esp_camera_fb_return(fb);
}

// Close the video file
videoFile.close();
Serial.printf("Video saved: %s\n", filename);
imageCount++;

Serial.println("Video will begin in one minute, please be ready.");

// Wait for the remaining time of the minute
delay(60000 - (millis() - lastCaptureTime));
}
}
}

コードをXIAO ESP32S3 Senseにアップロードし、シリアルモニターを開きます。この時、記録したいオブジェクトにカメラの位置を調整してください。1分後、XIAOのオレンジ色のLEDが点滅し始め、録画が開始されてmicroSDカードに保存されます。

note

プログラムにはエンコーディングやフレームレートなどの設定が含まれていないため、録画された映像の各フレームに変化がない場合、ビデオは1秒間しか再生されない可能性があります。

プログラムの注釈

ビデオ録画手順の核心と鍵は、連続した10秒間にわたって写真ストリームを取得し続け、それをmicroSDカードに継続的に書き込むことです。

// Start capturing video frames
while ((millis() - lastCaptureTime) < captureDuration) {
camera_fb_t *fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Error getting framebuffer!");
break;
}
videoFile.write(fb->buf, fb->len);
esp_camera_fb_return(fb);
}

その上で、外側に1分間の待機判定のレイヤーをネストして、動画が1分ごとに開始されることを確実にします。

//If it has been more than 1 minute since the last video capture, start capturing a new video
if ((now - lastCaptureTime) >= 60000) {

...

delay(60000 - (millis() - lastCaptureTime));
}

プロジェクト II: ビデオストリーミング

このチュートリアルの最後に、ビデオストリーミングプロジェクトを紹介しましょう。このプロジェクトでは、XIAO ESP32S3 Senseによって作成されたWebページでライブビデオストリームを見ることができ、いくつかのパラメータを設定することで画面の表示を変更できます。

完全なプログラムコードと必要な依存ファイルは、以下のリンクから見つけることができます。

Arduino で 2.0.x バージョンの esp32 boards パッケージを使用している場合は、以下からダウンロードしてください:

Arduino で 3.0.x バージョンの esp32 boards パッケージを使用している場合は、以下からダウンロードしてください:

以下は、このプロジェクトのArduinoプログラムです。

#include "esp_camera.h"
#include <WiFi.h>

#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM

#include "camera_pins.h"

// ===========================
// Enter your WiFi credentials
// ===========================
const char* ssid = "**********";
const char* password = "**********";

void startCameraServer();
void setupLedFlash(int pin);

void setup() {
Serial.begin(115200);
while(!Serial);
Serial.setDebugOutput(true);
Serial.println();

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 = 20000000;
config.frame_size = FRAMESIZE_UXGA;
config.pixel_format = PIXFORMAT_JPEG; // for streaming
//config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12;
config.fb_count = 1;

// if PSRAM IC present, init with UXGA resolution and higher JPEG quality
// for larger pre-allocated frame buffer.
if(config.pixel_format == PIXFORMAT_JPEG){
if(psramFound()){
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
// Limit the frame size when PSRAM is not available
config.frame_size = FRAMESIZE_SVGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}
} else {
// Best option for face detection/recognition
config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
config.fb_count = 2;
#endif
}

// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}

sensor_t * s = esp_camera_sensor_get();
// initial sensors are flipped vertically and colors are a bit saturated
if (s->id.PID == OV3660_PID) {
s->set_vflip(s, 1); // flip it back
s->set_brightness(s, 1); // up the brightness just a bit
s->set_saturation(s, -2); // lower the saturation
}
// drop down frame size for higher initial frame rate
if(config.pixel_format == PIXFORMAT_JPEG){
s->set_framesize(s, FRAMESIZE_QVGA);
}

// Setup LED FLash if LED pin is defined in camera_pins.h
#if defined(LED_GPIO_NUM)
setupLedFlash(LED_GPIO_NUM);
#endif

WiFi.begin(ssid, password);
WiFi.setSleep(false);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");

startCameraServer();

Serial.print("Camera Ready! Use 'http://");
Serial.print(WiFi.localIP());
Serial.println("' to connect");
}

void loop() {
// Do nothing. Everything is done in another task by the web server
delay(10000);
}

プログラムをアップロードする前に、コード内のWiFi名とパスワードを自分のものに変更する必要があります。プログラムをアップロードした後、XIAO ESP32C3が正常にWiFiに接続されると、そのIPアドレスが出力されます。

caution

XIAO ESP32S3 このプロジェクトを長時間実行する場合は、放熱に注意してください。XIAOは非常に熱くなりますので、やけどにご注意ください!

tip

上図のように、デバッグ情報の出力をオンにすると、シリアルモニターにチップカーネルのデバッグ情報が出力される場合があります。例えば [0;31mE (2947) MFN: Partition Not found[0m などですが、心配する必要はありません。プログラムの実行には影響しません。

ブラウザを開いてください。EdgeまたはGoogle Chromeを推奨します。そのIPアドレスを入力すると、ビデオの設定ページが表示されます。

note

ブラウザを使用するデバイスは、XIAOと同じLAN内にある必要があります。

設定したいビデオストリームの仕様を設定した後、左側のツールバーの下部にあるStart Streamをクリックすると、カメラのライブフィードが表示されます。

幸い、ESP32は公式に顔認識機能もプログラムに追加しています。画質を下げて顔認識のボタンスイッチをオンにすることで、この機能を体験できます。

tip

パフォーマンス上の理由から、画面の品質はCIFより高くできません。そうでなければ、顔認識のスイッチをオンにしたときにWebページでエラーがポップアップします。

おお、私の大きな顔が囲まれています。

OV5640 オートフォーカス

ハードウェアの準備

XIAO ESP32S3 Sense用OV5640カメラ

ソフトウェア準備

方法1

オープンソースコードを提供してくださった @Eric に特別な感謝を

コード例

#include "esp_camera.h"
#include <WiFi.h>
#include "ESP32_OV5640_AF.h"

#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM

#include "camera_pins.h"

const char* ssid = "";
const char* password = "";

void startCameraServer();
void setupLedFlash(int pin);
OV5640 ov5640 = OV5640();

void setup() {
Serial.begin(115200);
while(!Serial);
Serial.setDebugOutput(true);
Serial.println();

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 = 20000000;
config.frame_size = FRAMESIZE_UXGA;
config.pixel_format = PIXFORMAT_JPEG; // for streaming
//config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12;
config.fb_count = 1;

// if PSRAM IC present, init with UXGA resolution and higher JPEG quality
// for larger pre-allocated frame buffer.
if(config.pixel_format == PIXFORMAT_JPEG){
if(psramFound()){
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
// Limit the frame size when PSRAM is not available
config.frame_size = FRAMESIZE_SVGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}
} else {
// Best option for face detection/recognition
config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
config.fb_count = 2;
#endif
}

// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}

sensor_t * s = esp_camera_sensor_get();
ov5640.start(s);

if (ov5640.focusInit() == 0) {
Serial.println("OV5640_Focus_Init Successful!");
}

if (ov5640.autoFocusMode() == 0) {
Serial.println("OV5640_Auto_Focus Successful!");
}

// Setup LED FLash if LED pin is defined in camera_pins.h
#if defined(LED_GPIO_NUM)
setupLedFlash(LED_GPIO_NUM);
#endif

WiFi.begin(ssid, password);
WiFi.setSleep(false);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");

startCameraServer();

Serial.print("Camera Ready! Use 'http://");
Serial.print(WiFi.localIP());
Serial.println("' to connect");
}

void loop() {
uint8_t rc = ov5640.getFWStatus();
Serial.printf("FW_STATUS = 0x%x\n", rc);

if (rc == -1) {
Serial.println("Check your OV5640");
} else if (rc == FW_STATUS_S_FOCUSED) {
Serial.println("Focused!");
} else if (rc == FW_STATUS_S_FOCUSING) {
Serial.println("Focusing!");
}
}

結果チャート

tip

フォーカス効果を確認するには解像度が1280*1024以上である必要があります。フォーカス時に画面が遅延し、しばらく画面を待つ必要があります。

方法2

tip

フォーカス効果を確認するには解像度が1600*1200以上である必要があります。フォーカス時に画面が遅延し、しばらく画面を待つ必要があります。

以下のzipファイルをダウンロードしてArudinoに追加してください

tip

方法1と方法2のライブラリ内のOV5640は同時に存在できません

#include "esp_camera.h"
#include <WiFi.h>
#include "ESP32_OV5640_AF.h"

#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM

#include "camera_pins.h"

const char *ssid = "";
const char *password = "";

void startCameraServer();
void setupLedFlash(int pin);
OV5640 ov5640 = OV5640();

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 = 20000000;
config.frame_size = FRAMESIZE_UXGA;
config.pixel_format = PIXFORMAT_JPEG;
config.grab_mode = CAMERA_GRAB_LATEST;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 10;
config.fb_count = 2;

if(psramFound()){
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
// Limit the frame size when PSRAM is not available
config.frame_size = FRAMESIZE_SVGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}

esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}

// auto focus
#if 1
sensor_t* sensor = esp_camera_sensor_get();
int ret = 0;
ov5640.start(sensor);

if (ov5640.focusInit() == 0) {
Serial.println("OV5640_Focus_Init Successful!");
} else {
Serial.println("OV5640_Focus_Init Failed!");
}

ret = ov5640.autoFocusMode(false);
if (ret == 0) {
Serial.println("OV5640_Auto_Focus Successful!");
} else {
Serial.printf("OV5640_Auto_Focus Failed! - [%d]\n", ret);
}
#endif

WiFi.begin(ssid, password);
WiFi.setSleep(false);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected");

startCameraServer();

Serial.printf("Camera Ready! Use 'http://%s' to connect\n", WiFi.localIP().toString().c_str());
}

void loop() {
if (Serial.available()) {
sensor_t* sensor = esp_camera_sensor_get();
int ret = 0;

switch (Serial.read()) {
case 'b':
ret = sensor->set_reg(sensor, 0x3022, 0xff, 0x03);
Serial.printf("begin to auto focus - %d\n", ret);
break;
case 's':
ret = sensor->set_reg(sensor, 0x3022, 0xff, 0x06);
Serial.printf("focus stop here - %d\n", ret);
break;
}
}

uint8_t rc = ov5640.getFWStatus();
Serial.printf("FW_STATUS = 0x%x\n", rc);

if (rc == -1) {
Serial.println("Check your OV5640");
} else if (rc == FW_STATUS_S_FOCUSED) {
Serial.println("Focused!");
} else if (rc == FW_STATUS_S_FOCUSING) {
Serial.println("Focusing!");
} else {
}

delay(1000);
}
tip

モード1は、モード2よりも集束効果が顕著で、よりシャープな画像を提供するため推奨されます。

トラブルシューティング

Q1: XIAO ESP32S3 SenseとRound Displayを一緒に使用する場合、J3ピンをカットする必要がありますか?どのSDカードスロットが使用できますか?

A: 原則として、XIAO ESP32S3 SenseをRound Displayと一緒に使用してmicroSDカードを使用する場合は、J3ピンをカットする必要があります。理由は、両方の拡張ボードの回路設計にプルアップ抵抗があるため、理論的には2つのプルアップ抵抗が同時に動作すると、SDカードスロットが正常に動作しないからです。SDカードのマウント失敗のエラーメッセージが表示されます。Round Display上のプルアップ抵抗はブロックできないため、両方を一緒に使用する際に1つのプルアップ抵抗のみが動作するように、senseエクスパンションボード上のJ3をカットする必要があります。これにより、両方を一緒に使用する場合、Round Display上のSDカードスロットのみがアクティブになることが決まります。

しかし、XIAO ESP32S3 Sense上のmicroSDカードスロットを同時に使用する新しい方法を提供してくれたエンジニアMjrovaiに感謝する必要があります。これはソフトウェアレベルでも可能です。**彼の方法と手順**を参照できます。

技術サポートと製品ディスカッション

弊社製品をお選びいただきありがとうございます!弊社製品での体験が可能な限りスムーズになるよう、さまざまなサポートを提供いたします。異なる好みやニーズに対応するため、複数のコミュニケーションチャンネルを提供しています。

Loading Comments...