Light Painting Robot
To answer questions on the subject of light painting and the tools I use I have created a beginners guide to light painting here...
https://www.instructables.com/id/Light-Painting-a-Beginners-Guide/
Ever wanted to create cool light painting images like this one above (a collaberation between me and Stephen elliott)??? me too however i can never seem to get my orbs to be even and round! (I am of course assuming you know what light painting is if not here's a quick wiki on the subject. https://en.wikipedia.org/wiki/Light_painting and here's a quick google image search on the subject).
So I decided to apply some of my technical skill to create a Robot to draw the orbs for me. this is intended to be used along side other light painting tools and my example images are created with the robot as it stands now.
My goal was to make the design as simple and as cheap as possible. The parts chosen for the project are easily obtainable via ebay and amazon. to complete the light painting robot you will need the following items.
- 28byj-48 stepper motor x2
- Uln2003 Driver Module x2
- Arduino pro mini (5v) x1
- Infrared Remote Control Set x1 (pick a remote with as many buttons as possible you will need them all)
- Ch340g Usb To Serial Module x1
- Neopixel led x4
- Small USB power bank
- 3d printed parts from files included or parts made of wood etc
Before We Start!
before getting into the detail i wanted to share some examples of what it can achieve and the technique required to produce the images, if i miss something or you have any questions give me a shout ill help any way i can.
so the above images were created with the light painting robot on its own and the last image showing all three designs was taken in one single exposure. with the robot being moved to a new location between each orb being drawn. let me explain to create a light painting image with the robot you will need a camera with a remote shutter preferably with Bulb mode or equivalent and a dark environment the first four images have a shutter speed of around 30 seconds at f22 iso100 the last image has a shutter speed of around 200 seconds again at f22 iso100 and as the robot moves its arm with LEDs attached it leaves a trail of light recorded by the camera's sensor so although as you view the image being created your eyes only see the instant light the camera sees all of the light from start to finish resulting in these "light trails".
Lets Get Started!
first of all you will need to 3d print or have a printing farm print the items above they consist of
- the Body / motor housing
- Robot arm
- Base plate / wheel
for the sake of clarity the body and base are derivatives of a design found on Thingiverse which i have modified for this project and the arm is my own design.
if printing the parts is a problem it should be possible to make them from ply wood etc
before assembly it may be a good idea to wire the modules as per the schematic above. Im showing the power supply as a 9v pp3 battery but this is in reality the 5v usb power bank. in the diagram i show a neo pixel ring as this was the only model available in the drawing software i am using and i recommend individual Neopixels and in this case you connect 5v and gnd to each Neopixel and then connect Arduino pin 10 to Din (data in) on the first Neopixel and then Dout (data out) to Din on the next Neopixel and so on to the end of the chain. Take extra care to ensure you get the polarity correct for both the IR receiver and Neopixels as errors here will certainly lead to dead parts. once the wiring is done we can move onto assembly
I used a Glue gun to attach the drivers to the sides of the motor housing and the lights to indicate movement create the red "nucleus" to the orb as an added bonus. I then attached the Arduino to the back of the motor housing with the glue gun and found a spot to hold the IR receiver (the project is still a work in progress) and then glue gunned the power bank to the top of the motor housing. finally fit the Neopixels to the end of the robot arm and run the 3 cables back down the arm to the hub. leave a loop of cable to allow the arm to rotate 180 degrees without snagging or pulling the cable and connect this cable to VCC, GND and digital pin 10 of the Arduino. this should be all the assembly and wiring done now we just need to upload the code. if you are not familiar with Arduino I recommend you read this article on programming the pro mini as it is slightly different to the full sized arduino.
first of all down load the code included above and the Arduino IDE
you will need to add the following libraries to your Arduino IDE
- accelstepper
- multistepper (part of accelstepper)
- Adafruit neopixel
- IRremote
follow this guide to install the required libraries.
once the ide is configured to work with your programmer and arduino and you have the code open you should be able to upload the code to the arduino. once it says "upload done" you will notice the robot arm moves to the start position you will need to create a stop (i used a small wood screw) as this is the index position of the robot arm and it uses this as the start point for all animations this start position should be around 10mm from the floor when the robot is on a level surface. Now you can give the remote a whirl, each of the number buttons selects a different colour to use with the custom colour programs or you can choose to use the 3 pre selected colour programs. Experiment with your remote as yours may be different to mine, at the moment the code uses all but 5 of the buttons leaving room for you to experiment and create your own animations. i have kept the code as simple as possible with simple program sections and annotations. At some point i shall upload a video of the robot in action and some close up images of the completed robot.
Current & Future Developments
having given the Light painting robot a shakedown run last night it became apparent that I needed some control over the brightness of the neopixels as i was struggling to maintain correct exposure in the camera. In light of this I have updated the code to make the output of the neopixels variable in 5 steps. this feature is adjusted and displayed by pressing the CH+ button on my remote control, use CH- to turn the neopixels off once you have the desired brightness.
i have also added a little mod to the arm of the robot to give you the option of a filled nucleus using two single colour LED's inserted into two halves of a Bic pen roughed up with a screw to diffuse and spread the light along the length of the pen body. electrically the LED's are connected anode to 5v/+ and cathode/- connected to digital pin 13 of the Arduino these are switched off by default and toggled with the CH button on my remote control. two flashes of the LED's indicates that the nucleus LED's are ON and a single flash indicates the nucleus LED's are OFF.
The code below will always be the latest version with all of the features listed above.
updated: 18/01/2018
- cleaned up code to make it easier to understand and customise with own animations
- added adjustment of Neopixels brightness in 5 increments
- added optional nucleus LED's
- increased speed and acceleration to help with exposure
Downloads
As Requested Images of the Completed Robot
This is what you should have having got to this point, congratulations!
Programming Custom Moves, OH No Not the Code!
programming custom moves should be fairly straight forward and i will use the current code to explain how to plot movements.
movements can be done one axis at a time and both axis moving to one destination at the same time and i use both in my code. the neopixel colours can be changed between moves as many time as you like but try to keep animations under 1 minute for best results.
for both types of animation the robot starts at position 0,0 that is the robot sees the arm in position 0 rotation and 0 swing at switch on and i always reset the current position to 0,0 at the end of the animation or return to this position so we are ready for the next orb to be painted. the swing axis is limited at the moment to a total motion of 1100 steps this represents just over 180 degrees of swing however the rotational axis has no limit on the number of turns it can make and requires around 2200 steps to complete one single rotation of the entire robot.
to explain moving one axis at a time i shall dissect one of my blocks of code for one of the animations.
case 0xFF9867: // 100+ this is the marker for a block of code associated with a particular button on the remote control and is only executed if this button is seen to be pressed on my remote it is the 100+ button
if (core == "1") { this line of code checks if the nucleus feature is activated if it isnt skip past the next }
digitalWrite (13,LOW); if nucleus feature is activated then turn on nucleus LED's (Active low)
}
rotation.runToNewPosition(2000); here the rotation stepper is commanded to move to position 2000. keep in mind its location before executing this move is 0 rotation and 0 swing no other code will be executed until the rotation stepper stops
swing.runToNewPosition(100); now the swing arm is commanded to raise to 100 again no other command will be executed until the swing stepper stops
rotation.runToNewPosition(0); now the rotation stepper is commanded to return to position 0
swing.runToNewPosition(200); now the swing arm is commanded to raise another 100 steps to position 200
rotation.runToNewPosition(2000); again the rotation stepper is commanded to move to position 2000
swing.runToNewPosition(300); now the swing arm is commanded to raise another 100 steps to position 300
rotation.runToNewPosition(0); etc
swing.runToNewPosition(400);
rotation.runToNewPosition(2000);
swing.runToNewPosition(500);
rotation.runToNewPosition(0);
swing.runToNewPosition(600);
rotation.runToNewPosition(2000);
swing.runToNewPosition(700);
rotation.runToNewPosition(0);
swing.runToNewPosition(1100);
for(int i=0;i etc here we setup a loop with enough executions to match the number of neopixels in the robot
pixels.setPixelColor(i, pixels.Color(0,0,0)); sends a message to the neopixels to set all colour LED's to 0 intensity essentially off
pixels.show(); update the pixels to show the settings sent in the line above
}
digitalWrite (13,HIGH); ensure the nucleus feature is turned off at the end of the animation (active low) it is done this way because all arduino's can sink more current than they can supply.
break; end execution and return to looking for remote control instructions
multi axis animation is a little more complicated but not excessively so and again i shall dissect a small piece of code as above.
case 0xFFC23D: // play this is the marker for a block of code associated with a particular button on the remote control and is only executed if this button is seen to be pressed on my remote it is the Play button
if (core == "1") { this line of code checks if the nucleus feature is activated if it isnt skip to next }
digitalWrite (13,LOW); if nucleus feature is activated then turn on nucleus LED's (Active low)
}
{
for(int i=0;i etc sets up a loop to change all neopixel colours
pixels.setPixelColor(i, pixels.Color(0,(50*brightness),0)); this line of code is used to set the neopixel to a particular RGB value (R,G,B) each colour can have an intensity from 0 to 255 0 being off and 255 being full brightness so to make a neopixel bright red you would send (255,0,0) here we send (0,50x brightness,0) so this will be green and its brightness could be from 50 to 250 depending on the chosen brightness setting (default is 150)
pixels.show(); update the pixels to show the settings sent in the line above
}
long positions[2]; prepare the multi-stepper library to receive two new positions for rotation and swing.
positions[0] = 16000; tells the multi-stepper library to be prepared to rotate from 0 to 16000
positions[1] = 1100; tells the multi-stepper library to be prepared to swing from 0 to 1100
steppers.moveTo(positions); calculate the number of steps required on each axis to have each axis arrive at its programmed destination at the same time
steppers.runSpeedToPosition(); moves to new position and stops the program from continuing until all steppers stop
delay(10);
for(int i=0;i etc sets up a loop to change all neopixel colours
pixels.setPixelColor(i, pixels.Color(0,0,(50*brightness))); this line of code is used to set the neopixel to a particular RGB value (R,G,B) each colour can have an intensity from 0 to 255 0 being off and 255 being full brightness so to make a neopixel bright red you would send (255,0,0) here we send (0,0,50x brightness) so this will be Blue and its brightness could be from 50 to 250 depending on the chosen brightness setting (default is 150)
pixels.show(); update the neopixels to show the settings sent in the line above
}
positions[0] = 32000; tells the multi-stepper library to be prepared to rotate from 16000 (current location) to 32000
positions[1] = 0; tells the multi-stepper library to be prepared to swing from 1100 (Current location) back to 0
steppers.moveTo(positions); calculate the number of steps required on each axis to have each axis arrive at its programmed destination at the same time
steppers.runSpeedToPosition(); moves to new position and stops the program from continuing until all steppers stop
delay(10);
}
for(int i=0;i (etc) sets up a loop to change all neopixel colours
pixels.setPixelColor(i, pixels.Color(0,0,0)); sends a message to the neopixels to set all colour LED's to 0 intensity essentially off
pixels.show(); update the neopixels to show the settings sent in the line above
}
swing.setCurrentPosition(0); sets the current location to 0 rotation 0 swing saves us travelling back to 0,0
rotation.setMaxSpeed(600); because we reset location we now have to reset max speed
rotation.setAcceleration(400.0); and acceleration
digitalWrite (13,HIGH); turn off nucleus LED's if on (active low)
break; stop current activity and look for new remote button presses
hopefully that helps to answer the question i had "how do i program custom animations?" now you are limited only by your imagination and arduino space. the current version occupies 57% of memory with libraries and could probably be optimised to save space as well. there are currently 5 buttons spare / unconfigured and 3 buttons just set the same colours twice now i have included an option to set brightness so you could add 8 more animations on top of the ones i have already programmed. but again if you still need assistance give me a poke im happy to help!
I Did Say I Wasn't Finished
I had many request to make the light painting robot do a full orb instead of a half orb as per my original design... so here it is.
You will need to 3D print or have a printing farm do it for you, a higher platform so the arm is free to run a full rotation. Also ensure you have enough slack cable at the hub to allow the swing arm full movement.
you will need the following items
- base x1
- motor spindle x1
- stiffener x3
- 180mm of 21.5mm overflow pipe
- some matt black paint
once you have the 3d printed parts and tube you can use super glue to create the "tripod" by assembling the parts as per the images above I used a solder rework station to soften the plastic slightly (hair dryer or kettle spout would work just as well) to make a slight bend in the tripod legs to match the angle in the stiffener arm and then glued the two parts together and then once completed spray black to make it less visible in your photos.
you will then need to upload the code for the full orb version to your arduino pro mini.