"""Grooved pulley for classical and narrow V-belts (ISO 4183): a solid pulley with one or more grooves and a plain bore, axis along Z, the first face on the XY plane. The groove profile, its spacing and the groove angle follow the standard's tables for the section and the datum diameter. Dimensions from ISO 4183:1995, listed in the README.""" import math from steve import Model section = "A" # Groove profile: Y, Z, A, B, C, D, E (classical) or SPZ, SPA, SPB, SPC (narrow) datum_diameter = 94.5 # mm Datum diameter dd (the outside diameter is dd + 2 b) grooves = 1 # Number of grooves bore = 10.0 # mm Bore diameter material = "cast-iron-en-gjl-200" # Material # ISO 4183:1995 "Belt drives - Classical and narrow V-belts - Grooved pulleys (system based on datum width)", third edition 1995-07-01. # Table 2 (with table 1's datum widths): wd, b min, h min, e, f min in mm. Narrow sections share their classical twin's wd, b, e and f and # have a deeper h. GROOVES = { "Y": (5.3, 1.6, 4.7, 8, 6), "Z": (8.5, 2, 7, 12, 7), "SPZ": (8.5, 2, 9, 12, 7), "A": (11, 2.75, 8.7, 15, 9), "SPA": (11, 2.75, 11, 15, 9), "B": (14, 3.5, 10.8, 19, 11.5), "SPB": (14, 3.5, 14, 19, 11.5), "C": (19, 4.8, 14.3, 25.5, 16), "SPC": (19, 4.8, 19, 25.5, 16), "D": (27, 8.1, 19.9, 37, 23), "E": (32, 9.6, 23.4, 44.5, 28), } # Table 4: the groove angle in degrees by datum diameter: (largest dd for the smaller angle, smaller angle, larger angle). Y: 32° up to # dd 60, 36° above; D and E: 36° up to 475 and 600, 38° above; the rest 34° up to the limit, 38° above. ANGLES = { "Y": (60, 32, 36), "Z": (80, 34, 38), "SPZ": (80, 34, 38), "A": (118, 34, 38), "SPA": (118, 34, 38), "B": (190, 34, 38), "SPB": (190, 34, 38), "C": (315, 34, 38), "SPC": (315, 34, 38), "D": (475, 36, 38), "E": (600, 36, 38), } # Table 5: the smallest datum diameter, mm. MIN_DATUM = {"Y": 20, "Z": 50, "A": 75, "B": 125, "C": 200, "D": 355, "E": 500, "SPZ": 63, "SPA": 90, "SPB": 140, "SPC": 224} MATERIALS = {"cast-iron-en-gjl-200": "#6f7378", "steel-c45e": "#8d9196", "aluminum-6061-t6": "#c9ccd0"} if section not in GROOVES: raise ValueError(f"no groove profile {section!r}: {', '.join(GROOVES)}") wd, b, h, e, f = GROOVES[section] if datum_diameter < MIN_DATUM[section]: raise ValueError(f"ISO 4183 table 5: a {section} pulley's datum diameter is at least {MIN_DATUM[section]} mm") if grooves < 1 or grooves != int(grooves): raise ValueError("grooves is a whole number, at least 1") limit, small, large = ANGLES[section] alpha = small if datum_diameter <= limit else large outside = datum_diameter + 2 * b root = datum_diameter - 2 * h # The bore must leave at least 1 mm of wall under the groove bottoms (a proportion; the standard gives no hub or bore). if bore <= 0 or bore > root - 2: raise ValueError(f"bore: up to {root - 2:.1f} mm for a {section} groove at datum Ø {datum_diameter} (groove bottom Ø {root:.1f})") if material not in MATERIALS: raise ValueError(f"material: one of {', '.join(MATERIALS)}") width = (grooves - 1) * e + 2 * f # face width: f from each face to the nearest groove's centre, e between grooves t = math.tan(math.radians(alpha / 2)) top = wd + 2 * b * t # groove width at the outside diameter bottom = wd - 2 * h * t # groove width at its bottom (drawn flat) model = Model() outline = [(bore / 2, 0), (outside / 2, 0)] for i in range(grooves): zc = f + i * e outline += [(outside / 2, zc - top / 2), (root / 2, zc - bottom / 2), (root / 2, zc + bottom / 2), (outside / 2, zc + top / 2)] outline += [(outside / 2, width), (bore / 2, width)] with model.sketch("profile", on="XZ", name="Pulley section") as sk: sk.polyline("section", outline, closed=True) model.revolve("pulley", "profile", axis="Z", op="new", body="pulley_body", name="Pulley") model.material(material, color=MATERIALS[material]) result = model.result()