Once again I’m planning to attend the Cabin Fever Expo in York; my shop assistant says this year she won’t barf in the kitchen sink Thursday evening just before bedtime…
If I’m going to haul a Sherline CNC setup that far and spend all day talking machining, I must have some tchotchkes / swag to talk about. We figured a small plastic dog tag with relevant URLs would be appropriate.

I modeled the tag after my father’s WWII tag, including the mysterious notch. The rounded ends actually have three curves: two small fairing arcs blend the sides into the end cap.
The G-Code routine figures out all the coordinates and suchlike from some basic physical measurements & guesstimates, so tweaking the geometery is pretty straightforward. There was a blizzard going on while I wrote it: a fine day to spend indoors hacking code.
My assistant fired up Inkscape, laid out the text, figured out how to coerce G-Code out of Inkscape using the cnc-club.ru extension, then aligned it properly with the center of the chain hole as the origin on the right side. My routine calls the text G-Code file as a subroutine.
The extension’s header and footer files wrap EMC2’s SUB / ENDSUB syntactic sugar around the main file. The default files include an M2 that kills off the program; took a while to track that one down.
The header file:
O<dogtagtext> SUB
And the matching footer file:
O<dogtagtext> ENDSUB
The Inkscape-to-gcode instructions come out with absolute coordinates relative to the origin you define when you create the layout. The nested loops in my wrapper slap a G55 coordinate offset atop each label in turn, then call the subroutine.
The result is pretty slick:

I carved out that proof-of-concept label atop double-sided adhesive tape, but peeling off the goo is a real pain; a 2×3 array will be much worse. I’d rather do that than figure out how to clamp the fool things to the sacrificial plate, though.
The engraving is 0.2 mm deep with a Dremel 30 degree tool. My shop assistant describes it as “disturbing” the acrylic, not actually engraving a channel. This isn’t entirely a Bad Thing, as the font isn’t quite a stick font and the outline of each character mushes together. We must fiddle with the font a bit more; she favors a boldified OCR-A look.
Some lessons:
- The Kate G-Code syntax highlighter isn’t down with EMC2’s dialect
- Be very sure you touch off the workpiece origin in G54, not G55
- Xylene doesn’t bother acrylic and works fine on tape adhesive
- Symlinks aimed across an NFS link work fine in ~/emc2/nc_files/
- That 2×3 array may be too big for the Sherline’s tooling plate
- Tool length probing FTW!
The G-Code:
(Cabin Fever 2011 Dogtag) (Ed Nisley - KE4ZNU - December 2010) (Origin at center of chain hole near right side) (Stock held down with double-stick tape) (--------------------) (Flow Control) #<_DoText> = 1 #<_DoDrill> = 1 #<_DoMill> = 1 ( Sizes and Shapes) (-- Tag array layout) #<_NumTagsX> = 3 (number of tags along X axis) #<_NumTagsY> = 2 ( ... Y axis) #<_TagSpaceX> = 60 (center-to-center along X axis) #<_TagSpaceY> = 35 ( ... Y axis) (-- Tag Dimensions) #<_TagSizeX> = 50.8 (2.0 inches in WWII!) #<_TagSizeY> = 28.6 (1-1/8 inches) #<_TagSizeZ> = 2.0 #<_HoleOffsetX> = 4.0 (hole center to right-side tag edge) #<_NotchSizeX> = 3.5 (locating notch depth from far left edge) #<_NotchCtrY> = 5.0 (locating notch from Y=0) #<_NotchAngleBot> = 30 (lower angle in notch) #<_NotchAngleTop> = 45 (upper angle in notch) (-- Fairing Curve Dimensions as offsets from end arc center) #<_EndFairR> = [0.68 * #<_TagSizeY>] #<_CornerFairR> = [0.25 * #<_TagSizeY>] #<_PCRadius> = [#<_EndFairR> - #<_CornerFairR>] #<_PCY> = [[#<_TagSizeY> / 2] - #<_CornerFairR>] #<_PCTheta> = ASIN [#<_PCY> / #<_PCRadius>] #<_PCX> = [#<_PCRadius> * COS [#<_PCTheta>]] #<_P1Y> = [#<_TagSizeY> / 2] (top / bottom endpoint) #<_P1X> = #<_PCX> #<_P2X> = [#<_EndFairR> * COS [#<_PCTheta>]] #<_P2Y> = [#<_EndFairR> * SIN [#<_PCTheta>]] (-- Tooling) #<_TraverseZ> = 1.0 (safe clearance above workpiece) #<_DrillDia> = 3.2 (drill for hole and notch) #<_DrillNum> = 1 ( ... tool number) #<_DrillRadius> = [#<_DrillDia> / 2] #<_DrillFeed> = 200 (drill feed for holes) #<_DrillRPM> = 3000 #<_MillDia> = 3.2 (mill for outline) #<_MillNum> = 1 ( ... tool number) #<_MillRadius> = [#<_MillDia> / 2] #<_MillFeed> = 150 (tool feed for outlines) #<_MillRPM> = 5000 #<_TextDia> = 0.1 (engraving tool) #<_TextNum> = 1 #<_TextFeed> = 600 (tool feed for engraving) #<_TextRPM> = 10000 (-- Useful calculated values) #<_TagRightX> = #<_HoleOffsetX> (extreme limits of tag in X) #<_TagLeftX> = [#<_TagRightX> - #<_TagSizeX>] #<_EndFairRtX> = [#<_TagRightX> - #<_EndFairR>] #<_EndFairLfX> = [#<_TagLeftX> + #<_EndFairR>] #<_NotchCtrX> = [#<_TagLeftX> + #<_NotchSizeX> - #<_DrillRadius>] (--------------------) (--------------------) ( Initialize first tool length at probe switch) ( Assumes G59.3 is still in machine units, returns in G54) ( ** Must set these constants to match G20 / G21 condition!) #<_Probe_Speed> = 400 (set for something sensible in mm or inch) #<_Probe_Retract> = 1 (ditto) O<Probe_Tool> SUB G49 (clear tool length compensation) G30 (move above probe switch) G59.3 (coord system 9) G38.2 Z0 F#<_Probe_Speed> (trip switch on the way down) G0 Z[#5063 + #<_Probe_Retract>] (back off the switch) G38.2 Z0 F[#<_Probe_Speed> / 10] (trip switch slowly) #<_ToolZ> = #5063 (save new tool length) G43.1 Z[#<_ToolZ> - #<_ToolRefZ>] (set new length) G54 (coord system 0) G30 (return to safe level) O<Probe_Tool> ENDSUB (-------------------) (-- Initialize first tool length at probe switch) O<Probe_Init> SUB #<_ToolRefZ> = 0.0 (set up for first call) O<Probe_Tool> CALL #<_ToolRefZ> = #5063 (save trip point) G43.1 Z0 (tool entered at Z=0, so set it there) O<Probe_Init> ENDSUB (--------------------) (Start machining) G40 G49 G54 G80 G90 G94 G97 G98 (reset many things) G21 (metric!) (msg,Verify G30.1 position in G54 above tool change switch) M0 (msg,Verify XYZ=0 touched off at left front tag hole center on surface) M0 O<Probe_Init> CALL T0 M6 (clear the probe tool) (-- Engrave Text) O<DoText> IF [#<_DoText>] (msg,Insert engraving tool) T#<_TextNum> M6 (load engraving tool) O<Probe_Tool> CALL F#<_TextFeed> S#<_TextRPM> (debug,Set spindle to #<_TextRPM>) M0 G0 X0 Y0 (get safely to first tag) G0 Z#<_TraverseZ> (to working level) G10 L20 P2 X0 Y0 Z#<_TraverseZ> (set G55 origin to 0,0 at this point) G55 (activate G55 coordinates) O3000 REPEAT [#<_NumTagsX>] O3100 REPEAT [#<_NumTagsY>] O<dogtagtext> CALL G0 X0 Y0 G10 L20 P2 Y[0 - #<_TagSpaceY>] (set Y orgin relative to next tag in +Y direction) O3100 ENDREPEAT G10 L20 P2 X[0 - #<_TagSpaceX>] Y[[#<_NumTagsY> - 1] * #<_TagSpaceY>] (next to +X, Y to front) O3000 ENDREPEAT G54 (bail out of G55 coordinates) (-- Drill holes) O<DoDrill> IF [#<_DoDrill>] T0 M6 (msg,Insert drill) T#<_DrillNum> M6 O<Probe_Tool> CALL F#<_DrillFeed> S#<_DrillRPM> #<_DrillZ> = [0 - #<_TagSizeZ> - #<_DrillRadius>] (debug,Set spindle to #<_DrillRPM>) M0 G0 X0 Y0 (get safely to first tag) G0 Z#<_TraverseZ> (to working level) #<IndexX> = 0 O1000 DO #<IndexY> = 0 O1100 DO #<TagOriginX> = [#<IndexX> * #<_TagSpaceX>] #<TagOriginY> = [#<IndexY> * #<_TagSpaceY>] G81 X#<TagOriginX> Y#<TagOriginY> Z#<_DrillZ> R#<_TraverseZ> G81 X[#<TagOriginX> + #<_NotchCtrX>] Y[#<TagOriginY> + #<_NotchCtrY>] Z#<_DrillZ> R#<_TraverseZ> #<IndexY> = [#<IndexY> + 1] O1100 WHILE [#<IndexY> LT #<_NumTagsY>] #<IndexX> = [#<IndexX> + 1] O1000 WHILE [#<IndexX> LT #<_NumTagsX>] G30 (go home) O<DoDrill> ENDIF (-- Machine outlines) O<DoMill> IF [#<_DoMill>] T0 M6 (eject drill) (msg,Insert end mill) T#<_MillNum> M6 (load mill) O<Probe_Tool> CALL F#<_MillFeed> S#<_MillRPM> (debug,Set spindle to #<_MillRPM>) M0 G0 X0 Y0 (get safely to first tag) G0 Z#<_TraverseZ> (to working level) G10 L20 P2 X0 Y0 Z#<_TraverseZ> (set G55 origin to 0,0 at this point) G55 (activate G55 coordinates) O2000 REPEAT [#<_NumTagsX>] O2100 REPEAT [#<_NumTagsY>] G0 X[#<_NotchCtrX>] Y[#<_NotchCtrY>] (get to center of notch hole) G0 Z[0 - #<_TagSizeZ>] (down to cutting level) G91 (relative coordinate for notch cutting) G1 X[0 - #<_NotchSizeX>] Y[0 - #<_NotchSizeX> * TAN [#<_NotchAngleBot>]] G1 X[0 + #<_NotchSizeX>] Y[0 + #<_NotchSizeX> * TAN [#<_NotchAngleBot>]] G1 X[0 - #<_NotchSizeX>] Y[0 + #<_NotchSizeX> * TAN [#<_NotchAngleTop>]] G90 (back to abs coords) G42.1 D#<_MillDia> (cutter comp to right) G1 X[#<_TagLeftX>] Y0 (comp entry move to tip of left endcap) G3 X[#<_EndFairLfX> - #<_P2X>] Y[0 - #<_P2Y>] I[#<_EndFairR>] J0 (left endcap front half) G3 X[#<_EndFairLfX> - #<_P1X>] Y[0 - #<_P1Y>] I[#<_P2X> - #<_PCX>] J[#<_P2Y> - #<_PCY>] G1 X[#<_EndFairRtX> + #<_P1X>] (front edge) G3 X[#<_EndFairRtX> + #<_P2X>] Y[0 - #<_P2Y>] I0 J[#<_CornerFairR>] G3 X[#<_EndFairRtX> + #<_P2X>] Y[#<_P2Y>] I[0 - #<_P2X>] J[#<_P2Y>] (right endcap) G3 X[#<_EndFairRtX> + #<_P1X>] Y[#<_P1Y>] I[#<_PCX> - #<_P2X>] J[#<_PCY> - #<_P2Y>] G1 X[#<_EndFairLfX> - #<_P1X>] (rear edge) G3 X[#<_EndFairLfX> - #<_P2X>] Y[#<_P2Y>] I0 J[0 - #<_CornerFairR>] G3 X[#<_EndFairLfX> - #<_P2X>] Y[0 - #<_P2Y>] I[#<_P2X>] J[0 - #<_P2Y>] (left endcap complete) G0 Z#<_TraverseZ> G40 G0 X0 Y0 G10 L20 P2 Y[0 - #<_TagSpaceY>] (set Y orgin relative to next tag in +Y direction) O2100 ENDREPEAT G10 L20 P2 X[0 - #<_TagSpaceX>] Y[[#<_NumTagsY> - 1] * #<_TagSpaceY>] (next to +X, Y to front) O2000 ENDREPEAT G54 (bail out of G55 coordinates) G30 (go home) O<DoMill> ENDIF M2
The doodles leading to the equations:

We’ll see you there!
2 thoughts on “Cabin Fever Tchotchke: Engraved Dog Tag”
Comments are closed.