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

  • Thing-O-Matic: Skeinforge Reversal Failure

    As it turned out, though, that part wasn’t the first attempt.

    Caliper part - heavy blobbing
    Caliper part – heavy blobbing

    Even switching to red filament didn’t help:

    Extrusion blob - top view
    Extrusion blob – top view

    That, in fact, was when the light dawned: it always failed at exactly the same point for a given set of G-Code.

    Come to find out that, for some parts printed with certain options, the Skeinforge Reversal plugin dependably produces huge blobs of plastic after a move. The extruder reverses properly, the XY stages move, then the extruder starts running forward at the Reversal speed while the XY stages move at whatever rate they’re supposed to for the next thread, producing a prodigious blob.

    Extrusion blob - side view
    Extrusion blob – side view

    Most parts have much more interior than they do exterior and, with any luck, the blobs vanish inside. However, this little bitty thing has no room to hide a blob. Several parts went down the drain, but at least it had a countable number of layers!

    Here’s a sample of the failure:

    G1 X0.0 Y2.11 Z3.3 F708.318
    M108 R25.0       <--- Reversal speed
    M101             <--- Extruder on forward
    G04 P125.0       <--- Reversal pause
    M108 R0.3778     <--- Normal speed (continues forward)
    G1 X0.0 Y2.19 Z3.3 F354.159
    G1 X-0.66 Y2.11 Z3.3 F354.159
    G1 X-0.66 Y2.29 Z3.3 F354.159
    G1 X-1.32 Y2.29 Z3.3 F354.159
    G1 X-1.32 Y2.11 Z3.3 F354.159
    G1 X-1.98 Y2.29 Z3.3 F354.159
    G1 X-2.64 Y2.29 Z3.3 F354.159
    G1 X-2.64 Y-3.4 Z3.3 F354.159
    G1 X-1.98 Y-3.4 Z3.3 F354.159
    M108 R25.0       <--- Reversal speed
    M102             <--- Extruder on reverse
    G04 P125.0       <--- Reversal pause
    M103             <--- Extruder off
    G1 X-3.3 Y2.11 Z3.3 F708.318 <--- move to next thread
    M101             <--- Extruder on forward
    G1 X-3.3 Y2.29 Z3.3 F354.159 <--- BLOB FAIL
    G1 X-3.96 Y2.28 Z3.3 F354.159
    G1 X-3.96 Y2.11 Z3.3 F354.159
    M103             <--- Extruder off
    

    The pcregrep progam (do a sudo apt-get install pcregrep on Ubuntu) can find the blob-causing sequences after you generate the G-Code:

    pcregrep -n -M 'G04.*\nM103\nG1.*\nM101\nG1' Caliper.gcode
    

    You need that program, because ordinary grep only searches within a single line. In this case, the G-Code pattern extends over several lines. The pcre stands for Perl Compatible Regular Expressions and the -M turns on multi-line matching.

    The results look like this:

    905:G04 P125.0
    M103
    G1 X-3.3 Y2.11 Z3.3 F708.318
    M101
    G1 X-3.3 Y2.29 Z3.3 F354.159
    1101:G04 P125.0
    M103
    G1 X-3.3 Y2.13 Z3.96 F651.721
    M101
    G1 X-3.3 Y2.29 Z3.96 F325.861
    

    You can count the number of blobs with the -cl options.

    Having found the blobs, edit the file, jump to the indicated lines, copy the nearest preceding forward extruder move, including the speed setting, and paste it in front of the M101 that starts the extruder. If my sed-fu were stronger, I could automate that process.

    Unleashing pcregrep on my collection of G-Code files shows a bunch of ’em with blobs and a few without. Note that this has nothing to do with the firmware running on the printer, because the G-Code has the error.

    What happens, I think, is that Reversal emits a correct reverse at the end of a thread, does a fast move to the start of the next thread, notices that (at least) the first G1 of the new thread falls below the length threshold that would activate the un-reversal action, and incorrectly assumes that it need not run the extruder forward to restore working pressure. The to-be-printed G1 commands all seem to be very short in the failing G-Code files I’ve examined.

    Setting the reversal threshold to 0.0 should avoid triggering this error. I’ve verified that it produces correct G-Code for two parts that didn’t work before, but that’s not conclusive proof.

    I’ve looked into reversal.py and fixing (heck, finding) this error lies beyond my abilities.

    This is now Issue 175 on the ReplicatorG tracker…

  • Thing-O-Matic: Caliper Repair Perfection

    With only two feet of Barbie Filament left, I ran some Reversal tests leading up to printing another replacement part for that digital caliper. The end result, printed in red ABS, turned out to be perfect:

    Caliper Part - Installed
    Caliper Part – Installed

    Quite literally, I snapped the part off the build platform, lined it up in the caliper, ran that 1-72 screw through it, and It Just Worked. No cleanup, no trimming, no fiddling around, no problems!

    Unlike the previous part, I printed this one as a singleton in the middle of the plate in order to concentrate on the other parameters:

    Finished caliper repair part
    Finished caliper repair part

    I set the Cool plugin to 15 s/layer, which meant the top few layers printed very very slowly and the tip of the hook took forever. That’s fine with me: notice the total lack of overshoot and oscillation, compared with those Companion Cubes printed at much higher speeds.

    Side view:

    Caliper Part - Side
    Caliper Part – Side

    Bottom (the side against the caliper frame) view:

    Caliper Part - Bottom
    Caliper Part – Bottom

    Top view:

    Caliper Part - Top
    Caliper Part – Top

    The fill orientation is 0° for the first layer with 90° rotation, which lines it up neatly with the sides. There’s not enough room for anything fancy; the interior layers came out nearly solid even with the usual 0.25 fill ratio for the hex shapes.

    The fill isn’t quite as solid as you might like, but given the overall size & shape, I think it’s just about as good as it can be expected.

    Isn’t that just the cutest little thing you’ve ever seen?

    The OpenSCAD code that built it:

    // Digital Caliper thumbwheel holder
    // Ed Nisley - KE4ZNU - May 2011
    
    Build = true;						// set true to generate buildable layout
    
    $fn = 8;							// default for holes
    
    // Extrusion values
    // Use 0 extra shells
    //     2 solid shells on the top & bottom
    
    ThreadThickness = 0.33;
    ThreadWT = 2.00;
    ThreadWidth = ThreadThickness * ThreadWT;
    
    HoleWindage = 0.0;					// enlarge hole dia by small Finagle Constant
    
    Protrusion = 0.1;					// extend holes beyond surfaces for visibility
    
    // Caliper dimensions
    
    WheelDia = 10.0;					// thumbwheel OD
    WheelRadius = WheelDia/2;
    WheelMargin = 1.5;					// space around wheel
    WheelRimThick = 2.5;				// subtract from repair block
    
    ShaftDia = 2.90;					// axle between knurled wheels
    ShaftRadius = ShaftDia/2;
    ShaftLength = 2.7;
    ShaftRetainer = 3.0;				// thickness around shaft
    
    StubThick = 2.45;					// stub of holder on caliper head
    StubLength = 6.0;					// toward caliper head
    StubHeight = 7.0;					// perpendicular to caliper head
    StubClearanceX = 0.0;				// distance to caliper head
    StubClearanceZ = 0.75;				// distance to caliper frame
    
    FrameLength = 50;					// for display only
    FrameHeight = 16.0;
    FrameThick = 3.0;
    
    // Repart part dimensions
    
    ForkLength = StubLength - StubClearanceX;	// toward caliper head around stub
    ForkHeight = StubHeight;			// perpendicular to caliper head
    ForkGap = 0.3;						// clearance to stub on all sides
    ForkBladeThick = 3 * ThreadWidth;	// on each side of stub
    
    ShaftClearance = 0.1;				// Additional clearance around shaft
    ShaftOffset = 8.5;					// Shaft center to stub
    
    BoltHoleDia = 1.8;					// 1-72 machine screw, more or less
    BoltHoleRadius = BoltHoleDia/2;
    BoltHoleOffset = 3.5;				// offset from caliper frame to hole center
    
    // Convenient sizes and shapes
    
    FrameBlock = [FrameLength,FrameThick,FrameHeight];
    
    StubBlock = [StubLength,StubThick,StubHeight];
    StubMargin = [ForkGap,2*ForkGap,ForkGap];
    
    RepairBlockLength = ForkLength + ShaftOffset;
    RepairBlockThick = 2*ForkBladeThick + StubThick;
    RepairBlockHeight = WheelRadius + ShaftRadius + ShaftRetainer;
    
    RepairBlock = [RepairBlockLength,RepairBlockThick,RepairBlockHeight];
    
    // Caliper parts to show how repair fits in
    
    module CaliperParts() {
      union() {
    	translate([0,0,-(StubClearanceZ + FrameHeight/2)])
    	  cube(FrameBlock,center=true);
    	translate([-(StubLength/2 + ShaftOffset),0,(StubHeight/2)])
    	  cube(StubBlock,center=true);
      }
    }
    
    // Repair block with origin below wheel shaft
    
    module RepairPart() {
    
      difference() {
    
    // Body of repair part
    	union() {
    	  translate([-RepairBlockLength/2,0,RepairBlockHeight/2])
    		cube(RepairBlock,center=true);
    	  translate([0,0,WheelRadius])
    		rotate([90,0,0])
    		  cylinder(r=ShaftRadius+ShaftRetainer,h=ShaftLength,center=true,$fn=12);
    	}
    
    // wheels
    	translate([0,(ShaftLength + WheelRimThick)/2,WheelRadius])
    	  rotate([90,0,0])
    		cylinder(r=(WheelRadius + WheelMargin),h=WheelRimThick,center=true,$fn=16);
    	translate([-(WheelRadius + WheelMargin)/2,
    			  (ShaftLength + WheelRimThick)/2,
    			  (WheelRadius - Protrusion)/2])
    	  cube([(WheelRadius + WheelMargin),WheelRimThick,(WheelRadius + Protrusion)],
    			center=true);
    	translate([0,-(ShaftLength + WheelRimThick)/2,WheelRadius])
    	  rotate([90,0,0])
    		cylinder(r=(WheelRadius + WheelMargin),h=WheelRimThick,center=true,$fn=16);
    	translate([-(WheelRadius + WheelMargin)/2,
    			  -(ShaftLength + WheelRimThick)/2,
    			  (WheelRadius - Protrusion)/2])
    	  cube([(WheelRadius + WheelMargin),WheelRimThick,(WheelRadius + Protrusion)],
    			center=true);
    
    // axle clearance
    	translate([0,0,WheelRadius])
    	  rotate([90,0,0])
    		cylinder(r=(ShaftRadius + 2*ShaftClearance),	// hack clearance to match octagon to cube
    				 h=(ShaftLength + 2*Protrusion),
    				 center=true);
    	translate([0,0,(WheelRadius - Protrusion)/2])
    	  cube([(ShaftDia + 2*ShaftClearance),
    		    (ShaftLength + 2*Protrusion),
    		    (WheelRadius + Protrusion)],
    		    center=true);
    
    // stub of previous wheel holder
    	translate([-(ShaftOffset + (ForkLength - ForkGap)/2 + Protrusion),
    			  0,
    			  (StubHeight + ForkGap - Protrusion)/2])
    	  cube([(ForkLength + ForkGap + Protrusion),
    		   (StubThick + 2*ForkGap),
    		   (StubHeight + ForkGap + Protrusion)],
    		   center=true);
    
    // mounting screw hole
    	translate([-(RepairBlockLength - BoltHoleOffset),0,StubHeight/2])
    	  rotate([90,0,0])
    		cylinder(r=(BoltHoleDia + HoleWindage)/2,
    				 h=(RepairBlockThick + 2*Protrusion),
    				 center=true,$fn=6);
      }
    }
    
    // Build it!
    
    if (!Build) {
      CaliperParts();
      RepairPart();
    }
    
    if (Build) {
      translate([-RepairBlockLength/2,0,RepairBlockHeight])
    	rotate([0,180,0])
    	  RepairPart();
    }
    
  • Thing-O-Matic: Companion Cube Print Quality vs. Speed

    Companion Cubes* being nice handouts, at least in certain circles, I printed three arrays of nine. This being an opportunity for Science, they’re printed at 25, 40, and 50 mm/s, all with 100 mm/s moves.

    Cube array - 25-100
    Cube array – 25-100

    They’re scaled to about 16 mm on a side, making them about as small as anything you’d want to print. With a 0.66 mm extrusion width (0.33 mm thick and 2.0 w/t, they’re only 24 threads wide, which doesn’t allow for much detail. Here’s the top of one printed at 25 mm/s:

    Cube top - 25
    Cube top – 25

    And at 50 mm/s:

    Cube top - 50
    Cube top – 50

    Obviously, the faster cube turned out uglier. The 40 mm/s cubes look a whole lot like the 50 mm/s ones, which means the best printing quality occurs well below that.

    The front at 25 mm/s:

    Cube front - 25
    Cube front – 25

    And at 50 mm/s:

    Cube front - 50
    Cube front – 50

    The odd shadows on either side of the central bump become more obvious at an oblique angle. At 25 mm/s:

    Cube front oblique - 25
    Cube front oblique – 25

    And at 50 mm/s:

    Cube front oblique - 50
    Cube front oblique – 50

    This confirms a suspicion I’ve had for a while that the XY stages don’t have the positioning accuracy required for this level of detail when printing at any reasonable speed: they tend to oscillate slightly after changing position. I think acceleration limiting would help this, but I have no way to prove that. I know a more rigid mechanical assembly would help a lot, but there’s no way to get there from here.

    Obviously, slowing down will improve the overall quality. I’m printing at high speeds to see what goes wrong; I have no objection to reducing the speed to a crawl in order to wring the best quality out of the hardware.

    Moving at 100 mm/s, however, definitely reduces the opportunity for ooze. Even with Reversal, sometimes the nozzle dribbles a bit and very fast moves tend to produce a hair-fine thread that’s easily removed from the finished object. In this case, all three sets of nine cubes printed with no threads at all.

    These were printed with Reversal set to 25 rev/min, 110 ms in and out, and no early motion. That eliminates suck-out as the extruder reverses while the nozzle approaches the end of the thread, but still leaves a zit at the endpoint where the nozzle moves to the start of the next thread:

    Cube rear oblique - 25
    Cube rear oblique – 25

    The zits appear identical with faster print speeds, so they don’t depend on anything other than Reversal.

    The other two sides of each cube look about the same.

    For completeness, here’s the bottom at 50 mm/s:

    Cube bottom - 50
    Cube bottom – 50

    Comparing that with the top suggests that Skeinforge used bridging fill, rather than surface fill.

    (*) They’re actually Weighted Storage Cubes, as they lack the hearts found on Companion Cubes. My Shop Assistant asserts that if you cuddle them enough, they’ll grow hearts…

  • Thing-O-Matic: LED Lighting Upgrade

    Another one of those LED ring lights wound up in the Thing-O-Matic, affixed to the underside of the Z stage with double-sticky foam tape. You can see the whole ring reflected in that picture, but the front third of the ring obscured what the nozzle was doing.

    So I sawed out one of the three-LED strings to open a gap:

    LED ring light with gap
    LED ring light with gap

    Unfortunately, the designers arranged things so that the ballast resistor for each string sits directly above the last LED of the adjacent string. The white wire you can barely see connects the ballast resistor that drove the now-missing string on the left to the via feeding the first string on the right.

    It now fits around the extruder with the gap exactly matching the opening in front of the Thermal Core.

    LED ring light installed
    LED ring light installed

    Power comes from a screw terminal connector I hacked into the 4-pin block that used to be part of the 20+4-pin ATX power block at the Motherboard. There’s a length of overly stout 4-wire cable leading to a kludged not-a-connector made of square pins and heatshrink tubing jammed into the block.

    TOM auxiliary power connector
    TOM auxiliary power connector

    It provides +12, +5, +3.3 V, and ground for the fan and LED lighting.

    Most of the light in that last picture comes from LED strips on either side of the front opening. My Shop Assistant won a meter of warm-white LEDs at the 3rd Ward Make-a-Thon [Update: dead link. Try their pix from the event.] and graciously allowed me to chop off two 6-LED  strips for a good cause.

  • Thing-O-Matic: Replacing the Air Filter

    So I’d installed an activated charcoal air filter to cut down the hot-ABS stink and it’s been doing fine. Of late, however, I’ve noticed more smell, so I figured it was time to replace the filter…

    Dusty TOM carbon air filter
    Dusty TOM carbon air filter

    Guess I gotta vacuum the floor again this decade…

  • Thing-O-Matic: Platform Height Consistency vs. Build Plates

    After building a bunch of stuff (about which more later), the Skirt extrusions showed a consistent tilt of about 0.1 mm downward to the right and the Skirt along the that side was consistently around 0.42 mm thick. So I cranked the right side down by 0.10 mm (just over 1/6 turn) and changed the G92 setting to Z1.50 to move the plate up by 0.05 mm.

    Three test extrusions in quick succession gave these results (in multiples of 0.01 mm). I used the plates in reverse numerical sequence due to an accident of history:

    Plate 3 36 31
    38 34 35 31
    36 38 36 34
    33 37
    Plate 2 37 33
    40 36 41 34
    37 37 36 37
    34 36
    Plate 1 33 31
    35 32 35 33
    33 33 33 36
    31 34

    It just won’t get any better than that!

  • Thing-O-Matic: Z Axis Resolution / Repeatability / Backlash

    The three Skirt extrusions around those polyhole test plates had thicknesses that looked like this (in the usual units of 0.01 mm):

    28 33
    24 38
    29 34

    Average: 0.31 mm

    34 35
    30 41
    34 37

    Average: 0.35 mm

    36 37
    32 40
    35 38

    Average: 0.36 mm

    In round numbers the extrusions all fall within ±0.05 mm of their average (for a loose definition of average, of course) and the test pieces built just fine. The layer thickness is slightly over the desired 0.33 mm, but sheesh the Z-min switch gets it close enough.

    [Update: following tweaked to match reality. The motor steps are 0.005 mm, but the conclusion remains.]

    However, the Z axis motor drives a four-start leadscrew that moves the Z stage and the thingomatic.xml file specifies 200 step/mm = 0.005 mm/step. As a result, the Z axis positions occur in discrete steps (no surprise there) and the first extrusion happened ten-ish motor steps higher than the other two: 0.31 mm vs 0.35-ish.

    Other folks use layer thicknesses below 0.30 mm and I think they’ll start to see the effect of Z axis resolution and consistency on build quality. Putting the height adjustment on the build platform means you can set the initial nozzle height above the platform very precisely (no steps on the screw-and-spring adjusters), but the height will continue to vary due to all the usual effects. The Z-min switch can adjust the Z stage height only in integral motor steps that may not be precise enough.

    That means the actual extrusion thickness will vary by ±0.005 mm depending on where the Z-min switch trips with respect to the motor steps. Because the nozzle-to-plate distance varies smoothly with temperature / time / sag / whatever, you’ll see steps of that size no matter how much you twiddle the initial platform height.

    For example, if you adjust the build plate height (using the platform screws) to set the nozzle at 0.00 mm for a commanded Z=0.000, the next possible Z stage positions are 0.005 mm above and below that level: the Z-min switch cannot adjust the platform with better resolution. The possible ±0.005 mm variation represents ±2% of a 0.25 mm layer thickness (it’s 1.5% of the 0.33 mm I use).

    Using a 1/16 microstepping driver (and a better Z-axis motor!) would cut the nominal resolution to 0.0025 mm, but I think there’s no way to improve the actual resolution and precision given the present mechanical design. In short: you can make the steps smaller, but that doesn’t mean the Z stage will actually pay attention.

    There’s also backlash: the Z-min switch sets the height as the stage moves down and the nozzle moves down to the first layer, but the second layer thickness depends on the stage moving up by a precise distance. I now think some of the surface finish problem with the three-layer polyholes test pieces came from the second layer being a bit thinner than it should be: the Z stage didn’t really move up by the full 0.33 mm due to backlash and there’s more plastic than room to put it.

    A backlash compensation setting lies buried somewhere in RepG/SF, but I don’t have any measurements to justify anything other than zero. I think the entire Z stage assembly lacks the rigidity for motion on this scale, anyway, and the XY stages flop around more than that, too.

    Building a machine tool with positioning accuracy / repeatability / stability below 0.1 mm is an exceedingly non-trivial project; getting that much resolution is no big deal. The Thing-O-Matic works just fine, but smaller nozzles and thinner layers require more attention to the mechanical design. Achieving tighter tolerances with plywood and acrylic probably isn’t feasible, but anything else will drive the cost up far too much.

    It’s an interesting set of tradeoffs…

    FWIW, I picked 0.33 mm to get a (nearly) integral number of layers per millimeter of object height; I tend to build things using hard-metric sizes and that seemed reasonable. It’s now obvious that the actual heights will be in multiples of 0.005 mm, which doesn’t really matter at all in absolute terms. I should probably use 0.30 mm to make the answers come out easy.