--- jupyter: description: 'A connecting rod as a 3D CAD exercise: a dimensioned drawing with a section through its middle plane to model in planex2d or any CAD system, a solution from two eyes and a tapered shank united and filleted, padded, and an I-section pocketed into both faces from the outline''s inward offset, and the exact volume, the mass and center of mass to check a model against.' --- # Connecting rod A connecting rod joins a piston to its crankshaft. The big eye runs on the crank pin, the small eye on the piston pin, and the shank between them carries the gas force and the inertia of the piston. Its shank is an I-section, a web between two flanges, which is stiff in bending for its weight. As a solid, the rod's plan is two eyes and a tapered shank united and filleted, padded to the rod's width, and the I-section is a pocket in each face whose outline is the plan offset inward by the flanges' width. Model the rod 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 connecting rod exercise: a dimensioned drawing of a connecting rod with a big and a small eye and an I-section shank, in a top view, a section through its middle plane and an isometric](../_static/gallery/connecting-rod.png){.result} ```python import math import netgen.occ as occ import planex as px ``` ```python nbsphinx="hidden" from docs_figures import Row, Views ``` ## The plan The plan lies on the xy plane, which becomes the middle plane of the rod's width. The big eye is a disc of 50 around the origin and the small eye a disc of 24 around (100, 0). The shank is a trapezoid along the $x$ axis, 20 wide at 40 from the big eye's center and 16 wide at 80. Its straight flanks run on to the eyes' centers, where it is 24 and 14 wide. `px.Unify` unites them into one face with four corners where the shank meets the eyes (Figure 1): ```python big = px.Circle((0, 0), 50 / 2).Face() small = px.Circle((100, 0), 24 / 2).Face() shank = px.FromPolyline([(0, -12), (100, -7), (100, 7), (0, 12)], closed=True).Face() # its corners as points plan = px.Unify([big, small, shank]).Face() # the one face of the union print("corners", [(round(v.x, 3), round(v.y, 3)) for v in plan.vertices]) ``` ```python nbsphinx="hide-input" Row((px.Compound([big, small, shank]), "Two eyes and the shank", {"fill": False}), (plan, "United"), caption="The plan") ``` `Fillet` rounds the corners at the big eye with a radius of 8 and those at the small eye with 5. `vertices(near=)` picks the corner nearest to a point, so the points are given roughly (Figure 2): ```python plan = plan.Fillet([plan.vertices(near=(22, 11)), plan.vertices(near=(22, -11))], 8) plan = plan.Fillet([plan.vertices(near=(91, 7.5)), plan.vertices(near=(91, -7.5))], 5) print("plan", round(plan.mass, 4), "mm²") ``` ```python nbsphinx="hide-input" Row((plan, "The plan, its corners rounded", {}), caption="The fillets") ``` ## The rod `px.Pad` extrudes the plan 8 to both sides of the xy plane, 16 in all. The bores, 32 in the big eye and 14 in the small eye, are one face, united, and pocketed 8 to both sides, through the rod (Figure 3): ```python rod = px.Pad(plan, 8, length2=8) bores = px.Unify([px.Circle((0, 0), 32 / 2).Face(), px.Circle((100, 0), 14 / 2).Face()]) rod = px.Pocket(rod, bores, 8, length2=8) ``` ```python nbsphinx="hide-input" Views(("The plan padded 16 wide, with its bores", [(rod, "shade"), (rod, "ink")]), angles=(-60, 0, 30), caption="The rod") ``` ## The I-section The flanges are 3 wide along the shank's edges and the web 6 thick. The pocket's outline is the plan offset inward by the flanges' width, less a disc of radius 28 around the big eye's center and one of 15 around the small eye's, so that 3 of material stay around each eye, and its corners are rounded with a radius of 2.5 (Figure 4): ```python region = plan.Offset(-3, inplace=False) - px.Circle((0, 0), 28).Face() - px.Circle((100, 0), 15).Face() region = region.Face() # the one face left: the shank's middle region = region.Fillet(list(region.vertices), 2.5) print("pocket", round(region.mass, 4), "mm²") ``` ```python nbsphinx="hide-input" Row((plan, "The pocket's outline in the plan", {"fills": [(region, "#cfd9e6")]}), caption="The pocket's outline") ``` The pocket is 5 deep in each face, so that the web keeps $16 - 2 \cdot 5$. The region, moved to the top face at $z = 8$, is pocketed down. Moved to the bottom face, it is pocketed up with `reverse=True`, the same pocket mirrored about the middle plane (Figure 5): ```python rod = px.Pocket(rod, region.Translated((0, 0, 8)), 5) rod = px.Pocket(rod, region.Translated((0, 0, -8)), 5, reverse=True) ``` ```python nbsphinx="hide-input" Views(("The I-section pocketed into both faces", [(rod, "shade"), (rod, "ink")]), angles=(-60, 0, 30), caption="The I-section") ``` ## The checks These are the volume, the mass in steel 42CrMo4 (7.85 g/cm³) and the center of mass, with the origin at the big eye's center in the middle plane, to compare with your own model. The volume follows from the areas, $16\,(A_\text{plan} - A_\text{bores}) - 2 \cdot 5\,A_\text{pocket}$. The rod is symmetric about the middle plane and about the plane $y = 0$, so its center of mass lies on the $x$ axis: ```python exact = (plan.mass - bores.mass) * 16 - 2 * region.mass * 5 c = rod.center print("volume", round(rod.mass, 2), "mm³, exact", round(exact, 2)) print("mass", round(rod.mass * 7.85e-6, 4), "kg") print("center of mass", round(c.x, 3), "from the big eye's center, off the x axis by", round(math.hypot(c.y, c.z), 6)) ``` The rod as STEP, for another CAD system: ```python rod.WriteStep("connecting_rod.step") ``` The rod as STEP: [connecting_rod.step](connecting_rod.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 # the upper fillet of a radius, its center from the plan's arcs def arc(radius): centers = [e.Measure()["center"][:2] for e in plan.edges if abs(e.Measure().get("radius", 0) - radius) < 1e-6] return max(centers, key=lambda c: c[1]) # first angle: the top view, the section through the middle plane y = 0 above it (the symmetry plane: no # designation needed), seen from the front with its cut faces hatched; the pocket's sizes in a table front = px.XZ # x to the right, z up behind = rod * occ.Box((-30, 0, -12), (115, 30, 12)) 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, at=(0, 42), axes=[((0, -11), (0, 11)), ((100, -11), (100, 11)), ((-29, 0), (116, 0))], measures=[((-25, -8), (-25, 8), -32, 16), ((60, -3), (60, 3), 60, 6)]) top = View([], solid=rod, plane=px.XY, hidden_edges=False, axes=[((-29, 0), (116, 0)), ((0, -29), (0, 29)), ((100, -16), (100, 16))], measures=[((0, 0), (100, 0), -34, 100), ((40, -10), (40, 10), 40, 20), ((80, -8), (80, 8), 80, 16)], diameters=[((0, 0), 25, (120, "leader")), ((0, 0), 16, 225), ((100, 0), 12, (60, "leader")), ((100, 0), 7, (300, "leader"))], radii=[(arc(8), 8, (245, "inside")), (arc(5), 5, (295, "inside"))]) # from the center outside the part to the arc data = Table([("Flanges", "3 wide"), ("Web", 6), ("Pocket's ends", "R28, R15"), ("Pocket's corners", "R2,5")], at=(-20, -48), widths=(38, 28)) pictorial = Pictorial(rod, at=(128, -32), width=50, angles=(-60, 0, 30)) drawing = SheetFigure([section, top, data, pictorial], margin=16, notes=("planex2d.org", "3D exercise 23"), 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, "connecting-rod", dpi=200) plt.close(drawing) ```