A slight modification to the MPCNC LM12UU collet pen holder turns it into a long-reach Z-Axis Height Probe:

A flange on the top plate holds a Makerbot-style endstop switch:

The brass probe rod sports a 3/32 inch ball epoxied on its tip, although for my simple needs I could probably use the bare rod:

I clamped the rod to extend a bit beyond the plate, where it can soak up most of the switch release travel, leaving just enough to reset the clickiness after each probe:

The probe responds only to Z motion, not tip deflection in XY, so it’s not particularly good for soft objects with sloped sides, like the insole shown above. It works fine for rigid objects and should suffice to figure the modeling workflow.
The bCNC Auto-Level probe routine scans a grid over a rectangular region:

Which Meshlab turns into a solid model:

That’s the bottom of the insole probed on a 5 mm grid, which takes something over an hour to accomplish.
The OpenSCAD code as a GitHub Gist:
// Collet pen cartridge holder using LM12UU linear bearing | |
// Ed Nisley KE4ZNU - 2019-04-26 | |
// 2019-06 Adapted from LM12UU drag knife holder | |
// 2019-09 Probe switch mount plate | |
Layout = "Build"; // [Build, Show, Puck, Mount, Plate, SwitchPlate] | |
/* [Hidden] */ | |
// Extrusion parameters | |
ThreadThick = 0.25; // [0.20, 0.25] | |
ThreadWidth = 0.40; // [0.40] | |
// Constants | |
Protrusion = 0.1; // [0.01, 0.1] | |
HoleWindage = 0.2; | |
inch = 25.4; | |
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit); | |
ID = 0; | |
OD = 1; | |
LENGTH = 2; | |
//- Adjust hole diameter to make the size come out right | |
module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes | |
Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2); | |
FixDia = Dia / cos(180/Sides); | |
cylinder(r=(FixDia + HoleWindage)/2,h=Height,$fn=Sides); | |
} | |
//- Dimensions | |
// Basic shape of DW660 snout fitting into the holder | |
// Lip goes upward to lock into MPCNC mount | |
Snout = [44.6,50.0,9.6]; // LENGTH = ID height | |
Lip = 4.0; // height of lip at end of snout | |
// Holder & suchlike | |
PenShaft = 3.5; // hole to pass pen cartridge | |
WallThick = 4.0; // minimum thickness / width | |
Screw = [4.0,8.5,25.0]; // thread ID, washer OD, length | |
Insert = [4.0,6.0,10.0]; // brass insert | |
Bearing = [12.0,21.0,30.0]; // linear bearing body | |
Plate = [PenShaft,Snout[OD] - WallThick,WallThick]; // spring reaction plate | |
echo(str("Plate: ",Plate)); | |
SpringSeat = [0.56,7.5,2*ThreadThick]; // wire = ID, coil = OD, seat depth = length | |
PuckOAL = max(Bearing[LENGTH],(Snout[LENGTH] + Lip)); // total height of DW660 fitting | |
echo(str("PuckOAL: ",PuckOAL)); | |
Key = [Snout[ID],25.7,(Snout[LENGTH] + Lip)]; // rectangular key | |
NumScrews = 3; | |
//ScrewBCD = 2.0*(Bearing[OD]/2 + Insert[OD]/2 + WallThick); | |
ScrewBCD = (Snout[ID] + Bearing[OD])/2; | |
echo(str("Screw BCD: ",ScrewBCD)); | |
NumSides = 9*4; // cylinder facets (multiple of 3 for lathe trimming) | |
// MBI Endstop switch PCB | |
PCB = [40.0,1.6,16.5]; // endstop PCB, switch downward, facing parts | |
Touchpoint = [-4.8,4.8,4.5]; // contact point from PCB edges, solder side | |
TapeThick = 1.0; // foam mounting tape | |
SwitchMount = [PCB.x,WallThick,PCB.z + Touchpoint.z + Plate.z]; | |
module DW660Puck() { | |
translate([0,0,PuckOAL]) | |
rotate([180,0,0]) { | |
cylinder(d=Snout[OD],h=Lip/2,$fn=NumSides); | |
translate([0,0,Lip/2]) | |
cylinder(d1=Snout[OD],d2=Snout[ID],h=Lip/2,$fn=NumSides); | |
cylinder(d=Snout[ID],h=(Snout[LENGTH] + Lip),$fn=NumSides); | |
translate([0,0,(Snout[LENGTH] + Lip) - Protrusion]) | |
cylinder(d1=Snout[ID],d2=2*WallThick + Bearing[OD],h=PuckOAL - (Snout[LENGTH] + Lip),$fn=NumSides); | |
intersection() { | |
translate([0,0,0*Lip + Key.z/2]) | |
cube(Key,center=true); | |
cylinder(d=Snout[OD],h=Lip + Key.z,$fn=NumSides); | |
} | |
} | |
} | |
module MountBase() { | |
difference() { | |
DW660Puck(); | |
translate([0,0,-Protrusion]) // bearing | |
PolyCyl(Bearing[OD],2*PuckOAL,NumSides); | |
for (i=[0:NumScrews - 1]) // clamp screws | |
rotate(i*360/NumScrews) | |
translate([ScrewBCD/2,0,-Protrusion]) | |
rotate(180/8) | |
PolyCyl(Insert[OD],2*PuckOAL,8); | |
} | |
} | |
module SpringPlate() { | |
difference() { | |
cylinder(d=Plate[OD],h=Plate[LENGTH],$fn=NumSides); | |
translate([0,0,-Protrusion]) // pen cartridge hole | |
PolyCyl(PenShaft,2*Plate[LENGTH],NumSides); | |
translate([0,0,Plate.z - SpringSeat[LENGTH]]) // spring retaining recess | |
PolyCyl(SpringSeat[OD],SpringSeat[LENGTH] + Protrusion,NumSides); | |
for (i=[0:NumScrews - 1]) // clamp screws | |
rotate(i*360/NumScrews) | |
translate([ScrewBCD/2,0,-Protrusion]) | |
rotate(180/8) | |
PolyCyl(Screw[ID],2*PuckOAL,8); | |
} | |
} | |
module SwitchPlate() { | |
translate([0,0,Plate.z]) | |
rotate([180,0,0]) | |
SpringPlate(); | |
rotate(45) | |
translate([Touchpoint.x,Touchpoint.y + TapeThick,0]) | |
cube(SwitchMount,center=false); | |
} | |
//----- | |
// Build it | |
if (Layout == "Puck") | |
DW660Puck(); | |
if (Layout == "Plate") | |
SpringPlate(); | |
if (Layout == "SwitchPlate") | |
SwitchPlate(); | |
if (Layout == "Mount") | |
MountBase(); | |
if (Layout == "Show") { | |
MountBase(); | |
translate([0,0,1.6*PuckOAL]) | |
rotate([180,0,0]) | |
SpringPlate(); | |
} | |
if (Layout == "Build") { | |
translate([0,Snout[OD]/2,PuckOAL]) | |
rotate([180,0,0]) | |
MountBase(); | |
translate([0,-Snout[OD]/2,0]) | |
SpringPlate(); | |
} |
One thought on “MPCNC: Z-Axis Height Probe”
Comments are closed.