8240浏览
查看: 8240|回复: 0

[项目] 用树莓派PICO制作一个FPV小车

[复制链接]
本帖最后由 豆爸 于 2024-1-10 15:17 编辑

作品介绍:


本作品使用树莓派Pico实现一个小车。


功能介绍:
  
基础功能:实现小车的进行、后退、停止、左转、右转的控制。
  
  拓展功能:手机APP控制、FPV、视觉控制等。


设计思路:


基础功能:通过Raspberry Pi Pico + 悟空2040树莓派扩展板,通过实现microblocks编程实现。
  
  基础功能:由于Raspberry Pi Pico不支持wifi,为了实现无线控制,需要增加支持wifi的模块,鉴于视觉的考虑,可以增加一块ESP32-S3,来实现APP控制、FPV等功能。


器材清单:

  基础功能:

  • 悟空2040树莓派扩展板WuKong2040 * 1块
  • N20电机 * 4个
  • 43MM轮子 * 4个

  拓展功能:

  • ESP32-S3
  • OV2640摄像头模块

制作过程(基础功能部分):

   1、嘉立创EDA绘制小车底板
   用树莓派PICO制作一个FPV小车图1


用树莓派PICO制作一个FPV小车图2



  2、PCB打样


用树莓派PICO制作一个FPV小车图3



3、安装电机,焊接电机线


用树莓派PICO制作一个FPV小车图4


  4、悟空2040树莓派扩展板安装

用树莓派PICO制作一个FPV小车图5






5、最终合体

用树莓派PICO制作一个FPV小车图6


编写程序(基础功能部分):

https://microblocks.fun/run/microblocks.html

  编程这里使用了microblocks,这里使用了悟空扩展板WUKong2040扩展库。

用树莓派PICO制作一个FPV小车图7



  基本的小车运行的程序,如下图所示


用树莓派PICO制作一个FPV小车图8



拓展功能:

   1、接线图


用树莓派PICO制作一个FPV小车图9


树莓派Pico                         ESP32

TX   GPIO0   ——————   U0R   IO13

RX   GPIO1   ——————   U0T  IO12

  GND   ——————   GND



     2、树莓派Pico端程序:



用树莓派PICO制作一个FPV小车图10



     3、ESP32-S3端程序:

    1)主程序FPVCar.ino


  1. #include "esp_camera.h"
  2. #include <WiFi.h>
  3. #include <ArduinoOTA.h>
  4. #include <ESP32Servo.h>
  5. // #include <EEPROM.h>
  6. // #define  EEPROM_speed 2   //地址范围0-4095
  7. // #define  EEPROM_Size 1024  //开辟1024个位空间
  8. /* Wifi Crdentials */
  9. // String sta_ssid = "MKMK";     // set Wifi network you want to connect to
  10. // String sta_password = "MAKRMAKER";   // set password for Wifi network
  11. /* define CAMERA_MODEL_AI_THINKER */
  12. #define PWDN_GPIO_NUM     32
  13. #define RESET_GPIO_NUM    -1
  14. #define XCLK_GPIO_NUM      0
  15. #define SIOD_GPIO_NUM     26
  16. #define SIOC_GPIO_NUM     27
  17. #define Y9_GPIO_NUM       35
  18. #define Y8_GPIO_NUM       34
  19. #define Y7_GPIO_NUM       39
  20. #define Y6_GPIO_NUM       36
  21. #define Y5_GPIO_NUM       21
  22. #define Y4_GPIO_NUM       19
  23. #define Y3_GPIO_NUM       18
  24. #define Y2_GPIO_NUM        5
  25. #define VSYNC_GPIO_NUM    25
  26. #define HREF_GPIO_NUM     23
  27. #define PCLK_GPIO_NUM     22
  28. /* Defining motor and servo pins */
  29. extern int DRV_A = 2;
  30. extern int DRV_B = 13;
  31. extern int DIR_A = 14;
  32. extern int DIR_B = 15;
  33. extern int ledVal = 20;  // setting bright of flash LED 0-255
  34. extern int ledPin = 4;  // set digital pin GPIO4 as LED pin (use biult-in LED)
  35. // extern int buzzerPin = 2;  // set digital pin GPIO2 as LED pin (use Active Buzzer)
  36. // extern int servoPin = 12;  // set digital pin GPIO2 as servo pin (use SG90)
  37. extern int  servoPin = 12;
  38. Servo myservo;
  39. // int EEPROM_dataT;
  40. unsigned long previousMillis = 0;
  41. int speed1=255;//右边
  42. int speed2=255;
  43. void startCameraServer();
  44. void initServo() {
  45.   myservo.attach(12,500,2500);
  46.   myservo.write(90);
  47.   delay(100);
  48.   digitalWrite(servoPin, LOW);
  49. }
  50. void initLed() {
  51.   ledcSetup(7, 5000, 8); /* 5000 hz PWM, 8-bit resolution and range from 0 to 255 */
  52.   ledcAttachPin(ledPin, 7);
  53. }
  54. void setup() {
  55.   Serial.begin(115200);         // set up seriamonitor at 115200 bps
  56.   Serial.setDebugOutput(true);
  57.   Serial.println();
  58.   Serial.println("*ESP32 Camera Remote Control - L293D Bluino Shield*");
  59.   Serial.println("--------------------------------------------------------");
  60.   Serial1.begin(9600, SERIAL_8N1, 12, 13); // 初始化 UART1,波特率为 115200,TX 引脚为 GPIO12,RX 引脚为 GPIO13
  61.   // Set all the motor control pin to Output
  62.   pinMode(DRV_A, OUTPUT);
  63.   pinMode(DRV_B, OUTPUT);
  64.   pinMode(DIR_A, OUTPUT);
  65.   pinMode(DIR_B, OUTPUT);
  66.   
  67.   pinMode(ledPin, OUTPUT); // set the LED pin as an Output
  68.   // pinMode(buzzerPin, OUTPUT); // set the buzzer pin as an Output
  69.   pinMode(servoPin, OUTPUT); // set the servo pin as an Output
  70.   // Initial state - turn off motors, LED & buzzer
  71.   // digitalWrite(DRV_A, LOW);
  72.   // digitalWrite(DRV_B, LOW);
  73.   // digitalWrite(DIR_A, LOW);
  74.   // digitalWrite(DIR_B, LOW);
  75.   analogWrite(DRV_A, 0);
  76.   analogWrite(DRV_B, 0);
  77.   analogWrite(DIR_A, 0);
  78.   analogWrite(DIR_B, 0);
  79.   digitalWrite(ledPin, LOW);
  80.   // digitalWrite(buzzerPin, LOW);
  81.   digitalWrite(servoPin, LOW);
  82.   myservo.setPeriodHertz(50);// Standard 50hz servo
  83.   myservo.attach(servoPin, 500, 2400);
  84.   /* Initializing Servo and LED */
  85.   initServo();
  86.   initLed();
  87.   
  88.   camera_config_t config;
  89.   config.ledc_channel = LEDC_CHANNEL_0;
  90.   config.ledc_timer = LEDC_TIMER_0;
  91.   config.pin_d0 = Y2_GPIO_NUM;
  92.   config.pin_d1 = Y3_GPIO_NUM;
  93.   config.pin_d2 = Y4_GPIO_NUM;
  94.   config.pin_d3 = Y5_GPIO_NUM;
  95.   config.pin_d4 = Y6_GPIO_NUM;
  96.   config.pin_d5 = Y7_GPIO_NUM;
  97.   config.pin_d6 = Y8_GPIO_NUM;
  98.   config.pin_d7 = Y9_GPIO_NUM;
  99.   config.pin_xclk = XCLK_GPIO_NUM;
  100.   config.pin_pclk = PCLK_GPIO_NUM;
  101.   config.pin_vsync = VSYNC_GPIO_NUM;
  102.   config.pin_href = HREF_GPIO_NUM;
  103.   config.pin_sscb_sda = SIOD_GPIO_NUM;
  104.   config.pin_sscb_scl = SIOC_GPIO_NUM;
  105.   config.pin_pwdn = PWDN_GPIO_NUM;
  106.   config.pin_reset = RESET_GPIO_NUM;
  107.   config.xclk_freq_hz = 20000000;
  108.   config.pixel_format = PIXFORMAT_JPEG;
  109.   //init with high specs to pre-allocate larger buffers
  110.   if(psramFound()){
  111.     config.frame_size = FRAMESIZE_UXGA;
  112.     config.jpeg_quality = 10;
  113.     config.fb_count = 2;
  114.   } else {
  115.     config.frame_size = FRAMESIZE_SVGA;
  116.     config.jpeg_quality = 10;
  117.     config.fb_count = 1;
  118.   }
  119.   // camera init
  120.   esp_err_t err = esp_camera_init(&config);
  121.   if (err != ESP_OK) {
  122.     Serial.printf("Camera init failed with error 0x%x", err);
  123.     return;
  124.   }
  125.   //drop down frame size for higher initial frame rate
  126.   sensor_t * s = esp_camera_sensor_get();
  127.   s->set_framesize(s, FRAMESIZE_QVGA);
  128.   // Set NodeMCU Wifi hostname based on chip mac address
  129.   char chip_id[15];
  130.   snprintf(chip_id, 15, "%04X", (uint16_t)(ESP.getEfuseMac()>>32));
  131.   String hostname = "esp32cam-" + String(chip_id);
  132.   Serial.println();
  133.   Serial.println("Hostname: "+hostname);
  134.   // first, set NodeMCU as STA mode to connect with a Wifi network
  135.   // WiFi.mode(WIFI_STA);
  136.   // WiFi.begin(sta_ssid.c_str(), sta_password.c_str());
  137.   // Serial.println("");
  138.   // Serial.print("Connecting to: ");
  139.   // Serial.println(sta_ssid);
  140.   // Serial.print("Password: ");
  141.   // Serial.println(sta_password);
  142.   // // try to connect with Wifi network about 10 seconds
  143.   // unsigned long currentMillis = millis();
  144.   // previousMillis = currentMillis;
  145.   // while (WiFi.status() != WL_CONNECTED && currentMillis - previousMillis <= 10000) {
  146.   //   delay(500);
  147.   //   Serial.print(".");
  148.   //   currentMillis = millis();
  149.   // }
  150.   // if failed to connect with Wifi network set NodeMCU as AP mode
  151.   IPAddress myIP;
  152.   // if (WiFi.status() == WL_CONNECTED) {
  153.   //   Serial.println("");
  154.   //   Serial.println("*WiFi-STA-Mode*");
  155.   //   Serial.print("IP: ");
  156.   //   myIP=WiFi.localIP();
  157.   //   Serial.println(myIP);
  158.   //   delay(2000);
  159.   // } else {
  160.   WiFi.mode(WIFI_AP);
  161.   WiFi.softAP(hostname.c_str());
  162.   myIP = WiFi.softAPIP();
  163.   Serial.println("");
  164.   // Serial.println("WiFi failed connected to " + sta_ssid);
  165.   Serial.println("");
  166.   Serial.println("*WiFi-AP-Mode*");
  167.   Serial.print("AP IP address: ");
  168.   Serial.println(myIP);
  169.   delay(2000);
  170.   // }
  171.   // Start camera server to get realtime view
  172.   startCameraServer();
  173.   Serial.print("Camera Ready! Use 'http://");
  174.   Serial.print(myIP);
  175.   Serial.println("' to connect ");
  176.   // ArduinoOTA.begin();   // enable to receive update/upload firmware via Wifi OTA
  177. }
  178. void loop() {
  179.   // put your main code here, to run repeatedly:
  180.   // ArduinoOTA.handle();
  181. }
复制代码


    2)app_httpd.cpp程序


  1. #include "esp_http_server.h"
  2. #include "esp_timer.h"
  3. #include "esp_camera.h"
  4. #include "img_converters.h"
  5. #include "Arduino.h"
  6. #include <ESP32Servo.h>
  7. #include "cJSON.h"
  8. // #include <EEPROM.h>
  9. // #define  EEPROM_speedT 2   //地址范围0-4095
  10. // // #define  EEPROM_speedY 10   //地址范围0-4095
  11. // // #define  EEPROM_speedU 20   //地址范围0-4095
  12. // #define  EEPROM_Size 1024  //开辟1024个位空间
  13. extern int EEPROM_dataT;
  14. // extern int EEPROM_dataY;
  15. // extern int EEPROM_dataU;
  16. /* Initializing pins */
  17. extern int DRV_A;
  18. extern int DRV_B;
  19. extern int DIR_A;
  20. extern int DIR_B;
  21. extern int ledPin;
  22. // extern int buzzerPin;
  23. // extern int servoPin;
  24. extern int ledVal;
  25. extern Servo myservo;
  26. // extern Servo servo_1;
  27. extern int servoPin;
  28. extern int speed1;
  29. extern int speed2;
  30. extern int speed1d;
  31. extern int speed2d;
  32. // servo_1.attach(2,500,2500);
  33. typedef struct {
  34.         httpd_req_t *req;
  35.         size_t len;
  36. } jpg_chunking_t;
  37. //定义视频流相关常量
  38. #define PART_BOUNDARY "123456789000000000000987654321"
  39. static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
  40. static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
  41. static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
  42. httpd_handle_t stream_httpd = NULL;
  43. httpd_handle_t camera_httpd = NULL;
  44. // 这是一个回调函数,用于编码并发送JPEG数据流
  45. static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){
  46.     jpg_chunking_t *j = (jpg_chunking_t *)arg;
  47.     if(!index){
  48.         j->len = 0;
  49.     }
  50.     if(httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK){
  51.         return 0;
  52.     }
  53.     j->len += len;
  54.     return len;
  55. }
  56. // 这是处理图像捕获请求的函数,捕获并发送图像
  57. static esp_err_t capture_handler(httpd_req_t *req){
  58.     camera_fb_t * fb = NULL;
  59.     esp_err_t res = ESP_OK;
  60.     int64_t fr_start = esp_timer_get_time();
  61.     fb = esp_camera_fb_get();
  62.     if (!fb) {
  63.         Serial.printf("Camera capture failed");
  64.         httpd_resp_send_500(req);
  65.         return ESP_FAIL;
  66.     }
  67.     httpd_resp_set_type(req, "image/jpeg");
  68.     httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg");
  69.     size_t fb_len = 0;
  70.     if(fb->format == PIXFORMAT_JPEG){
  71.         fb_len = fb->len;
  72.         res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
  73.     } else {
  74.         jpg_chunking_t jchunk = {req, 0};
  75.         res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL;
  76.         httpd_resp_send_chunk(req, NULL, 0);
  77.         fb_len = jchunk.len;
  78.     }
  79.     esp_camera_fb_return(fb);
  80.     int64_t fr_end = esp_timer_get_time();
  81.     Serial.printf("JPG: %uB %ums", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start)/1000));
  82.     return res;
  83. }
  84. // 这是处理视频流请求的函数,捕获视频流并发送给客户端
  85. static esp_err_t stream_handler(httpd_req_t *req){
  86.     camera_fb_t * fb = NULL;
  87.     esp_err_t res = ESP_OK;
  88.     size_t _jpg_buf_len = 0;
  89.     uint8_t * _jpg_buf = NULL;
  90.     char * part_buf[64];
  91.     static int64_t last_frame = 0;
  92.     if(!last_frame) {
  93.         last_frame = esp_timer_get_time();
  94.     }
  95.     res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
  96.     if(res != ESP_OK){
  97.         return res;
  98.     }
  99.     while(true){
  100.         fb = esp_camera_fb_get();
  101.         if (!fb) {
  102.             Serial.printf("Camera capture failed");
  103.             res = ESP_FAIL;
  104.         } else {
  105.             if(fb->format != PIXFORMAT_JPEG){
  106.                 bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
  107.                 esp_camera_fb_return(fb);
  108.                 fb = NULL;
  109.                 if(!jpeg_converted){
  110.                     Serial.printf("JPEG compression failed");
  111.                     res = ESP_FAIL;
  112.                 }
  113.             } else {
  114.                 _jpg_buf_len = fb->len;
  115.                 _jpg_buf = fb->buf;
  116.             }
  117.         }
  118.         if(res == ESP_OK){
  119.             size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
  120.             res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
  121.         }
  122.         if(res == ESP_OK){
  123.             res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
  124.         }
  125.         if(res == ESP_OK){
  126.             res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
  127.         }
  128.         if(fb){
  129.             esp_camera_fb_return(fb);
  130.             fb = NULL;
  131.             _jpg_buf = NULL;
  132.         } else if(_jpg_buf){
  133.             free(_jpg_buf);
  134.             _jpg_buf = NULL;
  135.         }
  136.         if(res != ESP_OK){
  137.             break;
  138.         }
  139.         int64_t fr_end = esp_timer_get_time();
  140.         int64_t frame_time = fr_end - last_frame;
  141.         last_frame = fr_end;
  142.         frame_time /= 1000;
  143.     }
  144.     last_frame = 0;
  145.     return res;
  146. }
  147. // 这是处理命令请求的函数,根据请求执行不同的命令
  148. static esp_err_t cmd_handler(httpd_req_t *req){
  149.     char*  buf;
  150.     size_t buf_len;
  151.     char variable[32] = {0,};
  152.     char value[32] = {0,};
  153.     buf_len = httpd_req_get_url_query_len(req) + 1;
  154.     if (buf_len > 1) {
  155.         buf = (char*)malloc(buf_len);
  156.         Serial.println(buf);
  157.         if(!buf){
  158.             httpd_resp_send_500(req);
  159.             return ESP_FAIL;
  160.         }
  161.         if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
  162.             if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) == ESP_OK &&
  163.                 httpd_query_key_value(buf, "val", value, sizeof(value)) == ESP_OK) {
  164.             } else {
  165.                 free(buf);
  166.                 Serial.println(buf);
  167.                 httpd_resp_send_404(req);
  168.                 return ESP_FAIL;
  169.             }
  170.         } else {
  171.             free(buf);
  172.             Serial.println(buf);
  173.             httpd_resp_send_404(req);
  174.             return ESP_FAIL;
  175.         }
  176.         Serial.println(buf);
  177.         free(buf);
  178.     } else {
  179.         httpd_resp_send_404(req);
  180.         Serial.println(ESP_FAIL);
  181.         return ESP_FAIL;
  182.     }
  183.     int val = atoi(value);
  184.     sensor_t * s = esp_camera_sensor_get();
  185.     int res = 0;
  186.     if(!strcmp(variable, "framesize")) {
  187.         if(s->pixformat == PIXFORMAT_JPEG) res = s->set_framesize(s, (framesize_t)val);
  188.     }
  189.     else if(!strcmp(variable, "quality")) res = s->set_quality(s, val);
  190.     else if(!strcmp(variable, "contrast")) res = s->set_contrast(s, val);
  191.     else if(!strcmp(variable, "brightness")) res = s->set_brightness(s, val);
  192.     else if(!strcmp(variable, "saturation")) res = s->set_saturation(s, val);
  193.     else if(!strcmp(variable, "gainceiling")) res = s->set_gainceiling(s, (gainceiling_t)val);
  194.     else if(!strcmp(variable, "colorbar")) res = s->set_colorbar(s, val);
  195.     else if(!strcmp(variable, "awb")) res = s->set_whitebal(s, val);
  196.     else if(!strcmp(variable, "agc")) res = s->set_gain_ctrl(s, val);
  197.     else if(!strcmp(variable, "aec")) res = s->set_exposure_ctrl(s, val);
  198.     else if(!strcmp(variable, "hmirror")) res = s->set_hmirror(s, val);
  199.     else if(!strcmp(variable, "vflip")) res = s->set_vflip(s, val);
  200.     else if(!strcmp(variable, "awb_gain")) res = s->set_awb_gain(s, val);
  201.     else if(!strcmp(variable, "agc_gain")) res = s->set_agc_gain(s, val);
  202.     else if(!strcmp(variable, "aec_value")) res = s->set_aec_value(s, val);
  203.     else if(!strcmp(variable, "aec2")) res = s->set_aec2(s, val);
  204.     else if(!strcmp(variable, "dcw")) res = s->set_dcw(s, val);
  205.     else if(!strcmp(variable, "bpc")) res = s->set_bpc(s, val);
  206.     else if(!strcmp(variable, "wpc")) res = s->set_wpc(s, val);
  207.     else if(!strcmp(variable, "raw_gma")) res = s->set_raw_gma(s, val);
  208.     else if(!strcmp(variable, "lenc")) res = s->set_lenc(s, val);
  209.     else if(!strcmp(variable, "special_effect")) res = s->set_special_effect(s, val);
  210.     else if(!strcmp(variable, "wb_mode")) res = s->set_wb_mode(s, val);
  211.     else if(!strcmp(variable, "ae_level")) res = s->set_ae_level(s, val);
  212.     else {
  213.         res = -1;
  214.     }
  215.     if(res){
  216.         return httpd_resp_send_500(req);
  217.     }
  218.     httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  219.     return httpd_resp_send(req, NULL, 0);
  220. }
  221. // 这个函数用于处理状态请求,返回相机的当前状态
  222. static esp_err_t status_handler(httpd_req_t *req){
  223.     static char json_response[1024];
  224.     sensor_t * s = esp_camera_sensor_get();
  225.     char * p = json_response;
  226.     *p++ = '{';
  227.     p+=sprintf(p, ""framesize":%u,", s->status.framesize);
  228.     p+=sprintf(p, ""quality":%u,", s->status.quality);
  229.     p+=sprintf(p, ""brightness":%d,", s->status.brightness);
  230.     p+=sprintf(p, ""contrast":%d,", s->status.contrast);
  231.     p+=sprintf(p, ""saturation":%d,", s->status.saturation);
  232.     p+=sprintf(p, ""special_effect":%u,", s->status.special_effect);
  233.     p+=sprintf(p, ""wb_mode":%u,", s->status.wb_mode);
  234.     p+=sprintf(p, ""awb":%u,", s->status.awb);
  235.     p+=sprintf(p, ""awb_gain":%u,", s->status.awb_gain);
  236.     p+=sprintf(p, ""aec":%u,", s->status.aec);
  237.     p+=sprintf(p, ""aec2":%u,", s->status.aec2);
  238.     p+=sprintf(p, ""ae_level":%d,", s->status.ae_level);
  239.     p+=sprintf(p, ""aec_value":%u,", s->status.aec_value);
  240.     p+=sprintf(p, ""agc":%u,", s->status.agc);
  241.     p+=sprintf(p, ""agc_gain":%u,", s->status.agc_gain);
  242.     p+=sprintf(p, ""gainceiling":%u,", s->status.gainceiling);
  243.     p+=sprintf(p, ""bpc":%u,", s->status.bpc);
  244.     p+=sprintf(p, ""wpc":%u,", s->status.wpc);
  245.     p+=sprintf(p, ""raw_gma":%u,", s->status.raw_gma);
  246.     p+=sprintf(p, ""lenc":%u,", s->status.lenc);
  247.     p+=sprintf(p, ""hmirror":%u,", s->status.hmirror);
  248.     p+=sprintf(p, ""dcw":%u,", s->status.dcw);
  249.     p+=sprintf(p, ""colorbar":%u", s->status.colorbar);
  250.     *p++ = '}';
  251.     *p++ = 0;
  252.     httpd_resp_set_type(req, "application/json");
  253.     httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  254.     return httpd_resp_send(req, json_response, strlen(json_response));
  255. }
  256. // 这个函数用于处理设备状态请求,根据请求执行不同的操作,例如控制舵机角度
  257. static esp_err_t state_handler(httpd_req_t *req){
  258.     char*  buf;
  259.     size_t buf_len;
  260.     char cmd[32] = {0,};
  261.     buf_len = httpd_req_get_url_query_len(req) + 1;
  262.     if (buf_len > 1) {
  263.         buf = (char*)malloc(buf_len);
  264.         Serial.println(buf);
  265.         
  266.         if(!buf){
  267.             httpd_resp_send_500(req);
  268.             return ESP_FAIL;
  269.         }
  270.         
  271.         if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
  272.             if (httpd_query_key_value(buf, "cmd", cmd, sizeof(cmd)) == ESP_OK) {
  273.               
  274.             } else {
  275.                 free(buf);
  276.                 Serial.print("*");
  277.                 Serial.println(ESP_FAIL);
  278.                 httpd_resp_send_404(req);
  279.                 return ESP_FAIL;
  280.             }
  281.         } else {
  282.             free(buf);
  283.             Serial.print("**");
  284.             Serial.println(ESP_FAIL);
  285.             httpd_resp_send_404(req);
  286.             return ESP_FAIL;
  287.         }
  288.         free(buf);
  289.         
  290.     } else {
  291.         Serial.print("***");
  292.         Serial.println(ESP_FAIL);
  293.         httpd_resp_send_404(req);
  294.         return ESP_FAIL;
  295.     }
  296.     int res = 0;
  297.     if(!strcmp(cmd, "F")) {
  298.       Serial.println("Forward");
  299.       // digitalWrite(DRV_A, LOW);
  300.       // digitalWrite(DRV_B, HIGH);
  301.       // digitalWrite(DIR_A, LOW);
  302.       // digitalWrite(DIR_B, HIGH);
  303.       Serial1.println("F"); // 发送前进指令
  304.       analogWrite(DRV_A, 0);
  305.       analogWrite(DRV_B, speed1);
  306.       analogWrite(DIR_A, 0);
  307.       analogWrite(DIR_B, speed2);
  308.       httpd_resp_set_type(req, "text/html");
  309.       return httpd_resp_send(req, "OK", 2);
  310.     }
  311.    
  312.     else if(!strcmp(cmd, "B")) {
  313.       Serial.println("Backward");
  314.       // digitalWrite(DRV_A, HIGH);
  315.       // digitalWrite(DRV_B, LOW);
  316.       // digitalWrite(DIR_A, HIGH);
  317.       // digitalWrite(DIR_B, LOW);
  318.       Serial1.println("B"); // 发送后退指令
  319.       analogWrite(DRV_A, speed1);
  320.       analogWrite(DRV_B, 0);
  321.       analogWrite(DIR_A, speed2);
  322.       analogWrite(DIR_B, 0);
  323.       httpd_resp_set_type(req, "text/html");
  324.       return httpd_resp_send(req, "OK", 2);
  325.     }
  326.    
  327.     else if(!strcmp(cmd, "L")) {
  328.       Serial.println("Turn Left");
  329.       
  330.       // digitalWrite(DRV_A, HIGH);
  331.       // digitalWrite(DRV_B, LOW);
  332.       // digitalWrite(DIR_A, LOW);
  333.       // digitalWrite(DIR_B, HIGH);
  334.       Serial1.println("L"); // 发送左转指令
  335.       analogWrite(DRV_A, speed1);
  336.       analogWrite(DRV_B, 0);
  337.       analogWrite(DIR_A, 0);
  338.       analogWrite(DIR_B, speed2);
  339.       httpd_resp_set_type(req, "text/html");
  340.       return httpd_resp_send(req, "OK", 2);
  341.     }
  342.    
  343.     else if(!strcmp(cmd, "R")) {
  344.       Serial.println("Turn Right");
  345.       Serial1.println("R"); // 发送右转指令
  346.       analogWrite(DRV_A, 0);
  347.       analogWrite(DRV_B, speed1);
  348.       analogWrite(DIR_A, speed2);
  349.       analogWrite(DIR_B, 0);
  350.       httpd_resp_set_type(req, "text/html");
  351.       return httpd_resp_send(req, "OK", 2);
  352.     }
  353.    
  354.     else if(!strcmp(cmd, "G")) {
  355.       Serial.println("Forward Left");
  356.       analogWrite(DRV_A, 0);
  357.       analogWrite(DRV_B, 0);
  358.       analogWrite(DIR_A, 0);
  359.       analogWrite(DIR_B, speed2);
  360.       httpd_resp_set_type(req, "text/html");
  361.       return httpd_resp_send(req, "OK", 2);
  362.     }
  363.    
  364.     else if(!strcmp(cmd, "H")) {
  365.       Serial.println("Backward Left");
  366.       analogWrite(DRV_A, speed1);
  367.       analogWrite(DRV_B, 0);
  368.       analogWrite(DIR_A, 0);
  369.       analogWrite(DIR_B, 0);
  370.       httpd_resp_set_type(req, "text/html");
  371.       return httpd_resp_send(req, "OK", 2);
  372.     }
  373.    
  374.     else if(!strcmp(cmd, "I")) {
  375.       Serial.println("Forward Right");
  376.       analogWrite(DRV_A, 0);
  377.       analogWrite(DRV_B, speed1);
  378.       analogWrite(DIR_A, 0);
  379.       analogWrite(DIR_B, 0);
  380.       httpd_resp_set_type(req, "text/html");
  381.       return httpd_resp_send(req, "OK", 2);
  382.     }
  383.    
  384.     else if(!strcmp(cmd, "J")) {
  385.       Serial.println("Backward Right");
  386.       analogWrite(DRV_A, 0);
  387.       analogWrite(DRV_B, 0);
  388.       analogWrite(DIR_A, speed2);
  389.       analogWrite(DIR_B, 0);
  390.       httpd_resp_set_type(req, "text/html");
  391.       return httpd_resp_send(req, "OK", 2);
  392.     }
  393.    
  394.     else if(!strcmp(cmd, "S")) {
  395.       Serial.println("Stop");
  396.       Serial1.println("S"); // 发送停止指令
  397.       analogWrite(DRV_A, 0);
  398.       analogWrite(DRV_B, 0);
  399.       analogWrite(DIR_A, 0);
  400.       analogWrite(DIR_B, 0);
  401.       httpd_resp_set_type(req, "text/html");
  402.       return httpd_resp_send(req, "OK", 2);
  403.     }
  404.    
  405.     // else if(!strcmp(cmd, "V")) {
  406.     //   Serial.println("Horn On");
  407.     //   digitalWrite(buzzerPin, HIGH);
  408.     //   httpd_resp_set_type(req, "text/html");
  409.     //   return httpd_resp_send(req, "OK", 2);
  410.     // }
  411.    
  412.     // else if(!strcmp(cmd, "v")) {
  413.     //   Serial.println("Horn Off");
  414.     //   digitalWrite(buzzerPin, LOW);
  415.     //   httpd_resp_set_type(req, "text/html");
  416.     //   return httpd_resp_send(req, "OK", 2);
  417.     // }
  418.     else if(!strcmp(cmd, "T")) {
  419.       speed1=105;   //左
  420.       speed2=105;
  421.       httpd_resp_set_type(req, "text/html");
  422.       return httpd_resp_send(req, "OK", 2);
  423.     }
  424.    
  425.     else if(!strcmp(cmd, "Y")) {
  426.       speed1=165;
  427.       speed2=165;
  428.       httpd_resp_set_type(req, "text/html");
  429.       return httpd_resp_send(req, "OK", 2);
  430.     }        
  431.     else if(!strcmp(cmd, "U")) {
  432.       speed1=255;
  433.       speed2=255;
  434.       httpd_resp_set_type(req, "text/html");
  435.       return httpd_resp_send(req, "OK", 2);
  436.     }  
  437.     // else if(!strcmp(cmd, "W")) {
  438.     //   Serial.println("LED On");
  439.     //   ledcWrite(7, ledVal);
  440.     //   httpd_resp_set_type(req, "text/html");
  441.     //   return httpd_resp_send(req, "OK", 2);
  442.     // }
  443.    
  444.     else if(!strcmp(cmd, "w")) {
  445.       Serial.println("LED Off");
  446.       Serial1.println("w"); // 发送关灯指令
  447.       ledcWrite(7, 0);
  448.       httpd_resp_set_type(req, "text/html");
  449.       return httpd_resp_send(req, "OK", 2);
  450.     }
  451.    
  452.     // else if (!strcmp(cmd, "x")){
  453.     //   Serial.println("Flash Light : Low (20)");
  454.     //   ledVal = 20;
  455.     //   ledcWrite(7, ledVal);
  456.     //   httpd_resp_set_type(req, "text/html");
  457.     //   return httpd_resp_send(req, "OK", 2);
  458.     // }
  459.     // else if (!strcmp(cmd, "y")){
  460.     //   Serial.println("Flash Light : Medium (50)");
  461.     //   ledVal = 50;
  462.     //   ledcWrite(7, ledVal);
  463.     //   httpd_resp_set_type(req, "text/html");
  464.     //   return httpd_resp_send(req, "OK", 2);
  465.     // }
  466.     // else if (!strcmp(cmd, "z")){
  467.     //   Serial.println("Flash Light : Bright (100)");
  468.     //   ledVal = 100;
  469.     //   ledcWrite(7, ledVal);
  470.     //   httpd_resp_set_type(req, "text/html");
  471.     //   return httpd_resp_send(req, "OK", 2);
  472.     // }   
  473.     else if (!strcmp(cmd, "Z")){
  474.       Serial.println("Flash Light : Super Bright (255)");
  475.       Serial1.println("Z"); // 发送开灯指令
  476.       ledVal = 255;
  477.       ledcWrite(7, ledVal);
  478.       httpd_resp_set_type(req, "text/html");
  479.       return httpd_resp_send(req, "OK", 2);
  480.     }   
  481.    
  482.     else if (!strcmp(cmd, "a")){
  483.       Serial.println("Servo q (0)");
  484.       // ledcWrite(8, 400);
  485.       myservo.write(110);
  486.       delay(100);
  487.       myservo.write(90);
  488.       delay(100);
  489.       digitalWrite(servoPin, LOW);
  490.       httpd_resp_set_type(req, "text/html");
  491.       return httpd_resp_send(req, "OK", 2);
  492.     }
  493.     else if (!strcmp(cmd, "b")){
  494.       Serial.println("Servo q (6500)");
  495.       // ledcWrite(8, 6000);
  496.       myservo.write(70);
  497.       delay(100);
  498.       myservo.write(90);
  499.       delay(100);
  500.       digitalWrite(servoPin, LOW);
  501.       httpd_resp_set_type(req, "text/html");
  502.       return httpd_resp_send(req, "OK", 2);
  503.     }
  504.     // else if (!strcmp(cmd, "n")){
  505.     //   EEPROM.begin(EEPROM_Size);  //开启EEPROM
  506.     //   EEPROM_dataT=EEPROM.read(EEPROM_speedT);
  507.     //   Serial.printf("last_EEPROM_speed:%d",EEPROM_dataT);
  508.     //   if (EEPROM_dataT<60)
  509.     //     EEPROM_dataT=EEPROM_dataT+1;
  510.     //   Serial.printf("now_EEPROM_speed:%d",EEPROM_dataT);
  511.     //   EEPROM.write(EEPROM_speedT,EEPROM_dataT);
  512.     //   EEPROM.commit();
  513.     //   String response = String(EEPROM_dataT); // 将整数转换为字符串
  514.     //   httpd_resp_set_type(req, "text/html");
  515.     //   return httpd_resp_send(req,response.c_str(), response.length());
  516.     // }
  517.     // else if (!strcmp(cmd, "m")){
  518.     //   EEPROM.begin(EEPROM_Size);  //开启EEPROM
  519.     //   EEPROM_dataT=EEPROM.read(EEPROM_speedT);
  520.     //   Serial.printf("last_EEPROM_speed:%d",EEPROM_dataT);
  521.     //   if (EEPROM_dataT>0)
  522.     //     EEPROM_dataT=EEPROM_dataT-1;
  523.     //   Serial.printf("now_EEPROM_speed:%d",EEPROM_dataT);
  524.     //   EEPROM.write(EEPROM_speedT,EEPROM_dataT);
  525.     //   EEPROM.commit();
  526.     //   String response = String(EEPROM_dataT); // 将整数转换为字符串
  527.     //   httpd_resp_set_type(req, "text/html");
  528.     //   return httpd_resp_send(req, response.c_str(), response.length());
  529.     // }
  530.     // else if (!strcmp(cmd, "h")){
  531.     //   EEPROM.begin(EEPROM_Size);  //开启EEPROM
  532.     //   EEPROM_dataT=EEPROM.read(EEPROM_speedT);
  533.     //   Serial.printf("last_EEPROM_speed:%d",EEPROM_dataT);
  534.     //   Serial.printf("now_EEPROM_speed:%d",EEPROM_dataT);
  535.     //   EEPROM.write(EEPROM_speedT,EEPROM_dataT);
  536.     //   EEPROM.commit();
  537.     //   speed1=125+EEPROM_dataT;
  538.     //   speed2=155;
  539.     //   String response = String(EEPROM_dataT); // 将整数转换为字符串
  540.     //   httpd_resp_set_type(req, "text/html");
  541.     //   return httpd_resp_send(req,"OK", 2);
  542.     // }
  543.     // else if (!strcmp(cmd, "j")){
  544.     //   EEPROM.begin(EEPROM_Size);  //开启EEPROM
  545.     //   EEPROM_dataY=EEPROM.read(EEPROM_speedY);
  546.     //   Serial.printf("last_EEPROM_speed:%d",EEPROM_dataY);
  547.     //   if (EEPROM_dataY>0)
  548.     //     EEPROM_dataY=EEPROM_dataY+1;
  549.     //   Serial.printf("now_EEPROM_speed:%d",EEPROM_dataY);
  550.     //   EEPROM.write(EEPROM_speedY,EEPROM_dataY);
  551.     //   EEPROM.commit();
  552.     //   //  speed1=speed1d+EEPROM_data;
  553.     //   String response = String(EEPROM_dataY); // 将整数转换为字符串
  554.     //   httpd_resp_set_type(req, "text/html");
  555.     //   return httpd_resp_send(req, response.c_str(), response.length());
  556.     // }
  557.     // else if (!strcmp(cmd, "k")){
  558.     //   EEPROM.begin(EEPROM_Size);  //开启EEPROM
  559.     //   EEPROM_dataY=EEPROM.read(EEPROM_speedY);
  560.     //   Serial.printf("last_EEPROM_speed:%d",EEPROM_dataY);
  561.     //   if (EEPROM_dataY>0)
  562.     //     EEPROM_dataY=EEPROM_dataY-1;
  563.     //   Serial.printf("now_EEPROM_speed:%d",EEPROM_dataY);
  564.     //   EEPROM.write(EEPROM_speedY,EEPROM_dataY);
  565.     //   EEPROM.commit();
  566.     //   //  speed1=speed1d+EEPROM_data;
  567.     //   String response = String(EEPROM_dataY); // 将整数转换为字符串
  568.     //   httpd_resp_set_type(req, "text/html");
  569.     //   return httpd_resp_send(req, response.c_str(), response.length());
  570.     // }
  571.     // else if (!strcmp(cmd, "i")){
  572.     //   EEPROM.begin(EEPROM_Size);  //开启EEPROM
  573.     //   EEPROM_dataU=EEPROM.read(EEPROM_speedU);
  574.     //   Serial.printf("last_EEPROM_speed:%d",EEPROM_dataU);
  575.     //   if (EEPROM_dataU>0)
  576.     //     EEPROM_dataU=EEPROM_dataU+1;
  577.     //   Serial.printf("now_EEPROM_speed:%d",EEPROM_dataU);
  578.     //   EEPROM.write(EEPROM_speedU,EEPROM_dataU);
  579.     //   EEPROM.commit();
  580.     //   //  speed1=speed1d+EEPROM_data;
  581.     //   String response = String(EEPROM_dataU); // 将整数转换为字符串
  582.     //   httpd_resp_set_type(req, "text/html");
  583.     //   return httpd_resp_send(req, response.c_str(), response.length());
  584.     // }
  585.     // else if (!strcmp(cmd, "o")){
  586.     //   EEPROM.begin(EEPROM_Size);  //开启EEPROM
  587.     //   EEPROM_dataU=EEPROM.read(EEPROM_speedU);
  588.     //   Serial.printf("last_EEPROM_speed:%d",EEPROM_dataU);
  589.     //   if (EEPROM_dataU>0)
  590.     //     EEPROM_dataU=EEPROM_dataU-1;
  591.     //   Serial.printf("now_EEPROM_speed:%d",EEPROM_dataU);
  592.     //   EEPROM.write(EEPROM_speedU,EEPROM_dataU);
  593.     //   EEPROM.commit();
  594.     //   //  speed1=speed1d+EEPROM_data;
  595.     //   String response = String(EEPROM_dataU); // 将整数转换为字符串
  596.     //   httpd_resp_set_type(req, "text/html");
  597.     //   return httpd_resp_send(req, response.c_str(), response.length());
  598.     // }
  599.    
  600.     else {
  601.         res = -1;
  602.     }
  603.     if(res){
  604.         return httpd_resp_send_500(req);
  605.     }
  606.     httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  607.     return httpd_resp_send(req, NULL, 0);
  608. }
  609. // static esp_err_t data_handler(httpd_req_t *req) {
  610. //     char buf[1024];  // 增加缓冲区大小
  611. //     int ret, remaining = req->content_len;
  612. //     char request_data[1024];  // 增加缓冲区大小
  613. //     int data_index = 0;
  614. //     while (remaining > 0) {
  615. //         ret = httpd_req_recv(req, buf, MIN(remaining, sizeof(buf)));
  616. //         if (ret <= 0) {
  617. //             if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
  618. //                 httpd_resp_send_408(req);
  619. //             } else {
  620. //                 httpd_resp_send_500(req);
  621.             
  622. //             return ESP_FAIL;
  623. //         }
  624. //         for (int i = 0; i < ret; i++) {
  625. //             request_data[data_index] = buf[i];
  626. //             data_index++;
  627. //         }
  628. //         remaining -= ret;
  629. //     }
  630. //     // 解析JSON数据
  631. //     cJSON *root = cJSON_Parse(request_data);
  632. //     if (root == NULL) {
  633. //         // JSON解析失败
  634. //         httpd_resp_send_500(req);
  635. //         return ESP_FAIL;
  636. //     }
  637. //     // 获取JSON对象中的数据项
  638. //     cJSON *value1 = cJSON_GetObjectItem(root, "value1");
  639. //     cJSON *value2 = cJSON_GetObjectItem(root, "value2");
  640. //     if (value1 == NULL || value2 == NULL) {
  641. //         // JSON数据项不存在
  642. //         //httpd_resp_send_400(req);  // 使用400 Bad Request
  643. //         httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Bad Request");
  644. //         cJSON_Delete(root);
  645. //         return ESP_FAIL;
  646. //     }
  647. //     // 将数据项转换为整数
  648. //     int intValue1 = value1->valueint;
  649. //     int intValue2 = value2->valueint;
  650. //     // 打印解析后的数据
  651. //     printf("Received JSON data - value1: %d, value2: %d\n", intValue1, intValue2);
  652. //     cJSON_Delete(root);
  653. //     // 发送响应给客户端
  654. //     httpd_resp_set_type(req, "text/plain");
  655. //     httpd_resp_send(req, "JSON data received and processed", -1);
  656. //     return ESP_OK;
  657. // }
  658. // }
  659. // 这是启动相机服务器的函数,它会注册URI处理程序,包括视频流处理程序
  660. void startCameraServer(){
  661.     httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  662.    
  663.     httpd_uri_t status_uri = {
  664.         .uri       = "/status",
  665.         .method    = HTTP_GET,
  666.         .handler   = status_handler,
  667.         .user_ctx  = NULL
  668.     };
  669.     httpd_uri_t cmd_uri = {
  670.         .uri       = "/control",
  671.         .method    = HTTP_GET,
  672.         .handler   = cmd_handler,
  673.         .user_ctx  = NULL
  674.     };
  675.     httpd_uri_t capture_uri = {
  676.         .uri       = "/capture",
  677.         .method    = HTTP_GET,
  678.         .handler   = capture_handler,
  679.         .user_ctx  = NULL
  680.     };
  681.    httpd_uri_t stream_uri = {
  682.         .uri       = "/stream",
  683.         .method    = HTTP_GET,
  684.         .handler   = stream_handler,
  685.         .user_ctx  = NULL
  686.     };
  687.    httpd_uri_t state_uri = {
  688.         .uri       = "/state",
  689.         .method    = HTTP_GET,
  690.         .handler   = state_handler,
  691.         .user_ctx  = NULL
  692.     };
  693.     // httpd_uri_t data_uri = {
  694.     // .uri       = "/data",
  695.     // .method    = HTTP_GET,
  696.     // .handler   = data_handler,
  697.     // .user_ctx  = NULL
  698.     // };
  699.     Serial.printf("Starting web server on port: '%d'", config.server_port);
  700.     if (httpd_start(&camera_httpd, &config) == ESP_OK) {
  701.         httpd_register_uri_handler(camera_httpd, &cmd_uri);
  702.         httpd_register_uri_handler(camera_httpd, &capture_uri);
  703.         httpd_register_uri_handler(camera_httpd, &status_uri);
  704.         httpd_register_uri_handler(camera_httpd, &state_uri);
  705.         // httpd_register_uri_handler(camera_httpd, &data_uri);
  706.     }
  707.     config.server_port += 1;
  708.     config.ctrl_port += 1;
  709.     Serial.printf("Starting stream server on port: '%d'", config.server_port);
  710.     if (httpd_start(&stream_httpd, &config) == ESP_OK) {
  711.         httpd_register_uri_handler(stream_httpd, &stream_uri);
  712.     }
  713. }
复制代码



    4、APP

APP来自开源项目ESP32履带车

用树莓派PICO制作一个FPV小车图11




附件:








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

本版积分规则

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

硬件清单

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

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

mail