Drawing with a laser

Reading Hack a Day I found an interesting challenge: drawing their logo somewhere. And the fact that was even more interesting: “preference will be given to the largest and smallest submissions“.
I started figuring out how to do something like that with the things I had around, and settled for using a laser and two servos. Even though I missed the deadline for submissions, it became a very interesting project and I learned a lot.

Part list

This is a neat list of parts I used for this project (and some links to get them).

  • Arduino UNO (R3) [Amazon | DX]
  • red laser pointer [DX]
  • 2 x TowerPro SG90 servos [Amazon | DX]
  • 6 x AA rechargeable Ni-MH batteries [DX]
  • LM2596 (voltage regulator) [DX]
  • NPN transistor (I used a C547B)
  • 270 Ω resistor
  • potentiometer
  • a tiny breadboard [DX]
  • thin cardboard
  • copper wire
  • Breadboard wires [DX]
  • a Meccano set (well, only some pieces of it) [Amazon]

I also used a Canon T2i to shoot the resulting images (long exposure).

Getting started

I built the structure using only what I had at home and because of that many design choices were governed by that. There are many ways to draw with a laser and I think the best one is using a moving mirror, but sadly I didn’t have a tiny mirror for this, so the next option was moving the laser directly. The main disadvantage of this design is that I can’t replace the laser easily, but I can live with that.
I started by cutting a piece of cardboard to fit the servo arm. Once that was done, I attached the second servo to that cardboard using a copper wire and some ninja knitting technique.

Who can make science using inches?!

Behold, the metric system! And cardboard.

My laser pointer was convenient at pointing things but not so much at being an electronic part for my project. It was inside a large cylinder and it was necesary to push a button to turn it on. The solution: a hacksaw (a tool with a cool name, by the way).


After tearing open the laser pointer I soldered two cables to the laser (bypassing the switch) and it was ready to be used.

The second servo (which holds the laser) had a cardboard piece too, but it was bulky and (more importantly) useless, so I attached the laser to the arm with high technology (masking tape).

You can't have enough masking tape in your project.

You can’t have enough masking tape in your project.

The electronics

The circuit is nothing too complicated, but there are a few important considerations: servos need more current than what Arduino can provide safely, so I had to add an external battery (6 Ni-MH batteries). This battery pack outputs 7.2V when fully charged, and goes below 4.8V when depleted. The servos need 5 volts (I don’t know exactly what tolerance they have), and I’m pretty sure that 7.2V are too much for them. To keep them at 5V all the time, I used a switching regulator (LM2956). Once set, this IC works very nice.
Now that the servos are sourcing their power from the battery pack it is important to join its ground with the GND pin of the Arduino, so the servos work with the PWM.
The laser draws 43 mA, which is over the maximum limit per pin in the Arduino. To circumvent this limitation I used a NPN transistor. The laser is connected to the Arduino +5V pin and the ground goes through the transistor. When the laser pin is set to HIGH the transistor closes the laser circuit.
A potentiometer is connected to A0 in order to manually move the servos (calibration).


Fritzing diagram

Making it move!

With this simple rig I started writing code to drive the servos and do the first tests. I promptly had my servos moving, but it was obvious that each step would be abrupt using Servo.write(). Remember that with this design I can move the laser 180° in both the X and Y axis: this means I can’t use the whole range to draw over a wall! So instead of 180 points I have… less (it depends on the distance to the wall). Setting limits to both axes solves that at the cost of less drawing points. Fortunately I learned there’s a way to handle the servos much precisely: using Servo.writeMicroseconds().

Servo movements are determined by the length of the pulse received via their signal cable using PWM. In the case of the TowerPro SG90, the acceptable values range from 600 to 2300 (I tested it). It’s not safe to drive the servos to their limits! (they will draw more current) Speaking of servos and current, according to this, servos draw more current doing small steps.


It was time to get the Hackaday logo and transform it into something Arduino could understand. My code stores drawings as an array of points. Specifically, for each point stores the laser flag (1=on, 0=off) and 0-based X and Y coordinates (no offsets). The laser flag determines the status of the laser until it reaches the corresponding coordinates. Example:
    {0, 50, 50},
    {1, 70, 50},
    {1, 50, 70},
    {1, 50, 50}

My embarrasing odyssey through file types began with the SVG file provided by Hackaday. I imported it into Adobe Illustrator and exported it to PDF. Then I went to AutoCAD and imported that PDF to re-draw it since I wanted a simpler version of the logo. All this reminded me of this XKCD comic. From AutoCAD I managed to get a TXT file with lines formated like this: X1 Y1 X2 Y2.

PythonSo I went and wrote a tiny Python program to translate those coordinates into the format my code uses. It also stretched/shrinked the image to fit the available canvas and removed any offset. The output looked promising, except for one thing: it didn’t look like it was following the path of each part of the drawing propperly. A quick test with the laser didn’t yield a good looking result. To be sure of what was going on, I wrote a Processing sketch and figured out that AutoCAD exports coordinates looking for objects using a sweep line algorithm, making my laser move like this (green lines are movements of the servos without drawing):

Your browser does not support the canvas tag.

JavaScript is required to view the contents of this page.

Yes, it’s upside down. Science isn’t about why, it’s about why not.

Though I could have made the program reorder the points, at this moment I decided it was better to make something simple and taylored to my needs. But this time I used processing. With the new script it was very easy to load the SVG as background, store the click-made path and export it to a simple TXT file (that was ready to copy and paste into the Arduino program).

Redrawing (manually) the Hackaday logo with the provided SVG as background.

Redrawing (manually) the Hackaday logo with the provided SVG as background.

Testing it with my other processing script yielded a fantastic, smooth, continuous drawing. See for youselves:

Your browser does not support the canvas tag.

JavaScript is required to view the contents of this page.

Fast and smooth. And facing down like it should.

It’s showtime!

I lost a lot of time trying to make things work using strings in Arduino. Turns out it doesn’t work so well (due to allocation problems, I think?) and I ended up rewriting every string related code to use char arrays. I also learned the wonders of using the F() helper (read about it here).
It was finally working! After some failed tests, I managed to get a picture with the logo. Success!

After 70 seconds of exposure, this was the result

After 70 seconds of exposure, this was the result

The lines are shaky for two (maybe three) reasons:

  • The servos move in steps. Even the tiny steps in a line are noticeable because with my settings the drawing space stretches across 400 points and as the laser moves away from the wall the separation between the points is bigger. They points are like pixels, in this case.
  • The laser was on an unstable surface for this photo: I had to move the whole thing to my bedroom (where there’s almost no light from outside) and the structure was over some clothes on a stool I put over my bed. The movement of the servos is probably exagerated by this. Compared with other shot, there is no notable change (it’s still shaky).
  • I may be using an inadequate algorithm to draw the lines. Instead of small steps (“pixels”) going from point A to B many times may yield better results at the cost of more movements.


I’m using serial communication to issue basic commands. I can start/stop drawing, redefine the min/max for each servo, and adjust the speed of drawing (so the camera can capture it). This allowed me to define the boundaries of the canvas (i.e. the wall) and start to draw when my camera was ready.

Using the serial monitor to control the driver.

Using the serial monitor to control the driver.

What’s next

I learned a lot by making this. These are some of the things I’d like to change in the future:

  • The line algorithm must be enhanced in some way.
  • I must redesign the frame to take advantage of the servos’ definition.
  • The laser is weak. I should use something more powerful.
  • I could store the canvas boundaries‘ variables using the EEPROMex library, so they don’t need to be entered at startup.
  • The drawing array consists of 3 integers per point. It’s a huge waste of memory, given that the coordinate values are usually below 3000 and the laser status is just a binary value. Memory usage can be optimized.
  • A physical button to start/stop drawing would be somewhat easy to add (to dispense serial communication)
  • An automatic camera trigger would be helpful. I didn’t have an opto-isolator for that.

Get the code!

I took the time to upload the code to my GitHub account. You can download the Arduino code, both Processing scripts and even the Python code I used previously from the laserdriver repository. It’s all released under the MIT license.


I want to thank Hack a day for giving me the push I needed to start this project. Also to my friends mag for his help and ideas, Valenzine for his support and encouragement through the project, and Katya for helping me fix grammatical errors in the post.
And you: thank you for taking the time to read this post.