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
This represents the first pass at un-constraining the X stage, so the poor little X axis stepper motor doesn’t have such a hard time of it and we can all get out of the sand-the-plywood-to-fit mindset. The Y stage has a similar mechanism, albeit with three bearings on the rod.
As seen from the front, the rear guide rod constrains the X stage in roll and yaw, while this Follower constrains pitch. The bearings turn in X, slide very slightly as needed in Y, and prevent motion in Z. Slight angle and distance mismatches between the rods no longer matter; I think the as-built (pre-sanding) rods will be sufficiently parallel for all practical purposes.
I have yet to install this, as I have a few other thing to do before tearing the entire XY assembly apart again; this is just a see-if-it-fits prototype:
Prototype X Axis rod follower
The front view:
X Axis follower – model front view
I wanted to mount it on the rear face of the X stage Idler plate, but there’s simply not enough room between the rod and the plywood Idler plate. Indeed, this version may be slightly too chubby for the space available in front of the Drive plate.
The OpenSCAD code produces a recess that clamps the belt into the drive serrations; the prototype doesn’t have that. The rear view shows the recess; I don’t know if that will build successfully. The dimple just below the top bearing bolt hole fits around the nut holding the build platform in place.
X Axis follower – model rear view
My Little Box o’ Tiny Bearings disgorged a pair of hard-inch bearings, but something along the lines of a 603 or 693 bearing would be better. Having shields on both sides would be a nice touch. The recently expanded table there gives some useful bearing dimensions.
The M3x12 bolts on the bearings cut their own threads on the way into the slightly undersized holes. I think that will be adequate, but you could sink nuts into the back.
The OpenSCAD source code will should auto-size the Follower around the bearings and your own measured / guesstimated clearances. Obviously, smaller bearings are better and there’s precious little clearance to the Y stage even with 3/8 inch OD bearings.
Make sure the extrusion settings near the top match your actual build values and that both collections match what the printer actually produces, because there’s not much room around the features for fill.
The top fits flush underneath the HBP stage to maintain proper alignment. That’s not really necessary, given the four bolts holding the Follower to the Drive plate, but there it is.
The Preload value adjusts the Z position of the lower bearing: + up, – down. It’s at zero for the prototype and the as-built Follower has 0.16 mm of preload: the bearings are 0.16 mm too close together. I think that’s OK, although I might dial it back a little bit by setting Preload=-0.1. For all I know, it’ll relax to fit and eventually wind up being marginally rattly.
The Build value at the top controls whether the model has the rods & bearings to show how it fits together (as above) or just the Follower block laid on its back for exporting to the STL file.
The OpenSCAD source:
// Thing-O-Matic X Stage rear guide rod follower
// Ed Nisley - KE4ZNU - Mar 2011
include </home/ed/Thing-O-Matic/lib/MCAD/units.scad>
Build = false; // set true to generate buildable layout
$fn = 8; // default for holes
// Extrusion values
// Use 2 extra shells behind the perimeter
// ... and 3 solid shells on the top & bottom
ThreadThickness = 0.33;
ThreadWT = 1.75;
ThreadWidth = ThreadThickness * ThreadWT;
HoleWindage = ThreadWidth; // enlarge hole dia by extrusion width
Protrusion = 0.1; // extend holes beyond surfaces for visibility
// Bearing dimensions
BearingOD = (3/8) * inch; // I used a hard-inch bearing -- try a 603 or 693
BearingID = (1/8) * inch;
BearingThick = (5/32) * inch;
BearingBoltDia = 3.0; // allow this to shrink: drill & tap the threads!
BearingBoltRadius = BearingBoltDia/2;
BearingStemOD = BearingBoltDia + 6*ThreadWidth;
BearingStemRadius = BearingStemOD/2;
BearingStemLength = 2.0;
// X guide rod dimensions
RodDia = (3/8) * inch; // hard inch rod
RodRadius = RodDia/2;
RodLength = 75; // for display convenience
RodClearTop = 12.6; // clearance from HBP to rod
RodClearSide = 9.0; // ... idler to rod
RodClearBottom = 10.7; // ... rod to Y stage
RodClearCirc = 1.5; // ... around circumference
// Drive mounting piece (from ABP teardown)
DriveHolesX = 16.0; // on-center distance
DriveHolesZ = 9.0; // on-center distance
DriveHoleZOffset = -5.0; // below bottom of HBP platform
DriveHeight = 28.0;
DriveBoltDia = 3.0 + HoleWindage; // bolt dia to hold follower in place
DriveBoltRadius = DriveBoltDia/2;
DriveBoltHeadDia = 6.0 + HoleWindage;
DriveBoltHeadRadius = DriveBoltHeadDia/2;
DriveBoltWeb = 4.5; // leave this on block for 12 mm bolts
HBPNutDia = 4.0; // HBP mounting nut in middle of idler
HBPNutRadius = HBPNutDia/2;
HBPNutRecess = 0.5; // ... pocket for corner of nut
HBPNutZOffset = -10.0; // ... below bottom of HBP platform
BeltWidth = 7.0; // drive belt slots
BeltThick = 1.2; // ... backing only, without teeth
BeltZOffset = -22.5; // ... below bottom of HBP platform
// Bearing locations
Preload = 0.0; // positive to add pressure on lower bearing
TopZ = RodRadius + BearingOD/2;
BottomZ = Preload - TopZ;
// Follower dimensions
BlockWidth = 28.0; // along X axis, must clear bolts in idler
BlockHeight = RodDia + 2*BearingOD - Preload;
BlockThick = (RodClearSide + RodRadius) - BearingThick/2 - BearingStemLength;
BlockHeightPad = RodClearTop - BearingOD;
echo(str("Block Height: ",BlockHeight));
echo(str("Block Height Pad: ",BlockHeightPad));
echo(str("Block Thick: ",BlockThick));
BottomPlateWidth = 10.0;
BottomPlateThick = 5.0;
BlockTop = RodRadius + RodClearTop;
BlockOffset = BlockThick/2 + BearingThick/2 + BearingStemLength;
// Construct the follower block with
module Follower() {
difference() {
union() {
translate([0,BlockOffset,0])
difference() {
union(){
cube([BlockWidth,BlockThick,BlockHeight],center=true);
translate([0,0,(BlockHeight + BlockHeightPad)/2])
cube([BlockWidth,BlockThick,BlockHeightPad],center=true);
}
for(x=[-1,1]) for(z=[0,1])
translate([x*DriveHolesX/2,
Protrusion/2,
(BlockHeight/2 + BlockHeightPad + DriveHoleZOffset - z*DriveHolesZ)])
rotate([90,0,0])
cylinder(r=DriveBoltRadius,
h=(BlockThick + Protrusion),
center=true);
for(x=[-1,1]) for(z=[0,1])
translate([x*DriveHolesX/2,
(-(DriveBoltWeb + Protrusion)/2),
(BlockHeight/2 + BlockHeightPad + DriveHoleZOffset - z*DriveHolesZ)])
rotate([90,0,0])
cylinder(r=DriveBoltHeadRadius,
h=(BlockThick - DriveBoltWeb + Protrusion),
center=true);
translate([0,
((BlockThick - BeltThick + Protrusion)/2),
(BlockHeight/2 + BlockHeightPad + BeltZOffset)])
cube([(BlockWidth + 2*Protrusion),
(BeltThick + Protrusion),
BeltWidth],center=true);
}
translate([0,BearingStemLength/2 + BearingThick/2,TopZ])
rotate([90,0,0])
cylinder(r=BearingStemRadius,h=BearingStemLength,center=true,$fn=10);
translate([0,BearingStemLength/2 + BearingThick/2,BottomZ])
rotate([90,0,0])
cylinder(r=BearingStemRadius,h=BearingStemLength,center=true,$fn=10);
}
translate([0,(BlockOffset - BearingStemLength/2),TopZ])
rotate([90,0,0])
cylinder(r=BearingBoltRadius,
h=(BlockThick + BearingStemLength + 2*Protrusion),
center=true);
translate([0,(BlockOffset - BearingStemLength/2),BottomZ])
rotate([90,0,0])
cylinder(r=BearingBoltRadius,
h=(BlockThick + BearingStemLength + 2*Protrusion),
center=true);
translate([0,
(BlockThick + BearingStemLength + BearingThick/2 - (HBPNutRecess - Protrusion)/2),
(BlockHeightPad + BlockHeight/2 + HBPNutZOffset)])
rotate([90,0,0])
cylinder(r=HBPNutRadius,h=(HBPNutRecess + Protrusion),center=true);
rotate([0,90,0])
cylinder(r=(RodRadius + RodClearCirc),h=RodLength,center=true,$fn=32);
}
}
// Arrange things for construction
if (Build)
translate([0,(-BlockHeightPad/2),(BlockOffset + BlockThick/2)])
rotate([-90,0,0])
Follower();
// Arrange things for convenient inspection
if (!Build) {
Follower();
translate([0,0,TopZ])
rotate([90,0,0])
#cylinder(r=BearingOD/2,h=BearingThick,center=true,$fn=32);
translate([0,0,BottomZ])
rotate([90,0,0])
#cylinder(r=BearingOD/2,h=BearingThick,center=true,$fn=32);
rotate([0,90,0])
#cylinder(r=RodDia/2,h=RodLength,center=true,$fn=32);
}
Having salvaged the sliding bearings from the ABP, I built up the HBP, stuck it into the Thing-O-Matic, and wasn’t in the least surprised to discover that it was mechanically jammed solid on the rods. This time, however, I wanted to measure the actual rod (mis)alignment to see what was going on.
Remember that, as described there, the X stage overconstrains the rods by forcing them through four bearings. It would be much better to use a pair of sliding bearings on one rod and a set of ball bearings rolling on the other, much as MBI did with the Y stage. Something involving 603 or 693 bearings, perhaps… there’s a scant 12 mm clearance from the top of the rod to the bottom of the HBP.
So I laid it upside down on the surface plate and tickled it with a scribe mounted in a surface gage. Of course, I’m doing it all wrong, but the results are close enough. What you can’t see are the two half-inch chrome-steel lathe bits supporting the platform; it may be warped a bit, but that’s part of what’s being measured.
Measuring HBP rod misalignment
I adjusted the scribe to just kiss the slip of waxed paper (0.02 mm) atop each end of each rod, which turns out to be surprisingly easy to do by feel.
Measuring rod height
Then eyeball the result on a scale.
Rod height on scale
One should tweak the surface gage until a dial test indicator reads zero, then stack up gage blocks to the same height. I actually hauled out my box o’ blocks before I came to my senses.
Anyhow.
The far rod was spot-on level and the front rod was off by 1 mm from one end to the other. They were within 0.2 mm of equal spacing horizontally, which was somewhat surprising given the amount of side sanding required to fit the ABP into Y stage.
Height
Right
Center
Left
Back
42.6
42.7
42.7
Front
43.5
43
42.5
Separation
39.93
39.72
I sanded out one of the holes, laid a bead of expanding urethane adhesive around the bearing housing, slid it into place, and then held the rod level with the tip of the scribe. The two random cylinders held the rods in the proper horizontal alignment.
Setting HBP rod alignment
When the glue cured, the rods were basically dead parallel in both planes.
Note the nuts epoxied on the bottom surface. That’s part of the cough precision platform alignment system…
After modifying the ABP to use an aluminum build plate, I’m going to junk it and modify a Heated Build Platform to get much more precise control over the plate alignment.
As with the ABP, the HBP instructions tell you to use short-headed bolts to clear the guide rod. There’s no need to do that if you take the time to modify the plywood clamps, as described there, so they actually clamp across the entire width of the belt, thusly:
Those plates handle the upper mount points, but the fairing also attaches to each side of the front fork. A nice rounded oval mates the fairing to the bracket, with two foam pads adapting the flat plates to the curved fairing surface. This view shows the outside of the fairing:
Lower mount – front
The hole position requires a mirror-image pair of mounts that, mercifully, all fit on the build platform at once. The solid models look about like you’d expect:
Lower Bushings
Those little tabs on the inside edge of the bracket recess printed about as poorly as you’d expect, but they’re not really critical.
I printed a set of white plates for my bike, installed the new filament tensioner, and went full frontal Barbie for my favorite ladies. This view shows the inside of the fairing:
Lower mount – rear
Turns out my ladies don’t like pink any more than I do.
The OpenSCAD source:
// Clamp plates for Zzipper fairing on Tour Easy recumbents
// Ed Nisley - KE4ZNU - Mar 2011
// Build with...
// extrusion parameters matching the values below
// 4 outer shells
// 4 solid surfaces at top + bottom
include </home/ed/Thing-O-Matic/lib/MCAD/units.scad>
// Extrusion parameters for successful building
ThreadWidth = 0.55; // should match extrusion width
ThreadZ = 0.33; // should match extrusion thickness
HoleWindage = ThreadWidth; // enlarge hole dia by extrusion width
// Plate dimensions
Layer1X = 35; // against fairing surface
Layer1Y = 30;
Layer1Z = 2*ThreadZ;
HoleOffsetX = 5.0; // will be sign-flipped as needed
HoleOffsetY = -(Layer1Y/2 - 10.0);
Layer2Margin = 1.5; // uncovered edge
Layer2X = Layer1X - 2*Layer2Margin;
Layer2Y = Layer1Y - 2*Layer2Margin;
Layer2Z = 3*ThreadZ;
MountX = 16.3 + HoleWindage; // front fork mounting plate
MountHoleOffset = 13.0; // Y end to hole center
MountY = Layer1Y;
MountZ = 4*ThreadZ; // recess depth
MountCap = 3.0; // endcap arc height
MountR = (pow(MountCap,2) + 0.25*pow(MountX,2)) / (2*MountCap); // ... radius
Layer3Margin = 1.5;
Layer3X = Layer2X - 2*Layer3Margin;
Layer3Y = Layer2Y - 2*Layer3Margin;
Layer3Z = 3*ThreadZ;
PlateZ = Layer1Z + Layer2Z + Layer3Z;
HoleDia = 0.25 * inch; // these are 1/4-20 bolt holes
// Convenience settings
BuildOffsetX = 3.0 + Layer1X/2; // build X spacing between top & bottom plates
BuildOffsetY = 3.0 + Layer1Y/2; // ... Y
Protrusion = 0.1; // extend holes beyond surfaces for visibility
//---------------
// Create plate
module Plate() {
union() {
translate([0,0,Layer1Z/2])
scale([Layer1X,Layer1Y,1]) cylinder(r=0.5,h=Layer1Z,$fn=32,center=true);
translate([0,0,Layer1Z + Layer2Z/2])
scale([Layer2X,Layer2Y,1]) cylinder(r=0.5,h=Layer2Z,$fn=32,center=true);
translate([0,0,Layer1Z + Layer2Z + Layer3Z/2])
scale([Layer3X,Layer3Y,1]) cylinder(r=0.5,h=Layer3Z,$fn=32,center=true);
}
}
//---------------
// Create hole
module Hole(OffsetX,OffsetY) {
translate([OffsetX,OffsetY,PlateZ/2])
cylinder(r=(HoleDia + HoleWindage)/2,
h=(PlateZ + 2*Protrusion),
center=true,$fn=10);
}
//---------------
//-- Build the things...
// Right side
translate([BuildOffsetX,BuildOffsetY,0])
difference() {
Plate();
Hole(HoleOffsetX,HoleOffsetY);
}
translate([BuildOffsetX,-BuildOffsetY,0])
difference() {
Plate();
Hole(-HoleOffsetX,HoleOffsetY);
translate([-HoleOffsetX,(HoleOffsetY - MountY/2 + MountHoleOffset),(PlateZ - MountZ/2 + Protrusion/2)])
intersection() {
cube([MountX,MountY,(MountZ + Protrusion)],center=true);
translate([0,(MountY/2 - MountR),0]) cylinder(r=MountR,h=(MountZ + Protrusion),center=true);
}
}
// Left side
translate([-BuildOffsetX,BuildOffsetY,0])
difference() {
Plate();
Hole(-HoleOffsetX,HoleOffsetY);
}
translate([-BuildOffsetX,-BuildOffsetY,0])
difference() {
Plate();
Hole(HoleOffsetX,HoleOffsetY);
translate([HoleOffsetX,(HoleOffsetY - MountY/2 + MountHoleOffset),(PlateZ - MountZ/2 + Protrusion/2)])
intersection() {
cube([MountX,MountY,(MountZ + Protrusion)],center=true);
translate([0,(MountY/2 - MountR),0]) cylinder(r=MountR,h=(MountZ + Protrusion),center=true);
}
}
You can rub and you can rub, but you can’t shine shit.
Eks tells me that was one of his grandmother’s favorite sayings.
He introduced me to the concept of a “used-car polish”: high shine over deep scratches. Sometimes, that’s exactly what the job requires.
There’s also the notion of making a silk purse from a sow’s ear (attributed variously to Jonathan Swift and Anon), which someone actually did: render the ear down to a gel, extrude thread, loom cloth, and sew up a purse. Yes, it can be done, but there’s a practical limit in there somewhere.
Contrary to what you might think, this has nothing to do with a certain Thing-O-Matic. A bit of laparoscopic surgery on our front yard just revealed that our septic leach field has filled with gunk; it’s 56 years old and hadn’t been pumped for two decades before we bought the place. The next week or two should be interesting: I can do the diagnosis, but I can’t handle this repair.
Putting a geared stepper motor on the MK5 filament drive produced greatly improved print quality, which meant I could finally print ScribbleJ’s version of the classic Wade Filament Tensioner and expect that it’d come out right. It’s a rather large lump of plastic that printed quite nicely on an aluminum plate.
Wade-ScribbleJ Filament Tensioner on plate
The whole thing looks like this when it’s all assembled and adjusted:
Complete Geared Stepper Extruder
[Update: The motor comes directly from the usual eBay supplier. You won’t find another one like it, but this is directly from the label…
38 mm case
Minebea-Matsushita 17PM-K150-P1V
No. T6824-02
]
You can see the two thermal switches near the bottom of the picture. The 100 °C switch is inside the acrylic frame on the Thermal Riser, the 40 °C switch is just taped to the filament tensioner’s base. The former is OK, the latter isn’t as secure as it should be. FWIW, Riser temperatures run around 70 °C during normal extrusion, albeit in a chilly Basement Laboratory without covers on the TOM’s windows.
A better view of the shaft bearings and filament position:
Filament tensioner – overview
The four long screws are 1.5 inch 4-40 from my heap, although 2 inch screws would give more room for adjustment. Some folks mount the screws the other way around, with the nuts pressing on the springs and little knobs on the nuts. I gave up on the washers to get a bit more adjustment range.
The springs came from my Big Box o’ Little Springs, sporting absolutely no pedigree at all. They’re not quite completely compressed, so there’s a bit of push left in them to handle filament diameter variations (which is the whole point of this exercise). I added four nuts (between the shaft bearing plate and the idler block) to keep the idler block from resting against the drive gear when there’s no filament in place: inserting a new filament became much easier.
Somewhat to my surprise, the entire filament drive gear assembly is free-floating and self-aligning within the housing:
Filament drive gear detail
I enabled the option to put a 5 mm diameter cleanout hole in the bearing housing, which turned out to be absolutely essential for monitoring the location of the drive gear inside all the machinery. You can barely see the hole in the first picture, on the left side of the curved section.
A floating shaft means the 7-tooth motor drive gear’s position must line up with wherever the 51-tooth filament drive gear happens to be. There’s not much room to adjust the motor gear, but a few iterations sorted out the proper number and placement of all the filament drive shaft washers, nuts, and bearings.
Filament drive gear – shaft spacing
You (well, I) really really must put a flat on the shaft and use full-strength Loctite to hold the setscrew in place. I used an all-thread M6x40 bolt because that’s what I had on hand, but a partially threaded M6x50 bolt would provide better support for the bearings, more clearance for the spacers, and look a lot better; it’d require a custom-turned bushing instead of the nut against the big gear, though.
Flatted filament drive shaft
I initially used low-strength Loctite. Word: a loose drive gear setscrew can convince you that Skeinforge’s Reversal plugin isn’t working after you make many changes with worsening results. Those fast reversals loosen the setscrew in short order.
The diameters of the 7- and 51-tooth herringbone gears determine the center-to-center distance between the motor shaft and the extruder shaft. Alas, two of the motor mounting bolts wind up directly behind the larger gear. I marked the gear adjacent to the bolt heads and drilled a hole that just barely admits the hex wrench:
Stepper Extruder – motor mount access hole
If you knew where that hole was supposed to be, you could print it right into the gear, but I haven’t a clue as to how you might algorithmically determine the precise location on the as-printed gears.
The modified OpenSCAD source produces two recesses for the bolt head and nut, but I just applied an end mill to the head side of the finished idler block. There’s no room for the bolt head between the block and the motor mounting plate.
Idler housing with recessed bolt
Of course, I modified the OpenSCAD code along the way:
Changing the bearing size moved the base: use front_bearing_r in the routine that punches the holes
Add a complete outer surface on the idler block; I thought I might want a flat metal plate to distribute the stress.
Add bolt head / nut recesses for idler block pulley shaft
Include base_wall_h in the calculation for idler_max_h
Tweaked spacing to get idler bolt heads out of the walls
Extend motor wall rightward to cover all of the base plate
Adjust base hole positioning: -10 / +4.0, not -10 / +3.5
But not all instances of 3.5 must change, I think
Filament offset may need further tweakage
Other miscellaneous tweaks
Not all of those changes made it to the printed object shown here; if I ever print another one, they’ll be included. Use at your own risk!
The OpenSCAD source, which is almost entirely ScribbleJ’s work:
// MK5 Wade's-Style Tensioner
// (C)2011, Christopher "ScribbleJ" Jansen
//
// Released under the BSD license.
// Modifications: Ed Nisley - KE4ZNU - Mar 2011
// Parametric Settings
// INTERESTING OPTIONS
// 1 = on, 0 = off
extend_shaft = 1 ; // 0 will allow a bridge over the front of the motor hole
make_stepper_holes = 1; // 1 will create mounting holes for a stepper mount.
make_dc_holes = 0; // 1 will create mounting holes for a MK5 DC motor.
motor_shaft_supports = 1; // 1 will create angle supports to the motor shaft. (See options below for support angle/size)
generate_for_viewing = 0; // 1 creates the model suitable for viewing. 0 creates the model suitable for printing.
cleaning_hole_d = 5; // The diameter of a cleaning hole to punch. (0 = no cleaning hole)
cleaning_hole_r = cleaning_hole_d/2;
cleaning_hole_angle = 75; // Angle offset from 9 o'clock position (i.e. directly left)
hole_protrusion = 0.05; // surface clearance for holes and suchlike
hole_windage = 0.4; // allowance for small hole shrinkage
// _r = radius, _d = diameter, _h = height
// REAR BEARING = bearing closest to motor
rear_bearing_d = 17.0 + hole_windage;
rear_bearing_r = rear_bearing_d/2;
rear_bearing_h = 6.0;
// EXTRA SHAFT = include an extra length of motor shaft. This is useful
// for giving your idler bolts enough room depth-wise.
extra_shaft = 5;
// FRONT BEARING = bearing furthest from motor (Technically, front bearing diameter must be >= than rear to print properly... so
// there are many places in the code that we assume the front bearing is the largest d.
front_bearing_d = 17.0 + hole_windage;
front_bearing_r = front_bearing_d/2;
front_bearing_h = 6;
// EXTRA FILAMENT = extend the length of the filament column. This is useful
// for giving your idler bolts enough room height-wise.
extra_filament = 40;
filament_margin = 3.0; // How wide is shaft on either side of filament?
filament_d = 4; // How wide is filament shaft hole?
filament_r = filament_d/2;
// FILAMENT OFFSET = How far from the center of the motor axis your MK5 plastic pusher gear thingy
// or hobbed bolt groove is.
filament_offset = 6;
// MOTOR WALL = "rear" wall of tensioner.
motor_wall_h = 5; // thickness of wall
motor_bolt_d = 3.0 + hole_windage; // diameter of motor mounting bolts
motor_bolt_r = motor_bolt_d/2;
motor_bolt_h = motor_wall_h;
motor_bolt_hex_d = 6.3 + hole_windage; // diameter of motor mounting bolt hex caps
motor_bolt_hex_r = motor_bolt_hex_d/2;
motor_bolt_hex_h = 3; // height of hex caps
motor_dropbolts = 2.0; // distance to sink bolts into wall
motor_boltmargin = 5; // Distance to allow between bolts and edges of wall.
motor_shaft_width = 5; // How thick is the wall around the motor shaft?
motor_shaft_support_width = 10; // How thick are the motor supports (if any)?
motor_shaft_support_angle = 0; // if non-0, will create three supports spaced apart this many degrees.
// 0 creates a single support if enabled above.
// 31 is distance from center to bolt holes... do not chang this without changing hardcoded numbers
// in the motor bolt generating module.
motor_wall_w = 31 + (motor_boltmargin * 2) + motor_bolt_d;
motor_wall_d = 31 + (motor_boltmargin * 2) + motor_bolt_d;
// IDLER BEARING = the bearing that holds the plastic against the hobbed bolt/MK5 plastic pusher.
// You should include about an extra 2mm over your actual bearing measurements here so it can spin freely.
idler_bearing_d = 19 + 3;
idler_bearing_r = idler_bearing_d/2;
idler_bearing_h = 6 + 2;
h_i = idler_bearing_h/2;
idler_bearing_bolt_d = 5; // This is the size of the bolt holding the bearing in place.
idler_bearing_bolt_r = idler_bearing_bolt_d/2;
idler_bolt_d = 3.0 + hole_windage; // This is the size of the (4) bolts holding the idler block in place.
idler_bolt_r = idler_bolt_d/2;
idler_bolt_margin = 4; // How much room to allow between bolt holes and edge of block.
idler_bolt_hex_d = 7.0 + hole_windage;
idler_bolt_hex_r = idler_bolt_hex_d/2;
idler_bolt_hex_h = 5; // Arbitrarily large to be sure to punch through supports/shaft.
idler_dropbolts = 2.0; // Try negative numbers here to catch your nuts on the supports.
idler_wall = 2.5; // thickness of wall to left of idler bearing
idler_recess_dia = 9.0 + hole_windage; // recess idler shaft bolt head & nut
idler_recess_r = idler_recess_dia/2;
idler_recess_depth = 3.0;
// BASE = the bottom part that bolts onto the hot end.
base_wall_h = 6; // How thick or tall is the base.
base_h=base_wall_h;
base_bolt_d = 3.0 + hole_windage; // Size of bolts used to hold base -- rest of base settings are same as motor wall settings above.
base_bolt_r = base_bolt_d/2;
base_bolt_hex_d = 6.3 + hole_windage;
base_bolt_hex_r = base_bolt_hex_d/2;
base_bolt_hex_h = 5;
base_dropbolts = 1.5;
base_boltmargin = 6;
base_filament_offset_x = 6;
// 30/14.0 is distance from center to bolt holes...
// do not change this without changing hardcoded numbers
// in the base bolt generating module.
base_w = 30 + (base_boltmargin*2) + base_bolt_r;
base_d = 14.0 + (base_boltmargin*2) + base_bolt_r;
// base_z_extra is used for configurations where base wall or motor wall
// would be unprintable due to differential in height.
// shrinks or grows the base to fit.
base_z_extra = ((idler_bearing_h/2) + rear_bearing_h + motor_wall_h) - ((base_d/2) + 3.5);
base_filament_offset_z = -3.5; // How far the filament hole is from the bolts furthest from the motor.
base_d_use = base_d + base_z_extra;
// make up difference between bottom of wall and base... not really necessary but more support more better.
motor_wall_extra = front_bearing_r + (extra_filament/2) + base_h - (motor_wall_d/2);
// Calculate maximum space for idler block.
idler_max_h = idler_bearing_d + extra_filament + ((-base_bolt_hex_h+base_dropbolts)*2) - base_wall_h;
half_idler_max_h = idler_max_h/2;
idler_bolt_y = half_idler_max_h - idler_bolt_r - idler_bolt_margin;
//idler_max_w = .55 * idler_bearing_d;
idler_max_w = idler_bearing_r + idler_wall; // enforce wall thickness on right side
idler_max_d = extra_shaft+front_bearing_h+idler_bearing_h+rear_bearing_h+((-motor_bolt_hex_h+motor_dropbolts)*2);
half_idler_max_d = idler_max_d/2;
idler_bolt_z = half_idler_max_d - idler_bolt_r - idler_bolt_margin;
echo(str("Idler block size: ",idler_max_d," x ",idler_max_h," x ",idler_max_w));
echo(str("Idler bolt spacing: ",2*idler_bolt_z," x ",2*idler_bolt_y));
// This module generates the bolt pattern for the idler, trying to fill the maximum space available.
module IDLERBOLTS()
{
// echo(idler_bolt_r, idler_bolt_d, idler_max_d, idler_bolt_z, half_idler_max_d);
// echo(idler_bolt_r, idler_bolt_d, idler_max_h, idler_bolt_y, half_idler_max_h);
translate([idler_bolt_z,idler_bolt_y,0]) cylinder(r=idler_bolt_r, h=40);
translate([idler_bolt_z,-idler_bolt_y,0]) cylinder(r=idler_bolt_r, h=40);
translate([-idler_bolt_z,idler_bolt_y,0]) cylinder(r=idler_bolt_r, h=40);
translate([-idler_bolt_z,-idler_bolt_y,0]) cylinder(r=idler_bolt_r, h=40);
translate([0,0,-idler_bolt_hex_h])
{
translate([idler_bolt_z,idler_bolt_y,0]) cylinder(r=idler_bolt_hex_r, h=idler_bolt_hex_h,$fn=6);
translate([idler_bolt_z,-idler_bolt_y,0]) cylinder(r=idler_bolt_hex_r, h=idler_bolt_hex_h,$fn=6);
translate([-idler_bolt_z,idler_bolt_y,0]) cylinder(r=idler_bolt_hex_r, h=idler_bolt_hex_h,$fn=6);
translate([-idler_bolt_z,-idler_bolt_y,0]) cylinder(r=idler_bolt_hex_r, h=idler_bolt_hex_h,$fn=6);
}
}
// This module generates an idler block, filling the maximum space available.
module IDLER()
{
difference()
{
translate([0,0,(idler_max_w/2)-(.25 * idler_bearing_bolt_d)]) cube([idler_max_d, idler_max_h, idler_max_w], center=true);
translate([0,0,(-.5 * idler_bearing_bolt_r) + idler_max_w]) rotate([0,180,0]) IDLERBOLTS();
#rotate([0,90,0]) cylinder(h=idler_max_d+1, r=idler_bearing_bolt_r,center=true);
#rotate([0,90,0]) cylinder(h=idler_bearing_h, r=idler_bearing_r, center=true);
translate([(idler_max_d/2 - idler_recess_depth),0,0])
rotate([0,90,0])
#cylinder(r=idler_recess_r,h=(idler_recess_depth + hole_protrusion),$fn=10);
translate([(-idler_max_d/2 + idler_recess_depth),0,0])
rotate([0,270,0])
#cylinder(r=idler_recess_r,h=(idler_recess_depth + hole_protrusion),$fn=10);
}
echo(str("IDLER BEARING BOLT LENGTH REQUIRED (longer is OK): ", idler_max_d, "mm"));
}
// This module creates the motor shaft hole pattern.
module MOTORSHAFT()
{
// idler bearing
cylinder(h=idler_bearing_h, r=rear_bearing_r, center=true);
// front bearing
translate([0,0,h_i]) cylinder(h=front_bearing_h, r=front_bearing_r);
if(extend_shaft == 1)
{
translate([0,0,h_i]) cylinder(h=front_bearing_h+(extra_shaft/2)+50, r=front_bearing_r);
}
// rear bearing
translate([0,0,0 - h_i - rear_bearing_h - (extra_shaft/2) - motor_wall_h])
cylinder(h= rear_bearing_h + (extra_shaft/2) + motor_wall_h, r=rear_bearing_r);
echo(str("MOTOR SHAFT/BOLT LENGTH REQUIRED (longer is OK): ", front_bearing_h+idler_bearing_h+rear_bearing_h+motor_wall_h+(extra_shaft/2), "mm"));
echo(str("MOTOR SHAFT LENGTH FROM REAR OF MOUNT TO FILAMENT:", motor_wall_h+(extra_shaft/2)+rear_bearing_h+(idler_bearing_h/2), "mm"));
}
// This module creates an MK5 mount motor hole pattern with optional hex insets for bolt heads/nuts.
module MK5_MOTORHOLES(include_dc = 1, include_stepper = 1, include_hex = 1)
{
// The hardcoded numbers in the module below are simply the coordinates of the motor holes,
// relative to the center of the motor shaft.
// STEPPER MOUNT HOLES
if(include_stepper == 1)
{
translate([15.5,15.5,-motor_dropbolts-hole_protrusion]) cylinder(r=motor_bolt_r, h=motor_bolt_h+(2*hole_protrusion));
translate([15.5,-15.5,-motor_dropbolts-hole_protrusion]) cylinder(r=motor_bolt_r, h=motor_bolt_h+(2*hole_protrusion));
translate([-15.5,-15.5,-motor_dropbolts-hole_protrusion]) cylinder(r=motor_bolt_r, h=motor_bolt_h+(2*hole_protrusion));
translate([-15.5,15.5,-motor_dropbolts-hole_protrusion]) cylinder(r=motor_bolt_r, h=motor_bolt_h+(2*hole_protrusion));
if(include_hex == 1)
{
translate([15.5,15.5,motor_bolt_h-motor_dropbolts-hole_protrusion]) cylinder(r=motor_bolt_hex_r, h=motor_bolt_hex_h + (2*hole_protrusion), $fn=6);
translate([15.5,-15.5,motor_bolt_h-motor_dropbolts-hole_protrusion]) cylinder(r=motor_bolt_hex_r, h=motor_bolt_hex_h + (2*hole_protrusion), $fn=6);
translate([-15.5,-15.5,motor_bolt_h-motor_dropbolts-hole_protrusion]) cylinder(r=motor_bolt_hex_r, h=motor_bolt_hex_h + (2*hole_protrusion), $fn=6);
translate([-15.5,15.5,motor_bolt_h-motor_dropbolts-hole_protrusion]) cylinder(r=motor_bolt_hex_r, h=motor_bolt_hex_h + (2*hole_protrusion), $fn=6);
}
}
// DC MOUNT HOLES
if(include_dc == 1)
{
// DC MOUNT HOLES
translate([0,-15.5,-motor_dropbolts]) cylinder(r=motor_bolt_r,h=motor_bolt_h);
rotate([0,0,-60]) translate([0,-15.5,-motor_dropbolts]) cylinder(r=motor_bolt_r,h=motor_bolt_h);
rotate([0,0,-120]) translate([0,-15.5,-motor_dropbolts]) cylinder(r=motor_bolt_r,h=motor_bolt_h);
rotate([0,0,-180]) translate([0,-15.5,-motor_dropbolts]) cylinder(r=motor_bolt_r,h=motor_bolt_h);
if(include_hex == 1)
{
translate([0,-15.5,motor_bolt_h-motor_dropbolts]) cylinder(r=motor_bolt_hex_r,h=motor_bolt_hex_h, $fn=6);
rotate([0,0,-60]) translate([0,-15.5,motor_bolt_h-motor_dropbolts]) cylinder(r=motor_bolt_hex_r,h=motor_bolt_hex_h, $fn=6);
rotate([0,0,-120]) translate([0,-15.5,motor_bolt_h-motor_dropbolts]) cylinder(r=motor_bolt_hex_r,h=motor_bolt_hex_h, $fn=6);
rotate([0,0,-180]) translate([0,-15.5,motor_bolt_h-motor_dropbolts]) cylinder(r=motor_bolt_hex_r,h=motor_bolt_hex_h, $fn=6);
}
}
}
// This module creates MK5 hot-end hole patterns with optional hex heads for the bolts/nuts.
module MK5_BASEHOLES(include_MK5boltheads = 1, include_filament = 1, include_hex = 1)
{
// The hardcoded numbers in the routine below are simply the coordinates of the base holes,
// relative to the filament hole.
if(include_filament == 1)
{
translate([0,0,100/4]) cylinder(r=filament_r, h=100,center=true);
}
translate([-15,4.0,-base_dropbolts-hole_protrusion]) cylinder(r=base_bolt_r,h=base_h+(2*hole_protrusion));
translate([-15,-10,-base_dropbolts-hole_protrusion]) cylinder(r=base_bolt_r,h=base_h+(2*hole_protrusion));
translate([15,4.0,-base_dropbolts-hole_protrusion]) cylinder(r=base_bolt_r,h=base_h+(2*hole_protrusion));
translate([15,-10,-base_dropbolts-hole_protrusion]) cylinder(r=base_bolt_r,h=base_h+(2*hole_protrusion));
if(include_MK5boltheads == 1)
{
translate([17,9.5,-hole_protrusion]) cylinder(r=3, h=4);
translate([17,-15.5,-hole_protrusion]) cylinder(r=3, h=4);
translate([-17,9.5,-hole_protrusion]) cylinder(r=3, h=4);
translate([-17,-15.5,-hole_protrusion]) cylinder(r=3, h=4);
}
if(include_hex == 1)
{
translate([-15,4.0,base_h-base_dropbolts-hole_protrusion]) cylinder(r=base_bolt_hex_r,h=base_bolt_hex_h+(2*hole_protrusion), $fn=6);
translate([-15,-10,base_h-base_dropbolts-hole_protrusion]) cylinder(r=base_bolt_hex_r,h=base_bolt_hex_h+(2*hole_protrusion), $fn=6);
translate([15,4.0,base_h-base_dropbolts-hole_protrusion]) cylinder(r=base_bolt_hex_r,h=base_bolt_hex_h+(2*hole_protrusion), $fn=6);
translate([15,-10,base_h-base_dropbolts-hole_protrusion]) cylinder(r=base_bolt_hex_r,h=base_bolt_hex_h+(2*hole_protrusion), $fn=6);
}
}
// This module generates the mounting part of the Wade's-style tensioner.
// The generated item is centered on the motor shaft in X,Y and the filament in Z.
module MOUNT()
{
difference()
{
union()
{
translate([0,0,-1 * (motor_wall_h/2)])
{ // MOTOR SHAFT RELATIVE TO FILAMENT IN Z, MOTOR SHAFT IN X,Y
cylinder(h=front_bearing_h + idler_bearing_h + rear_bearing_h + extra_shaft + motor_wall_h, r=front_bearing_r+motor_shaft_width, center=true);
translate([base_filament_offset_x,0,0]) cube([filament_d + (2 * filament_margin), front_bearing_d + extra_filament, front_bearing_h + idler_bearing_h + rear_bearing_h + extra_shaft + motor_wall_h], center=true);
if(motor_shaft_supports == 1)
{
translate([0,0,(motor_wall_h/2)]) {
intersection()
{
cylinder( h=front_bearing_h + idler_bearing_h + rear_bearing_h + extra_shaft, r1=(motor_wall_w/2), r2=front_bearing_r+motor_shaft_width, center=true);
rotate([0,0,90]) translate([0,50,0]) cube([motor_shaft_support_width, 100, front_bearing_h + idler_bearing_h + rear_bearing_h + extra_shaft], center=true);
}
intersection()
{
cylinder( h=front_bearing_h + idler_bearing_h + rear_bearing_h + extra_shaft, r1=(motor_wall_w/2), r2=front_bearing_r+motor_shaft_width, center=true);
rotate([0,0,90-motor_shaft_support_angle]) translate([0,50,0]) cube([motor_shaft_support_width, 100, front_bearing_h + idler_bearing_h + rear_bearing_h + extra_shaft], center=true);
}
intersection()
{
cylinder( h=front_bearing_h + idler_bearing_h + rear_bearing_h + extra_shaft, r1=(motor_wall_w/2), r2=front_bearing_r+motor_shaft_width, center=true);
rotate([0,0,90+motor_shaft_support_angle]) translate([0,50,0]) cube([motor_shaft_support_width, 100, front_bearing_h + idler_bearing_h + rear_bearing_h + extra_shaft], center=true);
}
}
}
}
translate([0,motor_wall_extra/-2,((motor_wall_h/-2) + rear_bearing_h+(extra_shaft/2)+motor_wall_h+(idler_bearing_h/2)) * -1])
{ // MOTOR WALL RELATIVE TO MOTOR SHAFT X,Y
union() {
cube([motor_wall_w, motor_wall_d+motor_wall_extra, motor_wall_h], center=true);
translate([base_filament_offset_x - (motor_wall_w - base_w)/2 + motor_wall_w/4,0,0])
cube([motor_wall_w/2,motor_wall_d+motor_wall_extra, motor_wall_h],center=true);
}
}
translate([filament_offset, -1* (front_bearing_r + (extra_filament/2) + (base_h/2)), base_filament_offset_z])
{ // BASE RELATIVE TO FILAMENT HOLE IN Z,X
translate([0,0,-(base_z_extra/2)])
cube([base_w, base_h, base_d_use], center=true);
// extend filament shaft
translate([0,(front_bearing_d + extra_filament + base_h)/2, 0])
cube([filament_d + (2 * filament_margin), front_bearing_d + extra_filament, base_d], center=true);
}
}
// Punch motor holes
translate([0,0,-1*((idler_bearing_h/2) + (rear_bearing_h) + (motor_wall_h) + (extra_shaft/2))])
# MK5_MOTORHOLES(include_stepper=make_stepper_holes, include_dc = make_dc_holes);
// Punch motor shaft
MOTORSHAFT();
// Punch idler bolt holes
translate([filament_offset - filament_margin - (filament_r) + idler_dropbolts,0,0])
rotate([90,90,90]) # IDLERBOLTS();
// Punch baseplate holes
translate([filament_offset, -1* (front_bearing_r + (extra_filament/2) + base_h), 0])
rotate([-90,180,0]) # MK5_BASEHOLES();
// Punch idler bearing clearance
translate([filament_offset + idler_bearing_r - filament_r, 0,0])
cylinder(h=idler_bearing_h + front_bearing_h + rear_bearing_h + extra_shaft + hole_protrusion, r=idler_bearing_r, center=true);
// Punch cleaning hole
rotate([-1 * cleaning_hole_angle,-90,0])
cylinder(h=50,r=cleaning_hole_r);
}
}
if(generate_for_viewing == 1)
{
MOUNT();
translate([filament_offset + idler_bearing_r,0,0]) rotate([0,90,0]) IDLER();
}
else if(generate_for_viewing == 0)
{
translate([15.5+motor_boltmargin+motor_bolt_r+2.5, 0, (motor_wall_h+(extra_shaft/2)+rear_bearing_h+(idler_bearing_h/2))]) MOUNT();
translate([(idler_max_d/-2)-2.5, 0, (-.5 * idler_bearing_bolt_r) + idler_max_w]) rotate([180,0,0]) IDLER();
}
The first step of a good print requires nailing the extrusion to the build platform. The Skeinforge Splodge plugin seems to thicken the first part of each filament on the first layer, which is not helpful. So I turned that off and added a few lines to start.gcode that do a much better job.
I also disabled the Wipe plugin, because you really can’t wipe the nozzle after the first few layers without having some part of the Z stage clobber the object. Rather than enable Wipe for just the first layer, I put a manual wipe in start.gcode, too.
The relevant sections look like this; they fit after the homing sequence at the end of the file:
(--- manual wipe ---)
G0 X54 Y-57.0 Z15 (move above wipe start)
G0 Z8 (down to wipe level)
M6 T0 (wait for temperature settling)
M101 (Extruder on, forward)
G4 P4000 (take up slack, get pressure)
M103 (Extruder off)
G4 P4000 (Wait for filament to stop oozing)
G0 Y-40 (wipe nozzle)
(--- manual splodge)
G0 X-50 Y-55 (to front left corner)
G1 Z0.50 (just over surface)
M108 R2.0 (set stepper extruder speed)
M101 (start extruder)
G4 P2000 (build up a turd)
Depending on a myriad imponderable factors, the manual wipe sequence flips off either a huge tangle or a tiny strand. That’s why I used a 4 second delay: it’s long enough to leave the extruder pressure in a consistent state no matter how it starts.
The manual splodge location depends on your platform layout; I’m thinking of putting it entirely outside the build area. It must be somewhere near the front left corner, because Skeinforge starts each new layer from that direction. Two seconds of extrusion at 2 rev/min forms a blob with a generous contact patch, although the nozzle must plow through the side on its way out.
Note that I leave the extruder running at the end of start.gcode, which means that it’s printing all the way to the outline. That won’t interfere with any part of the object, because (by definition) the first layer of the object lies entirely within the outline.
The Outline plugin puts a single filament around the entire object, allowing me to measure the actual nozzle height and extrusion width on the first layer. More on that later.
The final result looks like this:
Manual Splodge with Companion Cube
Notice that the splodge turd isn’t firmly glued to the platform, but the thread leading to the outline sticks like it was glued and the outline comes out perfectly formed. That’s the whole idea in a nutshell: paste the thread down from a stationary nozzle, then start moving with the turd acting as an anchor.
Trying to start pasting the filament with the nozzle moving doesn’t work well, as witness the left edge of the outline around these test pieces:
ABS coating on aluminum build plate
Admittedly, that was with a DC extruder, but the same principle applies to stepper extruders.