--- jupyter: description: 'A gear pump housing as a 3D CAD exercise: a dimensioned drawing with a full section to model in planex2d or any CAD system, a solution with the gasket''s opening pocketed as the gear chambers, bearing bores, tapped holes on the gasket''s bolt line and ports drilled from the sides into the chambers, and the cavity, the volume, mass and center of mass to check a model against.' --- # Gear pump housing The housing of the [gear pump](pump-gasket.md) holds the two gears in their chambers. The [gasket](pump-gasket.md) seals it, and the [cover](pump-cover.md) closes it. The chambers are the gasket's opening pocketed to the gears' width, the tapped holes for the cover's screws lie on the gasket's bolt line, and the oil comes in and goes out through two ports drilled from the sides into the chambers, where the gears mesh. Model the housing from the drawing in planex2d or in any CAD system. Then check that its cavity is one passage, and compare its volume, mass and center of mass with the values at the end of the page. A solution in planex2d follows. ![The gear pump housing exercise: a dimensioned drawing of a block with two overlapping gear chambers, bearing bores, tapped holes around the chambers, mounting holes and a port on each side, in a top view, a full section, a side view and an isometric](../_static/gallery/pump-housing.png){.result} ```python import math import netgen.occ as occ import planex as px ``` ```python nbsphinx="hidden" from docs_figures import Row, Views ``` ## The block The block is 130 by 90 and 30 high, with its corners rounded to a radius of 10. It is a `RectangleC` around the origin on the xy plane, filleted at its corners and padded 30 up. Its top, at $z = 30$, is the face the gasket and the cover sit on, and the gears' centers lie 17 to either side of the origin on the $x$ axis (Figure 1): ```python outline = px.Sketch(auto_constraint=True) outline.RectangleC(130, 90, id="block") outline.Constrain("block.center", "origin", px.Coincident) outline.Constrain("block.Line.1", px.Horizontal) outline.Constrain("block.Line.1", px.Distance, 130, id="length") outline.Constrain("block.Line.2", px.Distance, 90, id="width") outline.Fillet(["block.Line.1.start", "block.Line.2.start", "block.Line.3.start", "block.Line.4.start"], 10, id=["corner_1", "corner_2", "corner_3", "corner_4"]) print("status", outline.status, "| degrees of freedom", outline.dof) housing = px.Pad(outline, 30) ``` ```python nbsphinx="hide-input" Row((outline, "The block's outline, every dimension and tie", {"constraints": True}), (housing, "Padded 30", {"views": [(housing, "shade"), (housing, "ink")], "angles": (-60, 0, 30)}), caption="The block") ``` ## The chambers and the bearings The chambers are the gasket's opening, two circles of 38.5 around the gears' centers, united and pocketed 20 deep from the top, the [rotors'](pump-rotors.md) width. That leaves 10 of wall below them. The gears' shafts run in two bearing bores of 15, 8 deep into that wall, sketched on the chambers' floor, the xy plane lifted to 10 (Figure 2): ```python opening = px.Unify([px.Circle((-17, 0), 38.5 / 2).Face(), px.Circle((17, 0), 38.5 / 2).Face()]).Face() housing = px.Pocket(housing, opening.Translated((0, 0, 30)), 20) bearings = px.QuickSketch(px.Plane(px.XY, 10)).Circle(15 / 2, center=(-17, 0)).Circle(15 / 2, center=(17, 0)) housing = px.Pocket(housing, bearings, 8) ``` ```python nbsphinx="hide-input" Views(("The chambers and the bearing bores", [(housing, "shade"), (housing, "ink")]), angles=(-60, 0, 30), caption="The chambers and the bearings") ``` ## The holes The cover's ten M6 screws go into tapped holes where the gasket's holes are. They are equally spaced along the bolt line, the opening offset by 8, the first half a pitch from its start. `along` walks the bolt line as on the [cover's page](pump-cover.md), and each hole is the tapping drill of 5, 15 deep. The housing is bolted down through four holes of 9 through its corners, 110 by 70 apart (Figure 3): ```python def along(wire, n): """n points equally spaced along a closed wire, the first half a pitch from its start""" pitch = wire.mass / n targets = [pitch / 2 + k * pitch for k in range(n)] points, walked = [], 0.0 for e in wire.edges: length = e.Measure()["length"] points += [e.PointAt((t - walked) / length) for t in targets if walked <= t < walked + length] walked += length return [(p.x, p.y) for p in points] bolt_line = opening.Offset(8, inplace=False).Face().outer tapped = px.QuickSketch(px.Plane(px.XY, 30)) for c in along(bolt_line, 10): tapped.Circle(5 / 2, center=c) housing = px.Pocket(housing, tapped, 15) mounting = px.QuickSketch(px.Plane(px.XY, 30)) for x in (-55, 55): for y in (-35, 35): mounting.Circle(9 / 2, center=(x, y)) housing = px.Pocket(housing, mounting, until=px.last) # through the block ``` ```python nbsphinx="hide-input" Views(("The tapped holes and the mounting holes", [(housing, "shade"), (housing, "ink")]), angles=(-60, 0, 30), caption="The holes") ``` ## The ports The inlet and the outlet are drilled from the block's two long sides at $x = 0$, where the chambers meet and the gears mesh, in the middle of the chambers' depth, 20 above the bottom. Each has a spot face of 22, 1 deep, for the fitting's seal, and a bore of 12, 38 deep, into the chambers. A sketch on a side face has its own axes, and `ToHV` gives the port's center, a 3D point, in them (Figure 4): ```python for side in (housing.faces.Min(occ.Y), housing.faces.Max(occ.Y)): center = (0, side.center.y, 20) spot = px.QuickSketch(side) spot.Circle(22 / 2, center=spot.ToHV(center)) housing = px.Pocket(housing, spot, 1) port = px.QuickSketch(side) port.Circle(12 / 2, center=port.ToHV(center)) housing = px.Pocket(housing, port, 38) ``` ```python nbsphinx="hide-input" Views(("The ports from the sides into the chambers", [(housing, "shade"), (housing, "ink")]), angles=(-30, 0, 20), caption="The ports") ``` ## The checks The cavity is what is taken out of the block, the block less the housing. Its pieces are the solids of that difference, and the chambers, the bearing bores and the two ports must form one of them, with the ten tapped holes and the four mounting holes apart. Then come the volume, the mass in aluminum EN AC-AlSi10Mg (2.68 g/cm³) and the center of mass, with the origin in the middle of the bottom, to compare with your own model. The housing is symmetric about the plane $y = 0$, so its center of mass lies in it: ```python block = px.Pad(outline, 30) pieces = sorted((block - housing).solids, key=lambda s: -s.mass) print(len(pieces), "pieces taken out: the cavity", round(pieces[0].mass, 1), "mm³ and", len(pieces) - 1, "holes") c = housing.center print("volume", round(housing.mass, 1), "mm³") print("mass", round(housing.mass * 2.68e-6, 4), "kg") print("center of mass", (round(c.x, 4), round(c.z, 4)), "| off the plane y = 0 by", round(abs(c.y), 6)) ``` The housing as STEP, for another CAD system: ```python housing.WriteStep("pump_housing.step") ``` The housing as STEP: [pump_housing.step](pump_housing.step) ```python nbsphinx="hidden" import sys sys.path.insert(0, "..") import matplotlib.pyplot as plt from drawings import LANDSCAPE, Pictorial, SheetFigure, View from gallery import save_figure # first angle: the full section through the plane y = 0 in front (the symmetry plane: no designation), seen from the # front, its cut faces hatched; the top view below it; the view A onto the outlet's side to the right of the section holes = along(bolt_line, 10) front = px.XZ # x to the right, z up behind = housing * occ.Box((-70, 0, -1), (70, 50, 31)) cut = [f for f in behind.faces if abs(f.center.y) < 1e-6 and f.bounding_box[1].y - f.bounding_box[0].y < 1e-6] section = View([], solid=behind, plane=front, hidden_edges=False, hatch=cut, axes=[((-17, -4), (-17, 34)), ((17, -4), (17, 34)), ((-44.25, 12), (-44.25, 33)), ((44.25, 12), (44.25, 33))], measures=[((-65, 0), (-65, 30), -75, 30), ((-20, 10), (-20, 30), -20, 20), ((-24.5, 2), (-24.5, 10), -31, 8), ((-24.5, 2), (-9.5, 2), -12, "⌀15"), ((-17, 30), (17, 30), 38, 34)]) top = View([], solid=housing, plane=px.XY, at=(0, -104), hidden_edges=False, axes=[bolt_line.Polylines(1e-3)[0], ((-70, 0), (70, 0)), ((0, -50), (0, 50)), ((-17, -8), (-17, 8)), ((17, -8), (17, 8))] + [((x - 7, y), (x + 7, y)) for x in (-55, 55) for y in (-35, 35)] + [((x, y - 7), (x, y + 7)) for x in (-55, 55) for y in (-35, 35)], arrows=[((0, 52), (0, -1), "A")], radii=[((-17, 0), 27.25, (160, "outside")), ((55, 35), 10, (45, "outside"))], diameters=[(holes[0], 2.5, (110, "leader", 10, "↧15 EQS")), ((55, -35), 4.5, (315, "leader", 4)), ((17, 0), 19.25, (335, "leader"))], measures=[((-55, -35), (-55, 35), -76, 70), ((-65, -45), (-65, 45), -90, 90), ((-55, -35), (55, -35), -58, 110), ((-65, -45), (65, -45), -68, 130)]) view_a = px.Plane(normal=(0, 1, 0), axis=(-1, 0, 0)) # seen from +y: -x to the right, z up side_view = View([], solid=housing, plane=view_a, at=(150, 0), hidden_edges=False, label="A", axes=[((0, 10), (0, 30)), ((-14, 20), (14, 20))], diameters=[((0, 20), 11, (45, "leader")), ((0, 20), 6, (135, "leader"))], measures=[((65, 0), (65, 20), 75, 20)]) pictorial = Pictorial(housing, at=(150, -104), width=80, angles=(-30, 0, 20)) drawing = SheetFigure([section, top, side_view, pictorial], margin=16, notes=("planex2d.org", "3D exercise 30"), 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, "pump-housing", dpi=200) plt.close(drawing) ```