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カードに写真を保存するスケッチを作ります。

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 | 電源入力(推奨) | - |
| 3V3 | 3.3 Vの電源入力 | - |
| GND(3本) | グランド | - |
| VCC | 電源出力(初期設定で3.3 V) | ボードへの給電には使わない |
| U0R(GPIO 3) | シリアルRX:プログラミングとシリアルモニタ | シリアルポートが不要な場合のみ |
| U0T(GPIO 1) | シリアルTX:プログラミングとシリアルモニタ | シリアルポートが不要な場合のみ |
| GPIO 0 | カメラのクロック(XCLK)と起動モード | 不可。書き込み中だけGNDにつなぐ |
| GPIO 16 | 多くのボードでPSRAMにつながっている | 不可 |
| GPIO 2 | SD DATA0 | SDカードを使わない場合。ストラッピングピン |
| GPIO 4 | SD DATA1とフラッシュLED | SDの1ビットモード時、またはSDなしの場合 |
| GPIO 12 | SD DATA2 | SDの1ビットモード時、またはSDなしの場合。起動時はLOWでなければならない |
| GPIO 13 | SD DATA3 | SDの1ビットモード時、またはSDなしの場合。もっとも安全な空きピン |
| GPIO 14 | SD CLK | SDカードを使わない場合 |
| GPIO 15 | SD CMD | SDカードを使わない場合。ストラッピングピン |
| GPIO 33 | 赤いLED(ピンヘッダーにはない) | LED専用。LOWを書くと点く |
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の線は、まさにこの役目を果たします。

| USB-TTL変換モジュール | ESP32-CAM | 備考 |
|---|---|---|
| GND | GND | 共通のグランド |
| 5V | 5V | ボードに給電する。変換モジュールの3.3 V出力では足りない |
| TX | U0R(GPIO 3) | クロス接続:送信側を受信側へ |
| RX | U0T(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
- Arduino IDEでボードマネージャを開き、esp32 by Espressif Systemsパッケージをインストールします。くわしくはArduino IDEのセットアップのガイドで解説しています。
- 「ツール」>「ボード」>「esp32」からAI Thinker ESP32-CAMのボードを選びます。
- Partition SchemeがHuge APP (3MB No OTA/1MB SPIFFS)になっているか確認します。カメラの例には3 MB以上のアプリ領域が必要です。
- ボードをアダプターにつなぎ、「ツール」>「ポート」で新しいポートを選びます(WindowsではCOMx、macOSでは/dev/cu.usbserial...か/dev/cu.wchusbserial...)。
- ポートがまったく表示されなければ、CH340かCP2102のドライバをインストールし、データ通信ができるUSBケーブルを使ってください。
| 設定 | 推奨値 | 理由 |
|---|---|---|
| ボード | AI Thinker ESP32-CAM | PSRAM、4 MBのフラッシュ、正しいパーティションスキームがあらかじめ設定されている |
| Partition Scheme | Huge APP (3MB No OTA/1MB SPIFFS) | CameraWebServerに必要な3 MBのアプリ領域 |
| PSRAM | このボード定義では常にオン | ESP32 Dev ModuleではPSRAM: Enabledにする。ESP32 Wrover Moduleでは最初からオン |
| CPU Frequency | 240MHz (WiFi/BT) | 画像の転送とWi-Fiに最高速度 |
| Flash Mode / Flash Frequency | QIO / 80MHz | 書き込みや起動に失敗するならDIO / 40MHzを試す |
| Core Debug Level | None(トラブル調査時はInfo) | Infoにすると、カメラとFPSの詳細がシリアルモニタに表示される |
| Upload Speed | 460800(このボードでは固定) | 書き込みがよく途切れるなら、ESP32 Wrover Moduleを選んで115200を試す |
最初の書き込みをステップごとに
- 配線します。ピンをそろえてボードをMBアダプターに差し込むか、上の表のとおりにUSB-TTL変換モジュールをつなぎます。USB-TTL変換モジュールを使うなら、IO0とGNDの間の短い線も加えます。
- ボードをダウンロードモードにします。MBアダプターでは、IO0ボタンを押したままRSTを押して離し、それからIO0を離します。USB-TTL変換モジュールでは、IO0-GNDの線をつないだ状態でRSTを押すだけです。自動リセット回路のあるMBアダプターの中には、ボタンを押さなくても書き込めるものもあります。
- Arduino IDEで書き込みをクリックします。出力にはまずConnecting...(接続中)と表示され、続いて書き込みの進み具合がパーセントで表示されます。
- Hard resetting via RTS pin...(RTSピンでハードリセット中)の行が表示されたら、書き込みは完了です。USB-TTL変換モジュールを使っているなら、ここでIO0-GNDの線を外します。
- シリアルモニタを115200 baudで開き、RSTを押します。新しいプログラムが動き始めます。
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の例:ブラウザでライブ映像を見る
- 「ファイル」>「スケッチ例」>「ESP32」>「Camera」>「CameraWebServer」を開きます。
- カメラのモデルを選びます。board_config.hのタブ(新しいバージョン)か、メインファイルの先頭(古いバージョン)にある一覧で、CAMERA_MODEL_ESP_EYEの行の前に//を付け、CAMERA_MODEL_AI_THINKERの行の前の//を外します。
- ssidとpasswordの行に、2.4 GHzのWi-Fiネットワークの名前とパスワードを入力します。
- ボードをダウンロードモードにしてスケッチを書き込み、IO0の接続を外してRSTを押します。
- シリアルモニタにCamera Ready! Use 'http://192.168.1.45' to connect(カメラの準備完了)のような行が表示されます。そのアドレスを、同じネットワークにつないだスマートフォンかパソコンのブラウザで開きます。
- ページのStart Streamボタンでライブ映像を始めるか、Get Stillで写真を1枚撮ります。
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配信) | 向いている用途 |
|---|---|---|---|
| QQVGA | 160×120 | 25〜30 | 動体検知、非常に弱いネットワーク |
| QVGA | 320×240 | 20〜30 | ロボットカー、なめらかなライブ映像 |
| CIF | 400×296 | 15〜25 | 小さな画面でのなめらかな視聴 |
| VGA | 640×480 | 10〜20 | 汎用のライブ視聴 |
| SVGA | 800×600 | 8〜15 | よりくっきりした視聴。PSRAMなしで使える最大のサイズ |
| XGA | 1024×768 | 5〜10 | 細部まで見える画像 |
| HD | 1280×720 | 4〜8 | ワイド(16:9)の構図 |
| SXGA | 1280×1024 | 3〜6 | 写真 |
| UXGA | 1600×1200 | 2〜5 | 最高解像度の写真 |
自分のコードでは、カメラが正常に起動したあと、センサーのオブジェクトを通して解像度、画質、向きを変えられます。JPEGの画質は0〜63の数値で、数値が小さいほど高画質です。10を下回るとフレームが大きくなり、途中で切れた画像の原因になることがあります。
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以上に上げ、電源を改善する |
ブラウンアウトのエラーと正しい電源(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電池を何本もつなぐよりずっと安定します。

ネットでは、コードでブラウンアウト検出を無効にする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に押しボタンをつなぐ方法を参照してください。
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を書く |
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を点滅
ESP32のGPIO出力の基本を学びます。デジタルピンからLEDを点灯・消灯させて、点滅させます。Arduino UNOの定番のLED点滅プロジェクトのESP32版です。Arduino環境で使う基本的な点滅コマンドは同じですが、ESP32のピン配置と3.3 VのGPIO電圧レベルはArduino UNOとは異なります。

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

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

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

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に標準対応しています。

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

ESP32動体検知アラーム(PIR + ブザー + LED + Telegram)
PIRセンサーが動きを検知するとブザーとLEDを作動させ、同時にTelegramで持ち主に即座に通知するスマート防犯アラームです。アラームが繰り返される頻度を抑えるため、30秒のクールダウン(待ち時間)を設けています。この仕組みはPIRの検知が正しいかを確認したり、誤検知をなくしたりするものではありません。家の防犯、ガレージの監視、倉庫や作業部屋などに使えます。ESP32-CAMなら写真付きの通知を追加でき、通常のESP32 DevKit V1ではテキストで通知します。
ほかの記事
BlueGraysアプリ
この回路をスマホでステップごとに作る
回路図、コード、部品リストを1つの画面で確認できます。Arduino、ESP32、Picoのプロジェクトを200件以上用意しています。

