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.

Tag: M2

Using and tweaking a Makergear M2 3D printer

  • Tube Turning Adapters

    Tube Turning Adapters

    Finishing the PVC tubes reinforcing the vacuum cleaner adapters required fixtures on each end:

    Dirt Devil adapter - pipe turning
    Dirt Devil adapter – pipe turning

    Because the tubes get epoxied into the adapters, there’s no particular need for a smooth surface finish and, in fact, some surface roughness makes for a good epoxy bond. The interior of a 3D printed adapter is nothing if not rough; the epoxy in between will be perfectly happy.

    Turning the tubes started by just grabbing the conduit in the chuck and peeling the end that stuck out down to the finished diameter, because the conduit was thick-walled enough to let that work.

    The remaining wall was so thin that the chuck would crunch it into a three-lobed shape, so the white ring in the chuck is a scrap of PVC pipe turned to fit the tube ID and provide enough reinforcement to keep the tube round.

    The conduit ID isn’t a controlled dimension and was, in point of fact, not particularly round. It was, however, smooth, which counts for more than anything inside a tube carrying airborne fuzzy debris; polishing the interior of a lathe-bored pipe simply wasn’t going to happen.

    The fixture on the other end started as a scrap of polycarbonate bandsawed into a disk with a hole center-drilled in the middle:

    Pipe end lathe fixture - center drilling
    Pipe end lathe fixture – center drilling

    Stick it onto a disk turning fixture and sissy-cut the OD down a little smaller than the eventual tube OD:

    Pipe end lathe fixture - turning OD
    Pipe end lathe fixture – turning OD

    Turn the end down to fit the tube ID, flip it around to center-drill the other side, stick it into the tube, and finally finish the job:

    Dirt Devil adapter - pipe fixture
    Dirt Devil adapter – pipe fixture

    The nice layering effect along the tube probably comes from molding the conduit from recycled PVC with no particular concern for color matching.

    A family portrait of the fixtures with a finished adapter:

    Dirt Devil adapter - fixtures
    Dirt Devil adapter – fixtures

    A fine chunk of Quality Shop Time: solid modeling, 3D printing, mini-lathe turning, and even some coordinate drilling on the Sherline.

  • Dirt Devil Vacuum Tool Adapters

    Dirt Devil Vacuum Tool Adapters

    Being the domain expert for adapters between a new vacuum cleaner and old tools, this made sense (even though it’s not our vacuum):

    Dirt Devil Nozzle Bushing - solid model
    Dirt Devil Nozzle Bushing – solid model

    The notch snaps into a Dirt Devil Power Stick vacuum cleaner and the tapered end fits a variety of old tools for other vacuum cleaners:

    Dirt Devil Nozzle Bushing top view - solid model
    Dirt Devil Nozzle Bushing top view – solid model

    Having some experience breaking thin-walled adapters, these have reinforcement from a PVC tube:

    Dirt Devil adapter - parts
    Dirt Devil adapter – parts

    A smear of epoxy around the interior holds the tube in place:

    Dirt Devil adapters - assembled
    Dirt Devil adapters – assembled

    Building the critical dimensions with a 3D printed part simplified the project, because I could (and did!) tweak the OpenSCAD code to match the tapers to the tools. Turning four of those tubes from a chunk of PVC conduit, however, makes a story for another day.

    The OpenSCAD source code as a GitHub Gist:

    // Dirt Devil nozzle adapter
    // Ed Nisley KE4ZNU 2021-10
    // Tool taper shift
    Finesse = -0.1; // [-0.5:0.1:0.5]
    // PVC pipe liner
    PipeOD = 28.5;
    /* [Hidden] */
    //- Extrusion parameters
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    HoleWindage = 0.2;
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    Protrusion = 0.1; // make holes end cleanly
    //———————-
    // Dimensions
    TAPER_MIN = 0;
    TAPER_MAX = 1;
    TAPER_LENGTH = 2;
    Socket = [36.0,37.0,40.0];
    LockringDia = 33.5;
    LockringWidth = 4.5;
    LockringOffset = 2.5;
    Tool = [Finesse,Finesse,0] + [30.0,31.1,30.0];
    AdapterOAL = Socket[TAPER_LENGTH] + Tool[TAPER_LENGTH];
    NumSides = 36;
    $fn = NumSides;
    //———————-
    // 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(r=(FixDia + HoleWindage)/2,h=Height,$fn=Sides);
    }
    //——————-
    // Define it!
    module Adapter() {
    difference() {
    union() {
    difference() {
    cylinder(d1=Socket[TAPER_MIN],d2=Socket[TAPER_MAX],h=Socket[TAPER_LENGTH]);
    translate([0,0,LockringOffset])
    cylinder(d=2*Socket[TAPER_MAX],h=LockringWidth);
    }
    cylinder(d=LockringDia,h=Socket[TAPER_LENGTH]);
    translate([0,0,LockringOffset + 0.75*LockringWidth])
    cylinder(d1=LockringDia,d2=Socket[TAPER_MIN],h=0.25*LockringWidth);
    translate([0,0,Socket[TAPER_LENGTH]])
    cylinder(d1=Tool[TAPER_MAX],d2=Tool[TAPER_MIN],h=Tool[TAPER_LENGTH]);
    }
    translate([0,0,-Protrusion])
    PolyCyl(PipeOD,AdapterOAL + 2*Protrusion,NumSides);
    }
    }
    //———————-
    // Build it!
    Adapter();

    The taper in the code almost certainly won’t fit whatever tool you have: measure thrice, print twice, and maybe fit once …

  • Tour Easy Rear Running Light: Circuit Support Plate

    Tour Easy Rear Running Light: Circuit Support Plate

    Building the circuit support plate for the amber front running light was entirely too fiddly:

    1 W LED Running Light - baseplate dry assembly
    1 W LED Running Light – baseplate dry assembly

    This was definitely easier:

    Running Light Circuit Plate - solid model
    Running Light Circuit Plate – solid model

    Two pins fit in the small holes to align it with the LED heatsink, with an M3 stud and brass insert holding it in place:

    Tour Easy Rear Running Light - circuit plate attachment
    Tour Easy Rear Running Light – circuit plate attachment

    The rectangular hole around the insert let me glop urethane adhesive over it to lock it into the plate, with more goop on the screw and pins to unify heatsink and plate.

    The LED wires now emerge from the heatsink on the same side of the plate, simplifying the connections to the MP1584 regulator and current-sense resistor:

    Tour Easy Rear Running Light - regulator wiring
    Tour Easy Rear Running Light – regulator wiring

    The paralleled 5.1 Ω and 3.3 Ω resistors form a 2.0 Ω resistor setting the LED current to 400 mA = 1 W at 2.6 V forward drop. They’re 1 W resistors dissipating a total of 320 mW and get barely warm.

    The resistors and wires are stuck in place with clear adhesive, so things shouldn’t rattle around too much.

    The OpenSCAD source code as a GitHub Gist:

    // Circuit plate for Tour Easy running lights
    // Ed Nisley – KE4ZNU – 2021-09
    /* [Hidden] */
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    HoleWindage = 0.2;
    Protrusion = 0.1; // make holes end cleanly
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    ID = 0;
    OD = 1;
    LENGTH = 2;
    inch = 25.4;
    //———————-
    // Dimensions
    // Light case along X axis
    LightID = 23.0;
    WallThick = 2.0;
    Screw = [3.0,6.8,4.0]; // M3 OD=washer, length=nut + washers
    Insert = [3.0,4.2,8.0]; // splined brass insert, minus splines
    InsertOffset = 10.0; // insert from heatsink end
    PinOD = 1.6; // alignment pins
    PinOC = 14.0;
    PinDepth = 5.0;
    Plate = [50.0,LightID,Insert[OD] + 4*ThreadThick]; // overall plate size
    WirePort = [10.0,3.0,2*Plate.z];
    NumSides = 2*3*4;
    //———————-
    // 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(r=(FixDia + HoleWindage)/2,
    h=Height,
    $fn=Sides);
    }
    // Circuit plate
    module Plate() {
    difference() {
    intersection() {
    cube(Plate,center=true);
    rotate([0,90,0])
    cylinder(d=LightID,h=2*Plate.x,$fn=NumSides,center=true);
    }
    rotate([0,90,0]) rotate(180/6)
    translate([0,0,-Plate.x])
    PolyCyl(Screw[ID],2*Plate.x,6);
    rotate([0,90,0]) rotate(180/6)
    translate([0,0,-Plate.x/2 – Protrusion])
    PolyCyl(Insert[OD],Insert[LENGTH] + InsertOffset + Protrusion,6);
    translate([-Plate.x/2 + InsertOffset + Insert[LENGTH]/2,0,Plate.z/2])
    cube([Insert[LENGTH],Insert[OD],Plate.z],center=true);
    for (j=[-1,1])
    translate([-Plate.x/2,j*PinOC/2,0])
    rotate([0,90,0]) rotate(180/6)
    translate([0,0,-PinDepth])
    PolyCyl(PinOD,2*PinDepth,6);
    for (j=[-1,1])
    translate([0,j*(Plate.y/2 – WirePort.y/2),0])
    cube(WirePort,center=true);
    }
    }
    //- Build it
    Plate();

  • Rear Running Light: Tour Easy Seat Clamp

    Rear Running Light: Tour Easy Seat Clamp

    With the amber front running light blinking away, it’s time to replace the decade-old Planet Bike Superflash behind the seat:

    Superflash on Tour Easy
    Superflash on Tour Easy

    The new mount descends directly from the clamps holding the fairing strut on the handlebars and various hose clamps:

    Rear Running Light Seat Clamp - solid model
    Rear Running Light Seat Clamp – solid model

    The central block has two quartets of brass inserts epoxied inside:

    Rear Running Light Seat Clamp - sectioned - solid model
    Rear Running Light Seat Clamp – sectioned – solid model

    That means I can install the light, then mount the whole affair on the bike, without holding everything together while fiddling with overly long screws.

    A trial fit with the not-yet-cut-to-length 25.3 (-ish) PVC pipe body tube:

    Rear Running Light - Tour Easy seat clamp trial fit
    Rear Running Light – Tour Easy seat clamp trial fit

    The aluminum plates have the standard used-car finish: nice polish over deep scratches.

    Although I’ve been thinking of mounting the light below the seat rail, as shown, it can also sit above the rail.

    Mary hauls seedlings and suchlike to the garden in a plastic drawer bungied to the rack, with the SuperFlash serving as an anchor point; this light may need fine tuning for that purpose.

    The OpenSCAD source code as a GitHub Gist:

    // Rear running light clamp for Tour Easy seat strut
    // Ed Nisley – KE4ZNU – 2021-09
    Layout = "Show"; // [Show,Build,Block]
    Section = true;
    /* [Hidden] */
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    HoleWindage = 0.2;
    Protrusion = 0.1; // make holes end cleanly
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    ID = 0;
    OD = 1;
    LENGTH = 2;
    inch = 25.4;
    //———————-
    // Dimensions
    // Light case along X axis, seat strut along Y, Z=0 at strut centerline
    LightOD = 25.4 + HoleWindage;
    StrutOD = 5/8 * inch + HoleWindage;
    PlateThick = 1/16 * inch;
    WallThick = 2.0;
    Kerf = ThreadThick;
    Screw = [3.0,6.8,4.0]; // M3 OD=washer, length=nut + washers
    Insert = [3.0,5.4,8.0 + 1.0]; // splined brass insert
    RoundRadius = IntegerMultiple(Screw[OD]/2,0.5); // corner rounding
    ScrewOC = [IntegerMultiple(StrutOD + 2*WallThick + Screw[ID],1.0),
    IntegerMultiple(LightOD + 2*WallThick + Screw[ID],1.0)];
    echo(str("Screw OC: ",ScrewOC));
    BlockSize = [ScrewOC.x + Insert[OD] + 2*WallThick,
    ScrewOC.y + Insert[OD] + 2*WallThick,
    LightOD + StrutOD + 3*WallThick];
    echo(str("Block: ",BlockSize));
    BaseOffset = -(WallThick + LightOD/2); // block bottom to centerline
    StrutOffset = LightOD/2 + WallThick + StrutOD/2; // light centerline to strut centerline
    echo(str("Strut screw min: ",IntegerMultiple(PlateThick + WallThick + StrutOD/2 + Insert[LENGTH]/2,1.0)));
    echo(str("Light screw min: ",IntegerMultiple(PlateThick + WallThick + LightOD/2 + Insert[LENGTH]/2,1.0)));
    NumSides = 2*3*4;
    //———————-
    // 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(r=(FixDia + HoleWindage)/2,
    h=Height,
    $fn=Sides);
    }
    // Block with light along X axis
    module Block() {
    difference() {
    hull()
    for (i=[-1,1], j=[-1,1])
    translate([i*(BlockSize.x/2 – RoundRadius),j*(BlockSize.y/2 – RoundRadius),BaseOffset])
    cylinder(r=RoundRadius,h=BlockSize.z,$fn=NumSides);
    for (i=[-1,1], j=[-1,1])
    translate([i*ScrewOC.x/2,j*ScrewOC.y/2,BaseOffset – Protrusion])
    rotate(180/8)
    PolyCyl(Screw[ID],BlockSize.z + 2*Protrusion,8);
    for (i=[-1,1], j=[-1,1])
    translate([i*ScrewOC.x/2,j*ScrewOC.y/2,0]) {
    translate([0,0,-Protrusion])
    rotate(180/8)
    PolyCyl(Insert[OD],Insert[LENGTH] + 1*Protrusion,8);
    translate([0,0,(StrutOffset – Insert[LENGTH] – Kerf/2 + Protrusion)])
    rotate(180/8)
    PolyCyl(Insert[OD],Insert[LENGTH] + 1*Protrusion,8);
    }
    translate([-BlockSize.x,0,0])
    rotate([0,90,0])
    cylinder(d=LightOD,h=2*BlockSize.x,$fn=NumSides);
    translate([0,BlockSize.y,StrutOffset])
    rotate([90,0,0])
    cylinder(d=StrutOD,h=2*BlockSize.y,$fn=NumSides);
    translate([0,0,StrutOffset])
    cube([2*BlockSize.x,2*BlockSize.y,Kerf],center=true);
    cube([2*BlockSize.x,2*BlockSize.y,Kerf],center=true);
    }
    }
    //- Build it
    if (Layout == "Block")
    if (Section)
    difference() {
    Block();
    rotate(atan(ScrewOC.y/ScrewOC.x))
    translate([0,BlockSize.y,0])
    cube(2*BlockSize,center=true);
    }
    else
    Block();
    if (Layout == "Show") {
    Block();
    color("Green",0.25)
    translate([-BlockSize.x,0,0])
    rotate([0,90,0])
    cylinder(d=LightOD,h=2*BlockSize.x,$fn=NumSides);
    color("Green",0.25)
    translate([0,BlockSize.y,StrutOffset])
    rotate([90,0,0])
    cylinder(d=StrutOD,h=2*BlockSize.y,$fn=NumSides);
    }
    if (Layout == "Build") {
    translate([-1.2*BlockSize.x,0,-BaseOffset])
    difference() {
    Block();
    translate([0,0,BlockSize.z])
    cube(2*BlockSize,center=true);
    }
    translate([1.2*BlockSize.x,0,StrutOD/2 + WallThick])
    difference() {
    rotate([180,0,0])
    translate([0,0,-StrutOffset])
    Block();
    translate([0,0,BlockSize.z])
    cube(2*BlockSize,center=true);
    }
    translate([0,0,StrutOffset – Kerf/2])
    rotate([180,0,0])
    intersection() {
    Block();
    translate([0,0,StrutOffset/2])
    cube([2*BlockSize.x,2*BlockSize.y,StrutOffset],center=true);
    }
    }

  • Tour Easy 1 W Amber Running Light: Firmware

    Tour Easy 1 W Amber Running Light: Firmware

    Rather than conjure a domain specific language to blink an LED, it’s easier to use Morse code:

    Herewith, Arduino source code using Mark Fickett’s Morse library to blink an amber running light:

    // Tour Easy Running Light
    // Ed Nisley - KE4ZNU
    // September 2021
    
    #include <morse.h>
    
    #define PIN_OUTPUT	13
    
    LEDMorseSender Morser(PIN_OUTPUT,(float)10.0);
    
    void setup()
    {
    	Morser.setup();
    
        Morser.setMessage(String("qst de ke4znu "));
        Morser.sendBlocking();
    
    //    Morser.setWPM((float)3.0);
        Morser.setSpeed(50);
    	Morser.setMessage(String("s   "));
    }
    
    void loop()
    {
    	if (!Morser.continueSending())
    		Morser.startSending();
    
    }
    

    Bonus: a trivially easy ID string.

    A dit time of 50 ms produces a brief flash that’s probably about as fast as it can be, given that the regulator must ramp the LED current up from zero after its Enable input goes high. In round numbers, a 50ms dit corresponds to 24 WPM Morse.

    Each of the three blanks after the “s” produces a seven element word space to keep the blinks from running together.

    Sending “b ” (two blanks) with a 75 ms dit time may be more noticeable. You should tune for maximum conspicuity on your rides.

    1 W Amber Running Light - installed front
    1 W Amber Running Light – installed front

    On our first ride, Mary got a friendly wave from a motorcyclist, an approving toot from a driver, and several “you go first” gestures at intersections.

    Works for us …

  • Seedling Shelter Frame Deployment

    Seedling Shelter Frame Deployment

    Mary bound up a mesh cover for the shelter frame and deployed it to protect some yummy seedlings:

    Seedling Mesh Shelter - installed
    Seedling Mesh Shelter – installed

    Those will become the next round of lunchtime sandwiches:

    Turkey Sandwich with Excessive Lettuce
    Turkey Sandwich with Excessive Lettuce

    It’s a quarter-pounder: 4 oz of turkey, 4 oz of lettuce, and a layer of Swiss and good stinky Provolone cheese. Yum!

  • Vacuum Tube Lights: Urethane Coated Plate Cap

    Vacuum Tube Lights: Urethane Coated Plate Cap

    With a generous dollop of JB Plastic Bonder left over from a set of Bafang brake sensor magnets, I tried coating the ersatz plate cap of a triode tube:

    Triode - urethane coated plate cap
    Triode – urethane coated plate cap

    That’s the result after leaving it hanging upside-down while it cured to push all the drips to the top.

    For comparison, the uncoated cap back in the day:

    Triode - plate cap plug
    Triode – plate cap plug

    Seeing as how the urethane is an adhesive, not a coating, I’d say it looks about as bad as expected.

    As with all 3D printed things, one must embrace imperfections and striations, rather than endlessly strive for perfection.

    Now, if I had a resin printer …