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

  • Rubber Soaker Hose Repair

    A soaker hose leaped under a descending garden fork and accumulated a nasty gash:

    Soaker Hose Splice - gashed
    Soaker Hose Splice – gashed

    Mary deployed a spare and continued the mission, while I pondered how to fix such an odd shape.

    For lack of anything smarter, I decided to put a form-fitting clamp around the hose, with silicone caulk buttered around the gash to (ideally) slow down any leakage:

    Soaker Hose Splice - Solid Model - Assembled
    Soaker Hose Splice – Solid Model – Assembled

    As usual, some doodling got the solid model started:

    Soaker Hose Splice - Dimension doodle 1
    Soaker Hose Splice – Dimension doodle 1

    A hose formed from chopped rubber doesn’t really have consistent dimensions, so I set up the model to spit out small test pieces:

    Soaker Hose Splice - Test Fit - Slic3r
    Soaker Hose Splice – Test Fit – Slic3r

    Lots and lots of test pieces:

    Soaker Hose Splice - test pieces
    Soaker Hose Splice – test pieces

    Each iteration produced a better fit, although the dimensions never really converged:

    Soaker Hose Splice - Dimension doodle 2
    Soaker Hose Splice – Dimension doodle 2

    The overall model looks about like you’d expect:

    Soaker Hose Splice - Complete - Slic3r
    Soaker Hose Splice – Complete – Slic3r

    The clamp must hold its shape around a hose carrying 100 psi (for real!) water, so I put 100 mil aluminum backing plates on either side. Were you doing this for real, you’d shape the plates with a CNC mill, but I just bandsawed them to about the right size and transfer-punched the hole positions:

    Soaker Hose Splice - plate transfer punch
    Soaker Hose Splice – plate transfer punch

    Some drill press action with a slightly oversize drill compensated for any misalignment and Mr Disk Sander rounded the corners to match the plastic block:

    Soaker Hose Splice - plate corner rounding
    Soaker Hose Splice – plate corner rounding

    A handful of stainless steel 8-32 screws holds the whole mess together:

    Soaker Hose Splice - installed
    Soaker Hose Splice – installed

    These hoses spend their lives at rest under a layer of mulch, so I’m ignoring the entire problem of stress relief at those sharp block edges. We’ll see how this plays out in real life, probably next year.

    I haven’t tested it under pressure, but it sure looks capable!

    The OpenSCAD source code as a GitHub Gist:

    // Rubber Soaker Hose Splice
    // Ed Nisley KE4ZNU July 2018
    Layout = "Build"; // Hose Block Show Build
    TestFit = false; // true to build test fit slice from center
    //- Extrusion parameters must match reality!
    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);
    //———-
    // Dimensions
    // Hose lies along X axis
    Hose = [200,27.0,12.0]; // X = longer than anything else
    Block = [80.0,50.0,4.0 + Hose.z]; // overall splice block size
    echo(str("Block: ",Block));
    Kerf = 0.1; // cut through middle to apply compression
    ID = 0;
    OD = 1;
    LENGTH = 2;
    // 8-32 stainless screws
    Screw = [4.1,8.0,3.0]; // OD = head LENGTH = head thickness
    Washer = [4.4,9.5,1.0];
    Nut = [4.1,9.7,6.0];
    CornerRadius = Washer[OD]/2;
    NumScrews = 3; // screws along each side of cable
    ScrewOC = [(Block.x – 2*CornerRadius) / (NumScrews – 1),
    Block.y – 2*CornerRadius,
    2*Block.z // ensure complete holes
    ];
    echo(str("Screw OC: x=",ScrewOC.x," y=",ScrewOC.y));
    //———————-
    // 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);
    }
    // Hose shape
    // This includes magic numbers measured from reality
    module HoseProfile() {
    RimThick = 10.0; // outer sections
    RimOD = RimThick;
    RimFlatRecess = -0.7; // recess to front flat surface
    OuterOC = Hose.y – RimOD; // outer tube centers
    RecessM = 1.5; // back recess chord
    RecessC = OuterOC;
    RecessR = (pow(RecessM,2) + pow(RecessC,2)/4) / (2*RecessM);
    RidgeM = 1.0; // front ridge chord
    RidgeC = 8.0;
    RidgeR = (pow(RidgeM,2) + pow(RidgeC,2)/4) / (2*RidgeM);
    NumSides = 12*4;
    rotate([0,-90,0])
    translate([0,0,-Hose.x/2])
    linear_extrude(height=Hose.x,convexity=4)
    difference() {
    union() {
    for (j=[-1,1]) // outer channels
    translate([0,j*OuterOC/2])
    circle(d=RimOD,$fn=NumSides);
    translate([-RimOD/4,0]) // rear flat fill
    square([RimOD/2,OuterOC],center=true);
    translate([(RimOD/4 + RimFlatRecess),0]) // front flat fill
    square([RimOD/2,OuterOC],center=true);
    intersection() {
    translate([Hose.z/2,0])
    square([Hose.z,OuterOC],center=true);
    translate([-RidgeR + RimOD/2 + RimFlatRecess + RidgeM,0])
    circle(r=RidgeR,$fn=NumSides);
    }
    }
    translate([-(RecessR + RimOD/2 – RecessM),0])
    circle(r=RecessR,$fn=2*NumSides);
    }
    }
    // Outside shape of splice Block
    // Z centered on hose rim circles, not overall thickness through center ridge
    module SpliceBlock() {
    difference() {
    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=4*8);
    for (i = [0:NumScrews – 1], j=[-1,1]) // screw holes
    translate([-(Block.x/2 – CornerRadius) + i*ScrewOC.x,
    j*ScrewOC.y/2,
    -(Block.z/2 + Protrusion)])
    PolyCyl(Screw[ID],Block.z + 2*Protrusion,6);
    cube([2*Block.x,2*Block.y,Kerf],center=true); // slice through center
    }
    }
    // Splice block less hose
    module ShapedBlock() {
    difference() {
    SpliceBlock();
    HoseProfile();
    }
    }
    //———-
    // Build them
    if (Layout == "Hose")
    HoseProfile();
    if (Layout == "Block")
    SpliceBlock();
    if (Layout == "Bottom")
    BottomPlate();
    if (Layout == "Top")
    TopPlate();
    if (Layout == "Show") {
    difference() {
    SpliceBlock();
    HoseProfile();
    }
    color("Green",0.25)
    HoseProfile();
    }
    if (Layout == "Build") {
    SliceOffset = TestFit && !NumScrews%2 ? ScrewOC.x/2 : 0;
    intersection() {
    translate([SliceOffset,0,Block.z/4])
    if (TestFit)
    cube([ScrewOC.x/2,4*Block.y,Block.z/2],center=true);
    else
    cube([4*Block.x,4*Block.y,Block.z/2],center=true);
    union() {
    translate([0,0.6*Block.y,Block.z/2])
    ShapedBlock();
    translate([0,-0.6*Block.y,Block.z/2])
    rotate([0,180,0])
    ShapedBlock();
    }
    }
    }