This post is both an overview of the small photobooth application that I wrote in Elixir, and some general observations of the issues I had writing an application in Elixir.
The purpose
The whole goal of writing this application was to setup a photobooth at my friends wedding, and letting it run all night long, uninterrupted and unattended. This means I wanted something that would just work, and not need to be watched. I also wanted to try something new, and pick up some new skills. This goal was partly achieved, but the application did fail at one point and had to be restarted. More on that later.
The setup
I’m using a Raspberry Pi, Elixir, and a handful of 3rd party libraries to get this working, and a DSLR camera to take the pictures. The application I wrote mostly acted as the glue, controlling when things should happen.
GPhoto2 is used talk to the camera. I was using a Nikon D3000 to take the pictures. Some of the functions available in GPhoto2 do not work with this camera, and the code reflects that. It would have been easier to take pictures and download images all in one command, but I had to first take a series of pictures, and then download all of them at once. Then delete all of them from the camera. Talking to the camera through this library was also the most unreliable part of the application. Trying to take pictures too fast, or failing to focus on an object would cause the call to fail and throw an error.
GraphicsMagik will take a set of photos and stitch them together into a single image.
The concept was to take 4 pictures, stitch them into one image, and then print it out right away. But, getting a printer to work with a Raspberry Pi was pretty difficult, and I was unable to get my Canon printer working properly. Different brands of printers may work better, but I gave up on getting printouts to work. In the end, we just let the images sit on the Pi, and pulled them off after the party, to be sent out to the guests later.
Elixir_Ale is used to talk to the GPIO pins, and both turn on LEDs and and react to a button press.
What went well
I was able to counteract the issues with camera communication by using an OTP server to talk to the camera. If communication failed with the camera, the server would be restarted, and it would try to retake the picture again.
The GPIO pin library also worked well, except for the issues with accessing the pins when not running as root. Eventually, I found a good workaround for this, but I was still able to get things working by just starting the program twice. For some reason, access would fail the first time, but succeed the second try. Writing and reading the pins with the library was pretty easy, and worked without issue after that. And setting up pin interrupts works very well with Elixir/OTP system.
What didn’t go so well
As with learning any new thing, you are bound to trip and find pitfalls when you don’t know the lay of the land yet. Some things I was able to work out or work around. Others are still issues, which I haven’t yet found a solution to.
Writing an Elixir app for the Raspberry Pi, which doesn’t compile on your laptop is pretty frustrating. I would like to make some more changes to this project, and start up another project to use the same tools, but the process is just so slow. This is the first issue I need to figure out before moving forward. Cross compiling is possible, but I didn’t spend the time to set this up in advance. Note that this is only an issue when using the GPIO library, as some C code needs to be compiled for the Pi. Elixir code compiles fine on either machine.
Setting up GenServers is also a bit of a pain. Several times I found that making a call would not work, but there was no error either. Simply, nothing would happen at all. Lack of feedback makes fixing the issue a bit of a challenge. Along with this, debugging and finding issues is a bit harder than what I am used to, coming from Visual Studio. It seems like there should be some ways to better this experience, but I haven’t found them yet. Of course, you probably should be running unit tests on everything to prevent these kinds of issues, which might be why things didn’t go so smoothly.
Also, when this was actually running during the wedding, it worked great, for a while. After about an hour, something broke, and it needed to be restarted. I started this project before the Logging library was included in Elixir, so I didn’t include it in this project. It would probably help to keep track of what was happening. I suspect that something probably happened with the camera communication, since too many failures will still cause the application to crash.
Conclusion and code
I think the issues I ran into could be fixed, with enough time. I’d like to get all of these things worked out and resolved, so that I can do a bit more with my Pi. Also, it would be nice to have the project itself in a bit better shape. Due to the difficulties I was having, and time pressure, the application is in rough shape. Adding docs, tests, getting more things put into OTP servers… the list goes on.
But, if you want to take a look, the source code is on Github.
Overall, I think it went pretty well. This seems to be a fairly good use case for Elixir, and writing everything in a high level language to access pins and interact with hardware is pretty fun. This is something I want to try again soon, and get better at.