--- jupyter: description: 'A pillow block as a 3D CAD exercise: a dimensioned drawing to model in planex2d or any CAD system, a solution from a fully constrained profile, and the volume, mass and center of mass to check a model against.' --- # Pillow block A pillow block carries a bearing and is bolted to a frame through its base. As a solid, it is a profile padded into a block, with holes pocketed from its faces. Model the block 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 pillow block exercise: a dimensioned drawing of a pillow block in a front view, a top view and an isometric, with a bore of 40, two bolt holes and an oil hole](../_static/gallery/pillow-block.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 front view, sketched in the front plane, the plane with its normal toward the viewer, $-y$. It has $x$ to the right and $z$ up, with the origin in the middle of the bottom. The outline runs from the bottom left corner along the bottom, up the right end, over the right shoulder, up the right side, over the crown and down the left side to the left shoulder. With `auto_constraint=True`, the flags `px.Horizontal` and `px.Vertical` in the drawing calls become constraints, `Arc(30, 180)` makes the crown a half circle tangent to both sides, and the bore goes around the crown's center with `concentric=`. The profile is symmetric about the vertical axis. The left side and the left shoulder mirror the lines of the right ones, and the mirror sets their directions too, so they carry no flags. With the sizes of the front view, nothing in the sketch is left free (Figure 1): ```python front = px.XZ profile = px.Sketch(front, auto_constraint=True) profile.Move((-70, 0)).Line(140, px.Horizontal, id="bottom") profile.Turn(90).Line(16, px.Vertical, id="right_end") # Turn(90) turns the pen left, Turn(-90) right profile.Turn(90).Line(40, px.Horizontal, id="right_shoulder") profile.Turn(-90).Line(35, px.Vertical, id="right_side") profile.Arc(30, 180, id="crown") profile.Line(35, id="left_side") profile.Turn(-90).Line(40, id="left_shoulder") profile.Close(px.Vertical, id="left_end") profile.Circle(40 / 2, concentric="crown", id="bore") profile.Constrain("bottom.mid", "origin", px.Coincident) profile.Constrain("bottom", px.Distance, 140, id="length") profile.Constrain("right_end", px.Distance, 16, id="base") profile.Constrain("bore.center", "bottom", px.Distance, 50, id="center_height") profile.Constrain("bore", px.Diameter, 40, id="bore_d") profile.Constrain("crown", px.Radius, 30, id="crown_r") profile.Constrain("left_side", "right_side", "V", px.SymmetricCarriers) profile.Constrain("left_shoulder", "right_shoulder", "V", px.SymmetricCarriers) print("status", profile.status, "| degrees of freedom", profile.dof) ``` ```python nbsphinx="hide-input" Row((profile, "Every dimension and tie of the profile", {"constraints": True}), caption="The fully constrained profile") ``` ## The block `px.Pad` extrudes the profile 22.5 to both sides of the front plane, 45 in all, so that the block is symmetric about the front plane as well. Its volume is the area of the profile times 45 (Figure 2): ```python block = px.Pad(profile, 22.5, length2=22.5) print("volume", block.mass, "area × 45", profile.Face().mass * 45) ``` ```python nbsphinx="hide-input" Views(("The profile extruded 45 deep", [(block, "shade"), (block, "ink")]), caption="The block") ``` ## The holes The bolt holes for M12 go through the base. They are sketched on the bottom of the block, its face lowest in $z$, and `until=px.last` cuts them up through the base. They are placed roughly, 80 apart, and the spacing of 110 moves them to their place. The right hole is equal to the left one and both are mirrored about the vertical axis, so the sketch carries one diameter and the spacing, as the drawing gives them (Figure 3): ```python holes = px.Sketch(block.faces.Min(occ.Z)) holes.Circle(13.5 / 2, center=(-40, 0), id="left_hole") holes.Circle(13.5 / 2, center=(40, 0), id="right_hole") holes.Constrain("left_hole", px.Diameter, 13.5, id="hole_d") holes.Constrain("left_hole", "right_hole", px.Equal) holes.Constrain("left_hole.center", "right_hole.center", px.Distance, 110, id="spacing") holes.Constrain("left_hole.center", "H", px.Coincident) holes.Constrain("left_hole.center", "right_hole.center", "V", px.Symmetric) block = px.Pocket(block, holes, until=px.last) # through to the last flat face it crosses ``` ```python nbsphinx="hide-input" Views(("Both bolt holes through the base", [(block, "shade"), (block, "ink")]), caption="The bolt holes") ``` The oil hole runs from the top of the crown down into the bore. Its pocket starts 80 up and ends 30 deeper, on the bore's axis. Below the wall of the crown it runs through the empty bore (Figure 4): ```python oil = px.Sketch(px.Plane(px.XY, 80)) # the xy plane offset by 80: z = 80, on the top of the crown oil.Circle(6 / 2, id="oil_hole") oil.Constrain("oil_hole", px.Diameter, 6, id="oil_d") oil.Constrain("oil_hole.center", "origin", px.Coincident) block = px.Pocket(block, oil, 30) # 30 deep, against the plane's normal: down ``` ```python nbsphinx="hide-input" Views(("The oil hole from the top of the crown into the bore", [(block, "shade"), (block, "ink")]), angles=(-40, 0, 20), caption="The oil hole") ``` ## The checks These are the volume, the mass in steel S235 (7.85 g/cm³) and the center of mass, with the origin in the middle of the bottom, to compare with your own model. The block is symmetric about two planes, so its center of mass lies on the vertical axis: ```python c = block.center print("volume", round(block.mass, 1), "mm³") print("mass", round(block.mass * 7.85e-6, 3), "kg") print("center of mass", round(c.z, 2), "above the bottom, off the axis by", round(math.hypot(c.x, c.y), 6)) ``` The block as STEP, for another CAD system: ```python block.WriteStep("pillow_block.step") ``` The block as STEP: [pillow_block.step](pillow_block.step) ```python nbsphinx="hidden" import sys sys.path.insert(0, "..") import matplotlib.pyplot as plt import netgen.occ as occ from drawings import Pictorial, SheetFigure, View from gallery import save_figure # the views from the sketches and the block: the outline of the top view, the edges seen from the side, the holes # (not the block's bounding box: OpenCASCADE enlarges it after the pockets) x0, x1 = profile.Location("bottom.start")[0], profile.Location("bottom.end")[0] y0, y1 = block.faces.Min(occ.Y).center.y, block.faces.Max(occ.Y).center.y base = profile.Location("right_end.end")[1] side = profile.Location("right_side.start")[0] (cx, cz), r = profile.Location("bore.center"), profile.Measure("bore")["radius"] top = cz + profile.Measure("crown")["radius"] bolts = [(holes.Location(h + ".center")[0], holes.Measure(h)["radius"]) for h in ("left_hole", "right_hole")] oil_r = oil.Measure("oil_hole")["radius"] front_view = View( [(profile, {"length": -20, "base": x1 + 15, "center_height": x0 - 15, "bore_d": 135, "crown_r": (45, "outside")}, {"bore": "lines-h"}, front)], hidden=[[(x + s * hr, 0), (x + s * hr, base)] for x, hr in bolts for s in (-1, 1)] + [[(s * oil_r, cz + math.sqrt(r**2 - oil_r**2)), (s * oil_r, top)] for s in (-1, 1)], axes=[((cx, -5), (cx, top + 5), (cx, cz))] + [((x, -5), (x, base + 5)) for x, _ in bolts]) top_view = View( [(holes, {"spacing": y0 - 15, "hole_d": (135, "leader", 2)}, {"left_hole": "lines-v", "right_hole": "lines-v"}), (oil, {"oil_d": (60, "leader")}, {})], at=(0, -80), lines=[[(x0, y0), (x1, y0), (x1, y1), (x0, y1), (x0, y0)]] + [[(s * side, y0), (s * side, y1)] for s in (-1, 1)], hidden=[[(cx + s * r, y0), (cx + s * r, y1)] for s in (-1, 1)], axes=[((x0 - 5, 0), (x1 + 5, 0), (0, 0)), ((0, y0 - 5), (0, y1 + 5), (0, 0))], measures=[((x1, y0), (x1, y1), x1 + 15, y1 - y0)]) drawing = SheetFigure([front_view, top_view, Pictorial(block, at=(x1 + 100, 20), width=100)], margin=15, notes=("planex2d.org", "3D exercise 01"), first_angle=True) print("scale 1 :", round(1 / drawing.planex_scale), "| paper", [round(v * 25.4) for v in drawing.get_size_inches()], "mm") save_figure(drawing, "pillow-block", dpi=200) plt.close(drawing) ```