您现在的位置是:网站首页> 硬件

ESP32开发相关资料收集

  • 硬件
  • 2024-08-23
  • 243人已阅读
摘要

ESP32开发相关资料收集


arduino配置esp32-cam开发环境

ESP32-CAM视频传输至公网服务器并转发视频数据流

ESP32-CAM 摄像头开发板 进行 推流 已解决

保姆级教程手把手教你使用Arduino开发ESP32



ESP32-CAM视频传输至公网服务器并转发视频数据流

上代码, esp32-cam端使用的Arduino c语言编写: 

#include <Arduino.h>

#include <WiFi.h>

#include "esp_camera.h"

#include <vector>

 

const char *ssid = "xxxx"; //wifi用户名

const char *password = "xxxx"; //wifi密码

const IPAddress serverIP(xxxx);  //你自己的公网服务器ip地址

uint16_t serverPort = xxxx;         //服务器端口号(tcp协议)

 

#define maxcache 1430

 

WiFiClient client; //声明一个客户端对象,用于与服务器进行连接

 

//CAMERA_MODEL_AI_THINKER类型摄像头的引脚定义

#define PWDN_GPIO_NUM     32

#define RESET_GPIO_NUM    -1

#define XCLK_GPIO_NUM      0

#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       21

#define Y4_GPIO_NUM       19

#define Y3_GPIO_NUM       18

#define Y2_GPIO_NUM        5

#define VSYNC_GPIO_NUM    25

#define HREF_GPIO_NUM     23

#define PCLK_GPIO_NUM     22

 

static camera_config_t camera_config = {

    .pin_pwdn = PWDN_GPIO_NUM,

    .pin_reset = RESET_GPIO_NUM,

    .pin_xclk = XCLK_GPIO_NUM,

    .pin_sscb_sda = SIOD_GPIO_NUM,

    .pin_sscb_scl = SIOC_GPIO_NUM,

    

    .pin_d7 = Y9_GPIO_NUM,

    .pin_d6 = Y8_GPIO_NUM,

    .pin_d5 = Y7_GPIO_NUM,

    .pin_d4 = Y6_GPIO_NUM,

    .pin_d3 = Y5_GPIO_NUM,

    .pin_d2 = Y4_GPIO_NUM,

    .pin_d1 = Y3_GPIO_NUM,

    .pin_d0 = Y2_GPIO_NUM,

    .pin_vsync = VSYNC_GPIO_NUM,

    .pin_href = HREF_GPIO_NUM,

    .pin_pclk = PCLK_GPIO_NUM,

    

    .xclk_freq_hz = 20000000,

    .ledc_timer = LEDC_TIMER_0,

    .ledc_channel = LEDC_CHANNEL_0,

    

    .pixel_format = PIXFORMAT_JPEG,

    .frame_size = FRAMESIZE_VGA,

    .jpeg_quality = 12,

    .fb_count = 1,

};

void wifi_init()

{

    WiFi.mode(WIFI_STA);

    WiFi.setSleep(false); //关闭STA模式下wifi休眠,提高响应速度

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED)

    {

        delay(500);

        Serial.print(".");

    }

    Serial.println("WiFi Connected!");

    Serial.print("IP Address:");

    Serial.println(WiFi.localIP());

}

esp_err_t camera_init() {

    //initialize the camera

    esp_err_t err = esp_camera_init(&camera_config);

    if (err != ESP_OK) {

        Serial.println("Camera Init Failed");

        return err;

    }

    sensor_t * s = esp_camera_sensor_get();

    //initial sensors are flipped vertically and colors are a bit saturated

    if (s->id.PID == OV2640_PID) {

    //        s->set_vflip(s, 1);//flip it back

    //        s->set_brightness(s, 1);//up the blightness just a bit

    //        s->set_contrast(s, 1);

    }

    Serial.println("Camera Init OK!");

    return ESP_OK;

}

 

void setup()

{

    Serial.begin(115200);

    wifi_init();

    camera_init();

}

 

void loop()

{

    Serial.println("Try To Connect TCP Server!");

    if (client.connect(serverIP, serverPort)) //尝试访问目标地址

    {

        Serial.println("Connect Tcp Server Success!");

        client.println("Frame Begin");  //46 72 61 6D 65 20 42 65 67 69 6E // 0D 0A 代表换行  //向服务器发送数据

        while (1){       

          camera_fb_t * fb = esp_camera_fb_get();

          uint8_t * temp = fb->buf; //这个是为了保存一个地址,在摄像头数据发送完毕后需要返回,否则会出现板子发送一段时间后自动重启,不断重复

          if (!fb)

          {

              Serial.println( "Camera Capture Failed");

          }

          else

          { 

            //先发送Frame Begin 表示开始发送图片 然后将图片数据分包发送 每次发送1430 余数最后发送 

            //完毕后发送结束标志 Frame Over 表示一张图片发送完毕 

            client.print("Frame Begin"); //一张图片的起始标志

            // 将图片数据分段发送

            int leng = fb->len;

            int timess = leng/maxcache;

            int extra = leng%maxcache;

            for(int j = 0;j< timess;j++)

            {

              client.write(fb->buf, maxcache); 

              for(int i =0;i< maxcache;i++)

              {

                fb->buf++;

              }

            }

            client.write(fb->buf, extra);

            client.print("Frame Over");      // 一张图片的结束标志

            Serial.print("This Frame Length:");

            Serial.print(fb->len);

            Serial.println(".Succes To Send Image For TCP!");

            //return the frame buffer back to the driver for reuse

            fb->buf = temp; //将当时保存的指针重新返还

            esp_camera_fb_return(fb);  //这一步在发送完毕后要执行,具体作用还未可知。        

          }

          delay(30);//短暂延时 增加数据传输可靠性

        }

        /*

        while (client.connected() || client.available()) //如果已连接或有收到的未读取的数据

        {

            if (client.available()) //如果有数据可读取

            {

                String line = client.readStringUntil('\n'); //读取数据到换行符

                Serial.print("ReceiveData:");

                Serial.println(line);

                client.print("--From ESP32--:Hello Server!");    

            }

        }

        Serial.println("close connect!");

        client.stop(); //关闭客户端

        */

    }

    else

    {

        Serial.println("Connect To Tcp Server Failed!After 10 Seconds Try Again!");

        client.stop(); //关闭客户端

    }

    delay(10000);

}


客户端代码, Python编写:


import socket

import threading

import time

import numpy as np

import cv2

 

begin_data = b'Frame Begin'

end_data = b'Frame Over'

 

 

# 接收数据

# ESP32发送一张照片的流程

# 先发送Frame Begin 表示开始发送图片 然后将图片数据分包发送 每次发送1430 余数最后发送

# 完毕后发送结束标志 Frame Over 表示一张图片发送完毕

# 1430 来自ESP32cam发送的一个包大小为1430 接收到数据 data格式为b''

def handle_sock(sock, addr):

    temp_data = b''

    t1 = int(round(time.time() * 1000))

    while True:

        data = sock.recv(1430)

        # 如果这一帧数据包的开头是 b'Frame Begin' 则是一张图片的开始

        if data[0:len(begin_data)] == begin_data:

            # 将这一帧数据包的开始标志信息(b'Frame Begin')清除   因为他不属于图片数据

            data = data[len(begin_data):len(data)]

            # 判断这一帧数据流是不是最后一个帧 最后一针数据的结尾时b'Frame Over'

            while data[-len(end_data):] != end_data:

                temp_data = temp_data + data  # 不是结束的包 将数据添加进temp_data

                data = sock.recv(1430)  # 继续接受数据 直到接受的数据包包含b'Frame Over' 表示是这张图片的最后一针

            # 判断为最后一个包 将数据去除 结束标志信息 b'Frame Over'

            temp_data = temp_data + data[0:(len(data) - len(end_data))]  # 将多余的(\r\nFrame Over)去掉 其他放入temp_data

            # 显示图片

            receive_data = np.frombuffer(temp_data, dtype='uint8')  # 将获取到的字符流数据转换成1维数组

            r_img = cv2.imdecode(receive_data, cv2.IMREAD_COLOR)  # 将数组解码成图像

            r_img = r_img.reshape(480, 640, 3)

            t2 = int(round(time.time() * 1000))

            fps = 1000 // (t2 - t1)

            cv2.putText(r_img, "FPS" + str(fps), (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)

            cv2.imshow('server_frame', r_img)

            if cv2.waitKey(1) & 0xFF == ord('q'):

                break

            t1 = t2

            # print("接收到的数据包大小:" + str(len(temp_data)))  # 显示该张照片数据大小

            temp_data = b''  # 清空数据 便于下一章照片使用

 

 

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server.connect(("xxxx", xxxx))

server.send('monitor'.encode("utf-8"))

# server.bind(('0.0.0.0', 9090))

# server.listen(5)

# CONNECTION_LIST = []

 

# 主线程循环接收客户端连接

handle_sock(server, '')  # mac电脑直接在主线程运行

# while True:

    # sock, addr = server.accept()

    # CONNECTION_LIST.append(sock)

    # print('Connect--{}'.format(addr))

    # 连接成功后开一个线程用于处理客户端

    # handle_sock(server, '')  # mac电脑直接在主线程运行

    # client_thread = threading.Thread(target=handle_sock, args=(sock, addr))

    # client_thread.start()


这里做一下特别说明, 在python代码的最后主线程那里, 由于我是运行在Mac电脑中, 所以不能开新的线程, 否则会报错, 如果你是运行在Windows电脑下, 请把注释打开, 创建新线程来运行.


下面是nodejs写的服务器端代码, 用于视频数据流的透传转发:


// 创建tcp连接服务

const net = require('net')

const { size } = require('underscore')

const HOST = 'xxxx'

const PORT = xxxx

 

// 创建udp

// const dgram = require("dgram")

// const server = dgram.createSocket("udp4")

 

// 统计连接客户端的个数

var count = 0

 

// 创建slave_server服务

const slave_server = new net.createServer()

// slave_server.setEncoding = 'UTF-8'

 

// 保存监视器的socket

var s

 

// 获得一个连接,该链接自动关联scoket对象

var tcp_sock = null

slave_server.on('connection', sock => {

  tcp_sock = sock

  sock.name = ++count

  console.log(`当前连接客户端数:${count}`)

 

  // 接收client发来的信息  

  sock.on('data', data => {

    // console.log(`客户端${sock.name}发来一个信息:${data}`)

 

    // 判断是否为监视器发来的链接

    if (data == 'monitor') {

      

      // 则把当前的socket保存起来

      s = sock

    } else {

      s.write(data)

    }

  })

 

  // 为socket添加error事件处理函数

  sock.on('error', error => { //监听客户端异常

    console.log('error' + error)

    sock.end()

  })

 

  // 服务器关闭时触发,如果存在连接,这个事件不会被触发,直到所有的连接关闭

  sock.on('close', () => {

    console.log(`客户端${sock.name}下线了`)

    count -= 1

  })

})

 

// listen函数开始监听指定端口

slave_server.listen(PORT, () => {

  console.log(`服务器已启动,运行在:http://xxxx:xxxx`)

})

再次特别说明一下, 先启动服务器端代码, 然后在电脑端运行python端代码, 最后再烧录esp32-cam的代码, 第一次运行时电脑客户端可能报错直接就退出了, 没关系, 重新运行一下电脑客户端的python代码, 就能看到视频图像了. 我在服务器端的逻辑是接收到'monitor'字符串时认为是客户端监视器, 把对应的socket保存一下, 然后当接收到下一个socket连接时, 则默认认为是esp32-cam, 将之前保存的socket取出来, 把视频流数据转发出去, 此种方式只能有一个esp32-cam和一个客户端监视器, 有需要的小伙伴可以自行修改代码.



ESP32-CAM 摄像头开发板 进行 推流 已解决

项目背景,自己喜欢折腾电子。对嘉立创打板子。非常热爱。 购买了n多个电子模块 都在这儿进行一一展示,

1.png

2.png


配置参数

3.png

 


祖传代码


       


#include "esp_camera.h"

#include <WiFi.h>

 

//

// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality

//            Ensure ESP32 Wrover Module or other board with PSRAM is selected

//            Partial images will be transmitted if image exceeds buffer size

//

 

// Select camera model

//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM

//#define CAMERA_MODEL_ESP_EYE // Has PSRAM

//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM

//#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM

//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM

//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM

#define CAMERA_MODEL_AI_THINKER // Has PSRAM

//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM

 

#include "camera_pins.h"

 

const char* ssid = "*****";

const char* password = "******";

 

void startCameraServer();

 

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 = 20000000;

  config.pixel_format = PIXFORMAT_JPEG;

  

  // if PSRAM IC present, init with UXGA resolution and higher JPEG quality

  //                      for larger pre-allocated frame buffer.

  if(psramFound()){

    config.frame_size = FRAMESIZE_UXGA;

    config.jpeg_quality = 10;

    config.fb_count = 2;

  } else {

    config.frame_size = FRAMESIZE_SVGA;

    config.jpeg_quality = 12;

    config.fb_count = 1;

  }

 

#if defined(CAMERA_MODEL_ESP_EYE)

  pinMode(13, INPUT_PULLUP);

  pinMode(14, INPUT_PULLUP);

#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);

    return;

  }

 

  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

  s->set_framesize(s, FRAMESIZE_QVGA);

 

#if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM)

  s->set_vflip(s, 1);

  s->set_hmirror(s, 1);

#endif

 

  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");

}

 

void loop() {

  // put your main code here, to run repeatedly:

  delay(10000);

}

 出现问题 三种情况


   1、问题一    1.png 


 解决办法 、出现这个问题。 在出现 connectiing 的时候。按住按键


1.png


 问题二1.png


        


解决办法 设置 比特率


是由于ESP32的开发版下载速度太大出的问题,把下载速度设为460800波特率或者更低试试


问题三 


        串口窗口乱码问题。  设置波特率 115200 


传输完毕 


        开机 在一定时间按一下 那个 boo键。就能正常使用

1.png

        


出现  wifi连接地址  进行简单配置 


浏览器输入 192.168.31.9  进行 简单配置。进行简单推流    

1.png



 购买建议


        由于自己喜欢玩,一下买了两个


        1.png

2.png





        


右面镜头比左面镜头清晰, 建议购买 右面产品。 摄像头参数 分别 


                左面:AF2569C927*8   右面:DC-26 40-V3


1.png

2.png




购买截图。 没记错右面专门选的摄像头是高清的。 

3.png

                


记录完毕。 接下里会根据 安立信芯片 画一个班子。 做一个属于自己的监控小工具。 配合小程序 可以进行 远程查看



保姆级教程手把手教你使用Arduino开发ESP32

Arduino简单,易学,好用,资料全,特别适合小白新手上路。但是最初ARDUINO使用 ATMEL的51单片机同级别低配芯片,频率限制了我的想象力!


ESP32频率高,价格低,内置蓝牙WIFI,支持语音识别LVGL等,是国产芯片中神一样的存在,大有取代STM32的趋势,再不学就晚了。但是原生的ESP_IDF确实对新手不太友好。还没开始写代码,就需要整开发环境,搞FREERTOS,头疼头疼。


ESP32+ARDUINO强强联手,价格便宜,功能强大,界面友好,创意多多。接下来自己挖坑自己填,用ESP32+ARDUINO平台,完成一些好玩的东西。边学边玩边输出,不亦乐乎!


下载开发环境

官网连接入选:


https://www.arduino.cc/en/software

完成下载后,直接解压即可运行。


也可以从百度网盘下载:


链接:https://pan.baidu.com/s/1vmKzPDiy4NKpyVISvsCSNg


提取码:4dp8


安装开发环境

 1.png


发现这里没有ESP32开发板,下面进行ESP32开发环境安装。

2.png

进入首选项。

1.png


这里输入ESP32 ARDUINO的网址。


https://dl.espressif.com/dl/package_esp32_index.json


然后再次进入工具->开发板->开发板管理器

1.png


安装需要一端时间。 


 1.png


下载时候往往会出错。如果出错,多试几次即可。实在不行也可以用手机热点来试试。多试几次基本上都可以安装成功。














Top