The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Tag: Improvements

Making the world a better place, one piece at a time

  • Makergear M2: Re-Relocated Z-min Platform Height Switch

    A few trips with the M2 convinced me that the cable to the relocated Z-min switch along the front of the X gantry needed a clip on each end and should not run under the gantry. This time I used the full width of the steel strap and bashed a neater curve around a length of drill rod:

    M2 Z-min Cable Clip - forming
    M2 Z-min Cable Clip – forming

    The new clips look a bit better with straight edges:

    M2 Z-min Cable Clips - old vs new
    M2 Z-min Cable Clips – old vs new

    The top view shows the new clips and cable location:

    M2 Z-min Switch - top view
    M2 Z-min Switch – top view

    While I was at it, I trimmed the edges off the switch mounting block. Rather than figure out the trig required to hack off the corners, I applied linear_extrude() to a polygon() defined by some obvious points, then poked the same holes in the block:

    Z-min Front Mount Switch Block - chamfer - solid model
    Z-min Front Mount Switch Block – chamfer – solid model

    It pretty much vanishes in the top view, but here’s a view from the +Y end of the platform:

    M2 Z-min Switch - bottom view
    M2 Z-min Switch – bottom view

    Despite all that maneuvering, the G92 Z-4.55 touchoff value remained the same!

    If you’ve forgotten why all this makes sense, it’s a first pass at detecting the actual build platform position. The stock M2 uses that switch to detect the top of a screw attached to the Z-axis stage, which means it can’t sense the actual platform. The Z-min switch I added to the Thing-O-Matic convinced me that was the only way to fly; given the TOM’s plywood-and-acrylic frame, it was essentially mandatory.

    Mounting the switch on the extruder would allow probing the entire platform, which would allow on-the-fly correction for both average height and (non-)flatness, but that’s a whole ‘nother project.

    The OpenSCAD source code:

    // Block to mount M2 Z-min switch on X gantry
    // Ed Nisley KE4ZNU - Oct 2013
    
    //- Extrusion parameters - must match reality!
    
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    
    Protrusion = 0.1;
    
    HoleWindage = 0.2;
    
    //- Sizes
    
    SwitchLength = 20.0;					// switch size across front of block
    
    SwitchScrewOD = 2.05;					// microswitch screw tapping
    SwitchScrewOC = 9.5;					//  ... on-center spacing
    
    GantryScrewOD = 3.0;					// X rail screw clearance
    GantryScrewOC = 25.0;					//  ... on-center spacing along X
    GantryScrewOffset = 12.0;				//  ... Y offset from gantry front
    
    BlockSize = [1.5*GantryScrewOC,17.0,5.0];			// XYZ dimensions as mounted
    HalfBlock = BlockSize/2;
    
    SwitchScrewLength = BlockSize[1] - 5*ThreadWidth;	// net length of switch screws
    echo("Max switch screw length: ",SwitchScrewLength + 5.0);		// ... allow switch thickness
    
    ChamferAngle = atan((BlockSize[0] - SwitchLength)/(BlockSize[1]/2));
    echo("Chamfer Angle: ",ChamferAngle);
    
    //- 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);
    }
    
    //- Put peg grid on build surface
    
    module ShowPegGrid(Space = 10.0,Size = 1.0) {
    
      RangeX = floor(100 / Space);
      RangeY = floor(125 / Space);
    
    	for (x=[-RangeX:RangeX])
    	  for (y=[-RangeY:RangeY])
    		translate([x*Space,y*Space,Size/2])
    		  %cube(Size,center=true);
    
    }
    
    //- Define basic block shape
    
    module BaseBlock() {
    	translate([0,-GantryScrewOffset,0])
    		linear_extrude(height=BlockSize[2])
    		polygon(points=[[-HalfBlock[0],BlockSize[1]],
    						[HalfBlock[0],BlockSize[1]],
    						[HalfBlock[0],HalfBlock[1]],
    						[SwitchLength/2,0],
    						[-SwitchLength/2,0],
    						[-HalfBlock[0],HalfBlock[1]]
    						]);
    }
    
    //- Build it
    
    ShowPegGrid();
    
    difference() {
    	BaseBlock();
    	for (i=[-1,1]) {
    		translate([i*GantryScrewOC/2,0,-Protrusion])
    			rotate(-90)
    				PolyCyl(GantryScrewOD,(BlockSize[2] + 2*Protrusion));
    		translate([i*SwitchScrewOC/2,-(GantryScrewOffset + Protrusion),BlockSize[2]/2])
    			rotate([-90,0,0])
    				rotate(90)
    					PolyCyl(SwitchScrewOD,(SwitchScrewLength + Protrusion));
    	}
    }
    
  • Brita Water Pitcher: Reinforced Lid Screws

    While I had the epoxy for the last step in the eyeglass frame repair, I fixed the lid on the never-sufficiently-to-be-damned Brita filter pitcher, as it had just tossed one of its miniature screws somewhere on the kitchen floor.

    Nothing too challenging and, as nobody else ever sees this side of the lid, not very pretty:

    Brita Pitcher - reinforced lid screws
    Brita Pitcher – reinforced lid screws

    I probably should have added a brass reinforcement strip around the cracked plastic mounts, but JB Weld epoxy should be strong enough for this job all by itself. Assuming, that is, it can maintain a grip on the plastic; I’m hoping the various fractures will lock it in place.

  • Makergear M2 Filament Guide Tube: Bigger Is Better

    The whole point of the new guide tube block is to see if a larger ID tube will reduce the force required to pull the filament through it; long after Dan suggested simply using a larger tube, I got around to picking up a lifetime supply of 1/4 inch OD polyethylene tubing: 25 feet for $3. The ID is about 0.17 inch = 4.3 mm, large enough to let the 1.75 mm filament move smoothly, and the inside clearance provides a few millimeters of free motion so that retraction moves don’t require pushing the guide tube around.

    The new filament guide + wire cover anchors the spool end of the tube:

    M2 Larger Filament Guide - overview
    M2 Larger Filament Guide – overview

    On the other end, I blobbed a piece of 1/4 inch ID tubing to anchor the guide tube. It’s nicer than the twist of cardboard I used before, but nothing to get excited about:

    M2 Extruder - nested filament guide tubes
    M2 Extruder – nested filament guide tubes

    There exists a printed tubing anchor that attaches to the bolt that adjusts the force pressing the filament against the drive gear, but:

    • It’s just an STL model
    • That fits the original guide tube
    • So I’d have to reverse engineer it
    • And I don’t want to fiddle with the extruder

    This will suffice for a while.

    As I hoped, the larger guide tube reduces the force required to pull the filament into the extruder under 1 pound. Most of that force comes from persuading the filament spool to drag-rotate around the plastic support arm, so some simple improvements should help there, as well. I foresee some bearings in its future.

    Fine tuning of the tubing length is also in order, but that’ll require more printing sessions.

  • Makergear M2: Improved X-Min Wire Cover and Filament Guide Anchor

    With the reverse-engineered wire cover model in hand, a bit of tinkering extends one side into a relentlessly rectangular block with a hole for the filament guide tube:

    M2 Wire Cover Filament Guide - overview
    M2 Wire Cover Filament Guide – overview

    Because the block sits somewhat to the rear of the spool, I added a conical entrance to help ease the filament around the corner into the tube. The hole fits the larger 1/4 inch tube that I’m trying out, with a stop equal to the tube’s 0.17 inch ID just before the conical section, as shown in this cross-section view:

    M2 Wire Cover Filament Guide - guide tube section
    M2 Wire Cover Filament Guide – guide tube section

    It fits just about the way you’d expect:

    M2 Larger Filament Guide - rear view
    M2 Larger Filament Guide – rear view

    The perspective makes the guide tube look more angled than it really is; most of that curve is toward the front, so it’s considerably foreshortened in this view.

    The metal bar with the cross pin sticking up in front is a bar clamp that holds an oak strip across the back of the bench to keep the M2 from walking away.

    The OpenSCAD source code:

    // Improved M2 filament guide and X-min switch wire guide
    // Ed Nisley KE4ZNU - Oct 2013
    
    Layout = "Build";				// Build Section
    
    //- Useful Stuff
    
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    
    Protrusion = 0.1;
    
    HoleWindage = 0.2;
    
    //- Sizes
    
    PlateMinThick = 8.0;				// basic thickness excluding wire guides
    PlateLength = 55.0;					// from side of frame beyond top wire guide
    
    TopGuideLength = 7.0;				// protrusion from plate
    
    PlateThick = PlateMinThick + TopGuideLength;
    
    echo(str("Total thickness: ",PlateThick));
    
    GuideTubeOD = 6.3;					// max diameter!
    GuideTubeID = 4.3;					// max diameter!
    GuideTubeOffset = 45.0;				// centerline from edge of frame
    
    //- 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);
    }
    
    //- Put peg grid on build surface
    
    module ShowPegGrid(Space = 10.0,Size = 1.0) {
    
      RangeX = floor(100 / Space);
      RangeY = floor(125 / Space);
    
    	for (x=[-RangeX:RangeX])
    	  for (y=[-RangeY:RangeY])
    		translate([x*Space,y*Space,Size/2])
    		  %cube(Size,center=true);
    
    }
    
    //- Define basic block shape
    //  Mostly reverse engineered from
    //    https://github.com/MakerGear/M2/blob/master/Printed%20Parts/STL/M2%20X%20Endstop%20Wire%20Cover%20with%20Filament%20Guide.stl
    //	Hence all the magic numbers...
    
    module BaseBlock() {
    
    SideGuideLength = 4.0;				// protrusion = even with frame interior
    ChannelDepth = 4.5;					// wiring channel
    FrameOffset = 28;
    
    	translate([18,28,0]) {			// align neatly for later processing
    
    		if (true)
    			color("Green",0.2)
    				translate([-18,22,15])
    					rotate([-90,0,-90])
    						import("file:///mnt/bulkdata/Project%20Files/Thing-O-Matic/M2%20Parts/Filament%20Guide/M2+X+Endstop+Wire+Cover+with+Filament+Guide.stl",
    								convexity=10);
    
    		difference() {
    			linear_extrude(height=PlateThick,convexity=5)		// main block
    				polygon(points=[[0,0],[0,22],[12,22],[12,7.5],[22,7.5],
    								[22,-(PlateLength + FrameOffset)],[-18,-(PlateLength + FrameOffset)],
    								[-18,0]
    						]);
    
    			for (i=[-1,0])
    				translate([17,((i*15.0)+ 1.05),-Protrusion])
    					rotate(180/6) {
    						PolyCyl(3.1,(PlateMinThick + 2*Protrusion),6);		// screw holes
    						PolyCyl(5.7,(3.0 + Protrusion),6);					//  ... countersink
    					}
    
    			translate([0,0,(PlateMinThick - ChannelDepth)])		// wire channel
    				linear_extrude(height=15,convexity=5)
    					polygon(points=[[2,-5],[2,19],[10,19],[10,-22],[-15,-22],[-15,-5]
    							]);
    
    			translate([-10,14,PlateMinThick])				// M2 frame
    				rotate(-90)
    					cube([42,35,10],center=false);
    
    			translate([-5,5,(PlateMinThick + SideGuideLength)])	// shorten side guide
    				cube([20,20,10],center="false");
    		}
    	}
    }
    
    //- Complete object
    
    module GuideCover() {
    
    	difference() {
    		BaseBlock();
    
    		translate([50,-GuideTubeOffset,PlateThick/2])
    			rotate([0,-90,0])
    				rotate(180/6)
    					PolyCyl(GuideTubeID,60,6);
    
    		translate([25,-GuideTubeOffset,PlateThick/2])
    			rotate([0,-90,0])
    				rotate(180/6)
    					PolyCyl(GuideTubeOD,60,6);
    
    		translate([41,-GuideTubeOffset,PlateThick/2])
    			rotate([0,-90,0])
    				rotate(180/6)
    					cylinder(r1= 0.5*PlateThick,r2=GuideTubeID/2,h=8,$fn=12);
    	}
    }
    
    //- Build it
    
    ShowPegGrid();
    
    if (Layout == "Section")
    	difference() {
    		GuideCover();
    		translate([2*100/3,-GuideTubeOffset,-PlateThick])
    			rotate(180)
    				cube([100,PlateLength,3*PlateThick]);
    	}
    
    if (Layout == "Build")
    	GuideCover();
    
  • Makergear M2: Reverse-engineering the X-min Wire Cover

    The Makergear M2 comes with a plastic block that covers the X-min switch wiring and anchors the end of the filament guide. Because the guide wasn’t anchored to the block, bumping the guide tended to bend the filament where it exited the block. To prevent that, I hot-melt-glued the guide to the block, which really wasn’t particularly elegant. This picture shows the X-min switch relocated to contact the platform, with the slightly out of focus blob anchoring the guide off to the right:

    M2 - Z-min switch at rear X gantry
    M2 – Z-min switch at rear X gantry

    Makergear provides STL files of the M2’s printable bits, including several versions of the wire cover block. This corresponds to the one on my M2, although the rounded edges don’t come through in the plastic very welll:

    Stock M2 Wire Cover Filament Guide - solid model
    Stock M2 Wire Cover Filament Guide – solid model

    Because STL files aren’t editable, I reverse-engineered the dimensions into an OpenSCAD model that I could use as the basis for a different guide. This is just the basic wire cover, minus the filament guide extension, plus a flat end that wraps around the edge of the chassis:

    M2 Wire Cover - reverse engineered
    M2 Wire Cover – reverse engineered

    The trick is to import the STL into OpenSCAD, then build a model that matches the key dimensions. Fortunately, Makergear used hard metric sizes for everything, so most of the numbers came out as integers or single-place decimals:

    M2 Wire Cover Filament Guide - overlay reverse engineered
    M2 Wire Cover Filament Guide – overlay reverse engineered

    The shimmer indicates coincident surfaces; that’s ordinarily a Very Bad Thing, but in this case it shows that the dimensions match. The top of the holes have neat hexagonal patterns where my straight-sided PolyHoles extend through their chamfered circular holes:

    M2 Wire Cover Filament Guide - overlay - hole detail
    M2 Wire Cover Filament Guide – overlay – hole detail

    Unlike my from-scratch OpenSCAD models, this one bristles with magic numbers that describe the dimensions of the M2 STL model. The basic shape comes from an extruded polygon matching the outside walls, another extruded polygon knocking out the wire channel, then cubes lopping off the top surfaces:

    M2 Wire Cover Filament Guide - overlay - F12 view
    M2 Wire Cover Filament Guide – overlay – F12 view

    The end result of all that thrashing around has a certain Soviet Concrete look to it:

    M2 Wire Cover - OpenSCAD solid model
    M2 Wire Cover – OpenSCAD solid model

    This version lacks the filament guide; I wanted to make sure all the protrusions and channels fit, which they sort of did:

    M2 reverse engineered wire cover - installed
    M2 reverse engineered wire cover – installed

    The next version will have slightly more clearance on the side and slightly less on the top; that’s easy to do now that I have an editable OpenSCAD model.

    The OpenSCAD source code:

    // Improved M2 filament guide and X-min switch wire guide
    // Ed Nisley KE4ZNU - Oct 2013
    
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    
    Protrusion = 0.1;
    
    HoleWindage = 0.2;
    
    //- Sizes
    
    PlateMinThick = 8.0;				// basic thickness excluding wire guides
    PlateLength = 5.0;					// from side of frame beyond top wire guide
    
    TopGuideLength = 7.0;				// protrusion from plate
    
    PlateThick = PlateMinThick + TopGuideLength;
    
    echo(str("Total thickness: ",PlateThick));
    
    //- 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);
    }
    
    //- Put peg grid on build surface
    
    module ShowPegGrid(Space = 10.0,Size = 1.0) {
    
      RangeX = floor(100 / Space);
      RangeY = floor(125 / Space);
    
    	for (x=[-RangeX:RangeX])
    	  for (y=[-RangeY:RangeY])
    		translate([x*Space,y*Space,Size/2])
    		  %cube(Size,center=true);
    
    }
    
    //- Define basic block shape
    //  Mostly reverse engineered from
    //    https://github.com/MakerGear/M2/blob/master/Printed%20Parts/STL/M2%20X%20Endstop%20Wire%20Cover%20with%20Filament%20Guide.stl
    //	Hence all the magic numbers...
    
    module BaseBlock() {
    
    SideGuideLength = 4.0;				// protrusion = even with frame interior
    ChannelDepth = 4.5;					// wiring channel
    FrameOffset = 28;
    
    	translate([18,FrameOffset,0]) {			// align neatly for later processing
    
    		if (true)
    			color("Green",0.3)
    				translate([-18,22,15])
    					rotate([-90,0,-90])
    						import("/mnt/bulkdata/Project Files/Thing-O-Matic/M2 Parts/Filament Guide/M2+X+Endstop+Wire+Cover+with+Filament+Guide.stl",
    								convexity=10);
    
    		difference() {
    			linear_extrude(height=PlateThick,convexity=5)		// main block
    				polygon(points=[[0,0],[0,22],[12,22],[12,7.5],[22,7.5],
    								[22,-(PlateLength + FrameOffset)],[-18,-(PlateLength + FrameOffset)],
    								[-18,0]
    						]);
    
    			for (i=[-1,0])
    				translate([17,((i*15.0)+ 1.05),-Protrusion])
    					rotate(180/6) {
    						PolyCyl(3.1,(PlateMinThick + 2*Protrusion),6);		// screw holes
    						PolyCyl(5.7,(3.0 + Protrusion),6);					//  ... countersink
    					}
    
    			translate([0,0,(PlateMinThick - ChannelDepth)])		// wire channel
    				linear_extrude(height=15,convexity=5)
    					polygon(points=[[2,-5],[2,19],[10,19],[10,-22],[-15,-22],[-15,-5]
    							]);
    
    			translate([-10,14,PlateMinThick])				// M2 frame
    				rotate(-90)
    					cube([42,35,10],center=false);
    
    			translate([-5,5,(PlateMinThick + SideGuideLength)])	// shorten side guide
    				cube([20,20,10],center="false");
    
    		}
    	}
    
    }
    
    //- Build it
    
    ShowPegGrid();
    
    BaseBlock();
    
  • Kitchen Sink Faucet: Base Rejuvenation

    The kitchen sink has a small faucet that used to connect directly to the well out back, but now delivers town water from a line bypassing the water softener. The large steel washer below the sink deck has been shedding rust for a while and finally disintegrated:

    Kitchen faucet - rusted washer assembly
    Kitchen faucet – rusted washer assembly

    Well, this is a perfect application for plastic, not steel, so I conjured up a pair of disks:

    Sink Base - Build
    Sink Base – Build

    The large flat one goes below the sink deck in place of the steel washer and the smaller part of the stepped disk fits inside the deck opening to stabilize the faucet:

    Sink Base - Show
    Sink Base – Show

    The two dark rings bracketing the deck between the orange plastic disks represent a pair of gaskets / washers / seals cut from 1 mm rubber sheet with a straight razor toting compass:

    Kitchen faucet - plastic disks and rubber deck washers
    Kitchen faucet – plastic disks and rubber deck washers

    Just for fun, I used Slic3r’s Hilbert Curve top and bottom fill pattern. It produces a nice, grainy texture that feels appropriate for anything needing a non-slip grip (at least on the top, as the bottom surface is glass-smooth).

    Everything stacks up thusly, with the top dark ring representing a rubber seal that came with the faucet:

    Sink Base - Assemble
    Sink Base – Assemble

    It looks about the same in real life, albeit minus all the colors:

    Kitchen faucet - fitting stack
    Kitchen faucet – fitting stack

    The black plastic and black rubber blend together and vanish amid all the chrome:

    Kitchen faucet - assembled
    Kitchen faucet – assembled

    Alas, when I turned the water on, Mary said “That doesn’t sound right…” at about the same time I discovered a fine mist under the sink. See if you can spot the problem:

    Kitchen faucet - corroded copper tube
    Kitchen faucet – corroded copper tube

    A shined-up view should make it obvious:

    Kitchen faucet - corroded copper tube - pinhole
    Kitchen faucet – corroded copper tube – pinhole

    A trip to the precious metals aisle of the Big Box Home Repair Store produced a roll of 3/8 inch copper tubing, although I should have the stub end of that original roll somewhere in the heap. The fitting at the bottom of the faucet turned out to be completely non-standard and I had to re-use it with the new tubing, but it still sealed perfectly.

    I hate plumbing jobs. That fix better last for another decade…

    The OpenSCAD source code:

    // Sink faucet bottom seal
    // Ed Nisley KE4ZNU - Oct 2013
    
    Layout = "Assemble";				// Build Show Upper Lower Gasket
    
    Plastic = "Orange";
    Rubber = "DarkSlateGray";
    
    //- Extrusion parameters - must match reality!
    
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    
    Protrusion = 0.1;
    
    HoleWindage = 0.2;
    
    Gap = 10.0;
    
    //- Dimensions
    
    FaucetOD = 32.0;
    
    UpperOD = 44.5;
    UpperThick = IntegerMultiple(1.0,ThreadThick);
    
    DeckHoleOD = 37.5;
    DeckThick = IntegerMultiple(1.0,ThreadThick);
    
    LowerOD = 50.0;
    LowerThick = IntegerMultiple(5.0,ThreadThick);
    
    PipeOD = 11.0;
    PipeLength = 50;			// for Show layout
    
    GasketThick = 1.0;
    TopGasket = [FaucetOD,PipeOD,GasketThick];
    MidGasket = [UpperOD,DeckHoleOD,GasketThick];
    BotGasket = [LowerOD,PipeOD,GasketThick];
    
    NumSides = 4*12;
    
    //- 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);
    }
    
    //- Put peg grid on build surface
    
    module ShowPegGrid(Space = 10.0,Size = 1.0) {
    
      RangeX = floor(100 / Space);
      RangeY = floor(125 / Space);
    
    	for (x=[-RangeX:RangeX])
    	  for (y=[-RangeY:RangeY])
    		translate([x*Space,y*Space,Size/2])
    		  %cube(Size,center=true);
    
    }
    
    module UpperDisk() {
    	difference() {
    		union() {
    			cylinder(r=UpperOD/2,h=UpperThick,$fn=NumSides);
    			cylinder(r=DeckHoleOD/2,h=(DeckThick + UpperThick + GasketThick),$fn=NumSides);
    		}
    		translate([0,0,-Protrusion])
    			PolyCyl(PipeOD,(DeckThick + UpperThick + GasketThick + 2*Protrusion));
    	}
    }
    
    module LowerDisk() {
    	difference() {
    		cylinder(r=LowerOD/2,h=LowerThick,$fn=NumSides);
    		translate([0,0,-Protrusion])
    			PolyCyl(PipeOD,(LowerThick + 2*Protrusion));
    	}
    }
    
    module MakeGasket(Gasket=[10,5,1],Color=Rubber) {
    	color(Color)
    		difference() {
    			cylinder(r=Gasket[0]/2,h=Gasket[2]);
    			translate([0,0,-Protrusion])
    				PolyCyl(Gasket[1],(Gasket[2] + 2*Protrusion));
    		}
    
    }
    
    module SinkDeck() {
    	color("LightSlateGray")
    		difference() {
    			translate([-LowerOD,-LowerOD,0])
    				cube([2*LowerOD,2*LowerOD,DeckThick]);
    			translate([0,0,-DeckThick])
    				cylinder(r=DeckHoleOD/2,h=3*DeckThick);
    		}
    
    }
    
    //- Build it
    
    ShowPegGrid();
    
    if (Layout == "Upper")
    	UpperDisk();
    
    if (Layout == "Lower")
    	LowerDisk();
    
    if (Layout == "Gasket")
    	MakeGasket(MidGasket);
    
    if (Layout == "Show") {
    	color(Plastic)
    	translate([0,0,(UpperThick + DeckThick + Gap)])
    		rotate([180,0,0])
    			UpperDisk();
    
    	color(Plastic)
    	translate([0,0,-(Gap + LowerThick)])
    		LowerDisk();
    
    	color("Yellow",0.25)
    		translate([0,0,-PipeLength/2])
    			PolyCyl(0.9*PipeOD,PipeLength,NumSides);
    
    	color("DarkSlateGray")
    		difference() {
    			translate([0,0,3*Gap/2])
    				cylinder(r=FaucetOD/2,h=GasketThick);
    			translate([0,0,-25])
    				cylinder(r=PipeOD/2,h=50);
    		}
    
    	translate([0,0,3*Gap/2])
    		MakeGasket(TopGasket);
    
    	translate([0,0,-DeckThick])
    		SinkDeck();
    
    	translate([0,0,Gap/2])
    		MakeGasket(MidGasket);
    
    	translate([0,0,-Gap/2])
    		MakeGasket(BotGasket);
    
    }
    
    if (Layout == "Assemble") {
    	color(Plastic)
    	translate([0,0,(UpperThick + GasketThick)])
    		rotate([180,0,0])
    			UpperDisk();
    
    	color(Plastic)
    	translate([0,0,-(LowerThick + DeckThick + GasketThick)])
    		LowerDisk();
    
    	color("Yellow",0.25)
    		translate([0,0,-PipeLength/2])
    			PolyCyl(PipeOD,PipeLength,NumSides);
    
    	translate([0,0,-DeckThick])
    		SinkDeck();
    
    	color("DarkSlateGray")
    		difference() {
    			translate([0,0,3*Gap/2])
    				cylinder(r=FaucetOD/2,h=GasketThick);
    			translate([0,0,-25])
    				cylinder(r=PipeOD/2,h=50);
    		}
    
    	translate([0,0,3*Gap/2])
    		MakeGasket(TopGasket);
    
    	MakeGasket(MidGasket);
    
    	translate([0,0,-(DeckThick + GasketThick)])
    		MakeGasket(BotGasket);
    
    }
    
    if (Layout == "Build") {
    	translate(0.75*[UpperOD,UpperOD,0]/2)
    		UpperDisk();
    	translate(0.75*[-LowerOD,-LowerOD,0]/2)
    		LowerDisk();
    }
    

    As a reward for being the type of person who reads all the way to the end, yes, that’s a riff on Poke Salad Annie.

  • Makergear M2: Relocating the Z-Min Switch

    Fairly obviously, taping the Z-min switch to the back of the X gantry isn’t a long-term solution. There’s just enough clearance between the extruder and the X gantry for the switch, so I made a small block with clearance holes for the screws holding the X axis linear slide rail in place and tapping holes for the M2.5×0.45 screws in the switch:

    Z-min Front Mount Switch Block - solid model
    Z-min Front Mount Switch Block – solid model

    Not much to it, is there? That printed just fine with the taped-in-place switch and exactly fit the screws; the rail screws dropped right through the holes and the switch screws tapped their way in.

    The stock M2 cable reaches to the front of the X gantry, but only with the switch mounted to the left side:

    M2 Z-min switch - left gantry
    M2 Z-min switch – left gantry

    Those are 25 mm M3 screws shortened to about 19 mm; the one on the right looks a bit short to me, too.

    Unfortunately, that spot on the gantry is the only place you can pick up the M2 with one hand: it balances perfectly when you (well, I) put four fingers between the five leftmost rail screws. It’s a beast to carry any other way, so that switch had to move.

    So I spliced in a snippet of six conductor cable, just so I could match the original color code, replaced the red through-hold LED with a blue SMD LED, and moved it to the middle of the gantry:

    M2 Z-min switch - center gantry
    M2 Z-min switch – center gantry

    The view from below shows a sticky clamp holding a bight of the original cable and a small clamp (bent & drilled from a steel strap) holding the new cable in place:

    M2 Z-min switch - center gantry - bottom view
    M2 Z-min switch – center gantry – bottom view

    It’s once again possible to grab the printer and lug it away…

    The first test piece was Madscifi’s classic Tiny Toy Dump Truck, because I needed a show-n-tell tchotchke for a Squidwrench meeting:

    M2 Z-min switch - center gantry - in action
    M2 Z-min switch – center gantry – in action

    Yes, that dangling switch lever looks precarious, but it can’t touch the platform because the nozzle is below it.

    With the switch in place, I melted a blob of solder atop the brass tubing on the platform, popped it off, and removed the residue with a razor scraper.

    Before doing the truck, however, I had to recalibrate the Z switch and make the homing sequence do a different dance:

    • Home Y and leave the platform at the rear
    • Home X and move it to the far right to clear the platform
    • Home Z against the platform glass

    The complete start.gcode sequence (which isn’t really a separate file in Slic3r, but the notation helps keep things straight):

    ;-- Slic3r Start G-Code for M2 starts --
    ;  Ed Nisley KE4NZU - 7 Oct 2013
    ; Z-min switch at platform, must move nozzle to X=130 to clear platform
    M140 S[first_layer_bed_temperature]	; start bed heating
    G90				; absolute coordinates
    G21				; millimeters
    M83				; relative extrusion distance
    M84				; disable stepper current
    ;G4 S3			; allow Z stage to freefall to the floor
    G28 Y0			; home Y to be sure of clearing probe point in X
    G92 Y-127 		; set origin to 0 = center of plate
    G28 X0			; home X
    G92 X-95		; set origin to 0 = center of plate
    G1 X130 F30000	; move off platform to right side
    G28 Z0			; home Z
    G92 Z-4.55		; set origin to measured z offset
    G0 Z10 F2000    ; get nozzle clearance
    G0 X0 Y-124 Z3.0 F20000     ; set up for priming
    M190 S[first_layer_bed_temperature]	; wait for bed to finish heating
    M109 S[first_layer_temperature]	; set extruder temperature and wait
    G1 Z0.0 F2000	; plug extruder on plate
    G1 E10 F300		; prime to get pressure
    G1 Z5 F2000		; rise above blob
    G1 X5 Y-123 F30000	; move away from blob
    G1 Z0.0 F2000		; dab nozzle to remove outer snot
    G4 P1			; pause to clear
    G1 Z0.5 F2000		; clear bed for travel
    ;-- Slic3r Start G-Code ends --
    

    The G92 Z-4.55 instruction sets the Z position (without moving the stage) to the measured difference between the switch trip point and the nozzle tip.

    Finding that value is a two-step process:

    • Manually home Z against the platform (with the nozzle off to the right!)
    • Issue G92 Z0 to define the switch trip point as Z=0.0
    • Move the Z stage downward by a known distance so it clears the nozzle
    • Move the nozzle over the platform
    • Measure the distance between nozzle and platform (perhaps with a tapered gauge)
    • Subtract that measurement from the distance you moved the nozzle

    For example, I lowered the platform by 7.0 mm and measured 2.6 mm between the nozzle and the platform, so the G92 value = -7.0 + 2.6 = -4.4. Put that in the start.gcode G92 instruction: G92 Z-4.4.

    That’ll get you in the ballpark, so print a thinwall open box and measure its top-to-bottom height at the corners. The second box came out about 4.85 mm tall, which means the nozzle was 0.15 mm too close to the platform: subtract 0.15 from the G92 setting: -4.4 – 0.15 = -4.55.

    The next thinwall box came out exactly 5.0 mm tall.

    Then I could print that truck, which came out just fine, apart from the usual slight drooping where the filament must bridge the left side of the dump box:

    M2 Tiny Toy Dump Truck test piece
    M2 Tiny Toy Dump Truck test piece

    After breaking one errant strand from the left side of the hinge, everything moved smoothly.

    I must tinker up some G-Code to measure the switch closure point along the length of the platform, which would detect front-to-back tilt.

    The OpenSCAD source code for the switch mounting block:

    // Block to mount M2 Z-min switch on X gantry
    // Ed Nisley KE4ZNU - Oct 2013
    
    //- Extrusion parameters - must match reality!
    
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    
    Protrusion = 0.1;
    
    HoleWindage = 0.2;
    
    //- Sizes
    
    SwitchScrewOD = 2.05;					// microswitch screw tapping
    SwitchScrewOC = 9.5;					//  ... on-center spacing
    
    GantryScrewOD = 3.0;					// X rail screw clearance
    GantryScrewOC = 25.0;					//  ... on-center spacing along X
    GantryScrewOffset = 12.0;				//  ... Y offset from gantry front
    
    BlockSize = [1.5*GantryScrewOC,17.0,5.0];			// XYZ dimensions as mounted
    
    SwitchScrewLength = BlockSize[1] - 5*ThreadWidth;	// net length of switch screws
    echo ("Max switch screw length: ",SwitchScrewLength + 5.0);		// ... allow switch thickness
    
    //- 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);
    }
    
    //- Put peg grid on build surface
    
    module ShowPegGrid(Space = 10.0,Size = 1.0) {
    
      RangeX = floor(100 / Space);
      RangeY = floor(125 / Space);
    
    	for (x=[-RangeX:RangeX])
    	  for (y=[-RangeY:RangeY])
    		translate([x*Space,y*Space,Size/2])
    		  %cube(Size,center=true);
    
    }
    
    //- Build it
    
    ShowPegGrid();
    
    difference() {
    	translate([-BlockSize[0]/2,-GantryScrewOffset,0])
    		cube(BlockSize,center=false);
    	for (i=[-1,1]) {
    		translate([i*GantryScrewOC/2,0,-Protrusion])
    			rotate(-90)
    				PolyCyl(GantryScrewOD,(BlockSize[2] + 2*Protrusion));
    		translate([i*SwitchScrewOC/2,-(GantryScrewOffset + Protrusion),BlockSize[2]/2])
    			rotate([-90,0,0])
    				rotate(90)
    					PolyCyl(SwitchScrewOD,(SwitchScrewLength + Protrusion));
    	}
    }