The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

The New Hotness

  • ShopVac Nozzle Caddy

    Shortly after acquiring the Greatest ShopVac, I zip-tied half a foot of cardboard tube to the handle to corral the nozzle and keep the ungainly hose from sprawling across the floor. While disembowling the Ottlite into a mini-lathe light, the plastic trim joining the baseplate to the vertical tube cried out to become a nozzle caddy:

    ShopVac Nozzle Caddy - front view
    ShopVac Nozzle Caddy – front view

    It was exactly the right size and shape (by my admittedly slack standards) to hold the nozzle, plus being destined for the trash, so all it needed was a pair of clamp brackets conjured from the vasty digital deep:

    ShopVac Nozzle Caddy - solid model
    ShopVac Nozzle Caddy – solid model

    The bosses fit into a tapered slot along what was the rear side, with a pair of 4 mm holes at each end for screws into threaded brass inserts epoxied into the brackets:

    ShopVac Nozzle Caddy - clamps mounted
    ShopVac Nozzle Caddy – clamps mounted

    They obviously descend from the many clamp mounts I’ve made for everything from garden hoses to bike running lights. A pair of 4 mm SHCS squish the clamp around the handle, with a strip of electrical tape improving plastic-to-metal griptivity:

    ShopVac Nozzle Caddy - side view
    ShopVac Nozzle Caddy – side view

    The clearance just barely allows a nylock nut atop a washer and you’ll want to trim those 40 mm screws to an exact fit, but it came out pretty well.

    The original dimension doodle with some modeling ideas that didn’t survive more thinking:

    ShopVac Nozzle Caddy - Dimension Doodle 1
    ShopVac Nozzle Caddy – Dimension Doodle 1

    A more detailed doodle with brass inserts instead of the nylock nuts and an aluminum spreader plate that was obviously not necessary:

    ShopVac Nozzle Caddy - Dimension Doodle 2
    ShopVac Nozzle Caddy – Dimension Doodle 2

    In retrospect, the inserts would make more sense.

    The angle doodles convinced me not to bother modeling either the slot’s taper along its length or its mold draft.

    Kinda looks like it grew there and makes one wonder why they don’t include a caddy as a standard option.

    The OpenSCAD source code as a GitHub Gist:

    // ShopVac Nozzle Caddy
    // Ed Nisley KE4ZNU 2022-02
    Layout = "Show"; // [Handle,Block,Show,Build]
    HandleOD = 20.0;
    //- Extrusion parameters must match reality!
    /* [Hidden] */
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    HoleWindage = 0.2;
    Protrusion = 0.1; // make holes end cleanly
    inch = 25.4;
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    ID = 0;
    OD = 1;
    LENGTH = 2;
    //———-
    // Dimensions
    // Handle lies along X axis
    Handle = [200,HandleOD,HandleOD]; // X = longer than anything else
    WallThick = 5.0; // Thinnest printed wall
    Screw = [4.0,7.0,25.0]; // M4 socket head cap screw
    Washer = [4.5,9.0,0.8]; // M4 washer
    Insert = [4.0,5.9,10.0]; // M4 brass insert
    Block = [15.0,Handle.y + 4*WallThick + 2*Screw[ID],HandleOD + 2*WallThick]; // overall clamp block
    echo(str("Block: ",Block));
    Bosses = [[Block.x,9.5,13.0],[Block.x,15.0,9.0]];
    ScrewOC = Handle.y + 2*WallThick + Screw[ID];
    Kerf = 1.0; // cut through middle to apply compression
    Gap = 1.25;
    CornerRadius = Washer[OD]/2;
    //———————-
    // Useful routines
    module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes
    Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2);
    FixDia = Dia / cos(180/Sides);
    cylinder(d=(FixDia + HoleWindage),h=Height,$fn=Sides);
    }
    // Shopvac handle
    module Handle() {
    rotate([0,90,0])
    translate([0,0,-Handle.x/2])
    rotate(180/(4*8))
    PolyCyl(Handle.y,Handle.x,4*8);
    }
    // Clamp block
    module ClampBlock(BossID=0) {
    difference() {
    union() {
    hull()
    for (i=[-1,1], j=[-1,1]) // rounded block
    translate([i*(Block.x/2 – CornerRadius),j*(Block.y/2 – CornerRadius),-Block.z/2])
    cylinder(r=CornerRadius,h=Block.z,$fn=8);
    translate([0,0,-(Block.z/2 + Bosses[BossID].z/2 – Protrusion)])
    cube(Bosses[BossID],center=true);
    }
    for (j = [-1,1]) // screw holes
    translate([0,j*ScrewOC/2,-(Block.z/2 + Protrusion)])
    rotate(180/6)
    PolyCyl(Screw[ID],Block.z + 2*Protrusion,6);
    cube([2*Block.x,2*Block.y,Kerf],center=true);
    Handle();
    translate([0,0,-Block.z])
    rotate(180/6)
    PolyCyl(Screw[ID],Block.z,6);
    translate([0,0,-(Handle.z/2 + Insert[LENGTH])])
    rotate(180/6)
    PolyCyl(Insert[OD],Handle.y,6);
    }
    }
    // Splice block less handle bore
    module ShapedBlock() {
    difference() {
    ClampBlock();
    Handle();
    }
    }
    //———-
    // Build them
    if (Layout == "Handle")
    Handle();
    if (Layout == "Block")
    ClampBlock(BossID=0);
    if (Layout == "Show") {
    color("Green",0.25)
    Handle();
    xofs = -((len(Bosses) – 1)/2 * Gap*Block.x);
    for (i=[0:len(Bosses) – 1])
    translate([xofs + i*Gap*Block.x,0,0])
    ClampBlock(i);
    }
    if (Layout == "Build") {
    yofs = -((len(Bosses) – 1)/2 * Gap*Block.y);
    for (j=[0:len(Bosses) – 1])
    translate([0,yofs + j*Gap*Block.y,0])
    translate([0,0,Block.x/2])
    rotate([0,90,0])
    ClampBlock(j);
    }