Introduction: Your Own Laser Etcher. Cheap.

About: Recent graduate from CMU, now working at Northrop Grumman. Mostly inactive at this point, but still around occasionally.

Didn't win the laser contest? Bummer.  Well, you can still get your very own laser etcher, for next to nothing. 
This is my entrance to the epilog laser contest and arduino contest (so please vote for me), as well as my entrance to the world of home laser etching. 

This is an arduino and brushless motor-turned-galvo based etcher, which also accepts g-code files, while maintaining an easy build process and cheap materials. 

Both the hardware and software were made by me (though originally inspired by nothinglabs's project here:  https://www.instructables.com/id/Arduino-Laser-Show-with-Full-XY-Control/
Let's get started!

Step 1: Parts

To make this, you'll need a few things.  All can be bought for under $50, but should be avaliable for a lot less if you don't buy it new. 
direction:
Arduino-any flavor really.  I used UNO. 
2 small mirrors.  First-surface is best, but a regular mirror without a backing should also work if it's simply set up reflector-side out (more on this in a minute)
2 H-bridge motor drivers, must be direction-pwm type. 
2 resistors, 1k ohm
2 small LEDs, less than 20mA
2 resistors 100 ohm-1K ohm.
Laser:
laser pointer or module.  (aixiz laser modules are popular and fairly cheap)
high powered laser diode (such as blu-ray diode or DVD burner module)
driver for said laser
OR
premade laser module. 
1 transistor or relay, capable of the same current as the laser, and switchable from an arduino.  A 2n3904 will work for most laser diodes below 200mW

Step 2: The Final Material

You may have noticed that I didn't put any actuators in the materials list.  I lied.  There are some used, but they require much more explanation.  to move the laser, you will need a device called a galvonometer.  We will not be using premade galvos, as they can be upwards of a hundred dollars.  Instead, we'll use much cheaper and more common brushless DC motors. 

I know you're saying to youself, wait a second, motors aren't galvos! they have no precision and spin forever!  I'd say you're right, but we'll fix that presently.  You will need a pair of identical motors, the most important aspect of which is not power, speed, or even size.  They will need to be brushless motors, the most common source of which (and the type I highly suggest) is computer fans.  They also have the added bonus of having very low inertia, which is important.  When selecting your motors, make sure you can physically hold them before you buy/decide on them.  The motors should turn with very little force, they should feel like they're "clicking" as they turn (go for the motors with the fewest clicks), and they should spin for a second or two if you spin the fan and let go.  

The two main factors of the device decided by the motors are speed and size.  Smooth, fast motors will move quickly, and fewer "clicks" per rotation means a smaller overall device.  Keep in mind that more expensive fans may not always be better than their more cost-efficient counterparts. 

Step 3: The Build

Now, you will need to prepare your motors.  Cut off the fan blades and the housing of the motor, but do not damage the central "hub". Once you have just the cylinder that contains the motor, carefully cut off the back of it (the side not previously connected to the fan blades), making sure not to damage the coils or the brushing/bearing that extends throught the center of the circuit board, which allows the motor to spin smoothly.
Now, you need to identify the motor coil connections.  This is either very obvious, or very much the opposite, depending on the make and model of fan.  Most have three board connections, one directly to positive (or through a diode), the other two to transistors.  If you are unsure of which connections are which, check with a multimeter, the connections should have 20~50 ohms between one of the connections and positive, and twice that between each other.  Solder a wire to the poitive side of the coil , making sure it goes directly through the wire, not through a diode. 
set up your two motors at a right-angle, so that one mirror piviots up and down, and one left to right.  Then position a small laser or laser pointer so that it reflects off both mirrors, and adjust the galvo position if needed.  Do not use the high-power laser yet, as it is not needed and presents a significant risk to it and you at this stage.  

Step 4: Serial Controlled Silicon Electron Divergence Matrix (also Known As an Arduino)

This is the easiest step.  Open the arduino IDE and connect your arduino, then copy and paste the following text into the window and click "upload".  This software will be updated here as it is improved.  I am currently on revision 8.   


// Arduino laser plotter software.  Created and maintained by J Duffy (jduffy54 on instructables).  Full project and explanation
//avaliable there.
//revision 11
int stepporty = 0;
int wd = 1;
float ib = 0;
int ib1 = 0;
int ib2 = 0;
int ib3 = 0;
float iby = 0;
int iby1 = 0;
int iby2 = 0;
int iby3 = 0;
int val = 30;
int prev8 = 1;
int spy = 0;
int g = 9;
float maxx = 1;
float movefract;
float decimal = 0;
float stepsd = 0;
float stepsw = 0;
float stepsdy = 0;
float stepswy = 0;
int let = 0;
int xd = 0;
int yd = 0;
int sp = 1;
int skp = 0;
float prevx = 0;
float prevy = 0;
float distx;
float disty;
float mx = 1;
float my = 1;
float tt = 0;
int go = 0;
float del = 3;
float movedel = 20;
float printdel = 5;
void setup() {               
Serial.begin(115200);
TCCR1B &= ~(1 << CS12);
  TCCR1B  |=   (1 << CS11);
  TCCR1B &= ~(1 << CS10); 


/**********************************************************************************/
// Set pwm resolution  to mode 7 (10 bit)
/**********************************************************************************/

TCCR1B &= ~(1 << WGM13);    // Timer B clear bit 4
TCCR1B |=  (1 << WGM12);    // set bit 3

TCCR1A |= (1 << WGM11);    //  Timer A set bit 1
TCCR1A |= (1 << WGM10);    //  set bit 0


  pinMode(13, OUTPUT); 
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
    pinMode(8, INPUT);
  digitalWrite(8, HIGH);

     delay(50);

     }

void loop() {
  // digitalWrite(12, LOW);

  if (digitalRead(8) == 0){
    delay(100);
digitalWrite(11, LOW);
digitalWrite(12, LOW);
digitalWrite(10, LOW);
prev8 = 0;
    loop();
  } else {
    if (prev8 == 0){
  prev8 = 1;
    }

  if (Serial.available() > 0) {
     let = Serial.read();

    if (let == 'X'){
      digitalWrite(12, LOW);
     xmove();
    }

    if (let == 'Y'){ 
    ymove();
    }
     if (let == 'G'){
     upd();
    }
     if (let == 'F'){
     skipline();
    }

  } else {
   Serial.print(1);
   digitalWrite(12, LOW);
   delay(printdel);
  Serial.print(2);
  }
}
// pos();
}
      void skipline(){
        skp = Serial.read() - 48;
        if (skp = 1){
        //  delay(200);
        }
    loop(); 
      }


      void upd(){
        if (digitalRead(8) == 0){
    loop();////////////////////////////E-stop, stops and returns to loop();
  }
  g = Serial.read() - 48;
      // delay(10);
    if (g == 1){ 
      digitalWrite(12, HIGH);
    }else{
      if (digitalRead(8) == 0){
    loop();
  }
digitalWrite(12, LOW);
}

    loop(); 
    }

      void xmove(){
        delay(movedel);
        prevx = ib;
    ib = Serial.read() - 48;
    if (ib == -2){
      decimal = 0.1;
     // dyn = 1;
      ib = Serial.read() - 48;
    }
delay(movedel);
      if (Serial.available() > 0) {
    ib1 = Serial.read() - 48;
    if (ib1 == -2){
      decimal = 1;
  ib1 = Serial.read() - 48;
    }
      }
delay(movedel);
      if (Serial.available() > 0) {
     ib2 = Serial.read() - 48;
    if (ib2 == -2){
      decimal = 10;
   ib2 = Serial.read() - 48;
    }
      }
   delay(movedel);
      if (Serial.available() > 0) {
   ib3 = Serial.read() - 48;
    if (ib3 == -2){
      decimal = 100;
  ib3 = Serial.read() - 48;
    }
      }
      ib = (ib * decimal) + (ib1 * (decimal / 10)) + (ib2 * (decimal / 100)) + (ib3 * (decimal / 1000));
  loop(); 
  }







   void ymove(){
     if (digitalRead(8) == 0){
    loop();////////////////////////////E-stop, stops and returns to loop();
  }
    delay(movedel);
     prevy = iby;
    iby = Serial.read() - 48;
    if (iby == -2){
      decimal = 0.1;
     // dyn = 1;
      iby = Serial.read() - 48;
    }
delay(movedel);
      if (Serial.available() > 0) {
    iby1 = Serial.read() - 48;
    if (ib1 == -2){
      decimal = 1;
  iby1 = Serial.read() - 48;
    }
      }
     delay(movedel);
      if (Serial.available() > 0) {
     iby2 = Serial.read() - 48;
    if (iby2 == -2){
      decimal = 10;
   iby2 = Serial.read() - 48;
    }
      }
   delay(movedel);
      if (Serial.available() > 0) {
   iby3 = Serial.read() - 48;
    if (iby3 == -2){
      decimal = 100;
  iby3 = Serial.read() - 48;
    }
      }
      iby = (iby * decimal) + (iby1 * (decimal / 10)) + (iby2 * (decimal / 100)) + (iby3 * (decimal / 1000));  
ib = int(ib *4);
iby = int(iby * 4);
go = 0;
xd = 0;
yd = 0;
mx = abs(ib - distx);
my = abs(iby - disty);
maxx = max(mx,my);
my = my/maxx;
mx = mx/maxx;
tt = 0;
while (tt < maxx){
tt++;
pos();
   }}

   void pos(){
      if (g == 1){ 
      digitalWrite(12, HIGH);
    }
   if (distx < ib){
     distx = distx + mx;
   }
   if (distx > ib){
     distx = distx - mx;
   }
   if (disty < iby){
      disty = disty + my;
   }
   if (disty > iby){
   disty = disty - my;
   }
   delay(del);
   analogWrite(10, distx);
   analogWrite(9, disty);
   }

Step 5: Code Explanation.

Basic run down of the code, skip this if you want, it contains no steps of the actual build. 

The code starts like most others, with variable declaration. Most of these should be left alone, but three are useful to alter to calibrate your setup.  These are:
float del = 2;
float movedel = 2;
float printdel = 5;

"del" is the delay between steps of movement.  this is (inversely) the actual speed of the laser.  If this is set too low, it may cause problems in etching, or "motor fart", as I call it, where the motor makes a loud buzz for about a half a second.  Since the motor controls the laser, this is a problem.  The other two variables are used to help counter this.  

movedel is how long the program waits between recieving numbers from the serial port.  This is required, as without it, the numbers occasionally change drastically from what was sent, which poses a significant problem. 

printdel is how long the program wait between sending a "1" and "2" to processing.  I'll discuss this more in the next step.


After setting up the variables, there's an odd two lines
"TCCR1B = TCCR1B & 0b11111000 | 0x01;
TCCR2B = TCCR2B & 0b11111000 | 0x01;"
These lines increase the speed of the PWM on the output pins.  If this is not done, the speakers will oscillate with the pwm, which is normally at around 500Hz (500 oscillations per second).  These lines increase that above 20KHz (20000 oscillations per second). 

The majority of the code is just figuring out what position was sent, and turning that into a value the arduino can use.  The real code starts at the end of "ymove". 

Here, the values for X and Y (ib, and iby) are scaled to compensate for the difference of distance per angle that occours, which would stretch the image the farther it is from the center (X and Y of 100).  Then, it figures how far each step of the laser needs to be.  To do that, it first figures how far each axis must travel:
mx = abs(ib - distx);
my = abs(iby - disty);
then takes the maximum value between the two and divides them both by that value:
maxx = max(mx,my);
my = my/maxx;
mx = mx/maxx;
This results in one of the values (my or mx) being one, and the other a decimal.  
The next part uses these, as the next while statement repeats the void "pos();"  the number of times it needs to in order to move each axis the distance it needs to.   

pos(); just detrmines if the value going out to the speakers needs to go up or down, then adds or subtracts mx or my accordingly, then it writes the analog pin going to that speaker to the new, altered value, after delaying the time specified at the beginning in "del". 

Then it goes back, and does it all again.  hundreds
of times every second. 

Step 6: Upload Software

This is a much simpler software for processing, and this is what gives each line of g-code to the arduino over serial. 
You shouldn't need to alter any settings on this, except for the line second to the bottom of the setup, which is commented "change this to match the file you wish to send".  Change only the area withing the quotation marks.  This should be the name and file type of the file you wish to send, which will usually be a  .gcode file. 
This will also be updated as I work on it.  this is version 4_115200 (4th revision, 115200 baud).

import processing.serial.*;
String texts;
String strLines[];
long lines = 28;
float number;
Serial port;
int val = 1;
void setup(){
  size(640, 360);
   println(Serial.list());
  port = new Serial(this, Serial.list()[0], 115200);
strLines = loadStrings("dcoup.gcode");// change this to match the file you wish to send
println("start of send");

}
void draw(){


  if ( port.available() > 0) {
   val = port.read() - 48;      

}
  if (mousePressed && (mouseButton == LEFT))  {

    val = 1;
  }
  if (val == 1){
port.clear();

   delay(4);

   port.write(strLines[int(lines)]);
lines++;
background(128);
//texts = strLines[int(lines)];
//text(texts, 10, 10, 70, 80);
text(lines, 100, 100);
texts = strLines[int(lines)];
text(texts, 10, 10, 70, 80);
print("  ");
println(val);
print(lines);
val = 0;
  }

  if (val == 3){  //emergency-stop code, to determine which line the laser failed on
    println("STOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOP");
    val = 2;
  }
}

Step 7: Quick Code Explanation

I promise this won't be as long as the arduino explanation, so I suggest you read it just to get an understanding of what may everything means. 

After declaring the variables and starting serial, the code loads the file you chose, starting at line 28. 
strLines = loadStrings("dcoup.gcode");// change this to match the file you wish to send
The reason it starts at line 28 is that that's the first line of G-code that we care about.  The g-code making software used puts in information useful to 3D printers, but not needed here.   

It first checks to see what's on the serial port.  This is where the 1s and 2s from "printdel" from the arduino software come into play.  The arduino uses a 1 to indicate that it's ready to recieve the next coordinate, and a 2 to indicate that it is not ready to recieve coordinates.  A three means that the E-stop has been activated, and to display STOP repeatedly next to the line where this happened (for debugging purposes). 
After it recieves a line of code, it updates the display (which shows the line number, serial input, and outgoing data), and increases the line number variable by one.    

Step 8: Electronics

Most motor driver ICs will work, You do not need to use an L2619 as I did, though I like it because it has current limiting built in.   
Note than the DIRECTION pin is attahed to the PWM on the arduino, and the power/enable is held high.  This will be explained in the next step.  Make sure that your motor driver can handle the voltage and current you will be applying, otherwise you will quickly discover the joys of the magic smoke. 

Step 9: How to Make a Cheap Motor Into a Precision Instrument.

The galvonometer for this project is made from a brushless DC motor.  These DC motors work by using a series of three or more coils inside a hollow magnet.  When power is applied to a driver circuit, it powers the coils in a specific pattern which determines the direction and speed of rotation. 

By removing the circuit and powering one of the coils directly, the motor cannot turn more than 360*(1/n) degrees, where N is the number of coils.  By pulsing the power to the coil, and modulating the width of the pulse (PWM), the motor can be accurately positioned based on a single-wire signal.  The reason the motor driver must be connected to change direction and not power is that if only the power was changed, the motor would only move foward, as it lacks any force to push it back toward center.  A mechanical force (such as a rubber band) could work, but that would cause a much longer period of stabilizing after it has reached the desired point, as well as a much more pronounced alteration in linearity. 

Step 10: Slasher Movie.....of a Cad File....

To use this, you will need a g-code file.  This file contains coordinates for the laser to move to.  The current version uses the same file type as a reprap.  The program used to generate this file is slic3r, which can be downloaded at http://slic3r.org/download  Once downloaded and running, make the following setting adjustments:
Printer settings tab:
G-code flavor-RepRap (Marlin/Sprinter)
uncheck (if checked) "use relative E distances"
1 extruder
200mm x 200mm bed (~8"x~8"), (the actual size will be about 4x4, so when making your file, make it twice the size you want the final print to be.  This is done for better accuracy, as the arduino code only reads a certain number of digits, so digits of a greater value = more accuracy.) 
print center 100mmx100mm

Print settings tab:
layers and perimeters: layer height-1mm
infill: fill density-0.4, 
        fill angle 45 degrees
Skirt and Brim: all 0
Support material: uncheck if checked

I suggest saving the settings by clicking the floppy disk icon in the upper left corner. 
Now, go back to the "platter" tab, and click "Add".  
Select an STL file of your choice if you have one, if you have none, there are many avaliable at www.thingiverse.com such as this calibration block. http://www.thingiverse.com/thing:68445  This is 40x40 mm, so just scale it to 500% to get a full 200mm square.  Then, just click "export G-code".  It is very important that you do two things when saving it.  One, remember the name exactly, or write it down.  One letter or number off and it will not upload.  Two, save it in the processing folder.  Make sure it is the "inner" folder that contains all the subfolders and the .exe file of processing.  Saving it elsewhere (or not copying it somewhere within the processing folder) will prevent the sketch from finding the file, and it will not work.   






Step 11: First Movement

Now, open the processing sketch from earlier.  Type in the name of the G-code file you just made into the designated area (don't forget to put .gcode at the end).  Connect your arduino, but not the external power supply.  Run the processing sketch, and after a few seconds, you should see the LEDs on pins 10 and 11 rapidly fading in and out, and pin 13 blinking sparatically.  That means it is working, and connect the motors and power supply.  The motors should move slightly, but in-sync with the corresponding LEDs.  Now connect the low-power laser from step 2 to pin 13, and position it where you did, so that it reflects off both galvos. The dot should move about in a square, then filling it by moving back and forth on a diagonal.  If it does that, it's working! move to the next step. 

If not, then try to identify what went wrong.  If the leds are fading, check the circuit and wire connections, if the laser isn't on, check that it is connected to pin 13 and ground, and that 13 is blinking.  If it still doesn't turn on, make sure that it is a low-powered laser.  Anything greater than 5mW may damage the arduino, or at least will probably not work.  If the processing sketch isn't sending lines, make sure you have the right sketch on the arduino, and it is connected to the computer.  If you are still having a problem, shoot me a message, I'll be glad to help.     

Step 12: Boxxy

After getting all that working, I replaced the temporary setup with a more permanent one. 

It's best to keep everthing close together, and only leave openings at the new laser "aperture", or point where the moving laser will be emitted.  Make sure to use something that your laser cannot burn through.  Usually light-colored boxes or boxes the same color as the laser are best.  Plywood would be even better.  Make sure all the parts are secured well, as this will be flipped upside-down. 

Step 13: Burn, Baby Burn. Disco-inferno Style.

Now comes the dangerous part, the real laser.  Make sure to mark off the area that the laser can reach, plus a little extra, and place a backing that the laser cannot penetrate behind this.  Do not use a white surface, as this will make it very, VERY dangerous to be around.  I suggest black, spray-painted plywood.  

Now, disconnect ALL sources of power (usb included) and attach the laser to the relay or transistor (whichever you picked), and mount it exactly where the low power laser was.  The following step is the single most important step in the whole build: Put on your laser glasses*.  Don't have any?  Stop NOW and go buy some.  Seriously, if you don't have these, dont even considder adding power to this.  You WILL damage your eyes.  If you have laser glasses on, then tape a piece of black construction paper (on all sides) to the backing, roughly centered where the laser will be.  Stand away from the laser path and connect usb and external power.  Run the calibration cube, and after focusing the laser, let it run until it has cut or marked a square in the paper.  If it moves too fast for your laser, increase "del" in the arduino sketch until it is slow enough, and re-upload it.  Finially, mark the outside of the square that was cut, and measure it.  adjust the height / distance of the laser assembly to the target until it is 200mm. 

Once it's to size, congratulations, you just made a laser engraver!
Thanks for reading, and don't forget to vote for me in the laser contest!


To cut/etch other files, I suggest getting sketchup, which is a free CAD software from google avaliable here http://www.sketchup.com/intl/en/product/gsu.html    There is a plugin for it that allows you to export .stl files that are ready to send to the laser (after running through slic3r) avaliable at  http://www.guitar-list.com/download-software/convert-sketchup-skp-files-dxf-or-stl   (watch out for the fake "download" ad at the top of the page The real download link is text)..  I also suggest sending the files through Netfabb if slic3r says its not manifold (http://cloud.netfabb.com).   Alternatively, just download files from thingiverse.com

*A final note on safety: Be safe! NEVER connect any power unless you have laser glasses on, rated for the power and wavelength of your laser.  If you have any doubts on anything, stop and check first.  Lasers powerful enough to burn are very dangerous, and WILL blind you permanently if you are not careful.  Never operate this if there is a risk of someone entering the area it is in or looking even the reflected beam.  Never operate it near windows, outdoors, or in any area with any living thing without glasses.  
I assume no responsibily if you hurt yourself, anyone, or anything else.  The safety of this device is in your hands. 

Pocket Sized Electronics

Participated in the
Pocket Sized Electronics

Epilog Challenge V

Participated in the
Epilog Challenge V

Arduino Contest

Participated in the
Arduino Contest