--- jupyter: description: 'A handwheel as a 3D CAD exercise: a dimensioned drawing to model in planex2d or any CAD system, a solution from a rim and a hub revolved and five spokes whose ends lie on them, a strip times a ring turned around the axis and padded, and the exact volume, mass and center of mass to check a model against.' --- # Handwheel A handwheel turns a spindle by hand, on a valve, a machine table or a press. Its rim and its hub are turned parts, revolved about the axis, and the spokes between them are flat bars in the rim's middle plane. Each spoke's plan is a strip cut to the ring between the hub and the rim, so that its ends lie on them exactly, and the five spokes are one plan turned around the axis. Model the handwheel from the drawing in planex2d or in any CAD system, then check its volume, mass and center of mass against the values at the end of the page. A solution in planex2d follows. ![The handwheel exercise: a dimensioned drawing of a handwheel with a rim, a hub standing out at both faces and five flat spokes, in a front view, a top view and an isometric](../_static/gallery/handwheel.png){.result} ```python import math import netgen.occ as occ import planex as px ``` ```python nbsphinx="hidden" from docs_figures import Row, Views ``` ## The rim and the hub The rim and the hub are rectangles in the front plane, the plane with its normal toward the viewer, $-y$, with $x$ out from the axis and $z$ along it, the origin on the axis in the rim's middle plane. The rim is 140 across outside and 124 inside, 12 wide. The hub is 40 across with a bore of 16, from 10 below the middle plane to 14 above it. Their corners are given, so they are `Rectangle`s from two corners in a `QuickSketch`, and each face is revolved about the $z$ axis (Figure 1): ```python front = px.XZ axis = occ.Axis((0, 0, 0), occ.Z) rim_section = px.QuickSketch(front).Rectangle((62, -6), (70, 6)).Face() # two opposite corners hub_section = px.QuickSketch(front).Rectangle((8, -10), (20, 14)).Face() rim = rim_section.ToOCCFace().Revolve(axis, 360) hub = hub_section.ToOCCFace().Revolve(axis, 360) ``` ```python nbsphinx="hide-input" Row((px.Compound([rim_section, hub_section]), "The rim's and the hub's sections", {}), (rim + hub, "Revolved", {"views": [(rim + hub, "shade"), (rim + hub, "ink")], "angles": (-60, 0, 30)}), caption="The rim and the hub") ``` ## The spokes The spokes are 12 wide and 8 thick, in the rim's middle plane. One spoke's plan is a strip 12 wide along the $x$ axis times the ring between the hub's outside, 20 from the axis, and the rim's inside, 62 from it, their intersection `*`. Its ends are arcs on the hub and on the rim. Turned by 72° four times and united, the five spokes form one plan, padded 4 to both sides of the xy plane (Figure 2): ```python strip = px.QuickSketch((0, -6)).Rectangle(75, 12).Face() ring = px.Circle((0, 0), 62).Face() - px.Circle((0, 0), 20).Face() spoke = (strip * ring).Face() plan = px.Unify([spoke.Rotated((0, 0), 90 + 72 * k) for k in range(5)]) # the first one along +y spokes = px.Pad(plan, 4, length2=4) print("spoke", round(spoke.mass, 4), "mm² in plan") ``` ```python nbsphinx="hide-input" Row((plan, "The spokes' plan between the hub and the rim", {"dashed": [px.Circle((0, 0), 62), px.Circle((0, 0), 20)]}), caption="The spokes") ``` `+` fuses the spokes with the rim and the hub. The spokes' ends lie on them, so they share faces and nothing overlaps (Figure 3): ```python wheel = rim + hub + spokes print("solids", len(wheel.solids)) ``` ```python nbsphinx="hide-input" Views(("The handwheel", [(wheel, "shade"), (wheel, "ink")]), angles=(-60, 0, 30), caption="The handwheel") ``` ## The checks These are the volume, the mass in cast iron EN-GJL-200 (7.2 g/cm³) and the center of mass, with the origin on the axis in the rim's middle plane, to compare with your own model. The rim and the hub are rings, $\pi\,(R^2 - r^2)$ times their width. A strip of width $w$ between the circles of radius $r$ and $R$ has the area $S(R) - S(r)$, with $S(\rho) = \tfrac{w}{2} \sqrt{\rho^2 - w^2/4} + \rho^2 \arcsin\tfrac{w}{2\rho}$, the part of the disc of radius $\rho$ inside the strip with $x \ge 0$, on the spoke's side of the axis. Nothing overlaps, so the volume is the sum. The wheel is symmetric about its axis, so its center of mass lies on it, and only the hub stands out more on one side: ```python def S(rho, w=12): return w / 2 * math.sqrt(rho**2 - w**2 / 4) + rho**2 * math.asin(w / (2 * rho)) parts = [(math.pi * (70**2 - 62**2) * 12, 0), (math.pi * (20**2 - 8**2) * 24, 2), (5 * (S(62) - S(20)) * 8, 0)] exact = sum(v for v, z in parts) c = wheel.center print("spoke", round(spoke.mass, 4), "mm², exact", round(S(62) - S(20), 4)) print("volume", round(wheel.mass, 1), "mm³, exact", round(exact, 1)) print("mass", round(wheel.mass * 7.2e-6, 4), "kg") print("center of mass", round(c.z, 4), "above the middle plane, exact", round(sum(v * z for v, z in parts) / exact, 4), "| off the axis by", round(math.hypot(c.x, c.y), 6)) ``` The handwheel as STEP, for another CAD system: ```python wheel.WriteStep("handwheel.step") ``` The handwheel as STEP: [handwheel.step](handwheel.step) ```python nbsphinx="hidden" import sys sys.path.insert(0, "..") import matplotlib.pyplot as plt from drawings import LANDSCAPE, Pictorial, SheetFigure, Table, View from gallery import save_figure # first angle: the front view, the top view below it with the spokes' width and pitch up = [(math.cos(math.radians(90 + 72 * k)), math.sin(math.radians(90 + 72 * k))) for k in range(5)] front_view = View([], solid=wheel, plane=front, hidden_edges=False, axes=[((0, -14), (0, 18)), ((-76, 0), (76, 0))], measures=[((-70, -6), (-70, 6), -80, 12), ((20, -10), (20, 0), 30, 10), ((20, 0), (20, 14), 30, 14)]) top_view = View([], solid=wheel, plane=px.XY, at=(0, -95), hidden_edges=False, axes=[((-75, 0), (75, 0)), ((0, -75), (0, 75))] + [((10 * u, 10 * v), (74 * u, 74 * v)) for u, v in up[:2]], diameters=[((0, 0), 70, (200, "leader")), ((0, 0), 62, (225, "leader")), ((0, 0), 8, (300, "leader")), ((0, 0), 20, (330, "leader"))], measures=[((-6, 40), (6, 40), 52, 12)], angles=[((0, 0), up[0], up[1], 50, 72)]) data = Table([("Spokes", "5, 12 × 8")], at=(92, 14), widths=(40, 56), height=14) # at 1:2: cells twice as large pictorial = Pictorial(wheel, at=(130, -60), width=80, angles=(-60, 0, 30)) drawing = SheetFigure([front_view, top_view, data, pictorial], margin=16, notes=("planex2d.org", "3D exercise 28"), first_angle=True, sheet=LANDSCAPE) print("scale", drawing.planex_scale, "| paper", [round(v * 25.4) for v in drawing.get_size_inches()], "mm") save_figure(drawing, "handwheel", dpi=200) plt.close(drawing) ```