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
安装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.
保存到文件夹下
修改内容:
··· //添加库引用 #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