- ESP32
#include <Arduino.h> /* esp32cam_to_esp32:. esp32cam_to_esp32:. esp32cam_to_esp32:. esp32cam_to_esp32:. esp32cam_to_esp32:. esp32cam_to_esp32:. esp32cam_to_esp32:. esp32cam_to_esp32:. esp32cam_to_esp32:. esp32cam_to_esp32:. esp32cam_to_esp32:Connected esp32cam_to_esp32:Connected esp32cam_to_esp32:IP Address: esp32cam_to_esp32:IP Address: esp32cam_to_esp32:67152064 esp32cam_to_esp32:67152064 esp32cam_to_esp32:Camera Init OK! esp32cam_to_esp32:Camera Init OK! esp32cam_to_esp32:Connect To Tcp Server Failed!After 10 Seconds Try Again! esp32cam_to_esp32:Connect To Tcp Server Failed!After 10 Seconds Try Again! esp32cam_to_esp32:Connect To Tcp Server Failed!After 10 Seconds Try Again! esp32cam_to_esp32:Connect To Tcp Server Failed!After 10 Seconds Try Again! */ String recv_data = ""; //接受串口数据的变量 String esp32_head = "esp32_head:"; //esp32与服务器的通信标识头 //esp32cam 串口向 esp32发送消息的标识头 主要是联网信息 摄像头初始化信息等 // 这些信息 esp32显示在串口或小屏幕上 String esp32cam_to_esp32 = "esp32cam_to_esp32:"; const int LED = 2; void setup() { Serial.begin(115200); Serial2.begin(115200); pinMode(LED,OUTPUT); digitalWrite(LED, LOW); } void loop() { if(Serial2.available()){ recv_data = Serial2.readStringUntil('\n'); Serial.println(recv_data); if(recv_data.substring(0,esp32_head.length()) == esp32_head){ //消息来自服务器端 处理相关指令 必须这样判断 防止存在 \r\n等看不见的字符 if(recv_data.substring(0,(esp32_head + "openLed").length()) == (esp32_head + "openLed") ){ digitalWrite(LED, HIGH); Serial2.println( esp32_head + "Led ON!"); //串口发送给ESPCAM ESPCAM在发送给服务器 } if(recv_data.substring(0,(esp32_head + "closeLed").length()) == (esp32_head + "closeLed") ){ digitalWrite(LED, LOW); Serial2.println( esp32_head + "Led OFF!"); } }else if(recv_data.substring(0,esp32cam_to_esp32.length()) == esp32cam_to_esp32){ //消息来自esp32cam的数据一般为一些提示信息 可以用在串口或屏幕起到提示作用 Serial.println(recv_data); }else{ Serial.println("Error Msg!"); } } }
- ESP32CAM
#include <Arduino.h> #include <WiFi.h> #include "esp_camera.h" #include <vector> const char *ssid = "dsx_zj"; const char *password = "dsxbs725"; const IPAddress serverIP(192,168,0,2); //欲访问的地址 uint16_t serverPort = 8080; //服务器端口号 String esp32_head = "esp32_head:"; //esp32与服务器的通信标识头 String esp32_cam_head = "esp32_cam_head:"; //esp32cam与服务器的通信标识头 //esp32cam 串口向 esp32发送消息的标识 发送的消息主要是联网信息 摄像头初始化信息等 // 这些信息 esp32用来显示在串口或小屏幕上 起到提醒作用 String esp32cam_to_esp32 = "esp32cam_to_esp32:"; bool cam_state = true; //打开或关闭摄像头标识 const int LED = 4;//闪光灯 const int ZHESHI_LED = 33; //指示灯 亮表示连接上服务器 灭表示没有连上服务器 String esp32_data = "";//保存esp32串口发过来的数据 然后espcam转发给服务器 #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, }; //初始化摄像头 esp_err_t camera_init() { //initialize the camera esp_err_t err = esp_camera_init(&camera_config); if (err != ESP_OK) { Serial.println( esp32cam_to_esp32 + "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(esp32cam_to_esp32 + "Camera Init OK!"); return ESP_OK; } //初始化wifi void wifi_init() { WiFi.mode(WIFI_STA); WiFi.setSleep(false); //关闭STA模式下wifi休眠,提高响应速度 WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.println(esp32cam_to_esp32 + "."); } Serial.println(esp32cam_to_esp32 + "Connected"); Serial.println(esp32cam_to_esp32 + "IP Address:"); Serial.println(esp32cam_to_esp32 + WiFi.localIP()); } void setup() { Serial.begin(115200); pinMode(ZHESHI_LED, OUTPUT); digitalWrite(ZHESHI_LED, HIGH); pinMode(LED, OUTPUT); digitalWrite(LED, LOW); wifi_init(); camera_init(); } void loop() { if (client.connect(serverIP, serverPort)) //尝试访问目标地址 { client.println(esp32_cam_head + "Hello Server,I Am ESP32CAM!"); digitalWrite(ZHESHI_LED, LOW); while (client.connected() || client.available()) //如果已连接或有收到的未读取的数据 { // 读取串口esp32数据 转发给服务器 if(Serial.available()) { esp32_data = Serial.readStringUntil('\n'); client.println(esp32_data); } if (client.available()) //如果tcp网络有数据可读取 读取网络数据 { String line = client.readStringUntil('\n'); //读取数据到换行符 // 如果数据是服务器发送给esp32的 则通过串口发给esp32 if (line.substring(0,esp32_head.length()) == esp32_head) { Serial.println(line); } // 如果数据是服务器发送给esp32cam的 则 根据指令处理相关逻辑 if (line.substring(0,esp32_cam_head.length()) == esp32_cam_head) { // 打开摄像头 if(line == (esp32_cam_head + "openCam") ){ cam_state = true; client.println(esp32_cam_head + "Camera ON!"); } // 关闭摄像头 if(line == (esp32_cam_head + "closeCam") ){ cam_state = false; client.println(esp32_cam_head + "Camera OFF!"); } // 打开闪光灯 if(line == (esp32_cam_head + "openLed") ){ digitalWrite(LED, HIGH); client.println(esp32_cam_head + "Led ON!"); } // 关闭闪光灯 if(line == (esp32_cam_head + "closeLed") ){ digitalWrite(LED, LOW); client.println(esp32_cam_head + "Led OFF!"); } } } // 视频传输 if(cam_state) { camera_fb_t * fb = esp_camera_fb_get(); uint8_t * temp = fb->buf; //这个是为了保存一个地址,在摄像头数据发送完毕后需要返回,否则会出现板子发送一段时间后自动重启,不断重复 if (!fb) { Serial.println(esp32cam_to_esp32 + "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(20);//短暂延时 增加数据传输可靠性 } } } else { digitalWrite(ZHESHI_LED, HIGH); Serial.println(esp32cam_to_esp32 + "Connect To Tcp Server Failed!After 10 Seconds Try Again!"); client.stop(); //关闭客户端 } delay(10000); }
- TCP Server
import socket import threading import time import cv2 import numpy as np from tkinter import * # 监听连接 def handle_accept(): while True: # 阻塞连接 info一个socket对象 info, addr = server.accept() client_list.append(info) #有客户端连接 将客户端对象放在列表 # 开线程 用于接受客户端数据 t = threading.Thread(target=recv_data, args=(info, addr)) t.start() # 接收客户端数据 def recv_data(sock, addr): temp_data = b'' # 保存一张照片数据 while True: try: data = sock.recv(1430) except Exception as e: print(e) sock.close() client_list.remove(sock) #data = sock.recv(1430) 出现异常 先关闭在移除 if bool(data): # 判断数据不为 b'' # print('收到客户端的信息:' + data.decode('utf-8')) # 如果这一帧数据包的开头是 b'Frame Begin' 则是一张图片的开始 #图像数据 标志位 b'Frame Begin' if data[0:len(begin_data)] == begin_data: t1 = int(round(time.time() * 1000)) # 将这一帧数据包的开始标志信息(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'' # 清空数据 便于下一章照片使用 # esp32发送过来的数据 标志位b'esp32_head:' if data[0:len(esp32_head)] == esp32_head: print('来自ESP32的消息:' + data.decode()) # esp32cam发送过来的数据 标志位 b'esp32_cam_head:' if data[0:len(esp32_cam_head)] == esp32_cam_head: print('来自ESP32CAM的消息:' + data.decode()) # 关闭ESP32cam摄像头 别忘记发送数据带 esp32_cam_head def close_cam(): for s in client_list: try: s.send(esp32_cam_head + 'closeCam'.encode()) except: try: s.close() client_list.remove(s) except: print("Client is Closed!") # 打开ESP32cam摄像头 别忘记发送数据带 esp32_cam_head def open_cam(): for s in client_list: try: s.send(esp32_cam_head + 'openCam'.encode()) except: try: s.close() client_list.remove(s) except: print("Client is Closed!") # 打开ESP32cam闪光灯 别忘记发送数据带 esp32_cam_head def open_led(): for s in client_list: try: s.send(esp32_cam_head + 'openLed'.encode()) except: try: s.close() client_list.remove(s) except: print("Client is Closed!") # 关闭ESP32cam闪光灯 别忘记发送数据带 esp32_cam_head def close_led(): for s in client_list: try: s.send(esp32_cam_head + 'closeLed'.encode()) except: try: s.close() client_list.remove(s) except: print("Client is Closed!") # 打开ESP32上的led 别忘记发送数据带 esp32_head def open_esp32_led(): for s in client_list: try: s.send(esp32_head + 'openLed'.encode()) except: try: s.close() client_list.remove(s) except: print("Client is Closed!") # 关闭ESP32上的led 别忘记发送数据带 esp32_head def close_esp32_led(): for s in client_list: try: s.send(esp32_head + 'closeLed'.encode()) except: try: s.close() client_list.remove(s) except: print("Client is Closed!") client_list = [] #列表存放客户端对象 begin_data = b'Frame Begin' # 接受摄像头一张照片数据的起始标志 end_data = b'Frame Over' # 接受摄像头一张照片数据的结束标志 esp32_head = b'esp32_head:' # 发送和接受esp32消息的标志头 esp32_cam_head = b'esp32_cam_head:' # 发送和接受esp32cam消息的标志头 # 创建窗口 win = Tk() # 设置窗口大小 win.geometry("440x300") # 添加一个Label用于显示视频 label = Label(win) label.grid(row=0, column=0) btn = Button(win, text="关闭摄像头", command=close_cam) btn.grid(row=1, column=1) btn = Button(win, text="打开摄像头", command=open_cam) btn.grid(row=2, column=1) btn = Button(win, text="打开闪光灯", command=open_led) btn.grid(row=3, column=1) btn = Button(win, text="关闭闪光灯", command=close_led) btn.grid(row=4, column=1) btn = Button(win, text="打开ESP32灯", command=open_esp32_led) btn.grid(row=5, column=1) btn = Button(win, text="关闭ESP32灯", command=close_esp32_led) btn.grid(row=6, column=1) server = socket.socket() #创建回话对象 host = ('192.168.0.2', 8080) #设置主机 server.bind(host) #建立长期的连接 server.listen(5) #设置监听 # 开线程 监听连接 t0 = threading.Thread(target=handle_accept) t0.start() win.mainloop()
tcp服务端与ESP32Cam通信ESP32Cam通过串口控制ESP32
最新推荐文章于 2024-04-23 10:19:59 发布