Skip to content

Instantly share code, notes, and snippets.

@relistan
Created April 24, 2026 20:51
Show Gist options
  • Select an option

  • Save relistan/f004b4b852eccdd98c984c8a83c6ceff to your computer and use it in GitHub Desktop.

Select an option

Save relistan/f004b4b852eccdd98c984c8a83c6ceff to your computer and use it in GitHub Desktop.
3D Printed Reduction Drive for Variable Capacitors
// Reduction Drive © 2026 by Karl Matthias is licensed under CC BY-SA 4.0. To
// view a copy of this license, visit
// https://creativecommons.org/licenses/by-sa/4.0/
// 5:1 Reduction for Variable Capacitor
// Herringbone gears with adjustable center distance for anti-backlash
/* [Gear Parameters] */
gear_module = 0.9; // Gear module (mm)
pinion_teeth = 12; // Pinion tooth count
gear_teeth = 60; // Driven gear tooth count (5:1 ratio)
pressure_angle = 20; // Degrees
helix_angle = 30; // Herringbone helix angle (degrees)
gear_width = 10; // Total herringbone width (mm)
apex_gap = 0; // No gap — solid herringbone
/* [Shaft Parameters] */
cap_shaft_dia = 9.53; // Capacitor shaft diameter (mm)
axle_dia = 5.0; // Fixed axle for pinion (5mm stainless rod)
bearing_oversize = 0.4; // Diametral clearance where pinion rotates on axle (FDM needs ~0.2mm/side)
pillar_clearance = 0.2; // Diametral clearance where axle sits in pillar (snug but insertable)
snug_tolerance = 0.05; // Per-side tolerance for press/snug fits
knob_stub_dia = 6.35; // D-shaft stub on pinion for standard pot knob
knob_stub_length = 15; // Length of knob stub
d_flat_depth = 1.0; // D-flat cut depth on knob stub
/* [Platform Parameters] */
shaft_height = 30.63; // Capacitor shaft center height from mounting surface
base_thickness = 5; // Platform base plate thickness
pillar_wall = 4; // Bearing pillar wall thickness
mount_hole_dia = 4.2; // M4 mounting screw clearance
base_margin = 10; // Extra base material around pillars
/* [Print Tuning] */
print_clearance = 0.1; // Extra root clearance for FDM (mm)
$fn = 96;
// =============================================
// Derived values
// =============================================
pinion_pitch_r = pinion_teeth * gear_module / 2;
gear_pitch_r = gear_teeth * gear_module / 2;
center_distance = pinion_pitch_r + gear_pitch_r;
cap_gear_bore = cap_shaft_dia + snug_tolerance * 2; // Driven gear bore (snug on shaft)
cap_pillar_bore = cap_shaft_dia + 0.4; // Loose pass-through (cap bearings locate the shaft)
axle_bore = axle_dia + bearing_oversize; // Pinion bore (rotates freely on axle)
axle_press = axle_dia + pillar_clearance; // Pillar bore (snug on axle, doesn't rotate)
cap_pillar_od = cap_pillar_bore + pillar_wall * 2;
knob_pillar_od = axle_press + pillar_wall * 2;
slot_travel = 6.0; // End travel (mm) for tensioner clamp plate
clamp_l = knob_pillar_od + 9; // Clamp plate length (X) — accommodates pillar + screws
clamp_w = knob_pillar_od + 4; // Clamp plate width (Y)
gear_outer_r = gear_pitch_r + gear_module;
pinion_outer_r = pinion_pitch_r + gear_module;
// Pillar height: short bearing surface so the capacitor shaft
// reaches well into the gear (19.5mm shaft protrusion).
pillar_height = 5;
// =============================================
// Involute math
// =============================================
// Point on involute of base circle rb at roll angle t (degrees)
function inv_pt(rb, t) =
let(tr = t * PI / 180)
[ rb * (cos(t) + tr * sin(t)),
rb * (sin(t) - tr * cos(t)) ];
// Roll angle (degrees) when the involute reaches radius r
function inv_roll(rb, r) =
sqrt(pow(r / rb, 2) - 1) * 180 / PI;
// Rotate 2D point by angle a (degrees)
function r2(p, a) =
[ p[0] * cos(a) - p[1] * sin(a),
p[0] * sin(a) + p[1] * cos(a) ];
// =============================================
// 2D involute gear profile
//
// Each tooth polygon traces the involute flanks directly.
// Right flank uses the mirrored involute (curves CW → converges
// toward tooth center going outward). Left flank uses the normal
// involute (curves CCW → also converges). Result: teeth are wide
// at the root and taper toward the tip.
// =============================================
module gear_2d(teeth, mod, pa) {
pr = teeth * mod / 2;
br = pr * cos(pa);
ar = pr + mod;
rr = max(pr - 1.25 * mod - print_clearance, 0.5);
n = 24; // points per involute flank
// Roll angle range
t_start = (br > rr) ? 0 : inv_roll(br, rr);
t_outer = inv_roll(br, ar);
// Centering rotation: places the tooth symmetrically about
// the x-axis with correct thickness at the pitch circle
t_pitch = inv_roll(br, pr);
pp = inv_pt(br, t_pitch);
theta_p = atan2(pp.y, pp.x);
half_tooth = 90 / teeth;
rot = half_tooth + theta_p;
union() {
// Root body
circle(r = rr);
// Teeth
for (i = [0 : teeth - 1])
rotate([0, 0, i * 360 / teeth])
polygon(concat(
// Radial line from root to base circle (right side)
(br > rr) ? [
[rr * cos(rot), rr * sin(rot)]
] : [],
// Right flank: mirrored involute rotated by +rot
// (curves CW going outward → tooth tapers)
[for (s = [0 : n])
let(t = t_start + (t_outer - t_start) * s / n)
let(p = inv_pt(br, t))
r2([p[0], -p[1]], rot)
],
// Tip arc at addendum
[for (s = [1 : 3])
let(rp = inv_pt(br, t_outer))
let(rt = r2([rp[0], -rp[1]], rot))
let(a_right = atan2(rt.y, rt.x))
let(lt = r2(rp, -rot))
let(a_left = atan2(lt.y, lt.x))
let(a = a_right + (a_left - a_right) * s / 4)
[ar * cos(a), ar * sin(a)]
],
// Left flank: normal involute rotated by -rot
// (curves CCW going outward → tooth tapers)
[for (s = [n : -1 : 0])
let(t = t_start + (t_outer - t_start) * s / n)
r2(inv_pt(br, t), -rot)
],
// Radial line from base circle to root (left side)
(br > rr) ? [
[rr * cos(-rot), rr * sin(-rot)]
] : []
));
}
}
// =============================================
// Herringbone gear — two mirrored helical halves
//
// hand = 1 or -1 controls helix direction.
// Meshing gears MUST have opposite hands.
// =============================================
module herringbone_gear(teeth, mod, pa, ha, width, bore_dia, hand = 1) {
half_w = (width - apex_gap) / 2;
pr = teeth * mod / 2;
twist_deg = hand * 360 * half_w * tan(ha) / (2 * PI * pr);
difference() {
union() {
// Top half: extrudes upward from center
translate([0, 0, width / 2 + apex_gap / 2])
linear_extrude(height = half_w, twist = twist_deg,
convexity = 10, slices = 24)
gear_2d(teeth, mod, pa);
// Bottom half: mirror with SAME twist — the mirror
// reverses the helix direction, creating the V
translate([0, 0, width / 2 - apex_gap / 2])
mirror([0, 0, 1])
linear_extrude(height = half_w, twist = twist_deg,
convexity = 10, slices = 24)
gear_2d(teeth, mod, pa);
}
// Center bore
translate([0, 0, -1])
cylinder(d = bore_dia, h = width + 2);
}
}
// =============================================
// Gear parts
// =============================================
module driven_gear() {
color("SteelBlue")
herringbone_gear(gear_teeth, gear_module, pressure_angle,
helix_angle, gear_width, cap_gear_bore, hand = 1);
}
stub_flare_h = 2; // Flared boss height bridging gear top to stub
module pinion() {
color("Orange") {
// Gear body — rotates on the fixed 5mm axle
herringbone_gear(pinion_teeth, gear_module, pressure_angle,
helix_angle, gear_width, axle_bore, hand = -1);
// Flared boss — cone from full gear OD down to stub OD, so the
// stub grips the whole gear top face instead of just the thin
// ring between the axle bore and the stub radius.
translate([0, 0, gear_width])
cylinder(d1 = 2 * pinion_outer_r,
d2 = knob_stub_dia,
h = stub_flare_h);
// D-shaft stub on top face for knob mounting
translate([0, 0, gear_width + stub_flare_h])
difference() {
cylinder(d = knob_stub_dia, h = knob_stub_length);
// D-flat so standard pot knobs grip
translate([knob_stub_dia / 2 - d_flat_depth,
-knob_stub_dia / 2 - 1, -1])
cube([d_flat_depth + 1, knob_stub_dia + 2,
knob_stub_length + 2]);
}
}
}
// =============================================
// Platform parts
// =============================================
// Bearing pillar with reinforcement flange
module bearing_pillar(bore_dia, outer_dia, height) {
color("SlateGray")
difference() {
union() {
cylinder(d = outer_dia, h = height);
cylinder(d = outer_dia + 4, h = min(3, height));
}
translate([0, 0, -1])
cylinder(d = bore_dia, h = height + 2);
}
}
// Mounting face parameters — vertical wall along the -Y long side of
// the base, with holes going through in Y so the whole assembly bolts
// flat to a wooden board (shared with the capacitor).
bracket_face_thick = 5; // Thin — buttresses at the outer X edges reinforce
bracket_face_height = shaft_height + 15;
mount_hole_margin = 8; // Margin from bracket edge to mounting hole center
gear_clearance = 3; // Swing clearance around driven gear
gusset_thick = 4; // X thickness of each buttress
gusset_y_depth = 12; // How far the buttress reaches into the drive
gusset_z_tall = 22; // Buttress height on the bracket inner face
module pinion_pillar_assembly() {
// Push tab — must stay below the gear bottom to avoid interference.
// Gear bottom is at base_thickness + pillar_height.
tab_width = 10;
tab_height = base_thickness + pillar_height - 1; // 1mm below gear
tab_thick = 4;
// Clamp plate slides in the base slot
color("DarkGray")
difference() {
union() {
// Main clamp plate
translate([-clamp_l / 2, -clamp_w / 2, 0])
cube([clamp_l, clamp_w, base_thickness]);
// Push tab on the back face for the adjustment screw
translate([clamp_l / 2 - tab_thick, -tab_width / 2, 0])
cube([tab_thick, tab_width, tab_height]);
}
// M3 clamping screw holes
for (dx = [-clamp_l / 2 + 4, clamp_l / 2 - 4])
translate([dx, 0, -1])
cylinder(d = 3.4, h = base_thickness + 2);
}
// Pillar on top of clamp plate — press-fit bore holds the 5mm axle
translate([0, 0, base_thickness])
bearing_pillar(axle_press, knob_pillar_od, pillar_height);
}
/* [Adjustment Screw] */
adjust_screw_pilot = 3.5; // M4 pilot hole for self-tapping into PLA
thrust_wall_thick = 12; // Thrust wall thickness
// Screw and push tab must be BELOW the gear bottom to clear it.
// Gear bottom is at base_thickness + pillar_height = 10mm.
adjust_screw_z = base_thickness + pillar_height / 2; // Centered in pillar zone
thrust_wall_height = adjust_screw_z + adjust_screw_pilot + 6; // Enough material around the screw
module platform_base() {
knob_x = center_distance;
// Base plate — extends from past the driven gear to the thrust wall.
// y_half = shaft_height puts the cap-shaft axis exactly shaft_height
// above the bracket's outer face (the surface that lies on the board).
x_min = -(gear_outer_r + 10);
y_half = shaft_height;
plate_wid = y_half * 2;
// Slot geometry — snug fit on the sides, slot_travel of end play
slot_w = clamp_w + 0.4;
slot_x = knob_x - clamp_l / 2;
slot_len = clamp_l + slot_travel;
thrust_x = slot_x + slot_len;
x_max = thrust_x + thrust_wall_thick;
color("SlateGray")
difference() {
union() {
// Base plate — full extent
translate([x_min, -y_half, 0])
cube([x_max - x_min, plate_wid, base_thickness]);
// Cap shaft bearing pillar at x=0
translate([0, 0, base_thickness]) {
cylinder(d = cap_pillar_od, h = pillar_height);
cylinder(d = cap_pillar_od + 4, h = 3);
}
// Mounting face — vertical wall along the -Y long side,
// spanning the full X length of the base plate. When the
// assembly is laid on the wooden board, this face is the
// one that sits against the board.
translate([x_min, -y_half, 0])
cube([x_max - x_min, bracket_face_thick,
bracket_face_height]);
// Buttresses at the outer X edges — triangular gussets from
// base plate top up the bracket inner face.
for (bx = [x_min, x_max - gusset_thick])
translate([bx, 0, 0])
rotate([90, 0, 90])
linear_extrude(height = gusset_thick)
translate([-y_half + bracket_face_thick,
base_thickness])
polygon([[0, 0],
[gusset_y_depth, 0],
[0, gusset_z_tall]]);
// Thrust wall at far right for adjustment screw
translate([thrust_x, -slot_w / 2 - 3, 0])
cube([thrust_wall_thick, slot_w + 6, thrust_wall_height]);
}
// Cap shaft bore through pillar and base plate
translate([0, 0, -1])
cylinder(d = cap_pillar_bore, h = base_thickness + pillar_height + 2);
// Swing clearance for the driven gear — rectangular slot through
// the bracket face, from the bottom up past the gear top, wide
// enough for the gear to rotate freely.
cutout_x_half = sqrt(pow(gear_outer_r, 2)
- pow(y_half - bracket_face_thick, 2))
+ gear_clearance;
translate([-cutout_x_half, -y_half - 0.5, -0.5])
cube([2 * cutout_x_half,
bracket_face_thick + 1,
base_thickness + pillar_height + gear_width
+ gear_clearance + 0.5]);
// 4x mounting holes through the bracket face (along Y). Three
// are at the standard corner positions; the bottom-right is
// shifted inward so the +X buttress doesn't block screwdriver
// access.
mount_positions = [
[x_min + mount_hole_margin,
base_thickness + mount_hole_margin], // bottom-left
[x_min + mount_hole_margin,
bracket_face_height - mount_hole_margin], // top-left
[x_max - mount_hole_margin,
bracket_face_height - mount_hole_margin], // top-right
[x_max - gusset_thick - 12,
base_thickness + mount_hole_margin] // bottom-right (shifted)
];
for (p = mount_positions)
translate([p[0], -y_half - 1, p[1]])
rotate([-90, 0, 0])
cylinder(d = mount_hole_dia,
h = bracket_face_thick + 2);
// Slot for pinion pillar adjustment
translate([slot_x, -slot_w / 2, -1])
cube([slot_len, slot_w, base_thickness + 2]);
// Adjustment screw pilot hole centered in thrust wall
translate([thrust_x - 1, 0, adjust_screw_z])
rotate([0, 90, 0])
cylinder(d = adjust_screw_pilot, h = thrust_wall_thick + 2);
}
}
// =============================================
// Assembly (preview)
// =============================================
module assembly() {
gear_bottom_z = base_thickness + pillar_height;
// Platform: base plate, cap pillar, mounting face, thrust wall
platform_base();
// Driven gear on capacitor shaft
translate([0, 0, gear_bottom_z])
driven_gear();
// Pinion pillar on adjustable clamp plate
translate([center_distance, 0, 0])
pinion_pillar_assembly();
// Pinion with D-shaft knob stub
translate([center_distance, 0, gear_bottom_z])
rotate([0, 0, 180 / pinion_teeth])
pinion();
// Visual shafts (translucent)
%cylinder(d = cap_shaft_dia, h = shaft_height + gear_width);
%translate([center_distance, 0, 0])
cylinder(d = axle_dia, h = shaft_height + gear_width);
}
// =============================================
// Print layout — all parts laid flat on the bed
// =============================================
module print_layout() {
spacing = 10;
platform_y_half = shaft_height;
// Driven gear
driven_gear();
// Pinion (with knob stub pointing up)
translate([gear_outer_r + pinion_outer_r + spacing, 0, 0])
pinion();
// Base plate with thrust wall
translate([0, -(gear_outer_r + platform_y_half + spacing), 0])
platform_base();
// Pinion pillar assembly
translate([-(gear_outer_r + spacing + 20),
0, 0])
pinion_pillar_assembly();
}
// =============================================
// Render — uncomment one
// =============================================
//assembly();
print_layout();
// driven_gear();
// pinion();
// platform_base();
// pinion_pillar_assembly();
@relistan
Copy link
Copy Markdown
Author

Reduction Drive for Variable Capacitors

See the blog post at https://ei9itb.com/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment