Introduction: Kodak Brownie Digital Camera - WiFi & SD Card Compatible

About: Just another tinkerer



Hello fellow makers,



If you've ever wanted a unique way to capture those special moments, a stylish dedicated webcam or even an unassuming wireless security camera this is the Instructable you've been looking for.



Recently I have seen in increase of these old Kodak Brownie box style for sale locally, most are dirt cheap and I have even come across some at the metal recycling centres!

As I'm always trying to save as many antique pieces as humanly possible, I wanted to come up with a way to return the usefulness of these beauties.



This gave me the chance to finally have a go at a project using the incredible little ESP32-CAM boards that are all setup with a mighty little 2MP sensor.



If you enjoy my Instructables and would like to support my future projects you can Buy Me A Coffee.



Let's get making...

Supplies

To make your own you will need the following:





Step 1: The History of the Brownie Camera:

The Brownie was a series of camera models made by Eastman Kodak. Released in 1900.


It introduced the snapshot to the masses by addressing the cost factor which had meant that amateur photography remained beyond the means of many people the Pocket Kodak for example would cost most families in Britain nearly a whole month's wages.


The Brownie was a basic cardboard box camera with a simple convex-concave lens that took 2 1/4-inch square pictures on No. 117 roll film. It was conceived and marketed for sales of Kodak roll films. Because of its simple controls and initial price of US$1 (equivalent to $35 in 2022) along with the low price of Kodak roll film and processing, the Brownie camera surpassed its marketing goal.


Initially marketed to children, with Kodak using them to popularise photography, it achieved broader appeal as people realised that although very simple in design and operation, the Brownie could produce very good results under the right conditions.


As they were ubiquitous, many iconic shots were taken on Brownies on 15 April 1912, Bernice Palmer used a Kodak Brownie 2A, Model A to photograph the iceberg that sank RMS Titanic as well as survivors hauled aboard RMS Carpathia, the ship on which Palmer was travelling. They were also taken to war by soldiers but by World War I the more compact Kodak Vest Pocket Camera as well as Kodak’s Autographic Camera were the most frequently used.


Source: Wikipedia

Step 2: Disassembling the Brownie:

First we are going to need to disassemble our old Brownie for a much deserved clean and to get rid of any unnecessary parts.


Starting with the front panel you simply pull it off like a lid, if your camera has a bit of rust this might make it more difficult but you can use something like the handle of a screwdriver to tap around the edge in order to loosen its grip a bit.

I would advise against the use of any rust lubricants as it might end up damaging the vinyl.


With the front panel off we can remove the shutter mechanism next, you'll notice that there's some small slits on the edges of the shutter plate this corresponds to some protrusions on the camera body. We simply need to pry the shutter away from the camera body in order for it to release and slide out.



Now all the rest of the parts are simply held to the body by bent over tabs, using a small flat screwdriver we can simply bend the tabs straight and the parts will pop out.


Be careful when opening up the tabs not to over bend them as they can break off when bent too many times.



As seen on the picture above the lens assembly is held in place by 3 little dimples that need to be pressed flat in order to disassemble. I used a small sharp punch positioned on top of the bump and pressed it down on a piece of rubber with some force until it was flush.


The lens consists of 5 pieces, the glass lens, two metal retaining rings and two spacers.


Step 3: Tidy Up the Brownie:

With the camera disassembled we need to give it a deep clean!


Usually I like fully restoring antiques but with this camera I feel like all the imperfections tell its story and I want to preserve that.


As you can see in the picture above my poor camera was unfortunately exposed to the elements in its life and has gotten some minor rust. By accident I discovered a great way I use to deep clean things like this whist also preserving their beauty.


You will simply need some brushes and rubbing compound, not polishing compound but rubbing compound. What's the difference?, well unlike the white chalky polish this one is a very oily gritty compound.



On the metal parts I used a brass bristle brush in my Dremel along with the rubbing compound on medium speed and a nylon bristle brush on the vinyl with the rubbing compound on a slower speed setting. This lifts away the grime like a dream and retains the antique look on the metal parts.



After cleaning off the leftover rubbing compound from the parts with a damp cloth I used some good old black shoe polish and wiped down the vinyl parts and leather handle.



Step 4: Design and Print the New Internals:

I designed all of the components needed to convert the camera using Fusion 360, the measurements used for the parts were from the Brownie Model 1 as seen in this Instructable but I have a Brownie six-20 as well and they are identical on the inside and the parts fit without any modifications needed.


Comparing the different models online it looks like the parts will fit in most models with the same form factor without any major modifications needed.


The back assembly holds all of our electronic boards and is designed so that all the modules simply slide or press into their respective slots and are held in place by the friction.

The front assembly houses our image sensor and is made to have adjustment to centre the sensor onto the original Brownie lens as well as a height adjustment to keep the OV2640 lens from colliding with the Brownie lens after focusing.

Brownie Camera

Step 5: Modify the OV2640

Because there is such a massive amount of M12 lenses (the ones used by arducam and on your cctv cameras) available from fisheye, colored optics, switchable IR etc. I decided to remove the original mount and upgrade it to the universal M12 mounting base.


From the factory they add glue to the threads of the lens after focusing to prevent it from unintentional turning. We will need to break this seal, there are two ways to do this depending on the type of adhesive they used.

If a soft adhesive similar to contact adhesive is used you can use a sharp knife to scrape away as much of the glue off the threads as possible then using some small pliers start unscrewing the lens making sure to support the base as you turn.

On both of my modules they used a hard epoxy like glue that I could simply squeeze a little with the pliers and it broke loose.


OOPS!...

I decided to also remove the original base around the sensor as well and whilst taking it off I bumped off a capacitor next to the sensor that required some MICRO soldering to reattach. If you are afraid of doing the same I recommend you use a sharp hobby knife to cut away the original protruding thread on the base instead of removing the entire thing.


Optional:

Next we need to extend the 24w FFC cable

This is necessary but the step is optional as you can buy premade cable extenders or an OV2640 module with a longer cable.


Because I had none of the extenders or modules available locally I had to find a DIY solution, I was lucky to find a 24w cable out of an old DVD player that I could reuse.


You need a 24 way 0.5mm pitch FFC cable.


I cut the cable aproximatly 100mm long and cleaned off the covering from the cut end to reveal the copper traces, the end was then aligned with the camera modules connector and soldered together.

I covered the solder point with some kapton tape and copper tape to stiffen the joint.



After the cable was done I adhered the image sensor onto the square block on the "Sensor Holder.stl" with the cable through the slit.


Make sure your sensor is clean and dust free.


The M12 base is then attached over the sensor using 2.5mm screws.

The screws of the base has been countersunk so that a 2.5mm heatset insert can be added on top of it in order to attach it to the sensor slide.


After finishing with the base I sealed around the base and cable using B6000 glue to ensure that no dust can get in afterwards.

Step 6: Lens Customization:

The M12 lenses that i'm using in this project is salvaged from some old broken CCTV cameras and have their IR filters mounted on the image sensor as oppose to the lens so I had to glue a IR filter onto one of the lenses with some CA glue.


But this also means I can swap out the lens with the one without the IR filter and have a great little low light night time camera!

Step 7: Coding:

The following is two examples that can be used on the ESP32-CAM.


This code is for a basic digital camera built as is how I have the camera configured in this Instructable.


The ESP32 module is constantly in "Deep sleep" mode until the reset button is pressed that then wakes it up, it takes a picture, saves it onto the SD card and goes back into deep sleep until the button is pressed again.


// Digital Camera Code

#include "esp_camera.h"
#include "Arduino.h"
#include "FS.h"                // SD Card ESP32
#include "SD_MMC.h"            // SD Card ESP32
#include "soc/soc.h"           // Disable brownour problems
#include "soc/rtc_cntl_reg.h"  // Disable brownour problems
#include "driver/rtc_io.h"
#include <EEPROM.h>            // read and write from flash memory


// define the number of bytes you want to access
#define EEPROM_SIZE 1


// Pin definition for 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


int pictureNumber = 0;


void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector

  Serial.begin(115200);
  //Serial.setDebugOutput(true);
  //Serial.println();

  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; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

  // Init Camera
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }






  //Serial.println("Starting SD Card");
  if(!SD_MMC.begin()){
    Serial.println("SD Card Mount Failed");
    return;
  }

  uint8_t cardType = SD_MMC.cardType();
  if(cardType == CARD_NONE){
    Serial.println("No SD Card attached");
    return;
  }

  camera_fb_t * fb = NULL;

  // Take Picture with Camera
  fb = esp_camera_fb_get();  
  if(!fb) {
    Serial.println("Camera capture failed");
    return;
  }
  // initialize EEPROM with predefined size
  EEPROM.begin(EEPROM_SIZE);
  pictureNumber = EEPROM.read(0) + 1;


  // Path where new picture will be saved in SD Card
  String path = "/picture" + String(pictureNumber) +".jpg";


  fs::FS &fs = SD_MMC; 
  Serial.printf("Picture file name: %s\n", path.c_str());

  File file = fs.open(path.c_str(), FILE_WRITE);
  if(!file){
    Serial.println("Failed to open file in writing mode");
  } 
  else {
    file.write(fb->buf, fb->len); // payload (image), payload length
    Serial.printf("Saved file to path: %s\n", path.c_str());
    EEPROM.write(0, pictureNumber);
    EEPROM.commit();
  }
  file.close();
  esp_camera_fb_return(fb); 

  // Turns off the ESP32-CAM white on-board LED (flash) connected to GPIO 4
  pinMode(4, OUTPUT);
  digitalWrite(4, LOW);
  rtc_gpio_hold_en(GPIO_NUM_4);

  delay(2000);
  Serial.println("Going to sleep now");
  delay(2000);
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}


void loop() {

}

(*I'm working on a tinting issue with the code above otherwise it works perfectly)



Next up we have the web server that is included in the examples on the Arduino IDE, the ESP32 connects to the specified WiFi network and can then be accessed via its IP address where you can stream the feed and take still pictures from your browser.


Remember to change the SSID and password in the code to yours.


#include "esp_camera.h"
#include <WiFi.h>


//
// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
//            Ensure ESP32 Wrover Module or other board with PSRAM is selected
//            Partial images will be transmitted if image exceeds buffer size
//
//            You must select partition scheme from the board menu that has at least 3MB APP space.
//            Face Recognition is DISABLED for ESP32 and ESP32-S2, because it takes up from 15 
//            seconds to process single frame. Face Detection is ENABLED if PSRAM is enabled as well


// ===================
// Select camera model
// ===================
//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
#define CAMERA_MODEL_ESP_EYE // Has PSRAM
//#define CAMERA_MODEL_ESP32S3_EYE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
//#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM
//#define CAMERA_MODEL_M5STACK_UNITCAM // No PSRAM
//#define CAMERA_MODEL_AI_THINKER // Has PSRAM
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM
//#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM
// ** Espressif Internal Boards **
//#define CAMERA_MODEL_ESP32_CAM_BOARD
//#define CAMERA_MODEL_ESP32S2_CAM_BOARD
//#define CAMERA_MODEL_ESP32S3_CAM_LCD


#include "camera_pins.h"


// ===========================
// Enter your WiFi credentials
// ===========================
const char* ssid = "**********";
const char* password = "**********";


void startCameraServer();
void setupLedFlash(int pin);


void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println();


  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_sccb_sda = SIOD_GPIO_NUM;
  config.pin_sccb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.frame_size = FRAMESIZE_UXGA;
  config.pixel_format = PIXFORMAT_JPEG; // for streaming
  //config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition
  config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  config.fb_location = CAMERA_FB_IN_PSRAM;
  config.jpeg_quality = 12;
  config.fb_count = 1;

  // if PSRAM IC present, init with UXGA resolution and higher JPEG quality
  //                      for larger pre-allocated frame buffer.
  if(config.pixel_format == PIXFORMAT_JPEG){
    if(psramFound()){
      config.jpeg_quality = 10;
      config.fb_count = 2;
      config.grab_mode = CAMERA_GRAB_LATEST;
    } else {
      // Limit the frame size when PSRAM is not available
      config.frame_size = FRAMESIZE_SVGA;
      config.fb_location = CAMERA_FB_IN_DRAM;
    }
  } else {
    // Best option for face detection/recognition
    config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
    config.fb_count = 2;
#endif
  }


#if defined(CAMERA_MODEL_ESP_EYE)
  pinMode(13, INPUT_PULLUP);
  pinMode(14, INPUT_PULLUP);
#endif


  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }


  sensor_t * s = esp_camera_sensor_get();
  // initial sensors are flipped vertically and colors are a bit saturated
  if (s->id.PID == OV3660_PID) {
    s->set_vflip(s, 1); // flip it back
    s->set_brightness(s, 1); // up the brightness just a bit
    s->set_saturation(s, -2); // lower the saturation
  }
  // drop down frame size for higher initial frame rate
  if(config.pixel_format == PIXFORMAT_JPEG){
    s->set_framesize(s, FRAMESIZE_QVGA);
  }


#if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM)
  s->set_vflip(s, 1);
  s->set_hmirror(s, 1);
#endif


#if defined(CAMERA_MODEL_ESP32S3_EYE)
  s->set_vflip(s, 1);
#endif


// Setup LED FLash if LED pin is defined in camera_pins.h
#if defined(LED_GPIO_NUM)
  setupLedFlash(LED_GPIO_NUM);
#endif


  WiFi.begin(ssid, password);
  WiFi.setSleep(false);


  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");


  startCameraServer();


  Serial.print("Camera Ready! Use 'http://");
  Serial.print(WiFi.localIP());
  Serial.println("' to connect");
}


void loop() {
  // Do nothing. Everything is done in another task by the web server
  delay(10000);
}

Step 8: Modify the ESP32-CAM Board:

If you are going to be using the "Digital Camera Code" from the previous step you'll need to make some minor modifications to the ESP32 board.


First because we need to press the reset button to wake the module we will need to relocate it, luckily we will not reuse the button so it can be destroyed in the process. With a hot soldering iron heat and remove the tactile switch on the module and then clean the pads, to these two pads simply solder on two wires that will be connected to our new reset button later on.



Then because we have no screen to see when the picture is taken we will need an indicator light, for this we can simply desolder the existing "Flash" LED from the board and solder in a red 5mm LED with extended legs in its place as pictured.

Step 9: Wiring the Electronics:

It's time to wire everything up.


Starting with the 18650 lithium ion battery solder on a wire to both the positive and negative size, the battery positive then gets soldered to the TP4056 boards BAT+ pad and the negative from the battery to the BAT-. This will provide the under and over voltage protection to your battery as well as charging.


Next solder a wire from the OUT+ on the TP4056 charging board to the IN+ on the boost converter (arrow side) and another from the OUT- to IN-. On the boost converter we leave both jumpers open to provide 5V output and also it's advisable to remove the onboard LED indicator jumper.

Now simply solder corresponding wires from the boost converters + and - output to the VIN and GND pins of the ESP32-CAM board. We will solder the wires onto the reset button after assembly.



After everything is soldered together we can simply slide each board into its corresponding slot as pictured above.

Step 10: Assembly:

Now for the final step...Assembly time!


We start by mounting our lens assembly in the cavity of the lens slide, the cable from the lens assembly fits through the slit in the slide and then the assembly gets screwed in with two 2.5mm bolts with washers. The slide provide some adjustability to ensure you can centre the lens.



The assembled slide then pops into the printed front assembly, two screws go into the sides of the lens assembly that can be loosened and tightened to lock the slide into place after adjusting the lens.



Now you need to reassemble all the cleaned parts we removed from the camera body in the beginning, when the camera body has all its original bits and bobs attached we can slide the entire front and back assemblies into the camera body.


I use some "Nano/magic" double sided tape at the back of the assemblies to hold them in place as it provide great adhesion that can be removed without causing any damage and also offers some vibration dampening.


A little tip is to drip some isopropyl alcohol on the tape for easy release.


With the reset button's wires fed through to the front we can also solder them to the tactile push button, you want the button to be closed when pressed.


Finally you can adjust the focus (to make this easier you should upload the "Web Server" code so that you can continuously view the stream while adjusting) by first adjusting the slide until it is nearly pressed against of the original Brownie lens when the front cover is on. Now you can adjust the lens by turning it in and out until the picture is in focus (you will be taking off the Brownies front lid a lot while focussing so it might be easier to bend the lids clips slightly open so it doesn't latch on every time).


Your digital Brownie is now ready to be used!


Step 11: Enjoy!

I hope you guys find this Instructable useful and if you have any questions please feel free to leave me a message or comment bellow.




Thank you for taking the time to read through my project and as always..


Happy making!

---


Repair and Reuse Contest

First Prize in the
Repair and Reuse Contest