PC CONTROLLED ENGRAVING MACHINE


A few years ago I made a computer controlled machine to engrave a sundial with a special kind of hour line called an analemma.
To remind myself what I did, and to share with anyone who may be interested, I decided to record the details on a web page.

The machine was designed to be cheaply made in a home workshop equipped with a lathe, drilling machine and a selection of hand tools.

   X axis trolley
Detail view showing the 'x' axis trolley, the 'z' axis is not fitted in this picture.
A full picture of the machine can be seen further down this page.

M.D.F chipboard was chosen for the base board, this floor grade material is sufficiently stable for the job, and looks nice when its varnished!

For the slides to create the 'x' and 'y' axis, I used 1 inch (25.4mm) diameter seamless mild steel tubing.
The moving elements, made mostly from aluminium, are guided along the tubes by ball races arranged round the tubes as guide rollers.

Two parallel tubes form the 'y' axis, and two more tubes forming a travelling bridge run on the 'y' axis tubes.

A trolley running along the travelling bridge forms the 'x' axis, this in turn carries the vertical 'z' axis.

Drive is by stepper motors, each motor turns a 12mm diameter threaded bar, with corresponding M12 threaded nuts attached to the moving elements , except for the 'z' axis, which is raised and lowered manually.

The problem of ensuring the 'x' axis bridge stayed square to the 'y' axis bars was solved by each 'y' axis guide bar having it's own motor and threaded bar. The two motors are only synchronised electrically, there is no mechanical connection between the two.


Connection to the computer is made via the parallel printer port.
   Engraving the sundial
Detail view showing the partially engraved grey slate sundial.

The port connects to a circuit board that displays the status of the port's outputs on 8 led's. These outputs are also taken from the board's switching transistors to a 9-way 'D' socket, and this in turn taken to extra output transistors that are capable of carrying the current required to power the stepper motors.
The 'y' axis and 'x' axis motors use 4 of the 8 available outputs each.


Control software was written in Qbasic for DOS. The full program can be seen in the column to the right of this page.

To create the analemma profiles for the sundial, the profile 'x' and 'y' values are calculated by another program that is not described here, and the profile is read into the machine control program.
The control program also allows input in the form of 'x','y' coordinates from the keyboard, movement from the keyboard arrow keys and the profile of a circle from a specified radius.
At the end of each profile the 'z' axis that holds the engraving stylus has to be raised and lowered manually from screen 'pen up' and 'pen down' instructions as dictated by the profile.

The program sends motor step instruction as a series 'LPRINT' commands that are received by the motor electronics from the parallel port.

Links. Please feel free to email if you have any questions. The finished sundial can be seen on the Derbyshire Sundials site. http://www.pandy.me.uk/sundials/pdsdials.htm

To see how stepper motors work have a look at the Wikipedia stepper motor page.



Engraving machine
The base board size is 42" x 36" (1066mm x 914mm). Each 'y' axis screw is directly connected to its motor, and the 'x' axis screw is connected with a timing belt. The 'z' axis is not fitted on this picture, just a pen holder for trial purposes.

First version 2 January 2005
This update 13 July 2012

DECLARE SUB Ring ()
DECLARE SUB Readme ()
DECLARE SUB control ()
DECLARE SUB Fileplot ()
DECLARE SUB Keydrive ()
DECLARE SUB Menudisp ()
DECLARE SUB Stepdrive ()
DECLARE SUB Filein ()
DECLARE SUB Delay ()
'***********************
'Title "STEPOUT"
'Version 1.4 7-1-95....Circle added
'Description - input motor steps and output to stepper driver
'Written P.L.Daykin Nov 93
'QBASIC
'***********************
DECLARE SUB Xmax270 ()
DECLARE SUB Xmax360 ()
DECLARE SUB Ymax270 ()
DECLARE SUB Ymax360 ()
DECLARE SUB Xmax180 ()
DECLARE SUB Ymax180 ()
DECLARE SUB Testquad ()
DECLARE SUB Quadout180y ()
DECLARE SUB Quadout270y ()
DECLARE SUB Quadout360y ()
DECLARE SUB Ymax90 ()
DECLARE SUB Quadout90y ()
DECLARE SUB Xmax90 ()
DECLARE SUB Quadout90xy ()
DECLARE SUB Quadout90x ()
DECLARE SUB Quadout180xy ()
DECLARE SUB Quadout180x ()
DECLARE SUB Quadout270xy ()
DECLARE SUB Quadout270x ()
DECLARE SUB Quadout360xy ()
DECLARE SUB Quadout360x ()
DEFSNG A-Z
DIM SHARED xinc
DIM SHARED yinc
DIM SHARED xprev
DIM SHARED yprev
DIM SHARED c
DIM SHARED a(367, 3)
DO
'LPRINT CHR$(0)
CALL Menudisp
LOCATE 19, 35: INPUT "Item "; item
IF item = 1 THEN
CALL Keydrive
ELSEIF item = 2 THEN
CALL Stepdrive
ELSEIF item = 3 THEN
CALL Filein
ELSEIF item = 4 THEN
CALL Fileplot
ELSEIF item = 5 THEN
LPRINT CHR$(0)
ELSEIF item = 6 THEN
CALL Ring
ELSEIF item = 7 THEN
CALL Readme
END IF
LOOP
END
SUB control
DIM p AS STRING
IF c = 99 THEN
EXIT SUB
ELSEIF c = 71 THEN
EXIT SUB
ELSEIF c = 73 THEN
PRINT "*** PEN UP ***"
ELSEIF c = 81 THEN
PRINT "*** PEN DOWN ***"
END IF
LPRINT CHR$(0)
PRINT "Press enter"
p = INPUT$(1)
END SUB
SUB Delay
DIM n AS INTEGER
speed = 250
FOR n = 1 TO speed
NEXT n
END SUB
SUB Filein
DIM F AS STRING
DIM n AS INTEGER
DIM filenum AS INTEGER
CLS
INPUT "Filename..in inverted commas "; F
OPEN "I", #1, F
DO
n = n + 1
INPUT #1, a(n, 1)'----xabs
INPUT #1, a(n, 2)'----yabs
INPUT #1, a(n, 3)'----control number 73 pen up 81 pen down
LOOP UNTIL a(n, 3) = 71
CLOSE
'SLEEP 0
END SUB
SUB Fileplot
DIM p AS STRING
CLS
scale = 2
xdatumshift = 0
ydatumshift = 0
n = 1
xinc = INT((a(1, 1) + xdatumshift) * scale)'--first move from
yinc = INT((a(1, 2) + ydatumshift) * scale)'-- x y zero
c = a(1, 3)
xinctot = xinc
yinctot = yinc
CALL Testquad
CALL control'------------pen control
DO
n = n + 1
ink$ = INKEY$
IF ink$ <> "" THEN
PRINT "** PEN UP ** back to x y zero"
p = INPUT$(1)
xinc = 0 - xinctot
yinc = 0 - yinctot
CALL Testquad
EXIT DO
END IF
xabs = (a(n, 1) + xdatumshift) * scale
yabs = (a(n, 2) + ydatumshift) * scale
c = a(n, 3)
IF c = 71 THEN
PRINT "*** HOME / PEN UP *** press enter"
p = INPUT$(1)
END IF
xinc = INT(xabs) - xinctot
yinc = INT(yabs) - yinctot
xinctot = xinc + xinctot
yinctot = yinc + yinctot
CALL Testquad
CALL control
PRINT , " n "; n, "xinc "; xinc, "yinc "; yinc, "control "; c
LOOP UNTIL c = 71
PRINT : LPRINT CHR$(0)
PRINT "Press enter.... run complete"
p = INPUT$(1)
END SUB
SUB Keydrive
DIM k AS STRING
DIM scancode AS INTEGER
CLS
PRINT "Press escape to exit"
DO
DO
k = INKEY$
LOOP UNTIL k <> ""
IF LEN(k) = 1 THEN
IF k <> CHR$(27) THEN
PRINT "You entered "; k
END IF
ELSE
scancode = ASC(MID$(k, 2, 1))
SELECT CASE scancode
CASE 72
CALL Quadout90y'---------------------Up arrow
yprev = yprev + 1
CASE 80
CALL Quadout270y'--------------------Down arrow
yprev = yprev - 1
CASE 75
CALL Quadout180x'--------------------Left arrow
xprev = xprev - 1
CASE 77
CALL Quadout90x'---------------------Right arrow
xprev = xprev + 1
END SELECT
END IF
LOOP UNTIL k = CHR$(27)
END SUB
SUB Menudisp '*********************************************
SCREEN 9: COLOR 14, 1: CLS
LINE (5, 7)-(635, 335), , B
LOCATE 1, 28: PRINT "** X Y Drive control **"
COLOR 11, 1
LOCATE 5, 32: PRINT "1) Keydrive"
LOCATE 7, 32: PRINT "2) Stepdrive"
LOCATE 9, 32: PRINT "3) Input file"
LOCATE 11, 32: PRINT "4) Plot file"
LOCATE 13, 32: PRINT "5) Power off"
LOCATE 15, 32: PRINT "6) Circle"
LOCATE 17, 32: PRINT "7) Info'"
END SUB
SUB Quadout180x
LPRINT CHR$(6)
CALL Delay
LPRINT CHR$(10)
CALL Delay
LPRINT CHR$(9)
CALL Delay
LPRINT CHR$(5)
PRINT "Quadout180x"
END SUB
SUB Quadout180xy
LPRINT CHR$(102)
CALL Delay
LPRINT CHR$(170)
CALL Delay
LPRINT CHR$(153)
CALL Delay
LPRINT CHR$(85)
PRINT "Quadout180xy"
END SUB
SUB Quadout270xy
LPRINT CHR$(150)
CALL Delay
LPRINT CHR$(170)
CALL Delay
LPRINT CHR$(105)
CALL Delay
LPRINT CHR$(85)
PRINT "Quadout270xy"
END SUB
SUB Quadout270y
LPRINT CHR$(144)
CALL Delay
LPRINT CHR$(160)
CALL Delay
LPRINT CHR$(96)
CALL Delay
LPRINT CHR$(80)
PRINT "Quadout270y"
END SUB
SUB Quadout360xy
LPRINT CHR$(153)
CALL Delay
LPRINT CHR$(170)
CALL Delay
LPRINT CHR$(102)
CALL Delay
LPRINT CHR$(85)
PRINT "Quadout360xy"
END SUB
SUB Quadout90x
LPRINT CHR$(9)
CALL Delay
LPRINT CHR$(10)
CALL Delay
LPRINT CHR$(6)
CALL Delay
LPRINT CHR$(5)
PRINT "Quadout90x"
END SUB
SUB Quadout90xy
LPRINT CHR$(105)
CALL Delay
LPRINT CHR$(170)
CALL Delay
LPRINT CHR$(150)
CALL Delay
LPRINT CHR$(85)
PRINT "Quadout90xy"
END SUB
SUB Quadout90y
LPRINT CHR$(96)
CALL Delay
LPRINT CHR$(160)
CALL Delay
LPRINT CHR$(144)
CALL Delay
LPRINT CHR$(80)
PRINT "Quadout90y"
END SUB
SUB Readme
CLS
PRINT "Keydrive will move x and y axis by using the keyboard arrow keys."
PRINT
PRINT "Stepdrive uses input in motor steps, 1*4 steps = 1.75mm/12 = 0.1458mm"
PRINT "or 0.00574 inch. Note that Stepdrive works in absolute, the x y zero "
PRINT "position for both Stepdrive and Keydrive is set from Stepdrive after"
PRINT "moving to the required position."
PRINT
PRINT "Filein reads in from the disc drive included in the file spec'."
PRINT
PRINT "Fileplot moves x and y axis to the data in Filein, including onscreen"
PRINT "instructions for pen up/down. If escape is pressed in cycle, the axis"
PRINT "move back to x y zero. X y zero is taken from the position of the axis"
PRINT "at cycle start, and is independant of Stepdrive x y zero."
PRINT
PRINT "Move the axis round before inputting the file to settle the motors."
PRINT
PRINT "Circle draws with centre at x y zero, and pen down is at 3 o'clock."
PRINT
PRINT TAB(25); "***Press esc' to exit***"
DO
k$ = INKEY$
LOOP UNTIL k$ = CHR$(27)
END SUB
SUB Ring
CLS
DIM p AS STRING
ppi = 8 * ATN(1)
s = ppi / 1440
rad = 174
PRINT "Rad is set at "; rad; " this gives a rad of 1 inch"
INPUT "Alter rad ? Y \ N "; a$
IF a$ = "y" THEN
INPUT "New rad "; rad
ELSEIF a$ = "Y" THEN
INPUT "New rad "; rad
END IF
PRINT
PRINT "x , y zero is at circle centre."
PRINT "Press escape to return"
PRINT
PRINT "***PEN UP*** press enter"
p = INPUT$(1)
xinc = rad
yinc = 0
xinctot = xinc
yinctot = yinc
CALL Testquad
PRINT "***PEN DOWN*** press enter"
p = INPUT$(1)
FOR n = 0 TO ppi STEP s
ink$ = INKEY$
IF ink$ <> "" THEN
PRINT "***PEN UP*** press enter"
p = INPUT$(1)
xinc = 0 - xinctot
yinc = 0 - yinctot
CALL Testquad
EXIT SUB
END IF
xabs = COS(n) * rad
yabs = SIN(n) * rad
xinc = INT(xabs) - xinctot
yinc = INT(yabs) - yinctot
xinctot = xinc + xinctot
yinctot = yinc + yinctot
CALL Testquad
NEXT n
PRINT "***PEN UP*** press enter"
p = INPUT$(1)
xinc = 0 - xinctot
yinc = 0 - yinctot
CALL Testquad
LPRINT CHR$(0)
PRINT "Press enter.... run complete"
p = INPUT$(1)
END SUB
SUB Stepdrive
DIM k AS STRING
CLS
DO
LPRINT CHR$(0)
PRINT "***************"
INPUT " Q to quit or Z to zero x and y "; k
IF k = LCASE$("q") THEN
EXIT SUB
ELSEIF k = LCASE$("z") THEN
xabs = 0: yabs = 0: xprev = 0: yprev = 0
PRINT "x and y now at zero for Keydrive and Stepdrive"
END IF
PRINT
INPUT "xabsolute "; xabs
PRINT
INPUT "yabsolute "; yabs
PRINT
xinc = xabs - xprev
yinc = yabs - yprev
xprev = xabs
yprev = yabs
CALL Testquad
LOOP
END SUB
SUB Testquad
IF xinc >= 0 AND yinc >= 0 THEN '--------test for quadrant
quad = 90
ELSEIF xinc < 0 AND yinc >= 0 THEN
quad = 180
ELSEIF xinc <= 0 AND yinc < 0 THEN
quad = 270
ELSEIF xinc > 0 AND yinc < 0 THEN
quad = 360
ELSE
PRINT "Test for quadrant fault"
END IF
xinc = ABS(xinc)'----------remove minus sign if present
yinc = ABS(yinc)
IF xinc >= yinc AND quad = 90 THEN '-----test for Xmax90 etc
CALL Xmax90
ELSEIF yinc >= xinc AND quad = 90 THEN
CALL Ymax90
EXIT SUB
END IF
IF xinc >= yinc AND quad = 180 THEN '-----test for Xmax180
CALL Xmax180
ELSEIF yinc >= xinc AND quad = 180 THEN
CALL Ymax180
EXIT SUB
END IF
IF xinc >= yinc AND quad = 270 THEN '-----test for Xmax270
CALL Xmax270
ELSEIF yinc >= xinc AND quad = 270 THEN
CALL Ymax270
EXIT SUB
END IF
IF xinc >= yinc AND quad = 360 THEN '-----test for Ymax360
CALL Xmax360
ELSEIF yinc >= xinc AND quad = 360 THEN
CALL Ymax360
END IF
END SUB
SUB Xmax180
'Stepper x y linear interpolation
IF yinc = 0 THEN
mult = xinc
GOTO X180
END IF
mult = xinc / yinc - .001
X180: ystep = 1
FOR xstep = 1 TO xinc
IF (ystep * mult) < xstep THEN
ystep = ystep + 1
CALL Quadout180xy
ELSE CALL Quadout180x
END IF
NEXT
END SUB
SUB Xmax270
'Stepper x y linear interpolation
mult = xinc / yinc - .001
ystep = 1
FOR xstep = 1 TO xinc
IF (ystep * mult) < xstep THEN
ystep = ystep + 1
CALL Quadout270xy
ELSE CALL Quadout180x
END IF
NEXT
END SUB
SUB Xmax360
'Stepper x y linear interpolation
mult = xinc / yinc - .001
ystep = 1
FOR xstep = 1 TO xinc
IF (ystep * mult) < xstep THEN
ystep = ystep + 1
CALL Quadout360xy
ELSE CALL Quadout90x
END IF
NEXT
END SUB
SUB Xmax90
'Stepper x y linear interpolation
IF yinc = 0 THEN
mult = xinc
GOTO X90
END IF
mult = xinc / yinc - .001
X90: ystep = 1
FOR xstep = 1 TO xinc
IF (ystep * mult) < xstep THEN
ystep = ystep + 1
CALL Quadout90xy
ELSE CALL Quadout90x
END IF
NEXT
END SUB
SUB Ymax180
'Stepper x y linear interpolation
mult = yinc / xinc - .001
xstep = 1
FOR ystep = 1 TO yinc
IF (xstep * mult) < ystep THEN
xstep = xstep + 1
CALL Quadout180xy
ELSE CALL Quadout90y
END IF
NEXT
END SUB
SUB Ymax270
'Stepper x y linear interpolation
IF xinc = 0 THEN
mult = yinc
GOTO Y270
END IF
mult = yinc / xinc - .001
Y270: xstep = 1
FOR ystep = 1 TO yinc
IF (xstep * mult) < ystep THEN
xstep = xstep + 1
CALL Quadout270xy
ELSE CALL Quadout270y
END IF
NEXT
END SUB
SUB Ymax360
'Stepper x y linear interpolation
mult = yinc / xinc - .001
xstep = 1
FOR ystep = 1 TO yinc
IF (xstep * mult) < ystep THEN
xstep = xstep + 1
CALL Quadout360xy
ELSE CALL Quadout270y
END IF
NEXT
END SUB
SUB Ymax90
'Stepper x y linear interpolation
IF xinc = 0 THEN
mult = yinc
GOTO Y90
END IF
mult = yinc / xinc - .001
Y90: xstep = 1
FOR ystep = 1 TO yinc
IF (xstep * mult) < ystep THEN
xstep = xstep + 1
CALL Quadout90xy
ELSE CALL Quadout90y
END IF
NEXT
END SUB