ESP-WROOM-02にカメラモジュールを繋いでネットワークカメラを作る


話題のESP-WROOM-02にシリアルカメラモジュールをつないで，写真をWi-Fiでサーバに定期的にアップロードするネットワークカメラにしてみました．Wi-Fiと5Vの電源さえあれば単体で写真をサーバに送信できます．


シルバーウイーク中にハッカソン的なことをしてたので，初日にハッカソンの様子を記録する定点観測カメラとして制作しました．そのときのメモです．もう少しちゃんとまとめたいですが，あまり寝かせるとお蔵入りしてしまいそうなので一旦公開．

![board01.jpg](https://qiita-image-store.s3.amazonaws.com/0/58515/cd6c5819-7d5a-4b43-bcab-3483bd6fcafd.jpeg)

- WiFiモジュール: [ESP-WROOM-02](http://akizukidenshi.com/catalog/g/gM-09607/)
- カメラ: [Grove-シリアルカメラキット](http://akizukidenshi.com/catalog/g/gM-09161/)

どちらも[秋月](http://akizukidenshi.com/catalog/default.aspx)で購入しました．Amazonでも買えます．

# ESP-WROOM-02

![esp-wroom02.jpg](https://qiita-image-store.s3.amazonaws.com/0/58515/29f374a7-216a-233b-5d23-4900910aa016.jpeg)

技適マークついてて，Wi-Fi喋れて，マイコンとメモリも載ってるモジュールです．
Wi-FiにつながってTCP/IPスタックまで載ってるコンピュータが550円な時代すごい．やばい．

- ESP8266
- MCU Tensilica L106 80MHz (最大160MHz)
- SRAM 80KB (自由に使用可能なのは36KB)
- Flash 4MB (最大16MB)

MCUは32ビットのL106で，使うの初めてです．
SRAMはWiFiモジュールが内部で使うメモリと共有で，36Kまでユーザが使ってよいらしい．
Flashは，4MBのSPIフラッシュメモリが載っている．16MBまでサポートしてると書かれているけど，信号線が外に出てないので，シールド剥がさないと交換はできなさそう．

そのままでも，PCとシリアルでつないでATコマンドでWiFiに接続したりTCPコネクション張ったりできます．
プログラム書くためにはL106用のクロスコンパイル環境が必要ですが，Arduino IDEで開発できるようにしてくれているので，簡単に使えます．

https://github.com/esp8266/Arduino

[Arduino IDE](https://www.arduino.cc/en/Main/Software)をインストールして，上記githubに書いてある通りにセットアップすると，「Generic ESP8266 Module」というボードが選択可能になります．


https://github.com/esp8266/gcc-compiler

githubを見ているとgccも用意してくれている？と期待してしまいましたが，上のリポジトリの中身は空っぽでした．
しかし，Arduino IDEの環境をセットアップすると，Windowsであれば `AppData\Roaming\Arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc` にgccが一式入るようなので，Arduinoとかよくわからないという場合には普通にCかC++で開発できそうです(試してないですが)．

# Grove-シリアルカメラキット

![jpeg-camera.jpg](https://qiita-image-store.s3.amazonaws.com/0/58515/530a4306-038f-f229-7263-b9877c87ff71.jpeg)

jpegエンコーダが内蔵されていて，シリアルでjpegデータを取得できます．30万画素．3,880円でちょっと高価です．

特定のArduinoシールド用として売られているっぽくて説明少ないですが，カメラのコントローラにはOV528が使われています．
配線は，これも説明見つけにくいですが以下のようになってました．

- 黒: GND
- 赤: 5V
- 黄: カメラTX (ESP-WROOM-02のRXにつなぐ)
- 白：カメラRX (ESP-WROOM-02のTXにつなぐ)

カメラモジュールの電源電圧は5Vですが信号は3.3VのようなのでESP-WROOM-02に直接接続できます．
OV528との通信プロトコルやコマンドなどはググれば資料がすぐ出てきますし，Arduino用のサンプルなどもあるので簡単に使えると思います．

# 回路

![wificamera.png](https://qiita-image-store.s3.amazonaws.com/0/58515/6f678be7-8512-1871-072b-8a6399bf5c5d.png)

基本的に，ESP-WROOM-02を動かすための回路＋カメラのTX,RXをつなぐだけです．USBコネクタからは電源だけ取って三端子レギュレータで3.3Vを作っています．

また，カメラへの接続端子はファームウェアの転送用も兼ねています．ESP-WROOM-02のUARTはカメラとの接続に使ってしまうので，少し面倒ですが，プログラムを書き込むたびに接続しなおす必要があります．

ESP-WROOM-02自体を動かすための回路や，HTTPServerを立ててブラウザでアクセスできるようにするあたりは説明を省きますが，記事を公開してくれてる方がいるのであまり苦労せずに試せました思います．

今回，下記の記事を参考にしました：
- [ESP-WROOM-02 の Arduino 環境で I2C 制御](http://qiita.com/ikesato/items/92f4cb143e7aeb5e0f9b)
- [ESP-WROOM-02でWeb Serverを動かす](http://qiita.com/snumano/items/95cdca970ec0a4695547)

## ブレッドボードに挿しやすいように足を生やす

![esp-wroom02_2.jpg](https://qiita-image-store.s3.amazonaws.com/0/58515/a5ef7982-377c-68c9-5ce4-b71124c29053.jpeg)

適当にはんだ付けします．

## ブレッドボードの様子

![DSC_0072.jpg](https://qiita-image-store.s3.amazonaws.com/0/58515/c5f3bbe3-8734-ec0e-1c77-3c20aa587471.jpeg)

あとで使う予定の回路やファームウェア書き込み用のシリアル変換基板も載ってますが，通常動作に必要なパーツは少ないです．

# プログラム

ESP8266用のサンプルにHelloServerというHTTPサーバがあるので，これを使いました．

何かするたびにカメラとシリアルケーブルをつなぎ直すのは面倒なので，ブラウザからカメラを初期化したりシャッターを切ったりできるようにしておくと少しだけ開発が楽になります．

作ったもの(GitHub): https://github.com/binzume/ov528cam/tree/master/arduino/HelloServer

ssidや写真のアップロード先などはハードコーディングされているので環境に合わせて設定してください．
写真のアップロードはjpegデータをbodyに入れてPOSTするだけなので良しなにやってください．

### HTTP Client

サンプルにWebサーバはあるんですが，HTTPクライアントが無いっぽい(?)ので実装しました．ヘッダファイルだけのだいぶいい加減な実装です．

https://github.com/binzume/ov528cam/blob/master/arduino/HelloServer/HttpClient.h

Arduinoの作法あまり知らないせいではまったのですが，なぜかコンストラクタが呼ばれずメンバが初期化されなくて困りました．原因は，Arduinoのライブラリ中にある別の同名のクラスも自動的にリンクされていて，そちらのコンストラクタが呼ばれている？っぽかったです．クラス名変えてtypedefしたら動きましたが，まだ何か怪しいかもしれません．

## ブラウザで写真を見る

最初にIPアドレスを知る必要があります．起動時にシリアルに出ているものか，コード中でHEARTBEAT_URLで指定したURLにlocal_ipというパラメータを付けてアクセスしているのでそれを利用してください．

`HelloServer.ino` では以下のようなハンドラが登録されています．

``` c
  server.on("/", handleRoot);
  server.on("/init", handleInit); // init camera
  server.on("/snap", handleSnapshot); // snapshot
  server.on("/get", handleGetJpeg); // get jpeg
  server.on("/post", handlePostPhoto); // post jpeg(test)
  server.on("/start", handlePostStart); // post jpeg
```

`http://[取得したIPアドレス]/init` でカメラを初期化．

`http://[取得したIPアドレス]/snap` でOV528のバッファに写真取得(シャッター相当．不要かも？)．

`http://[取得したIPアドレス]/get` で写真を取得．

本来はsnapした時点での画像がそれ以降のgetで取得されることを期待してましたが，snapしなくてもOV528のバッファ更新されるようです．ただ，snapしないと光量が足りない時に白黒になったり，ホワイトバランスがおかしくなったりするので一応叩いておいたほうが良さそうです．

(initは起動時の処理に入れる予定ですがデバッグ時に不便なので今のところコメントアウトしています)

シングルスレッドなので，処理中は他のリクエストを処理できません．

## 定期的に写真をアップロード

`http://[取得したIPアドレス]/start?interval=60` で毎分の写真のアップロードを開始．

POST_URLに書かれているURLにjpegデータをHTTPでPOSTします．
`Content-Type: image/jpeg` でbodyにjpegがそのまま入っています(マルチパートメッセージではないです)．

intervalで更新間隔を指定できます(デフォルト60秒)．

TODO: アップロードを受け付けるサーバ側のコードも公開する．

### サンプル画像

窓からの風景．深夜2時過ぎの写真ですがシャッタースピード遅いかわりにかなり明るく映ります．一晩窓の外を撮ってみましたが金星と木星も写ってました(そして太陽も．．．一応カメラは大丈夫でした)．

![sample.jpg](https://qiita-image-store.s3.amazonaws.com/0/58515/2284b216-209b-8b8a-c7a5-7eaedce7761e.jpeg)

あまり電力に気を使ったことはしてませんがモバイルバッテリーからの給電でも１日くらいは動作します．


# TODO

以下あとでやるかもしれないこと．

- 設定を永続化
- 安いWebカメラを使う
- ライブ配信

## 設定を永続化

EEPROM(？)に設定等を書き込んで電源入れ直した時に状態を戻したい．サンプルもあるようなので試してみる．

## 安いWebカメラを使う

Webカメラにもmjpegに対応したコントローラが載っていることがあるので，使えればもっと安価に実現できそうです．ただ，USBホストコントローラが必要になってしまうので少し面倒．
I2CかSPIで接続できる安いカメラモジュールを探すか自作するかすれば色々できそうです(というかいまどきな電子工作にちょうど良いカメラ欲しいです)．

## ライブ配信

なんとなくできそうなところまで来てますが，転送速度の関係でfps低いです．．．