Taking pictures and geeking out over cameras was one of my first hobbies starting with an old Olympus point and shoot, I then moved up to a DSLR upgrading as new and exciting technology became accessible to my summer job budget. I then got the opportunity to buy a Leica M8 and was immediately hooked on the rangefinder system and manual lenses. But being an engineer I always wanted to build my own camera.
This camera project is a culmination of countless hours of learning to code in various languages, design 3D parts, print them successfully, build basic electronic circuits, use optical elements, and solve complex problems in general. So without further ado, I introduce the Pieca Camera System!
Based on the venerable Raspberry Pi4 and the High-Quality image sensor module it incorporates a 5-in touch screen with a live view and full manual controls. The camera uses the M mount system for attaching lenses. Allowing the camera to use a plethora of small manual lenses from Leica, 7Artisans, TTartisan, and other vintage lenses. The name is a play on the combination of Raspberry Pi and the Leica cameras because it was just too hard to pass up this pun, sorry not sorry.
Inspiration
I was initially inspired by this Instagram post showing a concept Leica camera, that used M mount lenses with a lower-cost sensor and integrated an instant photo printer of all things. I realized that I could make something like this using a Raspberry Pi and some 3D design software and obviously some time.
Others have also done amazing things with the Raspberry Pi and camera module. This one even looks like a DSLR! Designed with the HQ camera module and a Pi Zero computer.
I decided to mock something up in a Shapr3D which is just a 3D design tool and not a parametric design so was very different than what I was used to. Here are a few images of the mock-up I created.
Now that I have my ideas mapped out I can start pulling everything together from electronics to software to 3d printed components and assembly. Here we go!
Camera Sensor
For a digital camera, the sensor is one of the most critical pieces of the design. This is because it takes light and transforms that into the ones and zeros that make up a digital image. If the sensor resolution is too small you will get blocky images and if the pixel area is too small noise will dominate the image ruining it.
Ever since the Raspberry Pi foundation came out with the high-quality camera sensor I have been looking for a good excuse to build a camera system around it. because it has a much higher resolution and pixel area size to create usable photography pictures. The sensor is designed for CCTV lenses, but I want to spice things up a bit and configure it to mount to Leica M mount lenses.
Optical Design
Normally when you try to mount a lens from different camera systems you need to adapt them so that they correctly illuminate the sensor area. the crop factor occurs when a lens designed to illuminate a larger sensor is adapted to a smaller sensor camera. this shows up as a cropped image effectively extending the lens’s focal length. For example, a 35mm lens designed for a full-frame camera would look closer to a 50mm equivalent when attached to an APS-C sensor camera.
On the Pi HQ Camera, the sensor size is 6.287mm x 4.712mm or 7.85mm diagonally. Dividing this into the full-frame of 43.3mm that the lenses were designed for we get a crop factor of 5.5x the lens focal length. So a 50mm full frame lens would look like a 275mm equivalent on the Pi sensor! That’s a massive telephoto!
Adafruit: All About Raspberry Pi HQ Camera Lenses
To try and combat this I will try to use a focal reducer. This is a lens that is designed to focus incoming light onto a smaller area in a lens system. This decreases the crop factor and increases the aperture of the lens. Below is an optical simulation of what a focal reducer should do, with the top simulation without the focal reducer and the bottom with it.
we can now see that the focus point has shifted forward, closer to the 1st lens. These are very common in the world of astrophotography to reduce the focal length of a telescope so that all of an object can be in view. This is often the case with taking pictures of the moon since it is much closer than other celestial objects like stars and planets.
In the world of digital photography focal reducers are commonly known as speed-boosters. These allow the user to boost the aperture of the lens that they are using and refocus the light illuminating the sensor and correcting the crop effect when mounting a full-frame lens to an APS-C sensor body. Metabones were the first creators of a general-purpose speed-booster and they have a great document on this here.
MetaBones: Speed Booster White Paper.pdf
These lenses sound too good to be true and for the most part, they deliver, but they complicate the optical design and can make using certain lenses impossible due to the distance between the last element of a lens protruding into where the focal reducer needs to be placed to achieve focus.
So going back to our focal length calculations, if I can achieve a 0.5x focal length reduction that 275mm lens will look close to 137.5mm. Still telephoto but more in a usable range.
Raspberry Pi 4
The Raspberry Pi 4 is a single-board computer (SBC) about the size of a credit card. 4 USB ports, Ethernet, 40 pin GPIO, 1.5GHz Processor, up to 8GB of RAM, 2x Micro HDMI, DSI Display port, CSI Camera port, Just to name a few.
With the increasing power of the raspberry pi 4, the plethora of add-on devices, and of course the software, it’s an easy no-brainer option to power this system. The HQ camera that is integral to this project is also supported natively in the hardware and by the Pi foundation. The other main benefit is that there is so much code and examples available for reference.
Other hardware
A camera is more than just a computer and a sensor, it needs a screen to view the image and focus the lens, a battery and power system to make the design portable, a shutter button, a storage device for photos, and a bunch of other devices to make a modern digital camera.
Screen
For the screen, I wanted to have a medium-size touch screen that would connect to the DSI port on the raspberry pi. This would simplify the connections and leave the HDMI and GPIO free. I had used the 7-in screen from the Pi Foundation and was impressed with its ease of use, but it was just too large for a camera system. So I found this 5-in basically no-name screen off amazon and was actually really impressed.
Amazon: 5in DSI Touch Screen for Raspberry Pi
Adjust brightness with
1) Run the following command in terminal to switch user permission as administrator
sudo su root
(2) Run the follwing command to adjust brightness of display (change the number 100 to any number from 0 to 255)
echo 100 > /sys/class/backlight/rpi_backlight/brightness
Battery
I wanted the battery and power system to be drop-in, meaning I could easily charge the battery as well as turn off and on the system. For this, I went with the PiSugar, which was designed to be a UPS. This is an integrated lipo and power solution that also can be upgraded from the base model to include things like RTC or a built-in auto battery manager. There are also multiple iterations so it should be easy to get in the future. I went with the S-Plus version just to keep the price down but would probably opt for a newer version with more features.
Tindie: PiSugar S Plus Battery
ATTiny85
I decided to add an attiny85 to provide a level of battery monitoring of the lipo battery. This is a small USB microcontroller, programmable with Arduino. I needed to use this because the raspberry pi does not have an ADC to measure the voltage of the battery.
Cherry MX Switch
I wanted the camera to be modular and be able to express the user’s preferences, using switches made for mechanical keyboards makes your options almost infinite. Whether you want clicky, linear, tactile, tough or soft actuation, or a plethora of other tunable features. On top of all the options in switches, the user can choose a keycap that matches their expression.
USB Thumb Drive
I choose a USB drive that could connect to both a USB A and a USB C port. This is because I need to connect it to the USB extensions and then be able to connect it to an iPad Pro or newer laptop computers to do post-editing in photoshop or the darkroom app.
Amazon: USB C and USB A Thumb Drive
USB GPS
I decided to add a GPS module to the design in order to capture location information for the images that get taken on the system. I really enjoy seeing all the images I take in a certain location or on a trip to a new destination so not having it built into my Leica or point and shoot is not ideal. This particular GPS module is cheap so it won’t really work indoors and it needs quite a long time to achieve the initial lock so be patient or maybe spend a bit more on a more sensitive module.
Flat Flex USB Cables
These will be used to extend the pi USB ports to both the storage area for the GPS module. These are great because they are lightweight and I can swap out connectors or cable lengths as needed.
Amazon: Flat Flexible USB Extension
Focal Reducer Lens
The focal reducer lens that I choose tried for the design is a c mount to 1.25in thread model that is meant to be attached to a digital sensor. There are probably others out there that would also fit the bill optically. But to be consistent with this design you need to use this one and print the new 3d spacer that I designed. I would also suggest a lens spanner or if you have an old pair of locking calipers since you will need to remove the lens from its mount.
Amazon: C Mount to 1.25in 0.5x Focal Reducer
3D Design
I spent most of my time re-learning 3d design and experimenting with 3d printed parts. I never have enough time to keep up my CAD design skills. I learned 3d design in SOLIDWORKS at university but since the software is prohibitively expensive for a hobbyist like myself I have bounced between a couple of different options. I’ve used Fusion360 and liked the interface but was put off by their licensing practices. I did a few things in FreeCAD, an open-source alternative but the interface was just not intuitive to me. I then landed on Onshape, which is a cloud-based solution with a free component, as long as all your designs are public. This is fine for me because I was planning on releasing them anyway! The other nice thing was that I could design on the go with my iPad Pro, which has been my main portable “computer” since my MacBook air has gotten too old to run practically anything.
Leica M mount and Pi HQ Camera Sensor Design
I started the design with the most critical piece, the lens, and sensor mount. This is because if I cannot get the correct distance the project is basically dead in the water as I would not be able to use Leica lenses, the whole purpose of the project. I started by just setting up the sensor with the pi to produce an image on the screen, then I took the lens and moved it closer and farther away to get a rough focal distance. I then looked up the flange distance of the Leica M mount to get a starting point, from there I could increase or decrease the distance to achieve infinity and close focal distance.
Took me 3 tries to dial it in correctly the flange distance was too far 27.8mm, and 26mm was too close but the 27.5 was just right! I also added some cutouts in the mounting barrel to allow the metal mount to fit inside it.
This could be due to the fact that when printing the final distance could be different than the design. When creating 3d printed products I usually only need to get relative dimensions to other designed parts, but since this is a dimension that is determined by the optics I need to get it spot on. this means it could change printer to printer or when using a different material so this could be a pain point for others that wish to design this themselves.
Focal Reducer Lens C Mount and Sensor Spacer
After finishing the optical design for the lens and sensor combination, I began to research ways to decrease the crop factor of the small sensor combined with a lens that was made for a full-frame camera. This lead me to the world of astrophotography and focal reducers. This is a lens element that would go between the camera lens and the sensor to focus the light resulting in an image that appears to be at a smaller focal length. Since I could not find any information on lens placement I basically had to trial and error this design so it is probably not optimal. I first replaced the metal c mount lens housing with a 3d printed version.
This was necessary as the length of the metal housing caused it to interfere with the Leica lens mount making it impossible to mount the lens. It was a tight fit, which will keep the lens in place but I needed to file down the part and use quite a bit of force to push the lens into the mount.
After mounting the lens I attached it to the Pi HQ sensor mount but due to the new lens the focal point was now off and I could not reach infinity at the infinity focus of the lens. I went through several iterations of designs to lengthen the distance between the flange and the sensor but settled on a spacer design where the sensor is extended into the camera body by a few millimeters.
Like the original design, this could need to be tuned for your 3D printer set up as the plane of focus for the new optical design is extremely picky. Also due to the new extended sensor PCB, you will need to cut the tab out of the original design to allow the metal mount to be placed correctly. I wanted to make the design compatible with both the original and focal reduced options for future compatibility by removing the IR filter and HQ mount for full-spectrum photography.
Camera Base Plate
The base plate does several things in the design but its main purpose is to house the raspberry pi and power system. it uses the standard raspberry pi mounting holes positions and is raised up off the bottom to provide a storage area for a USB drive. The other side of the base plate holds the battery and battery gauge system as well as a keyed mount for the front plate to slide into.
For the storage area, I needed a door that I could open and close easily, this was actually much harder than I originally anticipated as making moving mechanical parts takes several iterations. I finally landed on an offset radius design that allows the user to lock and unlock the door with their fingernail.
Camera Top Shell, Screen Mount, and Bezel
The screen comes with mounting standoffs that are sized for the raspberry pi but I wanted to mount the screen at an angle. So I devised a ledge that the screen could fit into with cutouts to protect the fragile flex cables. Then since the screen already has some massive black bezels on its glass surface I made a plastic bezel that could overlap the screen sandwiching it in place.
Camera Front Plate and Shutter Button
To create the front of the camera I combined it with the lens mount and sensor 3d printed model to make it one solid piece in the CAD design. This made printing the front a long ordeal but makes the design much more solid. This mount is keyed to slide onto the base plate for a solid connection between critical components.
I then added the lettering to give this device some life. I decided to inset the lettering to allow me to add another color to the print to give some needed contrast. I was going to paint the lettering but then decided to print the lettering in white on its own, then glue the pieces into the removed material in the front plate.
To create this I made the inset lettering print 98% scale in the slicer. So you cannot just print this file you need to scale the lettering and pi symbol.
The shutter button is designed around the Cherry MX style switches, so all I needed was to copy the dimensions, but I decided to inset the switch so that it would not protrude too far away from the camera body. I then printed a few keycaps, one more normal style with the open-source hardware symbol, and two kinds of ortho keycaps in red. The red really pops and makes the design come together emulating the red that is synonymous with the Leica brand.
Raspberry Pi IO Plate
I decided to have the IO plate that protects the raspberry pi ports and battery charging ports be a separate 3D printed component that I would glue onto the design. This is because I knew getting all the dimensions for all the different ports was going to be a challenge. This way I could rapidly prototype iteration after iteration to get just the right fit.
3D Design Files
GitHub: Tschucker/Pieca-3d-design-files
Battery Fuel Gauge
Creating the battery gauge out of an external microcontroller is a bit out of scope for this post so I created a second post just for that because it has some cool basic electronics elements that would be good for aspiring engineers if they wanted to create their own.
Camera Software
For software, I have a few options that I am going to explore. The first is the now legacy raspistill library and PiCamera software that integrates with Python.
The successor libcamera, is a redesigned driver library that uses the pi resources much more efficiently and integrates some new powerful features. The issue is that it does not integrate with the original PiCamera. There is a PiCamera2 software but is still in the preview stage. This should be a good option once released as the Pi Foundation has taken over its development, as the original PiCamera library was created by a 3rd party.
I decided to adopt a GUI-based camera software that was built by eat-sleep-code. It’s based on PiCamera and raspistill. To use this you need to either install an older os version or enable legacy camera library support in newer OS configurations.
UI Modifications
I decided to fork the code into my own repo as I wanted to make some major modifications that maybe others would not really need. The first glaring issue was that the UI was not really built for my application. The Issue was that preview was length-wise and did not represent the whole frame and the UI buttons were along the bottom. This meant I needed to re-organize all the elements so that the preview was the right size and then the UI buttons were along the righthand side so that they mimic a normal camera interface.
def handler(buttonDictionary, e):
# print(' DEBUG: ' + e + ' was clicked ')
if e == 'shutterUp':
buttonDictionary.update({'shutterUp': True})
elif e == 'shutterDown':
buttonDictionary.update({'shutterDown': True})
elif e == 'isoUp':
buttonDictionary.update({'isoUp': True})
elif e == 'isoDown':
buttonDictionary.update({'isoDown': True})
elif e == 'evUp':
buttonDictionary.update({'evUp': True})
elif e == 'evDown':
buttonDictionary.update({'evDown': True})
elif e == 'bracketUp':
buttonDictionary.update({'bracketUp': True})
elif e == 'bracketDown':
buttonDictionary.update({'bracketDown': True})
elif e == 'videoMode':
buttonDictionary.update({'videoMode': True})
elif e == 'capture':
buttonDictionary.update({'capture': True})
elif e == 'captureVideo':
buttonDictionary.update({'captureVideo': True})
elif e == 'exit':
buttonDictionary.update({'exit': True})
time.sleep(0.2)
return buttonDictionary
The interface was built on Tkinter so it was pretty easy to change the window location, and resize the buttons to match the new preview window.
Shutter Button Code
To enable capturing an image using the mechanical keyboard switch I had to enable one of the Raspberry Pi’s GPIO to trigger an event. But first, I had to set up the GPIO as an input and use the internal pull-up, this is because when the button is pressed it connects the pin to ground. So the pull-up floats the pin voltage to logic 1 then when pressed it grounds the pin to voltage logic 0. Then I used the python GPIO library to add an asynchronous event that triggers a callback function. This is a pre-threaded function so I just need to set it up and hack the callback to trigger the same mechanism that the UI capture photo button calls.
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(26, GPIO.FALLING, bouncetime=200, callback=lambda x: self.hw_handler(buttonDictionary, 'capture'))
Power Button and Auto-Off
I used the same method to enable using the GPIO for the shutter button, but instead of a one-way callback, I used a trigger on both the rising and falling edge. This is because I wanted to time the interval between pressing the button down and releasing it.
GPIO.setup(3, GPIO.IN)
GPIO.add_event_detect(3, GPIO.BOTH, bouncetime=2000, callback=lambda x: self.hw_handler(buttonDictionary, 'init_shutdown'))
The only issue is that when the charger is connected it triggers the interrupt designed for the button. So I added an upper limit to the button press function that way it does not power off the camera when the charger is disconnected.
elif buttonDictionary['init_shutdown'] == True:
if (power_button_start_time == 0) and (GPIO.input(3) == 0):
power_button_start_time = time.time()
else:
pressed_time = time.time() - power_button_start_time
if (pressed_time > 2) and (pressed_time < 6):
statusDictionary.update({'message': ' Power Off '})
time.sleep(1)
os.system("sudo shutdown -h now")
else:
statusDictionary.update({'message': ' Charged '+ str(int(pressed_time/60))+' m '})
power_button_start_time = 0
buttonDictionary.update({'init_shutdown': False})
Battery Gauge Integration
To enable the battery UI display I needed to get the information from the ATTiny pins to the pi software. As with any of the GPIO, I needed to set them up as inputs. Then instead of setting up interrupts on the pins, I decided to use a separate thread and use the messaging feature already built into the code to send battery updates to the UI similar to how the UI already displays messages about settings changes.
GPIO.setup(22, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
batteryVariable = tk.StringVar()
batteryLabel = ttk.Label(root, compound=tk.CENTER, textvariable=batteryVariable)
batteryLabel['style'] = 'primary.TLabel'
batteryLabel.configure(anchor='center')
batteryVariable.set(statusDictionary['battery'])
batteryLabel.place(x=windowWidth,y=root.winfo_screenheight()-messageHeight,width=45,height=messageHeight)
def update_battery_gauge():
global statusDictionary
global battery_level
while True:
try:
battery_level = int(str(GPIO.input(24)) + str(GPIO.input(23)) + str(GPIO.input(22)),2)
if battery_level < 2:
time.sleep(2)
battery_level = int(str(GPIO.input(24)) + str(GPIO.input(23)) + str(GPIO.input(22)),2)
if battery_level < 2:
print("would shutdown now level:"+str(battery_level))
#os.system("sudo shutdown -h now")
statusDictionary.update({'battery': str(int((battery_level/7)*100))+'%'})
#print("battery level:"+str(battery_level))
time.sleep(5)
except Exception as ex:
print(str(ex))
pass
batteryThread = threading.Thread(target=update_battery_gauge)
batteryThread.start()
RAW support
Unfortunately, the current DNG library is broken. So this will also need to be updated when it is fixed or I have time to fix it myself.
GPS Metadata Code
I decided to save this part of the project for a future update. This is because the GPS module is not sensitive enough to get the position fix indoors and requires some outdoor exploration that I will get once I start using the camera more extensively to take pictures.
Software Autostart
To get the camera software to start automatically when the Raspberry Pi is turned on I needed to configure a few things. There are several ways to get software to run at boot on the Pi but because we need the OS GUI to be up and running before launching the camera it was a bit more tricky.
Take the pieca.desktop file and copy it into the directory below
.config/autostart
Then reboot the Pi
sudo reboot
The camera UI should then pop up after a few seconds countdown. You can also copy the pieca.desktop file to the desktop where you can then click on it to start the UI if you accidentally exit out.
GitHub Repo
GitHub: Tschucker/Pieca-camera-software
Wiring Diagrams
Electronics Assembly
Here are a few images of the electronics layout. No detailed instructions on assembly but I used all off-the-shelf wires and connectors, you only need to do some soldering if you want the battery monitor. everything else is stuck down with double-stick tape, super glue, and raspberry pi compatible screws.
Leica Lenses
With the limited flange depth and the decreased space due to the focal reducer, I cannot use lenses that have protruding elements out the back. That limits me to use 3 out of my 4 compatible lenses, leaving out my 7Artisans 35mm.
Leica Elmar 50mm
This is a vintage Leica lens using the L39 mount that I adapted to the M mount with an adapter. This is a collapsible lens made for the pre-M cameras like the iiic. it’s a 50mm F3.5 lens. So not the fastest lens out there but very usable in daylight.
Jupiter 8 50mm
The Jupiter 8 lens is a postwar soviet-era50mm lens that copies the design of the Zeiss Sonnar 50mm F2 lens. It is also an L39 mount lens that I adapted to M mount with an F2 aperture up to F22.
TTArtisan 28mm
This is my newest lens based on the M mount and has a much wider field of view. This is probably going to be the lens I use most frequently on this camera due to the crop factor still in play.
7Artisan 35mm
For fun I took a picture of this lens, you can see the protruding element. I removed the focal reducer to see what it would look like on the camera, and the black looks so nice!
Focal Reducer Comparison
To show the focal reduction of the final images I took pictures with the focal reducer in the optical path and without. For this test, I used the collapsible Elmar lens so that I did not have to remove the sensor spacer and could just push the lens back into the housing to achieve focus. So the images without the spacer could look a bit soft in comparison but the focal comparison should still be accurate.
The effect is subtle but gives just a bit more flexibility to the camera. This should be a reduction from 275 to 137.5 but it could be less than that due to the placement of the reducer.
Testing and Images
Here is a gallery of images taken with the Pieca camera. It has the capability to take some really nice photos and definitely has a unique artistic look.
Issues
This definitely has a plethora of issues, the biggest being the 3D design. I want the next version to be much more sturdy. For this, I want to use heat-set inserts and screws to clamp everything together relying less on super glue to hold things together. The other big piece is the lens mount, the plastic is just not cutting it, my plan is to purchase a cheap adapter from URTH that I can either disassemble and remount or permanently mount with epoxy.
Unlimited Potential
I don’t see this as a finished project but a platform that can be built upon as time goes on. I have tons of ideas on what I want to do next I had to reign in my options and get the basics down and finish the project! I want to use this to explore computational photography and HDR imaging, image color science, lens correction, Infrared and UV spectrum photography, and much more.
References
Here are some links that I found useful during the length of this project, peruse at your leisure.
- https://ruha.camera
- https://github.com/penk/ruha.camera
- https://www.raspberrypi.com/documentation/accessories/camera.html
- https://www.raspberrypi.com/news/a-preview-release-of-the-picamera2-library/
- https://github.com/raspberrypi/picamera2
- https://github.com/eat-sleep-code/camera
- https://berrylan.org
- https://pimylifeup.com/raspberry-pi-samba/
- https://github.com/tutRPi/Raspberry-Pi-OCR-Live-Text-Detection
- https://agenaastro.com/articles/product-types/focal-reducers-guide.html#appendix
- https://ricktu288.github.io/ray-optics/simulator/
- https://protosupplies.com/product/attiny85-module-with-micro-usb/
- https://osoyoo.com/2019/09/20/instruction-for-raspberry-pi-5-dsi-touch-screen/
- https://sourceforge.net/p/raspberry-gpio-python/wiki/Home/
- https://picamera.readthedocs.io/en/release-1.13/index.html
- https://www.w3schools.com/colors/colors_picker.asp?colorhex=E8B5CE
- https://pimylifeup.com/raspberry-pi-temperature/
- https://projects.raspberrypi.org/en/projects/code-for-your-astro-pi-mission-space-lab-experiment/5
- rigacci.org/wiki/doku.php/doc/appunti/hardware/raspberry_explorer#time_syncronization_with_gps_and_ntp
- https://github.com/RigacciOrg/raspberry-pi-gpsphotologger
- https://www.rc-astro.com/resources/reducer.html#:~:text=The%20focal%20reducer%20must%20be%20placed%20a%20distance%20Y%20in,233mm%2C%20or%20about%209.2%20inches.
3D Printed Keycaps
- https://www.thingiverse.com/thing:1955421/files
- https://www.printables.com/model/168522-corsair-k6070809095-low-profile-keycap-set/files
Subscribe to Tea and Tech Time for Blog posts and Project updates!
1 thought on “Pieca: A Raspberry Pi Camera System for Leica M Mount Lenses”
Comments are closed.