Exit Full View
Up

/Tools/ScrewDriver.foocad

ScrewDriver

A screwdriver for the common size screwdriver bits.

The body can store spare bits, and the end can free-wheel.

There are two versions of the body depending on useCollet parameter. Instead of using a collet, the end is a fixed hexagonal hole, into which you should glue a magnet (use 2 part epoxy).

The bits are held in place using a "collet". The nut is tapered, so that it starts off easy going, and gets progressively tighter as you turn it. If the bits are too loose, then increase snug. But if the collet tightens too soon, then decrease it. (Alternatively, you could scale the nut in X & Y before slicing).

I printed these in ABS, but other plastics should also work fine. However, as PLA is brittle, if you tighten the collet without a bit in place, then it would probably break.

The collet only has to be tightened enough to stop the bit from falling out. Don't overtighten.

FooCAD Source Code
import static uk.co.nickthecoder.foocad.extras.v1.Extras.*
import static uk.co.nickthecoder.foocad.chamferedextrude.v1.ChamferedExtrude.*
import static uk.co.nickthecoder.foocad.arrange.v1.Arrange.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.*
import uk.co.nickthecoder.foocad.threaded.v2.*
import static uk.co.nickthecoder.foocad.threaded.v2.Thread.*

// used to make the collet nut narrower as we increase in the Z direction.
class NarrorWithZ( val factor : double ) : Transform3d {
    override fun transform( point : Vector3 ) = Vector3(
        point.x - point.x * point.z*factor,
        point.y - point.y * point.z*factor,
        point.z
    )
}

class ScrewDriver : Model {

    // When not using a collet, the diameter must be really accurate!
    // Test with a very stubby screwdriver first!
    // Note. This is the distance between opposite vertices of the hex, not the
    // easy to measure 1/4 inch :-(
    // The conversion factor is Sin(60) 0.866
    // So the tight fit value is 25.4 / 4 / 0.866 = 7.3
    // Therefore I've included 0.5mm of clearance. YMMV.
    @Custom( about="Internal length and diameter of the collet to accomodate the driver bit" )
    var bitSize = Vector2( 7.8, 12 )

    @Custom( about="X : Diameter. Y : At least 10mm, then 25mm for every bit you wish to store" )
    var handleSize = Vector2( 14, 3*25 + 10 )

    @Custom( about="Diameter of the hole to hold spare bits" )
    var insideDiameter = 8

    @Custom
    var useCollet = true
    // Too large, and the collect won't tighten around the screwdriver bit.
    // Too small, and the collect won't screw very far onto the screwdriver.
    // This may need adjusting to suit your printer / print settings.
    @Custom( about="The amount of taper in the collet nut" )
    var snug = 0.8

    @Custom( about="Set this to 0 if you wish to use the slicer's brim" )
    var brimSize = 25

@Piece 
fun test() : Shape3d {

    return Square( 7.0, 1 ).center().extrude(2).color("Green") +
        Circle( bitSize.x / 2 ).sides(6).extrude(1).color( "Yellow") + 
        collet().mirrorZ().topTo(-2)
}


    fun colletThread() : Thread {
        val d : int = bitSize.x + 5
        return Thread( d ).clearance(0.3)
    }

    fun endThread() : Thread = Thread( insideDiameter + 1 ).rodChamfer(0.5)

    @Piece
    fun nut() : Shape3d {
        val hex = Circle( colletThread().diameter / 2 + 3 )
            .sides(6).roundAllCorners(2)
        val outside = ExtrusionBuilder().apply {
            crossSection( hex )
            forward(7)
            crossSection( Circle( colletThread().diameter / 2 + 2 ) )
            forward(5)        
            crossSection(-1)
        }.build()
        val threadedHole = colletThread().threadedHole( 10 )
            .chamferEnd(false)
            .clipped()
        val hole = Circle( bitSize.x / 2 + 0.5 ).extrude(3).bottomTo(-1)

        val factor = snug / threadedHole.size.z / colletThread().diameter
        
        val narrowed = (outside - threadedHole).transform( NarrorWithZ( factor ) )

        val brim = if (brimSize > 0) {
            Triangle( brimSize + 1 )
                .backTo( -colletThread().diameter / 2 +1)
                .repeatAround(4)
                .extrude(0.2)
                .color("White").opacity(0.2)
        } else {
            null
        }
    
        return narrowed.rotateY(180).bottomTo(0) + brim - hole
    }

    fun brim( innerRadius : double ) : Shape3d {
        val outerRadius = innerRadius + brimSize
        return if (brimSize > 0) {
            (
                Circle( outerRadius ).extrude(0.2) +
                (
                    Circle( outerRadius ) - Circle(outerRadius - 1) +
                    Square( outerRadius - innerRadius - 1, 1.2 ).centerY().translateX( innerRadius + 1 ).repeatAround(4)
                )
                    .extrude(2.4)
            ).color( "White" ).opacity(0.2)
        } else {
            null
        }

    }

    fun collet() : Shape3d {

        val rod = colletThread().threadedRod( bitSize.y + 1 )
            .chamferTop(false)

        val hex = Circle( bitSize.x / 2 ).sides(6)
            .extrude( bitSize.y ).bottomTo(-0.01)
        val split = Cube( 1, handleSize.x, colletThread().diameter ).centerXY().bottomTo(-0.01)
            .rotateZ(30)
            .bottomTo(0.2)

        return rod + brim( colletThread().diameter/2 ) - hex - split
    }

    @Piece
    fun magneticBitHolder() : Shape3d {
        val outside = ExtrusionBuilder().apply {
            crossSection( Circle(bitSize.x/2 + 1.5) )
            forward( bitSize.y + 4 )
            crossSection( bodyShape() )
        }.build()    

        val hex = Circle( bitSize.x / 2 ).sides(6)
            .extrude( bitSize.y + 2 ).bottomTo(-0.01)
        
        return outside + brim( bitSize.x/2 + 1.5 ) - hex
    }

    fun bodyShape() : Shape2d {
        return Circle( handleSize.x / 2 ).sides(6)
            .roundAllCorners(2)
    }

    // The Solid part of the body, not including the collect, or end thread etc.
    // You could add writing to the side(s), or add extra shaped parts for better grip etc.
    fun plainBody() : Shape3d {
        return bodyShape().extrude( handleSize.y )
    }

    @Piece
    fun body() : Shape3d {
        val collet = if (useCollet) {
            collet()
        } else {
            magneticBitHolder()
        }

        val delta = handleSize.x/2 - colletThread().coreRadius()
        val transition = if ( useCollet ) {
            ExtrusionBuilder().apply {
                crossSection( Circle( colletThread().coreRadius() ) )
                forward( Math.abs(delta) )
                crossSection( bodyShape() )
            }.build()
        } else {
            Cube(0)
        }.bottomTo(collet.top-0.1)

        val body = plainBody().bottomTo(transition.top - 0.01)

        val end = ExtrusionBuilder().apply {
            crossSection( bodyShape() )
            forward(2)
            crossSection( Circle( handleSize.x / 2 ) )
            forward(2)
            crossSection()
        }.build().bottomTo( body.top )

        val endThreadHole = endThread().threadedHole( 10 )
            .chamferEnd(false)
            .chamferStart(false)
            .clipped(true)
            .topTo(end.top)

        val hole = Circle( insideDiameter/2 )
            .chamferedExtrude( end.top - transition.top, 0, (insideDiameter - handleSize.x )/2  )
            .topTo( end.top+ 0.01 )
            .color("Blue")

        return collet + body + transition + end - endThreadHole - hole
    }

    @Piece
    fun fixedEnd() : Shape3d {
        val end = Circle( handleSize.x/2 ).chamferedExtrude(8, 1, 4)
        val threaded = endThread().threadedRod(6)
            .chamferBottom(false)
            .chamferTop(false)
            .bottomTo( end.top-2 )
        return end + threaded
    }

    @Piece
    fun swivelEnd() : Shape3d {
        val fixedEnd = fixedEnd().rotateY(180).bottomTo(0).color("Green")
        val start = Circle(3).chamferedExtrude(1,0,1).bottomTo(-0.02)
        val slack = 0.6

        val diagonal = handleSize.x/2 - 2
        val bar = 9 - diagonal
        val profile = PolygonBuilder().apply {
            moveTo(0,0)
            lineBy( 1.5, 0 )
            lineBy( 0, bar )
            lineBy( 1.5, 1.5 )
            lineBy( -1, 1 )
            lineBy( diagonal, diagonal )
            lineBy( 0, 2 )
            lineTo( 0, 13.5 )
        }.build()

        val remove = (profile.translateX(slack) + Square(0.3, profile.size.y))
            .revolve()
            .color("Orange")

        val swivel = profile.revolve().color("Yellow")

        val whiskers = Cube( 0.4, 6, 0.2 ).centerXY().rotateZ(90).also()

        val brim = if (brimSize > 0) {
            Circle( endThread().diameter / 2 + brimSize ).extrude(0.2).color( "White" ).opacity(0.2)
        } else {
            null
        }

        return fixedEnd + brim - start - remove + swivel + whiskers
    }


    @Piece
    override fun preview() : Shape3d {
        brimSize = 0
        val body = body().rotateY(90)
        val nut = nut().rotateY(90).leftTo( body.left  )
        val end = swivelEnd().rotateY(90).rightTo( body.right + 6 ) 
        
        return body + end + nut
    }

    override fun build() : Shape3d {
        return arrangeX( 2, 
            body(),
            if (useCollet) nut() else Cube(0),
            swivelEnd()
        ).centerX()
    }

}