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.

Category: Machine Shop

Mechanical widgetry

  • Glass Tiles: 2×2 Matrix

    Glass Tiles: 2×2 Matrix

    Start with a single cell holding a glass tile over a WS2812 RGB LED:

    Glass Tile - 1x1 cell test - purple phase
    Glass Tile – 1×1 cell test – purple phase

    A bit of OpenSCAD tinkering produces a simple 2×2 array with square interiors as a test piece:

    Glass Tile - 2x2 - PETG strings
    Glass Tile – 2×2 – PETG strings

    The excessive stringing and the booger in the upper-left cell come from absurdly thin infill tucked into the too-thin walls; Slic3r doesn’t (seem to) have a “minimum infill width” setting and it’ll desperately try to fit infill between two nearly adjacent perimeter threads.

    The little support spiders under the LED PCB recesses snapped right out, though, so I got that part right:

    Glass Tile - 2x2 - support spiders
    Glass Tile – 2×2 – support spiders

    The perimeter threads around the LED aperture aren’t quite fused, because it was only one layer thick and that’s not enough.

    A quick test with two LEDs showed the white PETG let far too much light bleed between the cells, which was no surprise from the single cell test piece.

    Fortunately, it’s all parametric, so a bit more tinkering produced a slightly chunkier matrix with a base for an Arduino Nano and M3 threaded brass inserts for the screws holding it together:

    Glass Tile Frame - 2x2 - Arduino Nano base - solid model
    Glass Tile Frame – 2×2 – Arduino Nano base – solid model

    Those two parts require about three hours of printing, much faster than I could produce them by milling pockets into aluminum or black acrylic slabs, and came out with minimal stringing.

    A little cleanup, some epoxy work, and a few dabs of solder later:

    Glass Tile - 2x2 - Arduino wiring
    Glass Tile – 2×2 – Arduino wiring

    An initial lamp test showed the white-ish glass tiles aren’t all quite the same color:

    Glass Tile - 2x2 - white color variation
    Glass Tile – 2×2 – white color variation

    I thought it was an LED color variation, too, but the slightly blue tint in the lower left corner followed the tile.

    The blurred horizontal strip across the middle is adhesive tape holding the tiles in place; I was reluctant to glue them in before being sure this whole thing would work. A peek into the future, though, shows it’s got potential:

    Glass Tile - 2x2 - first two units
    Glass Tile – 2×2 – first two units

    They do give off a definite Windows logo vibe, don’t they?

    The OpenSCAD source code as a GitHub Gist:

    // Illuminated Tile Grid
    // Ed Nisley – KE4ZNU
    // 2020-05
    /* [Configuration] */
    Layout = "Build"; // [Cell,CellArray,MCU,Base,Show,Build]
    Shape = "Square"; // [Square, Pyramid, Cone]
    Cells = [2,2];
    CellDepth = 15.0;
    Support = true;
    Inserts = true;
    /* [Hidden] */
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    HoleWindage = 0.2;
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    Protrusion = 0.1; // make holes end cleanly
    ID = 0;
    OD = 1;
    LENGTH = 2;
    Tile = [25.0 + 0.1,25.0 + 0.1,4.0];
    WallThick = 3*ThreadWidth;
    Flange = [4*ThreadWidth,4*ThreadWidth,0]; // ridge supporting tile
    Separator = [3*ThreadWidth,3*ThreadWidth,Tile.z – 1]; // between tiles
    Screw = [3.0,6.0,3.5]; // M3 SHCS, OD=head, LENGTH=head
    Insert = [3.0,4.2,8.0]; // threaded brass insert
    PCB = [15.0,8.0,2.5];
    LED = [5.0 + 2*HoleWindage,5.0 + 2*HoleWindage,1.0];
    LEDOffset = [0.0,(PCB.y – LED.y)/2 – 0.5,0.0]; // slight offset from +Y PCB edge
    CellOAL = [Tile.x,Tile.y,0] + Separator + [0,0,CellDepth] + [0,0,WallThick] + [0,0,PCB.z];
    ArrayOAL = [Cells.x*CellOAL.x,Cells.y*CellOAL.y,CellOAL.z]; // just the LED cells
    BlockOAL = ArrayOAL + [2*WallThick,2*WallThick,0]; // LED cells + exterior wall
    echo(str("Block OAL: ",BlockOAL));
    InsertOC = ArrayOAL – [Insert[OD],Insert[OD],0] – [2*WallThick,2*WallThick,0];
    echo(str("Insert OC: ",InsertOC));
    TapeThick = 1.0;
    Arduino = [44.0,18.0,8.0 + TapeThick]; // Arduino Nano to top of USB Mini-B plug
    USBPlug = [15.0,11.0,8.5]; // USB Mini-B plug insulator
    USBOffset = [0,0,5.5]; // offset from PCB base
    WiringBay = [BlockOAL.x – 4*WallThick,38.0,3.0];
    PlateOAL = [BlockOAL.x,BlockOAL.y,WallThick + Arduino.z + WiringBay.z];
    echo(str("Base Plate: ",PlateOAL));
    //————————
    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);
    }
    //———————–
    // Base and optics in single tile
    module LEDCone() {
    hull() {
    translate([0,0,CellDepth + Tile.z/2])
    cube(Tile – [Flange.x,Flange.y,0],center=true);
    if (Shape == "Square") {
    translate([0,0,LED.z/2])
    cube([Tile.x,Tile.y,LED.z] – [Flange.x,Flange.y,0],center=true);
    }
    else if (Shape == "Pyramid") {
    translate([0,0,LED.z/2])
    cube(LED,center=true);
    }
    else if (Shape == "Cone") {
    translate([0,0,LED.z/2])
    cylinder(d=1.5*LED.x,h=LED.z,center=true);
    }
    else {
    echo(str("Whoopsie! Invalid Shape: ",Shape));
    cube(5);
    }
    }
    }
    // One complete LED cell
    module LEDCell() {
    difference() {
    translate([0,0,CellOAL.z/2])
    cube(CellOAL,center=true);
    translate([0,0,CellOAL.z – Separator.z + Tile.z/2])
    cube(Tile,center=true);
    translate([0,0,PCB.z + WallThick])
    LEDCone();
    cube([LED.x,LED.y,CellOAL.z],center=true);
    translate(-LEDOffset + [0,0,PCB.z/2 – Protrusion/2])
    cube(PCB + [0,0,Protrusion],center=true);
    }
    if (Support)
    color("Yellow") render()
    translate(-LEDOffset) {
    // translate([0,0,ThreadThick/2])
    // cube([PCB.x – 2*ThreadWidth,PCB.y – 2*ThreadWidth,ThreadThick],center=true);
    intersection() {
    translate([0,0,(PCB.z – ThreadThick)/2])
    cube([PCB.x – 2*ThreadWidth,PCB.y – 2*ThreadWidth,PCB.z – ThreadThick],center=true);
    union() { for (a=[0:22.5:359])
    rotate(a)
    translate([PCB.x/2,0,PCB.z/2])
    cube([PCB.x,2*ThreadWidth,PCB.z],center=true); }
    }
    }
    }
    // The whole array of cells
    module CellArray() {
    difference() {
    union() {
    translate([CellOAL.x/2 – Cells.x*CellOAL.x/2,CellOAL.y/2 – Cells.y*CellOAL.y/2,0])
    for (i=[0:Cells.x – 1], j=[0:Cells.y – 1])
    translate([i*CellOAL.x,j*CellOAL.y,0])
    LEDCell();
    if (Inserts) // bosses
    for (i=[-1,1], j=[-1,1])
    translate([i*InsertOC.x/2,j*InsertOC.y/2,0])
    rotate(180/8)
    cylinder(d=Insert[OD] + 3*WallThick,h=Insert[LENGTH],$fn=8);
    }
    if (Inserts) // holes
    for (i=[-1,1], j=[-1,1])
    translate([i*InsertOC.x/2,j*InsertOC.y/2,-Protrusion])
    rotate(180/8)
    PolyCyl(Insert[OD],Insert[LENGTH] + WallThick + Protrusion,8);
    }
    difference() {
    translate([0,0,CellOAL.z/2])
    cube(BlockOAL,center=true);
    translate([0,0,CellOAL.z])
    cube(ArrayOAL + [0,0,2*CellOAL.z],center=true);
    }
    }
    // Arduino bounding box
    // Origin at center bottom of PCB
    module Controller() {
    union() {
    translate([0,0,Arduino.z/2])
    cube(Arduino,center=true);
    translate([Arduino.x/2 – Protrusion,-USBPlug.y/2,USBOffset.z + TapeThick – USBPlug.z/2])
    cube(USBPlug + [Protrusion,0,0],center=false);
    }
    }
    // Baseplate
    module BasePlate() {
    difference() {
    translate([0,0,PlateOAL.z/2])
    cube(PlateOAL,center=true);
    translate([0,0,WallThick])
    Controller();
    translate([0,0,WallThick + PlateOAL.z/2])
    cube([Arduino.x – 2*2.0,WiringBay.y,PlateOAL.z],center=true);
    translate([0,0,PlateOAL.z – WiringBay.z + WiringBay.z/2])
    cube(WiringBay + [0,0,2*Protrusion],center=true);
    for (i=[-1,1], j=[-1,1])
    translate([i*InsertOC.x/2,j*InsertOC.y/2,-Protrusion])
    rotate(180/8) {
    PolyCyl(Screw[ID],2*PlateOAL.z,8);
    PolyCyl(Screw[OD],Screw[LENGTH] + 4*ThreadThick + Protrusion,8);
    }
    translate([0,0,ThreadThick-Protrusion])
    cube([17.0,45,2*ThreadThick],center=true);
    }
    linear_extrude(height=2*ThreadWidth + Protrusion) {
    translate([1,0,-Protrusion])
    rotate(-90) mirror([1,0,0])
    text(text="Ed Nisley",size=6,font="Arial:style:Bold",halign="center");
    translate([-6.5,0,-Protrusion])
    rotate(-90) mirror([1,0,0])
    text(text="softsolder.com",size=4.5,font="Arial:style:Bold",halign="center");
    }
    if (Support)
    color("Yellow")
    for (i=[-1,1], j=[-1,1])
    translate([i*InsertOC.x/2,j*InsertOC.y/2,0])
    for (a=[0:45:135])
    rotate(a)
    translate([0,0,(Screw[LENGTH] – ThreadThick)/2])
    cube([Screw[OD] – 2*ThreadWidth,2*ThreadWidth,Screw[LENGTH] – ThreadThick],center=true);
    }
    //———————–
    // Build things
    if (Layout == "Cell")
    LEDCell();
    else if (Layout == "CellArray")
    CellArray();
    else if (Layout == "MCU")
    Controller();
    else if (Layout == "Base")
    BasePlate();
    else if (Layout == "Show") {
    translate([0,0,PlateOAL.z + 10])
    CellArray();
    BasePlate();
    }
    else if (Layout == "Build") {
    translate([0,0.6*BlockOAL.y,0])
    CellArray();
    translate([0,-0.6*BlockOAL.y,0])
    rotate(90)
    BasePlate();
    }

  • Glass Tiles: Single Test Cell

    Glass Tiles: Single Test Cell

    A single glass tile rests on the ridge around the pyramidal interior:

    Glass Tile Frame - pyramid cell
    Glass Tile Frame – pyramid cell

    The bottom has a cutout for the WS2812 PCB, with some in-the-model support for simplicity:

    Glass Tile Frame - pyramid cell - bottom
    Glass Tile Frame – pyramid cell – bottom

    Which becomes this in real life:

    Glass Tile - 1x1 cell test - pyramid PETG strings
    Glass Tile – 1×1 cell test – pyramid PETG strings

    There’s plenty of PETG hair inside the opening, which seems like a Bad Thing all around.

    Cleaning out the worst of the fur, taping a WS2812 LED into the opening, and dropping a white-ish tile in place:

    Glass Tile - 1x1 cell test - purple phase
    Glass Tile – 1×1 cell test – purple phase

    Obviously, JPG compression wasn’t built with a finely textured granular surface in mind:

    Glass Tile - 1x1 cell test - blue phase
    Glass Tile – 1×1 cell test – blue phase

    But it looks really nice in a dim room!

    With a physical object in hand, it’s obvious the pyramidal interior adds exactly zero value:

    • Direct rays in the beam from the WS2812 don’t hit the walls
    • Light outside the beam doesn’t contribute much after hitting those irregular walls

    So the next pass should be just a hollow box with tweaked tile & PCB measurement: rapid prototyping in full effect!

  • Glass Tiles: Proof of Concept

    Glass Tiles: Proof of Concept

    Extract some victims from a square foot of glass tiles:

    Glass Tiles - as sold
    Glass Tiles – as sold

    Wire an old WS2812 breakout board (the new ones are much larger) to an Arduino Nano running the Nissan Fog Lamp firmware:

    Glass Tile - backlight blue - setup
    Glass Tile – backlight blue – setup

    Aaaand it looks like this might actually work:

    Glass Tile - backlight blue
    Glass Tile – backlight blue

    The WS2812 “beam” illuminates the 25 mm square tile without too much vignetting at about 15 mm.

    The bottom tile is white-ish, the top is gray-ish, and they look different enough to justify using only one color in each array:

    Glass Tile - backlight neutral
    Glass Tile – backlight neutral

    Now, for some solid modeling …

  • American Standard Kitchen Faucet: Yet Another Replacement

    American Standard Kitchen Faucet: Yet Another Replacement

    These cartridges seem to wear out after two years, at most:

    American Standard faucet cartridge
    American Standard faucet cartridge

    The handle becomes difficult to move, both left-to-right and up-and-down, with lubrication of the (obviously metal-on-plastic) shaft being unavailing.

    Having devoted considerable time & attention to keeping this thing alive, there really aren’t any user-serviceable parts inside:

    American Standard Ceramic Faucet Valve Cores - old vs new
    American Standard Ceramic Faucet Valve Cores – old vs new

    I think the sliding fit between the two ceramic blocks laps itself into a more perfect joint, to the extent it’s wrung together and can’t be moved. Even after filtering, our town-supplied water apperently has enough micro-fine grit for the purpose.

    So I have another valve core for the collection …

    On the upside, the improved spout bearing rings continue to work fine, although it’s only been five months.

  • Floor Lamp: Rattle-Can Black

    Floor Lamp: Rattle-Can Black

    Shooting the modified copper elbow with gloss black atop gray primer definitely improved its disposition:

    Floor Lamp - painted elbow - installed
    Floor Lamp – painted elbow – installed

    I’d have been more inclined to apply several light coats if the wind weren’t blowing up a storm. As it was, I shot enough black to cover the not-quite-dry primer (“top coat at any time”) and called it a day.

    The scuffed tubes aren’t quite that ugly in person, but they have suffered some abuse along the way. Seen from a normal working distance, however, it’s all good:

    Floor Lamp - finished
    Floor Lamp – finished

    The lamp isn’t quite as tippy as I feared, so I’ll try it without the broken truck spring counterweight until something untoward happens.

    I loves me some happy ending …

  • Floor Lamp: Threaded Fittings

    Floor Lamp: Threaded Fittings

    The reshaped copper elbow on the floor lamp now has the right angle, but lacks threaded connections to the tubes. The OEM tube threads are close to M15×1, thus prompting the change gear exercise persuading Tiny Lathe™ to cut metric threads.

    Chuck up a length of 5/8 inch aluminum tube, clean up the end, and poke a thread runout slot into it:

    Floor Lamp - tube fitting - thread runout
    Floor Lamp – tube fitting – thread runout

    Turn the soon-to-be-thread OD to 14.7 mm, well under the minimum 14.794 mm major thread diameter. I figure it’s better to match the existing not-quite-standard tube threads than to get all fussy about tolerances:

    Floor Lamp - tube fitting - thread OD
    Floor Lamp – tube fitting – thread OD

    Drill out the tube to 27/64 inch = 0.422 inch = 10.7 mm, a bit larger than the OEM fittings, to easily pass the JST-SM connector I added so I could take the lamp apart:

    Floor Lamp - tube fitting - drilling bore
    Floor Lamp – tube fitting – drilling bore

    Yeah, you’re not supposed to let the swarf build up like that, but it’s hard to stop when you’re getting good chip.

    Break the sharp edges:

    Floor Lamp - tube fitting - ready for threading
    Floor Lamp – tube fitting – ready for threading

    Set up for threading:

    Floor Lamp - tube fitting - external threading setup
    Floor Lamp – tube fitting – external threading setup

    That’s a really nice Warner laydown threader I won as a Cabin Fever door prize quite some years ago.

    A comprehensive discussion of threading may be handy.

    The compound is at 90° to the cross slide, because the DRO housing doesn’t let the compound swivel to the proper angle for thread cutting. I’m just ramming the threader straight into the tube, taking sissy cuts, and hoping for the best.

    Kiss the OD with the cutter, set the cross slide DRO to zero, position the cutter just off the end of the tube, close the split nuts around the leadscrew, engage the threading dial at a conspicuous mark:

    Mini-Lathe Threading Dial - aligned
    Mini-Lathe Threading Dial – aligned

    The first real pass looked good:

    Floor Lamp - tube fitting - first thread pass
    Floor Lamp – tube fitting – first thread pass

    The runout slot is 1/16 inch = 1.6 mm wide and I’m running the lathe dead slow, so there’s plenty of time to punch the STOP button as the cutter enters the slot and let the spindle coast down. Flip the switch to REVERSE, crank the cross slide out a turn (1 mm with 0.3 mm of crank backlash), run the cutter back to the starting point, crank the cross slide in, and iterate until the fitting screws into one of the OEM lamp tubes:

    Floor Lamp - tube fitting - final thread
    Floor Lamp – tube fitting – final thread

    The 5/8 inch tube is just a smidge too small for the copper fitting, so knurl the fitting to enlarge the OD slightly more than a smidge:

    Floor Lamp - tube fitting - knurled
    Floor Lamp – tube fitting – knurled

    Break the knurl edges, part off the fitting, clean up the new end, and do it all over again:

    Floor Lamp - tube fitting - threaded adapters
    Floor Lamp – tube fitting – threaded adapters

    The knurls got filed down to an exact slip fit in the copper elbow and will eventually be epoxied in place.

    The cut-off tube on the lamp head also needs internal threads, so bore out the interior to flatten the weld seam:

    Floor Lamp - tube fitting - cleaning tube bore
    Floor Lamp – tube fitting – cleaning tube bore

    No pix of the threading, but you have the general idea; the tube wall is a scant 0.6 mm thick, so this isn’t the place for full-spec threads. I stopped when the OEM tube screwed in place.

    Apart from the hideous solder job, it came together pretty well:

    Floor Lamp - tube fitting - unpainted
    Floor Lamp – tube fitting – unpainted

    It’s much more stable than Kapton-wrapped tubes jammed into a bare copper fitting, although that’s not saying much.

    A rattle-can finish seems appropriate …

  • Mini-Lathe: Threading Dial Alignment

    Mini-Lathe: Threading Dial Alignment

    As received, the mini-lathe’s threading dial was misaligned by about 1/4 division, which is nearly halfway to the next engagement point midway between the divisions:

    Mini-Lathe Threading Dial - as received - colorized
    Mini-Lathe Threading Dial – as received – colorized

    I added the red lacquer crayon while contemplating what to do, because I thought the dial was swaged onto the shaft. It turns out to be threaded, so I marked where the dial should be, grabbed the shaft in the (soft-jawed) bench vise, and twisted the dial with a Vise-Grip until it lined up:

    Mini-Lathe Threading Dial - aligned
    Mini-Lathe Threading Dial – aligned

    Well, it’s closer than it was, OK?

    There’s about that much slop on either side of the index line coming from the loose gear engaging the leadscrew, so that’s as good as it gets.