ESP32-CAM

hardware

  • esp32-cam ( ESP32-S chip + OV2640 camera + microSD card slot )

  • ov2640

  • FTDI programmer(upload code /USB to TTL Serial Converter)

Part A

how to set up a video streaming webserver with the example project

Part B

Streaming into the local network

Node.js +WebSocket=local server

检查已经安装node.js & npm

node -v V10.16.1

npm -v 6.14.8

安装packages

F:\> mkdir ESP32_CAM_LocalServer
F:\> cd ESP32_CAM_LocalServer
> npm init
> npm install --save path
> npm install --save express
> npm install --save ws

创建文件

  • server.js

  • client.html

vs code 打开编辑

code .

查看本地IP,修改ws_url为’ws://ip:port’.

ipconfig

定义:本地server的http port=8000,websocket port=8888.

运行node.js server

> mode server.js
ws server is listening at 8888
http server listening at 8000

esp32-cam 连接直接(websocket)到ws server, browser client 通过http server连接到ws server.

打开Arduino IDE

工具-管理库 安装ArduinoWebsockets 0.4.13

Download & install ESP32 board manager

文件-首选项 附加开发板管理器网址添加esp32 url. Stable release link: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

有些是:文件–>首选项–>附加开发板管理网址 输入https://dl.espressif.com/dl/package_esp32_index.json

工具-开发板-开发板管理库(Board Manager),输入esp32. 安装V1.0.4

打开示例file-examples-esp32-camera-camerawebserver. 保存到文件夹下 (4个文件.ino/.cpp/.h)。

修改内容:

··· //添加库引用 #include <ArduinoWebsockets.h> //选择正确cam(修改摄像头模块,默认选择是第一种摄像头模块;安信可,选择第五个) #define CAMERA_MODEL_AI_THINKER

//修改wifi:ssid & password //加入定义 const char* websocket_server_host=”192.168.31.94”; const uint16_t websocket_server_port=8888;

// 注释掉function定义及调用 // startCameraServer();

//修改cam参数 XCLR - 10Mhz Frame Size - VGA (640x480) JPEG quality - 40 (Lower is good quality)

//删除无用代码 #if defined(CAMERA_MODEL_ESP_EYE) pinMode(13, INPUT_PULLUP); pinMode(14, INPUT_PULLUP); #endif

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 blightness just a bit s->set_saturation(s, -2);//lower the saturation } //drop down frame size for higher initial frame rate s->set_framesize(s, FRAMESIZE_QVGA);

#if defined(CAMERA_MODEL_M5STACK_WIDE) s->set_vflip(s, 1); s->set_hmirror(s, 1); #endif

// 添加定义 using namespace websockets; WebsocketsClient client;

//wifi连接后 添加连接node.js server

//处理获取的JPEG

//Build ····

构建Build

ftdi连接esp32-cam

5v-5v  (or 3v3-3v3)
gnd-gnd
rx-U0T
tx-U0R

arduino连接板信息: Board “ESP32 Wrover Module” Upload Speed “921600” Flash Frequency:”80MHz” Flash Mode “QIO” Partition Scheme “Huge APP (3MB No OTA/1MB SPIFFS)” Port “Com7” Programmer “ArduinoISP”

烧录用5V,工作可以用3V3。 烧写的时候esp32-cam短接IO0-gnd引脚(拉低IO0电平),按下reset button。 完成后空开短接,按下reset button。

有些设置为: Upload Speed “115200” Flash Frequency:”40MHz” Programmer “AVR ISP”

CameraWeb.ino代码 ··· #include “esp_camera.h” #include <WiFi.h> #include <ArduinoWebsockets.h> #define CAMERA_MODEL_AI_THINKER #include “camera_pins.h” const char* ssid = “Xiaomi_78B9”; // wifi name const char* password = “12341234”; //wifi password const char* websocket_server_host=”192.168.31.94”; const uint16_t websocket_server_port= 8888; //void startCameraServer(); using namespace websockets; WebsocketsClient client;

void setup() { Serial.begin(115200); Serial.setDebugOutput(true); Serial.println();

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 = 10000000; //20000000 config.pixel_format = PIXFORMAT_JPEG; //init with high specs to pre-allocate larger buffers if(psramFound()){ config.frame_size = FRAMESIZE_VGA;// FRAMESIZE_UXGA; config.jpeg_quality = 40 ;//10; config.fb_count = 2; } else { config.frame_size = FRAMESIZE_SVGA; config.jpeg_quality = 12; config.fb_count = 1; }

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

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print(“.”); } Serial.println(“”); Serial.println(“WiFi connected”);

// startCameraServer();

Serial.print(“Camera Ready! Use ‘http://”); Serial.print(WiFi.localIP()); Serial.println(“’ to connect”);

while(!client.connect(websocket_server_host,websocket_server_port,”/”)){ delay(500); Serial.print(“.”); } Serial.println(“Websocket Connected!”); }

void loop() { // put your main code here, to run repeatedly: //delay(30);

camera_fb_t *fb = esp_camera_fb_get(); if (!fb){ Serial.println(“Camera capture failed”); esp_camera_fb_return(fb); return; }

if (fb->format != PIXFORMAT_JPEG){ Serial.println(“Non-JPEG data not implemented”); return; }

client.sendBinary((const char*) fb->buf,fb->len); esp_camera_fb_return(fb); } ···

Part C1

Multiple CAM Dashboard (ft. Modified Jpeg Header)

JPG 文件开头FFD8结尾FFD9. 修改第array[12]作为cam id如01-09.

WebCamera.ino code ··· #include “esp_camera.h” #include <WiFi.h> #include <ArduinoWebsockets.h> #define CAMERA_MODEL_AI_THINKER #include “camera_pins.h” const char* ssid = “Xiaomi_78B9”; // wifi name const char* password = “12341234”; //wifi password const char* websocket_server_host=”192.168.31.94”; const uint16_t websocket_server_port= 8888; //void startCameraServer(); using namespace websockets; WebsocketsClient client; bool isWebSocketConnected;

void onEventsCallback(WebsocketsEvent event, String data){ if(event == WebsocketsEvent::ConnectionOpened){ Serial.println(“Connection Opened”); isWebSocketConnected= true; }else if(event == WebsocketsEvent::ConnectionClosed){ Serial.println(“Connection Closed”); isWebSocketConnected= false; webSocketConnect(); } }

void setup() { isWebSocketConnected= false; Serial.begin(115200); Serial.setDebugOutput(true); Serial.println();

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 = 10000000; //20000000 config.pixel_format = PIXFORMAT_JPEG; //init with high specs to pre-allocate larger buffers //if(psramFound()){ config.frame_size = FRAMESIZE_VGA;// FRAMESIZE_UXGA; //FRAMESIZE_SVGA config.jpeg_quality = 40 ;//10; //12 config.fb_count = 2; //1

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

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print(“.”); } Serial.println(“”); Serial.println(“WiFi connected”);

// startCameraServer(); //Serial.print(“Camera Ready! Use ‘http://”); //Serial.print(WiFi.localIP()); //Serial.println(“’ to connect”); client.onEvent(onEventsCallback); //register webSocketConnect(); }

void webSocketConnect(){ while(!client.connect(websocket_server_host,websocket_server_port,”/”)){ delay(500); Serial.print(“.”); } Serial.println(“Websocket Connected!”); }

void loop() { if(client.available()){ client.poll(); } if(!isWebSocketConnected) return; //delay(30);

camera_fb_t *fb = esp_camera_fb_get(); if (!fb){ Serial.println(“Camera capture failed”); esp_camera_fb_return(fb); return; }

if (fb->format != PIXFORMAT_JPEG){ Serial.println(“Non-JPEG data not implemented”); return; }

fb->buf[12] = 0x01; //FIRST Camera

client.sendBinary((const char*) fb->buf,fb->len); esp_camera_fb_return(fb); } ···

Part C2

remote