PAGES-> 1, 2, 3, 4, 5 6 <-PAGES

The Operation - Final Adjustments

There are two distinct types of sensors on this machine, limit switches and home switches. Limit switches need no adjustment and trip just before each axis reaches the end of it's travel. The home switches however, can be set to almost anywhere along the travel of an axis.

I decided to set the X and Y home switches a small distance from the end of the axis's travel. The Z axis is set at about the 2 inch mark because the Z axis does not need to have as much travel as the X and Y axis. Setting these home switches is as easy as sliding the home switch assemblys to their desired positions. Once these switches are set it's time to go into the jog menu of TurboCNC and home all the axis'.

This is where a "hitch" in the operation comes up. The way homing is supposed to work is once initiated the axis travels in the home direction until the home switch is hit, then the axis slowly backs-up until the switch is no longer closed and finally it sets the distance to 0.00000. The first part works OK, but the backing up and setting to zero never happens, it needs to be aborted to continue on with the program. I still get the axis homed, it's just that I need to manually zero out the program position counter. Also, I can't do this on all three axis simultaneously, I need to do one axis at a time. It seems plausable to me that I am doing something wrong to cause this, anyway, I'm not going to worry about it now, I will just work around the problem for now. At least the axis' home in a fashion.

With the axis' homed, I now put a small drill bit in the chuck of the Dremel tool and jogged the Z axis down to almost touch the table. Using slow jog I carefully touch and then slightly embed the drill tip into the table surface, and then back out a bit. We now have a calibration mark in the table top representing the 0,0 location. I repeat this process after moving the X axis over about 5 inches, making a X axis direction mark, re-zero the axis' and then do the same thing with the Y axis. Now, simply connect the dots with a pen or pencil and I have the alignment marks necessary to attach and align drilling fixtures.

At this point I gave the drill a little test by entering the following code in the editor and running it single cycle:

G81 X0.0 Y0.0 Z1.87 F4.0 R1.70
G81 X0.0 Y1.0
G81 X1.0 Y1.0
G81 X1.0 Y0.0
G81 X0.50 Y0.50
G80
G01 X0.0 Y0.0 F10.0
M30

What this does is to do a moc drilling of 5 holes like the spots of a 5 dice. I say moc because the drill is not turning and the depths are set higher than the table... it should take about 40 seconds to complete and put the drill back at X0.0, Y0.0 when finished.

See the "Drill Cycle Test" Movie (MP3 - 18.04Mb)

The Operation - Dolling-up the Data

The primary function I have for this CNC drill is to drill component holes in copper clad F4 .062" thick circuit boards. I am using FREEPCB layout software which outputs Excellon drill files. Unfortunately I can not feed the Excellon drill file directly to the TurboCNC software controlling the CNC drill, I will need to do some translation to a Gerber RS-274D/X file first.
The following code is an Excellon drill file that drills 4 holes at .028" diameter:

;Holesize 1 = 28.0 PLATED MILS
M48
INCH
T01C0.028
%
G05
G90
T01
X000000Y000000
X000000Y003000
X002000Y003000
X002000Y000000
M30

A lot of the information in this file is meaningless to the CNC drill. The only pertinent information is the coordinate data.
The following Perl program will translate an Excellon drill file to a Gerber RS-274D/X file:

It should be noted here that I do my programming mainly in Perl on a "live" webserver using Vi and the UNIX shell. If you have this type of environment available to you and you know how to use it, then goodie, you're all set. If not, put your programming skills to work and translate my translators to a language you know and for which you have an operating environment.

#!/usr/bin/perl
$inbuf=@ARGV[0];
if(!$inbuf){print "\nSYNTAX: convert_excellon.cgi {filename}\n\n";exit;}
open (FILE, "$inbuf");@arr=;close(FILE);
$flag = 0;
print "G90^M\n";
foreach $line (@arr){
    if(substr($line, 0,1) eq "X"){
        ($thex,$they) = split /Y/, $line;
        $thex =~ s/X//;
        $thex = $thex / 10000;
        $they = $they / 10000;
        if($flag == 1){
            print "G81 X$thex Y$they^M\n";
        }else{
            print "G81 X$thex Y$they Z-0.75 F2.0 R0.25^M\n";
            $flag = 1;
        }
    }
}
print "G80^M\n";
print "M30^M\n";

This is the bare minimum program to translate an Excellon file to a Gerber RS-274D/X file. Once you run this program using the Excellon drill file as input you will get the following output:

G90
G81 X0 Y0 Z-0.75 F2.0 R0.25
G81 X0 Y0.3
G81 X0.2 Y0.3
G81 X0.2 Y0
G80
M30

This is all you would ever need if you lived in an ideal world, which by the way, you don't. The processes of manufacturing drive special considerations which demand something a bit more powerful to translate and "process" your Excellon drill files. I only bring this up because althought the code presented above is truely a miracle of human reasoning, it does not handle things like mirroring, multiplying, stretching (yes, stretching, you heard right!) as well as being able to offset and bias.

Real World Situation ...
I sometimes make circuit patterns for quick prototype use using FreePCB and then pass it to Viewmate to examine the resultant gerber images. I also take a screen capture of the gerber image and then pass that to my laser printer that reproduces the image in ortho-film style on some sort of transparent plastic sheet... there's a bunch of these type of things. My cheap ink jet printer prints around a drum rather than runnung the sheet through flat as in more exotic units. This causes the image to be slightly stretched in the axis of the circumference ... if that makes sense? This sheet is used to contact print using simple UV and presensitized boards. The only solution to this type of thing is to have the ability to proportionally stretch each axis independently, that is if you want to get the drill through the center of every pad on the board. For these small proto boards, amazingly enough the component parts dont mind an overall board difference of up to 100 thousandths of an inch, they have that in their tolerances anyway. The main thing you dont want however is tiny little pads drilled off center. It's bad for soldering and it just plain looks bad, even on prototypes and lab stuff.

As I said, there's a whole bunch of things you need to do in the real world that the previous code does not do. That's why I wrote the following program. It comes in 2 Perl files and needs 4 other files as working buffers. Here's what it looks like when you run it from a browser:



You use this thing by pasting some Excellon code in the first window. When you click the Generate Output File button it does just that in the second window. You can use the third, or Scratch window on the right to build an output file composed of snippets of other files or translations... I use this to produce ganged patterns, it's fast and easy this way.
The following Perl code is the main display file named convert.cgi:

#!/usr/bin/perl

##################################################
# Excellon to Gerber Converter
#
# V1.0.0 (04/28/2005) by, William Stephens
#
# This software is provided free for use as
# you see fit... don't worry about any intellectual
# property rights... no one here has an intellect!
#
##################################################

open(FILE, "input_file");@inarr=<FILE>;close(FILE);
open(FILE, "output_file");@outarr=<FILE>;close(FILE);
open(FILE, "scratch_file");@scratcharr=<FILE>;close(FILE);
open(FILE, "convert_data");@arr=<FILE>;close(FILE);
$boardwidth=$arr[0];
$boardheight=$arr[1];
$flip_x_flag=$arr[2];
$flip_y_flag=$arr[3];
$offset_x=$arr[4];
$offset_y=$arr[5];
$z=$arr[6];
$f=$arr[7];
$r=$arr[8];
$bias_x=$arr[9];
$bias_y=$arr[10];
$p=$arr[11];
$stretch_x=$arr[12];
$stretch_y=$arr[13];
$f2=$arr[14];

print "Content-type: text/html\n\n";
print <<END_OF_HTML;
<HTML><HEAD><TITLE>Excellon to Gerber Converter</TITLE></HEAD><BODY>
<FORM METHOD=post NAME=form1 ACTION="convert2.cgi"><BR>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3 WIDTH=800 BGCOLOR=505050><TR><TD ALIGN=center>
<FONT FACE=arial,helvetica SIZE=2 COLOR=white><B>Excellon to Gerber RS-274D\\X File Converter V1.0.0</FONT>
</TD></TR></TABLE>
<TABLE BORDER=1 WIDTH=800 CELLSPACING=0 CELLPADDING=3 BGCOLOR=a0a0a0><TR>

<TD><FONT FACE=arial,helvetica SIZE=2>Board Width: <INPUT TYPE=text SIZE=8 NAME=boardwidth VALUE="$boardwidth"></TD>
<TD><FONT FACE=arial,helvetica SIZE=2>Flip X Axis: <INPUT TYPE=checkbox NAME=flip_x_flag></TD>
<TD><FONT FACE=arial,helvetica SIZE=2>Offset X Axis: <INPUT TYPE=text SIZE=8 NAME=offset_x VALUE="$offset_x"></TD>
<TD><FONT FACE=arial,helvetica SIZE=2>Bias X Axis: <INPUT TYPE=text SIZE=8 NAME=bias_x VALUE="$bias_x"></TD>
<TD><FONT FACE=arial,helvetica SIZE=2>Stretch X Axis: <INPUT TYPE=text SIZE=8 NAME=stretch_x VALUE="$stretch_x"></TD>
</TR><TR>
<TD><FONT FACE=arial,helvetica SIZE=2>Board Height: <INPUT TYPE=text SIZE=8 NAME=boardheight VALUE="$boardheight"></TD>
<TD><FONT FACE=arial,helvetica SIZE=2>Flip Y Axis: <INPUT TYPE=checkbox NAME=flip_y_flag></TD>
<TD><FONT FACE=arial,helvetica SIZE=2>Offset Y Axis: <INPUT TYPE=text SIZE=8 NAME=offset_y VALUE="$offset_y"></TD>
<TD><FONT FACE=arial,helvetica SIZE=2>Bias Y Axis: <INPUT TYPE=text SIZE=8 NAME=bias_y VALUE="$bias_y"></TD>
<TD><FONT FACE=arial,helvetica SIZE=2>Stretch Y Axis: <INPUT TYPE=text SIZE=8 NAME=stretch_y VALUE="$stretch_y"></TD>
</TR><TR>
<TD><FONT FACE=arial,helvetica SIZE=2>Z Depth: <INPUT TYPE=text SIZE=8 NAME=z VALUE="$z"></TD>
<TD><FONT FACE=arial,helvetica SIZE=2>R Retract: <INPUT TYPE=text SIZE=8 NAME=r VALUE="$r"></TD>
<TD><FONT FACE=arial,helvetica SIZE=2>F Feed: <INPUT TYPE=text SIZE=8 NAME=f VALUE="$f"></TD>
<TD><FONT FACE=arial,helvetica SIZE=2>T Feed: <INPUT TYPE=text SIZE=8 NAME=f2 VALUE="$f2"></TD>
<!--<TD><FONT FACE=arial,helvetica SIZE=2>Precision: <INPUT TYPE=text SIZE=8 NAME=p VALUE="$p"></TD>-->
<TD><FONT FACE=arial,helvetica SIZE=2><BR></TD>
</TR></TABLE>
<TABLE BORDER=1 WIDTH=800 CELLSPACING=0 CELLPADDING=3 BGCOLOR=c0c0c0><TR><TD>
<FONT FACE=arial,helvetica SIZE=2>Input File (Excellon Drill file):<BR>
<TEXTAREA COLS=32 ROWS=20 NAME=input_file>
END_OF_HTML
foreach $line (@inarr){
print $line;
}
print <<END_OF_HTML;
</TEXTAREA>
</TD><TD>
<FONT FACE=arial,helvetica SIZE=2>Output File (Gerber RS-274D\\X):<BR>
<TEXTAREA COLS=32 ROWS=20 NAME=output_file>
END_OF_HTML
foreach $line (@outarr){
print $line;
}
print <<END_OF_HTML;
</TEXTAREA>
</TD><TD BGCOLOR=505050>
<FONT FACE=arial,helvetica COLOR=white SIZE=2>Scratch File:<BR>
<TEXTAREA COLS=32 ROWS=20 NAME=scratch_file>
END_OF_HTML
foreach $line (@scratcharr){
print $line;
}
print <<END_OF_HTML;
</TEXTAREA>
</TD></TR></TABLE>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3 WIDTH=800 BGCOLOR=505050><TR><TD ALIGN=center>
<INPUT TYPE=submit VALUE="Generate Output File"><BR>
</TD></TR></TABLE>
</FORM>
<SCRIPT LANGUAGE=javascript>
if($flip_x_flag == true){
document.form1.flip_x_flag.checked = true;
}
else{
document.form1.flip_x_flag.checked = false;
}
if($flip_y_flag == true){
document.form1.flip_y_flag.checked = true;
}
else{
document.form1.flip_y_flag.checked = false;
}
</SCRIPT>
</BODY></HTML>

END_OF_HTML


The following Perl code is the calculating engine file named convert2.cgi:

#!/usr/bin/perl

######################################
# Excellon to Gerber Converter (file two)
#
# V1.0.0 (04/28/2005) by, William Stephens
#
# This software is provided free for use as
# you see fit... don't worry about any intellectual
# property rights... no one here has an intellect!
#
######################################

######################################
### APPLICABLE G CODES AND M CODES ###
######################################
# G01 MOVE TO COORDINATES
# G04 PAUSE
# G81 CANONICAL DRILL CYCLE
# G80 END CANONICAL DRILL CYCLE
# M03 SPINDLE ON
# M05 SPINDLE OFF
# M30 END PROCESS
######################################

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&/, $buffer);
foreach $pair (@pairs){
   ($name, $value) = split(/=/, $pair);
   $value =~ tr/+/ /;
   $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
   $FORM{$name} = $value;
}

$boardwidth = $FORM{'boardwidth'};
$boardheight = $FORM{'boardheight'};
$boardcenter_x = $boardwidth/2;
$boardcenter_y = $boardheight/2;

$flip_x_flag = $FORM{'flip_x_flag'};
if($flip_x_flag eq "on"){$flip_x_flag = "true";}else{$flip_x_flag = "false";}
$flip_y_flag = $FORM{'flip_y_flag'};
if($flip_y_flag eq "on"){$flip_y_flag = "true";}else{$flip_y_flag = "false";}

$offset_x = $FORM{'offset_x'};
$offset_y = $FORM{'offset_y'};
$bias_x = $FORM{'bias_x'};
$bias_y = $FORM{'bias_y'};
$stretch_x = $FORM{'stretch_x'};
$stretch_y = $FORM{'stretch_y'};

$z = $FORM{'z'};
$f = $FORM{'f'};
$r = $FORM{'r'};
$p = $FORM{'p'};
$f2 = $FORM{'f2'};

open(PARAMS, ">convert_data");
print PARAMS "$boardwidth\n";
print PARAMS "$boardheight\n";
print PARAMS "$flip_x_flag\n";
print PARAMS "$flip_y_flag\n";
print PARAMS "$offset_x\n";
print PARAMS "$offset_y\n";
print PARAMS "$z\n";
print PARAMS "$f\n";
print PARAMS "$r\n";
print PARAMS "$bias_x\n";
print PARAMS "$bias_y\n";
print PARAMS "$p\n";
print PARAMS "$stretch_x\n";
print PARAMS "$stretch_y\n";
print PARAMS "$f2\n";
close(PARAMS);

open(INFILE, ">input_file");
print INFILE $FORM{'input_file'};
close(INFILE);
open(SCRATCHFILE, ">scratch_file");
print SCRATCHFILE $FORM{'scratch_file'};
close(SCRATCHFILE);

# START PRINTING THE GERBER RS-274D/X .CNC FILE
open(OUTFILE, ">output_file");
print OUTFILE "G01 X$offset_x Y$offset_y Z$r F$f2 \n";
print OUTFILE "M03 \n";
print OUTFILE "G04 P2 \n";

# READ THE EXCELLON INPUT FILE
open (FILE, "input_file");@arr=;close(FILE);
$flag = 0;
foreach $line (@arr){
   if(substr($line, 0,1) eq "X"){
      ($thex,$they) = split /Y/, $line;
      $thex =~ s/X//;
      $thex = $thex / 10000;
      $they = $they / 10000;

# ADD THE BIAS VALUES
      $thex = $thex + $bias_x;
      $they = $they + $bias_y;

# MIRROR COORDINATED IN THE X AXIS
      if($flip_x_flag eq "true"){
         if($thex < $boardcenter_x){
            $xx = $boardcenter_x - $thex;
            $thex = $boardcenter_x + $xx;
         }
         elsif($thex > $boardcenter_x){
            $xx = $thex - $boardcenter_x;
            $thex = $boardcenter_x - $xx;
         }
      }

# MIRROR COORDINATES IN THE Y AXIS
      if($flip_y_flag eq "true"){
         if($they < $boardcenter_y){
            $yy = $boardcenter_y - $they;
            $they = $boardcenter_y + $yy;
         }
         elsif($they > $boardcenter_y){
            $yy = $they - $boardcenter_y;
            $they = $boardcenter_y - $yy;
         }
      }

# ADD THE STRETCH VALUES
      $thex = ($thex*($stretch_x/$boardwidth))+$thex;
      $they = ($they*($stretch_y/$boardheight))+$they;

# ADD THE OFFSET VALUES TO 4 DECIMAL PLACES
      $thex = sprintf("%.4f", ($thex + $offset_x));
      $they = sprintf("%.4f", ($they + $offset_y));

# PRINT A CANONICAL DRILL CYCLE LINE
      if($flag == 1){
         print OUTFILE "G81 X$thex Y$they \n";
      }else{
         print OUTFILE "G81 X$thex Y$they Z$z F$f R$r \n";
         $flag = 1;      
      }
   }
}

# FINISH UP PRINTING OUT STUFF
print OUTFILE "G80 \n";
print OUTFILE "M05 \n";
print OUTFILE "M30 \n";

close(OUTFILE);

print "Location: convert.cgi\n\n";

Put each of these files in the same directory and touch convert_data, input_file, output_file and scratch_file in that directory.
-rwxr-xr-x  1 www   www  3872 May  5 21:24 convert.cgi*
-rwxr-xr-x  1 www   www  3649 May  6 09:12 convert2.cgi*
-rwxrw-rw-  1 www   www     0 May  5 21:22 convert_data
-rwxrw-rw-  1 www   www     0 May  5 21:22 input_file
-rwxrw-rw-  1 www   www     0 May  5 21:22 output_file
-rwxrw-rw-  1 www   www     0 May  5 21:22 scratch_file
Your directory should look like this when you are done copying, pasting and touching. Special attention should be paid to the permissions and user/group for your server. Once this is all straight, open up "convert.cgi" using your browser and click away. It has been designed to act like a desktop application although it's really just some fancy webpages.

Although this program is actually webpages, it is not a public affair. Buffer data is stored on the server without regards to who own the data. If, for example you wanted to publish this program on the internet, it would not work properly because there are no facilities for private data, so someone in New York USA would be clobbering the programmming of another person using the program in Tokyo Japan at the same time. Re-writing the code to use local data (the users computer via cookies) would have limited success because of the 4096 byte maximum size of cookies. I'm not saying that this utility can't be re-programmed to work publicly... of course it can, it's just that lazy me is satisfied with this being a private affair for use inside of my webspace hidden away, unlinked.