"""Jaw coupling, clamping type. Axis along Z, the first hub's end face on the XY plane, bore d1 in the first hub, bore d2 in the second. Two hubs and a spacer, three bodies. Fit dimensions from MISUMI's table; see the README.""" import math import cadquery as cq from steve import Model size = 20 # mm Outside diameter D d1 = 5 # mm Bore 1 (d1 <= d2) d2 = 8 # mm Bore 2 detail = "full" # full: jaws, slits and clamp screw holes; simple: plain cylinder with the bores # D: (L, hub length l, spacer B, gap C, screw from the end F, screw offset G, clamp screw M, bores offered). # MISUMI Couplings catalogue, Jaw Couplings, Clamping, CPJC table, https://de.misumi-ec.com/files/images/products/docs/flexibleshaftcouplings.pdf, PDF p. 20. SIZES = { 14: (22, 7, 6, 1, 3.5, 4, 2, (3, 4, 5)), 20: (30, 10, 8, 1, 5, 6.5, 2.5, (5, 6, 6.35, 7, 8)), 30: (35, 11, 10, 1.5, 5.5, 10, 4, (7, 8, 9.525, 10, 11, 12)), } L, hub, spacer_h, gap, screw_at, screw_off, screw, bores = SIZES[size] if d1 not in bores or d2 not in bores or d1 > d2: raise ValueError(f"The {size} mm jaw coupling offers bores {bores}, with d1 <= d2.") R = size / 2 SLIT = 0.05 * size # the slit's width, the jaws' width and inner radius, and the spacer's shape are proportions, for looks JAW = 40 INNER = 0.45 * R def sector(angle, spread, inner, outer, z0, height): """A sector of a ring, spread degrees wide.""" a, b, c = (math.radians(angle + t) for t in (-spread / 2, 0, spread / 2)) return (cq.Workplane("XY").workplane(offset=z0).moveTo(inner * math.cos(a), inner * math.sin(a)).lineTo(outer * math.cos(a), outer * math.sin(a)) .threePointArc((outer * math.cos(b), outer * math.sin(b)), (outer * math.cos(c), outer * math.sin(c))) .lineTo(inner * math.cos(c), inner * math.sin(c)).threePointArc((inner * math.cos(b), inner * math.sin(b)), (inner * math.cos(a), inner * math.sin(a))).close().extrude(height)) def half(z0, first_angle, bore, slit_z0): """One hub with its three jaws, from z0 for a hub length, the jaws reaching across the spacer.""" near, far = (hub, hub + gap) if first_angle == 0 else (hub + gap, hub) shape = cq.Workplane("XY").workplane(offset=z0).circle(R).extrude(hub) for k in range(3): shape = shape.union(sector(first_angle + 120 * k, JAW, 1.1 * INNER, R, near, L - 2 * hub - gap), clean=False) shape = shape.cut(cq.Workplane("XY").workplane(offset=slit_z0).center(R / 2 + 0.5, 0).rect(R + 1, SLIT).extrude(hub + 1)) shape = shape.cut(cq.Workplane("XY").workplane(offset=z0 - 1).circle(bore / 2).extrude(hub + 2)) return shape model = Model() if detail == "simple": body = cq.Workplane("XY").circle(R).extrude(L) body = body.cut(cq.Workplane("XY").workplane(offset=-1).circle(d1 / 2).extrude(L / 2 + 1)) body = body.cut(cq.Workplane("XY").workplane(offset=L / 2).circle(d2 / 2).extrude(L / 2 + 1)) model.add("body", body, name="Jaw coupling") model.material("aluminum-generic", color="#c9ccd1") else: first = half(0, 0, d1, -1) second = half(L - hub, 60, d2, L - hub) for z in (screw_at, L - screw_at): cross = cq.Workplane("YZ").center(screw_off, z).circle(screw / 2).extrude(R + 1, both=True) first, second = first.cut(cross), second.cut(cross) spacer = cq.Workplane("XY").workplane(offset=hub + gap).circle(INNER).circle(d2 / 2 + 0.3).extrude(spacer_h) for k in range(6): spacer = spacer.union(sector(30 + 60 * k, 60 - JAW - 2, 0.9 * INNER, R * 0.82, hub + gap, spacer_h), clean=False) model.add("hub_1", first, op="new", body="hub_1_body", name="Hub, d1") model.add("hub_2", second, op="new", body="hub_2_body", name="Hub, d2") model.add("spacer", spacer, op="new", body="spacer_body", name="Spacer") model.material("aluminum-generic", bodies=["hub_1_body", "hub_2_body"], color="#c9ccd1") model.material("tpu-98a", bodies=["spacer_body"], color="#c8362e") result = model.result()