Raspberry Pi DSLR Photo Booth
This is a photobooth built for a wedding. It was designed with the following requirements in mind
- Take very good photos
- Run entirely off battery power
- Be easy to use such that it can run unattended
- Allow users to immediately download their photos onto their phone
- Be easy to set up and take down
- GUI needs to be backwards-compatible enough to run on my 1st gen iPad Mini (released in 2012!)
iPad User Interface
![](../images/explorations/photo_booth_3.png)
![](../images/explorations/photo_booth_2.png)
![](../images/explorations/photo_booth_1.png)
![](../images/explorations/photo_booth_4.png)
Technical Details
The hardware is quite simple, consisting of only the following:
- Raspberry Pi 3
- iPad mini 1st Gen
- Cellphone to provide WiFi hotspot
- Canon DSLR camera
- 10,000mAh battery bank
The software stack is as follows
- Ruby on Rails application runs as a system service on the Pi
- Rails application communicates with camera through a libgphoto2 FFI for Ruby
- Pi acts as a WiFi hotspot, to which the iPad connects to.
- The iPad runs a kiosk browser which shows the RoR site. The iPad is put in 'Guest' mode to prevent exiting the kiosk browser.
- Photos are primarily stored locally, but temporarily stored in a Digital Ocean Space to allow users to download them via QR code
- The Pi needs an internet connection, but cannot use its WiFi to connect to a hotspot because it is acting as one itself. Thus, it connects to a phone via bluetooth, over which the phone provides an internet hotspot.
- Various system calls are made by the RoR application to aide in tasks like unmounting the camera (required for libgphoto2 to work), connecting to the Wifi hotspot, etc.
Making photos available via QR download code
We first capture the image:
# (in the controller's `create` method) @photo = Photo.new GPhoto2::Camera.first do |camera| file = camera.capture file.save('tmp/image.jpg') @photo.image.attach(io: File.open('tmp/image.jpg'), filename: 'image.jpg') end
Then, when the user requests a QR code for that image:
# (in the controller) def qr_image # get the raw file for the image attached to the 'photo' image (in a given quality variation [decent]) image = @photo.image.variant(:decent).processed.download begin # attach that file to the 'cloud_image' entity of the model. # This uploads the file to the cloud storage service (e.g. S3) @photo.cloud_image.attach(io: StringIO.new(image), filename: 'image.jpg') rescue Seahorse::Client::NetworkingError # if it fails, show the user an error image send_file("app/assets/images/no-net.png", type: 'image/png', disposition: 'inline') and return end @photo.save! # get a pre-signed URL for the cloud image and present it as a QR code. # the URL is only valid for 10min, as per config/environments/production: # config.active_storage.service_urls_expire_in = 10.minutes qr = RQRCode::QRCode.new(@photo.cloud_image.url, level: :l).as_png(size: 460) send_data qr, type: 'image/png', disposition: 'inline' end
The view loads the QR code as an image from the above controller method:
<%= image_tag("#{photo_path(@photo)}/qr_image?cache_buster=#{Time.now.to_time.to_i}", style: 'width: 500px; height: 500px; border: none; margin: 0; background: url(' + asset_path('Loading_icon.gif') + ') no-repeat center;') %>
I think Rails does a great job here -- many other frameworks would need many more lines for such a task.
System calls
The Rails application makes a number of system calls to make sure the OS is in a fit state to run the photobooth:
gio mount -u gphoto2://Canon_Inc._Canon_Digital_Camera/
[unmounts camera; require for libgphoto2 to use camera]nmcli connection up "$(nmcli -f name connection | grep 'iPhone' | xargs)"
[connect to the iPhone hotspot]