--- jupyter: description: 'A V-belt pulley as a 3D CAD exercise: a dimensioned drawing with a full section to model in planex2d or any CAD system, a solution from a half-section profile revolved about its axis with a keyway in the bore, and the volume, mass and center of mass to check a model against.' --- # V-belt pulley A V-belt pulley carries a belt in the groove of its rim and sits on a shaft by its hub, a key in the bore's keyway taking the torque. A turned part like this is a profile revolved about its axis, the half section from the axis out, here with the hub standing out on one side. Model the pulley 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 V-belt pulley exercise: a dimensioned drawing of a pulley with a V-groove, a hub on one side and a keyed bore, in a full section, a side view and an isometric](../_static/gallery/v-belt-pulley.png){.result} ```python import math import netgen.occ as occ import planex as px ``` ```python nbsphinx="hidden" from docs_figures import Row, Views ``` ## The profile The profile is the half section above the axis, sketched in the front plane, the plane with its normal toward the viewer, $-y$. Its $x$ runs along the axis and $z$ out from it, with the origin on the axis at the hub's end. The outline runs from the bore along the axis, up the rim's right face, into the groove and out of it, down the disc's left face and along the hub back to the start. With `auto_constraint={"horizontal": True, "vertical": True}`, the lines drawn level or plumb stay so (Figure 1). The bore is 20 across and the hub 40 across and 20 long, and the pulley is 40 long in all, 80 across the rim. The groove is 11 deep, 12 wide at the rim and 38° between its flanks, its middle 10 from the right face. Its flanks are equal, so that the groove is symmetric. `px.Angle` measures between the lines in the directions they are drawn in. The right flank is drawn down into the groove and the left one up out of it, so the angle between them as drawn is 180° less the groove's 38°: ```python front = px.XZ profile = px.Sketch(front, auto_constraint={"horizontal": True, "vertical": True}) profile.Move((0, 10)).Line(40, id="bore") profile.Turn(90).Line(30, id="right_face") # Turn(90) turns the pen left, Turn(-90) right profile.Turn(90).Line(4, id="rim_right") profile.Turn(71).Line(11, id="flank_right") profile.Turn(-71).Line(4, id="groove_bottom") profile.Turn(-71).Line(11, id="flank_left") profile.Turn(71).Line(4, id="rim_left") profile.Turn(90).Line(20, id="disc_face") profile.Turn(-90).Line(20, id="hub_top") profile.Close(px.Vertical, id="hub_end") # drawn only roughly plumb: the flag holds it profile.Constrain("bore.start", "V", px.Coincident) profile.Constrain("bore.start", "H", px.Distance, 10, id="bore_r") profile.Constrain("bore", px.Distance, 40, id="length") profile.Constrain("hub_top", px.Distance, 20, id="hub_l") profile.Constrain("hub_top", "H", px.Distance, 20, id="hub_r") profile.Constrain("rim_left", "H", px.Distance, 40, id="outside_r") profile.Constrain("rim_right", "H", px.Distance, 40) profile.Constrain("groove_bottom", "rim_left", px.Distance, 11, id="groove_depth") profile.Constrain("flank_left", "flank_right", px.Angle, 180 - 38, id="groove_angle") # between the lines as drawn profile.Constrain("flank_left", "flank_right", px.Equal) profile.Constrain("flank_right.start", "flank_left.end", px.Distance, 12, id="groove_w") profile.Constrain("groove_bottom.mid", "right_face", px.Distance, 10, id="groove_at") print("status", profile.status, "| degrees of freedom", profile.dof) ``` ```python nbsphinx="hide-input" Row((profile, "Every dimension and tie of the half section", {"constraints": True}), caption="The profile") ``` ## The pulley The profile's face, taken to OpenCASCADE with `ToOCCFace`, is revolved a full turn about the $x$ axis with netgen's `Revolve`. By Pappus's theorem, the volume is the profile's area times the length of the circle that its centroid runs on, $2\pi$ times its distance from the axis (Figure 2): ```python face = profile.Face() pulley = face.ToOCCFace().Revolve(occ.Axis((0, 0, 0), occ.X), 360) print("volume", round(pulley.mass, 3), "| Pappus", round(2 * math.pi * face.center[2] * face.mass, 3)) ``` ```python nbsphinx="hide-input" Views(("The profile revolved about the axis", [(pulley, "shade"), (pulley, "ink")]), angles=(-50, 0, -40), caption="The pulley") ``` ## The keyway The keyway is sketched on the hub's end, the face lowest in $x$. Its default axes would have $v$ pointing down, and `px.Plane(end, axis=(0, -1, 0))` turns them so that the sketch is seen as the side view shows it, $-y$ to the right and $z$ up. `Project` brings the bore's edge into the sketch, the shorter of the end face's two edges. The keyway is a rectangle drawn with `RectangleC` around its center, 6 wide and 12 high, enough to reach from its top down into the bore. Its center lies on the vertical axis and its bottom stays horizontal. As on the [keyed hub](keyed-hub.md), its depth runs from the far side of the bore to its top, 22.8 for a bore of 20, which sets the rectangle's height on the axis. It is pocketed 40 deep, through the hub (Figure 3): ```python end = pulley.faces.Min(occ.X) keyway = px.Sketch(px.Plane(end, axis=(0, -1, 0)), auto_constraint=True) keyway.Project(min(end.edges, key=lambda e: e.mass), id="bore") keyway.RectangleC((0, 6), 6, 12, id="keyway") # 6 along the pen's direction, 12 across it; its lines keyway.Line.1 to .4 keyway.Vertex("bore_bottom", (0, -9)) keyway.Constrain("keyway.center", "V", px.Coincident) keyway.Constrain("keyway.Line.1", px.Horizontal) keyway.Constrain("keyway.Line.3", px.Distance, 6, id="keyway_w") keyway.Constrain("keyway.Line.2", px.Distance, 12, id="keyway_h") keyway.Constrain("bore_bottom", "bore.Edge.0", px.Coincident) keyway.Constrain("bore_bottom", "V", px.Coincident) keyway.Constrain("bore_bottom", "keyway.Line.3", px.Distance, 22.8, id="keyway_depth") print("status", keyway.status, "| degrees of freedom", keyway.dof) pulley = px.Pocket(pulley, keyway, 40) ``` ```python nbsphinx="hide-input" Row((keyway, "The keyway at the hub's end, the bore projected", {"plot": {"show_parent": pulley, "show_constraints": True}}), (pulley, "The keyway through the hub", {"views": [(pulley, "shade"), (pulley, "ink")], "angles": (-50, 0, 50)}), caption="The keyway") ``` ## The checks These are the volume, the mass in steel S235 (7.85 g/cm³) and the center of mass, with the origin on the axis at the hub's end, to compare with your own model. The volume is the revolved profile less the keyway. The keyway is the rectangle 6 wide from the axis up to the keyway's top, $22.8 - 10$, less the bore's area under it, times the 40 of the bore's length. The keyway takes material above the axis, so the center of mass lies just below it: ```python under = 3 * math.sqrt(10**2 - 3**2) + 10**2 * math.asin(3 / 10) # the bore's area above the axis, |y| < 3 exact = 2 * math.pi * face.center[2] * face.mass - (6 * (22.8 - 10) - under) * 40 c = pulley.center print("volume", round(pulley.mass, 1), "mm³, exact", round(exact, 1)) print("mass", round(pulley.mass * 7.85e-6, 3), "kg") print("center of mass", round(c.x, 2), "along the axis,", round(-c.z, 3), "below it, off the plane y = 0 by", round(abs(c.y), 6)) ``` The pulley as STEP, for another CAD system: ```python pulley.WriteStep("v_belt_pulley.step") ``` The pulley as STEP: [v_belt_pulley.step](v_belt_pulley.step) ```python nbsphinx="hidden" import sys sys.path.insert(0, "..") import matplotlib.pyplot as plt from drawings import Pictorial, SheetFigure, View from gallery import save_figure # the full section through the axis: the part behind the plane y = 0, seen from the front, its cut faces hatched half = pulley * occ.Box((-1, 0, -50), (41, 50, 50)) cut = [f for f in half.faces if abs(f.center.y) < 1e-6 and f.bounding_box[1].y - f.bounding_box[0].y < 1e-6] left = px.Plane(normal=(-1, 0, 0), axis=(0, -1, 0)) # the view from the left: -y to the right, z up rim_x = profile.Location("rim_left.end")[0] section = View([(profile, {"length": -52, "hub_l": 56, "groove_at": 72, "groove_w": 46, "groove_depth": 50, "groove_angle": (34, "supplement")})], solid=half, plane=front, hidden_edges=False, hatch=cut, axes=[((-4, 0), (44, 0))], measures=[((0, -20), (0, 20), -10, "⌀40"), ((rim_x, -40), (rim_x, 40), -22, "⌀80")]) side = View([(keyway, {"keyway_w": 48, "keyway_depth": 50})], solid=pulley, plane=left, hidden_edges=False, at=(110, 0), axes=[((-44, 0), (44, 0)), ((0, -44), (0, 44))], diameters=[((0, 0), 10, (225, "leader"))]) pictorial = Pictorial(pulley, at=(110, -85), width=60, angles=(-40, 0, 50)) drawing = SheetFigure([section, side, pictorial], margin=42, notes=("planex2d.org", "3D exercise 06"), first_angle=True) print("scale", drawing.planex_scale, "| paper", [round(v * 25.4) for v in drawing.get_size_inches()], "mm") save_figure(drawing, "v-belt-pulley", dpi=200) plt.close(drawing) ```