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.

The New Hotness

  • Broom Handle Screw With Dedendum: Effect of Printing Orientation

    Although the current OpenSCAD could produce a solid model with the screw thread’s dedendum, I’d never actually printed one of them:

    Broom Handle Screw - full thread - solid model
    Broom Handle Screw – full thread – solid model

    I need some fondlestuff illustrating how to handle overhangs, so I ran one standing vertically, which (pretty much as I expected) didn’t work well at all:

    Broom Handle Screw - dedendum - vertical
    Broom Handle Screw – dedendum – vertical

    The trick is to split the model down the middle:

    Broom Handle Screw - horizontal top
    Broom Handle Screw – horizontal top

    And put holes in each half for alignment pins:

    Broom Handle Screw - horizontal bottom
    Broom Handle Screw – horizontal bottom

    Then you can print it lying down:

    Broom Handle Screw - horizontal - as-printed top
    Broom Handle Screw – horizontal – as-printed top

    The internal overhang would probably call for some support material, particularly in the square recess at the end, but in this case it’s a lesson:

    Broom Handle Screw - horizontal - as-printed bottom
    Broom Handle Screw – horizontal – as-printed bottom

    Glue some filament snippets into the holes, snap it together, and it looks just fine over there on the right:

    Broom Handle Screw - orientation comparison
    Broom Handle Screw – orientation comparison

    Doesn’t matter how many I print, it still doesn’t make any economic sense as a broom repair…

    The OpenSCAD source code now has a Layout variable to control the orientation and, not as shown in the model, the alignment pins have glue gutters in the first layer:

    // Broom Handle Screw End Plug
    // Ed Nisley KE4ZNU October 2013
    
    Layout = "Horizontal";		// Vertical Horizontal Pin
    
    UseDedendum = true;			// true to create full thread form
    
    //- Extrusion parameters must match reality!
    
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    
    HoleWindage = 0.2;
    
    Protrusion = 0.1;			// make holes end cleanly
    
    //----------------------
    // Dimensions
    
    PostOD = 22.3;				// post inside metal handle
    PostLength = 25.0;
    
    FlangeOD = 24.0;			// stop flange
    FlangeLength = 3.0;
    
    PitchDia = 15.5;			// thread center diameter
    ScrewLength = 20.0;
    
    ThreadFormOD = 2.5;			// diameter of thread form
    ThreadPitch = 5.0;
    NumSegments = 32;			//  .. number of cylinder approximations per turn
    
    BoltOD = 7.0;				// clears 1/4-20 bolt
    BoltSquare = 6.5;			// across flats
    BoltHeadThick = 3.0;
    
    RecessDia = 6.0;			// recesss to secure post in handle
    
    OALength = PostLength + FlangeLength + ScrewLength;
    
    SplitOC = 1.25*FlangeOD;	// separation in Horizontal layout
    PinOD = 1.75;				// alignment pin diameter = filament stub
    PinLength = 7.0;			//  ... length
    
    $fn=8*4;					// default cylinder sides
    
    echo("Pitch dia: ",PitchDia);
    echo("Root dia: ",PitchDia - ThreadFormOD);
    echo("Crest dia: ",PitchDia + ThreadFormOD);
    
    Pi = 3.14159265358979;
    
    //----------------------
    // Useful routines
    
    // Wrap cylindrical thread segments around larger plug cylinder
    
    module CylinderThread(Pitch,Length,PitchDia,ThreadOD,PerTurn) {
    
    CylFudge = 1.02;				// force overlap
    
        RotIncr = 1/PerTurn;
        PitchRad = PitchDia/2;
    
        Turns = Length/Pitch;
        NumCyls = Turns*PerTurn;
    
        ZStep = Pitch / PerTurn;
    
        HelixAngle = atan(Pitch/(Pi*PitchDia));
        CylLength = CylFudge * (Pi*(PitchDia + ThreadOD) / PerTurn) / cos(HelixAngle);
    
    	for (i = [0:NumCyls-1]) {
    		assign(Angle = 360*i/PerTurn)
    			translate([PitchRad*cos(Angle),PitchRad*sin(Angle),i*ZStep])
    				rotate([90+HelixAngle,0,Angle])
    					cylinder(r1=ThreadOD/2,
    							r2=ThreadOD/(2*CylFudge),
    							h=CylLength,
    							center=true,$fn=12);
    	}
    }
    
    // Build complete plug
    
    module ScrewPlug() {
    	difference() {
    		union() {
    			cylinder(r=PostOD/2,h=PostLength);
    			cylinder(r=PitchDia/2,h=OALength);
    			translate([0,0,PostLength])
    				cylinder(r=FlangeOD/2,h=FlangeLength);
    			color("Orange")
    			translate([0,0,(PostLength + FlangeLength)])
    				CylinderThread(ThreadPitch,(ScrewLength - ThreadFormOD/2),PitchDia,ThreadFormOD,NumSegments);
    		}
    
    		translate([0,0,-Protrusion])
    			PolyCyl(BoltOD,(OALength + 2*Protrusion),6);
    
    		translate([0,0,(OALength - BoltHeadThick)])
    			PolyCyl(BoltSquare,(BoltHeadThick + Protrusion),4);
    
    		if (UseDedendum)
    			translate([0,0,(PostLength + FlangeLength + ThreadFormOD/2 - ThreadPitch/(2*NumSegments))])
    				rotate(-90 - 360/(2*NumSegments))
    				CylinderThread(ThreadPitch,ScrewLength,PitchDia,ThreadFormOD,NumSegments);
    
    		for (i = [0:90:270]) {
    			rotate(45 + i)					// 45 works better with Horizontal layout
    				translate([PostOD/2,0,PostLength/2])
    					sphere(r=RecessDia/2,$fn=8);
    		}
    	}
    }
    
    // Locating pin hole with glue recess
    
    module LocatingPin() {
    
    	translate([0,0,-ThreadThick])
    		PolyCyl((PinOD + 2*ThreadWidth),2*ThreadThick,4);
    	translate([0,0,-(PinLength/2 + ThreadThick)])
    		PolyCyl(PinOD,(PinLength + 2*ThreadThick),4);
    
    }
    
    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();
    
    if (Layout == "Vertical")
    	ScrewPlug();
    
    if (Layout == "Pin")
    	LocatingPin();
    
    if (Layout == "Horizontal")
    	for (i=[-1,1])
    		difference() {
    			translate([i*SplitOC/2,PostLength/2,0])
    				rotate([90,180*(i + 1)/2,0])
    					ScrewPlug();
    
    			translate([0,0,-FlangeOD/2])
    				cube([2*OALength,2*OALength,FlangeOD],center=true);
    
    			for (j=[-1,1], pin=[-1,1])
    				assign(PinX = i*SplitOC/2 + pin*(PostOD + BoltOD)/4,
    					   PinY = j*PostLength/4) {
    					translate([PinX,PinY,0])
    						rotate(45)
    							LocatingPin();
    					echo("i j pin: ",i,j,pin);
    					echo("X Y: ",PinX,PinY);
    				}
    		}