OMTech 60 W Laser: Laser Power Indicator

Although the OMTech laser controls the laser power supply with a key-lock switch, there’s little visible difference between the OFF and ON positions. Having occasionally mistaken it in both directions, this seemed like a useful addition:

Laser Power Lock Indicator - installed
Laser Power Lock Indicator – installed

The strip of black duct tape below the lock muffles the rattle of the triangle hatch key against the metal cabinet.

Two snippets of foam tape hold the knob to the lock cylinder, making an admittedly tenuous connection, but the knob fits around the outside of the switch housing with minimal clearance and doesn’t shouldn’t suffer any torque or pulling, so it might work.

The solid model looks about like you’d expect:

Laser Power Lock Indicator - solid model
Laser Power Lock Indicator – solid model

Unfortunately, it has no good orientation for printing, so I let PrusaSlicer generate support material inside the knob:

Laser Power Lock Indicator - Support structures
Laser Power Lock Indicator – Support structures

Suffice it to say: removing all that plastic did not go well.

I eventually grabbed the knob in the lathe and bored the interior out to its more-or-less proper dimensions, figuring nobody would ever notice the carnage, and it worked reasonably well. In the unlikely event I need another pointer, I’ll add a support spider to hold up the interior with minimal contact and less plastic.

Yeah, the laser really needs a stack light showing its condition and safety status …

The OpenSCAD source code as a GitHub Gist:

// Indicator for OMTech laser power lock
// Ed Nisley KE4ZNU 2022-04-09
KnobOD = 35.0;
KnobHeight = 22.0;
KnobTaper = 4.0;
PointerLength = 45.0;
PointerThick = 3.0;
TipOD = 2.0;
/* [Hidden] */
//------
Protrusion = 0.1; // make holes end cleanly
HoleWindage = 0.2;
module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes
Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2);
FixDia = Dia / cos(180/Sides);
cylinder(d=(FixDia + HoleWindage),h=Height,$fn=Sides);
}
//----------
// Create part
// Plenty of magic numbers from actual measurements
module Pointer() {
difference() {
union() {
linear_extrude(height=PointerThick)
hull() {
circle(d=KnobOD,$fn=24);
translate([PointerLength - TipOD/2,0])
circle(d=TipOD,$fn=12);
}
cylinder(d=KnobOD,h=KnobHeight - KnobTaper,$fn=24);
translate([0,0,KnobHeight - KnobTaper - Protrusion])
cylinder(d1=KnobOD,d2=KnobOD - 3.0,h=KnobTaper + Protrusion,$fn=24);
}
translate([0,0,-Protrusion]) {
PolyCyl(29.0,14.0 + Protrusion,24);
PolyCyl(24.0,14.0 + 5.0 + Protrusion,24); // leaves clearance under pointer
}
translate([0,0,KnobHeight])
cube([12.0,2.0,2*KnobHeight],center=true);
}
}
//----------
// Build it
Pointer();

And doodles giving the dimensions of the key lock, not all of which can be true at the same time:

Laser Power Lock Indicator - Dimension Doodles
Laser Power Lock Indicator – Dimension Doodles

OMTech 60 W Laser: COB LED Shades

Adding LED strips around the interior of the laser platform definitely improved the visibility of things on the honeycomb platform:

OMTech 60W laser - COB LED strips
OMTech 60W laser – COB LED strips

However, all that upward-directed light goes directly into my glare-sensitive eyeballs, so I added shades above the strips:

COB LED Shade - installed
COB LED Shade – installed

They’re cut from corrugated cardboard because I have an essentially infinite supply and I’m still working out speeds and intensities. Eventually they’ll become something like black acrylic.

The brackets emerged from the vasty digital deep through the miracle of 3D printing:

COB LED Shade Brackets - slice preview
COB LED Shade Brackets – slice preview

They’re stuck to the laser cabinet and the cardboard with double-sided duct tape. If you’re careful, they will line up along one edge of the tape, roll over neatly to stick their other face, then a single razor knife cut can separate each pair of neighbors.

The underside sports an aluminized mylar strip to redirect the wasted light in a more useful direction:

COB LED Shade - aluminized Mylar reflector
COB LED Shade – aluminized Mylar reflector

The tapeless sticky shipped with the laser holds the reflector in place, while its 20 mm width sets the 21 mm shade dimension. Although you want a reasonably smooth layer, it need not be mirror-flat.

Now it’s really bright in there:

COB LED Shade - overview
COB LED Shade – overview

While I had my head under the hood, I stuck a fourth strip of COB LEDs on the lip along the rear edge of the opening; it’s bright enough to cast the shadow just forward of the laser head despite the OEM under-gantry LED strip. Because the rear strip is aimed downward, it didn’t need a shade.

The perforated cardboard sheet on the left is a spike plate: more about that later.

The SVG drawings as a GitHub Gist:

Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

The OpenSCAD source code as a GitHub Gist:

// Bracket for COB LED shade
// Ed Nisley KE4ZNU 2022-03-24
BaseLength = 20.0;
/* [Hidden] */
ThreadThick = 0.25;
ThreadWidth = 0.40;
HoleWindage = 0.2;
Protrusion = 0.1; // make holes end cleanly
WebThick = 4*ThreadWidth;
BasePlate = [BaseLength,5*WebThick,WebThick];
//----------
// Create parts
module Bracket() {
R = BaseLength/3;
N = 36;
union() {
rotate([90,0,0])
translate([0,0,-WebThick/2])
linear_extrude(height=WebThick,convexity=2)
difference() {
intersection() {
union () {
square(2*R,center=false);
translate([0,2*R])
rotate(180/N)
circle(r=R,$fn=N);
translate([2*R,0])
rotate(180/N)
circle(r=R,$fn=N);
}
square(3*R,center=false);
}
translate([2*R*cos(180/N),2*R*cos(180/N)])
rotate(180/N)
circle(r=R,$fn=N);
}
rotate([0,-90,0])
translate([0,-BasePlate.y/2,-BasePlate.z])
cube(BasePlate,center=false);
translate([0,-BasePlate.y/2,0])
cube(BasePlate,center=false);
}
}
//----------
// Build them
Bracket();

B4-size Light Pad: Stabilizing the USB Connector

What used to be a “light box” had become a “light pad” powered through a USB Micro-B connector on the side. Unfortunately, the pad’s 5 mm thickness allows for very little mechanical reinforcement around the USB jack, while providing infinite opportunity to apply bending force. Over the course of the last half-dozen years (during which the price has dropped dramatically, despite recent events), the slightest motion flickered the LEDs.

So I squished the jack’s metal shell back into shape, found a short right-angle USB cable, and conjured a reinforcing fixture from the vasty digital deep:

LitUp LED Light Pad
LitUp LED Light Pad

The plate fits under the light pad, where a strip of super-sticky duct tape holds it in place:

LitUp Light Pad USB jack reinforcement - bottom
LitUp Light Pad USB jack reinforcement – bottom

The USB plug fits between the two blocks with hot-melt glue holding it in place and filling the gap between the plug and the pad.

I’d like to say it’s more elegant than the cable redirection for my tablet, but anything involving black electrical tape and hot-melt glue just isn’t in the running for elegant:

LitUp Light Pad USB jack reinforcement - top
LitUp Light Pad USB jack reinforcement – top

On the other paw, that socket ought to last pretty nearly forever, which counts for a whole lot more around here.

The retina-burn orange tape patches on the connector eliminate all the fumbling inherent to an asymmetric connector with invisible surface features. The USB wall wart on the other end of the cable sports similar markings.

The OpenSCAD source code as a GitHub Gist:

// Bracket to protect USB jack on LitUp LED Pad
// Ed Nisley KE4ZNU 2022-03-28
Protrusion = 0.1; // make holes end cleanly
Pad = [10.0,30.0,1.2];
Plug = [8.0,10.5 + 0.5,8.0];
BasePlate = [Pad.x + Plug.x,Pad.y,Pad.z];
//----------
// Create parts
module Stiffener() {
difference() {
union() {
translate([-Pad.x,-BasePlate.y/2,0])
cube(BasePlate,center=false);
translate([0,-Pad.y/2,0])
cube([Plug.x,Pad.y,Plug.z],center=false);
}
translate([-Protrusion,-Plug.y/2,-Protrusion])
cube(Plug + [2*Protrusion,0,Plug.z],center=false);
}
}
//----------
// Build them
Stiffener();

Angel Food Cake Pan Liner

Laser cut from parchment paper, no less:

Angel Food Cake Pan liner
Angel Food Cake Pan liner

Radial slits around the middle let it bend upward over the folded aluminum joint around the pillar:

Angel Food Cake Pan liner - detail
Angel Food Cake Pan liner – detail

Ours claims to be a 10×4-½ inch pan, roughly the diameter at the top and the overall height. Your pan will surely be different: this one is, as the saying goes, old enough to know better.

The SVG image as a GitHub Gist:

Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Made in anticipation of the next time Mary bakes a special carrot cake with cream cheese frosting for my birthday …

CNC-3018XL X-Axis Recalibration

Plotting the backlash / calibration target on both the CNC-3018XL and the MPCNC quickly showed, contrary to what I expected, the MPCNC was dead-on accurate, albeit with some wobbulation and a trace of backlash:

MPCNC - Backlash test - detail
MPCNC – Backlash test – detail

Although it looks ug-u-lee, the (lower speed) drag knife cuts come out nice and, because the entry and exit moves match the main cut, the minimal backlash wasn’t a problem.

Turns out only the X axis on the 3018XL had a problem:

Cal Target - 400 step-mm - merged
Cal Target – 400 step-mm – merged

Apparently the longer leadscrew I installed as part of the “XL” conversion has a small thread pitch error: about 1 mm short in every 250 mm of travel. I don’t have any (definite, non-handwavy) method to measure the pitch directly, other than by running the follower nut and measuring the results, but it’s consistently short.

Quite some time ago (after blowing up the OEM controller board), I set up the Protoneer CNC board in 1:8 microstep mode, making the GRBL $100 setting a nice, round 400 step/mm for a two-start leadscrew with 2 mm pitch and 4 mm pitch:

400 step/mm = (200 step/rev * 8 µstep/step) / 4 mm 

After a few more measurements suggesting the leadscrew actually traveled 249.2 mm, the correct value will be:

401.28 step/mm = 400 step/mm × 250 mm / 249.2 mm

To verify I understood the problem and solution, I set $100 to a few integer values around the goal:

Cal Target - stacked - 399-402 step-mm
Cal Target – stacked – 399-402 step-mm

The top image shows the leftmost line at the 10 mm mark on the scale, because it’s easier for me to match the ink line with an engraved line, rather than the non-line at the end of the ruler.

The other images show the results for $100 set to 399, 400, 401, and 402 step/mm, respectively. The results last two results bracket the desired 250 mm outcome, with 401 step/mm being Close Enough™. GRBL accepts a floating point step/mm value, so I set $100 to 401.28, but I was unable to convince myself the result came out consistently different than 401.00.

Plotting both the tick marks (green) and the knife path (red) on the 3018XL, then cutting the bare paper on the MPCNC, showed the two machines now agree on where the knife should fall. The outer end of the tick marks extends 1 mm beyond the cut line to ensure small misalignments do not produce an obvious white gap around the edge of the deck.

The Y axis continues to match:

Tek CC - 2022-02-14 - Y detail
Tek CC – 2022-02-14 – Y detail

And now the X axis looks just as good:

Tek CC - 2022-02-14 - X detail
Tek CC – 2022-02-14 – X detail

The drag knife corners are rounded, as you’d expect. The cut seems slightly offset from a small origin touch-off error, but the scales now match.

GCMC XY Axis Calibration Target

The CNC-3018XL drawing the scales on a Tek Circuit Computer disagreed with the MPCNC cutting the perimeter. The Y axis edges looked OK:

Tek CC - 2021-11 - Y detail
Tek CC – 2021-11 – Y detail

But the cut on the X axis edges went too close to the tips:

Tek CC - 2021-11 - X detail
Tek CC – 2021-11 – X detail

I conjured a calibration target to help measure the two machines:

Cal Target - CNC3018XL
Cal Target – CNC3018XL

The X- side of the plot gives the general idea:

CNC-3018XL - Backlash Test - 400step-mm
CNC-3018XL – Backlash Test – 400step-mm

The vertical lines consist of two halves, drawn in order from left to right on the top and right to left on the bottom, meeting in the middle at the Y=0 axis. If they do, in fact, meet in the middle, then there’s no problem with backlash.

The 25 mm distance between adjacent lines verifies the linear calibration; the total distance along the X and Y axes provides more travel for more error accumulation.

The circles provide some reassurance the machine can draw a smooth circle, because they come from GRBL’s (or whatever) G2 G-Code commands, not a linear approximation.

Spoiler: after a considerable amount of drawing, measuring, and muttering, the problem emerged from the CNC-3018XL’s X-axis leadscrew:

Cal Target - 400 step-mm - merged
Cal Target – 400 step-mm – merged

It’s half a millimeter short on each end!

More on this tomorrow …

The GCMC source code as a GitHub Gist:

(epilog begins)
(bCNC may regard plot as done before this returns)
M2
(epilog ends)
view raw epilog.gcmc hosted with ❤ by GitHub
(prolog begins)
G17 (XY plane)
G21 (mm)
G40 (no cutter comp)
G49 (no tool length comp)
G80 (no motion mode)
G90 (abs distance)
G94 (units per minute)
(prolog ends)
view raw prolog.gcmc hosted with ❤ by GitHub
// Grid pattern to check XY scaling
// Ed Nisley KE4ZNU - 2021-11
// gcmc -P 4 --pedantic --prolog prolog.gcmc --epilog epilog.gcmc --output 'Scale Grid.ngc' 'Scale Grid.gcmc'
include("engrave.inc.gcmc");
FALSE = 0;
TRUE = !FALSE;
//-----
// Define useful constants
SafeZ = [-,-,10.0mm]; // above all obstructions
TravelZ = [-,-,2.0mm]; // within engraving / milling area
PenZ = [-,-,-1.0mm]; // depth for good inking
PenSpeed = 2000mm;
//-----
// Overall values
PlotSize = [250mm,200mm,-];
comment("PlotSize: ",PlotSize);
GridSize = [25mm,25mm,-];
Margins = [5mm,5mm,-];
CenterOD = 5.0mm;
TextFont = FONT_HSANS_1_RS; // single stroke stick font
TextSize = 3.0 * [1.0mm,1.0mm];
//-----
// Draw it
feedrate(PenSpeed);
comment("Draw title info");
tp = scale(typeset("Scale & Backlash Test Pattern",TextFont),TextSize);
tp += [-PlotSize.x/2 + GridSize.x/2,PlotSize.y/2 - GridSize.y/2,-];
engrave(tp,TravelZ.z,PenZ.z);
tp = scale(typeset("Grid " + GridSize,TextFont),TextSize);
tp += [-PlotSize.x/2 + GridSize.x/2,PlotSize.y/2 - GridSize.y/2 - 1.5*TextSize.y,-];
engrave(tp,TravelZ.z,PenZ.z);
tp = scale(typeset("F " + PenSpeed + "/min",TextFont),TextSize);
tp += [-PlotSize.x/2 + GridSize.x/2,PlotSize.y/2 - GridSize.y/2 - 3.0*TextSize.y,-];
engrave(tp,TravelZ.z,PenZ.z);
tp = scale(typeset("Ed Nisley - KE4ZNU",TextFont),TextSize);
tp += [-PlotSize.x/2 + GridSize.x/2,-(PlotSize.y/2 - GridSize.y/2),-];
engrave(tp,TravelZ.z,PenZ.z);
tp = scale(typeset("softsolder.com",TextFont),TextSize);
tp += [-PlotSize.x/2 + GridSize.x/2,-(PlotSize.y/2 - GridSize.y/2 + 1.5*TextSize.y),-];
engrave(tp,TravelZ.z,PenZ.z);
comment("Mark center point");
goto(SafeZ);
goto([CenterOD/2,0,-]);
move(PenZ);
circle_cw([0,0]);
comment("Label axes");
tp = scale(typeset("X+",TextFont),TextSize);
tp += [GridSize.x + 0.5*TextSize.x,-TextSize.y/2,-];
engrave(tp,TravelZ.z,PenZ.z);
tp = scale(typeset("Y+",TextFont),TextSize);
tp += [-TextSize.x/2,GridSize.y + 0.5*TextSize.y,-];
engrave(tp,TravelZ.z,PenZ.z);
comment("Draw left-to-right");
tp = scale(typeset("L to R →",TextFont),TextSize);
tp += [-PlotSize.x/2 + GridSize.x/2 - tp[-1].x/2,GridSize.y/2,-];
engrave(tp,TravelZ.z,PenZ.z);
goto([-(PlotSize.x/2 + Margins.x),GridSize.y,-]);
for (p=[-PlotSize.x/2,GridSize.y,-] ; p.x <= PlotSize.x/2 ; p.x += GridSize.x ) {
comment(" p: ",p);
goto(p);
move(PenZ);
move_r([-,-GridSize.y,-]);
goto(TravelZ);
}
comment("Draw right-to-left");
tp = scale(typeset("R to L ←",TextFont),TextSize);
tp += [PlotSize.x/2 - GridSize.x/2 - tp[-1].x/2,-GridSize.y/2,-];
engrave(tp,TravelZ.z,PenZ.z);
goto([(PlotSize.x/2 + Margins.x),-GridSize.y,-]);
for (p=[PlotSize.x/2,-GridSize.y,-] ; p.x >= -PlotSize.x/2 ; p.x -= GridSize.x ) {
comment(" p: ",p);
goto(p);
move(PenZ);
move_r([-,GridSize.y,-]);
goto(TravelZ);
}
comment("Draw bottom-to-top");
tp = scale(typeset("B to T ↑",TextFont),TextSize);
tp += [-GridSize.x/2 - tp[-1].x/2,-(PlotSize.y/2 - TextSize.y),-];
engrave(tp,TravelZ.z,PenZ.z);
goto([-GridSize.x,-(PlotSize.y/2 + Margins.y),-]);
for (p=[-GridSize.x,-PlotSize.y/2,-] ; p.y <= PlotSize.y/2 ; p.y += GridSize.y ) {
comment(" p: ",p);
goto(p);
move(PenZ);
move_r([GridSize.x,-,-]);
goto(TravelZ);
}
comment("Draw top-to-bottom");
tp = scale(typeset("T to B ↓",TextFont),TextSize);
tp += [GridSize.x/2 - tp[-1].x/2,(PlotSize.y/2 - 1.5*TextSize.y),-];
engrave(tp,TravelZ.z,PenZ.z);
goto([GridSize.x,(PlotSize.y/2 + Margins.y),-]);
for (p=[GridSize.x,PlotSize.y/2,-] ; p.y >= -PlotSize.y/2 ; p.y -= GridSize.y ) {
comment(" p: ",p);
goto(p);
move(PenZ);
move_r([-GridSize.x,-,-]);
goto(TravelZ);
}
comment("Draw circles");
maxr = (PlotSize.x < PlotSize.y) ? PlotSize.x/2 : PlotSize.y/2;
for (r=GridSize.x/2 ; r <= maxr ; r += GridSize.x) {
comment(" r: ",r);
goto([-r,0,-]);
move(PenZ);
circle_cw([0,0,-]);
goto(TravelZ);
}
goto(SafeZ);
goto([0,0,-]);
view raw Scale Grid.gcmc hosted with ❤ by GitHub

CNC-3018XL: Improved X-Axis Home Switch Mount

A few months of inactivity left the CNC-3018XL table parked in its homed position where the gentle-but-inexorable pressure of the switch lever displaced the foam holding the plastic actuator tab on the X-axis bearing enough that it would no longer operate reliably:

3018 CNC - Y axis endstop
3018 CNC – Y axis endstop

Putting foam tape in a highly leveraged position produces the same poor results as in finance.

The fix requires reorienting the switch so a solid block on the bearing can push directly on the actuator lever:

CNC-3018 X Home Switch - bottom view
CNC-3018 X Home Switch – bottom view

The block must curve around the bearing to give the tape enough surface area for a good grip:

CNC-3018 X Home Switch - oblique view
CNC-3018 X Home Switch – oblique view

The solid model for the new X-axis mount looks about like you’d expect:

CNC-3018 X Home Switch Mount - solid model
CNC-3018 X Home Switch Mount – solid model

I increased the home switch pulloff to 2 mm, although it’s not clear that will make any difference in the current orientation.

The OpenSCAD source code as a GitHub Gist:

// 3018-Pro Mount for Makerbot Endstop PCB
// Ed Nisley KE4ZNU - 2019-07 (using OEM machine axes)
// 2022-02-02 rotate X block (after renaming axes to match new layout)
/* [Build Options] */
Layout = "Show"; // [Build, Show]
/* [Hidden] */
ThreadThick = 0.25; // [0.20, 0.25]
ThreadWidth = 0.40; // [0.40]
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
Protrusion = 0.01; // [0.01, 0.1]
HoleWindage = 0.2;
ID = 0;
OD = 1;
LENGTH = 2;
//- Shapes
// Basic PCB with hole for switch pins
// origin at switch actuator corner, as seen looking at component side
SwitchClear = [15.0,5.0,2.0]; // clearance around switch pins
SwitchOffset = [12.5,9.0,0.0]; // center of switch pins from actuator corner
PCB = [26.0,16.4,2*SwitchClear.z]; // switch PCB beyond connector, pin height
//XBlock = [PCB.x + 10.0,PCB.y,20.0];
XBlock = [PCB.x,PCB.y,10.0];
XBearing = [10.0,26.5,28.5];
XPin = [10.0,20.0,10.0];
module XMount() {
if (false) // side-push switch tended to slip
difference() {
translate([-10.0,0,0])
cube(XBlock,center=false);
translate([0,-Protrusion,10.0])
cube(XBlock + [0,2*Protrusion,0],center=false);
translate(SwitchOffset + [0,0,10.0 - SwitchClear.z/2])
cube(SwitchClear + [0,0,Protrusion],center=true);
}
else {
difference() {
cube(XBlock,center=false);
translate(SwitchOffset + [0,0,XBlock.z - SwitchClear.z/2])
cube(SwitchClear + [0,0,Protrusion],center=true);
}
translate([1.25*XBlock.x,0,0])
difference() {
cube(XPin + [0,0,XBearing[OD]/4],center=false);
translate([-Protrusion,XPin.y/2,XPin.z + XBearing[OD]/2])
rotate([0,90,0])
cylinder(d=XBearing[OD],h=XPin.x + 2*Protrusion,center=false);
translate([-Protrusion,-XPin.y/2,XPin.z])
cube(XPin + [2*Protrusion,0,0],center=false);
}
}
}
YBlock = [PCB.x,PCB.y,5.0];
module YMount() {
difference() {
cube(YBlock,center=false);
translate(SwitchOffset + [0,0,YBlock.z - SwitchClear.z/2])
cube(SwitchClear + [0,0,Protrusion],center=true);
}
}
ZBlock = [PCB.x,PCB.y,6.0];
ZPin = [20.0,10.0,5.5];
module ZMount() {
difference() {
cube(ZBlock,center=false);
translate(SwitchOffset + [0,0,ZBlock.z - SwitchClear.z/2])
cube(SwitchClear + [0,0,Protrusion],center=true);
}
translate([1.25*ZBlock.x,0,0])
difference() {
cube(ZPin,center=false);
translate([ZPin.x/2,-Protrusion,4.0])
cube(ZPin + [0,2*Protrusion,0],center=false);
}
}
//- Build things
if (Layout == "Show") {
translate([0,XBlock.y,0])
YMount();
translate([0,-XBlock.y/2])
XMount();
translate([0,-(ZBlock.y + XBlock.y)])
ZMount();
}