Exit Full View
ZipUp

/GardenFurniture/Hardware/Wheel.foocad

Wheel

A wheel with a recess for a standard bearing. The wheel if free, i.e. it can turn, when the axel is fixed.

The recesses allow the nuts to be hidden within the wheel using hubCap.

There is no clearance between the tyre and the hub, and therefore we are relying on the tyre being stretchy (TPU). I don't expect the tyre to loosen over time, but if it does, use a small dab of glue.

Assembly.

  1. Stretch the tyre over the hub.
  2. Attach the axel to the frame.
  3. Add a pair of nuts on each side, and lock them in place by tightening them together. The threaded part faces outwards.
  4. Check the position of these nuts are correct by sliding on the wheel temporarily.
  5. Slide on the wheel, and secure using a third nut. This could be a lock-nut. YMMV.
  6. Screw on the hub caps.
FooCAD Source Code
import uk.co.nickthecoder.foocad.threaded.v2.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.*
import uk.co.nickthecoder.foocad.smartextrusion.v1.*
import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.*

class Wheel : Model {

    @Custom( about="Diameter and width of the hub" )
    var hubSize = Vector2( 60, 19 )

    @Custom( about="The final wheel's diameter = hubSize.x + typeDiameter*2" )
    var tyreThickness = 6
    
    @Custom
    var tyreRounding = 5

    @Custom( about="Only used to display a preview of the axel and nuts" )
    var axelDiameter = 8

    @Custom( about="Diameter of the recess for nuts" )
    var nutRecessDiameter = 16

    @Custom( about="Diameter and thickness of the bearing. The hole is given additional `clearance`" )
    var bearingSize = Vector2( 22, 7 )
    
    @Custom( about="Determines the size of the hub cap" )
    var threadDiameter = 35

    @Custom( about="Additional width and thickness for the hub cap" )
        var capSize = Vector2( 6, 2 )

    // 0.075 gives a perfect fit using a 0.6mm nozzel on Qidi Max3
    @Custom( about="Additional space for the bearing to fit into its hole" )
    var clearance = 0.075

    @Custom( about="Offsets for the tyre. Negative for a tight fit" )
    var tyreClearance = -0.2
    
    @Custom( about="Chamfer on the hub and the type to locate it in place" )
    var tyreChamfer = 1.0


    // Positions the bearing in the middle (Z direction as printed)
    meth recessDepth() = (hubSize.y - bearingSize.y) / 2

    // Thread for the hub cap.
    meth hubThread() = Thread( threadDiameter, 2 )
        .rodChamfer( 0.5 )

    @Piece( about="The main piece" )
    meth hub() : Shape3d {

        val main = Circle( hubSize.x/2 )
            .smartExtrude( hubSize.y )
                .top( Chamfer( 1 ) ) // To help put on the tyre.
                .bottom( Chamfer(-tyreChamfer,tyreChamfer) )

        val threadedRecess = hubThread().threadedHole( recessDepth() )
            .chamferStart(false)
            .topTo(main.top + 0.01)

        val forBearing = Circle( bearingSize.x / 2 + clearance )
            .smartExtrude( main.size.z )
            .bottomTo( main.top - recessDepth() - bearingSize.y )

        val nutRecess = Circle( nutRecessDiameter/2 )
            .extrude(forBearing.bottom + 0.2)
            .bottomTo( -0.1 )

        return main - forBearing - threadedRecess - nutRecess//- throughHole
    }
    
    @Piece( about="For display purposes only; showing the axel and nuts", printable = false )
    meth displayHub() : Shape3d {
        val hub = hub()
        val axel = Cylinder( 100, axelDiameter/2 )
            .topTo( hub.top )
            .previewOnly()

        val bearing = (
            Circle( bearingSize.x / 2 ) -
            Circle( axelDiameter/2 )
        ).extrude( bearingSize.y )
            .centerZTo( hub.middle.z )
            .color("orange").opacity(0.8)

        val nut = Circle( axelDiameter * 0.9 )
            .sides(6)
            .roundAllCorners(2)
            .extrude( axelDiameter/2 )
            .previewOnly()
        val nuts = nut.topTo(hub.top-1).also()

        return hub + axel + nuts + bearing
    }

    @Piece( about="Hides the nut which fixes the wheel in place. Finger tighten only." )
    meth hubCap() : Shape3d {

        val diameter = hubThread().diameter + capSize.x*2
        println( "cap diameter = $diameter" )
        val thread = hubThread()

        val cap = Circle( diameter/2 )
            .smartExtrude( capSize.y )
            .bottom( Chamfer( capSize.y/2 ) )

        val rod = thread.threadedRod( recessDepth() + capSize.y/2 - 0.5 )
            .chamferBottom(false)
            .bottomTo( capSize.y/2 )

        val hole = Cylinder( recessDepth(), thread.coreRadius() -2 )
            .bottomTo( cap.top + 0.01 )

        return cap + rod - hole
    }


    @Piece( about="TPU" )
    @Slice( fillDensity=100 )
    meth tyre() : Shape3d {
        val inside = Circle( hubSize.x/2 + tyreClearance )
        val outside = inside.offset( tyreThickness )
        val shape = outside - inside

        return shape
            .smartExtrude( hubSize.y  )
            .outside( roundedChamfer( tyreRounding ) )
            .insideTop( Chamfer(tyreChamfer) )
    }


    @Piece( about="Print this, and ensure the bearing is a tight fit. Adjust `clearance`" )
    meth testFit() : Shape3d {
        val inside = Circle( bearingSize.x/2 + clearance/2)
        val outside = inside.offset(3)

        val text = Text( "${clearance}", 8 )
        val text3d = (
            text.boundingSquare().offset(2).roundAllCorners(3).extrude(0.8) +
            text.extrude(1.6)
        ).leftTo( outside.right - 2 ).centerY()

        return text3d +
            (outside-inside).extrude( bearingSize.y + 2) +
            (outside - outside.offset(-6)).extrude(2)
    }
    
    @Piece( about="Helps remove a bearing from `testFit` piece" )
    meth bearingWhacker() : Shape3d {
        val pin = Cylinder( 16, axelDiameter/2 - 0.2 ) +
            Cylinder( 16 - bearingSize.y, axelDiameter/2 + 2 )

        val standCircle = Circle( bearingSize.x / 2 + 0.5 )
        val stand = (standCircle.offset(1) - standCircle)
            .extrude( bearingSize.y + 2 ) +
            standCircle.extrude(1)

        return pin + stand.leftTo(pin.right + 1 )
    }

    @Piece( printable=false )
    override meth build() : Shape3d {
        val hub = displayHub()

        val cap = hubCap()
            .rotateX(180)
            .topTo( hub.top + 2.02 )
            .previewOnly()

        val tyre = tyre()
            .rotateX(180)
            .bottomTo(0.1).color( "DarkGrey" )

        return (hub + tyre + cap)
            .rotateY(90)
    }
}