--- jupyter: description: 'A helical compression spring as a 3D CAD exercise: a drawing with its spring data to model in planex2d or any CAD system, a solution from a helix as a 3D spline through the coils'' points, the wire''s section swept along it and the ends ground flat, and the wire''s length, the volume, mass and center of mass to check a model against.' --- # Compression spring A helical compression spring is a wire coiled around an axis. Its active coils give it its rate, and at each end a closed coil, wound tighter, gives it a seat, ground flat so that the spring stands square. The wire's center line is a helix whose pitch changes from the closed ends to the active coils, so it is drawn as a spline through points of the coils, and the wire is its section swept along it. Model the spring from the drawing in planex2d or in any CAD system, then check the wire's length, the volume, mass and center of mass against the values at the end of the page. A solution in planex2d follows. ![The compression spring exercise: a drawing of a helical compression spring with closed and ground ends, in a front view, a top view, its spring data in a table and an isometric](../_static/gallery/compression-spring.png){.result} ```python import math import netgen.occ as occ import planex as px ``` ```python nbsphinx="hidden" from docs_figures import Row, Views ``` ## The center line The spring has 8 coils of wire 2 thick on a mean diameter of 16, around the $z$ axis. The first and the last coil are closed, with a pitch of 2.4, a little more than the wire, so that the coils do not touch, and the 6 active coils between them have a pitch of 6. `height` gives the center line's height after a number of turns, and the center line runs through 24 of its points per turn, from (8, 0, 0) on. `occ.SplineInterpolation` draws a spline through 3D points, and it smooths the changes of the pitch where the closed coils meet the active ones (Figure 1): ```python def height(turns): """the center line's height after the given number of turns""" if turns <= 1: return 2.4 * turns if turns <= 7: return 2.4 + 6 * (turns - 1) return 2.4 + 6 * 6 + 2.4 * (turns - 7) points = [occ.Pnt(8 * math.cos(2 * math.pi * k / 24), 8 * math.sin(2 * math.pi * k / 24), height(k / 24)) for k in range(8 * 24 + 1)] spine = occ.Wire([occ.SplineInterpolation(points)]) # a spline through the points in 3D print("center line", round(spine.mass, 4), "long, ends at a height of", height(8)) ``` ```python nbsphinx="hide-input" Views(("The center line, 8 coils", [(spine, "accent")]), angles=(-70, 0, 30), caption="The center line") ``` ## The coil The wire's section is a circle of 2 at the start of the center line, on the plane square to it there. That plane's normal is the helix's direction at the start, which turns $2\pi \cdot 8$ around the axis for a rise of 2.4. `occ.Pipe` sweeps the section's face along the center line, square to it all the way (Figure 2): ```python tangent = (0, 2 * math.pi * 8, 2.4) # the helix's direction at the start, (8, 0, 0) section = px.Circle((0, 0), 2 / 2, plane=px.Plane(origin=(8, 0, 0), normal=tangent, axis=(1, 0, 0))) coil = occ.Pipe(spine, section.Face().ToOCCFace()) print("solids", len(coil.solids)) ``` ```python nbsphinx="hide-input" Views(("The wire swept along the center line", [(coil, "shade"), (coil, "ink")]), angles=(-70, 0, 30), caption="The coil") ``` ## The ground ends The ends are ground flat at the heights of the center line's ends, so that the spring stands on a flat seat 40.8 high, its free length. The spring is what of the coil lies between the two planes, its intersection `*` with a box between them (Figure 3): ```python spring = coil * occ.Box(occ.Pnt(-12, -12, 0), occ.Pnt(12, 12, height(8))) # ground between z = 0 and the free length ``` ```python nbsphinx="hide-input" Views(("The spring with its ground ends", [(spring, "shade"), (spring, "ink")]), angles=(-70, 0, 30), caption="The ground ends") ``` ## The checks These are the wire's length, the volume, the mass in spring steel (7.85 g/cm³) and the center of mass, with the origin on the axis at the bottom, to compare with your own model. Two checks follow: - A helix of $n$ turns on the diameter $D$ with the pitch $p$ is $n \sqrt{(\pi D)^2 + p^2}$ long. The spline through the points comes close to the helices it joins, rounding off where the pitch changes. - A section square to its path and with its centroid on it sweeps the volume of its area times the path's length, by Pappus's second theorem. The spring's two halves are alike, since a half turn about the line through its middle along the $x$ axis takes the one onto the other. So its center of mass lies on that line, at half the free length, and a little off the spring's axis toward $-x$: ```python helices = 2 * math.hypot(math.pi * 16, 2.4) + 6 * math.hypot(math.pi * 16, 6) print("center line", round(spine.mass, 3), "| the helices", round(helices, 3)) print("coil", round(coil.mass, 2), "mm³ | Pappus", round(math.pi * 1**2 * spine.mass, 2)) c = spring.center print("volume", round(spring.mass, 1), "mm³") print("mass", round(spring.mass * 7.85e-6 * 1000, 2), "g") print("center of mass", tuple(round(v, 3) for v in (c.x, c.y, c.z))) ``` The spring as STEP, for another CAD system: ```python spring.WriteStep("compression_spring.step") ``` The spring as STEP: [compression_spring.step](compression_spring.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 drawn from the spring, the top view below it; the spring data in a table front = px.XZ # x to the right, z up front_view = View([], solid=spring, plane=front, hidden_edges=False, axes=[((0, -3), (0, height(8) + 3))], measures=[((-9, 0), (9, 0), -8, "⌀18"), ((9, 0), (9, height(8)), 18, 40.8)]) top_view = View([], solid=spring, plane=px.XY, at=(0, -26), hidden_edges=False, axes=[((-11, 0), (11, 0)), ((0, -11), (0, 11))], circles=[((0, 0), 8, "pitch")]) data = Table([("Wire diameter d", 2), ("Mean diameter D", 16), ("Total coils", 8), ("Active coils", 6), ("Pitch of the active coils", 6), ("Free length", 40.8), ("Coiling", "right-hand"), ("Ends", "closed, ground")], at=(30, 46), widths=(58, 32)) pictorial = Pictorial(spring, at=(142, 20), width=24, angles=(-70, 0, 30)) drawing = SheetFigure([front_view, top_view, data, pictorial], margin=14, notes=("planex2d.org", "3D exercise 26"), 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, "compression-spring", dpi=200) plt.close(drawing) ```