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

  • Planetary Gear Bearing: Now With Knurling!

    OK, I couldn’t resist. Tweaking a few lines of code wrapped a knurl around emmitt’s Gear Bearing for enhanced griptivity:

    Knurled vs original Planetary Gear Bearing
    Knurled vs original Planetary Gear Bearing

    That image has desaturated red to suppress the camera’s red burnout. It looks better in the realm of pure math:

    Planetary Gear Bearing - Kurled - solid model
    Planetary Gear Bearing – Kurled – solid model

    Reducing the tolerance parameter to 0.4 produced a surprisingly rigid, yet freely turning, bearing that required no cleanup: it popped off the plate ready to roll!

    The heavy lifting in the OpenSCAD source code remains emmitt’s work. I replaced the outer cylinder with a knurl and simplified his monogram to stand out better amid the diamonds. This is the affected section:

    ... snippage ...
    translate([0,0,T/2]){
    	difference(){
    //		cylinder(r=D/2,h=T,center=true,$fn=100);
    		render(convexity=10)
    		translate([0,0,-T/2])
    			knurl(k_cyl_hg=T,
    			k_cyl_od=D,
    			knurl_wd=5.0,
    			knurl_hg=5.0,
    			knurl_dp=0.5,
    			e_smooth=5.0/2);
    		herringbone(nr,pitch,P,DR,-tol,helix_angle,T+0.2);
    //		difference(){
    			translate([0,-(D/2+4.5),0])rotate([90,0,0])monogram(h=10);
    //			cylinder(r=D/2-0.25,h=T+2,center=true,$fn=100);
    //		}
    	}
    	rotate([0,0,(np+1)*180/ns+phi*(ns+np)*2/ns])
    	difference(){
    		mirror([0,1,0])
    			herringbone(ns,pitch,P,DR,tol,helix_angle,T);
    		cylinder(r=w/sqrt(3),h=T+1,center=true,$fn=6);
    	}
    	for(i=[1:m])rotate([0,0,i*360/m+phi])translate([pitchD/2*(ns+np)/nr,0,0])
    		rotate([0,0,i*ns/m*360/np-phi*(ns+np)/np-phi])
    			render(convexity=10)
    			herringbone(np,pitch,P,DR,tol,helix_angle,T);
    }
    

    I also added a few render(convexity=n) operations to improve the preview, but that’s just cosmetic.

  • Upstart vs. NFS Mounts vs. Display Manager: Resolved!

    Quick summary: the current Linux startup machinery Runs All The Things! in parallel, leaving you to figure out all the interdependencies and update all the script files to match your requirements. Mostly, the distro maintainers figure all that, but if you have essential files mounted as NFS shares, then you can will reach a login screen before the mount process completes.

    Having wrestled with this problem for a while, I think I’ve doped out the right way to coerce the Upstart Pachinko Machine to converge on a workable login.

    The solution is to fire off a unique signal after the NFS mount command, then force the display manager to wait until it receives that signal, rather than depend on happenstance as I did before. The mounts occur in /etc/init/local.conf, which now looks like this:

    description "Stuff that should be in /etc/rc.local"
    author "Ed Nisley - KE4ZNU"
    
    start on (local-filesystems and net-device-up IFACE=em1)
    stop on shutdown
    
    emits nfs-mounted
    
    script
    
    logger Starting local init...
    
    logger Mounting NFS filesystems
    mount /mnt/bulkdata
    mount /mnt/userfiles
    mount /mnt/diskimages
    mount /mnt/music
    initctl emit nfs-mounted
    logger Ending local init
    
    end script
    

    The start condition ensures that this code won’t run until the wired LAN is up; note that what was once eth0 is now em1. Then, after the mounts happen, initctl fires the nfs-mounted signal.

    The modification to /etc/init/lightdm.conf script consists of one additional line to wait for that signal:

    start on ((filesystem
               and runlevel [!06]
               and started dbus
               and plymouth-ready
               and nfs-mounted)
              or runlevel PREVLEVEL=S)
    
    stop on runlevel [016]
    
    emits login-session-start
    emits desktop-session-start
    emits desktop-shutdown
    

    I’m not convinced lightdm.conf is the right spot to jam a stick in the gears, but it seems to be the least-awful alternative. The login-session-start signal doesn’t appear in any file in that subdirectory and I have no idea where else to look.

    Anyhow, the greeter screen now shows a desktop background from the NFS mount, which I regard as A Good Sign:

    Xubuntu greeter - after NFS fix
    Xubuntu greeter – after NFS fix

    Until the next startup revision, anyway…

  • Sherline Four-Jaw Chuck Speed Wrenches: 3D Printed Edition

    A Home Shop Machinist article (A Speed Key for Your Four-Jaw Chuck, p 67 Nov-Dec 2013, David Morrow) showed some lovely knurled steel knobs. These 3D printed knobs aren’t nearly as pretty, but they do much the same thing:

    Sherline Knobs - in 4 jaw chuck
    Sherline Knobs – in 4 jaw chuck

    The solid model resembles the illegitimate offspring of a wine bottle and a pineapple:

    Sherline Knob - solid model
    Sherline Knob – solid model

    The knurling comes from aubenc’s Knurled Surface Library v2. I ran off a prototype (on the left), then tweaked the dimensions to get the final version on the right:

    Sherline Knobs - knurl depth variation
    Sherline Knobs – knurl depth variation

    Being that type of guy, I define the knurl in terms of its diametral pitch, compute the diamond width & length to fit in the available space, then hand those measurements to the knurling library… which recomputes everything and decides on one less diamond than I do: NumSides has a Finagle Constant of -1 to make the answer come out right. We may be using a different diameter or something, but I haven’t deciphered the source code. It’s parametric out the wazoo, as usual, so you can spin up what you like, how you like it.

    Anyhow, a 24 DP knurl with 1.0 mm depth looks and feels pretty good; the XY resolution isn’t good enough for a 48 DP knurl around that knob diameter. The diamonds don’t come out as crisp and pointy as crushed steel knurls, but they’re OK for my fingers.

    Doing half a dozen doesn’t take much longer than doing a few, because there’s a 20 second minimum layer time in effect and those things don’t have much plastic, so now I have one for the hold-down clamps and another for Show-n-Tell sessions:

    Sherline Knobs - M2 platform
    Sherline Knobs – M2 platform

    I chopped a 5/32 inch hex key into five 15 mm lengths with a Dremel cutoff wheel, then filed both ends flat and broke the edges. The hex stubs were a press fit in the hex holes, so I finger-started them, grabbed the hex in the drill press, aligned the handle below, and rammed the stub about 5 mm deep. The final depth comes from jamming the wrench into the chuck and pressing firmly, so the stubs project exactly as far as possible:

    Sherline Knobs - hex key inserted
    Sherline Knobs – hex key inserted

    One might quibble about the infill on the end; one may go adjust one’s own printer as one prefers.

    There’s 0.1 mm more HoleWindage than usual, because these holes must fix a hex shaft, not a circular pin, and the corners need some clearance. They came out a firm press fit: exactly what’s needed.

    They’re no good for final tightening of those chuck jaws, but that’s not their purpose…

    The OpenSCAD source code:

    // Knurled handles for Sherline hex keys
    // Ed Nisley - KE4ZNU - November 2013
    
    use <knurledFinishLib_v2.scad>
    
    //- Extrusion parameters must match reality!
    //  Print with 2 shells and 3 solid layers
    
    ThreadThick = 0.20;
    ThreadWidth = 0.40;
    
    HoleWindage = 0.3;			// extra clearance to improve hex socket fit
    
    Protrusion = 0.1;			// make holes end cleanly
    
    PI = 3.14159265358979;
    inch = 25.4;
    
    //----------------------
    // Dimensions
    
    ShaftDia = 10.5;				// un-knurled section diameter
    ShaftLength = 15.0;				//  ... length
    
    SocketDia = (5/32) * inch;		// hex key size
    SocketDepth = 10.0;
    
    KnurlLen = 20.0;				// length of knurled section
    KnurlDia = 15.0;				//   ... diameter
    KnurlDPNom = 24;				// Nominal diametral pitch = (# diamonds) / (OD inches)
    
    DiamondDepth = 1.0;				//   ... depth of diamonds
    DiamondAspect = 2;				// length to width ratio
    
    NumDiamonds = floor(KnurlDPNom * KnurlDia / inch);
    echo(str("Num diamonds: ",NumDiamonds));
    
    NumSides = 4*(NumDiamonds - 1);		// 4 facets per diamond. Library computes diamonds separately!
    
    KnurlDP = NumDiamonds / (KnurlDia / inch);				// actual DP
    echo(str("DP Nom: ",KnurlDPNom," actual: ",KnurlDP));
    
    DiamondWidth = (KnurlDia * PI) / NumDiamonds;
    
    DiamondLenNom = DiamondAspect * DiamondWidth;					// nominal diamond length
    DiamondLength = KnurlLen / round(KnurlLen/DiamondLenNom);		//  ... actual
    
    TaperLength = 0.75*DiamondLength;
    
    //----------------------
    // Useful routines
    
    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);
    }
    
    module ShowPegGrid(Space = 10.0,Size = 1.0) {
    
      Range = floor(50 / Space);
    
    	for (x=[-Range:Range])
    	  for (y=[-Range:Range])
    		translate([x*Space,y*Space,Size/2])
    		  %cube(Size,center=true);
    }
    
    //- Build it
    
    ShowPegGrid();
    
    difference() {
    	union() {
    		render(convexity=10)
    		translate([0,0,TaperLength])
    			knurl(k_cyl_hg=KnurlLen,
    				  k_cyl_od=KnurlDia,
    				  knurl_wd=DiamondWidth,
    				  knurl_hg=DiamondLength,
    				  knurl_dp=DiamondDepth,
    				  e_smooth=DiamondLength/2);
    		color("Orange")
    		cylinder(r1=ShaftDia/2,
    					r2=(KnurlDia - DiamondDepth)/2,
    					h=(TaperLength + Protrusion),
    					$fn=NumSides);
    		color("Orange")
    		translate([0,0,(TaperLength + KnurlLen - Protrusion)])
    			cylinder(r2=ShaftDia/2,
    					r1=(KnurlDia - DiamondDepth)/2,
    					h=(TaperLength + Protrusion),
    					$fn=NumSides);
    		color("Moccasin")
    		translate([0,0,(2*TaperLength + KnurlLen - Protrusion)])
    			cylinder(r=ShaftDia/2,h=(ShaftLength + Protrusion),$fn=NumSides);
    
    	}
    	translate([0,0,(2*TaperLength + KnurlLen + ShaftLength - SocketDepth + Protrusion)])
    		PolyCyl(SocketDia,(SocketDepth + Protrusion),6);
    }
    

    This might be a good stocking stuffer for that guy who has everything, but you’d need his shop to make it, so what’s the point in that?

  • Samsung Quiet Jet Vacuum: Improved Floor Brush Strips

    Those simple floor brush strips for the Samsung vacuum cleaner worked moderately well, but the urethane adhesive didn’t have enough grip on the plastic strips. Having just run out of that batch, I made up another set with slightly undercut holes:

    Bushing Solid Model - better holes - bottom
    Bushing Solid Model – better holes – bottom

    That’s half a thread width on each side, just enough to give the adhesive something to grab. Such is the plan, anyway.

    I taped the strips to a pair of credit cards (actually, flat cards without embossed characters), slathered a thin layer of urethane atop them, and laid on squares of the same wool fabric I used the last time:

    Samsung vacuum floor strips - gluing
    Samsung vacuum floor strips – gluing

    Then I piled a steel block atop an aluminum slab on both arrays, fast forwarded a day, peeled and flexed and cut the strips apart:

    Samsung floor brushes - glued
    Samsung floor brushes – glued

    The urethane foamed through the holes as I hoped and (seems to have) locked the fabric in place, at least well enough to withstand some experimental bending on the workbench.

    Now, to see how they stand up to actual use…

    The OpenSCAD source code:

    // Samsung Vacuum cleaner nozzle floor strips
    // Ed Nisley KE4ZNU January 2013
    //  November 2013 - adapt to M2, enlarge holes
    
    Layout = "Build";			// Show, Build
    
    //- Extrusion parameters must match reality!
    //  Print with +0 shells and 3 solid layers
    
    ThreadThick = 0.25;
    ThreadWidth = 0.4;
    
    HoleWindage = 0.75;
    
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    
    Protrusion = 0.1;           // make holes end cleanly
    
    //----------------------
    // Dimensions
    
    Body = [6.0,59.0,3*ThreadThick];	// width, length, thick
    
    Tab1 = [4.5,5.0,0.0];				// width, length, offset from centerline
    Tab2 = [3.5,5.0,0.5];
    
    HoleOC = 8.0;						// adhesive anchoring holes
    HoleDia = 2.0;
    HoleSides = 4;
    HoleMax = floor(Body[1]/(2*HoleOC));
    
    echo("HoleMax: ",HoleMax);
    
    //----------------------
    // Useful routines
    
    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);
    }
    
    module ShowPegGrid(Space = 10.0,Size = 1.0) {
    
        Range = floor(50 / Space);
    
        for (x=[-Range:Range])
            for (y=[-Range:Range])
                translate([x*Space,y*Space,Size/2])
                %cube(Size,center=true);
    
    }
    
    module BackingStrip() {
    
    	difference() {
    		union() {
    			translate([0,0,Body[2]/2])
    			cube(Body,center=true);
    			translate([Tab1[2],-1*Body[1]/2,Body[2]/2])
    			cube([Tab1[0],2*Tab1[1],Body[2]],center=true);
    			translate([Tab2[2],+1*Body[1]/2,Body[2]/2])
    			cube([Tab2[0],2*Tab2[1],Body[2]],center=true);
    		}
    		for (i = [-HoleMax:HoleMax])
    			translate([0,i*HoleOC,-Protrusion])
    			rotate(45) {
    				PolyCyl(HoleDia,(Body[2] + 2*Protrusion),HoleSides);
    				PolyCyl((HoleDia + ThreadWidth),(ThreadThick + Protrusion),HoleSides);
    			}
    	}
    }
    
    //----------------------
    // Build it!
    
    ShowPegGrid();
    
    if (Layout == "Show")
    	BackingStrip();
    
    if (Layout == "Build")
    	rotate(90) BackingStrip();
    
    
  • HP Scope Probe Flange Repair: Improved Spares

    While reducing the clutter atop the Electronics Workbench, I ran off four more probe flange reinforcements, just so I’m ready for the next crunch:

    HP scope probe flange disks
    HP scope probe flange disks

    They’re almost identical to the previous version, although I tweaked the taper to end slightly inside the cylindrical cup, thereby eliminating the coincident faces and leaving a minute rim that doesn’t matter:

    HP Scope Probe Flange Repair - bottom
    HP Scope Probe Flange Repair – bottom

    Given that I’ve had the ‘scope for nigh onto two decades and have only broken one probe flange, I think four reinforcements will be a lifetime supply: with any luck, the scope will blow a capacitor before I do.

    The OpenSCAD source code:

    // Tek Scope Probe Flange
    // Ed Nisley KE4ZNU November 2013
    
    //- Extrusion parameters must match reality!
    //  Print with 2 shells and 3 solid layers
    
    ThreadThick = 0.20;
    ThreadWidth = 0.40;
    
    HoleWindage = 0.2;
    
    Protrusion = 0.1;            // make holes end cleanly
    
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    
    //----------------------
    // Dimensions
    
    FlangeOD = 16.0;
    FlangeID = 8.75;
    FlangeThick = IntegerMultiple(1.25,ThreadThick);
    
    DiskOD = FlangeOD + 4*ThreadWidth;
    DiskThick = FlangeThick + 4*ThreadThick;
    
    NumSides = 8*4;
    
    //----------------------
    // Useful routines
    
    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);
    }
    
    module ShowPegGrid(Space = 10.0,Size = 1.0) {
    
    Range = floor(50 / Space);
    
    for (x=[-Range:Range])
    for (y=[-Range:Range])
    translate([x*Space,y*Space,Size/2])
    %cube(Size,center=true);
    
    }
    
    //----------------------
    // Build it
    
    ShowPegGrid();
    
    difference() {
    union() {
    translate([0,0,2*ThreadThick])
    cylinder(r=DiskOD/2,h=DiskThick,$fn=NumSides);    // cylinder around flange
    
    cylinder(r1=(DiskOD - 2*ThreadWidth)/2,                // flange reinforcing plate
    r2=DiskOD/2,
    h=(2*ThreadThick + Protrusion),
    $fn=NumSides);
    }
    translate([0,0,(DiskThick - FlangeThick)])                // flange clearance
    PolyCyl(FlangeOD,2*FlangeThick,NumSides);
    
    translate([0,0,-DiskThick/2])                            // probe nose clearance
    PolyCyl(FlangeID,2*DiskThick,NumSides);
    }
    
  • PVC Cement Can Lid Griptivity Improvement

    I’ve been doing a lot of fiddly gluing lately and, despite my best efforts, some adhesive collects in the lid’s screw threads. The gummy residue makes it really hard to unscrew the lid without a strap wrench after a few days.

    Wrapping two turns of silicone tape around the cap helps tremendously:

    Silicone tape on PVC cement can lid
    Silicone tape on PVC cement can lid

    It’s obvious in retrospect, is all I can say…

  • Dehumidified Processor Crackers

    The cracker recipe I’m using produces eight sets of crackers, so this time I added a variety of toppings to see what would work out best:

    • Plain
    • Salt
    • Sugar
    • Cinnamon
    • Garlic
    • Chopped chocolate
    • Chopped cashews
    • Chopped walnuts

    Garlic wins over everything else, hands-down, no contest, but the mixture of all the toppings in the bottom of the cooling bowl was wonderful.

    The crackers went into a large pot with a bag of desiccant:

    Whole wheat crackers with desiccant
    Whole wheat crackers with desiccant

    It pulled out 30 grams of water while reducing the humidity to 20% overnight; the crackers started out crisp and became really snappy. Definitely the right way to get the job done.

    These vaguely resemble the Processor Crackers recipe in Flatbreads & Flavors (Alford & Duguid):

    • 3 C hard whole wheat flour
    • 1 tsp salt
    • 1 C warm water, more as needed
    • Toppings
    • Water sprayer

    I’m using coarse-ground red wheat that doesn’t soak up the water like fine-ground flour. The original recipe called for 1-½ C water, which produced a sticky ball.

    • Blend wheat & salt in food processor
    • Add water in a slow stream until dough firms up
    • Blend another minute
    • Knead half a minute on cutting board
    • Cover
    • Let rest 30 minutes while you prepare toppings

    Finely chopped toppings work best; the nuts were too coarse.

    • Preheat oven to 500 °F
    • Divide dough in eight pieces, cover

    For each piece of dough:

    • Roll to about 2 mm
    • Put dough on vented pizza pan
    • Cut cracker shapes with pizza cutter
    • Sprinkle topping
    • Spritz with water
    • Put in oven on top rack
    • Punch timer for 3 minutes
    • Prepare next piece
    • Swap pans
    • Iterate

    Toss the crackers into a big bowl to cool, sampling as needed.

    When crackers cool:

    • Dump into large pot
    • Add desiccant bag & humidity card
    • Cover
    • Snarf combined toppings from bowl
    • Leave crackers to dry overnight

    Wonderful!

    Memo to Self: Shredded Parmesan cheese would be pretty good…