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

[1]:
import math
import netgen.occ as occ
import planex as px

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):

[3]:
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))
center line 404.378 long, ends at a height of 40.8
The center line, 8 coils
Figure 1: 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):

[5]:
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))
solids 1
The wire swept along the center line
Figure 2: 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):

[7]:
spring = coil * occ.Box(occ.Pnt(-12, -12, 0), occ.Pnt(12, 12, height(8)))  # ground between z = 0 and the free length
The spring with its ground ends
Figure 3: 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\):

[9]:
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)))
center line 404.378 | the helices 404.379
coil 1270.38 mm³ | Pappus 1270.39
volume 1242.5 mm³
mass 9.75 g
center of mass (-0.112, -0.0, 20.4)

The spring as STEP, for another CAD system:

[10]:
spring.WriteStep("compression_spring.step")

The spring as STEP: compression_spring.step