2025-5-16 21:28:47 [显示全部楼层]
101浏览
查看: 101|回复: 0

[ESP8266/ESP32] ESP32-AI摄像头物体检测+边框追踪

[复制链接]
本帖最后由 楼主 于 2025-5-16 21:32 编辑

本次测试的内容为ESP32 AI camera实现物体检测和物体追踪
五一前收到了心心念念的新一代ESP32 camera,听说从硬件上对产品做了很大的提升。不过最近工作任务太多,测试早早做完了,但是一直没有发帖子分享,这周终于挤出了时间码一篇心得,话不多说看看实测效果。
一、实验目的​​
掌握ESP32 AI Camera的硬件配置与开发环境搭建方法。
设计算法实现动态物体追踪,结合摄像头锁定目标。
二、实验器材与软件环境​​
硬件​​
1.ESP32 AI Camera开发板(带OV2640摄像头模块)
2.伺服舵机(用于物理追踪)
3.USB数据线、杜邦线
4.PC(Windows/Linux)
软件​​
1.Arduino IDE
2.OpenCV库(模型训练与数据预处理)
三、实验原理​​
1.物体检测​​
使用封装好的openCVLibrary348库的模型进行实时图像推理。
通过摄像头采集图像,模型输出目标类别与边界框坐标。
2.物体追踪​​
​​中心点追踪​​:计算检测框中心与画面中心的偏移量,控制云台转动。
​​手动追踪​​:通过手动锁定物体框进行追踪,控制云台转动。
四、实验步骤​​
1.环境搭建​​
安装Arduino ESP32开发板支持包
导入openCV库及摄像头驱动
连接摄像头模块至开发板
2.代码测试
  1. #include <WebSocketsServer.h>
  2. #include <WiFi.h>
  3. #include <WiFiUdp.h>
  4. #include "camera_wrap.h"
  5. // #define DEBUG
  6. // #define SAVE_IMG
  7. enum TRACK{
  8.   TRACK_NONE = 0,
  9.   TRACK_FW,
  10.   TRACK_LEFT,
  11.   TRACK_RIGHT,
  12.   TRACK_STOP
  13. };
  14. const char* ssid = "PS4";    // <<< change this as yours
  15. const char* password = "22222222"; // <<< change this as yours
  16. //holds the current upload
  17. int cameraInitState = -1;
  18. uint8_t* jpgBuff = new uint8_t[68123];
  19. size_t   jpgLength = 0;
  20. uint8_t camNo=0;
  21. bool clientConnected = false;
  22. //Creating UDP Listener Object.
  23. WiFiUDP UDPServer;
  24. IPAddress addrRemote;
  25. unsigned int portRemote;
  26. unsigned int UDPPort = 6868;
  27. const int RECVLENGTH = 16;
  28. byte packetBuffer[RECVLENGTH];
  29. WebSocketsServer webSocket = WebSocketsServer(86);
  30. String html_home;
  31. const int LED_BUILT_IN        = 4;
  32. const uint8_t TRACK_DUTY      = 100;
  33. const int PIN_SERVO_PITCH     = 12;
  34. // const int PIN_SERVO_YAW       = 2;
  35. const int PINDC_LEFT_BACK     = 13;
  36. const int PINDC_LEFT_FORWARD  = 15;
  37. const int PINDC_RIGHT_BACK    = 14;
  38. const int PINDC_RIGHT_FORWARD = 2;
  39. const int LEFT_CHANNEL        = 2;
  40. const int RIGHT_CHANNEL       = 3;
  41. const int SERVO_PITCH_CHANNEL = 4;
  42. const int SERVO_YAW_CHANNEL   = 5;
  43. const int SERVO_RESOLUTION    = 16;
  44. unsigned long previousMillisServo = 0;
  45. const unsigned long intervalServo = 10;
  46. bool servoUp = false;
  47. bool servoDown = false;
  48. bool servoRotateLeft = false;
  49. bool servoRotateRight = false;
  50. int posServo = 75;
  51. int PWMTrackHIGH = 138;
  52. int PWMTrackLOW = 138;
  53. void servoWrite(uint8_t channel, uint8_t angle) {
  54.   // regarding the datasheet of sg90 servo, pwm period is 20 ms and duty is 1->2ms
  55.   uint32_t maxDuty = (pow(2,SERVO_RESOLUTION)-1)/10;
  56.   uint32_t minDuty = (pow(2,SERVO_RESOLUTION)-1)/20;
  57.   uint32_t duty = (maxDuty-minDuty)*angle/180 + minDuty;
  58.   ledcWrite(channel, duty);
  59. }
  60. void controlServo(){
  61.   if(servoUp){
  62.     if(posServo>2){
  63.       posServo -= 2;
  64.     }
  65.   }
  66.   if(servoDown){
  67.     if(posServo<180){
  68.       posServo += 2;
  69.     }
  70.   }
  71.   servoWrite(SERVO_PITCH_CHANNEL,posServo);
  72. }
  73. void controlDC(int left0, int left1, int right0, int right1){
  74.   digitalWrite(PINDC_LEFT_BACK, left0);
  75.   if(left1 == HIGH){
  76.     ledcWrite(LEFT_CHANNEL, 255);
  77.   }else{
  78.     ledcWrite(LEFT_CHANNEL, 0);
  79.   }
  80.   digitalWrite(PINDC_RIGHT_BACK, right0);
  81.   if(right1 == HIGH){
  82.     ledcWrite(RIGHT_CHANNEL, 255);
  83.   }else{
  84.     ledcWrite(RIGHT_CHANNEL, 0);
  85.   }
  86. }
  87. void controlDCTrack(int left, int right){
  88.   digitalWrite(PINDC_LEFT_BACK, 0);
  89.   ledcWrite(LEFT_CHANNEL, left);
  90.   digitalWrite(PINDC_RIGHT_BACK, 0);
  91.   ledcWrite(RIGHT_CHANNEL, right);
  92. }
  93. void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
  94.   switch(type) {
  95.       case WStype_DISCONNECTED:
  96.           Serial.printf("[%u] Disconnected!\n", num);
  97.           camNo = num;
  98.           clientConnected = false;
  99.           break;
  100.       case WStype_CONNECTED:
  101.           Serial.printf("[%u] Connected!\n", num);
  102.           clientConnected = true;
  103.           break;
  104.       case WStype_TEXT:
  105.       case WStype_BIN:
  106.       case WStype_ERROR:
  107.       case WStype_FRAGMENT_TEXT_START:
  108.       case WStype_FRAGMENT_BIN_START:
  109.       case WStype_FRAGMENT:
  110.       case WStype_FRAGMENT_FIN:
  111.           Serial.println(type);
  112.           break;
  113.   }
  114. }
  115. std::vector<String> splitString(String data, String delimiter){
  116.     std::vector<String> ret;
  117.     // initialize first part (string, delimiter)
  118.     char* ptr = strtok((char*)data.c_str(), delimiter.c_str());
  119.     while(ptr != NULL) {
  120.         ret.push_back(String(ptr));
  121.         // create next part
  122.         ptr = strtok(NULL, delimiter.c_str());
  123.     }
  124.     return ret;
  125. }
  126. void processUDPData(){
  127.   int cb = UDPServer.parsePacket();
  128.   if (cb) {
  129.       UDPServer.read(packetBuffer, RECVLENGTH);
  130.       addrRemote = UDPServer.remoteIP();
  131.       portRemote = UDPServer.remotePort();
  132.       String strPackage = String((const char*)packetBuffer);
  133.   #ifdef DEBUG
  134.       Serial.print("receive: ");
  135.       // for (int y = 0; y < RECVLENGTH; y++){
  136.       //   Serial.print(packetBuffer[y]);
  137.       //   Serial.print("\n");
  138.       // }
  139.       Serial.print(strPackage);
  140.       Serial.print(" from: ");
  141.       Serial.print(addrRemote);
  142.       Serial.print(":");
  143.       Serial.println(portRemote);
  144.   #endif
  145.       if(strPackage.equals("whoami")){
  146.           UDPServer.beginPacket(addrRemote, portRemote-1);
  147.           String res = "ESP32-CAM";
  148.           UDPServer.write((const uint8_t*)res.c_str(),res.length());
  149.           UDPServer.endPacket();
  150.           Serial.println("response");
  151.       }else if(strPackage.equals("forward")){
  152.         controlDC(LOW,HIGH,LOW,HIGH);
  153.       }else if(strPackage.equals("backward")){
  154.         controlDC(HIGH,LOW,HIGH,LOW);
  155.       }else if(strPackage.equals("left")){
  156.         controlDC(LOW,LOW,LOW,HIGH);
  157.       }else if(strPackage.equals("right")){
  158.         controlDC(LOW,HIGH,LOW,LOW);
  159.       }else if(strPackage.equals("stop")){
  160.         controlDC(LOW,LOW,LOW,LOW);
  161.       }else if(strPackage.equals("camup")){
  162.         servoUp = true;
  163.       }else if(strPackage.equals("camdown")){
  164.         servoDown = true;
  165.       }else if(strPackage.equals("camstill")){
  166.         servoUp = false;
  167.         servoDown = false;
  168.       }else if(strPackage.equals("ledon")){
  169.         digitalWrite(LED_BUILT_IN, HIGH);
  170.       }else if(strPackage.equals("ledoff")){
  171.         digitalWrite(LED_BUILT_IN, LOW);
  172.       }else if(strPackage.equals("lefttrack")){
  173.         controlDCTrack(0, PWMTrackHIGH);
  174.       }else if(strPackage.equals("righttrack")){
  175.         controlDCTrack(PWMTrackHIGH, 0);
  176.       }else if(strPackage.equals("fwtrack")){
  177.         controlDCTrack(PWMTrackLOW, PWMTrackLOW);
  178.       }
  179.       memset(packetBuffer, 0, RECVLENGTH);
  180.   }
  181. }
  182. void setup(void) {
  183.   Serial.begin(115200);
  184.   Serial.print("\n");
  185.   #ifdef DEBUG
  186.   Serial.setDebugOutput(true);
  187.   #endif
  188.   pinMode(LED_BUILT_IN, OUTPUT);
  189.   digitalWrite(LED_BUILT_IN, LOW);
  190.   pinMode(PINDC_LEFT_BACK, OUTPUT);
  191.   ledcSetup(LEFT_CHANNEL, 100, 8);//channel, freq, resolution
  192.   ledcAttachPin(PINDC_LEFT_FORWARD, LEFT_CHANNEL);
  193.   pinMode(PINDC_RIGHT_BACK, OUTPUT);
  194.   ledcSetup(RIGHT_CHANNEL, 100, 8);//channel, freq, resolution
  195.   ledcAttachPin(PINDC_RIGHT_FORWARD, RIGHT_CHANNEL);
  196.   controlDC(LOW,LOW,LOW,LOW);
  197.   // 1. 50hz ==> period = 20ms (sg90 servo require 20ms pulse, duty cycle is 1->2ms: -90=>90degree)
  198.   // 2. resolution = 16, maximum value is 2^16-1=65535
  199.   // From 1 and 2 => -90=>90 degree or 0=>180degree ~ 3276=>6553
  200.   ledcSetup(SERVO_PITCH_CHANNEL, 50, 16);//channel, freq, resolution
  201.   ledcAttachPin(PIN_SERVO_PITCH, SERVO_PITCH_CHANNEL);// pin, channel
  202.   servoWrite(SERVO_PITCH_CHANNEL, posServo);
  203.   // ledcSetup(SERVO_YAW_CHANNEL, 50, 16);//channel, freq, resolution
  204.   // ledcAttachPin(PIN_SERVO_YAW, SERVO_YAW_CHANNEL);// pin, channel
  205.   // servoWrite(SERVO_YAW_CHANNEL, posServo);
  206.   cameraInitState = initCamera();
  207.   Serial.printf("camera init state %d\n", cameraInitState);
  208.   if(cameraInitState != 0){
  209.     return;
  210.   }
  211.   //WIFI INIT
  212.   Serial.printf("Connecting to %s\n", ssid);
  213.   if (String(WiFi.SSID()) != String(ssid)) {
  214.     WiFi.mode(WIFI_STA);
  215.     WiFi.begin(ssid, password);
  216.   }
  217.   while (WiFi.status() != WL_CONNECTED) {
  218.     delay(500);
  219.     Serial.print(".");
  220.   }
  221.   Serial.println("");
  222.   Serial.print("Connected! IP address: ");
  223.   String ipAddress = WiFi.localIP().toString();;
  224.   Serial.println(ipAddress);
  225.   webSocket.begin();
  226.   webSocket.onEvent(webSocketEvent);
  227.   UDPServer.begin(UDPPort);
  228. }
  229. void loop(void) {
  230.   webSocket.loop();
  231.   if(clientConnected == true){
  232.     grabImage(jpgLength, jpgBuff);
  233.     webSocket.sendBIN(camNo, jpgBuff, jpgLength);
  234.     // Serial.print("send img: ");
  235.     // Serial.println(jpgLength);
  236.   }
  237.   unsigned long currentMillis = millis();
  238.   if (currentMillis - previousMillisServo >= intervalServo) {
  239.     previousMillisServo = currentMillis;
  240.     processUDPData();
  241.     controlServo();
  242.   }
  243.   #ifdef DEBUG
  244.   if (Serial.available()) {
  245.     String data = Serial.readString();
  246.     Serial.println(data);
  247.     std::vector<String> vposVals = splitString(data, ",");
  248.     if(vposVals.size() != 4){
  249.       return;
  250.     }
  251.     int left0 = vposVals[0].toInt();
  252.     int left1 = vposVals[1].toInt();
  253.     int left2 = vposVals[2].toInt();
  254.     int left3 = vposVals[3].toInt();
  255.     controlDC(left0, left1, left2, left3);
  256.   }
  257.   #endif
  258. }
复制代码

五、实验结果


、实验总结
本次实验成功在ESP32上实现了实时物体检测与基础追踪功能,验证了边缘计算设备的视觉处理能力。尽管存在处理速度与精度的平衡挑战,同时APP软件我只能使用其他国外创客者的开发产品(需要恶补一下app开发的知识,然后将这个软件再做进一步优化).

物体检测

物体检测

物体追踪

物体追踪
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
关于楼主
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail