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: MK4

Prusa Mk 4 3D printer with MMU3 feeder

  • Translucent vs. Transparent PETG Soap Dishes

    Translucent vs. Transparent PETG Soap Dishes

    In addition to printing bendy objects with TPU, the 0.8 mm nozzle 3D-prints PETG into thin walls with better transparency than the default 0.4 mm nozzle:

    Clear PETG - 0.4 vs 0.8 mm nozzle - side view
    Clear PETG – 0.4 vs 0.8 mm nozzle – side view

    The wall is now 1.0 mm thick, rather than 0.6 mm, and is much closer to being transparent. Those gray links from the RPi camera mount inside the dishes help show the difference.

    The 2.0 mm thick base plate is also more transparent, but mostly just reveals the 0.4 mm thick infill layers:

    Clear PETG - 0.4 vs 0.8 mm nozzle - top view
    Clear PETG – 0.4 vs 0.8 mm nozzle – top view

    More study is needed, even if we already have far more soap dishes than strictly necessary.

  • Prusa MK4: Nozzle Change Checklist

    Prusa MK4: Nozzle Change Checklist

    Both the round and square TPU patio table feet came from a 0.8 mm nozzle on the Prusa MK4, which produces results much faster than the venerable Makergear M2’s 0.35 mm nozzle. However, for unknown reasons a 0.8 mm nozzle is not compatible with the MMU3, so changing from and to the default 0.4 mm nozzle requires a somewhat complex ritual.

    For context, the MK4 extruder and hot end:

    Prusa MK4 - extruder overview
    Prusa MK4 – extruder overview

    Because the MK4 automatically unloads the filament from the extruder (with help from auto-retracting filament spools) when using the MMU, the hot end doesn’t have any filament in it. Disconnect the PTFE tube from the fitting atop the extruder, insert the end of the TPU filament from its Polydryer box, and …

    Change to 0.8 mm nozzle:

    • Remove silicone sock from hot end
    • Install fixture to hold the hot end in place
    • Loosen the two knobs clamping the nozzle
    • Loosen nozzle with 7 mm socket wrench
    • Unscrew & remove nozzle by hand
    • Install new nozzle by hand
    • Tighten nozzle with wrench
    • Tighten those two knobs
    • Remove fixture
    • Install silicone sock

    Change MK4 settings using the LCD panel:

    • Settings → MMU = Off
    • Settings → Hardware → Printhead = 0.8 mm

    Then, with the TPU filament poked into the top of the extruder:

    • Filament → Load Filament =FLEX

    You’ll want to extrude a few lengths just to settle everything in place.

    Switching back to the 0.4 mm nozzle proceeds in the opposite direction, starting with:

    • Filament → Unload Filament

    Something of a nuisance, but not unbearable.

  • Square Patio Table Feet

    Square Patio Table Feet

    For a square patio table (with one missing foot), of course:

    Patio Table Feet - installed
    Patio Table Feet – installed

    These are chunky enough to demonstrate they’re made of clear-ish TPU, at least when backlit:

    Patio Table Feet - installed - backlit
    Patio Table Feet – installed – backlit

    The interior of the leg determines what fits into it:

    Patio Table Feet - leg interior
    Patio Table Feet – leg interior

    I pried out another foot, scanned it, and blew out the contrast:

    Patio Table Foot - scan
    Patio Table Foot – scan

    Importing that into LightBurn let me draw a rectangle matching the measured size, then node-edit the corners to approximate the shape:

    Patio Table Foot - LightBurn layout
    Patio Table Foot – LightBurn layout

    Export that shape as an SVG, import into OpenSCAD, and turn it into a solid model:

    Patio Table Foot - solid model - show view
    Patio Table Foot – solid model – show view

    That’s the Show view simulating the actual positions, which demonstrates why the pair of legs at each corner wear mirror-imaged feet. The Build view arranges the pair more sensibly for 3D printing:

    Patio Table Foot - solid model - build view
    Patio Table Foot – solid model – build view

    The protrusions and their bumps went through several iterations on the way to being functional, with the black TPU prototype on the left being entirely too bendy and the first clear version requiring utility knife editing to fit the end posts inside the leg:

    Patio Table Feet - prototypes
    Patio Table Feet – prototypes

    The original feet seem to be injection-molded ABS with a flat bottom intended to erode one corner against whatever the table stands on. However, the legs splay out at 5° from the vertical, which makes the flat bottom I used for the first few iterations obviously wrong:

    Patio Table Feet - flat foot
    Patio Table Feet – flat foot

    Somebody who can math harder than I would resolve the two angles and all the measurements into a single transformation matrix, but I rotated the foot separately around the X and Y axes, trigged the lowest corner to the proper height, then chopped off everything below Z=0. Works for me.

    The OpenSCAD source code as a GitHub Gist:

    // Patio Table Foot – rectangular legs
    // Ed Nisley – KE4ZNU
    // 2026-05-26
    include <BOSL2/std.scad>
    Layout = "Show"; // [Show,Build]
    /* [Hidden] */
    HoleWindage = 0.2;
    Protrusion = 0.01;
    NumSides = 4*3*2*4;
    Gap = 5.0/2;
    $fn=NumSides;
    PadOA = [50,23.5,4.5];
    LegAngles = [5,5];
    EndStrut = [2.5 + 2.5,13.3 – 1.0,23.0];
    SideStrut = [12.0,5.5 – 1.0,13.0];
    Clearance = 0.5;
    StrutsOC = [44.0 – EndStrut.x,18.0 – SideStrut.y];
    //—–
    // Define it
    module Foot(angles = LegAngles) {
    difference() {
    up((PadOA.x/2)*abs(sin(angles.x)) + (PadOA.y/2)*abs(sin(angles.y)))
    xrot(angles.x) yrot(angles.y)
    union() {
    down(3*PadOA.z)
    linear_extrude(4*PadOA.z)
    left(PadOA.x/2) fwd(PadOA.y/2)
    import("Patio Table Foot – pad outline.svg",center=true);
    up(PadOA.z)
    for (i = [-1,1])
    right(i*StrutsOC.x/2)
    cuboid(EndStrut,anchor=BOTTOM) position(TOP)
    down(EndStrut.y/2) left(i*Clearance)
    pie_slice(r=(PadOA.x – StrutsOC.x)/2,ang=180,l=EndStrut.y,anchor=CENTER,spin=-i*90,orient=FRONT);
    up(PadOA.z)
    for (j = [-1,1])
    fwd(j*StrutsOC.y/2)
    cuboid(SideStrut,anchor=BOTTOM) position(TOP)
    down(SideStrut.x/2) zrot(90) right(j*Clearance)
    pie_slice(r=(PadOA.y – StrutsOC.y)/2,ang=180,l=SideStrut.x,anchor=CENTER,spin=j*90,orient=FRONT);
    }
    cuboid(4*PadOA,anchor=TOP);
    }
    }
    //—–
    // Build it
    if (Layout == "Show") {
    back(PadOA.y/2 + Gap)
    Foot();
    left(0.8*PadOA.x) fwd(PadOA.y) zrot(-90)
    yflip() Foot();
    }
    if (Layout == "Build") {
    union() {
    fwd(PadOA.y/2 + Gap)
    Foot();
    back(PadOA.y/2 + Gap)
    yflip() Foot();
    }
    }

  • Round Patio Table Feet

    Round Patio Table Feet

    For a round patio table, although you can’t tell from the picture:

    Round patio table feet - installed
    Round patio table feet – installed

    Also despite appearances, that’s 3D printed from clear-ish TPU, with its black appearance due to internal reflections from the leg’s dark interior.

    The original hard-white-plastic feet had eroded enough to let the aluminum legs scrape the deck paint:

    Round patio table feet - old vs new
    Round patio table feet – old vs new

    The only way to extract each old foot was to hack out a segment with a razor knife, after which it slid out easily.

    The ring around the top of the sections provides enough griptivity inside the leg to hold the foot in place:

    Round Patio Table Foot - solid model
    Round Patio Table Foot – solid model

    As with the TPU chains on the bike rack tray holder, I expect the compressed / bent segments will gradually relax inside the legs, but the feet ought not fall out in normal use.

    The OpenSCAD source code isn’t quite a one-liner, but it’s close:

    // Patio Table Foot - round legs
    // Ed Nisley - KE4ZNU
    // 2026-05-29
    
    include <BOSL2/std.scad>
    
    /* [Hidden] */
    
    ID = 0;
    OD = 1;
    LENGTH = 2;
    
    HoleWindage = 0.2;
    Protrusion = 0.01;
    NumSides = 4*3*2*4;
    Gap = 5.0;
    
    $fn=NumSides;
    
    PadOA = [8.0,1*INCH,3.0];
    
    SleeveOA = [13.0,21.7 - HoleWindage,12.0];
    
    Kerf = 2.5;
    
    
    //-----
    // Build it
    
    difference() {
      union() {
        tube(PadOA[LENGTH],od=PadOA[OD],id=PadOA[ID],anchor=BOTTOM) position(TOP)
          tube(SleeveOA[LENGTH],od=SleeveOA[OD],id=SleeveOA[ID],anchor=BOTTOM);
        up(PadOA[LENGTH] + SleeveOA[LENGTH] - 1.0)
          torus(d_maj=SleeveOA[OD],r_min=(PadOA[OD] - SleeveOA[OD])/2,anchor=TOP);
      }
      up(PadOA[LENGTH])
        for (a = [0,60,120])
          zrot(a)
            cuboid([PadOA[OD],Kerf,2*SleeveOA[LENGTH]],anchor=BOTTOM);
    }
    
    
  • Bike Rack Tray Holder: Stretchy Tiedown Straps

    Bike Rack Tray Holder: Stretchy Tiedown Straps

    The tray holder on Mary’s bike worked well:

    Bike Rack Tray Holder - in use
    Bike Rack Tray Holder – in use

    Except for having the bungee cord run across the middle of the tray where it blocks access for larger trays and tends to bend the taller leaves.

    Well, I can fix that:

    Bike Rack Tray Holder - straps - rear
    Bike Rack Tray Holder – straps – rear

    The front tiedown is similar:

    Bike Rack Tray Holder - straps - front
    Bike Rack Tray Holder – straps – front

    They’re printed from TPU: rectangular blocks and chains, ending in wire hooks bashed from a coat hanger. The M4 button-head screws thread into (uncrushed) rivnuts, which seemed easier to manage than square nuts in this situation.

    The chains are just thick circles, with half of the top links sunk into the blocks:

    Stretchy Straps - build layout
    Stretchy Straps – build layout

    You’d (well, I’d) want to build them one at a time, because sometimes this happens:

    Bike Rack Tray Holder - bad platform adhesion
    Bike Rack Tray Holder – bad platform adhesion

    Based on those measurements, I raised the extruder by 0.1 mm, but apparently did a poor job of cleaning / flattening the cold TPU on the nozzle and got it wrong. As a result, the first layer didn’t get squooshed properly onto the BuildTak, came unstuck, and produced art . The track down the middle of the photo shows traces of a previous, badly over-squooshed test chain.

    The stretched TPU relaxes enough to leave very little tension after a day, as shown by the unhooked right chain:

    Bike Rack Tray Holder - straps - relaxing
    Bike Rack Tray Holder – straps – relaxing

    However, that make the chains exactly the right length, so they require even more force to get the hooks off the rack. After relaxing for another day, the stretched chains return to roughly their original lengths, so it’s all good.

    The OpenSCAD source code as a GitHub Gist:

    // TPU Tiedown Straps for bike rack tray holder
    // Ed Nisley – KE4ZNU
    // 2026-05-14
    include <BOSL2/std.scad>
    Layout = "Build"; // [Show,Build,Chain,Blocks,Front,Rear]
    /* [Hidden] */
    HoleWindage = 0.2;
    Protrusion = 0.01;
    NumSides = 4*3*2*4;
    Gap = 5.0;
    $fn=NumSides;
    LinkID = 7.0;
    LinkOD = 10.0;
    LinkOC = 14.0;
    LinkHeight = 4.0;
    JointWidth = 2.0;
    FrontChainAngle = 30; // from vertical
    FrontChainLength = 80.0; // nominal length
    RearChainAngle = 20; // from vertical
    RearChainLength = 100.0; // nominal length
    BlockOA = [80.0,12.0,15.0];
    InsertOC = 30.0;
    //—–
    // Define things
    module Chain(n=2) {
    render()
    difference() {
    union() {
    hull() {
    cyl(LinkHeight,d=JointWidth,anchor=BOTTOM,rounding=0.0);
    back((n – 1)*LinkOC)
    cyl(LinkHeight,d=JointWidth,anchor=BOTTOM,rounding=0.0);
    }
    for (i = [0:n-1])
    back(i*LinkOC)
    cyl(LinkHeight,d=LinkOD,anchor=BOTTOM,rounding=0.0);
    }
    for (i = [0:n-1])
    back(i*LinkOC)
    down(Protrusion)
    cyl(LinkHeight + 2*Protrusion,d=(LinkID + HoleWindage),anchor=BOTTOM,rounding=-1.0);
    }
    }
    module FrontBlock() {
    difference() {
    cuboid(BlockOA,anchor=BOTTOM,chamfer=1.0,except=BACK);
    for (i = [-1:1])
    right(i*InsertOC) down(Protrusion) {
    cyl(BlockOA.z + 2*Protrusion,d=4.0 + HoleWindage,anchor=BOTTOM); // screw clearance
    cyl(1.5,d=9.0,anchor=BOTTOM); // insert head
    cyl(11.0,d=6.0,anchor=BOTTOM); // insert body
    }
    }
    }
    module RearBlock() {
    up(BlockOA.z/2) fwd(BlockOA.y/2)
    difference() {
    cuboid(BlockOA,anchor=FRONT,chamfer=1.0,except=BACK);
    for (i = [-1:1])
    right(i*InsertOC) fwd(Protrusion) {
    ycyl(BlockOA.z + 2*Protrusion,d=4.0 + HoleWindage,anchor=FRONT); // screw clearance
    ycyl(1.5,d=9.0,anchor=FRONT); // insert head
    ycyl(11.0,d=6.0,anchor=FRONT); // insert body
    }
    }
    }
    module FrontAssembly(cl=FrontChainLength,ca=FrontChainAngle) {
    Links = ceil(cl / LinkOC);
    union() {
    up(cl*cos(ca)) {
    FrontBlock();
    back(BlockOA.y/2)
    xrot(90)
    for (i = [-1,1])
    left(i*InsertOC/2)
    zrot(-i*ca + 180)
    Chain(Links);
    }
    }
    }
    module RearAssembly(cl=RearChainLength,ca=RearChainAngle) {
    Links = ceil(cl / LinkOC);
    union() {
    up(cl*cos(ca)) {
    RearBlock();
    back(BlockOA.y/2)
    xrot(90)
    for (i = [-1,1])
    left(i*InsertOC/2)
    zrot(-i*ca + 180)
    Chain(Links);
    }
    }
    }
    //—–
    // Build things
    if (Layout == "Chain")
    Chain();
    if (Layout == "Blocks") {
    fwd(BlockOA.y)
    FrontBlock();
    back(BlockOA.y)
    RearBlock();
    }
    if (Layout == "Front")
    FrontAssembly();
    if (Layout == "Rear")
    RearAssembly();
    if (Layout == "Show") {
    fwd(BlockOA.y)
    FrontAssembly();
    back(BlockOA.y)
    zrot(180)
    RearAssembly();
    }
    if (Layout == "Build") {
    fwd(BlockOA.z + Gap/2)
    up(BlockOA.y/2)
    xrot(-90)
    down(FrontChainLength*cos(FrontChainAngle))
    FrontAssembly();
    back(BlockOA.z + Gap/2)
    zrot(180)
    up(BlockOA.y/2)
    xrot(-90)
    down(RearChainLength*cos(RearChainAngle))
    RearAssembly();
    }
  • Prusa MK4 Camera Lighting

    Prusa MK4 Camera Lighting

    Although the Raspberry Pi camera has a good view of the Prusa MK4’s extruder, there’s not much light under there:

    RPi Camera Mount - image
    RPi Camera Mount – image

    There’s also not much room for a lighting fixture on the printer where it must mount, so I modified a trio of nominally 12 V / 4 W COB LED panels:

    Prusa MK4 - Extruder sidelight - COB LEDs
    Prusa MK4 – Extruder sidelight – COB LEDs

    Their “4 W” rating seems aspirational, at best, as a 12 VDC supply pushes only 75 mA through the panel, so they tick along at 900 mW. If you expect cheap eBay / Amazon components to live up to their specs, dream on.

    The modifications:

    • Unsolder the pins
    • Crunch off the surprisingly precise 27.4 Ω SMD resistor
    • Clean up the rubble
    • Wire the panels directly in series, ignoring their bridge rectifiers

    The 15 LEDs on each panel are arranged in five parallel chains of three LEDs for a total forward drop of 8.3 V, so putting three panels in series works with the MK4’s 24 V power supply.

    Stick them onto the MK4 power supply case with foam tape and wire them directly to the 24 V terminals:

    Prusa MK4 - Extruder sidelight - installed
    Prusa MK4 – Extruder sidelight – installed

    There’s very little clearance between the machine frame and the X Axis carriage on the threaded rod. Putting the LEDs in a 3D printed case and routing the wires lower on the column would be nice touches:

    Prusa MK4 - Extruder sidelight - front view
    Prusa MK4 – Extruder sidelight – front view

    The panels start at 30 mA when cold and drop to 25 mA as they warm up in the 63 °F = 17 °C Basement Shop. Each panel dissipates 250 mW: bright enough for the task, dim enough to avoid overpowering the camera’s limited dynamic range, and definitely within whatever power rating they should have.

    Looking over the camera’s shoulder in normal shop lighting suggests it’s about right:

    Prusa MK4 - Extruder sidelight - camera overview
    Prusa MK4 – Extruder sidelight – camera overview

    A staged scene with the shop lights turned off:

    Prusa MK4 - Extruder sidelight - low-light view
    Prusa MK4 – Extruder sidelight – low-light view

    Call it Good Enough™ for the purpose.

  • Prusa MK4 Camera Mount

    Prusa MK4 Camera Mount

    Combining the Articulating Raspberry Pi Camera Mount with the Standardized Links and a few more bits & pieces from Printables made this happen:

    Prusa MK4 - RPi camera installed
    Prusa MK4 – RPi camera installed

    The camera will benefit from better lighting, but it has a great view of the proceedings and gets the job done:

    RPi Camera Mount - image
    RPi Camera Mount – image

    The Standardized Link holes clear an M6 bolt, but the Thumb Remix models use M5×25 hex-head screws (the doc says M4) and they work fine. I printed the (turn-able) bolt knobs in blue PETG-CF to distinguish them from the (fixed) nut knobs, which really don’t need knurling.

    The camera ball mount has a threaded socket for the original plastic screws, but the stem isn’t quite thick enough for an M5 insert. Heat-setting an M4 brass insert into the hole and epoxying an M4×25 hex-head screw into one of the Remix knobs worked fine.

    One Snap Fit Cable Management Clip holds the ribbon cable to a link. I think the RPi can fit under the platform inside the MK4 frame, with another clip or two routing the cable below the mount and frame. Adding another layer to the foam foot pads may improve the clearance.

    The mount attaches to the MK4 frame with a 3030 adapter and a 45° link on the top. If I were in the mood, I’d make the 3030 adapter link longer for enough clearance beyond the M4 socket-head cap screws to get a ball-end hex wrench in there.

    The small figure on the platform is a Articulated Grim Reaper done in black and white as an MMU3 test.

    Now I can keep an eye on the proceedings from the Comfy Chair …