module threadPiece(Xa, Ya, Za, Xb, Yb, Zb, radiusa, radiusb, tipRatioa, tipRatiob, threadAngleTop, threadAngleBottom) { angleZ=atan2(Ya, Xa); twistZ=atan2(Yb, Xb)-atan2(Ya, Xa); polyPoints=[ [Xa+ radiusa*cos(+angleZ), Ya+ radiusa*sin(+angleZ), Za ], [Xa+ radiusa*cos(+angleZ), Ya+ radiusa*sin(+angleZ), Za + radiusa*tipRatioa ], [Xa , Ya , Za+ radiusa*(tipRatioa+sin(threadAngleTop)) ], [Xa , Ya , Za ], [Xa , Ya , Za+ radiusa*sin(threadAngleBottom) ], [Xb+ radiusb*cos(angleZ+twistZ), Yb+ radiusb*sin(angleZ+twistZ), Zb ], [Xb+ radiusb*cos(angleZ+twistZ), Yb+ radiusb*sin(angleZ+twistZ), Zb+ radiusb*tipRatiob ], [Xb , Yb , Zb+ radiusb*(tipRatiob+sin(threadAngleTop)) ], [Xb , Yb , Zb ], [Xb , Yb , Zb+ radiusb*sin(threadAngleBottom)] ]; polyTriangles=[ [ 0, 1, 6 ], [ 0, 6, 5 ], // tip of profile [ 1, 7, 6 ], [ 1, 2, 7 ], // upper side of profile [ 0, 5, 4 ], [ 4, 5, 9 ], // lower side of profile [ 4, 9, 3 ], [ 9, 8, 3 ], [ 3, 8, 2 ], [ 8, 7, 2 ], // back of profile [ 0, 4, 3 ], [ 0, 3, 2 ], [ 0, 2, 1 ], // a side of profile [ 5, 8, 9 ], [ 5, 7, 8 ], [ 5, 6, 7 ] // b side of profile ]; polyhedron( polyPoints, polyTriangles ); } module shaftPiece(Xa, Ya, Za, Xb, Yb, Zb, radiusa, radiusb, tipRatioa, tipRatiob, threadAngleTop, threadAngleBottom) { angleZ=atan2(Ya, Xa); twistZ=atan2(Yb, Xb)-atan2(Ya, Xa); threadAngleTop=15; threadAngleBottom=-15; shaftRatio=0.5; polyPoints1=[ [Xa, Ya, Za + radiusa*sin(threadAngleBottom) ], [Xa, Ya, Za + radiusa*(tipRatioa+sin(threadAngleTop)) ], [Xa*shaftRatio, Ya*shaftRatio , Za + radiusa*(tipRatioa+sin(threadAngleTop)) ], [Xa*shaftRatio , Ya*shaftRatio , Za ], [Xa*shaftRatio , Ya*shaftRatio , Za + radiusa*sin(threadAngleBottom) ], [Xb, Yb, Zb + radiusb*sin(threadAngleBottom) ], [Xb, Yb, Zb + radiusb*(tipRatiob+sin(threadAngleTop)) ], [Xb*shaftRatio , Yb*shaftRatio , Zb + radiusb*(tipRatiob+sin(threadAngleTop)) ], [Xb*shaftRatio , Yb*shaftRatio , Zb ], [Xb*shaftRatio , Yb*shaftRatio , Zb + radiusb*sin(threadAngleBottom) ] ]; polyTriangles1=[ [ 0, 1, 6 ], [ 0, 6, 5 ], // tip of profile [ 1, 7, 6 ], [ 1, 2, 7 ], // upper side of profile [ 0, 5, 4 ], [ 4, 5, 9 ], // lower side of profile [ 3, 4, 9 ], [ 9, 8, 3 ], [ 2, 3, 8 ], [ 8, 7, 2 ], // back of profile [ 0, 4, 3 ], [ 0, 3, 2 ], [ 0, 2, 1 ], // a side of profile [ 5, 8, 9 ], [ 5, 7, 8 ], [ 5, 6, 7 ] // b side of profile ]; // this is the back of the raised part of the profile polyhedron( polyPoints1, polyTriangles1 ); } module trapezoidThread( length=45, // axial length of the threaded rod pitch=10, // axial distance from crest to crest pitchRadius=10, // radial distance from center to mid-profile threadHeightToPitch=0.5, // ratio between the height of the profile and the pitch // std value for Acme or metric lead screw is 0.5 profileRatio=0.5, // ratio between the lengths of the raised part of the profile and the pitch // std value for Acme or metric lead screw is 0.5 threadAngle=30, // angle between the two faces of the thread // std value for Acme is 29 or for metric lead screw is 30 RH=true, // true/false the thread winds clockwise looking along shaft, i.e.follows the Right Hand Rule clearance=0.1, // radial clearance, normalized to thread height backlash=0.1, // axial clearance, normalized to pitch stepsPerTurn=24 // number of slices to create per turn ) { numberTurns=length/pitch; steps=stepsPerTurn*numberTurns; trapezoidRatio= 2*profileRatio*(1-backlash); function threadAngleTop(i)= threadAngle/2; function threadAngleBottom(i)= -threadAngle/2; function threadHeight(i)= pitch*threadHeightToPitch; function pitchRadius(i)= pitchRadius; function minorRadius(i)= pitchRadius(i)-0.5*threadHeight(i); function X(i)= minorRadius(i)*cos(i*360*numberTurns); function Y(i)= minorRadius(i)*sin(i*360*numberTurns); function Z(i)= pitch*numberTurns*i; function tip(i)= trapezoidRatio*(1-0.5*sin(threadAngleTop(i))+0.5*sin(threadAngleBottom(i))); // this is the threaded rod if (RH==true) translate([0,0,-threadHeight(0)*sin(threadAngleBottom(0))]) for (i=[0:steps-1]) { threadPiece( Xa= X(i/steps), Ya= Y(i/steps), Za= Z(i/steps), Xb= X((i+1)/steps), Yb= Y((i+1)/steps), Zb= Z((i+1)/steps), radiusa= threadHeight(i/steps), radiusb= threadHeight((i+1)/steps), tipRatioa= tip(i/steps), tipRatiob= tip((i+1)/steps), threadAngleTop= threadAngleTop(i), threadAngleBottom= threadAngleBottom(i) ); shaftPiece( Xa= X(i/steps), Ya= Y(i/steps), Za= Z(i/steps), Xb= X((i+1)/steps), Yb= Y((i+1)/steps), Zb= Z((i+1)/steps), radiusa= threadHeight(i/steps), radiusb= threadHeight((i+1)/steps), tipRatioa= tip(i/steps), tipRatiob= tip((i+1)/steps), threadAngleTop= threadAngleTop(i), threadAngleBottom= threadAngleBottom(i) ); } if (RH==false) translate([0,0,-threadHeight(0)*sin(threadAngleBottom(0))]) mirror([0,1,0]) for (i=[0:steps-1]) { threadPiece( Xa= X(i/steps), Ya= Y(i/steps), Za= Z(i/steps), Xb= X((i+1)/steps), Yb= Y((i+1)/steps), Zb= Z((i+1)/steps), radiusa= threadHeight(i/steps), radiusb= threadHeight((i+1)/steps), tipRatioa= tip(i/steps), tipRatiob= tip((i+1)/steps), threadAngleTop= threadAngleTop(i), threadAngleBottom= threadAngleBottom(i) ); shaftPiece( Xa= X(i/steps), Ya= Y(i/steps), Za= Z(i/steps), Xb= X((i+1)/steps), Yb= Y((i+1)/steps), Zb= Z((i+1)/steps), radiusa= threadHeight(i/steps), radiusb= threadHeight((i+1)/steps), tipRatioa= tip(i/steps), tipRatiob= tip((i+1)/steps), threadAngleTop= threadAngleTop(i), threadAngleBottom= threadAngleBottom(i) ); } rotate([0,0,180/stepsPerTurn]) cylinder( h=length+threadHeight(1)*(tip(1)+sin( threadAngleTop(1) )-1*sin( threadAngleBottom(1) ) ), r1=minorRadius(0)-clearance*threadHeight(0), r2=minorRadius(0)-clearance*threadHeight(0), $fn=stepsPerTurn ); } module trapezoidThreadNegativeSpace( length=45, // axial length of the threaded rod pitch=10, // axial distance from crest to crest pitchRadius=10, // radial distance from center to mid-profile threadHeightToPitch=0.5, // ratio between the height of the profile and the pitch // std value for Acme or metric lead screw is 0.5 profileRatio=0.5, // ratio between the lengths of the raised part of the profile and the pitch // std value for Acme or metric lead screw is 0.5 threadAngle=30, // angle between the two faces of the thread // std value for Acme is 29 or for metric lead screw is 30 RH=true, // true/false the thread winds clockwise looking along shaft, i.e.follows the Right Hand Rule countersunk=0, // depth of 45 degree chamfered entries, normalized to pitch clearance=0.1, // radial clearance, normalized to thread height backlash=0.1, // axial clearance, normalized to pitch stepsPerTurn=24 // number of slices to create per turn ) { translate([0,0,-countersunk*pitch]) cylinder( h=2*countersunk*pitch, r2=pitchRadius+clearance*pitch+0.25*pitch, r1=pitchRadius+clearance*pitch+0.25*pitch+2*countersunk*pitch, $fn=24 ); translate([0,0,countersunk*pitch]) translate([0,0,-pitch]) trapezoidThread( length=length+0.5*pitch, // axial length of the threaded rod pitch=pitch, // axial distance from crest to crest pitchRadius=pitchRadius+clearance*pitch, // radial distance from center to mid-profile threadHeightToPitch=threadHeightToPitch, // ratio between the height of the profile and the pitch // std value for Acme or metric lead screw is 0.5 profileRatio=profileRatio, // ratio between the lengths of the raised part of the profile and the pitch // std value for Acme or metric lead screw is 0.5 threadAngle=threadAngle, // angle between the two faces of the thread // std value for Acme is 29 or for metric lead screw is 30 RH=true, // true/false the thread winds clockwise looking along shaft // i.e.follows Right Hand Rule clearance=0, // radial clearance, normalized to thread height backlash=-backlash, // axial clearance, normalized to pitch stepsPerTurn=stepsPerTurn // number of slices to create per turn ); translate([0,0,length-countersunk*pitch]) cylinder( h=2*countersunk*pitch, r1=pitchRadius+clearance*pitch+0.25*pitch, r2=pitchRadius+clearance*pitch+0.25*pitch+2*countersunk*pitch,$fn=24, $fn=24 ); } module trapezoidNut( length=45, // axial length of the threaded rod radius=25, // outer radius of the nut pitch=10, // axial distance from crest to crest pitchRadius=10, // radial distance from center to mid-profile threadHeightToPitch=0.5, // ratio between the height of the profile and the pitch // std value for Acme or metric lead screw is 0.5 profileRatio=0.5, // ratio between the lengths of the raised part of the profile and the pitch // std value for Acme or metric lead screw is 0.5 threadAngle=30, // angle between the two faces of the thread // std value for Acme is 29 or for metric lead screw is 30 RH=true, // true/false the thread winds clockwise looking along shaft, i.e.follows the Right Hand Rule countersunk=0, // depth of 45 degree chamfered entries, normalized to pitch clearance=0.1, // radial clearance, normalized to thread height backlash=0.1, // axial clearance, normalized to pitch stepsPerTurn=24 // number of slices to create per turn ) { difference() { cylinder( h=length, r1=radius, r2=radius, $fn=6 ); trapezoidThreadNegativeSpace( length=length, // axial length of the threaded rod pitch=pitch, // axial distance from crest to crest pitchRadius=pitchRadius, // radial distance from center to mid-profile threadHeightToPitch=threadHeightToPitch, // ratio between the height of the profile and the pitch // std value for Acme or metric lead screw is 0.5 profileRatio=profileRatio, // ratio between the lengths of the raised part of the profile and the pitch // std value for Acme or metric lead screw is 0.5 threadAngle=threadAngle, // angle between the two faces of the thread // std value for Acme is 29 or for metric lead screw is 30 RH=true, // true/false the thread winds clockwise looking along shaft // i.e.follows Right Hand Rule countersunk=countersunk, // depth of 45 degree countersunk entries, normalized to pitch clearance=clearance, // radial clearance, normalized to thread height backlash=backlash, // axial clearance, normalized to pitch stepsPerTurn=stepsPerTurn // number of slices to create per turn ); } }