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

Making the world a better place, one piece at a time

  • Thing-O-Matic: Heated Build Platform Center Screw

    While I was rebuilding the HPB heater wiring, I drilled / countersunk / tapped a 4-40 hole in the middle of the aluminum sub-plate for a screw to secure the middle of the heater PCB:

    HBP center attachement screw - top
    HBP center attachement screw – top

    Remember: this plate is firmly secured to the plywood build platform with three leveling screws over springs. Another aluminum plate, with Kapton tape as the build surface, sits on top, providing an absolutely flat build platform. If you’re using a single plate, you could backfill the hole with a dab of JB Industro Weld epoxy atop a lightly greased screw, then file the top flush with the plate.

    A flat-head screw harvested from a chunk of electronic junk came from the Drawer o’ Short 4-40 Screws and fit perfectly:

    HBP center attachment screw - bottom
    HBP center attachment screw – bottom

    Mirabile dictu, the screw was short enough that it didn’t require any trimming to stay below the top surface.

    Securing the center of the PCB to the aluminum plate cuts the heater’s free span in half: the PCB originally had screws only along the left and right edges. Its thermal expansion visibly bowed it away from the plate and I hope this will reduce that problem. Of course, now the PCB’s expansion has nowhere to go and those thermal stresses will probably begin chewing up the mounting holes.

    While I was at it, I removed the MBI “heat spreader” tape from the PCB. I’d been reluctant to do that, for fear of peeling the traces right off the board, but the surface was in fine shape. Whew!

    More on the wiring and epoxy blobbed brass tube later…

  • Platform Level Test Pattern

    Unlike that pattern, this OpenSCAD program produces an STL file that gets sliced in the usual manner, so that the end result shows exactly how the first layer of all other objects gets laid down.

    Thread Thickness Test - solid model
    Thread Thickness Test – solid model

    It’s two threads wide and one thread thick: customize the OpenSCAD code to match the settings in Skeinforge (or Slic3r or whatever you’re using) to make it build properly.

    The two tabs mark the +X and +Y directions. The bottom surface will be wonderfully shiny from the build plate, so the symmetry along the diagonal shouldn’t pose a problem.

    Should the thickness vary more-or-less linearly along any of the bars, then you know which way to level the platform. If it varies non-uniformly, then either the build plate isn’t flat or the printer has other problems.

    The actual width depends on the actual thickness, of course: a too-low nozzle will create a too-wide pattern regardless of the extrusion settings. The thickness should be uniform across the entire pattern, so you can still adjust the platform leveling screws.

    If you’re using a Z-minimum platform height sensor, now’s the time to adjust the switch touch-off height to make the thread thickness come out right.

    When the thread thickness comes out right, then the width should match the extrusion settings: the bottom layer will be exactly like all the others. That’s the ideal situation, anyway.

    A thickness snap gauge comes in handy for this sort of thing.

    The OpenSCAD source code:

    // Platform Level test pattern
    // Ed Nisley KE4ZNU - Dec 2011
    
    //-------
    //- Extrusion parameters must match reality!
    
    ThreadThick = 0.25;
    ThreadWidth = 2.0 * ThreadThick;
    
    //-------
    // Dimensions
    
    BoxSize = 80;
    
    //-------
    
    module ShowPegGrid(Space = 10.0,Size = 1.0) {
    
      Range = floor(50 / Space);
      for (x=[-Range:Range])
        for (y=[-Range:Range])
          translate([x*Space,y*Space,Size/2])
            %cube(Size,center=true);
    }
    
    //-------
    
    ShowPegGrid();
    
    for (Index=[0:3])
      rotate(Index*90)
        translate([0,BoxSize/2,ThreadThick/2])
          cube([BoxSize,2*ThreadWidth,ThreadThick],center=true);
    
    for (Index=[-1,1])
      rotate(Index*45)
        translate([0,0,ThreadThick/2])
          cube([sqrt(2)*BoxSize,2*ThreadWidth,ThreadThick],center=true);
    
    translate([BoxSize/2,0,ThreadThick/2])
      cube([BoxSize/6,2*ThreadWidth,ThreadThick],center=true);
    
    translate([0,BoxSize/2,ThreadThick/2])
      rotate(90)
        cube([BoxSize/6,2*ThreadWidth,ThreadThick],center=true);
    
  • Thing-O-Matic: Improved EC Thermistor Connector Orientation

    Given that the SMD pads fell off the HBP circuit board and I must replace the connector, I figured I may as well also replace the remarkably stiff MBI thermistor cable with a much more flexible CD-ROM audio cable. Although the EC end of the MBI cable looks like a standard CD-ROM audio connector, it’s been rewired. No problem: this is not an audio application and I’m going to do exactly the same thing.

    The Extruder Controller, however, doesn’t have a matching connector and the recommended attachment involves simply jamming the connector onto the pin header, per this detail cropped from that photo in the MBI assembly instructions:

    MBI EC HBP Thermistor Connector Alignment - Detail
    MBI EC HBP Thermistor Connector Alignment – Detail

    Here’s a better closeup of my EC, taken from the other side:

    MBI Extruder Controller - HBP thermistor connector
    MBI Extruder Controller – HBP thermistor connector

    The header block breaks out the Arduino’s Analog Input pins, with A6 in the front of that photo. From left to right, the pins under the HBP connector are A6 / +5 V / Gnd. Unfortunately, the connector wiring and alignment puts the thermistor signal on the cable shield, with the Gnd and +5 V wires safely tucked inside. This is, shall we say, suboptimal.

    The Gnd connection provides a low-impedance connection to the least-noisy part of the circuit, so putting it on the shield tends to prevent the relatively high-impedance signals within from picking up noise. This isn’t always successful, for a number of reasons, but it’s a Good Idea.

    Although probably doesn’t make much difference (it’d just add a bit of noise to the HBP temperature signal), but if I’m going to be rewiring it anyway, the cable shield will be at ground potential with the signal  wire inside. Here’s my cable & connector, rearranged to make that so:

    EC HBP thermistor connector - revised
    EC HBP thermistor connector – revised

    The analog audio connector on the back of old-school CD-ROM drives, back before digital audio output from the drives actually worked, had four pins:

    • Left (white) and Right (red) audio channels on the outer pair
    • Ground (black) on at least one of the central pair

    So the red wire will be in the far right-hand socket of the connector shell; depress its locking tab, slide it out of the shell, poke it into the socket between the other two wires, push to click, and you’re set. Conveniently, this puts the +5 V supply on the red wire, which is sorta-kinda standard. Your cable colors may vary; pay attention to the actual wiring and ignore the color code!

    Tape the connector in place (with the empty socket now toward the board edge) to prevent the tangle of wires in the Thing-O-Matic’s electronics bay from dislodging it at an inopportune moment:

    EC HBP thermistor connector - secured
    EC HBP thermistor connector – secured

    Admittedly, that arrangement still tucks the +5V wire right next to the signal wire inside the shield, but it’s a step in the right direction.

    You could flip the MBI cable around, too, as long as you also rearranged the pins at the HBP end to match.

  • Cleaning 3D Printed Recesses

    Having used screwdrivers and other improvised tools to clean out various 3D printed recesses, it finally penetrated my thick consciousness that a boring bar is exactly the right hammer for the job:

    Cleaning screw head recesses with a boring bar
    Cleaning screw head recesses with a boring bar

    In normal use, a boring bar’s head cuts mainly on its end surface, with the side cleaning up the hole’s periphery. Those edges remove droopy threads and Reversal zittage around a hole’s interior; an end mill works better to make the recess uniformly deeper.

    I have a few sets of these things, with larger & smaller cutting ends and longer & shorter shanks, that I occasionally use for lathe boring and rarely for mill boring (in the manual mill, not the Sherline!). The smallest head in the collection is maybe 4 mm across, so there’s a definite lower limit on the size of the hole they’ll clear.

    Hand-held while cutting plastic? They’ll last forever!

    I should probably print up some handles…

  • Planet Bike Superflash: Tour Easy Mount

    Having not yet gotten around to building better taillights for our bikes, we picked up some Planet Bike Superflash lights on sale. I don’t like single-LED lights, because the optics produce a concentrated beam (which is how they get such high lumen ratings) that’s essentially invisible anywhere off-axis; a taillight that requires careful alignment for maximum effect is a Bad Thing. But, eh, they were on sale…

    The graceful OEM seatpost mount, done in engineering plastic with smooth curves and something of a reputation for fragility, doesn’t work on a recumbent, so I build a butt-ugly mount that should last forever. It clamps firmly around a length of grippy silicone tape on the top seat frame rail:

    Superflash on Tour Easy
    Superflash on Tour Easy

    The reviews also complain that normal road vibrations transmitted through the somewhat whippy OEM mount pop the case apart, depositing the lens and electronics on the road behind you. Hence the black tape across the case joint.

    Here’s the whole affair on the bench:

    Superflash on mount
    Superflash on mount

    The weird color line comes from white plastic left in the extruder that covers the bottom layer or two of each part. I’m not fussy about the first pass of any new gadget, because I know I’ll build at least one more to get everything right.

    This is the first build arrangement; note the huge white teardrop blob at the start of the Skirt outline on the left. Obviously I didn’t have the initial retraction under control:

    Superflash mount on build platform
    Superflash mount on build platform

    The screw recesses built over the plate and got cute little support spiders to keep their interiors from sagging:

    Superflash mount - bolt support
    Superflash mount – bolt support

    After doing it that way, I flipped the top piece over so it builds with the screw head recesses upward to get a better finish on those nice curves. That means the arch needs support, which almost worked, although some of the fins fell over:

    Superflash mount - failed arch support
    Superflash mount – failed arch support

    The solid model now adds a two-layer-thick flat plate joining the fins that should hold them firmly to the build plate.

    Clamp Support - Solid Model
    Clamp Support – Solid Model

    I also added an option to build the flash mounting shoe separately:

    Superflash mount - solid model
    Superflash mount – solid model

    That gives better control over the flange thickness, which turns out to be critical parameter requiring a bit of adjustment with a file in the first version. Of course, the shoe needs an alignment pin and another assembly step to glue it in place:

    Superflash mount - gluing shoe
    Superflash mount – gluing shoe

    A 4-40 setscrew jams into the latch recess in the Superflash case, thus preventing it from walking off the shoe. You don’t need any particular pressure here, just enough protrusion to engage the case:

    Superflash mount - setscrew
    Superflash mount – setscrew

    The first pass at hex nut recesses were exactly cos(30) too large, as I forgot my Useful Sizes file has the across-the-points diameter, so I added a dab of epoxy to each recess before gluing the halves together with solvent:

    Superflash mount - glue clamping
    Superflash mount – glue clamping

    And then it’s all good.

    The OpenSCAD source code:

    // Planet Bike Superflash mount for Tour Easy seatback
    // Ed Nisley KE4ZNU - Dec 2011
    
    Layout = "Show";            // Assembly: Show
                                // Parts: Clamp Base Shoe Mount
                                // Build Plate: Build
    
    SeparateShoe = true;        // true = print mounting shoe separately
                                // false = join shoe to Mount block
    
    Support = true;             // true = include support
    
    Gap = 8;                    // between "Show" objects
    
    include </home/ed/Thing-O-Matic/lib/MCAD/units.scad>
    include </home/ed/Thing-O-Matic/Useful Sizes.scad>
    include </home/ed/Thing-O-Matic/lib/visibone_colors.scad>
    
    //-------
    //- Extrusion parameters must match reality!
    //  Print with +1 shells, 3 solid layers, 0.2 infill
    
    ThreadThick = 0.25;
    ThreadWidth = 2.0 * ThreadThick;
    
    HoleFinagle = 0.1;
    HoleFudge = 1.00;
    
    function HoleAdjust(Diameter) = HoleFudge*Diameter + HoleFinagle;
    
    Protrusion = 0.1;           // make holes end cleanly
    
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    function IntegerMultipleMin(Size,Unit) = Unit * floor(Size / Unit);
    
    //-------
    // Dimensions
    
    BarDia = (5/8) * inch;              // seat back rail diameter
    BarRad = BarDia/2;
    
    TapeThick = 0.3;                    // grippy tape around bar
    
    HoleDia = BarDia + 2*TapeThick;     // total hole dia
    HoleRad = HoleDia/2;
    HoleSides = 4*5;
    
    echo("Bar hole dia: ",HoleDia);
    
    TightSpace = 1.0;                   // space for tightening screws
    
    PlateWidth = 20.0;                  // mounting plate across flanges
    PlateLength = 20.0;                 //  ... parallel to flanges
    PlateThick = IntegerMultipleMin(1.96,ThreadThick);          //  ... thickness
    FlangeThick = IntegerMultiple(1.40,ThreadThick);            // lamp flange thickness
    FlangeWidth = 2.0;                  //  ... width
    
    ShoeThick = PlateThick + FlangeThick;    // dingus protruding from main block
    ShoeOffset = 1.0;                   // offset due to end wall
    
    echo("Shoe thickness: ",ShoeThick," = ",PlateThick," + ",FlangeThick);
    
    LockOffset = -5.0;                  // offset of locking setscrew
    
    TopRoundRad = 1.5*Head10_32/2;      // tidy rounding on top edge of clamp
    echo("Top rounding radius: ",TopRoundRad);
    
    NutDia = Nut10_32Dia*cos(30);       // adjust from across-points to across-flats dia
    NutPart = IntegerMultiple(0.5*Nut10_32Thick,ThreadThick);  // part of nut in each half
    
    BoltOffset = HoleRad + max(Head10_32,NutDia);
    BoltClear = Clear10_32;
    BoltHeadDia = Head10_32;
    BoltHeadThick = Head10_32Thick;
    
    MountWidth = PlateLength + ShoeOffset;         // side-to-side
    MountLength = HoleDia + 3.5*max(BoltHeadDia,NutDia);
    
    ClampHeight = TopRoundRad + HoleRad;            // includes gap/2 for simplicity
    BaseHeight = NutPart + HoleRad;                 //  ... likewise
    MountHeight = PlateWidth;
    
    echo("Mount width: ",MountWidth," length: ",MountLength);
    echo("Height of clamp: ",ClampHeight," base: ",BaseHeight," mount: ",MountHeight);
    echo(" total: ",ClampHeight+BaseHeight+MountHeight);
    
    AlignPegDia = 2.9;                  // shoe alignment peg
    AlignPegLength = ShoeThick;
    
    echo("Alignment peg length: ",AlignPegLength);
    
    //-------
    
    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=HoleAdjust(FixDia)/2,h=Height,$fn=Sides);
    }
    
    module ShowPegGrid(Space = 10.0,Size = 1.0) {
    
      Range = floor(50 / Space);
    
        for (x=[-Range:Range])
          for (y=[-Range:Range])
            translate([x*Space,y*Space,Size/2])
              %cube(Size,center=true);
    }
    
    //-------
    // Upper clamp half
    
    module Clamp() {
    
      difference() {
        translate([0,0,-TightSpace/2]) {
          difference() {
            translate([0,0,ClampHeight/2]) {
              intersection() {
                translate([0,0,-TopRoundRad])
                  minkowski() {
                    cube([(MountLength - 2*TopRoundRad),
                          (MountWidth - 2*Protrusion),
                          ClampHeight],center=true);
                    rotate([90,0,0])
                      cylinder(r=TopRoundRad,h=Protrusion,$fn=4*8);
    
                  }
                cube([MountLength,MountWidth,ClampHeight],center=true);
              }
            }
            translate([0,(MountWidth/2 + Protrusion)])
              rotate([90,0,0])
                PolyCyl(HoleDia,(MountWidth + 2*Protrusion),HoleSides);
            for (Index=[-1,1])
              translate([(Index*BoltOffset),0,0]) {
                translate([0,0,-Protrusion])
                  PolyCyl(BoltClear,(ClampHeight + Protrusion));
                translate([0,0,(ClampHeight - BoltHeadThick)])
                  PolyCyl(BoltHeadDia,(BoltHeadThick + Protrusion));
              }
          }
    
        }
        translate([0,0,-TightSpace/2])
          cube([(MountLength + 2*Protrusion),
               (MountWidth + 2*Protrusion),
               TightSpace],center=true);
      }
    
        if (Support)                    // choose support to suit printing orientation
          union() {
            translate([0,0,1.5*ThreadThick])
              cube([0.75*HoleDia,(MountWidth + 2*ThreadWidth),3*ThreadThick],center=true);
            intersection() {
              for (Index=[-3:3])
                translate([0,Index*(MountWidth/6),-TightSpace/2])
                  rotate([90,0,0])
                    cylinder(r=(HoleRad - 0.25*ThreadThick),
                            h=2*ThreadWidth,center=true,$fn=HoleSides);
              translate([-HoleRad,-MountWidth,0])
                cube([HoleDia,2*MountWidth,HoleRad]);
            }
          }
    }
    
    //-------
    // Lower clamp half = base
    
    module Base() {
    
      difference() {
        translate([0,0,-TightSpace/2])
          difference() {
            translate([0,0,BaseHeight/2])
              cube([MountLength,MountWidth,BaseHeight],center=true);
            translate([0,(MountWidth/2 + Protrusion)])
              rotate([90,0,0])
                PolyCyl(HoleDia,(MountWidth + 2*Protrusion),HoleSides);
            for (Index=[-1,1])
              translate([(Index*BoltOffset),0,0]) {
                translate([0,0,-Protrusion])
                  PolyCyl(BoltClear,(BaseHeight + Protrusion));
                translate([0,0,(BaseHeight - NutPart)])
                  rotate(30)
                    PolyCyl(NutDia,(NutPart + Protrusion),6);
    //              cylinder(r=NutDia/2,h=(NutPart + Protrusion),$fn=6);
              }
          }
        translate([0,0,-TightSpace/2])
          cube([(MountLength + 2*Protrusion),
               (MountWidth + 2*Protrusion),
               TightSpace],center=true);
    
      }
    
      if (Support)
        for (Index=[-1,1])                  // support inside nut openings
          translate([(Index*BoltOffset),
                    0,
                    (BaseHeight - (NutPart - ThreadThick) - TightSpace/2)]) {
            translate([0,0,0])
              for (Seg=[0:5]) {
                rotate(30 + 360*Seg/6)
                  cube([NutDia/2,2*ThreadWidth,NutPart - ThreadThick],center=false);
              }
          }
    
    }
    
    //-------
    // Superflash mounting shoe
    // Offset by -ShoeOffset/2 in Y to align on Mount (half of total offset on each side)
    
    module Shoe() {
    
        difference() {
          translate([-ShoeThick/2,-ShoeOffset/2,PlateWidth/2])
            if (SeparateShoe)
              cube([ShoeThick,PlateLength,PlateWidth],center=true);
            else
              cube([(ShoeThick + Protrusion),PlateLength,PlateWidth],center=true);
    
          translate([-(FlangeThick - Protrusion),
                    -(PlateLength/2 + ShoeOffset/2 + Protrusion),
                    (MountHeight - FlangeWidth)])
            cube([FlangeThick,(PlateLength + 2*Protrusion),(FlangeWidth + Protrusion)]);
    
          translate([-(FlangeThick - Protrusion),
                    -(PlateLength/2 + ShoeOffset/2 + Protrusion),
                    -Protrusion])
            cube([FlangeThick,(PlateLength + 2*Protrusion),(FlangeWidth + Protrusion)]);
    
          translate([-(ShoeThick + Protrusion),LockOffset,MountHeight/2])
            rotate([0,90,0])
              rotate(0)                 // align to match Mount hole orientation
                PolyCyl(Tap4_40,(ShoeThick + 2*Protrusion));
    
          if (SeparateShoe)
            translate([-(ShoeThick - AlignPegLength/2),0,MountHeight/2])
              rotate([0,90,0])
                PolyCyl(AlignPegDia,AlignPegLength);
        }
    }
    
    //-------
    // Bottom block for Superflash mount
    
    module Mount() {
    
      translate([0,0,MountHeight/2])
        union() {
          difference() {
            union() {
              translate([-MountLength/4,0,0])
                cube([MountLength/2,MountWidth,MountHeight],center=true);
              translate([((MountLength/2 - MountHeight)/2 + Protrusion),0,0])
                cube([(MountLength/2 - MountHeight + 2*Protrusion),
                     MountWidth,
                     MountHeight],center=true);
              translate([(MountLength/2 - MountHeight),0,0])
                intersection() {
                  translate([MountLength/4,0,0])
                    cube([MountLength/2,MountWidth,MountHeight],center=true);
                  translate([0,0,MountHeight/2])
                    rotate([90,0,0])
                      cylinder(r=MountHeight,h=MountWidth,center=true,$fn=4*16);
                }
            }
    
            translate([-(MountLength/2 + Protrusion),LockOffset,0])
              rotate([0,90,0])
                rotate(0)       // align through hole sides with point upward
                  PolyCyl(Clear4_40,(MountLength + 2*Protrusion));
    
            for (Index=[-1,1])
              translate([(Index*BoltOffset),0,0]) {
                translate([0,0,BaseHeight/2])
                  PolyCyl(BoltClear,(BaseHeight/2 + Protrusion));
                translate([0,0,(BaseHeight - NutPart)])
                  rotate(30)
                    PolyCyl(NutDia,(NutPart + Protrusion),6);
              }
    
            if (SeparateShoe)
              translate([-(MountLength/2 + AlignPegLength/2),0,0])
                rotate([0,90,0])
                  PolyCyl(AlignPegDia,AlignPegLength);
          }
    
          if (Support)
            for (Index=[-1,1])            // support inside nut openings
              translate([(Index*BoltOffset),0,(MountHeight/2 - (NutPart - ThreadThick))]) {
                translate([0,0,0])
                  for (Seg=[0:5]) {
                    rotate(30 + 360*Seg/6)
                      cube([NutDia/2,
                          2*ThreadWidth,
                          (NutPart - ThreadThick)],center=false);
                  }
              }
    
          if (!SeparateShoe)
            translate([-MountLength/2,0,-MountHeight/2])
              Shoe();
        }
    }
    
    //-------
    
    ShowPegGrid();
    
    if (Layout == "Clamp")
      Clamp();
    
    if (Layout == "Base")
      Base();
    
    if (Layout == "Shoe")
      Shoe();
    
    if (Layout == "Mount")
      Mount();
    
    if (Layout == "Show") {
      translate([0,0,(BaseHeight + MountHeight + Gap)]) {
        translate([0,0,TightSpace/2 + Gap])
          color(MFG) Clamp();
        translate([0,0,-TightSpace/2])
          rotate([180,0,0])
            color(DHC) Base();
      }
      translate([0,0,0])
        color(LDM) render(convexity=3) Mount();
    
      if (SeparateShoe)
        translate([-(MountLength/2 + Gap),0,0])
          color(DDM) Shoe();
    }
    
    if (Layout == "Build") {
      translate([-15,30,(BaseHeight - TightSpace/2)]) rotate([180,0,0])
        Base();
      translate([-15,00,0]) rotate([0,0,0])
        Clamp();
      if (SeparateShoe)
        translate([20,30,ShoeThick]) rotate([0,-90,180])
          Shoe();
      if (SeparateShoe)
        translate([-15,-30,MountHeight]) rotate([180,0,180])
          Mount();
      else
        translate([-15,-40,MountWidth/2]) rotate([90,0,180])
          Mount();
    
    }
    

    The original doodles, done on a retina-burning yellow scratchpad:

    Superflash Mount Doodles
    Superflash Mount Doodles
  • Acceleration Doodles

    The SJFW firmware applies acceleration limiting to motion along all four axes, so I did some doodling to come up with reasonable starting values, based on various measurements and estimates.

    Some useful background, with lots more tucked away in odd corners around here:

    Relevant equations for uniform linear acceleration a, velocity v, distance x, time t:

    • v2 – v02 = 2·a·x
    • x = (1/2)·a·t2

    X and Y Axes

    Current values with low-resistance / low-inductance steppers:

    • Decent printing at 30 mm/s = 1800 mm/min
    • Not-so-good printing at 60 mm/s = 3600 mm/min
    • Point-to-point non-printing motion at 100 mm/s

    Given that the (beefed up) XY motors can accelerate their respective stages to 100 mm/s without acceleration, assume they can reach a top speed of 200 to maybe 250 mm/s within 1 mm of travel. That’s half of the belt pitch and seems like an overestimate of the actual distance.

    • (250 mm/s)2 = 2·a·(1 mm) → a = 31000 mm/s2
    • (200 mm/s)2 = 2·a·(1 mm) → a = 20000 mm/s2

    The 1 kg Y axis probably can’t accelerate as fast as the 0.4 kg X, despite having a bigger motor.

    Z Axis

    Currently traverses at 17 mm/s = 1000 mm/min, OK at 25 mm/s, fails at 33 mm/s = 2000 mm/min. That’s with the original high-resistance / high-inductance MBI stepper without acceleration limiting.

    Typical motion will be 0.25 mm, which is 15 ms at 17 mm/s: it’s not a performance limitation.

    It’s a 4-start leadscrew that moves 8 mm/rev, so 0.25 mm = 0.031 rev. At 1/8 stepping = 1600 step/rev, that’s 50 steps. Allow 20 steps = 0.1 mm for acceleration to top speed:

    • (33 mm/s)2 = 2·a·(0.1 mm) → a = 5400 mm/s2
    • (17 mm/s)2 = 2·a·(0.1 mm) → a = 1400 mm/s2

    E Axis

    Currently runs at about 2 rev/min = 0.033 rev/s with a 9.6 mm effective drive diameter = 1 mm/s for the incoming filament. Reversal runs at 15 to 25 rev/min for about 100 ms, figure 20 rev/min = 0.33 rev/s = 10 mm/s, without acceleration limiting. The extruder has 7:51 geardown, so the motor runs at 14.6 rev/min and reverses at 146 rev/min = 2.4 rev/s = 500 step/s, none of which seems particularly challenging even in 1/1 step mode (due to using a defunct MBI stepper driver).

    That reversal speed tends to leave blobs at the end of threads, but it’s not clear the motor is up to much more acceleration. It’s a relatively small stepper, so a larger one with with more current may be needed for enough torque for faster reversal action.

    Allowing 0.1 mm to reach full speed:

    • (1 mm/s)2 = 2·a·(0.1 mm) → a = 5 mm/s2
    • (10 mm/s)2 = 2·a·(0.1 mm) → a = 500 mm/s2

    None of these numbers should be cast in stone!

    The original doodles:

    TOM286 Calibration Doodles
    TOM286 Calibration Doodles
  • Thing-O-Matic: Filament Melt Zone

    The 0.5 mm nozzle came off the hot end with surprisingly little effort; the high-temperature lube did its job! I dismantled the tensioner, clipped the filament at the top of the drive wheel, and extracted it (with the red PTFE insulation / guide tube) through the bottom of the Thermal Core. Getting the filament out of the tube required the gentle suasion of a pin punch, but eventually I found this:

    Filament melt zone - overview
    Filament melt zone – overview

    Although you can’t tell from the picture, the filament seems completely melted for about 20 mm, well-softened for another 20 mm, and soft for about 10 mm. Here’s a detail of the transition from well-softened to soft to hard:

    Filament melt zone - detail
    Filament melt zone – detail

    Notice how the notches from the drive wheel gradually fade out over about 10 mm, whereupon the filament expands to fill the PTFE tube. You can’t see the shallow depression from an air pocket offscreen at about 30 mm, but it suggests the filament isn’t quite molten from 20 mm onward. Given that the distance from the nozzle tip to the top of the Thermal Core is about 40 mm, all this makes sense, particularly when you figure the filament was stationary as the Core cooled off after the last print: the melted-to-melty sections are inside the Core and the softened section is just above the Core.

    In round numbers, the Thermal Core supplies enough heat through the PTFE tube to fully melt the filament for about 20 mm above the nozzle when printing at 2 rev/min. The effective drive diameter is 9.6 mm, so 1 rev = 9.6 π = 30 mm and the Core must melt 60 mm/min = 1 mm/s. This is obviously a grossly nonlinear situation, but if you get only 20 mm of molten filament at 1 mm/s, the maximum speed can’t be much more than 4 mm/s or so.

    The rest of the Thing-O-Matic’s mechanics set an upper limit for, say, printed octopi at 80 mm/s and 4 rev/min = 2 mm/s, but the extruder will definitely be the limiting factor for speeds over, say, 150 mm/s. Not much risk of that happening here, I’d say.

    I’ve settled on Reversal for 125 ms at 25 rev/min, so the retraction distance is:

    1.6 mm = (30 mm/rev) (0.125 s) (25 rev/min) / (60 s/min)

    That’s somewhat smaller than the 3 mm of pushback I’ve seen when swapping filaments in mid-print, but it’s in the right ballpark.

    Now, to install the 0.4 mm nozzle and recalibrate the software yet again…