Make your own automatic 35mm film scanner using an Arduino Nano and Python

Sep 28, 2020

Seckin Sinan Isik

We love it when our readers get in touch with us to share their stories. This article was contributed to DIYP by a member of our community. If you would like to contribute an article, please contact us here.

Make your own automatic 35mm film scanner using an Arduino Nano and Python

Sep 28, 2020

Seckin Sinan Isik

We love it when our readers get in touch with us to share their stories. This article was contributed to DIYP by a member of our community. If you would like to contribute an article, please contact us here.

Join the Discussion

Share on:

Getting started with Arduino Nano and Python is easy thanks to extensive online documentation and an increasing DIY culture. 

Waiting whilst flatbed scanners scan a colour negative film is nothing to be excited about. This process and the subsequent colour precorrection can take anywhere from an hour to two. Tools available today, such as Negative Lab Pro, make it easy to achieve great colour negative conversions. So fastening the scanning process using a camera makes more sense than ever before. However, the software to automate this process so far did not exist. Until today!

A typical digital camera scanning setup includes a digital camera, a tripod (or a copy stand) and a film carrier. Among the 3, I would imagine the most scarce item is the film carrier. Luckily companies such as Negative Supply started to make these much needed film carriers. But these can also be rather expensive. Luckily, any DIY film carrier made out from cardboard that is able to push and pull an uncut 135 format (35mm) film via a simple shaft system will work great. More on that later!

A bit of background. Right off the bat, I should say that I am not affiliated to Negative Supply, Capture One nor Negative Lab Pro. I happen to own their products, and I happen to like using them (for now). Before, I was operating the venerable epson V600 for scanning films. This was very nice as it enabled me to scan my own films, but the speed wasn’t there. Moreover, I was not completely enjoying the grains I was getting. Having said that, my reasons for why I decided to make this project is more multifaceted. I enjoy supporting the film community and film centric companies like Negative Supply, Lomography, and Negative Lab Pro. I also like the idea of slightly jolting the DIY community toward this niche domain. Lastly, I also really wanted to program a microcontroller for the first time. Taking up this project has thought me so many things. I admit, only a month ago, I couldn’t tell the difference between an Arduino and a Raspberry Pi.

After randomly settling down on an Arduino, mostly because of its price point, I needed to find a problem to solve.

This did NOT take very long! I first fixed my UniRoller developer issue, which was a result of using a JOBO expert tank 3010. And then I focused on automatically watering my tomato plants for the times I went on a hike. And my final and current project was to fix this issue I had with scanning films. This also gave me the excuse to practice some Python programming.

As of today, I have now completed 2 separate film scanning programs. One written in Python language, and the other one written in C++ (also referred to as an Arduino sketch). They both use the same hardware, but there are major differences in how they function. One is enabled by Python computer vision, and is fully autonomous (automated positioning, taking picture and moving to the next frame). The other only mechanizes the film progression. The user makes the necessary corrections in film position and then takes the picture using the controller buttons.

To implement this project knowing Python (C/C++ for Arduino) would be ideal, however it is not necessary for clicking the run button on a browser that runs Jupyter Notebook (found in Anaconda). That said, the user is required to download Python and 4 libraries. I highly suggest the Anaconda bundle (download Anaconda) as it is a one shop solution, with a very rich online community. After this installation, Python libraries, Numpy, pyFirmata, SciPy and cv2 are also required. You can install these Python libraries using the Anaconda-Navigator or PIP install em from the terminal. The internet is littered with how-to tutorials on this. Having said that, I have used Jupyter web interface for making and running the Python code. These programs will have an ipynb extension. However, it would be best to start by installing the Arduino IDE (download here Arduino IDE app). As this is where it all starts(Arduino scripts have a .ino extension). There will be more details on this later.

Ok, lets move on to the actual awesome Setup:

Figure 2: A) Capture One is connected to the Fufifilm X-T2 with a A-Male to Micro-B USB cable for data transfer and powering the Fujifilm X-T2 battery. B) Video Capture card, item 4 (items used are listed at the very bottom), is connected with a micro HDMI, and C) the camera shutter is controlled via a 2.5mm (3 pole) cable. The flow of information is depicted by the arrow.

Let’s see this setup in action!

Mode 1: Arduino only and using manually correcting position:

YouTube video

Mode 2: Automatic correction with Python:

YouTube video

Mode 3: Arduino plus Python in action on a DIY cardboard film carrier:


YouTube video
I made this cardboard box just under 2 hours. In order to make this an afternoon project, I’ve used the 3D printed film guides and rubber film rollers used on the Negative Supply carrier.

If Python and automation is not your cup of tea, but you still want a stepper motor to drive your film. You can also find a dedicated Arduino sketch on the Github site. I like this code as it is extremely simple to use and once uploaded to the microprocessor, using the Arduino IDE app, one would never need to see a computer script, plus it’s a tad faster. Which is really convenient. Here, the micro corrections to left and right are made using the dedicated buttons (the middle two in Figure 5). The button to the most left is the shutter release button, and the most right is to progress to the next frame. This setup should work on Fujifilm and Canon cameras. That is because the shutter release cable I once owned was Canon branded and I tried to imitate the voltage values I read from it. Please bear in mind that there are risks associated with connecting external circuitry to your camera. Please attempt this DIY setup at your own risk.

What does microcontroller do?

Firstly, the microcontroller used here is called the Arduino Nano. There are a gazillion youTube videos of DIYists using this board. Essential a microcontroller is an integrated circuit (a chip that has many many discrete electrical components) that uses discrete voltage (3.3V or 5V) in order to say yes (in computer terms equals to 1, True etc.) or 0V for saying no (0, False etc.). There is also a grey zone in between where its not good, but I don’t know the details at this time. It communicates using its pins that are located on its side. These pins can also read voltages too. Pins that read and write 1’s and 0’s are called digital pin and are denoted by D. Some of the D pins can also modulate pulse over time. This is denoted by PWM or ~. And some pins can read analog signals which are denoted by A. These are not 1’s or 0’s. They typical read a range of 0-1000 on an Arduino board, and this is how we input the desired speed of the stepper motor. The pin layout of the microcontrollers is available on the internet. So when wiring your circuit please take care of the wiring. Also, do not power your board while wiring.

Correcting film position using Python.

In order to correct the position of the film, Python requires a feedback. To do this we utilize the Video Capture Card HDMI to USB 1080p (item 4).

By perfectly positioning the film on the film carrier, maximum camera sensor resolution is achieved for every 35mm frame.

When maximum resolution is paired with a good macro lens, the grains can be a joy to look at. To active this, edges between frames are determined, and this information is used during the correction phase. This means that if we have a 24 megapixel sensor, like we do in FujiFilm X-T2, our scans will almost have a 4000 by 6000 pixels per image. To position the frame perfectly our Python program only requires a 100p resolution. Therefor, the 1080p video capture is downsized in Python. However, a full 1080p video streaming with the card would make an excellent WebCam over Skype, Zoom, etc.

The current version of the Python program will not work with colour positive films.

I have only been part-time working on this project since past August. I am hoping to update the program in the near future for colours positive film rolls. Next time I have an uncut positive film roll, I will take a weekend time to make this happen.

This is an open source project subjected to MIT open source license. Which means that it is free to distribute, change and use. In turn, the software for detecting frames could drastically get better with new and fancy algorithms over time. I highly encourage fellow Python programmers and data scientists to fork the project from my Github and showcase their talents.

I intended this page to be understood by people who are just starting off their journey into the world of microcontrollers. Thus, if you have a question or have a suggestion please don’t hesitate to share them.

Lets start making our scanning machine:


  1. Mounting the Stepper motor and making a new shaft
  2. The controller
  3. Starting with the Arduino Nano (Blue) and the Stepper Motor board (RED)
  4. The wiring
  5. Downloading from Github and getting started
  6. Items used and costs

1-Mounting the Stepper motor and making a new shaft

This part of the project is perhaps one of the most fun parts as things start to take shape. It’s the easiest part, but paradoxically the hardest part too. The crucial part to pay attention is to make sure the tension on the belt is equal during the rotation of the shaft. And that it does not pull the stepper motor, as it is mounted by a sticky silicon mounting tape (Gorilla double-sided tape). Also, word of caution, when mounting GT2 timing pulleys and knobs (Figure 3 a, b and c), please do not put too much force on the screws as the screw thread could tarnish soft aluminum piece. This is what happened with me with the Negative Supply knob.

Figure3: (a) is a negative supply knob to manually rotate the shaft, (b, item 22) is mounted on (e, item 6), and (c, item 6) is mounted on the stepper motor (item 1). (d, item 5) is a 158mm belt. Mounting (a),(b) and (c) are done using (f) and (g) are 1.27 and 1.5 hex key respectively (from item 10).

The stepper motor (item 1) is first mounted to stepper motor holder (item 19). Using the Gorilla double sided clear tape, the motor holder is mounted onto the negative supply carrier as seen in Figure 3. I used this type knowing it wouldn’t be a huge trouble to peal off, if needed.

It should look like this at the end when all these pieces are mounted and adjusted. The shaft length could be 1 cm less. But sometimes getting things done is better than just waiting for the perfect piece.

2-The controller

The controller will be the same for both versions of the film pusher program. However the buttons have a different function except for one, that is the shutter releases. Also the blue knob adjusting the film progression speed, on the top left, is not used in the full automatic version. This is because of Python. It is not as good as Arduino IDE when it comes to precise timing of things.

Figure 5: The switch at the bottom left (item 17) engages the stepper motor to turn on and off, the blue knob on the top left is a 10k potentiometer (item 9) adjusts the speed of the motor when using Arduino sketch, the 4 resistors used are all 5K Ohm (items 8). For the Arduino sketch the buttons (item 15) from left to right are: shutter release button, micro-left shifter, micro-right shifter, next frame. For the full automatic this is: shutter release button, move the next frame and correct position, move the next frame, correct position and take the picture, move the next frame, correct position, take the picture and carry on until a user specified number. You can always disengage the full automatic mode using the switch and stopping the python program.

3-Starting with the Arduino Nano (Blue) and the Stepper Motor board (RED)

Uploading Arduino sketch’s are required for both modes. To do this you will need to install the Arduino IDE app. After opening the app, from the tools/board, select “Arduino Nano”, from the tools/Processor, select “ATmega328P (old bootloader)“ and lastly from the tools/port, select that looks like “/dev/cu.usbserial-14xx” for mac users and possibly “ /com3 “ for windows users. Make a note of this address as it is needed for the Python program. At this point I would highly encourage you test out the Blink Sketch that is in the Files/Examples/01.Basics/Blink. A new sketch window will appear. On this window, hit the Upload button that is on the top left, next to the button that has a tick sign. On the bottom left, the opened sketch window will show Compiling Sketch/Uploading/Done Uploading and you should observe a led on your Arduino Nano blinking. This shows that the board is working and you are able to upload an Arduino Sketch. On my Macbook Pro 2012mid, only the USB port closest to the display port works for uploading Arduino sketches. So, if you experience a problem here, check if other USB sites work on your laptop work.

Figure 6: On the left is the stepper motor control board (item 2) and on the right is Arduino Nano (item 3), the resistors are used to dive voltage: horizontally placed is a 2k resistor and vertically place resistor is a 5k resistor. These are used to lower 5V to 3.3V.

The 2 Orange wires in Figure 6 (side by side on the top part, the other is red but I admit looks orange too) power the stepper motor controller board. Incorrect wiring here will make your stepper motor controller board stop working. Also pay attention to the wire colours of the stepper motor. The correct wiring will ensure the bipolar stepper motor to receive the voltages in the correct sequence for a successful 360 degree rotation. But this is not as sensitive.

Figure 7: When connecting the 9V DC source it is important to match the positive side of the capacitor with the positive power source and negative side (marked in grey) with the ground of the power source. In the case you mismatch, the capacitor will make a small explosion and spew out gas.

4-The wiring 

This is a simple system to wire and it doesn’t have a lot of components. However, during wiring it is important to turn off the power.

Let’s start with the 2.5mm jack that is responsible for the camera shutter. You will need a 3 pole jack, Figure 8(A). Using 3 instead of 2 will prevent the activation of the autofocus (manual lens are ideal here). The middle section (red in Figure 8) is triggering the autofocus, and is not connected to the mini breadboard. The black wire is ground and the white wire triggers the shutter. Next, would be to figure out which wire is which on your 2.5 mm jack. One unorthodox, yet trusty method, is the 9V battery and the tongue sensor. Another way would be using the power of deduction. For this you would insert the 2.5mm jack into your camera, having all wires exposed (white, red and black). Knowing that the autofocus is activated when the middle section is connected to the right section (probably black), and camera shutter is activated when left side connected to the right (probably white), we can deduce our wires. But I must admit, I am not sure what happens left side it first connected to the middle. Hopefully, nothing :) The best solution would be to use a multimeter.

I usually like to run the stepper motor on 9V as it does heat up over time, but if the tension on the belt is too strong it may need its specified 12V power source.

Figure 8: (A) is a 2.5mm jack, (B) and (C) are 2K Ohm and 5K Ohm resistors, (E) is a 1000uF 35V capacitor to dampen voltage spikes (100uF should be enough), (D) all 4 resistors are 10K Ohm resistor. The white arrows show the tiny wires. You do not need to solder a capacitor to wires as shown on (E), see Figure 7. Make sure the – negative site of the electrolytic capacitor is connected to the negative and + side to the positive DC source.
Figure 9: The wiring inside mini breadboards. Holes on the blu line are all connected to each other. So any two point on the blue line will be connected, ensuring a solderless project, with no flux fumes.

5-Downloading from Github and getting stated

I have just started using GitHub. It’s an excellent way to track changes and share ideas. If your interested in how Python moves to the correct position, please feel free to check out the algorithm. And also, please don’t hold back to Fork the project and share your ideas. You can find and download them here.

A good place to start is by running the Arduino Sketch. This will ensure correct wiring and components working. To do this download the Semi-automaticUsingArduino.ino from github and upload this sketch into your Arduino Nano as described in Section 3. This should be all. If your stepper motor is making funny noise, play around with the blue potentiometer until it sounds correct and the speed is to your liking. If progression of the film frame is repetitively falling short increase the FrameLength variable in the sketch, and conversely, if it is progressing too much. This value is probably specific to your device, as there could be small differences between devices. Make a note of your FrameLength variable, because it will be handy when using the Python program.

If you wish you can change the stepper motor resolution, you can do so by changing the 3 motMS(X)Pin values. For example, with mode 0,0,0 is 200 steps per one full rotation (which is the fastest), with mode 1, 1, 1 it is 3200 steps per full rotation, known as microstepping. This is the biggest spatial resolution we can achieve with this stepper board. This stepper controlling board also has 3 other modes 400, 800 and 1600 steps per 1 full rotation (item 2). This is easier to change in the Arduino sketch that it is in the Python program, as it is requires change at multiple places.

If you want to make the system work in full automatic mode, the Arduino needs a file called Standart Firmata uploaded from the Arduino IDE. This is sketch is found under File/Examples/Firmata/StandartFirmata. This makes the Arduino Nano ready to interact with Python. On the other end, the Python library responsible for the communicating with Arduino is called pyFirmata. Hopefully, pyFirmata is already installed either from the Anaconda-Navigation window or by PIP install, along with Cv2, Numpy and SciPy. The time library is a standard library that is already installed. The Python program is called Full-AutomaticUsingPython.ipynb and can be downloaded from Github.

6-Items used and costs

I generally used Amazon to purchase what I needed for this project. This was mostly out of convenience. It also didn’t require me to physically go to shops during the pandemic. I also sometimes when for the faster delivery option. That meant that I usually bought more parts than what I needed. I justified this to myself because I thought I would use it on other projects. If you also end up with parts you do not need at the end you can always donate them to your local schools. I spent about 300 Canadian dollars on this setup. And I now have enough resistors, capacitors, jumper cables and Arduino Nano’s to last me a lifetime. However, I think you can reduce the cost to about 100-150$, if you scout and search the internet for sites like Alibaba, ebay, etc.

A quick disclaimer, if you use the links below for your purchase I will receive a small commission. This little kick back could also motivate me to share other projects in the future. Using these links does not effect the price. That said, I also suggest you use other websites for cheeper prices.

I hope you enjoyed this how-to manual. If you have any question or suggestion please don’t hold back.

And Thank you.

About the Author

Seckin Sinan Isik is a film photographer based in Montréal, Canada. You can find more of his work on his website, and make sure to follow him on Facebook and Instagram. This article was also published here and shared with permission.

Filed Under:

Tagged With:

Find this interesting? Share it with your friends!


We love it when our readers get in touch with us to share their stories. This article was contributed to DIYP by a member of our community. If you would like to contribute an article, please contact us here.

Join the Discussion

DIYP Comment Policy
Be nice, be on-topic, no personal information or flames.

Leave a Reply

Your email address will not be published. Required fields are marked *

3 responses to “Make your own automatic 35mm film scanner using an Arduino Nano and Python”

  1. Jolyon Ralph Avatar
    Jolyon Ralph

    If only there was a way to get a digital image straight out of a camera without needing to do all this tedious messing around :)

  2. Joost Avatar

    wish i had the tools and patience for this! lovely article

  3. Stephane Schmuck Avatar
    Stephane Schmuck

    Great project, I’m just missing the code sources and the 3d printed film transport device…