部品 · 読了まで17分

ESP32-CAMの使い方:セットアップ、プログラミング、ライブ配信、SDカード

ESP32-CAMのプログラム方法:AI-Thinkerのピン配置、ESP32-CAM-MBとUSB-TTLでの書き込み、CameraWebServer、PSRAM、0x105とブラウンアウトの対処、フラッシュLED、SDカードへの写真保存を解説します。

ESP32-CAMは、わずか27 × 40 mmの大きさにESP32プロセッサ、200万画素のOV2640カメラ、microSDカードスロット、白いフラッシュLEDを載せた、手ごろなWi-Fiカメラボードです。単体で家のネットワークに接続し、ブラウザにライブ映像を配信し、写真を撮ってSDカードに保存したり、インターネットで送ったりできます。防犯カメラ、ドアホンのカメラ、植物の成長のタイムラプス、映像付きのロボットカーの定番ボードですが、USBコネクタがないため、使い慣れたESP32ボードとは始め方が少し違います。

このガイドでは、AI-Thinker ESP32-CAMのピン配置、ESP32-CAM-MBアダプターやUSB-TTL変換モジュールでのプログラム方法(IO0-GNDの接続を含む)、既製のCameraWebServerの例でブラウザにライブ映像を映す方法、使うべきPSRAMとパーティションの設定を学びます。続いて、よくあるCamera init failed with error 0x105(カメラの初期化に失敗)やブラウンアウトのエラーの原因を確認し、フラッシュLEDを制御し、ボタンを押すとmicroSDカードに写真を保存するスケッチを作ります。

AI-Thinker ESP32-CAMカメラモジュール
ESP32-CAM:ESP32-Sモジュール、OV2640カメラ、microSDスロット、フラッシュLEDを1枚のボードに載せています。USBコネクタがないので、プログラムするにはアダプターが必要です。

ESP32-CAMとは?そのしくみ

ボードの心臓部はESP32-Sモジュールで、Wi-FiとBluetoothを備えたデュアルコアのESP32チップを載せています。カメラは、細いリボンケーブル(FPC)でボード上の24ピンのコネクタに差し込まれています。ESP32はGPIO 0でカメラに20 MHzのクロック信号(XCLK)を送り、GPIO 26と27のI2Cに似たSCCBバスでカメラを設定します。OV2640センサーは自分で画像をJPEGに圧縮できるため、ESP32は生のピクセルではなく小さなJPEGのフレームを受け取ります。これらのフレームは8ビットのパラレルデータバスを通ってボードの4 MBのPSRAMに入り、Wi-Fiでブラウザやサーバーへ送られます。

項目値
プロセッサESP32(ESP32-Sモジュール)、デュアルコア、最大240 MHz
無線Wi-Fi 802.11 b/g/n(2.4 GHzのみ)、Bluetooth 4.2とBLE
メモリ内部SRAM 520 KB+PSRAM 4 MB、フラッシュ4 MB
カメラOV2640、2 MP、最大1600×1200(UXGA)、JPEG出力
ストレージmicroSDスロット(公式ドキュメントでは最大4 GB)
ライト白いフラッシュLED(GPIO 4)、裏の赤い状態表示LED(GPIO 33)
電源5Vピンに5 V(推奨)または3V3ピンに3.3 V
電流(5 V時)フラッシュ消灯時は約180 mA、フラッシュ最大輝度時は約310 mA。Wi-Fiのピークはさらに高い
大きさ27 × 40.5 × 4.5 mm

AI-Thinker ESP32-CAMのピン配置:空いているピンは?

ボードの両端には16本のピンがありますが、本当に空いているのはそのうちわずかです。カメラだけで15本のGPIOを使い、microSDスロットがさらに6本を共有しています。次の表は、端のピンと、それが使える条件をまとめたものです。ESP32の一般的なピンの機能はピン配置ツールでも調べられます。

ピン機能自由に使える?
5V電源入力(推奨)-
3V33.3 Vの電源入力-
GND(3本)グランド-
VCC電源出力(初期設定で3.3 V)ボードへの給電には使わない
U0R(GPIO 3)シリアルRX:プログラミングとシリアルモニタシリアルポートが不要な場合のみ
U0T(GPIO 1)シリアルTX:プログラミングとシリアルモニタシリアルポートが不要な場合のみ
GPIO 0カメラのクロック(XCLK)と起動モード不可。書き込み中だけGNDにつなぐ
GPIO 16多くのボードでPSRAMにつながっている不可
GPIO 2SD DATA0SDカードを使わない場合。ストラッピングピン
GPIO 4SD DATA1とフラッシュLEDSDの1ビットモード時、またはSDなしの場合
GPIO 12SD DATA2SDの1ビットモード時、またはSDなしの場合。起動時はLOWでなければならない
GPIO 13SD DATA3SDの1ビットモード時、またはSDなしの場合。もっとも安全な空きピン
GPIO 14SD CLKSDカードを使わない場合
GPIO 15SD CMDSDカードを使わない場合。ストラッピングピン
GPIO 33赤いLED(ピンヘッダーにはない)LED専用。LOWを書くと点く
VCCピンは入力ではありません。ボード上のレギュレーターの出力で、初期設定では3.3 Vを出しています。ここに5 Vをつなぐと3.3 Vのラインがそのまま5 Vに引き上げられ、ESP32が壊れるおそれがあるので、電源は必ず5Vピンに入れてください。また、起動時にGPIO 12がHIGHだと、ESP32はフラッシュを1.8 Vで動かそうとしてボードが起動しないので、このピンをHIGHに引き上げるプルアップ抵抗やモジュールをつながないでください。

ESP32-CAMのプログラム方法は?2つのやり方

ふつうのESP32ボードがパソコンと通信するためのUSBシリアル変換チップが、ESP32-CAMにはありません。コードを書き込むには2つの選択肢があります。ボードの下に差し込むESP32-CAM-MBアダプター(CH340チップとmicro USBコネクタを載せた小さな土台の基板)か、手持ちのUSB-TTL変換モジュール(FTDI、CH340、CP2102)です。どちらを選んでも考え方は同じです。起動時にGPIO 0がLOWならESP32はダウンロードモードに入ってコードを待ち、HIGHならフラッシュのプログラムを実行します。MBアダプターのIO0ボタンと、USB-TTL変換モジュールで加えるIO0-GNDの線は、まさにこの役目を果たします。

CP2102 USB-TTL変換モジュール
CP2102 USB-TTL変換モジュール:ESP32-CAMのプログラムに必要なのはGND、5V、TX、RXのピンだけです。
USB-TTL変換モジュールESP32-CAM備考
GNDGND共通のグランド
5V5Vボードに給電する。変換モジュールの3.3 V出力では足りない
TXU0R(GPIO 3)クロス接続:送信側を受信側へ
RXU0T(GPIO 1)クロス接続:受信側を送信側へ
-IO0とGNDの間書き込み中のみ。隣り合う2本のピンの間に短い線を入れる

変換モジュールに3.3 V / 5 Vの切り替えジャンパーがあるなら、TXの線がESP32のピンに合ったレベルになるよう3.3 Vに設定してください。ただし、ボードへの給電は変換モジュールの5Vピンから行います。ほとんどの変換モジュールの3.3 V出力は50〜100 mA程度しか供給できず、ESP32-CAMがWi-Fiをオンにした瞬間に電源が落ちてボードが再起動します。

Arduino IDEの設定:ボード、パーティションスキーム、PSRAM

  1. Arduino IDEでボードマネージャを開き、esp32 by Espressif Systemsパッケージをインストールします。くわしくはArduino IDEのセットアップのガイドで解説しています。
  2. 「ツール」>「ボード」>「esp32」からAI Thinker ESP32-CAMのボードを選びます。
  3. Partition SchemeがHuge APP (3MB No OTA/1MB SPIFFS)になっているか確認します。カメラの例には3 MB以上のアプリ領域が必要です。
  4. ボードをアダプターにつなぎ、「ツール」>「ポート」で新しいポートを選びます(WindowsではCOMx、macOSでは/dev/cu.usbserial...か/dev/cu.wchusbserial...)。
  5. ポートがまったく表示されなければ、CH340かCP2102のドライバをインストールし、データ通信ができるUSBケーブルを使ってください。
設定推奨値理由
ボードAI Thinker ESP32-CAMPSRAM、4 MBのフラッシュ、正しいパーティションスキームがあらかじめ設定されている
Partition SchemeHuge APP (3MB No OTA/1MB SPIFFS)CameraWebServerに必要な3 MBのアプリ領域
PSRAMこのボード定義では常にオンESP32 Dev ModuleではPSRAM: Enabledにする。ESP32 Wrover Moduleでは最初からオン
CPU Frequency240MHz (WiFi/BT)画像の転送とWi-Fiに最高速度
Flash Mode / Flash FrequencyQIO / 80MHz書き込みや起動に失敗するならDIO / 40MHzを試す
Core Debug LevelNone(トラブル調査時はInfo)Infoにすると、カメラとFPSの詳細がシリアルモニタに表示される
Upload Speed460800(このボードでは固定)書き込みがよく途切れるなら、ESP32 Wrover Moduleを選んで115200を試す
シリアルモニタは必ず115200 baudで開いてください。ブートメッセージはリセットの瞬間にしか表示されないので、画面が空なら、ボードのRSTボタンを押してください。waiting for download(ダウンロード待ち)と表示されるなら、IO0がまだGNDにつながっています。線を外してもう一度RSTを押すと、プログラムが動き始めます。

最初の書き込みをステップごとに

  1. 配線します。ピンをそろえてボードをMBアダプターに差し込むか、上の表のとおりにUSB-TTL変換モジュールをつなぎます。USB-TTL変換モジュールを使うなら、IO0とGNDの間の短い線も加えます。
  2. ボードをダウンロードモードにします。MBアダプターでは、IO0ボタンを押したままRSTを押して離し、それからIO0を離します。USB-TTL変換モジュールでは、IO0-GNDの線をつないだ状態でRSTを押すだけです。自動リセット回路のあるMBアダプターの中には、ボタンを押さなくても書き込めるものもあります。
  3. Arduino IDEで書き込みをクリックします。出力にはまずConnecting...(接続中)と表示され、続いて書き込みの進み具合がパーセントで表示されます。
  4. Hard resetting via RTS pin...(RTSピンでハードリセット中)の行が表示されたら、書き込みは完了です。USB-TTL変換モジュールを使っているなら、ここでIO0-GNDの線を外します。
  5. シリアルモニタを115200 baudで開き、RSTを押します。新しいプログラムが動き始めます。
C++ (Arduino IDE)
1// ESP32-CAM ilk yükleme testi / ESP32-CAM first upload test
2const int KIRMIZI_LED = 33;   // arkadaki kırmızı LED, ters mantık / red LED on the back, inverted logic
3
4void setup() {
5  Serial.begin(115200);
6  pinMode(KIRMIZI_LED, OUTPUT);
7  delay(500);
8
9  // PSRAM kontrolü / PSRAM check
10  if (psramFound()) {
11    Serial.print("PSRAM bulundu / PSRAM found: ");
12    Serial.print(ESP.getPsramSize());
13    Serial.println(" bayt / bytes");
14  } else {
15    Serial.println("PSRAM yok / No PSRAM");
16  }
17}
18
19void loop() {
20  digitalWrite(KIRMIZI_LED, LOW);    // LOW = yanar / LOW = on
21  delay(500);
22  digitalWrite(KIRMIZI_LED, HIGH);   // HIGH = söner / HIGH = off
23  delay(500);
24}

書き込みがうまくいけば、ボードの裏の小さな赤いLEDが0.5秒ごとに点滅します。このLEDは反転ロジックで、LOWを書くと点き、HIGHで消えます。シリアルモニタには約400万バイトのPSRAMが表示されるはずです。No PSRAM(PSRAMなし)と表示されたらボードの選択を確認し、それでもだめならボードにPSRAMのチップがないのかもしれません。カメラの例の前にこの短いテストを行えば、問題が書き込みにあるのかカメラにあるのかがすぐにわかります。

CameraWebServerの例:ブラウザでライブ映像を見る

  1. 「ファイル」>「スケッチ例」>「ESP32」>「Camera」>「CameraWebServer」を開きます。
  2. カメラのモデルを選びます。board_config.hのタブ(新しいバージョン)か、メインファイルの先頭(古いバージョン)にある一覧で、CAMERA_MODEL_ESP_EYEの行の前に//を付け、CAMERA_MODEL_AI_THINKERの行の前の//を外します。
  3. ssidとpasswordの行に、2.4 GHzのWi-Fiネットワークの名前とパスワードを入力します。
  4. ボードをダウンロードモードにしてスケッチを書き込み、IO0の接続を外してRSTを押します。
  5. シリアルモニタにCamera Ready! Use 'http://192.168.1.45' to connect(カメラの準備完了)のような行が表示されます。そのアドレスを、同じネットワークにつないだスマートフォンかパソコンのブラウザで開きます。
  6. ページのStart Streamボタンでライブ映像を始めるか、Get Stillで写真を1枚撮ります。
C++ (Arduino IDE)
1// board_config.h (eski sürümlerde CameraWebServer.ino) / (CameraWebServer.ino in older versions)
2//#define CAMERA_MODEL_ESP_EYE      // Has PSRAM  <- kapat / comment out
3#define CAMERA_MODEL_AI_THINKER     // Has PSRAM  <- aç / enable
4
5// CameraWebServer.ino
6const char *ssid = "AgAdi";          // Wi-Fi adı / Wi-Fi name
7const char *password = "Sifre123";   // Wi-Fi şifresi / Wi-Fi password

画面は2つの別々のサーバーで動いています。設定ページと、写真を1枚返す/captureのアドレスは80番ポートに、ライブ配信は81番ポートの/streamにあります(例:http://192.168.1.45:81/stream)。この配信アドレスを、自分のWebページやホームオートメーションのソフトウェアに加えられます。左のメニューでは解像度、JPEGの画質、明るさ、コントラスト、ホワイトバランスを変えられ、映像が上下逆ならV-FlipとH-Mirrorのスイッチを使います。新しいバージョンには、フラッシュ用のLED Intensityのスライダーもあります。ボードはふつう一度に1人のライブ配信の視聴者にしか対応しないので、2つ目のタブで開いた配信は止まることがあります。ページがまったく開かないなら、スマートフォンとボードが同じネットワークにあるか確認してください。接続のトラブルはESP32がWi-Fiにつながらないときを参照してください。

ESP32-CAMの解像度とFPSの表

カタログ上、OV2640センサーは1600×1200で毎秒15フレーム、800×600で30フレーム、CIFサイズで60フレームを出せます。実際のフレームレートはおもにWi-Fiの接続とJPEGのフレームの大きさで決まります。解像度と画質を上げるほど各フレームは大きくなり、ネットワークを通るのが遅くなります。次の値は、Wi-Fiの信号がよく、JPEGの画質が10〜12のときに、CameraWebServerで見られるおおよその範囲です。自分のボードを測るにはCore Debug LevelをInfoに設定してください。配信中、シリアルモニタにはフレームごとにMJPG: ... (x fps)のような行が表示されます。

解像度ピクセルおおよそのFPS(Wi-Fi配信)向いている用途
QQVGA160×12025〜30動体検知、非常に弱いネットワーク
QVGA320×24020〜30ロボットカー、なめらかなライブ映像
CIF400×29615〜25小さな画面でのなめらかな視聴
VGA640×48010〜20汎用のライブ視聴
SVGA800×6008〜15よりくっきりした視聴。PSRAMなしで使える最大のサイズ
XGA1024×7685〜10細部まで見える画像
HD1280×7204〜8ワイド(16:9)の構図
SXGA1280×10243〜6写真
UXGA1600×12002〜5最高解像度の写真

自分のコードでは、カメラが正常に起動したあと、センサーのオブジェクトを通して解像度、画質、向きを変えられます。JPEGの画質は0〜63の数値で、数値が小さいほど高画質です。10を下回るとフレームが大きくなり、途中で切れた画像の原因になることがあります。

C++ (Arduino IDE)
1// esp_camera_init() başarılı olduktan sonra / after esp_camera_init() succeeds
2sensor_t *s = esp_camera_sensor_get();
3s->set_framesize(s, FRAMESIZE_VGA);   // 640x480 çözünürlük / resolution
4s->set_quality(s, 12);                // 0-63: küçük = daha kaliteli, 10 altı önerilmez / lower = better, below 10 not advised
5s->set_vflip(s, 1);                   // görüntüyü dikey çevir / flip vertically
6s->set_hmirror(s, 1);                 // yatay ayna / mirror horizontally
7s->set_brightness(s, 1);              // parlaklık -2..2 / brightness -2..2

なぜESP32-CAMではPSRAMの設定がそれほど重要なのか

ESP32の内部メモリは520 KBで、その大部分をWi-Fiのスタックが使います。一方、1600×1200のJPEGのフレーム1枚は、場面と画質によって100〜250 KBになります。そのため、カメラのドライバはフレームバッファをPSRAMに置きます。CameraWebServerはpsramFound()関数でPSRAMの有無を確認します。あれば最高解像度とフレームバッファ2つで始め、なければ解像度をSVGA(800×600)に制限し、内部メモリにバッファを1つだけ置きます。

PSRAMが有効になっていないのに高い解像度を求めると、シリアルモニタにframe buffer malloc failed(フレームバッファを確保できない)、続いてCamera init failed with error 0xffffffffと表示されます。解決策は、ボードにAI Thinker ESP32-CAMを選ぶ(ESP32 Dev Moduleなら「ツール」> PSRAM: Enabledにする)か、解像度を下げてフレームバッファの数を1に減らすことです。安価な互換品の中にはPSRAMのチップがまったくないものもあります。最初のテスト用スケッチのPSRAMの行を見れば、すぐにわかります。

Camera init failed with error 0x105とそのほかのカメラのエラー

カメラのエラーのほとんどは、3つの原因のどれかにたどり着きます。コードのカメラのモデルが違う、リボンケーブルがコネクタにきちんと差さっていない、または電源が不十分です。シリアルモニタのエラーコードを読めば、原因をすぐに絞り込めます。

シリアルモニタのメッセージ意味対処法
Camera probe failed with error 0x105(ESP_ERR_NOT_FOUND)(カメラが見つからない)ESP32がSCCBバス上にカメラを見つけられなかったCAMERA_MODEL_AI_THINKERが選ばれているか確認し、リボンケーブルを差し直し、ボードを5 V / 2 Aで給電する
Detected camera not supported(未対応のカメラ)と0x106新しいドライバのバージョンでの同じ状況:カメラが見つからないか認識されない0x105と同じ手順。続くならカメラモジュールを交換する
frame buffer malloc failed(フレームバッファを確保できない)と0xffffffffフレームバッファ用のメモリを確保できなかったPSRAMを有効にし、解像度を下げ、fb_countを1にする
cam_hal: EV-VSYNC-OVFまたはFB-OVF前のフレームを処理する前に新しいフレームが届き、フレームが飛ばされたときどきなら無害。頻繁なら解像度を下げ、Wi-Fiの信号を改善する
NO-SOI(JPEGの開始マーカーがない)壊れた、または不完全なJPEGのフレーム電源とリボンケーブルを確認し、xclk_freq_hzを10000000にする
画像の半分が欠ける、緑色になる、縞模様になるフレームがバッファに収まらなかった、または電源にノイズがあるJPEGの画質の値を12以上に上げ、電源を改善する
リボンケーブルを差すときは、コネクタの黒いロック用のフラップを持ち上げ、ケーブルをまっすぐ奥まで押し込み、フラップを閉じます。ボードに電源が入っている間は、カメラを抜き差ししないでください。カメラとESP32の両方が壊れることがあります。また、新しいカメラモジュールのレンズの保護フィルムをはがすのも忘れずに。はがさないと映像がぼやけて見えます。

ブラウンアウトのエラーと正しい電源(5 V / 2 A)

シリアルモニタにBrownout detector was triggered(電圧低下を検出)と表示されてボードが再起動を繰り返すなら、ESP32の電源電圧が一瞬、安全なレベルを下回っています。ESP32-CAMは、Wi-Fiの送信機をオンにしてカメラが撮影を始める瞬間に、短いものの大きな電流のピークを引き込みます。電力の弱いUSBポート、細くて長いジャンパーワイヤー、変換モジュールの3.3 V出力では、このピークに追いつけません。根本的な解決策は次のとおりです。

  • 5 Vで2 A以上を供給できる電源を使い、ボードの5Vピンにつなぎます。ボード上のレギュレーターが3.3 Vに下げます。
  • 電源の線は短く太くします。ブレッドボードや長いジャンパーワイヤーは電圧降下を大きくします。
  • ボードの5VとGNDのピンの間、できるだけボードの近くに470〜1000 µFの電解コンデンサを入れます(プラスの足を5Vに)。
  • パソコンから給電するなら、USBハブではなく、パソコンの背面のポートに直接つなぎます。
  • 電池で動かすなら、18650セルと5 Vの昇圧モジュールを使います。単3電池を何本もつなぐよりずっと安定します。
18650リチウムイオン電池
18650リチウムイオンセル:5 Vの昇圧モジュールと組み合わせれば、電池で動くESP32-CAMのプロジェクトに安定した電源を供給できます。

ネットでは、コードでブラウンアウト検出を無効にするWRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0)の行をよく見かけます。これで再起動は止まりますが、問題は解決しません。電圧は下がり続け、今度はボードが固まったり、壊れたフレームを出したり、フラッシュへの書き込み中にデータを失ったりすることがあります。一時的なテストにだけ使ってください。再起動のメッセージの一覧はESP32のブラウンアウトとGuru Meditationのガイドにあります。電池の持ちを見積もるときは、連続配信中のボードの消費電流を平均180 mAと考えてください。2600 mAhの18650を効率85%の昇圧コンバーターで使うと、5 V側では約1600 mAhとなり、配信できるのはおよそ9時間です。自分の数値は電池寿命計算ツールで計算できます。ディープスリープ中でも、レギュレーターとPSRAMのためにボードが約6 mAを消費することを忘れないでください。

フラッシュLEDを制御する(GPIO 4)

ボードの表にある明るい白いLEDは、GPIO 4につながったトランジスタを通して駆動されています。ピンはトランジスタを切り替えるだけで、LEDの大きな電流は電源ラインから流れます。digitalWrite(4, HIGH)で点き、LOWで消えます。LEDはとても明るく、長く点けたままにするとLEDもボードも熱くなるので、フラッシュは写真を撮る間の数百ミリ秒だけ点けるのがおすすめです。GPIO 4はmicroSDカードのDATA1の線でもあるため、カードを4ビットモードで動かすと、読み書きのたびにフラッシュが勝手に点滅します。これを防ぐには、SDカードを1ビットモード(SD_MMC.begin("/sdcard", true))で始めてください。ボードによっては、それでもLEDがごくかすかに光ることがあります。

ESP32-CAMでmicroSDカードに写真を保存する

次のスケッチは、GPIO 13のボタンを押すたびにフラッシュを点け、1600×1200で写真を撮り、microSDカードにfoto1.jpg、foto2.jpg...として保存します。microSDカードはパソコンでFAT32にフォーマットしてください。公式ドキュメントでは最大4 GBのカードとされていますが、実際には16〜32 GBのFAT32のカードもたいてい問題なく動きます。ボタンの片方の足をGPIO 13に、もう片方をGNDにつなぎます。スケッチが内部プルアップ抵抗を有効にするので、追加の抵抗は不要です。ボタンの配線のしくみはArduinoに押しボタンをつなぐ方法を参照してください。

C++ (Arduino IDE)
1#include "esp_camera.h"
2#include "FS.h"
3#include "SD_MMC.h"
4
5// AI-Thinker ESP32-CAM kamera pinleri / AI-Thinker ESP32-CAM camera pins
6#define PWDN_GPIO_NUM     32
7#define RESET_GPIO_NUM    -1
8#define XCLK_GPIO_NUM      0
9#define SIOD_GPIO_NUM     26
10#define SIOC_GPIO_NUM     27
11#define Y9_GPIO_NUM       35
12#define Y8_GPIO_NUM       34
13#define Y7_GPIO_NUM       39
14#define Y6_GPIO_NUM       36
15#define Y5_GPIO_NUM       21
16#define Y4_GPIO_NUM       19
17#define Y3_GPIO_NUM       18
18#define Y2_GPIO_NUM        5
19#define VSYNC_GPIO_NUM    25
20#define HREF_GPIO_NUM     23
21#define PCLK_GPIO_NUM     22
22
23#define FLAS_LED  4    // beyaz flaş LED'i / white flash LED
24#define BUTON    13    // butonun diğer ucu GND'de / other button leg to GND
25
26int fotoNo = 1;        // sıradaki dosya numarası / next file number
27bool hazir = false;    // kamera ve SD hazır mı? / are camera and SD ready?
28
29bool kameraBaslat() {
30  camera_config_t config = {};
31  config.ledc_channel = LEDC_CHANNEL_0;
32  config.ledc_timer   = LEDC_TIMER_0;
33  config.pin_d0 = Y2_GPIO_NUM;
34  config.pin_d1 = Y3_GPIO_NUM;
35  config.pin_d2 = Y4_GPIO_NUM;
36  config.pin_d3 = Y5_GPIO_NUM;
37  config.pin_d4 = Y6_GPIO_NUM;
38  config.pin_d5 = Y7_GPIO_NUM;
39  config.pin_d6 = Y8_GPIO_NUM;
40  config.pin_d7 = Y9_GPIO_NUM;
41  config.pin_xclk     = XCLK_GPIO_NUM;
42  config.pin_pclk     = PCLK_GPIO_NUM;
43  config.pin_vsync    = VSYNC_GPIO_NUM;
44  config.pin_href     = HREF_GPIO_NUM;
45  config.pin_sccb_sda = SIOD_GPIO_NUM;
46  config.pin_sccb_scl = SIOC_GPIO_NUM;
47  config.pin_pwdn     = PWDN_GPIO_NUM;
48  config.pin_reset    = RESET_GPIO_NUM;
49  config.xclk_freq_hz = 20000000;           // 20 MHz kamera saati / 20 MHz camera clock
50  config.pixel_format = PIXFORMAT_JPEG;
51
52  if (psramFound()) {
53    config.frame_size   = FRAMESIZE_UXGA;   // 1600x1200
54    config.jpeg_quality = 10;               // küçük = daha kaliteli / lower = better quality
55    config.fb_count     = 2;
56    config.fb_location  = CAMERA_FB_IN_PSRAM;
57    config.grab_mode    = CAMERA_GRAB_LATEST;
58  } else {
59    config.frame_size   = FRAMESIZE_SVGA;   // PSRAM yoksa 800x600 / 800x600 without PSRAM
60    config.jpeg_quality = 12;
61    config.fb_count     = 1;
62    config.fb_location  = CAMERA_FB_IN_DRAM;
63    config.grab_mode    = CAMERA_GRAB_WHEN_EMPTY;
64  }
65
66  esp_err_t err = esp_camera_init(&config);
67  if (err != ESP_OK) {
68    Serial.printf("Camera init failed 0x%x (%s)\n", err, esp_err_to_name(err));
69    return false;
70  }
71  return true;
72}
73
74void fotoCek() {
75  digitalWrite(FLAS_LED, HIGH);              // flaşı yak / flash on
76  delay(150);                                // pozlama otursun / let exposure settle
77
78  camera_fb_t *fb = esp_camera_fb_get();     // eski kareyi at / discard the stale frame
79  if (fb) esp_camera_fb_return(fb);
80  fb = esp_camera_fb_get();                  // asıl fotoğraf / the real photo
81  digitalWrite(FLAS_LED, LOW);               // flaşı söndür / flash off
82
83  if (!fb) {
84    Serial.println("Kare alinamadi / Capture failed");
85    return;
86  }
87
88  String yol = "/foto" + String(fotoNo) + ".jpg";
89  File dosya = SD_MMC.open(yol, FILE_WRITE);
90  if (dosya) {
91    dosya.write(fb->buf, fb->len);           // JPEG verisini yaz / write the JPEG data
92    dosya.close();
93    Serial.printf("Kaydedildi / Saved: %s (%u bayt / bytes)\n", yol.c_str(), (unsigned)fb->len);
94    fotoNo++;
95  } else {
96    Serial.println("Dosya acilamadi / Could not open file");
97  }
98  esp_camera_fb_return(fb);                  // tamponu geri ver / return the buffer
99}
100
101void setup() {
102  Serial.begin(115200);
103  pinMode(BUTON, INPUT_PULLUP);
104
105  if (!kameraBaslat()) return;               // kamera yoksa dur / stop without a camera
106
107  // 1-bit mod: GPIO 4, 12 ve 13 boşta kalır / 1-bit mode keeps GPIO 4, 12 and 13 free
108  if (!SD_MMC.begin("/sdcard", true)) {
109    Serial.println("SD kart takilamadi / SD card mount failed");
110    return;
111  }
112  if (SD_MMC.cardType() == CARD_NONE) {
113    Serial.println("SD kart yok / No SD card");
114    return;
115  }
116
117  pinMode(FLAS_LED, OUTPUT);
118  digitalWrite(FLAS_LED, LOW);
119
120  // Var olan fotoğrafların üzerine yazma / don't overwrite existing photos
121  while (SD_MMC.exists("/foto" + String(fotoNo) + ".jpg")) fotoNo++;
122
123  hazir = true;
124  Serial.println("Hazir, butona bas / Ready, press the button");
125}
126
127void loop() {
128  if (!hazir) {                              // hata varsa bekle / wait if setup failed
129    delay(1000);
130    return;
131  }
132  if (digitalRead(BUTON) == LOW) {
133    delay(30);                               // buton sıçramasını (bounce) önle / debounce
134    if (digitalRead(BUTON) == LOW) {
135      fotoCek();
136      while (digitalRead(BUTON) == LOW) delay(10);   // bırakılmasını bekle / wait for release
137    }
138  }
139}

スケッチはSDカードを1ビットモードで始めるため、使うのはGPIO 2、14、15だけで、GPIO 4はフラッシュに、GPIO 13はボタンに空けておけます。写真を撮る前に、1枚のフレームを取得してすぐに返しています。カメラは常にフレームを作り続けているので、バッファの最初のフレームはフラッシュが点く前に撮られたものかもしれず、さらに自動露出が新しい光に合わせるのに少し時間が必要だからです。ファイル番号はカードにすでにあるファイルを見て決めるので、再起動しても古い写真が上書きされることはありません。SDカードへのデータ記録の一般的なルールはSDカードモジュールのガイドを見てみてください。

MicroPythonと新しいカメラボード

ESP32-CAMはMicroPythonでもプログラムできますが、公式のMicroPythonのビルドにはカメラのドライバが含まれていません。カメラ対応を加えたコミュニティのファームウェアを書き込む必要があります。そのため、初心者にはArduino IDEのほうがずっとスムーズです。USBコネクタのないボードを扱いたくないなら、USBとより多くのメモリを備えたESP32-S3ベースのカメラボード(例:Seeed XIAO ESP32S3 SenseやESP32-S3-EYE)も検討してください。これらのボードもCameraWebServerのモデルの一覧に入っています。

ESP32-CAMのプロジェクトアイデア

  • 動きを検知して撮影:PIRセンサーが人を見つけたら写真を撮り、スマートフォンに送ります。ステップごとの手順はESP32-CAMの写真をTelegramに送るにあります。
  • タイムラプス撮影:ボードを10分ごとに起こして写真を撮り、SDカードに保存してディープスリープに戻します。植物の成長や天気の移り変わりを観察できます。
  • ドアホンのカメラ:呼び鈴のボタンが押されたら玄関先を撮影し、Telegramのボットで通知を送ります。
  • 映像付きのロボットカー:スマートフォンでなめらかなQVGAのライブ映像を見ながら車を操作します。
  • ペットカメラ:家のネットワークでライブ映像を見て、必要ならWebページからフラッシュを点けます。
  • 自分だけのコントロールパネル:ライブ映像を自分のWebページに埋め込み、その横にリレーやセンサーの表示を加えます。ESP32 WebSocketのガイドが参考になります。

よくある間違いと対処法

症状考えられる原因対処法
Failed to connect to ESP32: No serial data received(シリアルデータを受信しない。古いバージョンではTimed out waiting for packet header)ボードがダウンロードモードになっていない、またはTXとRXが間違っているIO0をGNDにつなぐかIO0ボタンを使い、RSTを押す。TXがU0Rに、RXがU0Tにつながっているか確認する
Wrong boot mode detected (0x13)(起動モードが違う)起動時にGPIO 0がLOWになっていなかったIO0-GNDをつないだあと、必ずRSTを押す
シリアルモニタにwaiting for download(ダウンロード待ち)IO0がまだGNDにつながっているIO0の線を外してRSTを押す
シリアルモニタに文字化けした文字ボーレートが違うシリアルモニタを115200 baudに設定する
ポートの一覧にボードがないドライバがない、または充電専用ケーブルCH340かCP2102のドライバをインストールし、データ通信用ケーブルを使う
SDカードを差したままだと書き込みに失敗するGPIO 2はSDの線であり、ストラッピングピンでもある書き込み中はmicroSDカードを抜く
映像がとても遅い、またはよく止まるWi-Fiの信号が弱い、または解像度が高いVGAかQVGAに下げ、ボードをルーターに近づけ、必要なら外部アンテナを使う
フラッシュが常にかすかに光るSDカードが4ビットモード、またはGPIO 4が浮いているSDカードを1ビットモードで始め、GPIO 4をOUTPUTにしてLOWを書く
外部アンテナ(IPEX)を付けたい場合、ボードがどちらのアンテナを使うかは、アンテナの横にある小さな0 Ωの抵抗の位置で決まります。アンテナを差すだけでは不十分で、抵抗も付け替える必要があります。ボードが起動しない、またはSDカードが始まらないなら、GPIO 2、12、13につないだモジュールを外してもう一度試してください。GPIO 2と12はストラッピングピンで、GPIO 13はSDカードのDATA3の線であり、カードの初期化中はLOWであってはいけません。

ESP32-CAMは、手ごろなボードでWi-Fiカメラを作るいちばん簡単な方法で、ぶつかる難しさのほとんどはプログラミング用の接続か電源から来ています。この2つさえ正しくできれば、ボードは自分のWebサーバーからライブ映像を配信し、写真を撮ってSDカードに保存します。BlueGraysアプリには、Wi-Fi接続、Webサーバー、mDNS、microSDへのデータ記録、Telegram通知付きの動体アラームなどのESP32のプロジェクトが、ステップごとの回路図とすぐに使えるコード付きでそろっています。

よくある質問

ESP32-CAMはどうやってプログラムしますか?

ESP32-CAMにはUSBコネクタがないので、ESP32-CAM-MBアダプターかUSB-TTL変換モジュールが必要です。Arduino IDEでAI Thinker ESP32-CAMのボードを選び、GPIO 0をGNDにつないだ状態で(またはMBのIO0ボタンを押したまま)RSTを押して、ボードをダウンロードモードにします。書き込んだらIO0の接続を外し、もう一度RSTを押します。

Arduino UnoでESP32-CAMをプログラムできますか?

できます。UnoのRESETピンをGNDにつなぐと、そのUSBチップがUSBシリアルの橋渡しとして働きます。その場合の配線はクロスではなくストレートです。UnoのD0(RX)をU0Rに、D1(TX)をU0Tにつなぎ、IO0はやはりGNDにつなぎます。Unoの信号は5 Vなので、ESP32には限界ぎりぎりの負担がかかります。日常的に使うなら、MBアダプターか3.3 VのUSB-TTL変換モジュールのほうが安全です。

ESP32-CAMにはどの電圧が必要ですか?

5Vピンに5 Vで給電するのがおすすめです。ボード上のレギュレーターが3.3 Vに下げます。3V3ピンに3.3 Vを供給することもできますが、電源がWi-Fiの電流のピークに耐えられないと、ボードは再起動を繰り返します。2 A以上を供給できる電源なら、ブラウンアウトのエラーのほとんどを防げます。

ESP32-CAMのCamera init failedのエラーはどう直しますか?

エラーコード0x105か0x106は、カメラがまったく見つからなかったことを意味します。まずコードでCAMERA_MODEL_AI_THINKERが選ばれているか、次にリボンケーブルが奥まで差さっているかを確認し、ボードを5 V / 2 Aで給電してください。それでも続くなら、カメラモジュールが故障しているかもしれません。frame buffer malloc failedと一緒に0xffffffffが表示されるなら、PSRAMを有効にするか解像度を下げてください。

ESP32-CAMはインターネットなしで使えますか?

使えます。映像を見るのに必要なのはインターネットではなくローカルネットワークだけです。ESP32-CAMはWiFi.softAP()で自分のWi-Fiネットワークを作ることもでき、その場合はブラウザで192.168.4.1にアクセスします。ネットワークをまったく使わず、microSDカードに写真を保存するだけのカメラとして動かすこともできます。

ESP32-CAMで動画を録画できますか?

既製の例は、ライブ映像をMJPEGで配信し、写真を1枚ずつ撮るもので、動画ファイルを直接録画はしません。連続したJPEGのフレームをmicroSDカードに書いてAVIファイルを作るコミュニティのプロジェクトもありますが、低い解像度でもフレームレートは限られます。ボードにはマイクがないので、音も録音できません。

全プロジェクトを見る
ESP32でLEDを点滅
#103初級

ESP32でLEDを点滅

ESP32のGPIO出力の基本を学びます。デジタルピンからLEDを点灯・消灯させて、点滅させます。Arduino UNOの定番のLED点滅プロジェクトのESP32版です。Arduino環境で使う基本的な点滅コマンドは同じですが、ESP32のピン配置と3.3 VのGPIO電圧レベルはArduino UNOとは異なります。

4.7(37)
99
ESP32の内蔵LEDを点滅
#106初級

ESP32の内蔵LEDを点滅

ESP32 DevKit V1に内蔵された青色LEDを点滅させます。外付け部品は不要です!ESP32を購入したら、最初に試すプロジェクトです。GPIO 2が内蔵LEDにつながっています。

4.8(29)
53
ESP32 Wi-Fi STA接続(LCDディスプレイ付き)
#127上級

ESP32 Wi-Fi STA接続(LCDディスプレイ付き)

このプロジェクトでは、ESP32をステーション(STA)モードで家庭のWi-Fiネットワークに接続し、安全で障害に強い接続を実現します。SSIDとパスワードを別のsecrets.hファイルに保存してGitへの流出を防ぎ、自動再接続の仕組みを実装します。RSSIによる信号強度とIPアドレスはI2C LCDディスプレイに表示します。内蔵LEDは状態表示に使います。実運用を想定した接続管理の仕組みです。

4.4(21)
34
ESP32非同期Webサーバー(LCDにIPアドレスを表示)
#129上級

ESP32非同期Webサーバー(LCDにIPアドレスを表示)

このプロジェクトでは、ESP32を同じWi-Fiネットワーク上のスマートフォンやパソコンから操作できる非同期Webサーバーにします。ESPAsyncWebServerライブラリを使うと、従来のWebServer.hのように1つのリクエストで処理がブロックされず、複数のリクエストを同時に処理できます。ブラウザーでESP32のIPアドレスを開き、ON/OFFボタン(/onと/offのルート)を押すと、GPIO 5に接続したLEDを点灯・消灯できます。

4.8(16)
26
ESP32 mDNS:bluegrays-esp.localでデバイスにアクセス(LCD付き)
#131上級
プレミアム

ESP32 mDNS:bluegrays-esp.localでデバイスにアクセス(LCD付き)

このプロジェクトでは、ESP32にmDNS(Multicast DNS)サービスを追加し、IPアドレスの代わりにbluegrays-esp.localのような覚えやすいホスト名でアクセスできるようにします。DHCPで割り当てられるIPアドレスが変わっても、同じ名前でデバイスにアクセスできます。小さなWebサーバーも動かし、ブラウザーでhttp://bluegrays-esp.local/を開いてLEDを操作します。I2C LCDディスプレイにはホスト名、IPアドレス、LEDの状態をトルコ語と英語で表示します。iOS、macOS、LinuxはmDNSに標準対応しています。

4.8(14)
23
ESP32温度データロガー(DHT22 + DS1307 RTC + microSD + OLED)
#144上級
プレミアム

ESP32温度データロガー(DHT22 + DS1307 RTC + microSD + OLED)

ESP32で日時付きの温度・湿度記録システムを作ります!DHT22で1分ごとに温度と湿度を読み取り、DS1307 RTCから取得した日時とともにmicroSDカードへCSV形式で記録します。OLEDには最新の温度を大きな文字で表示し、湿度のパーセント値、日時、総記録数も表示します。SDカードの/temp_log.csvファイルはExcel、Google Sheets、Pythonのpandasで開いて分析できます。温室の監視、家や部屋の温度管理、実験室のデータ収集、食品の保管環境や養蜂箱の監視に適しています。

4.7(7)
12
ESP32動体検知アラーム(PIR + ブザー + LED + Telegram)
#145上級
プレミアム

ESP32動体検知アラーム(PIR + ブザー + LED + Telegram)

PIRセンサーが動きを検知するとブザーとLEDを作動させ、同時にTelegramで持ち主に即座に通知するスマート防犯アラームです。アラームが繰り返される頻度を抑えるため、30秒のクールダウン(待ち時間)を設けています。この仕組みはPIRの検知が正しいかを確認したり、誤検知をなくしたりするものではありません。家の防犯、ガレージの監視、倉庫や作業部屋などに使えます。ESP32-CAMなら写真付きの通知を追加でき、通常のESP32 DevKit V1ではテキストで通知します。

0.0(0)
9