Light Painting Robot

17,260

197

52

Posted in TechnologyArduino

Introduction: Light Painting Robot

About: my main interest is in photography, but i like to tinker and Arduino has opened many more options for creating electronics projects I could have not even imagined in my younger years. it also allows me to gi...

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.

  1. 28byj-48 stepper motor x2
  2. Uln2003 Driver Module x2
  3. Arduino pro mini (5v) x1
  4. Infrared Remote Control Set x1 (pick a remote with as many buttons as possible you will need them all)
  5. Ch340g Usb To Serial Module x1
  6. Neopixel led x4
  7. Small USB power bank
  8. 3d printed parts from files included or parts made of wood etc
LED Contest 2017

Second Prize in the
LED Contest 2017

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

  1. the Body / motor housing
  2. Robot arm
  3. 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

  1. accelstepper
  2. multistepper (part of accelstepper)
  3. Adafruit neopixel
  4. 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

  1. cleaned up code to make it easier to understand and customise with own animations
  2. added adjustment of Neopixels brightness in 5 increments
  3. added optional nucleus LED's
  4. increased speed and acceleration to help with exposure

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

  1. base x1
  2. motor spindle x1
  3. stiffener x3
  4. 180mm of 21.5mm overflow pipe
  5. 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.

Share

    Recommendations

    • Microcontroller Contest

      Microcontroller Contest
    • Space Challenge

      Space Challenge
    • Science of Cooking

      Science of Cooking
    user

    We have a be nice policy.
    Please be positive and constructive.

    Tips

    Questions

    52 Comments

    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?

    19 replies

    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);

    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.

    15-09-16_0003_01_k.JPG

    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.

    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.

    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.

    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.

    thanks for the code but i am at a loss how to add it into this current code, i will have to up my coding skills and fast i think, but if anyone can help me along i am happy to pay for your time.

    i will give it a try as soon as i get in, if it works i will credit your bit of code,

    thanks for helping

    thanks for the code but i am at a loss how to add it into this current code, i will have to up my coding skills and fast i think, but if anyone can help me along i am happy to pay for your time.

    awesome i have thought about up scaling it a bit as well as altering the design to create full orbs as well my idea was to use it to create multiple half orbs like bubbles sitting on the ground and connecting them with light "wires" just need a location to play

    Was not able to get a full orb. What you see up there is the maximum I could get at the bottom. Partly because arm was longer then the height of the robot tower. Could have been better designed, but I wanted the longer arm. Speed was an issue, think that orb there took 5 minutes. Well it was programmed to be controllable using serial communication over bluetooth, that was one part that took some speed. Other was that I had not developed a proper code at that time. Would have been better to work with acceleration to get some more speed. Or add a gear box.

    yes i had given this some thought as well there would always be a small area that could not be covered at the bottom and my main concern is stability. as you can see in some of the images the lines are not always perfectly formed and having the whole rig spinning around on a narrow shaft even as light as it is would be likely to create inconsistencies my original design was supposed to over come. having said that the hand made orbs are not a complete circle.

    Haha yes, hand made ones are sometimes only 180° depending on the type. Several years light painting experience. ;)
    I used one of those bearings that go under furniture. Around 30cm diameter with a hole in the middle that was perfect for the stepper. Added quite some stability.

    I have two of the steppers in this project and it is insanely hard to force the shafts to move without power, and they also are super slow. I think maybe yours were a different model in the same casing? And if not, maybe the interior gearing was broken? IDK. I doubt it would be a settings issue, though. At the fastest I can barely get 25 RPM out of mine, and that's when I hack the settings and start to overheat the drivers. I've heard of people having issues with these being really weak, especially when it comes to 3D printers, but I think it's because they are getting cheaper ones where the gearing isn't correct or the seller put the wrong model number on them.

    indeed the gearbox ratio multiplies the torque as well and i believe the ratio on these motors is 64 to 1 so turning the arm without power is quite difficult and while powered correctly very difficult and that can be a problem especially in this case as i want the robot to complete its animation in around 30 seconds and the slower i go with it the more i have to close the aperture down on the camera to avoid over exposing the light trails. i have increased the motor speed in my latest code to help with this but i think im getting close to max speed of the motor however it does work as it is.

    Yeah... Have you considered using metal-gear high-torque hobby servos? They are more expensive than these steppers but I would say they are almost twice as fast with similar precision and power.

    Servos usually only have 180° working area. Would work great, my first experiments were with those. But wanted to have more then the 180°. And once you modify them to have full 360° you loose the precision control and need to add a decoder or something like that to know where the arm currently is.

    Or you can buy continuous rotation servos that are meant to be precise throughout a full rotation. They are similar to steppers but smaller, faster, louder, and weaker. These are what I'm thinking of if you are wondering.

    Continuous rotation servos are never precise. You can't tell them to go to a specific point/angle. You can just set the turn speed in one or the other direction. Once you mod a servo to have continuous rotation you disable the internal decoder and loose the ability to set a precise angle on them.
    The only servos that exist with more then 180° rotation are some servos used in model boats for the anchors. Those can have 2-5x360° rotation. But they are not really strong and not really precise and more, because you just spread the control range from 180° to a bigger angle so difference between each control step gets larger.