Did you know that you can make light paintings with a long exposure camera? Light painting is a photographic technique in which exposures are made by moving a hand-held light source while taking a long exposure photograph. We take this a step further by finely controlling the light source's movement with a stepper motor driven rover. The results are stunning. The project consists of a Raspberry Pi 3, two stepper motors, and a NeoPixel LED matrix. It can easily be recreated with a 3D printer and all of the code is provided.
Get all the 3D printable part files on our Patreon: https://www.patreon.com/posts/light-rover-37733590
Check out this video to see how we made it and a demonstration of what it can do.
Here's a photo of the completed rover.
To create light photography, we're going to use this programmable 8x8 LED matrix. We've used the flexible version before for our LED Hat project. Most people in the community typically use an Arduino to control these matrices, but we decided to use a Raspberry Pi so that we could store more image data for the software and easily download new images from the internet.
The robot chassis consists of several different 3D printed parts. Unfortunately, the number of parts (and tolerances on those parts) was too high, so we decided to not to make plans for a MDF version. If you want to make your own and don't have a 3D printer, you can usually find one in a public library/school or use a 3D printing service online.
The chassis has a main base where we can attach all of our parts and brackets. Starting from the base, we slotted a small portable cell phone battery in the back and attached our Raspberry Pi to the front with some 2.5mm bolts and nuts. A small bracket was attached to the top so that we could easily remove the Raspberry Pi if we needed to.
The wheels are driven by 2 NEMA 17 200 rev stepper motors. Stepper motors were used so that we can make precise movements to draw the light painted imagery. We used two stepper motor breakout boards for this project instead of the stepper motor HAT that we used for the automated airsoft turret because we found that they had less jitter while moving two motors in parallel. Both boards were attached to the front of the rover with a small 3D printed clip and some 2.5mm bolts.
Four female jumper wire extensions were soldered to each stepper motor. They were mounted underneath the chassis with the help of two more brackets. Some 3mm screws were used to attach the motors. Since our screws were slightly long, we added a couple bots to under the screw head to act as a spacer. The wires were routed underneath the Raspberry Pi and attached directly to the breakout boards. A guide for wiring these breakout boards can be found here.
In order for the stepper motors to work with our battery, we needed to amplify the voltage from 5v to 12v with a boost adapter. Two wires were soldered to the ground/hot pins of the amplifier, and then attached to the stepper motor breakout boards.
Next we mounted the 3D printed wheels. Each wheel attached to the shaft of the stepper motors and were held in place with a small 3mm set screw. A couple small rubber bands were attached to the wheels for extra grip during the painting process.
The boost adapter and Raspberry Pi were plugged into the 5v battery. We attached the LED matrix with a 3D printed standoff and plugged the signal wire into pin 18 on our Raspberry Pi. A soldering iron was used to attached a small USB cable the the +/- terminals on the LED matrix. This USB was also plugged into the 5v battery.
Make sure you install the following dependencies:
Pillow
RPi.GPIO
numpy
We also used a custom Raspberry Pi Neopixel library found here: https://github.com/jgarff/rpi_ws281x
Follow the Raspberry Pi install instructions.
At the bottom of light_rover.py, we configured the pins for all of our components. Make sure these pins are correct.
stepper1 = Stepper(2, 3, 4, 17)
stepper2 = Stepper(27, 22, 10, 9)
led_matrix = create_strip(64, led_pin=18)
Drawing VectorsVector images are used to represent images in computer graphics. They consist of several lines with a magnitude and angle. You can make your light robot draw vector graphics by making a few modifications to the code.
Make sure the following section is commented out at the end of light_rover.py:
#if imageFile:
# rover.paint_image(imageFile)
#else:
# print "No image file provided!" exit(1)
Uncomment the following line:
rover.paint_vector(dog, single_value_affects_pixels=[27, 28, 35, 36])
Choose a vector from the vector_drawings.py
file and change that value in the paint_vector
function.
To run, make sure you are in the project directory and execute:
sudo python light_rover.py
Drawing ImagesYou can also paint images pixel-by-pixel with the LED matrix. Small images (~100px x 100px) usually work best. Make sure the following section is commented out at the end of light_rover.py:
# rover.paint_vector(dog, single_value_affects_pixels=[27, 28, 35, 36])
Uncomment the following line:
if imageFile:
rover.paint_image(imageFile)
else:
print "No image file provided!" exit(1)
To run, make sure you are in the project directory and execute:
sudo python light_rover.py images/sb.png
How Does It Work?Two stepper motors attached to the rover's wheels can make fine-tuned turns that move the rover over a specified path while the camera's shutter is open. Vector images were created by sending a rover an arbitrary distance, and then turning an arbitrary angle to line up for the next movement. Using this technique, we were able to draw several different straight line images.
If you want to create your own vector drawing, add a new array of vectors in:
vector_drawings.py
Such as:
rectangle = [LightVector(1000, 90, [[0, 255, 0]]),
LightVector(800, 90, [[0, 255, 255]]),
LightVector(1000, 90, [[0, 255, 0]]),
LightVector(800, 90, [[0, 255, 255]])]
Where a LightVector takes the following arguments:
def __init__(self, steps, angle, pixel_data):
"""
:param steps: number of steps to move
:param angle: angle to turn after the movement
:param pixel_data: a 2d array of pixel data [[r, g, b]...n] where n is the number of pixels in the matrix
"""
Images were drawn in a slightly different fashion. Instead of moving the rover over a series of vectors, we sectioned out 8x8 portions of the image and flashed those pixels on the LED matrix as the rover moved row-by-row from the top right of the image to the bottom left. After each flash, the rover moved just enough to line up the next set of pixels in the image.
Typically, images less than 120x120px work best for light paintings. Our program will automatically section the image for you.
Taking a PhotoTo take a photo, make sure you position your camera high enough to capture the entire image. Turn all of the lights off and make sure your camera is in bulb timer mode.
On some cameras you have to hold the shutter button to capture the image, but it is preferred that you set an automatic timer if you can.
Our camera used a 5 minute exposure with a low ISO setting and the lens aperture stepped down to f/10. We found that this produced the best image of the light painting without letting some of the ambient light in the room leak through.
Now that you've built your rover, go ahead and try it! If you make any interesting new images, make sure to post them here so that we can check them out.
Cheers,
Aaron @ Hacker Shack
Comments