ESP32-WROVER CAMボードを試してみました【Arduino使用】【Freenove FNK0060】

Raspberry Pi/電子工作
スポンサーリンク

こんにちは、あろっちです。

ESP32-WROVER CAMボードはESP32-WROVER-E(技適マーク付き)とカメラが搭載されたボードです。
こちらを入手したので情報をまとめてみました。

ESP32-WROVER CAMボードには、Freenoveのオリジナル品(FNK0060)とジェネリック品があります。

Freenove FNK0060は基板にFREENOVEの文字がシルク印刷されています。

左: Freenove FNK0060 右: ジェネリック品

参考サイト:

https://lang-ship.com/blog/work/esp32-cam-fnk0060/(Lang-ship)

上記にたなかさんの情報がありますので参考にしてください。
こちらによると、ジェネリック品のWROVER-Eモジュールはクローン品とのことで筆者の方でも挙動の違いを確認しました。

本記事では両方の情報を網羅しようと思いますが、国内ではオリジナル品であるFreenove FNK0060をお使いください。

本記事は以下を参考にしています。

GitHub - Freenove/Freenove_ESP32_WROVER_Board: Apply to FNK0060
Apply to FNK0060. Contribute to Freenove/Freenove_ESP32_WROVER_Board development by creating an account on GitHub.

本記事ではArduino(C/C++)で試してみます。

ESP32-S3-WROOM-1を搭載した最新モデルが販売開始され入手できましたので記事を書きました。ぜひご覧ください。

スポンサーリンク
スポンサーリンク

特徴

Freenove ESP32-WROVER Board FNK0060

Amazonで入手しました。

外箱
ボード本体の他、USBケーブルとリーフレットが付属しています。
ボードを袋から取り出したところ
モジュールESP32-WROVER-E
(技適マーク付き)
※1
フラッシュメモリ 4MB
PSRAM 8MB※2
カメラオンボードカメラ
(コネクタ)
付属カメラモジュール
OV2640 66°
USBシリアルMicro USBシリアル変換IC
CH340※3
※1 ジェネリック品はモジュールの相違があるようです。
※2 Arduinoで使用可能な容量は4MBまでです。
※3 シリアルドライバをインストールしていない場合は別途インストールが必要です。

ESP32-S3-WROOM-1を搭載した最新モデルの記事を書きました。ぜひご覧ください。

ギャラリー

Freenove FNK0060とジェネリック品を並べてみました。
基板サイズに違いはないようです。

表面
裏面
Freenove FNK0060とジェネリック品でボードのバージョンが異なっています

普通のブレッドボード(400穴)だと片側1ピン分の穴が確保できます。

ブレッドボード2枚を連結して設置すると左右どちらもピン穴が確保できました。

サンハヤトのニューブレッドボードでは、3ピン分(片側どちらか1ピン、他方2ピン)ピン穴が確保できました。
このボードを使うのにオススメのブレッドボードです。
※このボードの使用例を後述のサンプルプログラムに掲載しています。

カメラモジュール(OV2640)例

カメラモジュール(OV2640)には様々なバリエーションがあります。
こちらは別途購入したもの。

左から
66° 21mm(付属カメラ) 120°21mm 160°21mm
68°75mm 160°75mm

カメラはコネクタ接続なので換装して使えます。

ESP32-WROVER CAMボードに120°21mmを取り付けたところ
Freenove FNK0060
120° 21mmを取り付けたところ
Freenove FNK0060
160° 21mmを取り付けたところ
ジェネリック品
160° 21mmを取り付けたところ

CameraWebServer動作例

Freenove FNK0060

Arduino IDEでスケッチ書き込みした動作例

PlatformIO IDEでスケッチ書き込みした動作例

ジェネリック品

PlatformIO IDEにてビルド&書き込んだものを動かしたサンプル画像です。

カメラ OV2640 120° 21mm

カメラ OV2640 160° 21mm

ピン配列

※画像のバー付きのピン(GPIO)はカメラ(コネクタ)に接続されています。

下表のボード表記は左上のピンから反時計回りに記載しています。
※3.3V、EN、VCC、GNDを除く

ボード表記GPIO主機能備考
VPGPIO36ADC1_0Camera Y6
VNGPIO39ADC1_3Camera Y7
34GPIO34ADC1_6Camera Y8
35GPIO35ADC1_7Camera Y9
32GPIO32TOUCH_9
33GPIO33TOUCH_8
25GPIO25DAC_1Camera VSYNC
26GPIO26DAC_2Camera SIOD
27GPIO27TOUCH_7Camera SIOC
14GPIO14HSPI_CLK
12GPIO12HSPI_MISO
13GPIO13HSPI_MOSI
SD2GPIO9SPIHDフラッシュメモリ接続用(使用不可)
SD3GPIO10SPIWPフラッシュメモリ接続用(使用不可)
CMDGPIO11SPICS0フラッシュメモリ接続用(使用不可)
CLKGPIO6SPICLKフラッシュメモリ接続用(使用不可)
SD0GPIO7SPIQフラッシュメモリ接続用(使用不可)
SD1GPIO8SPIDフラッシュメモリ接続用(使用不可)
15GPIO15HSPI_SS
2GPIO2LED内蔵LED
0GPIO0TOUCH_1BOOTボタン
GND短絡にて書き込みモード(Download Boot)
4GPIO4TOUCH_0Camera Y2
5GPIO5VSPI_SSCamera Y3
18GPIO18VSPI_CLKCamera Y4
19GPIO19VSPI_MISOCamera Y5
21GPIO21I2C_SDACamera XCLK
RXGPIO3RX0シリアル通信
TXGPIO1TX0シリアル通信
22GPIO22I2C_SCLCamera PCLK
23GPIO23VSPI_MOSICamera HREF

VP, VN, 34, 35は入力(Input)のみとなります。
カメラ使用時は備考の空欄のピン(以下参考)が外部ピンとして使用できるかと思います。

GPIO12〜GPIO15(HSPI対応)
GPIO32、GPIO33

※HSPIを使用したスケッチ例を後述のサンプルプログラムに掲載しました。※2022年10月22日

参考URL(pdf):

https://github.com/Freenove/Freenove_ESP32_WROVER_Board/blob/main/C/C_Tutorial.pdf

本ボードは普通にESP32開発ボードとして使用することもでき、スターターキットが販売されています。

基本スターターキット

スーパースターターキット

アルティメットスターターキット

参考サイト:

ESP32-S3-WROOM-1を搭載した最新モデルの記事を書きました。ぜひご覧ください。

Arduinoボード設定

Arduino IDEにESP32ボードを追加しておきます。

追加方法については、以下の記事をご参照ください。

  • ボードインストール

[ツール] > [ボード] > [ボードマネージャ]からESP32ボードをインストールします。

※ジェネリック品の場合はバージョン2.0.3をインストールしてください。 2022年12月18日

  • ボードの選択

[ツール] > [ボード] > [ESP32 Arduino] > [ESP32 Wrover Module]を選択します。

  • シリアルポートの選択

ボードが接続されているポートを選択します。

環境ポート名
Mac/dev/cu.wchusbserial*
WindowsCOM*
*(アスタリスク)は任意の文字列を表しています。

※シリアルポートが認識されない場合はCH340用シリアルドライバを以下からダウンロードしてインストールしてください。

GitHub
https://github.com/Freenove/Freenove_ESP32_WROVER_Board/tree/main/CH340

PlatformIO IDEを使用する場合

動作確認した内容を記載します。

PlatformIO IDE

バージョン Core 6.1.4/Home 3.4.3

開発環境

PlatformEspressif 32バージョン 5.1.1
ボードEspressif ESP-WROVER-KITフレームワーク
Arduino

CameraWebServerの修正済みArduinoスケッチをインポートしてプロジェクトを作成
※スケッチ例の修正方法は後述のサンプルプログラムに掲載しています。

以下の設定で動作確認しました。

platformio.ini (例)

[env:esp-wrover-kit]
platform = espressif32
board = esp-wrover-kit
framework = arduino
;upload_port = /dev/cu.wchusbserial14110
upload_speed = 921600
monitor_speed = 115200

upload_port

上記パラメーターはコメントアウトしていますが、必要であれば設定してください。

こちらがPlatformIO IDEで書き込んだCameraWebServerの動作例です。

Freenove FNK0060での動作例

サンプルプログラム (Arduinoスケッチ)

開発環境

Arduino IDE バージョン1.8.19 (※1系)
2.0.3 (※2系)
ESP32 Arduinoボード基本的に最新版でOK ※Freenove FNK0060の場合
2.0.3 ※ジェネリック品の場合

以下にpdfやサンプルスケッチがあります。

Freenove_ESP32_WROVER_Board/C at main · Freenove/Freenove_ESP32_WROVER_Board
Apply to FNK0060. Contribute to Freenove/Freenove_ESP32_WROVER_Board development by creating an account on GitHub.

CameraWebServer (Arduino IDEスケッチ例を使用する場合)

CameraWebServerスケッチを書き込む場合、スケッチサイズの関係上[ツール] > [Partition Scheme] > [Huge APP (3MB No OTA/1MB SPIFFS)]を選択してください。

GitHubのサンプルスケッチにSketch_05.1_CameraWebServerがありますが、Arduino IDEのスケッチ例([スケッチ例] > [ESP32] > [Camera] > [CameraWebServer])を使用する場合、次のように修正します。

  1. カメラモデルの指定
    CAMERA_MODEL_WROVER_KITのコメントをはずし、CAMERA_MODEL_AI_THINKERをコメントアウトします。
  2. Wi-Fi設定
    ssidとpasswordを接続先Wi-Fiのssidとpasswordに書き換えます。

スケッチを書き込んだのち、シリアルモニターを開きリセットボタンを押すとCameraWebServerのURL(画像赤枠参照)が確認できます。

ブラウザからシリアルモニターに表示されたURLにアクセスすると以下のような画面が表示されます。

動作例

映像を液晶ディスプレイに表示する(HSPI使用例)

ボタンを押すと映像が液晶ディスプレイに表示されるというスケッチ例です。

素材はこちら

液晶ディスプレイ

今回のスケッチ例ではST7789の液晶ディスプレイを使用します。

左: 1.54インチ 右: 1.3インチ

いずれも解像度は240×240です。

ちなみに1.3インチの方はCSピンがありません。そのためスケッチを動かす場合は修正が必要です。

製作例

1.54インチディスプレイの例

1.54インチディスプレイ使用
右の箱は今回の被写体に使っている素材で製作には無関係です。

1.3インチディスプレイの例

1.3インチディスプレイ使用
パーツについて
  • 液晶ディスプレイ
    ST7789のものを使っています。

  • ボタン
    1.54インチディスプレイの例で使用しているボタンはタッチでON/OFFができるトグルスイッチ式のものです。
    1.3インチディスプレイの例ではスライドスイッチを使用してみました。

  • ブレッドボード
    ニューブレッドボード(サンハヤト)を使っています。
スケッチで使用しているライブラリについて
  • Adafruit ST7735 and ST7789 Library
  • Adafruit GFX Library
  • TJpg_Decoder

いずれのライブラリもArduino IDEのライブラリマネージャーから検索してインストールできます。

スケッチ

#include "esp_camera.h"
#include <SPI.h>
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <TJpg_Decoder.h>

// Pin definition for CAMERA_MODEL_WROVER_KIT
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 21
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27

#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 19
#define Y4_GPIO_NUM 18
#define Y3_GPIO_NUM 5
#define Y2_GPIO_NUM 4
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22

// Pin definition for TFT HSPI
#define TFT_SCLK 14
#define TFT_MISO -1
#define TFT_MOSI 13
#define TFT_CS 15 // Chip select control pin
#define TFT_DC 32 // Data Command control pin
#define TFT_RST 33

// Pin button
#define PIN_BTN 12

Adafruit_ST7789 tft = Adafruit_ST7789(&SPI, TFT_CS, TFT_DC, TFT_RST);

bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap)
{
  // Stop further decoding as image is running off bottom of screen
  if (y >= tft.height())
    return 0;
  tft.drawRGBBitmap(x, y, bitmap, w, h);
  // Return 1 to decode next block
  return 1;
}

void init_camera()
{
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.frame_size = FRAMESIZE_UXGA;
  config.pixel_format = PIXFORMAT_JPEG; // for streaming
  config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  config.fb_location = CAMERA_FB_IN_PSRAM;
  config.jpeg_quality = 12;
  config.fb_count = 1;

  // if PSRAM IC present, init with UXGA resolution and higher JPEG quality
  //                      for larger pre-allocated frame buffer.
  if (config.pixel_format == PIXFORMAT_JPEG)
  {
    if (psramFound())
    {
      config.jpeg_quality = 10;
      config.fb_count = 2;
      config.grab_mode = CAMERA_GRAB_LATEST;
    }
    else
    {
      // Limit the frame size when PSRAM is not available
      config.frame_size = FRAMESIZE_SVGA;
      config.fb_location = CAMERA_FB_IN_DRAM;
    }
  }
  else
  {
    // Best option for face detection/recognition
    config.frame_size = FRAMESIZE_QVGA;
#if CONFIG_IDF_TARGET_ESP32S3
    config.fb_count = 2;
#endif
  }

  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK)
  {
    Serial.printf("Camera init failed with error 0x%x", err);
    for (;;)
      ;
  }

  sensor_t *s = esp_camera_sensor_get();
  // initial sensors are flipped vertically and colors are a bit saturated
  if (s->id.PID == OV3660_PID)
  {
    s->set_vflip(s, 1);       // flip it back
    s->set_brightness(s, 1);  // up the brightness just a bit
    s->set_saturation(s, -2); // lower the saturation
  }
  // drop down frame size for higher initial frame rate
  if (config.pixel_format == PIXFORMAT_JPEG)
  {
    s->set_framesize(s, FRAMESIZE_QVGA);
  }
}

void setup()
{
  Serial.begin(115200);
  Serial.println("ESP32-WROVER-CAM Picture");

  init_camera();

  // Use HSPI
  SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI);
  // if the display has CS pin try with SPI_MODE0
  tft.init(240, 240); // Init ST7789 display 240x240 pixel
  tft.fillScreen(ST77XX_BLACK);

  TJpgDec.setJpgScale(1);
  // The decoder must be given the exact name of the rendering function above
  TJpgDec.setCallback(tft_output);

  pinMode(PIN_BTN, INPUT);
}

void take_picture()
{
  Serial.println("Taking picture..");
  camera_fb_t *fb = NULL;

  fb = esp_camera_fb_get();
  if (!fb)
  {
    Serial.println("Camera capture failed");
    return;
  }

  static uint16_t w = 0, h = 0;
  TJpgDec.getJpgSize(&w, &h, fb->buf, fb->len);
  Serial.print("- Width = ");
  Serial.print(fb->width);
  Serial.print(", height = ");
  Serial.println(fb->height);

  // Draw the image, top left at 0,0
  TJpgDec.drawJpg(0, 0, fb->buf, fb->len);

  // Free buffer
  esp_camera_fb_return(fb);
}

void loop()
{
  static int state = LOW;
  if (digitalRead(PIN_BTN) == HIGH)
  {
    Serial.println("Button pressed");
    take_picture();
    state = HIGH;
  }
  else if (digitalRead(PIN_BTN) == LOW && state == HIGH)
  {
    tft.fillScreen(ST77XX_BLACK);
    state = LOW;
  }

  delay(500);
}

ピン接続は次のようになっています。

項目GPIO備考
TFT SCLK14HSPI SCLK
TFT MOSI13HSPI MOSI
TFT CS15HSPI CS
TFT DC32
TFT RST33
BUTTON(スイッチ)12ボタン(トグルスイッチ)
INPUT
※TFTは液晶ディスプレイを表しています

液晶ディスプレイはHSPIで接続するようにしています。

スイッチに割り当てるGPIOが不足したため、GPIO12(HSPI MISO)を入力ピンに割り当てています。

スケッチの修正について

1.3インチディスプレイを使用する場合、CSピンがないためSPIをMODE 2に設定します。

tft.initの箇所を以下のように修正します。

  tft.init(240, 240, SPI_MODE2); // Init ST7789 display 240x240 pixel

スライドスイッチを使用する場合

以下のようにON側に3.3V(赤ワイヤー)、OFF側にGND(黒ワイヤー)、入力(青ワイヤー)をGPIO12に接続すればON/OFFを実現できます。

今回の製作例のようにON側の3.3V(赤)のみ配線する場合、以下のようにOFF側にスイッチを入れているとき入力ピン(青)の状態が不安定になります。

そこで、setup関数内のボタン入力ピンの設定を以下のようにINPUT_PULLDOWNにするとスイッチがOFF側(入力ピン(青)が開放された状態)の時に内部プルダウンされるようになるのでGNDの配線をしなくても動作するようになるかと思います。

  pinMode(PIN_BTN, INPUT_PULLDOWN);

1.3インチディスプレイ動作例

プリズムを使ってみました

見た目は透明なブロックみたいな感じです。1辺25.4mmの正方形です。

このプリズムを液晶ディスプレイに乗せるとプリズムに映像が投影されます。

投影している様子がこちら

関連記事

当ブログのマイコン記事です。ぜひご覧ください。

コメント

タイトルとURLをコピーしました