Advertisement
Guest User

Untitled

a guest
Nov 13th, 2021
106
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.96 KB | None | 0 0
  1. /*********
  2. Rui Santos
  3. Complete project details at https://RandomNerdTutorials.com/esp32-cam-video-streaming-web-server-camera-home-assistant/
  4.  
  5. IMPORTANT!!!
  6. - Select Board "AI Thinker ESP32-CAM"
  7. - GPIO 0 must be connected to GND to upload a sketch
  8. - After connecting GPIO 0 to GND, press the ESP32-CAM on-board RESET button to put your board in flashing mode
  9.  
  10. Permission is hereby granted, free of charge, to any person obtaining a copy
  11. of this software and associated documentation files.
  12.  
  13. The above copyright notice and this permission notice shall be included in all
  14. copies or substantial portions of the Software.
  15. *********/
  16.  
  17. /*
  18. PCA9685 goes onto pins 15(SDA) and 14(SCL) of the esp32-cam. it will create a wifi hotspot on startup.
  19. 192.168.4.1 will have the camera feed (but as of now it blocks the rest of the program from running).
  20. You add frames by POSTing them in binary format to 192.168.4.1/sv:
  21.  
  22. requests.post("http://192.168.4.1/sv", data=bytes([0x07, 0x01, 0x00, 0x1A, 0x00, 0x2A]))
  23.  
  24. the first byte selects the servo. the second byte is the flag bits, these are set to 0x01 for normal move,
  25. 0xFE to skip this servo or 0xFF to force-stop. the next two bytes are the position in degrees,
  26. and the last two are the speed in deg/s, both as 16 bit unsigned integers.
  27.  
  28. this will only load the movement into the buffer, to play it back send data=bytes([0xFF]).
  29. You can send as few or as many servo commands as you want in a single request, up to the FRAME_SZ.
  30. However, you must send 0xFF on its own (it is a substitute for an external trigger signal on PIN 2).
  31. */
  32.  
  33. #define DEBUG2
  34.  
  35. #include "esp_camera.h"
  36. #include <WiFi.h>
  37. #include "esp_timer.h"
  38. #include "img_converters.h"
  39. #include "Arduino.h"
  40. #include "fb_gfx.h"
  41. #include "soc/soc.h" //disable brownout problems
  42. #include "soc/rtc_cntl_reg.h" //disable brownout problems
  43. #include "esp_http_server.h"
  44. #include "driver/i2c.h"
  45.  
  46. // ***WIFI/SERVER VARIABLES***
  47. const char* ssid = "ESP32-Access-Point";
  48. const char* password = "123456789";
  49.  
  50. #define PART_BOUNDARY "123456789000000000000987654321"
  51.  
  52. // This project was tested with the AI Thinker Model, M5STACK PSRAM Model and M5STACK WITHOUT PSRAM
  53. #define CAMERA_MODEL_AI_THINKER
  54.  
  55. #if defined(CAMERA_MODEL_AI_THINKER)
  56. #define PWDN_GPIO_NUM 32
  57. #define RESET_GPIO_NUM -1
  58. #define XCLK_GPIO_NUM 0
  59. #define SIOD_GPIO_NUM 26
  60. #define SIOC_GPIO_NUM 27
  61.  
  62. #define Y9_GPIO_NUM 35
  63. #define Y8_GPIO_NUM 34
  64. #define Y7_GPIO_NUM 39
  65. #define Y6_GPIO_NUM 36
  66. #define Y5_GPIO_NUM 21
  67. #define Y4_GPIO_NUM 19
  68. #define Y3_GPIO_NUM 18
  69. #define Y2_GPIO_NUM 5
  70. #define VSYNC_GPIO_NUM 25
  71. #define HREF_GPIO_NUM 23
  72. #define PCLK_GPIO_NUM 22
  73. #else
  74. #error "Camera model not selected"
  75. #endif
  76.  
  77. static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
  78. static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
  79. static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
  80.  
  81. httpd_handle_t stream_httpd = NULL;
  82.  
  83. // ***BUFFER VARIABLES***
  84. #define BUFFER_EMPTY 1
  85. #define BUFFER_FULL 2
  86. #define BUFFER_SUCCESS 0
  87. #define BUFFER_SZ 10 // in frames
  88. #define FRAME_SZ 192 // in bytes; set to servo count * 6
  89.  
  90. struct frame_buffer_t {
  91. int read_ptr;
  92. int write_ptr;
  93. int items;
  94. char *contents[BUFFER_SZ];
  95. };
  96.  
  97. frame_buffer_t framebuf;
  98.  
  99. // ***I2C VARIABLES***
  100. #define I2C_SCL GPIO_NUM_15
  101. #define I2C_SDA GPIO_NUM_14
  102.  
  103. // i2c device addresses
  104. #define SVDRIVER1 0x40
  105. #define SVDRIVER2 0x40 //TODO
  106. #define IMU 0x68
  107.  
  108. // servo driver stuff
  109. #define DRV_PRESCALE_VAL 122
  110. #define DRV_MODE 0x00
  111. #define DRV_SLEEP 0x10
  112. #define DRV_RESTART 0x80
  113. #define DRV_PRESCALE 0xFE
  114. #define DRV_ON_PTR 0x06
  115. #define DRV_RESTART 0x80
  116.  
  117. // ***SERVO CONTROL VARIABLES***
  118. #define SERVO_COUNT 10
  119.  
  120. struct servo_command_t {
  121. uint8_t id;
  122. uint8_t flags;
  123. uint16_t position;
  124. uint16_t velocity;
  125. };
  126.  
  127. struct servo_action_t {
  128. uint8_t driver_id;
  129. uint16_t last_pos;
  130. uint16_t goal_pos;
  131. uint16_t real_pos;
  132. int speed;
  133. unsigned long cycle_dur;
  134. unsigned long cycle_start;
  135. bool moving;
  136. };
  137.  
  138. servo_action_t servos[SERVO_COUNT];
  139.  
  140. int frames_to_play = 0;
  141.  
  142. // ***BUFFER SECTION***
  143.  
  144. void buffer_init() {
  145. framebuf.read_ptr = 0;
  146. framebuf.write_ptr = 0;
  147. framebuf.items = 0;
  148.  
  149. for (int i = 0; i < BUFFER_SZ; i++) {
  150. char *buf_item = new char[FRAME_SZ];
  151. memset(buf_item, 0, FRAME_SZ);
  152. framebuf.contents[i] = buf_item;
  153. }
  154. }
  155.  
  156. int buffer_add(char* frame) {
  157. if (framebuf.items >= BUFFER_SZ)
  158. return BUFFER_FULL;
  159.  
  160. memcpy(framebuf.contents[framebuf.write_ptr], frame, FRAME_SZ);
  161.  
  162. framebuf.items++;
  163. framebuf.write_ptr++;
  164. if (framebuf.write_ptr >= BUFFER_SZ)
  165. framebuf.write_ptr = 0;
  166.  
  167. return BUFFER_SUCCESS;
  168. }
  169.  
  170. // sets frame to the first full buffer item
  171. int buffer_get(char* frame) {
  172. if (framebuf.items == 0)
  173. return BUFFER_EMPTY;
  174.  
  175. memcpy(frame, framebuf.contents[framebuf.read_ptr], FRAME_SZ);
  176.  
  177. framebuf.items--;
  178. framebuf.read_ptr++;
  179. if (framebuf.read_ptr >= BUFFER_SZ)
  180. framebuf.read_ptr = 0;
  181.  
  182. return BUFFER_SUCCESS;
  183. }
  184.  
  185. #ifdef DEBUG2
  186. void print_frame(char* frame) {
  187. yield();
  188. char temp[(FRAME_SZ * 2) + 1];
  189. for (int i = 0; i < FRAME_SZ; i++) {
  190. char conv[3];
  191. sprintf(conv, "%02X", frame[i]);
  192. temp[i * 2] = conv[0];
  193. temp[(i * 2) + 1] = conv[1];
  194. }
  195. Serial.print("DEBUG: Frame print: ");
  196. Serial.println(temp);
  197. }
  198.  
  199. void print_all_frames() {
  200. for (int i = 0; i < BUFFER_SZ; i++) {
  201. Serial.print("DEBUG: frame ");
  202. Serial.println(i);
  203. print_frame(framebuf.contents[i]);
  204. }
  205. }
  206. #endif
  207.  
  208. // ***I2C SECTION***
  209.  
  210. void i2c_init() {
  211. i2c_config_t conf;
  212. conf.mode = I2C_MODE_MASTER;
  213. conf.sda_io_num = I2C_SDA;
  214. conf.sda_pullup_en = GPIO_PULLUP_DISABLE;
  215. conf.scl_io_num = I2C_SCL;
  216. conf.scl_pullup_en = GPIO_PULLUP_DISABLE;
  217. conf.master.clk_speed = 100000;
  218.  
  219. i2c_param_config(I2C_NUM_1, &conf);
  220. i2c_driver_install(I2C_NUM_1, conf.mode, 0, 0, 0);
  221. }
  222.  
  223. // write len bytes from *dat to dev
  224. esp_err_t i2c_write(uint8_t dev, uint8_t *dat, size_t len) {
  225. i2c_cmd_handle_t i2c_h = i2c_cmd_link_create();
  226.  
  227. i2c_master_start(i2c_h);
  228. i2c_master_write_byte(i2c_h, (dev << 1) | I2C_MASTER_WRITE, true);
  229. i2c_master_write(i2c_h, dat, len, true);
  230. i2c_master_stop(i2c_h);
  231.  
  232. esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_1, i2c_h, (1000 / portTICK_RATE_MS));
  233. i2c_cmd_link_delete(i2c_h);
  234.  
  235. return ret;
  236. }
  237.  
  238. // read len bytes from dev's reg into *dat
  239. esp_err_t i2c_read(uint8_t dev, uint8_t reg, uint8_t *dat, size_t len) {
  240. i2c_write(dev, &reg, 1); //set register
  241.  
  242. i2c_cmd_handle_t i2c_h = i2c_cmd_link_create();
  243.  
  244. i2c_master_start(i2c_h);
  245. i2c_master_write_byte(i2c_h, (dev << 1) | I2C_MASTER_READ, true);
  246. i2c_master_read(i2c_h, dat, len, I2C_MASTER_ACK);
  247. i2c_master_stop(i2c_h);
  248.  
  249. esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_1, i2c_h, (1000 / portTICK_RATE_MS));
  250. i2c_cmd_link_delete(i2c_h);
  251.  
  252. return ret;
  253. }
  254.  
  255. void drv_init(uint8_t id) {
  256. uint8_t curr_mode;
  257. uint8_t cmd[2];
  258.  
  259. // reset
  260. cmd[0] = DRV_MODE;
  261. cmd[1] = DRV_RESTART;
  262. i2c_write(id, cmd, 2);
  263. delay(10);
  264.  
  265. // shut off driver
  266. i2c_read(id, DRV_MODE, &curr_mode, 1);
  267. cmd[0] = DRV_MODE;
  268. cmd[1] = (curr_mode & ~DRV_RESTART) | DRV_SLEEP;
  269. i2c_write(id, cmd, 2);
  270.  
  271. // set prescale
  272. cmd[0] = DRV_PRESCALE;
  273. cmd[1] = (uint8_t)DRV_PRESCALE_VAL;
  274. i2c_write(id, cmd, 2);
  275.  
  276. // restart driver
  277. cmd[0] = DRV_MODE;
  278. cmd[1] = curr_mode | DRV_RESTART | 0x20;
  279. i2c_write(id, cmd, 2);
  280. delay(10);
  281. }
  282.  
  283. void drv_write(uint8_t id, uint8_t pin, uint16_t amt) {
  284. uint8_t dat[5];
  285. dat[0] = DRV_ON_PTR + (4 * pin); // pin register pointer
  286. dat[1] = 0x00; // start pos = 0
  287. dat[2] = 0x00;
  288. dat[3] = amt; // end pos high
  289. dat[4] = amt >> 8; // end pos low
  290. i2c_write(id, dat, 5);
  291. }
  292.  
  293. // ***SERVO CONTROL SECTION***
  294.  
  295. // dat = charstream from POST request/buffer
  296. // index = command location in stream
  297. // command format: [index][flag][posn_high][posn_low][vel_high][vel_low]
  298. servo_command_t get_servo_command(char *dat, size_t index) {
  299. size_t posn = (index * 6);
  300.  
  301. uint8_t servo_index = dat[posn];
  302. uint8_t servo_flags = dat[1 + posn];
  303. uint16_t pos = ((uint16_t)dat[2 + posn] << 8) | ((uint16_t)dat[3 + posn]);
  304. uint16_t vel = ((uint16_t)dat[4 + posn] << 8) | ((uint16_t)dat[5 + posn]);
  305.  
  306. servo_command_t cmd;
  307. cmd.id = servo_index;
  308. cmd.flags = servo_flags;
  309. cmd.position = pos;
  310. cmd.velocity = vel;
  311.  
  312. return cmd;
  313. }
  314.  
  315. // takes a desired servo move and sets all the
  316. // vars as necessary - call this to move a servo
  317. void set_servo(servo_command_t cmd) {
  318. servos[cmd.id].driver_id = cmd.id;
  319. servos[cmd.id].last_pos = servos[cmd.id].real_pos; // save current position
  320. servos[cmd.id].goal_pos = cmd.position;
  321.  
  322. switch (cmd.flags) {
  323. case 254: // disable
  324. servos[cmd.id].moving = false;
  325. case 255: // skip
  326. return;
  327. break;
  328. }
  329.  
  330. // record start time and set velocity
  331. servos[cmd.id].cycle_start = millis();
  332. uint32_t pos_delta = abs(servos[cmd.id].goal_pos - servos[cmd.id].last_pos);
  333.  
  334. if (pos_delta != 0 && cmd.velocity != 0) {
  335. servos[cmd.id].cycle_dur = ((pos_delta * 1000) / cmd.velocity);
  336. servos[cmd.id].moving = true;
  337. }
  338. else {
  339. servos[cmd.id].moving = false;
  340. }
  341. }
  342.  
  343. uint16_t set_from_degrees(uint8_t id, uint16_t deg, uint8_t scale) {
  344. //TODO: using random min/max values, provide a way to calibrate
  345. uint8_t driver = id ? SVDRIVER2 : SVDRIVER1;
  346. uint8_t hw_pin = id % 16; // select second driver if needed
  347. uint16_t pwm_on_time = map((deg / scale), 0, 180, 205, 410); // 1/20 to 2/20 pwm
  348. drv_write(driver, hw_pin, pwm_on_time);
  349. }
  350.  
  351. // play back a frame
  352. void set_servos_from_frame(char *frame, size_t frame_len) {
  353. #ifdef DEBUG2
  354. print_all_frames();
  355. Serial.print("DEBUG: setting frame: ");
  356. print_frame(frame);
  357. #endif
  358. for (int i = 0; i < frame_len / 6; i++) {
  359. servo_command_t cmd = get_servo_command(frame, i);
  360. if (!cmd.flags)
  361. break;
  362. #ifdef DEBUG2
  363. Serial.print("DEBUG: setting servo ");
  364. Serial.print(cmd.id);
  365. Serial.print(" with position ");
  366. Serial.print(cmd.position);
  367. Serial.print(" velocity ");
  368. Serial.print(cmd.velocity);
  369. Serial.print(" flags ");
  370. Serial.println(cmd.flags);
  371. #endif
  372. set_servo(cmd);
  373. }
  374. memset(frame, 0, FRAME_SZ);
  375. }
  376.  
  377. void update_servos() {
  378. // check for unhandled frame pulses
  379. if (frames_to_play) {
  380. char frame[FRAME_SZ];
  381.  
  382. if (buffer_get(frame) == BUFFER_EMPTY) {
  383. #ifdef DEBUG2
  384. Serial.println("DEBUG: Frame requested but no frame in buffer");
  385. #endif
  386. }
  387. else {
  388. set_servos_from_frame(frame, FRAME_SZ);
  389. #ifdef DEBUG2
  390. Serial.print("DEBUG: ");
  391. Serial.print(framebuf.items);
  392. Serial.println(" left in buffer.");
  393. #endif
  394. }
  395. frames_to_play--;
  396. }
  397.  
  398. // update actual servo positions based on set timers
  399. for (int i = 0; i < SERVO_COUNT; i++) {
  400. if (servos[i].cycle_dur != 0) {
  401. unsigned long time_from_move_start = millis() - servos[i].cycle_start;
  402.  
  403. if (servos[i].moving) {
  404. servos[i].real_pos = map(
  405. time_from_move_start,
  406. 0,
  407. servos[i].cycle_dur - 1,
  408. servos[i].last_pos,
  409. servos[i].goal_pos);
  410.  
  411. set_from_degrees(servos[i].driver_id, servos[i].real_pos, 1);
  412. }
  413.  
  414. if (time_from_move_start >= servos[i].cycle_dur) {
  415. servos[i].moving = false;
  416. servos[i].last_pos = servos[i].real_pos;
  417. servos[i].real_pos = servos[i].goal_pos;
  418. set_from_degrees(servos[i].driver_id, servos[i].real_pos, 1);
  419. }
  420. }
  421. }
  422. }
  423.  
  424. // ***WEBSERVER SECTION***
  425.  
  426. //TODO: this will call set_servo/set_servos_from_cmds
  427. // from esp-idf example code
  428. esp_err_t servo_req_handler(httpd_req_t *req) {
  429. char content[FRAME_SZ];
  430. char res_text[64];
  431.  
  432. /* Truncate if content length larger than the buffer */
  433. memset(content, 0, FRAME_SZ);
  434. size_t recv_size = min(req->content_len, sizeof(content));
  435.  
  436. int ret = httpd_req_recv(req, content, recv_size);
  437. if (ret <= 0) { /* 0 return value indicates connection closed */
  438. /* Check if timeout occurred */
  439. if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
  440. /* In case of timeout one can choose to retry calling
  441. * httpd_req_recv(), but to keep it simple, here we
  442. * respond with an HTTP 408 (Request Timeout) error */
  443. httpd_resp_send_408(req);
  444. }
  445. /* In case of error, returning ESP_FAIL will
  446. * ensure that the underlying socket is closed */
  447. return ESP_FAIL;
  448. }
  449.  
  450. #ifdef DEBUG2
  451. Serial.println("DEBUG: received message");
  452. Serial.println(content);
  453. Serial.println(recv_size);
  454. #endif
  455.  
  456. // data received multiple of frame len - frame input
  457. if (!(recv_size % 6)) {
  458. if (buffer_add(content) == BUFFER_FULL)
  459. sprintf(res_text, "E: buffer full");
  460. else
  461. sprintf(res_text, "OK");
  462. }
  463. else if (recv_size < 6) {
  464. if (content[0] == 0xFF)
  465. frames_to_play++;
  466.  
  467. sprintf(res_text, "TODO: cmds here");
  468. }
  469. else {
  470. sprintf(res_text, "E: bad input");
  471. }
  472.  
  473. sprintf(res_text + strlen(res_text), "buffer status: %d / %d", framebuf.items, BUFFER_SZ);
  474. httpd_resp_send(req, res_text, strlen(res_text));
  475. #ifdef DEBUG2
  476. Serial.println(res_text);
  477. print_all_frames();
  478. #endif
  479. return ESP_OK;
  480. }
  481.  
  482. void IRAM_ATTR on_adv_pulse(void* arg) {
  483. frames_to_play++;
  484. }
  485.  
  486. // camera server code from RandomNerdTutorials
  487. //TODO:
  488. static esp_err_t stream_handler(httpd_req_t *req){
  489. camera_fb_t * fb = NULL;
  490. esp_err_t res = ESP_OK;
  491. size_t _jpg_buf_len = 0;
  492. uint8_t * _jpg_buf = NULL;
  493. char * part_buf[64];
  494.  
  495. res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
  496. if(res != ESP_OK){
  497. return res;
  498. }
  499.  
  500. while(true){
  501. fb = esp_camera_fb_get();
  502. if (!fb) {
  503. Serial.println("Camera capture failed");
  504. res = ESP_FAIL;
  505. } else {
  506. if(fb->width > 400){
  507. if(fb->format != PIXFORMAT_JPEG){
  508. bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
  509. esp_camera_fb_return(fb);
  510. fb = NULL;
  511. if(!jpeg_converted){
  512. Serial.println("JPEG compression failed");
  513. res = ESP_FAIL;
  514. }
  515. } else {
  516. _jpg_buf_len = fb->len;
  517. _jpg_buf = fb->buf;
  518. }
  519. }
  520. }
  521. if(res == ESP_OK){
  522. size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
  523. res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
  524. }
  525. if(res == ESP_OK){
  526. res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
  527. }
  528. if(res == ESP_OK){
  529. res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
  530. }
  531. if(fb){
  532. esp_camera_fb_return(fb);
  533. fb = NULL;
  534. _jpg_buf = NULL;
  535. } else if(_jpg_buf){
  536. free(_jpg_buf);
  537. _jpg_buf = NULL;
  538. }
  539. if(res != ESP_OK){
  540. break;
  541. }
  542. }
  543. return res;
  544. }
  545.  
  546. void startCameraServer() {
  547. httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  548. config.server_port = 80;
  549.  
  550. httpd_uri_t index_uri = {
  551. .uri = "/",
  552. .method = HTTP_GET,
  553. .handler = stream_handler,
  554. .user_ctx = NULL
  555. };
  556.  
  557. httpd_uri_t servo_uri = {
  558. .uri = "/sv",
  559. .method = HTTP_POST,
  560. .handler = servo_req_handler,
  561. .user_ctx = NULL
  562. };
  563.  
  564. //Serial.printf("Starting web server on port: '%d'\n", config.server_port);
  565. if (httpd_start(&stream_httpd, &config) == ESP_OK) {
  566. httpd_register_uri_handler(stream_httpd, &index_uri);
  567. httpd_register_uri_handler(stream_httpd, &servo_uri);
  568. }
  569. }
  570.  
  571. void setup() {
  572. WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
  573.  
  574. Serial.begin(115200);
  575. Serial.setDebugOutput(false);
  576.  
  577. camera_config_t config;
  578. config.ledc_channel = LEDC_CHANNEL_0;
  579. config.ledc_timer = LEDC_TIMER_0;
  580. config.pin_d0 = Y2_GPIO_NUM;
  581. config.pin_d1 = Y3_GPIO_NUM;
  582. config.pin_d2 = Y4_GPIO_NUM;
  583. config.pin_d3 = Y5_GPIO_NUM;
  584. config.pin_d4 = Y6_GPIO_NUM;
  585. config.pin_d5 = Y7_GPIO_NUM;
  586. config.pin_d6 = Y8_GPIO_NUM;
  587. config.pin_d7 = Y9_GPIO_NUM;
  588. config.pin_xclk = XCLK_GPIO_NUM;
  589. config.pin_pclk = PCLK_GPIO_NUM;
  590. config.pin_vsync = VSYNC_GPIO_NUM;
  591. config.pin_href = HREF_GPIO_NUM;
  592. config.pin_sscb_sda = SIOD_GPIO_NUM;
  593. config.pin_sscb_scl = SIOC_GPIO_NUM;
  594. config.pin_pwdn = PWDN_GPIO_NUM;
  595. config.pin_reset = RESET_GPIO_NUM;
  596. config.xclk_freq_hz = 20000000;
  597. config.pixel_format = PIXFORMAT_JPEG;
  598.  
  599. if (psramFound()) {
  600. config.frame_size = FRAMESIZE_UXGA;
  601. config.jpeg_quality = 10;
  602. config.fb_count = 2;
  603. } else {
  604. config.frame_size = FRAMESIZE_SVGA;
  605. config.jpeg_quality = 12;
  606. config.fb_count = 1;
  607. }
  608.  
  609. // Camera init
  610. esp_err_t err = esp_camera_init(&config);
  611. if (err != ESP_OK) {
  612. Serial.printf("Camera init failed with error 0x%x", err);
  613. return;
  614. }
  615. // Connect to Wi-Fi network with SSID and password
  616. Serial.print("Setting AP (Access Point)…");
  617. // Remove the password parameter, if you want the AP (Access Point) to be open
  618. WiFi.softAP(ssid, password);
  619.  
  620. IPAddress IP = WiFi.softAPIP();
  621. Serial.print("Camera Stream Ready! Connect to the ESP32 AP and go to: http://");
  622. Serial.println(IP);
  623.  
  624. // Start streaming web server
  625. startCameraServer();
  626.  
  627. buffer_init();
  628. i2c_init();
  629. drv_init(SVDRIVER1);
  630.  
  631. gpio_set_intr_type(GPIO_NUM_2, GPIO_INTR_POSEDGE);
  632. gpio_install_isr_service(0);
  633. gpio_isr_handler_add(GPIO_NUM_2, on_adv_pulse, NULL);
  634.  
  635. #ifdef DEBUG2
  636. print_all_frames();
  637. #endif
  638. }
  639.  
  640. void loop() {
  641. delay(1);
  642. update_servos();
  643. }
  644.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement