Internal Ratchet

Internal Ratchet render

ratchets/internal_ratchet.pyOBJECT_OT_add_internal_ratchet (object.add_internal_ratchet, "Add Internal Freewheel Ratchet")

A bicycle-freewheel-style mechanism: an outer ring with inward-pointing teeth, an inner hub, and pawl_count pawls mounted on the hub pointing radially outward. CW rotation of the inner hub (viewed from +Z) = LOCK; CCW = FREE — the opposite convention from ratchet_pawl.md's external wheel, see README.md for why.

Shared constants

HOLE_SEGMENTS = 32, RING_SEGMENTS_OUT = 64 (the outer ring's own circle resolution — finer than hole segments since it's the visible outer silhouette), PIVOT_PAD_MM = 2.0.

Some geometry helpers (finalize_mesh_object, build_pawl_profile_points, a variant of create_filled_profile_with_hole) are copied from ratchet_pawl.py — see README.md.

Properties

Ring:

Property Type Default Range Notes
sizing_modeEnumMODULEMODULE / OUTER_DIAMETER
tooth_countInt244–200 (soft)
moduleFloat (mm)2.00.1–20 (soft)
outer_diameter_mmFloat (mm)50.05–500 (soft)
ring_wall_thickness_mmFloat (mm)4.00.5–50 (soft)Radial thickness from outer surface to tooth roots
tooth_depth_autoBoolTruetooth_depth_mm = 0.6 * module
tooth_depth_mmFloat (mm)1.20.1–20 (soft)Only used when auto is off

Hub:

Property Type Default Range Notes
hub_outer_diameter_mmFloat (mm)20.01–200 (soft)Must be smaller than tip diameter minus clearance
bore_diameter_mmFloat (mm)5.00–100 (soft)
bore_compensation_mmFloat (mm)0.0-2.0–2.0 (soft)Added to bore diameter
clearance_mmFloat (mm)0.30–5 (soft)Running gap between hub surface and tooth tips — see README.md. Not a hole compensation.

Pawls:

Property Type Default Range Notes
pawl_countInt3min=1 (hard), soft_max 12The only property in this family (or the gear family) with a hard rather than soft minimum
pawl_arm_length_autoBoolTrueComputes arm length so the tip just reaches the tooth valley
pawl_arm_length_mmFloat (mm)8.01–100 (soft)Only used when auto is off
pawl_arm_width_mmFloat (mm)4.01–30 (soft)
pawl_tip_width_mmFloat (mm)1.50.1–20 (soft)
tip_engagement_depth_mmFloat (mm)0.60–10 (soft)How far the tip projects past the tooth tips into the valley
pivot_hole_diameter_mmFloat (mm)2.00–20 (soft)
pivot_hole_compensation_mmFloat (mm)0.0-2.0–2.0 (soft)

Shared:

Property Type Default Range Notes
width_mmFloat (mm)6.00.5–200 (soft)Shared by ring, hub, and all pawls
parent_under_emptyBoolTrueGroups everything under a FreewheelRatchet empty

Pawl positioning — radial, not tangent-biased

Unlike ratchet_pawl.py's tangent-biased heuristic solve, an internal ratchet's pawls are mounted radially outward from the hub, so the positioning math is much simpler: auto_pawl_arm_length() = max(contact_r - pivot_r, 1.0) where both the pivot and the tip contact point lie on the same radial line through the hub center. No angular bias term is needed.

Pawls are distributed at angle = i * 2*pi/pawl_count + pi/tooth_count — the +pi/tooth_count term is a half-tooth-pitch phase offset, likely so a pawl doesn't spawn straddling a tooth root/tip boundary by coincidence (not explicitly commented in the source, but the pattern is consistent across all pawl_count placements).

Ring teeth: a non-convex boundary needs a different tessellation method

build_inner_teeth_points() produces the same sawtooth pattern as the external wheel's tooth builder, with root/outer radius roles swapped so teeth point inward. But because the inner boundary is non-convex, build_ring_object() can't use bmesh.ops.triangle_fill the way every other ring-shaped generator in this library does — it uses mathutils.geometry.tessellate_polygon instead, with the outer contour wound CCW and the inner (tooth) contour wound CW as a hole. See README.md for why this matters if you're writing a new non-convex ring generator.

Drive/ramp faces per tooth (from the builder's own docstring): drive face root_i -> tip_i (radial, catches the pawl on CW hub rotation); ramp face tip_i -> root_(i+1) (angled chord, pawl slides over it on CCW/FREE rotation).

Validation

validate_freewheel() returns a list of error strings covering: non-positive ring/tip radius, tooth_depth_mm >= ring_inner_r, hub_outer_r >= tip_r - clearance_mm ("Hub outer radius must be < tip radius - clearance — reduce hub diameter or increase ring size"), bore_r >= hub_outer_r, tooth_count < 4, pawl_count < 1, pivot-hole-vs-arm-width, and pawl-arm-length-vs-pivot-hole. draw() shows every returned error at once in an "Issues:" box; execute() re-runs the same full check and cancels (CANCELLED, no self.report() message) if anything comes back non-empty — matching this family's general no-clamping discipline (see README.md).

Output

2 + pawl_count objects per call: FreewheelRing, FreewheelHub, and pawl_count pawls named FreewheelPawl.000FreewheelPawl.%03d (zero-padded). Default pawl_count=3 gives 5 objects. If parent_under_empty, all are parented under a new FreewheelRatchet empty (PLAIN_AXES, sized to ring_outer_r * 0.3). Ring is set active. Success message: "Internal freewheel ratchet: %d teeth, %d pawls, ring Ø %.1f mm".