46浏览
查看: 46|回复: 9

[项目] 【Arduino 动手做】Esghati:一个由垃圾制成的机器人

[复制链接]
Arduino是一个开放源码的电子原型平台,它可以让你用简单的硬件和软件来创建各种互动的项目。Arduino的核心是一个微控制器板,它可以通过一系列的引脚来连接各种传感器、执行器、显示器等外部设备。Arduino的编程是基于C/C++语言的,你可以使用Arduino IDE(集成开发环境)来编写、编译和上传代码到Arduino板上。Arduino还有一个丰富的库和社区,你可以利用它们来扩展Arduino的功能和学习Arduino的知识。

Arduino的特点是:
1、开放源码:Arduino的硬件和软件都是开放源码的,你可以自由地修改、复制和分享它们。
2、易用:Arduino的硬件和软件都是为初学者和非专业人士设计的,你可以轻松地上手和使用它们。
3、便宜:Arduino的硬件和软件都是非常经济的,你可以用很低的成本来实现你的想法。
4、多样:Arduino有多种型号和版本,你可以根据你的需要和喜好来选择合适的Arduino板。
5、创新:Arduino可以让你用电子的方式来表达你的创意和想象,你可以用Arduino来制作各种有趣和有用的项目,如机器人、智能家居、艺术装置等。

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图1

驴友花雕  中级技神
 楼主|

发表于 4 小时前

【Arduino 动手做】Esghati:一个由垃圾制成的机器人

Esghati 是一款基于 ESP32-CAM 和 Arduino nano 的非常简单的机器人。我为学校的学生制作了它,这样他们就可以自己制作,并认为与世界各地的其他孩子分享它会很有趣。它超级便宜、超级简单且极具教育意义。

该项目的制作方式是,每一步您都会学习制作一个单独的小工具。首先,您将学习制作移动电源,下一步您将 ESP32-CAM 添加为具有人脸识别功能的摄像头,然后添加移动机构和身体,使其成为机器人。

那么它是如何工作的呢?这个机器人不需要控制器,只需要你的手机或笔记本电脑或任何带有 Web 浏览器的东西。您可以使用任何设备连接到 Esghati 的 wifi,您可以通过它的摄像头看到并使用浏览器控制它。它还具有人脸识别功能!

我想向我的学生展示,很酷的东西是由***创造的,不花钱购买花哨的机器人零件就可以完成,我还希望为他们所有人提供一个平等的竞争平台,无论他们的家庭财富如何。所以所有的身体部位都是直接来自垃圾的。

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图1

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 4 小时前

【Arduino 动手做】Esghati:一个由垃圾制成的机器人

材料与用品

身体部位没什么特别的,只是我身边的一些垃圾。你可以用你的想象力来设计你的机器人的身体。它可以是一个破损的玩具,或者一个手工制作的纸板机器人,或者像我这样完全无关紧要的东西。我使用了四个坏掉的 LED 灯和一个旧的 wifi 路由器外壳作为机身。

电气部件包括:
1 个 ESP32-CAM
1x Arduino Nano (根据您的模块购买 USB 数据线)
2 节锂离子电池 18650 3.7V,至少 2000 mAh
2x 母针接头 2.54mm 2 排 40 针 直角
1x FT232RL Mini USB 转 TTL 串口转换器适配器模块 3.3V/5.5V
1 个 ON/OFF 开关
1 个移动电源模块,带 2 个 USB 输出
1 x 公 USB 转 USB 电缆(购买前请阅读文章)
2x MG996R 360 度舵机(建议使用金属变速箱)
一些电线

工具:
使用 3 毫米钻头钻孔
迷你角磨机或钢锯
烙铁
焊锡丝和油
螺丝刀
热胶枪
统治者
金属剪刀
刀具

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 4 小时前

【Arduino 动手做】Esghati:一个由垃圾制成的机器人

第 1 步:底盘和车轮

我会告诉你我为 Esghati 的身体所做的一切,以防你想制作精确的机器人。

车轮:
首先,我们从 LED PCB 后面切割两个相同尺寸的 LED 灯。你最后应该得到像照片这样的东西。然后将 LED PCB 中间的伺服手柄连接起来。断开灯泡与 PCB 部分的连接,并开始从内部粘合 PCB 的角落,以获得额外的保护。将它们放在一边晾干,然后进行下一步。

基础:

底座由旧的破损 wifi 路由器制成,因此请拿起螺丝刀打开路由器并移除所有电子设备。我保持天线完好无损,因为它看起来很酷,但如果你愿意,你可以把它取下来。现在您需要为机器人的前部选择路由器的一侧。选择一侧后,开始测量伺服系统,然后根据测量值开始切割路由器的两侧。现在将伺服器安装在路由器中,如图所示。您可以使用热胶或伺服系统随附的螺钉,不用说始终建议使用螺钉。

您可能希望稍后安装轮子,因为安装其他没有轮子的部件更容易。我将它们连接起来以进行演示。

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图1

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图3

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图2

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图4

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图5

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图6


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 4 小时前

【Arduino 动手做】Esghati:一个由垃圾制成的机器人

第 2 步:移动电源

布线:
接线非常简单,先将电池并联在一起,然后将负极连接到移动电源的负极。然后用中间的开/关开关将它们的正极连接在一起。

蒙太奇:
现在是时候将我们的移动电源连接到机箱了。首先,仔细测量移动电源模块端口,在机身的任何一侧打一些适合它们的孔,然后将电池和模块粘在机箱上。我亲自将它们连接到机器人的顶部前部。然后测量开/关开关并在机箱上为其留出一个位置。建议您将所有组件粘在机箱的一侧,以便可以轻松地继续其余的蒙太奇作。

最后,确保您的移动电源电池电量指示器通过机箱可见,无论是 LED 指示灯还是 LCD 指示灯。现在您可以继续下一步。

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图1

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图2

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图3

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图4

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图5




回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 4 小时前

【Arduino 动手做】Esghati:一个由垃圾制成的机器人

第 3 步:上半身

我们需要一个更大的灯泡和一个较小的上半身灯泡。从大灯泡上取下灯泡,剪断盖子,如图所示插入第二个小盖子。现在,您可以切割或钻孔较小的灯泡帽的底部,以便电线可以进入槽。您可以将这两个部分首尾相连,但不要将它们连接到机箱。

拿一块垃圾板金属,做一个至少 12 厘米长、3.5 厘米宽的 T 形支架。然后根据较小灯泡的底座弯曲 T 型支架的底部,并将其拧到小灯泡的顶部。

接下来,将轮子上剩余的灯泡体连接到机器人眼睛的 T 形支架的顶部。

最后,将大灯泡从底座上切成两半,并将其底部粘在机箱上,以便将上半身安装在其上。我这样做是为了随时可以拆下上半身,而且它也可以牢牢地安装在机箱上。但仍然不要将上半身连接到底盘。

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图1

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图2

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图3

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图4

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图5

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图6

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图7

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图8

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图9

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图10


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 4 小时前

【Arduino 动手做】Esghati:一个由垃圾制成的机器人

第 4 步:ESP32-CAM 支架

现在我们需要两个 8 行 2.54mm 2 行 40 针直角 将 ESP32-CAM 安装在 T 型支架上。首先,将内排排针连接到模块,使排针彼此指向。然后将外引脚粘在 T 型支架上,不要打扰内引脚,因为我们需要它们连接到模块。

一旦胶水固定好,您就可以开始为电子设备布线了。


【Arduino 动手做】Esghati:一个由垃圾制成的机器人图4

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图2

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图3

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图1


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 4 小时前

【Arduino 动手做】Esghati:一个由垃圾制成的机器人

第 5 步:电子元件

在这里,您需要决定是要使用 USB 端口为整个系统供电,还是要将电源线直接焊接到移动电源 PCB 上的 USB 引脚。我将电线焊接到 PCB 上,因为它更干净,您还可以使用额外的 USB 端口来连接其他电子设备,甚至为一些手机和小工具充电。

Arduino 适合 wifi 路由器机箱,不需要特殊支架,只是不要将电线直接焊接到上面;使用 pin 接头。现在一切都已连接,我们可以继续下一步。

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图1

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 4 小时前

【Arduino 动手做】Esghati:一个由垃圾制成的机器人

本帖最后由 驴友花雕 于 2025-5-22 19:02 编辑

第 6 步:项目代码

我基于这个项目开发了 Esghati 的平台并添加了更多功能。我在 GitHub 上上传了该项目的源代码,单击此处重定向。


  1. #include <SoftwareSerial.h>
  2. #include <VarSpeedServo.h>
  3. SoftwareSerial mySerial(4, 3);
  4. VarSpeedServo  Rwheel;
  5. VarSpeedServo  Lwheel;
  6. int VSPEED = 5 , HSPEED = 10 , MSPEED = 50, MACCEL = 125;
  7. int MAX_VSPEED = 10 , MAX_HSPEED = 20 , MAX_MSPEED = 255, MSTOP = 1500, MSTOPdeg = 90;
  8. String command;
  9. bool commandEnd=false;
  10. char inByte;
  11. int arg = 0;
  12. void setup() {
  13.   // put your setup code here, to run once:
  14.   Serial.begin(115200);
  15.   mySerial.begin(9600);
  16.   Rwheel.attach(6);
  17.   delay(100);
  18.   Rwheel.write(MSTOP);
  19.   delay(300);
  20.   Lwheel.attach(5);
  21.   delay(100);
  22.   Lwheel.write(MSTOP);
  23.   delay(300);
  24. }
  25. void loop() {
  26.   // put your main code here, to run repeatedly:
  27.   if (mySerial.available() > 0) {
  28.       if(commandEnd){
  29.       command="";
  30.       commandEnd=false;
  31.     }
  32.       inByte = mySerial.read();
  33.       if (inByte != '\n') {
  34.         if (inByte == '=') {
  35.           arg = mySerial.parseInt();
  36.           //Serial.println(arg);      
  37.         } else {
  38.           command += inByte;
  39.         }
  40.       }else{
  41.         commandEnd=true;
  42.         Serial.println(command);
  43.         execute(command, arg);
  44.       }
  45.   }
  46.    
  47. }
  48. void execute(String command, int arg){
  49. if(compareString(command, "l-rotate")){
  50.       Rwheel.write(MSTOPdeg-MSPEED,MACCEL);
  51.       Lwheel.write(MSTOPdeg-MSPEED,MACCEL);
  52.       command="";
  53.     }else if(compareString(command, "r-rotate")){
  54.       Rwheel.write(MSTOPdeg+MSPEED,MACCEL);
  55.       Lwheel.write(MSTOPdeg+MSPEED,MACCEL);
  56.       command="";
  57.     }else if(compareString(command, "f-forward")){
  58.       Rwheel.write(MSTOPdeg-MSPEED, MACCEL);
  59.       Lwheel.write(MSTOPdeg+MSPEED, MACCEL);
  60.       command="";
  61.     }else if(compareString(command, "f-left")){
  62.       Rwheel.write(MSTOPdeg-MSPEED,MACCEL);
  63.       Lwheel.write(MSTOP);
  64.       command="";
  65.     }else if(compareString(command, "f-right")){
  66.       Rwheel.write(MSTOP);
  67.       Lwheel.write(MSTOPdeg+MSPEED,MACCEL);
  68.       command="";
  69.     }else if(compareString(command, "b-backward")){
  70.       Rwheel.write(MSTOPdeg+MSPEED,MACCEL);
  71.       Lwheel.write(MSTOPdeg-MSPEED,MACCEL);
  72.       command="";
  73.     }else if(compareString(command, "b-right")){
  74.       Rwheel.write(MSTOPdeg+MSPEED,MACCEL);
  75.       Lwheel.write(MSTOP);
  76.       command="";
  77.     }else if(compareString(command, "b-left")){
  78.       Rwheel.write(MSTOP);
  79.       Lwheel.write(MSTOPdeg-MSPEED,MACCEL);
  80.       command="";
  81.     }else if(compareString(command, "stop")){
  82.       Rwheel.write(MSTOP);
  83.       Lwheel.write(MSTOP);
  84.       command="";
  85.     }
  86.     command="";
  87. }
  88. boolean compareString(String a, String b) {
  89.   if (a.length() != b.length() + 1) {
  90.     return false;
  91.   }
  92.   for (int i = 0; i < a.length() - 1; i++) {
  93.     if (a[i] != b[i]) {
  94.       return false;
  95.     }
  96.   }
  97.   return true;
  98. }
复制代码
  1. #include <ArduinoWebsockets.h>
  2. #include "esp_http_server.h"
  3. #include "esp_timer.h"
  4. #include "esp_camera.h"
  5. #include "camera_index.h"
  6. #include "Arduino.h"
  7. #include "fd_forward.h"
  8. #include "fr_forward.h"
  9. #include "fr_flash.h"
  10. #include "fb_gfx.h"
  11. const char* ssid = "your ssid";
  12. const char* password = "your password";
  13. #define ENROLL_CONFIRM_TIMES 5
  14. #define FACE_ID_SAVE_NUMBER 7
  15. #define LED_BUILTIN 4
  16. bool INT_LED = false;
  17. hw_timer_t *My_timer = NULL;
  18. // Select camera model
  19. //#define CAMERA_MODEL_WROVER_KIT
  20. //#define CAMERA_MODEL_ESP_EYE
  21. //#define CAMERA_MODEL_M5STACK_PSRAM
  22. //#define CAMERA_MODEL_M5STACK_WIDE
  23. #define CAMERA_MODEL_AI_THINKER
  24. #include "camera_pins.h"
  25. using namespace websockets;
  26. WebsocketsServer socket_server;
  27. camera_fb_t * fb = NULL;
  28. long current_millis;
  29. long last_detected_millis = 0;
  30. #define RED 15 // pin 12 can also be used
  31. #define GREEN 14
  32. #define BLUE 2
  33. #define Mic 12
  34. int light = 0;
  35. unsigned long door_opened_millis = 0;
  36. long interval = 5000;           // open lock for ... milliseconds
  37. bool face_recognised = false;
  38. const int numReadings = 5;
  39. int readings[numReadings];      // the readings from the analog input
  40. int readIndex = 0;
  41. int total = 0;                  // the running total
  42. int average_face_size = 0;      // the average
  43. int face_distance;
  44. int face_id = 0;
  45. String command;
  46. bool commandEnd=false;
  47. char inByte;
  48. int arg = 0;
  49. bool follow = 0;
  50. //void app_facenet_main();
  51. //void app_httpserver_init();
  52. typedef struct
  53. {
  54.   uint8_t *image;
  55.   box_array_t *net_boxes;
  56.   dl_matrix3d_t *face_id;
  57. } http_img_process_result;
  58. static inline mtmn_config_t app_mtmn_config()
  59. {
  60.   mtmn_config_t mtmn_config = {0};
  61.   mtmn_config.type = FAST;
  62.   mtmn_config.min_face = 80;
  63.   mtmn_config.pyramid = 0.707;
  64.   mtmn_config.pyramid_times = 4;
  65.   mtmn_config.p_threshold.score = 0.6;
  66.   mtmn_config.p_threshold.nms = 0.7;
  67.   mtmn_config.p_threshold.candidate_number = 20;
  68.   mtmn_config.r_threshold.score = 0.7;
  69.   mtmn_config.r_threshold.nms = 0.7;
  70.   mtmn_config.r_threshold.candidate_number = 10;
  71.   mtmn_config.o_threshold.score = 0.7;
  72.   mtmn_config.o_threshold.nms = 0.7;
  73.   mtmn_config.o_threshold.candidate_number = 1;
  74.   return mtmn_config;
  75. }
  76. mtmn_config_t mtmn_config = app_mtmn_config();
  77. face_id_name_list st_face_list;
  78. static dl_matrix3du_t *aligned_face = NULL;
  79. httpd_handle_t camera_httpd = NULL;
  80. typedef enum
  81. {
  82.   START_STREAM,
  83.   START_DETECT,
  84.   SHOW_FACES,
  85.   START_RECOGNITION,
  86.   START_ENROLL,
  87.   ENROLL_COMPLETE,
  88.   DELETE_ALL,
  89. } en_fsm_state;
  90. en_fsm_state g_state;
  91. typedef struct
  92. {
  93.   char enroll_name[ENROLL_NAME_LEN];
  94. } httpd_resp_value;
  95. httpd_resp_value st_name;
  96. void IRAM_ATTR onTimer(){
  97.   Serial.println("task");
  98. }
  99. void setup() {
  100.   Serial.begin(9600);
  101.   Serial.setDebugOutput(true);
  102.   Serial.println();
  103.   pinMode (LED_BUILTIN, OUTPUT);
  104.   pinMode(RED, OUTPUT);
  105.   pinMode(GREEN, OUTPUT);
  106.   pinMode(BLUE, OUTPUT);
  107.   pinMode(33, OUTPUT);
  108.   pinMode(Mic, INPUT);
  109.   digitalWrite(33, HIGH);
  110.   digitalWrite(RED, LOW);
  111.   digitalWrite(GREEN, LOW);
  112.   digitalWrite(BLUE, LOW);
  113.   camera_config_t config;
  114.   config.ledc_channel = LEDC_CHANNEL_0;
  115.   config.ledc_timer = LEDC_TIMER_0;
  116.   config.pin_d0 = Y2_GPIO_NUM;
  117.   config.pin_d1 = Y3_GPIO_NUM;
  118.   config.pin_d2 = Y4_GPIO_NUM;
  119.   config.pin_d3 = Y5_GPIO_NUM;
  120.   config.pin_d4 = Y6_GPIO_NUM;
  121.   config.pin_d5 = Y7_GPIO_NUM;
  122.   config.pin_d6 = Y8_GPIO_NUM;
  123.   config.pin_d7 = Y9_GPIO_NUM;
  124.   config.pin_xclk = XCLK_GPIO_NUM;
  125.   config.pin_pclk = PCLK_GPIO_NUM;
  126.   config.pin_vsync = VSYNC_GPIO_NUM;
  127.   config.pin_href = HREF_GPIO_NUM;
  128.   config.pin_sscb_sda = SIOD_GPIO_NUM;
  129.   config.pin_sscb_scl = SIOC_GPIO_NUM;
  130.   config.pin_pwdn = PWDN_GPIO_NUM;
  131.   config.pin_reset = RESET_GPIO_NUM;
  132.   config.xclk_freq_hz = 10000000;
  133.   config.pixel_format = PIXFORMAT_JPEG;
  134.   //init with high specs to pre-allocate larger buffers
  135.   if (psramFound()) {
  136.     config.frame_size = FRAMESIZE_UXGA;
  137.     config.jpeg_quality = 10;
  138.     config.fb_count = 2;
  139.   } else {
  140.     config.frame_size = FRAMESIZE_SVGA;
  141.     config.jpeg_quality = 12;
  142.     config.fb_count = 1;
  143.   }
  144. #if defined(CAMERA_MODEL_ESP_EYE)
  145.   pinMode(13, INPUT_PULLUP);
  146.   pinMode(14, INPUT_PULLUP);
  147. #endif
  148.   // camera init
  149.   esp_err_t err = esp_camera_init(&config);
  150.   if (err != ESP_OK) {
  151.     Serial.printf("Camera init failed with error 0x%x", err);
  152.     return;
  153.   }
  154.   sensor_t * s = esp_camera_sensor_get();
  155.   s->set_framesize(s, FRAMESIZE_QVGA);
  156. #if defined(CAMERA_MODEL_M5STACK_WIDE)
  157.   s->set_vflip(s, 1);
  158.   s->set_hmirror(s, 1);
  159. #endif
  160.   WiFi.softAP(ssid, password);
  161.   IPAddress IP = WiFi.softAPIP();
  162.   Serial.print("ACCESS POINT IP address: ");
  163.   Serial.println(IP);
  164.   app_httpserver_init();
  165.   app_facenet_main();
  166.   socket_server.listen(82);
  167.   Serial.print("Camera Ready! Use 'http://");
  168.   Serial.print(WiFi.localIP());
  169.   Serial.println("' to connect");
  170.   My_timer = timerBegin(0, 80, true);
  171.   timerAttachInterrupt(My_timer, &onTimer, true);
  172.   timerAlarmWrite(My_timer, 300000000, true);
  173.   timerAlarmEnable(My_timer);
  174. }
  175. static esp_err_t index_handler(httpd_req_t *req) {
  176.   httpd_resp_set_type(req, "text/html");
  177.   httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
  178.   return httpd_resp_send(req, (const char *)index_ov2640_html_gz, index_ov2640_html_gz_len);
  179. }
  180. httpd_uri_t index_uri = {
  181.   .uri       = "/",
  182.   .method    = HTTP_GET,
  183.   .handler   = index_handler,
  184.   .user_ctx  = NULL
  185. };
  186. void app_httpserver_init ()
  187. {
  188.   httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  189.   if (httpd_start(&camera_httpd, &config) == ESP_OK)
  190.     Serial.println("httpd_start");
  191.   {
  192.     httpd_register_uri_handler(camera_httpd, &index_uri);
  193.   }
  194. }
  195. void app_facenet_main()
  196. {
  197.   face_id_name_init(&st_face_list, FACE_ID_SAVE_NUMBER, ENROLL_CONFIRM_TIMES);
  198.   aligned_face = dl_matrix3du_alloc(1, FACE_WIDTH, FACE_HEIGHT, 3);
  199.   read_face_id_from_flash_with_name(&st_face_list);
  200. }
  201. static inline int do_enrollment(face_id_name_list *face_list, dl_matrix3d_t *new_id)
  202. {
  203.   ESP_LOGD(TAG, "START ENROLLING");
  204.   int left_sample_face = enroll_face_id_to_flash_with_name(face_list, new_id, st_name.enroll_name);
  205.   ESP_LOGD(TAG, "Face ID %s Enrollment: Sample %d",
  206.            st_name.enroll_name,
  207.            ENROLL_CONFIRM_TIMES - left_sample_face);
  208.   return left_sample_face;
  209. }
  210. static esp_err_t send_face_list(WebsocketsClient &client)
  211. {
  212.   client.send("delete_faces"); // tell browser to delete all faces
  213.   face_id_node *head = st_face_list.head;
  214.   char add_face[64];
  215.   for (int i = 0; i < st_face_list.count; i++) // loop current faces
  216.   {
  217.     sprintf(add_face, "listface:%s", head->id_name);
  218.     client.send(add_face); //send face to browser
  219.     head = head->next;
  220.   }
  221. }
  222. static esp_err_t delete_all_faces(WebsocketsClient &client)
  223. {
  224.   delete_face_all_in_flash_with_name(&st_face_list);
  225.   client.send("delete_faces");
  226. }
  227. void handle_message(WebsocketsClient &client, WebsocketsMessage msg)
  228. {
  229.   timerWrite(My_timer, 0); //reset timer (feed watchdog)
  230.   //Serial.println(msg.data());
  231.   if (msg.data() == "stream") {
  232.     g_state = START_STREAM;
  233.     client.send("STREAMING");
  234.   }else if (msg.data() == "detect") {
  235.     g_state = START_DETECT;
  236.     client.send("DETECTING");
  237.   }else if (msg.data().substring(0, 8) == "capture:") {
  238.     g_state = START_ENROLL;
  239.     char person[FACE_ID_SAVE_NUMBER * ENROLL_NAME_LEN] = {0,};
  240.     msg.data().substring(8).toCharArray(person, sizeof(person));
  241.     memcpy(st_name.enroll_name, person, strlen(person) + 1);
  242.     client.send("CAPTURING");
  243.   }else if (msg.data() == "recognise") {
  244.     g_state = START_RECOGNITION;
  245.     client.send("RECOGNISING");
  246.   }else if (msg.data().substring(0, 7) == "remove:") {
  247.     char person[ENROLL_NAME_LEN * FACE_ID_SAVE_NUMBER];
  248.     msg.data().substring(7).toCharArray(person, sizeof(person));
  249.     delete_face_id_in_flash_with_name(&st_face_list, person);
  250.     send_face_list(client); // reset faces in the browser
  251.   }else if (msg.data().substring(0, 5) == "tilt:") {
  252.     //int i = msg.data().substring(5).toInt();
  253.     Serial.print("tilt=");
  254.     Serial.println(msg.data().substring(5));
  255.   }else if (msg.data().substring(0, 4) == "pan:") {
  256.     //int j = msg.data().substring(4).toInt();
  257.     Serial.print("pan=");
  258.     Serial.println(msg.data().substring(4));
  259.   }else if (msg.data().substring(0, 9) == "lr-rhand:") {
  260.     //int i = msg.data().substring(5).toInt();
  261.     Serial.print("lr-rhand=");
  262.     Serial.println(msg.data().substring(9));
  263.   }else if (msg.data().substring(0, 9) == "ud-rhand:") {
  264.     //int j = msg.data().substring(4).toInt();
  265.     Serial.print("ud-rhand=");
  266.     Serial.println(msg.data().substring(9));
  267.   }else if (msg.data().substring(0, 9) == "lr-lhand:") {
  268.     //int i = msg.data().substring(5).toInt();
  269.     Serial.print("lr-lhand=");
  270.     Serial.println(msg.data().substring(9));
  271.   }else if (msg.data().substring(0, 9) == "ud-lhand:") {
  272.     //int j = msg.data().substring(4).toInt();
  273.     Serial.print("ud-lhand=");
  274.     Serial.println(msg.data().substring(9));
  275.   }else if (msg.data() == "stop") {
  276.     Serial.println("stop");
  277.   }else if (msg.data() == "r-rotate") {
  278.     Serial.println("r-rotate");
  279.   }else if (msg.data() == "l-rotate") {
  280.     Serial.println("l-rotate");
  281.   }else if (msg.data() == "f-left") {
  282.     Serial.println("f-left");
  283.   }else if (msg.data() == "f-forward") {
  284.     Serial.println("f-forward");
  285.   }else if (msg.data() == "f-right") {
  286.     Serial.println("f-right");
  287.   }else if (msg.data() == "b-left") {
  288.     Serial.println("b-left");
  289.   }else if (msg.data() == "b-backward") {
  290.     Serial.println("b-backward");
  291.   }else if (msg.data() == "b-right") {
  292.     Serial.println("b-right");
  293.   }else if (msg.data() == "introduce") {
  294.     Serial.println("introduce");
  295.   }else if (msg.data() == "greet") {
  296.     Serial.println("greet");
  297.   }else if (msg.data() == "find" && g_state == START_RECOGNITION) {
  298.     Serial.println("find");
  299.   }else if (msg.data() == "follow") {
  300.    
  301.     if(!follow){
  302.         Serial.println("follow");
  303.         follow = true;
  304.     }else{
  305.       Serial.println("nofollow");
  306.       follow = false;
  307.     }
  308.    
  309.   }else if (msg.data() == "dance") {
  310.     Serial.println("dance");
  311.   }else if (msg.data() == "random") {
  312.     Serial.println("random");
  313.   }else if (msg.data() == "history") {
  314.     Serial.println("history");
  315.   }else if (msg.data() == "hymn") {
  316.     Serial.println("hymn");
  317.   }else if (msg.data() == "hreset") {
  318.     Serial.println("hreset");
  319.   }else if (msg.data() == "reset") {
  320.     Serial.println("reset");
  321.   }else if (msg.data() == "light") {
  322.     if(INT_LED){
  323.       digitalWrite(LED_BUILTIN, LOW);
  324.       INT_LED = false;
  325.     }else{
  326.       digitalWrite(LED_BUILTIN, HIGH);
  327.       INT_LED = true;
  328.     }
  329.    
  330.     Serial.println("light");
  331.   }else if (msg.data() == "rgb") {
  332.     if(light == 0){
  333.       digitalWrite(RED, HIGH);
  334.       digitalWrite(GREEN, LOW);
  335.       digitalWrite(BLUE, LOW);
  336.       light++;
  337.       }else if(light == 1){
  338.       digitalWrite(RED, LOW);
  339.       digitalWrite(GREEN, HIGH);
  340.       digitalWrite(BLUE, LOW);
  341.       light++;
  342.       }else if(light == 2){
  343.       digitalWrite(RED, LOW);
  344.       digitalWrite(GREEN, LOW);
  345.       digitalWrite(BLUE, HIGH);
  346.       light++;
  347.       }else{
  348.       digitalWrite(RED, LOW);
  349.       digitalWrite(GREEN, LOW);
  350.       digitalWrite(BLUE, LOW);
  351.       light=0;
  352.       }
  353.     Serial.println("rgb");
  354.   }else if (msg.data() == "fire") {
  355.     Serial.println("fire");
  356.   }else if (msg.data() == "voicemode") {
  357.     Serial.println("voicemode");
  358.   }else if (msg.data() == "clearcache") {
  359.     Serial.println("free heap: ");
  360.     Serial.println(ESP.getFreeHeap());
  361.   }else if (msg.data() == "seq1") {
  362.     Serial.println("seq1");
  363.   }else if (msg.data() == "seq2") {
  364.     Serial.println("seq2");
  365.   }else if (msg.data() == "seq3") {
  366.     Serial.println("seq3");
  367.   }else if (msg.data() == "seq4") {
  368.     Serial.println("seq4");
  369.   }
  370.   
  371. }
  372. void open_door(WebsocketsClient &client) {
  373.   if (true/*digitalRead(relay_pin) == LOW*/) {
  374.     //digitalWrite(relay_pin, HIGH); //close (energise) relay so door unlocks
  375.     Serial.println("sorush");
  376.     client.send("door_open");
  377.     door_opened_millis = millis(); // time relay closed and door opened
  378.   }
  379. }
  380. static void draw_face_boxes(dl_matrix3du_t *image_matrix, box_array_t *boxes)
  381. {
  382.   int x, y, w, h, i, half_width, half_height;
  383.   fb_data_t fb;
  384.   fb.width = image_matrix->w;
  385.   fb.height = image_matrix->h;
  386.   fb.data = image_matrix->item;
  387.   fb.bytes_per_pixel = 3;
  388.   fb.format = FB_BGR888;
  389.   for (i = 0; i < boxes->len; i++) {
  390.     // Convoluted way of finding face centre...
  391.     x = ((int)boxes->box[i].box_p[0]);
  392.     w = (int)boxes->box[i].box_p[2] - x + 1;
  393.     half_width = w / 2;
  394.     int face_center_pan = x + half_width; // current face centre x co-ordinate
  395.     y = (int)boxes->box[i].box_p[1];
  396.     h = (int)boxes->box[i].box_p[3] - y + 1;
  397.     half_height = h / 2;
  398.     int face_center_tilt = y + half_height;  // current face centre y co-ordinate
  399.     // subtract the last reading:
  400.     total = total - readings[readIndex];
  401.     // add current face height:
  402.     readings[readIndex] = h;
  403.     // add the reading to the total:
  404.     total = total + readings[readIndex];
  405.     // advance to the next position in the array:
  406.     readIndex = readIndex + 1;
  407.     // if we're at the end of the array...
  408.     if (readIndex >= numReadings) {
  409.       // ...wrap around to the beginning:
  410.       readIndex = 0;
  411.     }
  412.     // calculate the average:
  413.     average_face_size = total / numReadings;
  414.     int eq_top = 3.6 * 200 * 240; //f(mm) x real height(mm) x image height(px)
  415.     int eq_bottom = average_face_size * 2.7; //object height(px) x sensor height(mm)
  416.     int face_distance = eq_top / eq_bottom;
  417.     /*Serial.print('<'); // start marker
  418.     Serial.print(face_center_pan);
  419.     Serial.print(','); // comma separator
  420.     Serial.print(face_center_tilt);
  421.     Serial.print(','); // comma separator
  422.     Serial.print(face_distance);
  423.     Serial.println('>'); // end marker*/
  424.     Serial.print("autopan=");
  425.     Serial.println(face_center_pan);
  426.     Serial.print("autotilt=");
  427.     Serial.println(face_center_tilt);
  428.     Serial.print("distance=");
  429.     Serial.println(face_distance);
  430.   }
  431. }
  432. void loop() {
  433.   
  434.   auto client = socket_server.accept();
  435.   client.onMessage(handle_message);
  436.   dl_matrix3du_t *image_matrix = dl_matrix3du_alloc(1, 320, 240, 3);
  437.   http_img_process_result out_res = {0};
  438.   out_res.image = image_matrix->item;
  439.   send_face_list(client);
  440.   client.send("STREAMING");
  441.   while (client.available()) {
  442.     client.poll();
  443.     // char voice[12];
  444.     //   sprintf(voice, "voice:%s", (const char *)analogRead(12));
  445.     //   client.send(voice);
  446.     //   Serial.println(analogRead(12));
  447.     //   client.sendBinary((const char *)analogRead(12));
  448.     if (Serial.available()) {
  449.       
  450.     String command = Serial.readStringUntil('\n');
  451.     if (command == "red") {
  452.       digitalWrite(RED, HIGH);
  453.       digitalWrite(GREEN, LOW);
  454.       digitalWrite(BLUE, LOW);
  455.     } else if (command == "green") {
  456.       digitalWrite(RED, LOW);
  457.       digitalWrite(GREEN, HIGH);
  458.       digitalWrite(BLUE, LOW);
  459.     } else if (command == "blue") {
  460.       digitalWrite(RED, LOW);
  461.       digitalWrite(GREEN, LOW);
  462.       digitalWrite(BLUE, HIGH);
  463.     } else if (command == "norgb") {
  464.       digitalWrite(RED, LOW);
  465.       digitalWrite(GREEN, LOW);
  466.       digitalWrite(BLUE, LOW);
  467.     }
  468.   }
  469.     if (millis() - interval > door_opened_millis) { // current time - face recognised time > 5 secs
  470.       //digitalWrite(relay_pin, LOW); //open relay
  471.     }
  472.     fb = esp_camera_fb_get();
  473.     if (g_state == START_DETECT || g_state == START_ENROLL || g_state == START_RECOGNITION)
  474.     {
  475.       out_res.net_boxes = NULL;
  476.       out_res.face_id = NULL;
  477.       fmt2rgb888(fb->buf, fb->len, fb->format, out_res.image);
  478.       out_res.net_boxes = face_detect(image_matrix, &mtmn_config);
  479.       if (out_res.net_boxes)
  480.       {
  481.         if (align_face(out_res.net_boxes, image_matrix, aligned_face) == ESP_OK)
  482.         {
  483.           out_res.face_id = get_face_id(aligned_face);
  484.           last_detected_millis = millis();
  485.           if (g_state == START_DETECT) {
  486.             client.send("FACE DETECTED");
  487.           }
  488.           if(follow){
  489.             draw_face_boxes(image_matrix, out_res.net_boxes);
  490.         }
  491.           if (g_state == START_ENROLL)
  492.           {
  493.             int left_sample_face = do_enrollment(&st_face_list, out_res.face_id);
  494.             char enrolling_message[64];
  495.             sprintf(enrolling_message, "SAMPLE NUMBER %d FOR %s", ENROLL_CONFIRM_TIMES - left_sample_face, st_name.enroll_name);
  496.             client.send(enrolling_message);
  497.             if (left_sample_face == 0)
  498.             {
  499.               ESP_LOGI(TAG, "Enrolled Face ID: %s", st_face_list.tail->id_name);
  500.               g_state = START_STREAM;
  501.               char captured_message[64];
  502.               sprintf(captured_message, "FACE CAPTURED FOR %s", st_face_list.tail->id_name);
  503.               client.send(captured_message);
  504.               send_face_list(client);
  505.             }
  506.           }
  507.           if (g_state == START_RECOGNITION  && (st_face_list.count > 0))
  508.           {
  509.             face_id_node *f = recognize_face_with_name(&st_face_list, out_res.face_id);
  510.             if (f)
  511.             {
  512.               char recognised_message[64];
  513.               sprintf(recognised_message, "Hi %s", f->id_name);
  514.               open_door(client);
  515.               client.send(recognised_message);
  516.             }
  517.             else
  518.             {
  519.               client.send("FACE NOT RECOGNISED");
  520.               Serial.println("stranger");
  521.             }
  522.           }
  523.           dl_matrix3d_free(out_res.face_id);
  524.         }
  525.           free(out_res.net_boxes->score);  // Free allocated memory
  526.           free(out_res.net_boxes->box);
  527.           free(out_res.net_boxes->landmark);
  528.           free(out_res.net_boxes);
  529.       }
  530.       else
  531.       {
  532.         if (g_state != START_DETECT) {
  533.           client.send("NO FACE DETECTED");
  534.         }
  535.       }
  536.       if (g_state == START_DETECT && millis() - last_detected_millis > 500) { // Detecting but no face detected
  537.         client.send("DETECTING");
  538.       }
  539.     }
  540.     client.sendBinary((const char *)fb->buf, fb->len);
  541.     esp_camera_fb_return(fb);
  542.     fb = NULL;
  543.   }
  544. }
  545. boolean compareString(String a, String b) {
  546.   if (a.length() != b.length() + 1) {
  547.     return false;
  548.   }
  549.   for (int i = 0; i < a.length() - 1; i++) {
  550.     if (a[i] != b[i]) {
  551.       return false;
  552.     }
  553.   }
  554.   return true;
  555. }
复制代码



ESP32-CAM 系列:

首先,您需要从开发板管理器安装 ESP32 1.0.4 版本(或其他版本)。然后安装所有缺少的库。将您的板子连接到 USB 到 TTL 转换器。将 GPIO0 连接到 GND 以启用引导模式。从工具中选择 AI Thinker ESP32-CAM 板,然后选择 Huge APP 作为您的分区方案。最后输入 wifi 凭据,选择您的 COM 端口并开始上传程序。

注意:您可能会遇到诸如 guru meditation 或 brownout detector was triggered 之类的错误。它们通常是由电缆连接质量差或电力短缺引起的。为了消除错误,请将板连接到外部电源并确保连接良好。此外,将地线连接到系统和电源也非常重要。

注意:建议您使用 5V 引脚旁边的 GND 引脚为模块供电。

现在,您可以测试您的模块,退出引导模式并重新启动模块。然后用手机或笔记本电脑连接到 ESP32-CAM,并在 chrome 浏览器中输入 192.168.4.1。您应该会看到如图所示的控制面板。灯光和人脸识别功能可以立即进行测试。

Arduino Nano:

首先安装所有库并从板管理器中选择 arduino nano。选择 COM 并单击 upload (上传)。如果您在上传处理器类型时遇到问题。当处理器设置为 ATmega328P Old Bootloader 时,我可以对我的 arduino nanos 进行编程。

现在您可以将轮子连接到框架上,两个在伺服系统上,一个在后面,以保持平衡。现在我们已经完成了这个项目!

享受你的机器人。


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 4 小时前

【Arduino 动手做】Esghati:一个由垃圾制成的机器人

项目场景动态图

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图1

【Arduino 动手做】Esghati:一个由垃圾制成的机器人图2


附录

项目链接:https://www.instructables.com/Esghati-a-Robot-Made-From-Garbage/
项目作者:伊朗 索拉什·莫拉迪萨尼(Sorush Moradisani)
项目视频(1分钟):https://www.youtube.com/watch?v=d39NgJqNWr8&t=57s
项目开源代码:https://github.com/Sorush-moradisani/Esghati
参考:https://github.com/robotzero1/esp32cam-access-control


Esghati-main.zip

16.64 KB, 下载次数: 0

esp32cam-access-control-master.zip

11.25 KB, 下载次数: 0

回复

使用道具 举报

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

本版积分规则

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

硬件清单

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

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

mail