Introduction: 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
Step 1: 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".
Step 2: 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.
Step 3: 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
Attachments
Step 4: As Requested Images of the Completed Robot
This is what you should have having got to this point, congratulations!
Step 5: 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 toset 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!
Step 6: 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.

Second Prize in the
LED Contest 2017

Participated in the
Arduino Contest 2017

Participated in the
Wheels Contest 2017
62 Comments
Question 2 years ago on Step 5
Hi. Thanks for the instructable, I've more or less completed it and I'm wanting to take it a bit further with my own animations. When programming new routines for the robot how does the code for the position relate to the number of steps that the motor is required to make? The 28byj stepper is 4096 Half steps or 2048 full steps and I'm finding it difficult to understand the 2200 steps listed in the code for a full rotation.
Question 4 years ago on Introduction
Hi, thank you for the inspiring instuctable! I'm hoping to have a go at this with my 10 year old son. Apologies if this is rather a basic question but can I ask what wire and connectors you used? Many thanks.
Answer 4 years ago
that would be awesome i would love to see the fruits of your labours with him. im happy to answer any questions you may have just fire away. the wires i used where from an old central heating boilers control system but any small wires similar to the type supplied with most arduino starter kits will do you just need them to be long enough to run the length of the rotating arm.
Reply 4 years ago
Thank you so much for getting back to me. We have an Arduino starter kit so hopefully we’ll be okay to get started. Will print the parts tomorrow and let you know how we get on! May be back to ask more questions if we get stuck.
5 years ago on Step 6
hi i have made this and also a new 3d case to enclose everything in, but i am wondering how hard would it be to change the code to use Nema 17 stepper motors with easy drivers.
i am newish to arduino so just wondering if you could point me in the right direction,
Reply 5 years ago
wow im glad you managed to follow my guide and even create your own light painting design for your robot to paint. you look like you have the foundation of programming the moves so adapting my code for the nema 17 steppers and associated drivers shouldn't be too much of a challenge. this video should give you an idea of the difference between the two types of motors, control requirements and arduino code. changing the code once you understand the principals should be fairly simple give it a go and if you need assistance give me a poke ill be happy to help. i would be interested in seeing an image of your completed robot this one and the nema 17 one.
https://www.youtube.com/watch?v=0qwrnUeSpYQ
Regards
Alan
Reply 5 years ago
hi mate i know your a busy man, i am getting stuck trying to use my Nema motors, is there any chance that you might make the code anytime soon. i am more than happy to trade you code skill for my finished design for the casing unit :)
Reply 5 years ago
Sorry Andreas been busy web server died and had to rebuilt then with my pc acting as a temporary web server while i fixed that it decided to throw a fit and blow a hard drive and take out my ssd i haven't stopped just looked at my code and the libraries i used and it should be a case of telling my code you are using nema 17 steppers and a4988 driver modules and it should work as is with no other modifications (may have to adjust step distance in each animation).
replace
with
you need to set the pin numbers you have chosen as your arduino step and direction output pins in the code example above. and you may have to adjust the max speed and acceleration in the setup part of the program to suit your application.
Reply 5 years ago
i will be giving it another try today, not sure why it puzzles me so much, i am not the best arduino programmer but am getting there lol slowwwlyy
:)
Reply 5 years ago
Hi thanks for sharing your code i have uploaded the case design i used for my version.
Reply 5 years ago
yeah not a problem i will give it a try, i will send over the stl file if you want to use it, i am not to bad with arduino its trying to understand it all with everything else i do, plus trying to find the time with 3 kids lol
thanks for this and your guide was very easy to follow.
i do have a great idea for this if you want to chat further,
5 years ago
Nice robot. I build something like that a bit larger a few years ago but never made it into a project. Hardest part was the weight of the arm, somehow those small steppers you used didn't have enough power to lift it and once it was up it crashed down real fast on the other side.
Maybe setting of the drivers were wrong, did you have similar issues?
Reply 5 years ago
you need to be careful that the firing order for the pins is correct if out of order the torque will be greatly reduced and it will not reverse. the coils fire out of sequence so if you had used pins 3,4,5 and 6 the firing order would most likely be 3,5,4,6 this is the order in which you pins need to be declared in your sketch eg:
AccelStepper stepper1(AccelStepper::FULL4WIRE, 2, 4, 3, 5);
AccelStepper stepper2(AccelStepper::FULL4WIRE, 6, 8, 7, 9);
Reply 5 years ago
I know, did some extensive playing around with those steppers.
Ended up using NEMA17 ones because had some still in the shelve. Was able to build an aluminium frame and an arm with around 40cm reach. Made some larger orbs possible.
Reply 5 years ago
do you have the code i could look at that you used please i am trying to get it to work with nema steppers with no joy.
Reply 5 years ago
Would have to dig into backups to find it, this was a long time ago. But I used A4988 stepper drivers. Just need to set them to the correct microstepping, then put the direction pin on high or low to set direction and pulse the step pin. Should be quite easy. There is also a good stepper library that is easy to use, check out the libraries on arduino homepage.
Reply 5 years ago
Hi thanks for your quick reply, i have been looking but cant seem to get my head round it at the moment, i am using the sparkfun control board.
Reply 5 years ago
Well found some of the code, but it is as I described above. Those stepper drivers have some pins to set microstep mode, one for direction and one to do the steps.
Stepp code was this:
int turnStep = A0;
int turnDir = A1;
int turnSpeed = 12;
void turnByVal(int xw){
boolean posMove = xw >0;
if (xw >0) {
digitalWrite(turnDir, HIGH);
}
else {
digitalWrite(turnDir, LOW);
}
for (int x=0;x<abs(xw);x++){
digitalWrite(turnStep, HIGH);
//delay(1);
digitalWrite(turnStep, LOW);
delay(turnSpeed);
}
}
Setting the microsteps this:
int enableStepperPin = 2;
int m1Pin = 3;
int m2Pin = 4;
int m3Pin = 5;
void setStepSize(int stepSize) {
switch(stepSize) {
case 1:
{
// Full Step
digitalWrite(m1Pin, LOW);
digitalWrite(m2Pin, LOW);
digitalWrite(m3Pin, LOW);
break;
}
case 2:
{
// Half Step
digitalWrite(m1Pin, HIGH);
digitalWrite(m2Pin, LOW);
digitalWrite(m3Pin, LOW);
break;
}
case 3:
{
// 1/4 Step
digitalWrite(m1Pin, LOW);
digitalWrite(m2Pin, HIGH);
digitalWrite(m3Pin, LOW);
break;
}
case 4:
{
// 1/8 Step
digitalWrite(m1Pin, HIGH);
digitalWrite(m2Pin, HIGH);
digitalWrite(m3Pin, LOW);
break;
}
case 5:
{
// 1/16 Step
digitalWrite(m1Pin, LOW);
digitalWrite(m2Pin, LOW);
digitalWrite(m3Pin, HIGH);
break;
}
case 6:
{
// 1/32 Step
digitalWrite(m1Pin, HIGH);
digitalWrite(m2Pin, LOW);
digitalWrite(m3Pin, HIGH);
break;
}
}
}
Just put the relevant outputs on the pins of the driver and should work.
Reply 5 years ago
know i am pushing it but any chance of the full code, dont mean to be cheeky but i cant seem to get it to work
Reply 5 years ago
Wouldn't help much. There is so much other stuff in it that would only be in the way, was complete communication using bluetooth to remote control the thing and more stuff.
The parts I posted are essentially those that control the movement. Just put the outputs on the right pins of the controllers and call the function, should work then. If it doesn't there is most likely an issue with the wiring. Can put an LED on the step output and increase the delay time to check if signal is send to the driver.