Exit Full View
Up

/Games/FloatingSphere.foocad

FloatingSphere

Inspired by Maker's Muse : [https://www.youtube.com/watch?v=7G5WpeJ1iG4]

A magic trick. Wind thread around both parts of the pulleys, with the ends exiting opposide poles of the sphere.

Pull to make the sphere rise up, release the tension to allow ot to fall under gravity.

Note. Maker's Muse is much more convoluted, mostly because he didn't use magnets to attach the two halves. This snowballed into lots of design constraints, such as the need for a separate shell, and printing the inside parts "upside-down".

To Do

Consider adding a place for a metal insert at the north and south pole, for a tiny tube, or even just a replacable plastic insert (which will wear quickly).

FooCAD Source Code
import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.*
import static uk.co.nickthecoder.foocad.chamferedextrude.v1.ChamferedExtrude.*

class FloatingSphere : Model {
    
    var pulleyA = 20
    var pulleyB = 10

    var bearingThickness = 8.0

    // Must be larger than bearingThickness
    var pulleyThickness = 9.0

    // The groovy will be pulleyThickness - pulleySide * 2
    var pulleySide = 0.8

    var innerR = 27

    var thickness = 1.2

    // Drill to a large size on one piece, and tap the other piece (using the
    // screw itself!)
    //var innerScrewD = 4

    var slack = 0.3

    var bearingD = 23

    var rodD = 8.0

    var lockSize = 4

    var magnetD = 10.2

    var magnetH = 1.1

    @Piece
    fun pulley( radius : double ) : Shape3d {
        val inside = pulleyThickness - pulleySide * 2
        val profile = PolygonBuilder().apply {
            moveTo(0, -pulleyThickness/2)
            lineTo(radius, -pulleyThickness/2)
            lineTo(radius, -inside/2)
            lineTo(radius-inside/2, -inside/2) // Assymetric
            lineTo(radius-inside/2, 0)
            lineTo(radius, inside/2)
            lineTo(radius, pulleyThickness/2)
            lineTo(0, pulleyThickness/2)

        }.build()

        return profile.revolve().sides(60)
    }
    
    @Piece
    fun doublePulley() : Shape3d {

        // Note, by adding a chamfer at the bottom of the hole for the bearing,
        // the bearing won't sit flush with the pulley, and therefore the inner
        // part of the bearing won't rub against the pulley.
        val bearingHole = Circle( bearingD/2 ).internalChamferedExtrude( bearingThickness, 1, -1 )

        // Note the hole doesn't go all the way through, so that it can use bridging
        // Drill the thin piece of plastic with a drill.
        // The hole is larger than the rod.
        val rodHole = Cylinder.hole( pulleyThickness*6,  rodD/2 + 0.5 )
            .translateZ( pulleyThickness )

        val result = pulley(pulleyA).toOriginZ() +
            pulley( pulleyB ).toOriginZ().translateZ(pulleyThickness - pulleySide) -
            bearingHole -
            rodHole

        return result.color("Silver")
    }

    @Piece
    fun inner() : Shape3d {
        val sides = 80

        val slotA = Cylinder( pulleyThickness + slack*2, pulleyA + slack*2 )
            .rotateX(90)
            .translateY(pulleyThickness-pulleySide/2+slack)
            .color("Red")
        val slotB = Cylinder( pulleyThickness - pulleySide + slack, pulleyB + slack*2 )
            .rotateX(90)
            .translateY( -pulleySide/2 )
            .color("Red")

        val rodGap = Cylinder.hole( innerR * 1.8, rodD/2 + slack )
            .center()
            .rotateX(90)

        
        /* NO longer used

        val innerThickness = pulleyThickness + thickness*2

        val cubes = Cube( innerR )
            .translate( innerThickness, innerThickness, bandWidth/2)
            .mirrorX().also().mirrorY().also()

        val screws = Cylinder.hole( innerThickness*3, innerScrewD/2 )
            .center()
            .translate( innerR*0.45, innerR*0.45, 0 )
            .mirrorX().also().mirrorY().also()

        val lockVoid = (
            Circle( innerR - lockSize ).sides(sides) -
            Circle( innerR - lockSize*2 ).sides(sides) -
            Square( innerR*2 , innerThickness*2 ).center()
         )
            .extrude( lockSize ).translateZ( bandWidth/2 )

        */

        val hemi = Sphere( innerR ).sides(sides) / Cube( innerR * 2 ).centerXY()

        val hole = Cube( 2, 4, innerR*2.1 ).center()
           
        // Attemps to make the string for pulleyB easier.
        // However, both strings will cut into the plastic over time.
        val exit =  Square( pulleyB + slack*2 ).rotate(45).center()
                .scale(1,pulleyA/pulleyB)
                .translate(0, (pulleyB+slack*2)/Math.sqrt(2))
                .extrude( pulleyThickness )
                .rotateX(90)

        val magnets = Cylinder.hole( magnetH+0.01, magnetD/2 ).translate( innerR/2, innerR/2, -0.01 )
            .repeatAroundZ(4)

        
        return hemi - slotA - slotB - rodGap - exit - hole - magnets //- cubes - screws  - lockVoid - holes
    }

    @Piece
    fun rod() : Shape3d {
        return (
            Cylinder( innerR * 1.7, rodD/2 ).center().rotateY(90)
                .translateZ( rodD* 0.4 ) /
            Cube( innerR*2, rodD, rodD ).centerXY()
        ).toOriginZ()
    }

    @Piece
    fun inspect() = inner() + doublePulley().center().rotateX(90)

    override fun build() : Shape3d {
        return inner().translateY(innerR*2+2).also() +
            doublePulley().translateX(innerR*2) +
            rod().translate(innerR*2, innerR,0)
    }
}