Exit Full View
Up

/Bike/BagClip.foocad

BagClip

A hook for the box on the back of my bike, for hanging bags on the sides/back if I need extra space for shopping.

The box has ribs at the top, so the hook has to clear those ribs.

There's an option for a bolt, which ensures the bag cannot jump out of the hook, and the hook cannot jump off the box The end of the bolt sits between the ribs at the top of the box.

Design Notes

I initially left the end of the bolt unthreaded, but changed my mind. The threads make the bolt stronger, and having threads along the whole length allows the bolt to stay in place while placing the bag on the clip.

Strength

My test print (with sparse infill) is much stronger than necessary. The bag handles (or the box) would break before the clip.

Print Notes

The clip lifted off the bed on my test print, so I resorted to adding a brim :-( Even a small lift can deform the threaded holes, and ruin the print.

My test prints used a 0.3 layer height with a 0.4 nozzle. This was slightly too agressive for the overhangs in the threaded holes, but the thread still worked, but was stiff until screwed and unscrewed several times.

bolt

Print with a brim, as it is tall and thin.

FooCAD Source Code
import static uk.co.nickthecoder.foocad.debug.v1.Debug.*
import uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion
import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.*
import uk.co.nickthecoder.foocad.threaded.v2.*
import static uk.co.nickthecoder.foocad.threaded.v2.Thread.*

class BagClip : Model {

    //@Custom( about="Length and Height" )
    //var size = Vector2( 10, 60 )

    @Custom
    var width = 12

    @Custom
    var thickness = 8
    
    @Custom
    var boxThickness = 2

    @Custom( about="X=Width of the box's lip. Y=Space to get the clip off" )
    var boxLip = Vector2(16,40)

    @Custom( about="Size of the gap for the bag handles" )
    var hookSize = Vector2(16,36)

    @Custom
    var overhang = 17

    @Custom
    var radius1 = 3

    @Custom
    var radius2 = 9

    @Custom
    var chamfer = 1.2

    val thread = Thread(8).pitch(10).threadSize(1.5, 3).threadCount(3).headSize( Vector2( 20, 5 ) )

    @Piece
    @Slice( brimWidth=10 )
    fun bolt() = thread.bolt( thickness*2 + hookSize.x + boxLip.x - 2 )
        

    @Slice( brimWidth=10 )
    override fun build() : Shape3d {

        var profile = PolygonBuilder().apply {
            moveTo( 0, 0 ) // Top left
            lineBy( thickness * 2 + boxLip.x + boxThickness, 0 )
            lineBy( 0, -thickness - boxLip.y )
            // Bottom of the hook
            lineBy( hookSize.x, 0 )
            lineBy( 0, hookSize.y )
            lineBy( thickness, 0 )
            // Now at the top right
            lineBy( 0, - hookSize.y - thickness )
            // Now at the bottom right
            lineBy( -thickness - hookSize.x - thickness - boxLip.x, 0 )
            // Now touching the box
            lineBy( 0, thickness )
            lineBy( boxLip.x, 0 )
            lineBy( 0, boxLip.y )
            lineBy( - boxLip.x - boxThickness, 0 )
            // Now at the top left of the box rim.
            lineBy( 0, -overhang  )
            lineBy( -thickness, 0 )
            lineTo(0,0) // Top left
        }.build().frontTo(0)

        val solid = profile
            .roundCorner( 13, radius1 ) // Top left
            .roundCorner( 12, radius2 ) // Top middle
            .roundCorner( 11, radius1 )
            .roundCorner( 10, radius1 )
            .roundCorner(  9, radius1 )
            .roundCorner(  8, radius1 ) // Top right
            .roundCorner(  7, radius2 ) // Bottom right
            .roundCorner(  5, radius1 ) // 
            .roundCorner(  4, radius1 ) // 
            .roundCorner(  3, radius1 )
            .roundCorner(  1, radius1 ) // Overhang
            .roundCorner(  0, radius1 ) // Overhang
            .smartExtrude( width )
                .chamfer( chamfer )

        val bolt = bolt()
            .rotateY(-90)
            .rightTo( solid.right + thread.headSize.y )
            .centerYTo( thickness + hookSize.y - 7 )
            .centerZTo( solid.size.z/2 )
            .previewOnly()

        val forBolt = thread.threadedHole( thickness*2 + hookSize.x )
            .chamferStart( false )
            .rotateY(90)
            .rightTo( solid.right )
            .centerYTo( thickness + hookSize.y - 7 )
            .centerZTo( solid.size.z/2 )

        return solid - forBolt + bolt

    }

}