定点観測カメラを電池駆動で作る

#はじめに
屋外用の定点観測カメラということで電源は電池！と云うことからスタートした。モバイルバッテリーも考えたができるだけ小型化したかったので、電池駆動にこだわった。そしてなるべく汎用的に低予算でシンプルに・・・。

初号機で完成したモノが下。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/a9424a82-f0aa-464f-0a81-e1f49928bf58.png" width=50%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/3cf6bebb-633f-c92e-ba5c-fabb9af6766a.png" width=50%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/252885e6-298e-7c27-cc94-df03924045d8.png" width=50%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/339714eb-665c-55b8-8bc0-3c2d4ef1bb27.png" width=50%>
※弐号機はもう少しコンパクトにする予定です。

関係ありませんが、下↓が零号機です。右上にコードが集まってクリップに挟まっているのがカメラです。下がESP32。上が書き込み装置。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/cbdfa0ff-519b-43bb-71d9-97a6b56301bd.png" width=50%>
大抵↑ここで満足してしまうのですが、ここでは上の初号機のユニバーサル基板化まで行きます！

#ここ大事
がっかりさせないために最初から言っておきます。残念ながら画像サイズは<B>160x120</B>です。下の画像です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/fb4a37e0-341a-726a-23b3-77e36422e983.png)

ブラウザで見ると1.5倍ぐらになっていると思う↑これよりもっと小さいです。この画像を保存して画像ソフトでみると分かると思います。カメラの性能的はVGAまでいけるのですが、ESP32だと頑張ってもう一つ上の320x240。このサイズで我慢できる人のみ挑戦してみてください。
ちなみにこの画像は、横向きですが我が家の桜の木です。

#部品
| 部品| 値段 |購入元|
|:-:|:-:|:-:|
|ESP-WROOM-32|1,100円|[スイッチサイエンス](https://www.switch-science.com/catalog/3170/)|
|OV7670(FiFo無)|300円|[Amazon](https://www.amazon.co.jp/gp/product/B00JZESFKE/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1)|
|ユニバーサル基板|170円|[秋月](http://akizukidenshi.com/catalog/g/gP-03232/)|
|ピンヘッダー|350円|[秋月](http://akizukidenshi.com/catalog/g/gC-06641/)|
|ピンソケット|80円|[秋月](http://akizukidenshi.com/catalog/g/gC-05779/)|
|ワイヤー|550円|[秋月](http://akizukidenshi.com/catalog/g/gP-06755/)|
|タクトスイッチ|20円|[秋月](http://akizukidenshi.com/catalog/g/gP-08074/)|
|抵抗(10Kx2, 4.7Kx2, 1K, 100K)|100円|[秋月](http://akizukidenshi.com/catalog/g/gR-25103/)|
|トランジスタ|200円|[秋月](http://akizukidenshi.com/catalog/g/gI-00881/)|
|コンデンサー 0.1μF|10円|[秋月](http://akizukidenshi.com/catalog/g/gP-11154/)|
|電池|220円|[ダイソー]()|
|電池ボックス|40円|[秋月](http://akizukidenshi.com/catalog/g/gP-03086/)|
全部で3,140円ですが、ピンヘッダーとかワイヤーとかお手持ちのもので良いので実際には2,000円ぐらいでイケると思います。

※写真では[スライドスイッチ](http://akizukidenshi.com/catalog/g/gP-08791/)が付いていますが、使用していません。このスイッチがあまり良くなくてかなり悩んでしまいました。定格で0.5AまでイケるとあるのですがESP32だと超えてしまうのかうまく起動できない状態になってしまい、結局使っていません。かわりにタクトスイッチでリセットスイッチを入れました。

## ESP-WROOM-32
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/ccd6a6b3-96ae-936b-13cd-3e5ecd4ffb36.png" width=50%>
電池駆動したいので開発ボードではなく、[ピッチ変換のみしたボード](https://www.switch-science.com/catalog/3170/)。1,100円とお高め。単体でESP32が700円でボードが300円なので自分でハンダすれば100円浮くけど、ここにはケチらずハンダ済みのを使った。ピンヘッダは付けないといけないけど。次回からは[aitendo](http://www.aitendo.com/product/15536)の方が最低限の部品もついているのでこっちにするかも。

##OV7670(FiFo無)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/5824e1c6-cac5-3e9f-748d-89398d2e0086.png" width=30%>

とてもお安くて Amazon で300円で購入した。Primeじゃなかったので2週間待ったが、弐号機を作る予定のでさらに必要になってくる。
お安いのは当然で、このOV7670には、FiFo（たぶん簡単に言うとバッファ用メモリ）が無くて、接続側が面倒見る必要がある。手間がかかる分だけお安い。実際に来たモノは上写真と同じモノ。注文したモノには上部にジャンパなどがあったけど無い。中華モノなのと値段で許容範囲。

#回路図
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/1b27cbd0-53fd-4e90-ea9e-4e7c67f0529c.png" width=100%>

### ESP32 ⇔ OV7670
ESP32とOV7670の接続はかなりあるのでうんざりしますが根気強く頑張りましょう。
回路図にOV7670→ESP32のGPIOを記述してあります。
SIOCとSIODは4.7Kでプルアップしてください。10Kでも大丈夫でした。

###OV7670のPower Down Mode
datasheetによると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/4cde9b17-5c5d-4162-01c9-5a811e65586c.png)


撮影時は 60mW でスタンバイ時は20μA以下ということで、Deepsleep中はカメラをスタンバイにしないと！やり方は以下のように PWDNピンをHIGHにするとPower Downモードになるらしい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/b2dbda09-fe68-0e64-4888-748dc5a88f1f.png)

HIGHにするのはちょっと厄介でNPNトランジスタでNOT回路作りました。回路図の右下辺り。
GPIO13をHIGHにするとPWDNがLOWになり、GPIO13をLOWにするとPWDNがHIGHになるように。実際にはESP32の起動時にGPIO13をHIGHにしてDeepsleep時には勝手にLOWになる。
ところが、実際に計測したところ 500μAまでしか下がらない！！分かる方がいたら教えて下さい！！

###自己電圧
自己電圧を取得したいので回路図中央辺りのR10Kx2。IO23をHIGHにしてR10K+R10Kで分圧してGPIO39(SENSOR_VN)ピンでAnalogRead()してます。0.1Vぐらい高いような気がしますが。

```cpp
digitalWrite(GPIO_NUM_23, HIGH);
float analog = analogRead(GPIO_NUM_39);
float V = analog / 4096 * 3.9 * 2;
```

#電源
回路図には 3V3 とありますが、実際にはダイソーの充電式単3ニッケル水素電池×2本です。
なのでフル充電しても3Vにも届きません・・・。公式にはESP32は3.0～3.6Vとなっていますが少し前までは2.7V～でした。安定して動作させるには3.0V必要なんですねきっと。ただ頑張れば2.5V辺りでも動作すると聞いたので、NiMH×2本の2.5V～2.8Vの電圧で動かしてみよう！ってことになっています。本来、NiMH の1本は1.1V～1.2Vが一番美味しいところなんですが、ほとんど無駄にしてます。

## Bitmap to JPEG
Slackの画像アップロードですが、Bitmap(RGB565)ファイルを上げると単なるファイルとして認識されるようで、画像フォーマットとしてはサポートしていないようです。
<img width="372" alt="キャプチャ.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/98af1245-9bf0-6831-4ab0-a9621f0d3134.png">

PNG かJPEG にエンコードできるライブラリがないか探していたのですが適当なものが見つからず。spressif の標準に [convert_line_format()](https://github.com/espressif/esp32-camera/blob/master/conversions/to_jpg.cpp) なるもの発見。しかし色が変。
![capture (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/f49b1942-0412-d55e-8865-c5ad8c3babd2.jpeg)
んー、けど全くダメではなくて、色が変なので何とか自力で直してみた。下記、コメントアウト部分を変更しました。オリジナルとは関数名を変えて使っています。

```cpp:to_jpg.cpp
static IRAM_ATTR void convert_line_format_(uint8_t * src, pixformat_t format, uint8_t * dst, size_t width, size_t in_channels, size_t line)
{
    int i=0, o=0, l=0;
    if(format == PIXFORMAT_GRAYSCALE) {
        memcpy(dst, src + line * width, width);
    } else if(format == PIXFORMAT_RGB888) {
        l = width * 3;
        src += l * line;
        for(i=0; i<l; i+=3) {
            dst[o++] = src[i+2];
            dst[o++] = src[i+1];
            dst[o++] = src[i];
        }
    } else if(format == PIXFORMAT_RGB565) {
        l = width * 2;
        src += l * line;
        for(i=0; i<l; i+=2) {
            /*
            dst[o++] = src[i] & 0xF8;
            dst[o++] = (src[i] & 0x07) << 5 | (src[i+1] & 0xE0) >> 3;
            dst[o++] = (src[i+1] & 0x1F) << 3;
            */
            dst[o++] = src[i+1] & 0xF8;
            dst[o++] = (src[i+1] & 0x07) << 5 | (src[i] & 0xE0) >> 3;
            dst[o++] = (src[i] & 0x1F) << 3;
        }
    } else if(format == PIXFORMAT_YUV422) {

```

##Slack
Slackへの投稿とアップロードは以下を参考にさせて頂きました。
https://qiita.com/ikegam1/items/f9a9351bb7d325b02ed3

Slackへのアップロードですが、切断前にインターバルを入れないと上手くアップされないようで、2秒入れてあります。

```cpp
  client.readStringUntil('\n');
  delay(2000); // need!! slack.com interval
  client.stop();
```

##ESP32 I2S Camera
ベースとなるコードは、こちらを使わせて頂きました。
https://github.com/bitluni/ESP32CameraI2S

#ソースコード
作成した全コードは下記に置いておきます。
https://github.com/nori-dev-akg/esp32-ov7670-slack

#目標
やりたいことは、先程もありましたが桜の植木の開花記録をしたいと思っています。
1日3回の撮影で3ヶ月を目標にしました。
撮影だけでも 3回(1日)×90日(3ヶ月)=270回 は出来ないといけません。

実際には slack に送信して記録しています。
テストでは、10分間隔で769回の撮影はできました。あとは長期運転かなと。ダメなら単4×3本も考えないとかなぁ・・・。

<img width="225" alt="13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/caa977bc-dec6-57cf-bfd2-2ff9303910e7.png">


No.769の次がNo.2になっています。ここでDeepSleepからの復帰ができず、リブートが掛かっています。リブートが掛かるとNoが1に戻ってしまいます。この後またNo.73まで行くのですが、以降はDeepSleepからの復帰でBrownOutが発生し、結局2.56Vで終わりました。
（No.768がありませんが送信エラーだったのでしょう。たまにあります。）

WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);

を入れてどれくらい伸びるか期待しています。

## 2020/04/04 追記
ようやく芽吹いてきました。うちのコは遅咲きのようです。
<img width="221" alt="202004040.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/541f807f-6ad3-f202-8054-b0c1609167f2.png">

## 2020/05/27 追記
残念ながら2ヶ月も持ちませんでした。1ヶ月と10日ぐらいです。スタートがフル充電ではなかったのでもう一度計測し直しますが、さほど変わらないでしょう。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203949/218bd33d-3c1f-76a3-bed3-436da1439af5.png">

#最後に
結果は後日分かり次第追記したいと思います。
現在、弐号機の製作に取り掛かっています。コンパクト化が中心ですが、これも後日アップしたいと思います。

#SpecialThanks!!
https://github.com/kobatan/OV7670-ESP32
https://www.webzoit.net/hp/it/internet/homepage/env/iot/esp8266/esp32_ov7670_without_fifo_on_linux/
https://github.com/bitluni/ESP32CameraI2S
https://qiita.com/lumbermill/items/2517c5f130384cced335