当前位置:   article > 正文

引航计划Day4_espasyncwebserver ov2640

espasyncwebserver ov2640

时间来到了引航计划第四天,今天的任务是小车摄像头的调试以及遥控小车采集数据。

安装好摄像头后,将小车烧入控制程序,然后向摄像头烧入如下程序:

  1. /*********
  2. https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
  3. https://github.com/espressif/arduino-esp32/issues/1313
  4. https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-timer.c
  5. *********/
  6. #include "WiFi.h"
  7. #include "esp_camera.h"
  8. #include "esp_timer.h"
  9. #include "img_converters.h"
  10. #include "Arduino.h"
  11. #include "soc/soc.h" // Disable brownout problems
  12. #include "soc/rtc_cntl_reg.h" // Disable brownout problems
  13. #include "driver/rtc_io.h"
  14. #include <ESPAsyncWebServer.h>
  15. #include <StringArray.h>
  16. #include "FS.h" // SD Card ESP32
  17. #include "SD_MMC.h" // SD Card ESP32
  18. #include "time.h"
  19. #include <WiFiUdp.h>
  20. #include "driver/timer.h"
  21. // Replace with your network credentials
  22. const char* ssid = "guozichang";
  23. const char* password = "123456789";
  24. // Set your Static IP address
  25. IPAddress local_IP(192, 168, 4, 5);
  26. // Set your Gateway IP address
  27. IPAddress gateway(192, 168, 4, 1);
  28. IPAddress subnet(255, 255, 0, 0);
  29. IPAddress primaryDNS(8, 8, 8, 8); //optional
  30. IPAddress secondaryDNS(8, 8, 4, 4); //optional
  31. // Create AsyncWebServer object on port 80
  32. AsyncWebServer server(80);
  33. boolean takeNewPhoto = false;
  34. String lastPhoto = "";
  35. String list = "";
  36. hw_timer_t * timer = NULL;
  37. hw_timer_t * timer_1 = NULL;
  38. boolean isRecording = false;
  39. // HTTP GET parameter
  40. const char* PARAM_INPUT_1 = "photo";
  41. const char* PARAM_INPUT_2 = "record_time";
  42. const char* PARAM_INPUT_3 = "record_interval";
  43. // OV2640 camera module pins (CAMERA_MODEL_AI_THINKER)
  44. #define PWDN_GPIO_NUM 32
  45. #define RESET_GPIO_NUM -1
  46. #define XCLK_GPIO_NUM 0
  47. #define SIOD_GPIO_NUM 26
  48. #define SIOC_GPIO_NUM 27
  49. #define Y9_GPIO_NUM 35
  50. #define Y8_GPIO_NUM 34
  51. #define Y7_GPIO_NUM 39
  52. #define Y6_GPIO_NUM 36
  53. #define Y5_GPIO_NUM 21
  54. #define Y4_GPIO_NUM 19
  55. #define Y3_GPIO_NUM 18
  56. #define Y2_GPIO_NUM 5
  57. #define VSYNC_GPIO_NUM 25
  58. #define HREF_GPIO_NUM 23
  59. #define PCLK_GPIO_NUM 22
  60. // Stores the camera configuration parameters
  61. camera_config_t config;
  62. File root;
  63. void setup() {
  64. // Turn-off the brownout detector
  65. WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
  66. // Serial port for debugging purposes
  67. Serial.begin(115200);
  68. // Configures static IP address
  69. if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
  70. Serial.println("STA Failed to configure");
  71. }
  72. // Wi-Fi connection
  73. WiFi.begin(ssid, password);
  74. while (WiFi.status() != WL_CONNECTED) {
  75. delay(1000);
  76. Serial.print(".");
  77. }
  78. Serial.println("");
  79. Serial.println("WiFi connected");
  80. Serial.print("Camera Stream Ready! Go to: http://");
  81. Serial.println(WiFi.localIP());
  82. Serial.println("Initializing the camera module...");
  83. configInitCamera();
  84. Serial.println("Initializing the MicroSD card module... ");
  85. initMicroSDCard();
  86. server.on("/capture", HTTP_GET, [](AsyncWebServerRequest * request) {
  87. if (takeNewPhoto) {
  88. request->send_P(200, "text/plain", "");
  89. } else {
  90. camera_fb_t * frame = esp_camera_fb_get();
  91. request->send_P(200, "image/jpeg", (const uint8_t *)frame->buf, frame->len);
  92. esp_camera_fb_return(frame);
  93. frame = NULL;
  94. }
  95. });
  96. server.on("/list", HTTP_GET, [](AsyncWebServerRequest * request) {
  97. request->send_P(200, "text/html", list.c_str());
  98. });
  99. server.on("/view", HTTP_GET, [](AsyncWebServerRequest * request) {
  100. String inputMessage;
  101. String inputParam;
  102. // GET input1 value on <ESP_IP>/view?photo=<inputMessage>
  103. if (request->hasParam(PARAM_INPUT_1)) {
  104. inputMessage = "/" + request->getParam(PARAM_INPUT_1)->value();
  105. Serial.print("Trying to open ");
  106. Serial.println(inputMessage);
  107. inputParam = PARAM_INPUT_1;
  108. }
  109. else {
  110. inputMessage = "No message sent";
  111. inputParam = "none";
  112. }
  113. Serial.println(inputMessage);
  114. request->send(SD_MMC, inputMessage, "image/jpg", false);
  115. });
  116. // Send a GET request to <ESP_IP>/delete?photo=<inputMessage>
  117. server.on("/delete", HTTP_GET, [] (AsyncWebServerRequest *request) {
  118. String inputMessage;
  119. String inputParam;
  120. // GET input1 value on <ESP_IP>/delete?photo=<inputMessage>
  121. if (request->hasParam(PARAM_INPUT_1)) {
  122. inputMessage = "/" + request->getParam(PARAM_INPUT_1)->value();
  123. inputParam = PARAM_INPUT_1;
  124. }
  125. else {
  126. inputMessage = "No message sent";
  127. inputParam = "none";
  128. }
  129. Serial.println(inputMessage);
  130. deleteFile(SD_MMC, inputMessage.c_str());
  131. request->send(200, "text/html", "Done. Your photo named " + inputMessage + " was removed." +
  132. "<br><a href=\"/list\">view/delete other photos</a>.");
  133. });
  134. server.on("/record", HTTP_GET, [](AsyncWebServerRequest * request) {
  135. String inputMessage_2;
  136. String inputMessage_3;
  137. // GET input1 value on <ESP_IP>/view?photo=<inputMessage>
  138. if (request->hasParam(PARAM_INPUT_2)) {
  139. inputMessage_2 = request->getParam(PARAM_INPUT_2)->value();
  140. if (request->hasParam(PARAM_INPUT_3)) {
  141. Serial.println("Start record... Can't get ip camera stream now.");
  142. inputMessage_3 = request->getParam(PARAM_INPUT_3)->value();
  143. take_save_record(inputMessage_2.toInt(), inputMessage_3.toInt());
  144. }
  145. else {
  146. inputMessage_3 = "Request on /record lacks Param 1!";
  147. Serial.println(inputMessage_3);
  148. }
  149. }
  150. else {
  151. inputMessage_2 = "Request on /record lacks Param 2!";
  152. Serial.println(inputMessage_2);
  153. }
  154. });
  155. server.on("/stop_record", HTTP_GET, [](AsyncWebServerRequest * request) {
  156. Serial.println("Stop record. You can get ip camera stream now.");
  157. stop_record();
  158. });
  159. // Start server
  160. server.begin();
  161. root = SD_MMC.open("/");
  162. listDirectory(SD_MMC);
  163. }
  164. void loop() {
  165. if (takeNewPhoto) {
  166. takeSavePhoto();
  167. takeNewPhoto = false;
  168. }
  169. delay(1);
  170. }
  171. void configInitCamera(){
  172. config.ledc_channel = LEDC_CHANNEL_0;
  173. config.ledc_timer = LEDC_TIMER_0;
  174. config.pin_d0 = Y2_GPIO_NUM;
  175. config.pin_d1 = Y3_GPIO_NUM;
  176. config.pin_d2 = Y4_GPIO_NUM;
  177. config.pin_d3 = Y5_GPIO_NUM;
  178. config.pin_d4 = Y6_GPIO_NUM;
  179. config.pin_d5 = Y7_GPIO_NUM;
  180. config.pin_d6 = Y8_GPIO_NUM;
  181. config.pin_d7 = Y9_GPIO_NUM;
  182. config.pin_xclk = XCLK_GPIO_NUM;
  183. config.pin_pclk = PCLK_GPIO_NUM;
  184. config.pin_vsync = VSYNC_GPIO_NUM;
  185. config.pin_href = HREF_GPIO_NUM;
  186. config.pin_sscb_sda = SIOD_GPIO_NUM;
  187. config.pin_sscb_scl = SIOC_GPIO_NUM;
  188. config.pin_pwdn = PWDN_GPIO_NUM;
  189. config.pin_reset = RESET_GPIO_NUM;
  190. config.xclk_freq_hz = 20000000;
  191. config.pixel_format = PIXFORMAT_JPEG; // YUV422,GRAYSCALE,RGB565,JPEG
  192. config.frame_size = FRAMESIZE_SVGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
  193. config.jpeg_quality = 10; //0-63 lower number means higher quality
  194. config.fb_count = 2;
  195. // // Select lower framesize if the camera doesn't support PSRAM
  196. // if(psramFound()){
  197. // config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
  198. // config.jpeg_quality = 10; //0-63 lower number means higher quality
  199. // config.fb_count = 2;
  200. // }
  201. // else {
  202. // config.frame_size = FRAMESIZE_SVGA;
  203. // config.jpeg_quality = 12;
  204. // config.fb_count = 1;
  205. // }
  206. // Initialize the Camera
  207. esp_err_t err = esp_camera_init(&config);
  208. if (err != ESP_OK) {
  209. Serial.printf("Camera init failed with error 0x%x", err);
  210. return;
  211. }
  212. }
  213. void initMicroSDCard(){
  214. // Start Micro SD card
  215. Serial.println("Starting SD Card");
  216. if(!SD_MMC.begin()){
  217. Serial.println("SD Card Mount Failed");
  218. return;
  219. }
  220. uint8_t cardType = SD_MMC.cardType();
  221. if(cardType == CARD_NONE){
  222. Serial.println("No SD Card attached");
  223. return;
  224. }
  225. }
  226. void takeSavePhoto(){
  227. struct tm timeinfo;
  228. char now[20];
  229. // Take Picture with Camera
  230. camera_fb_t * fb = esp_camera_fb_get();
  231. if(!fb) {
  232. Serial.println("Camera capture failed");
  233. return;
  234. }
  235. // Path where new picture will be saved in SD Card
  236. getLocalTime(&timeinfo);
  237. strftime(now, 20, "%Y%m%d_%H%M%S", &timeinfo); // Format Date & Time
  238. String path = "/photo_" + String(now) +".jpg";
  239. lastPhoto = path;
  240. Serial.printf("Picture file name: %s\n", path.c_str());
  241. // Save picture to microSD card
  242. fs::FS &fs = SD_MMC;
  243. File file = fs.open(path.c_str(),FILE_WRITE);
  244. if(!file){
  245. Serial.printf("Failed to open file in writing mode");
  246. }
  247. else {
  248. file.write(fb->buf, fb->len); // payload (image), payload length
  249. Serial.printf(" Saved: %s\n", path.c_str());
  250. listDirectory(SD_MMC);
  251. }
  252. file.close();
  253. esp_camera_fb_return(fb);
  254. }
  255. void IRAM_ATTR onTimer(){
  256. takeNewPhoto = true;
  257. }
  258. void IRAM_ATTR onTimer1() {
  259. Serial.println("Recording is complete. You can get ip camera stream now.");
  260. if (isRecording) {
  261. isRecording = false;
  262. //timer_disable_intr(TIMER_GROUP_0, TIMER_0);
  263. if (timer != NULL) {
  264. timerAlarmDisable(timer);
  265. timerDetachInterrupt(timer);
  266. timerEnd(timer);
  267. timer = NULL;
  268. }
  269. if (timer_1 != NULL) {
  270. timerAlarmDisable(timer_1);
  271. timerDetachInterrupt(timer_1);
  272. timerEnd(timer_1);
  273. timer_1 = NULL;
  274. }
  275. }
  276. }
  277. void take_save_record(long duration, long interval) {
  278. Serial.print("Duration: ");
  279. Serial.print(duration);
  280. Serial.print(" minute, Interval: ");
  281. Serial.print(interval);
  282. Serial.println(" s.");
  283. isRecording = true;
  284. if (timer == NULL) {
  285. timer = timerBegin(0, 40, true);
  286. // Attach onTimer function to our timer
  287. timerAttachInterrupt(timer, &onTimer, true);
  288. }
  289. /* Set alarm to call onTimer function every second 1 tick is 1us
  290. => 1 second is 1000000us
  291. Repeat the alarm (third parameter) */
  292. timerAlarmWrite(timer, interval * 1000000, true);
  293. /* Start an alarm */
  294. yield();
  295. timerAlarmEnable(timer);
  296. timer_1 = timerBegin(1, 80, true);
  297. timerAttachInterrupt(timer_1, &onTimer1, true);
  298. timerAlarmWrite(timer_1, duration * 60 * 1000000, false);
  299. yield();
  300. timerAlarmEnable(timer_1);
  301. }
  302. void stop_record() {
  303. if (isRecording) {
  304. isRecording = false;
  305. //timer_disable_intr(TIMER_GROUP_0, TIMER_0);
  306. if (timer != NULL) {
  307. timerAlarmDisable(timer);
  308. timerDetachInterrupt(timer);
  309. timerEnd(timer);
  310. timer = NULL;
  311. }
  312. if (timer_1 != NULL) {
  313. timerAlarmDisable(timer_1);
  314. timerDetachInterrupt(timer_1);
  315. timerEnd(timer_1);
  316. timer_1 = NULL;
  317. }
  318. }
  319. }
  320. void listDirectory(fs::FS &fs) {
  321. File root = fs.open("/");
  322. list = "";
  323. if(!root){
  324. Serial.println("Failed to open directory");
  325. return;
  326. }
  327. if(!root.isDirectory()){
  328. Serial.println("Not a directory");
  329. return;
  330. }
  331. File file = root.openNextFile();
  332. while(file){
  333. if(!file.isDirectory()){
  334. String filename=String(file.name());
  335. filename.toLowerCase();
  336. if (filename.indexOf(".jpg")!=-1){
  337. list = "<tr><td><button onclick=\"window.open('/view?photo="+String(file.name())+"','_blank')\">View</button></td><td><button onclick=\"window.location.href='/delete?photo="+String(file.name())+"'\">Delete</button></td><td>"+String(file.name())+"</td><td></td></tr>"+list;
  338. }
  339. }
  340. lastPhoto = file.name();
  341. file = root.openNextFile();
  342. }
  343. if (list=="") {
  344. list="<tr>No photos Stored</tr>";
  345. }
  346. else {
  347. list="<h1>ESP32-CAM View and Delete Photos</h1><table><th colspan=\"2\">Actions</th><th>Filename</th>"+list+"</table>";
  348. }
  349. }
  350. void deleteFile(fs::FS &fs, const char * path){
  351. Serial.printf("Deleting file: %s\n", path);
  352. if(fs.remove(path)){
  353. Serial.println("File deleted");
  354. listDirectory(SD_MMC);
  355. }
  356. else {
  357. Serial.println("Delete failed");
  358. }
  359. }

点击record按钮就可以记录一张480000像素的照片啦!

 设定好拍照持续时间和拍照间隔后,边可以遥控小车进行数据采集,得到的部分照片如下:

 

 共采集237张照片,构成了数据集。

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号