約800円のESP32-CAMで乾電池駆動のWebカメラサーバーを立てる

# 追記(2021/5/5)
ついに待望の技適付きESP32が付いたESP32-CAMがaitendoさんより販売されました！
これで安心して国内で使えます。
（早速、２個買っちゃいました。）

![IMG_3530D.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/165d774f-9c5c-72f6-794d-e4ae8392aa16.jpeg)


https://www.aitendo.com/product/19515

* [ESPカメラモジュール](https://www.aitendo.com/product/19515) 
 * 販売価格: 1,250円(税別)
 * 工事設計認証付きESP-WROOM-32とCMOSカメラモジュール（OV2640）、ESP32-CAMモジュール（ESP32-Sなし）の3点セット
 * 使用には半田付けが必要

# 追記(2019/12/20)
* ご指摘のコメントを頂きました。
 * 現時点でESP32は全てが技適を取得している訳では無いようです。（てっきりOKなのかと思い込んでました）
 * こちらの製品で使われているものはESP32Sと書かれております。
 * 色々調べると技適取得済のESP32Sもあるようですが、なんか違う気がするので、こちらで電波を出さない方が良さそうです。
 * 誤解を広め兼ねないので記事の削除も考えましたが、逆に注意喚起になると思い、一部修正して残す事にします。
 * これ、すごく良いコンセプトな製品なので誰か技適通してくれないかなぁ。。。

# はじめに
* 昨年あたりからAliExpressでESP32とOLED、カメラ、バッテリホルダなどを直接基板に実装した製品が出ている。
* 中でもスキャン性能を要するカメラ(ov2640)とそれに見合った性能を備えるESP32、というマッチングはすごく良い所を突いており、このESP32-CAMは魅力的。
* Amazonでもやっと~~1300円(送料込)~~800円台で販売されるようになったのを見つけたので、取り寄せてみた。


![IMG_1903.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/ab56a104-940d-8f7b-77a2-1fc709b20e46.jpeg)


# 用意するもの


* [ESP32-CAM](https://www.amazon.co.jp/gp/product/B07PKQ8B5M/) 
* [USB-TTLシリアルコンバータ](https://www.amazon.co.jp/KKHMF-CH340モジュール-コントローラー-ダウンロード-USBターンTTLシリアル/dp/B014VVPZT4)
 * Amazon最安で200円くらい。（届くまで２週間くらいかかるけど）
* メス/メスのジャンパピン、またはジャンパケーブル（１つ）


## カメラの取り付け
* 販売元によっては、販売時にカメラがコネクタに接続されてない状態で送られてくるものがあり、自分でセットする必要がある。

![スクリーンショット 2020-12-13 9.48.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/cbd6f938-ef97-d231-2464-5ab45933a9fa.png)


* この形状のコネクタは、黒い部分を90度起こせるようになっていて、起こした状態でカメラのフレキを挟み、元に戻すだけで無理なくセットできる。
 * と、言葉で書いても伝わらないので、以下の動画（1:50あたり）を参考にすると良い。
 * （自分は構造を理解せず、無理な方向に力を掛けてしまい、一度黒いパーツの足を折ってしまった。。。）
 * 構造的には、一般的なフレキの止め方と同じである。

[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/5XCb3t8J4Kg/0.jpg)](https://www.youtube.com/watch?v=5XCb3t8J4Kg)

## USB/TTLシリアルコンバーター

ESP32-CAMにはUSBコネクタが実装されていないので、
プログラムを書き込んだりするためにはUSB/TTLシリアルコンバーターが必要になる。
(その分、とても小さい基板サイズとなっている。)

こういう時のために、１つ持っておいた方が良い。
ちなみに自分はケーブルの長いのと、基板むき出しのと２種類持ってるが、どちらも普通に使える。
（使う前にドライバをインストールしておく。）

![IMG_2401.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/a940b776-e9d3-5d7e-3d86-eec27e8a680d.jpeg)


# 参考URL
* こちらの記事を参考にさせて頂いた。英語だが的確に書かれていて読みやすい。
 * [Ai-Thinker ESP32-CAM in the Arduino IDE](https://robotzero.one/esp32-cam-arduino-ide/)


# 接続


![ESP32CAM_OLED_ブレッドボード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/5468492b-d7d4-2786-95a3-06eb9081892d.png)


![IMG_1904.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/67852611-0fd8-8865-6a75-b103e6f266b8.jpeg)

![IMG_1907.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/1fa8d51b-8b76-6f0d-bce6-645dabe82611.jpeg)

| USB-TTL | ESP32-CAM  |
|:---------|:-------|
| TXD ( 緑 ) | UOR |
| RXD ( 白 ) | UOT |
| - | ( IO0 - GND )  |
| 5V | 5V  |
| GND | GND  |

* (2019/10/13 USB-TTLのケーブル色を追記)
 * 写真のUSB-TTLは基板むき出しタイプである。
 * 黒いカバーつきタイプの場合は、赤、黒、白、緑の４色のケーブルの色で判断する必要がある。
 * 赤：5V
 * 黒：GND
 * 緑：TXD
 * 白：RXD

* 書き込み時には、こんな感じでESP32-CAMのIO0とGNDをショートさせておく。
 * 書込み時:接続
 * 起動時:非接続
 * **起動時には必ず抜いておくこと!!**
 * もし起動しない時があっても落ち着いて。単にこれを抜き忘れてるだけだから。


![IMG_1905.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/cefa901c-d88b-efe2-7a39-11307f9d4ca9.jpeg)


# Arduino IDE のセットアップ

* もしArduino IDEで初めてESP32を使う場合は以下の要領でボードを追加する。
 * 「環境設定」 -> 「追加のボードマネージャのURL」 で以下のURLを追加。
 * https://dl.espressif.com/dl/package_esp32_index.json
 * 「ツール」 -> 「ボード」 -> 「ボードマネージャ」　で"ESP32"を追加しておく。
* 追加できたら、ツールメニューで以下を設定。

| 項目名 | 設定値  |
|:---------|:-------|
| ボード | ESP32 Wrover Module |
| Partition Scheme | Huge App(3MB No OTA) |
| Flash Mode | QIO |
| Flash Frequency | 80MHz  |
| Upload Speed | 921600  |

# サンプルコードを修正
* スケッチ例を開く。
 * 「ファイル」 ->「スケッチ例」 -> 「ESP32」 -> 「Camera」 -> 「CameraWebServer」
* 以下の部分を修正。
 * CAMERA_MODEL_WROVER_KIT をコメントアウト
 * 代わりにCAMERA_MODEL_AI_THINKERを有効化。
 * ssid, password は自分のWifi環境の情報を入力。

### 修正前

```
// Select camera model
#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_AI_THINKER

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

### 修正後

```
// Select camera model
//#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_M5STACK_PSRAM
#define CAMERA_MODEL_AI_THINKER

const char* ssid = "自分のWifi環境のSSID";
const char* password = "自分のWifi環境のPASSWORD";

```

# ボードへの書込み
* IO0/GNDピンが接続されている事を確認して書き込む。
* 出力結果はこんな感じ。

```
最大3145728バイトのフラッシュメモリのうち、スケッチが2233518バイト（71%）を使っています。
最大327680バイトのRAMのうち、グローバル変数が50700バイト（15%）を使っていて、ローカル変数で276980バイト使うことができます。

esptool.py v2.6-beta1
Serial port /dev/cu.wchusbserialfd1440
Connecting........
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: cc:50:e3:b6:ed:dc
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 8192 bytes to 47...

Writing at 0x0000e000... (100 %)
Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.0 seconds (effective 2535.3 kbit/s)...
Hash of data verified.
Compressed 17664 bytes to 11528...

Writing at 0x00001000... (100 %)
Wrote 17664 bytes (11528 compressed) at 0x00001000 in 0.2 seconds (effective 827.0 kbit/s)...
Hash of data verified.
Compressed 2233680 bytes to 1788388...

Writing at 0x00010000... (0 %)
Writing at 0x00014000... (1 %)
Writing at 0x00018000... (2 %)

.....//省略

Writing at 0x001bc000... (98 %)
Writing at 0x001c0000... (99 %)
Writing at 0x001c4000... (100 %)
Wrote 2233680 bytes (1788388 compressed) at 0x00010000 in 26.3 seconds (effective 680.3 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 134...

Writing at 0x00008000... (100 %)
Wrote 3072 bytes (134 compressed) at 0x00008000 in 0.0 seconds (effective 919.8 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...
```

# 起動
* IO0とGNDを接続していたピンを外し、起動。
* もし、起動したはずなのに反応しなかったら、「RST」って印字されている小さいリセットボタンを押す。
* （リセットボタンは1枚目の写真中央、ESP32が表面実装されている面の端っこにある）
* 正常に起動すると、シリアルモニタにはこんな感じでIPアドレスが表示される。
 * 自分の環境の場合は、http://192.168.0.11 になった。

```
ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1100
load:0x40078000,len:10088
load:0x40080400,len:6380
entry 0x400806a4

........
WiFi connected
Starting web server on port: '80'
Starting stream server on port: '81'
Camera Ready! Use 'http://192.168.0.11' to connect
```

# ブラウザから接続
* ブラウザを開いて、シリアルモニタに表示されたIPアドレス http://192.168.0.11 にアクセスする。
* メニュー下部にある"Start Stream"ボタンを押すと、映像転送が始まる。

![IMG_1896.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/946bb46f-0481-75e7-0c0d-e37d748ceee9.jpeg)


ボタンで色々設定を弄れるようになっていて、画像サイズを変えたり、
エフェクトをかけたり、更には顔検出まで出来てしまう。

![IMG_1900.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/87d08e4f-9ff2-0059-00fb-16be7c20911f.jpeg)

省電力なESP32なので、乾電池(5V)でWifiカメラサーバが運用できてしまう。

# 電源まわりの構成を考える。
- ESP32-CAMの基板を見ると「AMS1117」というレギュレータが実装されている。
- [このスペックシート](http://www.advanced-monolithic.com/pdf/ds1117.pdf)の最大入力電圧を見ると15Vまでとなっているので、9V乾電池から直接電源を供給できちゃう。
 - 試しにダイソーで買った100円の9V乾電池を5Vと書かれているピンに繋いで見た所、バッチリ動いた。
 - 省スペースでシンプルな回路構成にしたい場合、この構成が良さそう。
- カメラを動かすとそれなりに電流を食うようなので、弱った電池だと電圧降下でESP32が動かなくなる。
 - 9V乾電池を5Vに供給する場合、新品の電池でないと動かなかった。
 - 写真のように1.5V単三電池３本を使うのが間違いないみたい。

# 基板に実装されている大光量LEDを光らせる
* この基板には更にSDカードスロットとカメラのフラッシュライトが実装されている。
* GPIO 4がフラッシュになっており、digitalWrite()でHIGHを入力したところ、大光量のフラッシュLEDとして使えた。
* 自分はこれを正常起動完了ステータス表示する目的でこのLEDを点滅させている。

```
#define FLASH_GPIO_NUM   4

void setup() {

  // ....

  pinMode(FLASH_GPIO_NUM, OUTPUT);

  // startup status
  digitalWrite(FLASH_GPIO_NUM, HIGH);
  delay(300);
  digitalWrite(FLASH_GPIO_NUM, LOW);
  delay(300);
  digitalWrite(FLASH_GPIO_NUM, HIGH);
  delay(300);
  digitalWrite(FLASH_GPIO_NUM, LOW);
}
```

# HTML/GPIO制御をカスタマイズする。
* camera_index.h を編集する必要があるが、ちょっとやり方に癖があったので別記事で記載する。
 * [ESP32-CAMのCameraWebServerにLEDフラッシュボタンを追加する](https://qiita.com/Nabeshin/items/e7ce27f852af8086bc33)
* これで余ってるGPIO使ってモータードライバを制御したりすることができる。
 * [ESP32-CAMでカメラ付きロボット（カムロボ）を遠隔制御](https://qiita.com/Nabeshin/items/1ad8ab0f0f66472a2325)

# SoftAPモードで使う。
* SoftAPモードにすれば自宅のWiFi環境につながなくても、ESP32をアクセスポイント化して、直接スマホとやりとりができる。
 * 外出先で動かしたりする時に使えてかなり便利。 
* コードはこんな感じ。
 * ESP32-CAMを起動後、スマホからWiFiアクセスポイントを探すと`ESP32-NET`が出てくる。
 * 以下のパスワード`mypass12345 `を入力すると接続される。
 * ブラウザから`http://192,168,0,12`を開けば例の画面が表示される。

```
//ESP32 SoftAP Configration
const char ssid[] = "ESP32-NET";
const char pass[] = "mypass12345";
const IPAddress ip(192,168,0,12);
const IPAddress subnet(255,255,255,0);

void setup() {

  // ....

  //SoftAP
  WiFi.softAP(ssid,pass);
  delay(100);
  WiFi.softAPConfig(ip,ip,subnet);
  IPAddress myIP = WiFi.softAPIP();

/*
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
*/

  Serial.println("ESP32 SoftAP Mode start.");
  Serial.print("SSID:");
  Serial.println(ssid);

  startCameraServer();

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

* 以下の記事でも触れている。
 * [ESP32-CAMでカメラ付きロボット（カムロボ）を遠隔制御](https://qiita.com/Nabeshin/items/1ad8ab0f0f66472a2325)