Networking and Communications

Individual Assignment

1. I created a wired node with a network and a local interface to take a photo and display it on the web.

This week I decided to use the ESP32-CAM, a microcontroller that would allow me to take a photo. The task for this week was to establish a network between the device and a local interface, so I knew I needed to transfer the photo to my computer. With Shonit, I mapped out what would be needed in this information transfer: a node, a network, and a local interface (Fig. 1A).



Fig. 1A. Shonit's Map of information transfer.



We then further discussed that with node being the ESP32-CAM and the local interface being a program on my computer, we need to connect the node with the local interface by way of the network: IP address.

In Prof. Gershenfeld's example, he used a FTDI connector to bridge the universal asynchronous receiver/transmitter (UART) on the programmer board to a USB to be connected to the computer (Fig. 1B). FTDI connector can be found on the right side of the PCB Design layout.

Fig. 1B. Prof. Gershenfeld's programmer board.

I I was preparing to design my own PCB layout similar to Neil's board. However, I could not find the FTDI component from the Architecture Shop and decided to just use with the ESP32-CAM-MB USB Programmer, which is basically a manufactured version of what I was going to make.

Fig. 1C. Assembled ESP32-CAM-MB and ESP32-CAM

I followed through this online tutorial, to create a local interface that enabled me to take a picture with the ESP32-CAM (Fig. 1C).
The example code from the website below:

              
                #include "WiFi.h"
                #include "esp_camera.h"
                #include "esp_timer.h"
                #include "img_converters.h"
                #include "Arduino.h"
                #include "soc/soc.h"           // Disable brownour problems
                #include "soc/rtc_cntl_reg.h"  // Disable brownour problems
                #include "driver/rtc_io.h"
                #include 
                #include 
                #include 
                #include 
                
                // Replace with your network credentials
                const char* ssid = "REPLACE_WITH_YOUR_SSID";
                const char* password = "REPLACE_WITH_YOUR_PASSWORD";
                
                // Create AsyncWebServer object on port 80
                AsyncWebServer server(80);
                
                boolean takeNewPhoto = false;
                
                // Photo File Name to save in SPIFFS
                #define FILE_PHOTO "/photo.jpg"
                
                // OV2640 camera module pins (CAMERA_MODEL_AI_THINKER)
                #define PWDN_GPIO_NUM     32
                #define RESET_GPIO_NUM    -1
                #define XCLK_GPIO_NUM      0
                #define SIOD_GPIO_NUM     26
                #define SIOC_GPIO_NUM     27
                #define Y9_GPIO_NUM       35
                #define Y8_GPIO_NUM       34
                #define Y7_GPIO_NUM       39
                #define Y6_GPIO_NUM       36
                #define Y5_GPIO_NUM       21
                #define Y4_GPIO_NUM       19
                #define Y3_GPIO_NUM       18
                #define Y2_GPIO_NUM        5
                #define VSYNC_GPIO_NUM    25
                #define HREF_GPIO_NUM     23
                #define PCLK_GPIO_NUM     22
                
                const char index_html[] PROGMEM = R"rawliteral(
                
                
                
                )rawliteral";
                
                void setup() {
                  // Serial port for debugging purposes
                  Serial.begin(115200);
                
                  // Connect to Wi-Fi
                  WiFi.begin(ssid, password);
                  while (WiFi.status() != WL_CONNECTED) {
                    delay(1000);
                    Serial.println("Connecting to WiFi...");
                  }
                  if (!SPIFFS.begin(true)) {
                    Serial.println("An Error has occurred while mounting SPIFFS");
                    ESP.restart();
                  }
                  else {
                    delay(500);
                    Serial.println("SPIFFS mounted successfully");
                  }
                
                  // Print ESP32 Local IP Address
                  Serial.print("IP Address: http://");
                  Serial.println(WiFi.localIP());
                
                  // Turn-off the 'brownout detector'
                  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
                
                  // OV2640 camera module
                  camera_config_t config;
                  config.ledc_channel = LEDC_CHANNEL_0;
                  config.ledc_timer = LEDC_TIMER_0;
                  config.pin_d0 = Y2_GPIO_NUM;
                  config.pin_d1 = Y3_GPIO_NUM;
                  config.pin_d2 = Y4_GPIO_NUM;
                  config.pin_d3 = Y5_GPIO_NUM;
                  config.pin_d4 = Y6_GPIO_NUM;
                  config.pin_d5 = Y7_GPIO_NUM;
                  config.pin_d6 = Y8_GPIO_NUM;
                  config.pin_d7 = Y9_GPIO_NUM;
                  config.pin_xclk = XCLK_GPIO_NUM;
                  config.pin_pclk = PCLK_GPIO_NUM;
                  config.pin_vsync = VSYNC_GPIO_NUM;
                  config.pin_href = HREF_GPIO_NUM;
                  config.pin_sscb_sda = SIOD_GPIO_NUM;
                  config.pin_sscb_scl = SIOC_GPIO_NUM;
                  config.pin_pwdn = PWDN_GPIO_NUM;
                  config.pin_reset = RESET_GPIO_NUM;
                  config.xclk_freq_hz = 20000000;
                  config.pixel_format = PIXFORMAT_JPEG;
                
                  if (psramFound()) {
                    config.frame_size = FRAMESIZE_UXGA;
                    config.jpeg_quality = 10;
                    config.fb_count = 2;
                  } else {
                    config.frame_size = FRAMESIZE_SVGA;
                    config.jpeg_quality = 12;
                    config.fb_count = 1;
                  }
                  // Camera init
                  esp_err_t err = esp_camera_init(&config);
                  if (err != ESP_OK) {
                    Serial.printf("Camera init failed with error 0x%x", err);
                    ESP.restart();
                  }
                
                  // Route for root / web page
                  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
                    request->send_P(200, "text/html", index_html);
                  });
                
                  server.on("/capture", HTTP_GET, [](AsyncWebServerRequest * request) {
                    takeNewPhoto = true;
                    request->send_P(200, "text/plain", "Taking Photo");
                  });
                
                  server.on("/saved-photo", HTTP_GET, [](AsyncWebServerRequest * request) {
                    request->send(SPIFFS, FILE_PHOTO, "image/jpg", false);
                  });
                
                  // Start server
                  server.begin();
                
                }
                
                void loop() {
                  if (takeNewPhoto) {
                    capturePhotoSaveSpiffs();
                    takeNewPhoto = false;
                  }
                  delay(1);
                }
                
                // Check if photo capture was successful
                bool checkPhoto( fs::FS &fs ) {
                  File f_pic = fs.open( FILE_PHOTO );
                  unsigned int pic_sz = f_pic.size();
                  return ( pic_sz > 100 );
                }
                
                // Capture Photo and Save it to SPIFFS
                void capturePhotoSaveSpiffs( void ) {
                  camera_fb_t * fb = NULL; // pointer
                  bool ok = 0; // Boolean indicating if the picture has been taken correctly
                
                  do {
                    // Take a photo with the camera
                    Serial.println("Taking a photo...");
                
                    fb = esp_camera_fb_get();
                    if (!fb) {
                      Serial.println("Camera capture failed");
                      return;
                    }
                
                    // Photo file name
                    Serial.printf("Picture file name: %s\n", FILE_PHOTO);
                    File file = SPIFFS.open(FILE_PHOTO, FILE_WRITE);
                
                    // Insert the data in the photo file
                    if (!file) {
                      Serial.println("Failed to open file in writing mode");
                    }
                    else {
                      file.write(fb->buf, fb->len); // payload (image), payload length
                      Serial.print("The picture has been saved in ");
                      Serial.print(FILE_PHOTO);
                      Serial.print(" - Size: ");
                      Serial.print(file.size());
                      Serial.println(" bytes");
                    }
                    // Close the file
                    file.close();
                    esp_camera_fb_return(fb);
                
                    // check if file has been correctly saved in SPIFFS
                    ok = checkPhoto(SPIFFS);
                  } while ( !ok );
                }    
              
            


Fig. 1D. Error Message

Unfortunatly, I kept getting error message through the serial monitor. (Fig. 1D) I ended up spending a couple hours troubleshooting it but it was not successful.
Eventually, the issue was only resolved by switching to a new board...

Fig. 1E. Photo capture test. Success!

Through the network I was able to load the picture I took with the device in the local interface, as well as rotate it to view it properly (Fig. 1E). Looking at the photo quality, I feel very much transported back into the early-mid 2000s...

Fig. 1F Xiao ESP32S3 SENSE

Afterwards, I acquired a Xiao ESP32S3 SENSE, which comes with the micro-USB component. I thought this one will enable me to finally mill my PCB board for this.

Fig. 1G. Error Message

However, upon testing an example code, I kept getting this strange error which I could not resolve...

I looked up the error and found this webpage which has some hopeful comments. I will try to fix this. I will share a further update after troubleshooting it.