Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions designs/guitar_tuning_machine_head/family.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"family": "guitar_tuning_machine_head",
"standard": null,
"base_plane": "XY",
"description": "Sealed geared guitar tuning machine (Grover Rotomatic style): baseplate, sealed gear housing, string post with press-in bushing collar, worm/key shaft out the housing side, and a locating-screw hole. One solid.",
"source": "Grover Rotomatic 102 + Gotoh SG381 dimensioned drawings (post/bushing/housing/mount); proportion for housing depth and key shaft",
"contributor": "BenchCAD-org"
}
50 changes: 50 additions & 0 deletions designs/guitar_tuning_machine_head/part.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""guitar_tuning_machine_head — the parametric part.

A sealed geared guitar tuning machine (Grover Rotomatic style): a baseplate that
sits against the headstock rear, a sealed gear housing behind it, a string post
standing up through the peg-hole with a press-in bushing collar at its base, a
worm/key shaft out the side of the housing, and a small locating-screw hole in
the baseplate. Built in one piece (as cast + assembled), a single solid.

Interface + examples: docs/DESIGN_SPEC.md
"""

import cadquery as cq


def build(baseplate_l, baseplate_w, plate_t, housing_w, housing_h,
post_d, post_h, bushing_od, worm_d, mount_d, worm_both_sides):
# baseplate against the headstock, centred at z=0
result = cq.Workplane("XY").box(baseplate_l, baseplate_w, plate_t)

# sealed gear housing behind the baseplate (-Z)
result = result.union(
cq.Workplane("XY").box(housing_w, baseplate_w * 0.85, housing_h)
.translate((0.0, 0.0, -(plate_t / 2.0 + housing_h / 2.0)))
)

# string post up through the peg-hole, with the press-in bushing collar
result = result.union(
cq.Workplane("XY").workplane(offset=plate_t / 2.0).circle(post_d / 2.0).extrude(post_h)
)
result = result.union(
cq.Workplane("XY").workplane(offset=plate_t / 2.0).circle(bushing_od / 2.0).extrude(plate_t * 0.7)
)

# worm / key shaft out the side of the housing (one side, or both)
z_house = -(plate_t / 2.0 + housing_h / 2.0)
reach = baseplate_w * 0.9
shaft = cq.Workplane("XZ").circle(worm_d / 2.0).extrude(reach) # -Y direction
shaft = shaft.translate((0.0, baseplate_w * 0.3, z_house))
result = result.union(shaft)
if worm_both_sides:
shaft2 = cq.Workplane("XZ").circle(worm_d / 2.0).extrude(-reach) # +Y direction
shaft2 = shaft2.translate((0.0, -baseplate_w * 0.3, z_house))
result = result.union(shaft2)

# locating-screw hole near the +X end of the baseplate
mount_x = baseplate_l / 2.0 - mount_d - 2.0
hole = cq.Workplane("XY").circle(mount_d / 2.0).extrude(200.0).translate((mount_x, 0.0, -100.0))
result = result.cut(hole)

return result
Binary file added designs/guitar_tuning_machine_head/preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
121 changes: 121 additions & 0 deletions designs/guitar_tuning_machine_head/spec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
"""guitar_tuning_machine_head — the benchmark generator spec.

A sealed geared guitar tuning machine (Grover Rotomatic / Gotoh SG381 style).
PARAM_SPEC declares each build() parameter; check() holds the engineering rules
a reviewer audits. Nothing is coupled, so there is no refine().
Spec: docs/DESIGN_SPEC.md

Sources:
- Grover Rotomatic 102 dimensioned drawing (WD Music): post Ø6, bushing Ø7.8-9.9,
M8 bushing thread, housing ~27 x 24 mm, post height ~27 mm, mount screw Ø2.6.
- Gotoh SG381 drawing: post Ø6, hex bushing OD 14 mm, housing ~27 x 22 mm.
- Gear ratio (14:1-18:1) is internal and not a CAD dimension here.
"""


# ── 1. PARAM_SPEC ────────────────────────────────────────────────────────────
PARAM_SPEC = {
"baseplate_l": dict(
desc="baseplate length (along the string line)",
unit="mm",
range={"easy": (25.0, 30.0), "medium": (22.0, 38.0), "hard": (20.0, 45.0)},
source="Grover/Gotoh housing footprint ~27 mm -> proportion",
askable=True,
),
"baseplate_w": dict(
desc="baseplate width",
unit="mm",
range={"easy": (12.0, 15.0), "medium": (11.0, 16.0), "hard": (10.0, 18.0)},
source="Grover baseplate ~13-15 mm -> proportion",
askable=True,
),
"plate_t": dict(
desc="baseplate thickness",
unit="mm",
range={"easy": (1.2, 2.0), "medium": (1.0, 2.5), "hard": (1.0, 3.0)},
source="proportion (die-cast baseplate)",
askable=True,
),
"housing_w": dict(
desc="gear-housing width",
unit="mm",
range={"easy": (18.0, 24.0), "medium": (15.0, 26.0), "hard": (14.0, 28.0)},
source="Grover/Gotoh sealed housing ~24-27 mm -> proportion",
askable=True,
),
"housing_h": dict(
desc="gear-housing depth behind the baseplate",
unit="mm",
range={"easy": (12.0, 18.0), "medium": (10.0, 20.0), "hard": (10.0, 24.0)},
source="proportion (sealed worm-gear housing depth)",
askable=True,
),
"post_d": dict(
desc="string-post diameter",
unit="mm",
range={"easy": (5.8, 6.3), "medium": (5.5, 6.5), "hard": (5.5, 6.5)},
source="Grover 6.0 / Grover Super 6.3 / Gotoh 6.0 mm",
askable=True,
),
"post_h": dict(
desc="string-post height above the baseplate",
unit="mm",
range={"easy": (24.0, 28.0), "medium": (18.0, 30.0), "hard": (15.0, 32.0)},
source="Grover post height ~27 mm -> proportion",
askable=True,
),
"bushing_od": dict(
desc="press-in bushing collar outer diameter",
unit="mm",
range={"easy": (7.5, 10.0), "medium": (7.0, 14.0), "hard": (7.0, 15.0)},
source="Grover Ø7.8 / Ø9.9 collar; Gotoh Ø14 hex bushing",
askable=True,
),
"worm_d": dict(
desc="worm / key-shaft diameter",
unit="mm",
range={"easy": (5.0, 7.0), "medium": (4.0, 8.0), "hard": (4.0, 9.0)},
source="proportion (worm-gear key shaft)",
askable=True,
),
"mount_d": dict(
desc="locating-screw hole diameter",
unit="mm",
range={"easy": (2.4, 2.8), "medium": (2.0, 3.2), "hard": (2.0, 3.5)},
source="Grover mounting screw Ø2.6 mm",
askable=True,
),
"worm_both_sides": dict(
desc="key shaft exits both sides of the housing (1) vs one side (0)",
unit="",
range={"easy": (0, 0), "medium": (0, 1), "hard": (0, 1)},
source="in-line (both-sides) vs single-side key-shaft variants",
choices={"easy": [0], "medium": [0, 1], "hard": [0, 1]},
feature=True,
),
}


# ── 2. check ─────────────────────────────────────────────────────────────────
def check(p: dict) -> list[str]:
"""Engineering constraints (empty = valid). Each cites its rule."""
bad = []

# bushing must surround the post with a wall, and fit on the baseplate
if p["bushing_od"] < p["post_d"] + 1.5:
bad.append("bushing_od < post_d+1.5: bushing collar must surround the post with wall")
if p["bushing_od"] > p["baseplate_w"] - 1.0:
bad.append("bushing_od > baseplate_w-1: bushing wider than the baseplate")

# housing sits on the baseplate; worm fits inside the housing depth
if p["housing_w"] > p["baseplate_l"]:
bad.append("housing_w > baseplate_l: gear housing overhangs the baseplate")
if p["worm_d"] > p["housing_h"] - 2.0:
bad.append("worm_d > housing_h-2: key shaft does not fit the housing depth")

# the locating-screw hole (near the +X end) must clear the bushing collar
mount_x = p["baseplate_l"] / 2.0 - p["mount_d"] - 2.0
if mount_x - p["mount_d"] / 2.0 < p["bushing_od"] / 2.0 + 2.0:
bad.append("mount hole overlaps the bushing: baseplate too short for the collar + screw")

return bad
Loading