MTD Snowthrower Throttle Knob: Found!

After the snow cleared and we ventured out again, the missing snowthrower throttle knob was sitting on the far reaches of the driveway:

MTD Snowthrower Throttle Knob - crude repair
MTD Snowthrower Throttle Knob – crude repair

It’s a well-meaning, albeit totally ineffectual, expedient repair.

I put a channel around the slot for the throttle shaft to mimic the original design:

MTD Snowthrower Throttle Knob - fracture
MTD Snowthrower Throttle Knob – fracture

The fracture started at the end and worked its way back, loosening the knob’s grip on the shaft as it went:

MTD Snowthrower Throttle Knob - pieces
MTD Snowthrower Throttle Knob – pieces

Should my replacement survive the next 13 years, it’ll likely outlive the rest of the snowthrower:

Snowthrower throttle knob - installed
Snowthrower throttle knob – installed

If the original MTD choke knob didn’t have that fancy metal insert, I’d replace it just for pretty …

KeyboardIO Atreus: RGB LED Installation

Having scouted out the territory inside the KeyboardIO Atreus, adding an LED requires taking it completely apart to drill a hole in the aluminum faceplate:

Atreus keyboard - panel drilling
Atreus keyboard – panel drilling

Reattaching the plate to the PCB with only three screws allows marking the hole position on the PCB, which is much easier than pretending to derive the position from first principles:

Atreus keyboard - LED marking
Atreus keyboard – LED marking

Despite appearances, I traced the hole with a mechanical pencil: black graphite turns shiny silvery gray against matte black soldermask. Also, the PCB trace is off-center, not the hole.

Overlay the neighborhood with Kapton tape to protect the PCB from what comes next:

Atreus keyboard - Kapton tape

Snip a WS2812 RGB LED from a strip, stick it in place with eyeballometric alignment over the target, and wire it up:

Atreus keyboard - LED wiring
Atreus keyboard – LED wiring

Despite the terrible reliability of WS2812 RGB LEDs mounted on PCB carriers, a different set on a meter of high-density flex tape have worked reasonably well when not thermally stressed, so I’ll assume this one arrived in good order.

Aligning the LED directly under the hole required a few iterations:

Atreus keyboard - LED positioning
Atreus keyboard – LED positioning

The iridescent green patch is a diffraction pattern from the controller chip’s internal circuitry.

The data comes from MOSI, otherwise known as B2, down in the lower left corner:

Atmel 32U4 - JTAG pins
Atmel 32U4 – JTAG pins

Actually lighting the LED now becomes a simple matter of software QMK firmware.

Makergear M2: Initial PrusaSlicer Configuration

After replacing the nozzle and the filament drive body on the M2, I figured I might as well throw all the balls in the air and switch to PrusaSlicer for all my slicing needs. It’s built from the Slic3r project, gaining features used by Prusa’s printers / filaments and a considerably improved UI, with a full-time paid staff working on it:

PrusaSlicer screenshot
PrusaSlicer screenshot

Of course, I immediately turned on Expert mode.

CAUTION: My heavily customized start_gcode will crash your M2, because you haven’t relocated the Z-axis switch, haven’t calibrated Z=0 at the platform surface, and don’t put the XY=0 origin in the center of the platform.

You have been warned: consider this as a serving suggestion, not a finished product.

Because everything I design looks more-or-less like a bracket, I absolutely don’t care about surface finish, and I’m content to use only a few colors of PETG from a single supplier, a single Slic3r configuration has sufficed for nearly everything I print. A few manual tweaks for specific models, perhaps to change the number of perimeters or the infill percentage, handle the remaining cases.

With all that in mind, here’s the current result of File → Export → Export Config as a GitHub Gist:

# generated by PrusaSlicer 2.2.0+linux-x64 on 2021-01-01 at 13:33:03 UTC
avoid_crossing_perimeters = 0
bed_custom_model =
bed_custom_texture =
bed_shape = -100x-125,100x-125,100x125,-100x125
bed_temperature = 90
before_layer_gcode =
between_objects_gcode =
bottom_fill_pattern = hilbertcurve
bottom_solid_layers = 3
bottom_solid_min_thickness = 0
bridge_acceleration = 0
bridge_angle = 0
bridge_fan_speed = 100
bridge_flow_ratio = 1
bridge_speed = 50
brim_width = 0
clip_multipart_objects = 1
colorprint_heights =
complete_objects = 0
cooling = 1
cooling_tube_length = 5
cooling_tube_retraction = 91.5
default_acceleration = 0
default_filament_profile = ""
default_print_profile =
deretract_speed = 0
disable_fan_first_layers = 6
dont_support_bridges = 1
draft_shield = 0
duplicate_distance = 6
elefant_foot_compensation = 0
end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n"
end_gcode = ;-- PrusaSlicer End G-Code for M2 starts --\n; Ed Nisley KE4NZU - 15 November 2013\nG1 Z160 F2000 ; lower bed\nG1 X135 Y100 F30000 ; nozzle to right, bed front\nM104 S0 ; drop extruder temperature\nM140 S0 ; drop bed temperature\nM106 S0 ; bed fan off\nM84 ; disable motors\n;-- PrusaSlicer End G-Code ends --\n\n
ensure_vertical_shell_thickness = 1
external_perimeter_extrusion_width = 0
external_perimeter_speed = 50%
external_perimeters_first = 0
extra_loading_move = -2
extra_perimeters = 1
extruder_clearance_height = 20
extruder_clearance_radius = 20
extruder_colour = ""
extruder_offset = 0x0
extrusion_axis = E
extrusion_multiplier = 0.95
extrusion_width = 0.4
fan_always_on = 0
fan_below_layer_time = 15
filament_colour = #29B2B2
filament_cooling_final_speed = 3.4
filament_cooling_initial_speed = 2.2
filament_cooling_moves = 4
filament_cost = 25
filament_density = 0.95
filament_deretract_speed = nil
filament_diameter = 1.72
filament_load_time = 0
filament_loading_speed = 28
filament_loading_speed_start = 3
filament_max_volumetric_speed = 0
filament_minimal_purge_on_wipe_tower = 15
filament_notes = ""
filament_ramming_parameters = "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
filament_retract_before_travel = nil
filament_retract_before_wipe = nil
filament_retract_layer_change = nil
filament_retract_length = nil
filament_retract_lift = nil
filament_retract_lift_above = nil
filament_retract_lift_below = nil
filament_retract_restart_extra = nil
filament_retract_speed = nil
filament_settings_id = "M2 Esun PETG"
filament_soluble = 0
filament_toolchange_delay = 0
filament_type = PET
filament_unload_time = 0
filament_unloading_speed = 90
filament_unloading_speed_start = 100
filament_vendor = (Unknown)
filament_wipe = nil
fill_angle = 45
fill_density = 25%
fill_pattern = 3dhoneycomb
first_layer_acceleration = 0
first_layer_bed_temperature = 90
first_layer_extrusion_width = 0
first_layer_height = 0.25
first_layer_speed = 15
first_layer_temperature = 250
gap_fill_speed = 25
gcode_comments = 0
gcode_flavor = marlin
gcode_label_objects = 0
high_current_on_filament_swap = 0
host_type = octoprint
infill_acceleration = 0
infill_every_layers = 1
infill_extruder = 1
infill_extrusion_width = 0
infill_first = 1
infill_only_where_needed = 0
infill_overlap = 15%
infill_speed = 60
interface_shells = 0
layer_gcode =
layer_height = 0.25
machine_max_acceleration_e = 10000,5000
machine_max_acceleration_extruding = 10000,1250
machine_max_acceleration_retracting = 10000,1250
machine_max_acceleration_x = 2500,1000
machine_max_acceleration_y = 2500,1000
machine_max_acceleration_z = 2500,200
machine_max_feedrate_e = 10000,5000
machine_max_feedrate_x = 450,200
machine_max_feedrate_y = 450,200
machine_max_feedrate_z = 100,30
machine_max_jerk_e = 100,50
machine_max_jerk_x = 25,10
machine_max_jerk_y = 25,10
machine_max_jerk_z = 10,5
machine_min_extruding_rate = 0,0
machine_min_travel_rate = 0,0
max_fan_speed = 100
max_layer_height = 0
max_print_height = 200
max_print_speed = 80
max_volumetric_speed = 0
min_fan_speed = 100
min_layer_height = 0.1
min_print_speed = 10
min_skirt_length = 25
notes =
nozzle_diameter = 0.35
only_retract_when_crossing_perimeters = 1
ooze_prevention = 0
output_filename_format = [input_filename_base].gcode
overhangs = 1
parking_pos_retraction = 92
perimeter_acceleration = 0
perimeter_extruder = 1
perimeter_extrusion_width = 0
perimeter_speed = 50
perimeters = 3
post_process =
print_host =
print_settings_id = M2 Default
printer_model =
printer_notes =
printer_settings_id = M2 Default
printer_technology = FFF
printer_variant =
printer_vendor =
printhost_apikey =
printhost_cafile =
raft_layers = 0
remaining_times = 0
resolution = 0.01
retract_before_travel = 3
retract_before_wipe = 0%
retract_layer_change = 0
retract_length = 1
retract_length_toolchange = 10
retract_lift = 0
retract_lift_above = 0
retract_lift_below = 0
retract_restart_extra = 0
retract_restart_extra_toolchange = 0
retract_speed = 60
seam_position = nearest
serial_port =
serial_speed = 250000
silent_mode = 1
single_extruder_multi_material = 0
single_extruder_multi_material_priming = 1
skirt_distance = 3
skirt_height = 1
skirts = 3
slice_closing_radius = 0.049
slowdown_below_layer_time = 5
small_perimeter_speed = 25%
solid_infill_below_area = 70
solid_infill_every_layers = 0
solid_infill_extruder = 1
solid_infill_extrusion_width = 0
solid_infill_speed = 75%
spiral_vase = 0
standby_temperature_delta = -5
start_filament_gcode = "; Filament gcode\n"
start_gcode = ;-- PrusaSlicer Start G-Code for M2 starts --\n; Ed Nisley KE4NZU\n; Makergear V4 hot end\n; Origin at platform center, set by MANUAL_X_HOME_POS compiled constants\n; Z-min switch at platform, must move nozzle to X=135 to clear\nG90 ; absolute coordinates\nG21 ; millimeters\nM83 ; relative extrusion distance\nM104 S[first_layer_temperature] ; start extruder heating\nM140 S[first_layer_bed_temperature] ; start bed heating\nM17 ; enable steppers\nG4 P500 ; ... wait for power up\nG92 Z0 ; set Z to zero, wherever it might be now\nG0 Z10 F1000 ; move platform downward to clear nozzle; may crash at bottom\nG28 Y ; home Y to clear plate, offset from compiled constant\nG28 X ; home X, offset from M206 X, offset from compiled constant\nG0 X135 Y0 F15000 ; move off platform to right side, center Y\nG28 Z ; home Z to platform switch, offset from M206 Z measured\nG0 Z2.0 F1000 ; get air under switch\nG0 Y-126 F10000 ; set up for priming, zig around corner\nG0 X0 ; center X\nG0 Y-124.5 ; just over platform edge\nG0 Z0 F500 ; exactly at platform\nM190 S[first_layer_bed_temperature] ; wait for bed to finish heating\nM109 S[first_layer_temperature] ; set extruder temperature and wait\nG1 E20 F300 ; prime to get pressure, generate blob on edge\nG0 Y-123 F5000 ; shear off blob\nG0 X15 F15000 ; jerk away from blob, move over surface\nG4 P500 ; pause to attach\nG1 X45 F500 ; slowly smear snot to clear nozzle\nG1 Z1.0 F2000 ; clear bed for travel\n;-- PrusaSlicer Start G-Code ends --\n
support_material = 0
support_material_angle = 0
support_material_auto = 1
support_material_buildplate_only = 0
support_material_contact_distance = 0.2
support_material_enforce_layers = 0
support_material_extruder = 1
support_material_extrusion_width = 0.31
support_material_interface_contact_loops = 0
support_material_interface_extruder = 1
support_material_interface_layers = 3
support_material_interface_spacing = 0
support_material_interface_speed = 100%
support_material_pattern = rectilinear
support_material_spacing = 2.5
support_material_speed = 60
support_material_synchronize_layers = 0
support_material_threshold = 0
support_material_with_sheath = 1
support_material_xy_spacing = 50%
temperature = 250
thin_walls = 1
threads = 4
thumbnails =
toolchange_gcode =
top_fill_pattern = hilbertcurve
top_infill_extrusion_width = 0
top_solid_infill_speed = 50%
top_solid_layers = 3
top_solid_min_thickness = 0
travel_speed = 300
use_firmware_retraction = 0
use_relative_e_distances = 0
use_volumetric_e = 0
variable_layer_height = 1
wipe = 0
wipe_into_infill = 0
wipe_into_objects = 0
wipe_tower = 0
wipe_tower_bridging = 10
wipe_tower_no_sparse_layers = 0
wipe_tower_rotation_angle = 0
wipe_tower_width = 60
wipe_tower_x = 180
wipe_tower_y = 140
wiping_volumes_extruders = 70,70
wiping_volumes_matrix = 0
xy_size_compensation = 0
z_offset = 0

American Standard Elite Kitchen Faucet: O-Rings Again

My alleged improvement to the upper bearing ring in our American Standard Elite kitchen faucet didn’t survive nearly as well as I hoped and began leaking through the o-ring seals after the usual year. The 0.4 mm polypropylene shim ring apparently stuck to the nylon bearing ring, wore down to a 0.1 mm thick ribbon against the base, then let the o-ring wear out as usual.

The black gunk around the top of the upper seal area has the consistency of hard plastic paint, although it’s most likely rubber particles from the o-ring burnished against the bronze base by the sliding PP shim ring:

American Standard Elite faucet - base
American Standard Elite faucet – base

Remember Nisley’s First Rule of Plumbing: Never look inside your water supply pipes.

As before, the o-rings wear on their inner diameters, indicating that they turn with the spout around the base.

For lack of anything smarter, I removed as much of the debris as feasible, installed new seals, reassembled the faucet in reverse order, and ordered another set of parts.

If I hadn’t done such a great job of reinforcing the underside of the sink deck around the mounting rings, to the extent I’m not sure another faucet base else would fit, I’d be far less reluctant to start over.

Straightening Armature Wire

Although I was blithely unaware when I bought some useful-looking surplus, it turns out 1/16 inch armature wire works really well to seal our homebrew masks around our noses. Mary added a narrow passage along the top edge of her slightly reshaped Fu Mask pattern to retain the wire and I provided 4.5 inch lengths of straightened wire:

Armature wire - stock vs. straightened
Armature wire – stock vs. straightened

The wire comes off the roll in dead-soft condition, so I can straighten (and slightly harden) it by simply rolling each wire with eight fingertips across the battered cutting board. The slightly wavy wire shows its as-cut condition and the three straight ones are ready for their masks.

Although nearly pure aluminum wire doesn’t work-harden quickly, half a year of mask duty definitely takes its toll. This sample came from my biking mask after the edges wore out:

Armature wire - work-hardened
Armature wire – work-hardened

We initially thought using two wires would provide a better fit, but more metal just made adjusting the nose seal more difficult after each washing. The wire has work-hardened enough to make the sharper bends pretty much permanent; they can be further bent, but no longer roll out under finger pressure.

Although we’re not yet at the point where we must reuse wires, I took this as an opportunity to improve my annealing hand: heat the wire almost to its melting point, hold it there for a few seconds, then let it cool slowly. The usual technique involves covering the aluminum with something like hand soap or permanent marker ink, heat until the soap / marker burns away, then let it air-cool. Unlike steel, there’s no need for quenching or tempering.

Blue Sharpie worked surprisingly well with a propane torch:

Armature wire - annealed straightened
Armature wire – annealed straightened

As far as I can tell after a few attempts, the pigment vanishes just below the annealing temperature and requires another pass to reach the right temperature. Sweep the flame steadily, don’t pause, and don’t hold the wire over anything melt-able.

Those wires (I cut the doubled wire apart) aren’t quite as soft as the original stock, but they rolled straight and are certainly good enough for our simple needs; they’re back in the Basement Laboratory Warehouse for future (re)use.

MTD Snowthrower: Friction Wheel Tire Replacement

Late in last winter’s snowfall, our MTD snowthrower / snowblower ran low on get-up-and-go mobility, so I resolved to check inside before the next snowfall. What with one thing and another, time passed until, a few days before the first major snowfall of this winter season, I opened the bottom cover and found this mess:

Snowthrower friction wheel - worn in place
Snowthrower friction wheel – worn in place


A diagram from the manual identifies the components:

MTD Snowblower - drive train - Fig 23
MTD Snowblower – drive train – Fig 23

The 8 HP gas engine spins the drive plate, which transfers some of those horses through the rubber tire on the friction wheel to the gear shaft, which turns the axle attached to the wheels. The shift lever (not shown) moves the friction wheel along the shaft to change the “gear ratio” setting the ground speed, with five positions to the right of the plate center going forward and two on the left going in reverse.

It’s a modern implementation of the classic Lambert friction drive transmission from a century ago. Cheap, effective, nothing wrong with it other than requiring regular inspection and preventive maintenance.

Unfortunately, the rubber tire seems undersized for the task and had completely worn away, leaving its steel rim to chew on the drive plate:

Snowthrower friction wheel - scarred drive plate
Snowthrower friction wheel – scarred drive plate

Of course, you’re supposed to inspect the situation more regularly than I (and, most likely, anyone) ever have. I vaguely recall replacing the tire once before and, being that type of guy, ordered two to have a spare on the shelf. Anyhow, it was in fine shape the last time I checked to see what shape it was in.

The manual recommends loosening (but not removing) the hex nut on the left side of the gear shaft:

Snowthrower drive gear shaft bearing
Snowthrower drive gear shaft bearing

Then “lightly tap the hex nut to dislodge the ball bearing”. Well, it’s a nylon lock nut, not a plain hex nut, which means pounding the crimp holding the nylon ring on the nut will destroy it. I whacked the end of the shaft with a plastic hammer to no avail, removed the nut & washer, and gave it a few careful shots with a 2 lb ball peen hammer, also to no avail.

The basic problem comes down to having the bearing mounted in what’s basically a sheet metal wall of no particular substance: banging on the shaft deflects the wall and moves the bearing along with the shaft. As far as I could tell, the shaft was stuck inside the bearing race, so I soaked it in pentrating oil while pondering the next step overnight.

A few more shots with the hammer convinced me that wasn’t going to work and would likely damage the threads, so I made a pair of Special Service Tools:

Snowthrower friction wheel - homebrew removal tools
Snowthrower friction wheel – homebrew removal tools

The smaller one fits around the threaded end of the shaft and inside the inner race to apply the impact directly to the shaft instead of the threads. The larger one fits on the inner race itself, in the expectation I would need to persuade it, but it wasn’t necessary. They both started life as iron pipe, covered in what looks like aluminumized paint for no reason we’ll ever know, and faced in the lathe.

The combination of penetrating oil, a proper SST, and some diligent whacking popped the shaft out of the bearing without damage. The friction wheel assembly then slid off the shaft with no resistance and the shaft and right-side bearing slid easily out of the frame. Once in the shop, gentle filing knocked the rust & burrs off the shaft and let it slide freely into the bearing.

The friction wheel clamps the tire with six bolts, three from each side so MTD can use a single part number for the halves:

Snowthrower friction wheel - screw pattern
Snowthrower friction wheel – screw pattern

It came apart easily, the new tire went on easily, the drive assembly went back together easily, and the blower cleared more than a foot of snow from the driveway:

Mary running snowthrower - 2020-12-17
Mary running snowthrower – 2020-12-17

Nothing can make maneuvering a snowblower easy, alas.

I briefly thought of refacing the drive plate, but I’m pretty sure it comes heartbreakingly close to Tiny Lathe’s limited swing. With two spare tires on the shelf, should the scarred plate chew up the new tire in one season, I’ll make better measurements.

MTD Snowthrower: Replacement Throttle Knob

The throttle knob on our MTD snowthrower (a.k.a. snowblower) cracked apart around its metal shaft when I pulled it upward. A temporary fix involving duct tape and cable ties sufficed to start the engine, although the usual intense vibration shook the knob loose somewhere along the driveway during the next hour.

Update: Found it!

Although I have no photographic evidence, I did make a few quick measurements:

Throttle Knob Dimension Doodles
Throttle Knob Dimension Doodles

It fits an MTD model E6A4E, but I suspect nearly all their engines have identical throttle shafts:

Snowthrower Throttle Knob - stem end - solid model
Snowthrower Throttle Knob – stem end – solid model

The only practical way to build the thing has it standing on the shaft end, surrounded by a brim to improve adhesion, so I added (actually, subtracted) a pair of holes for music-wire reinforcements:

Snowthrower throttle knob - reinforcing wires
Snowthrower throttle knob – reinforcing wires

It definitely has a stylin’ look, next to the original choke control knob:

Snowthrower throttle knob - installed
Snowthrower throttle knob – installed

I omitted the finger grip grooves for obvious reasons.

The slot-and-hole came out slightly smaller than the metal shaft and, rather than wait for epoxy to cure, I deployed a 230 W soldering gun (not a piddly temperature-controlled iron suitable for electronics) on the shaft and melted it into the knob.

More snow may arrive this week and I printed another knob just in case …

The OpenSCAD source code as a GitHub Gist:

// MTD Snowthrower Throttle Knob
// Ed Nisley KE4ZNU 2020-12-18
/* [Options] */
Layout = "Show"; // [Build, Show]
// Extrusion parameters
/* [Hidden] */
ThreadThick = 0.25;
ThreadWidth = 0.40;
HoleWindage = 0.2;
Protrusion = 0.1; // make holes end cleanly
inch = 25.4;
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
// Dimensions
Throttle = [17.0,1.85,6.5]; // blade insertion, thickness, width
PaddleSize = [25,30,9];
PaddleRound = 4.0;
PaddleThick = 8.5;
StemDia = 13.0;
StemLength = 20.0;
PinDia = 1.6;
PinLength = PaddleSize.x + StemLength/2;
echo(str("Pin: ",PinLength," x ",PinDia," mm"));
// Useful routines
module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes
Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2);
FixDia = Dia / cos(180/Sides);
cylinder(r=(FixDia + HoleWindage)/2,
// Pieces
module Paddle() {
difference() {
hull() {
translate([PaddleSize.x/2,0,0]) {
for (i=[-1,1], j=[-1,1])
translate([i*(PaddleSize.x - PaddleRound)/2,j*(PaddleSize.y - PaddleRound)/2,0])
rotate([0,90,0]) rotate(180/12)
rotate([0,90,0]) rotate(180/12)
translate([-(StemLength + Protrusion),0,0])
rotate([0,90,0]) rotate(0*180/6)
for (j=[-1,1])
rotate([0,90,0]) rotate(180/4)
// Build it
if (Layout == "Show")
if (Layout == "Build") {