Spur gear

A spur gear turns a second gear on a parallel shaft. Its teeth have involute flanks. Where two involutes of the same pressure angle touch, the contact runs along one straight line as the gears turn, so the ratio of their speeds stays constant. The flanks follow from the gear’s data, its module, number of teeth and pressure angle, which the drawing gives in a table, and they are drawn from the involute’s formula. One pitch, a tooth and the half gaps beside it, is drawn once and repeated around the gear. Model the gear from the drawing in planex2d or in any CAD system, then check the span over three teeth, the volume, mass and center of mass against the values at the end of the page. A solution in planex2d follows.

The spur gear exercise: a dimensioned drawing of a spur gear with 24 involute teeth, a hub and a keyed bore, in a full section and a view along its axis, with its gear data in a table and an isometric

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

The gear data

The gear has a module of \(m = 2\) and \(z = 24\) teeth, a pressure angle of \(\alpha = 20^\circ\) and no profile shift. Its pitch circle has the radius \(m z / 2\), and the base circle, from which the involutes unwind, has the radius \(r \cos\alpha\). The tip circle lies one module outside the pitch circle and the root circle 1.25 modules inside it:

[3]:
m = 2
z = 24
alpha = math.radians(20)
r = m * z / 2  # the pitch circle
rb = r * math.cos(alpha)  # the base circle
ra = r + m  # the tip circle
rf = r - 1.25 * m  # the root circle
print("diameters: pitch", 2 * r, "| base", round(2 * rb, 3), "| tip", 2 * ra, "| root", 2 * rf)
diameters: pitch 48.0 | base 45.105 | tip 52.0 | root 43.0

The involute flanks

The involute of the base circle is the path of the end of a string unwound from it. At a radius \(\rho\), the string has unwound by the angle \(\tan\alpha_\rho\), with \(\alpha_\rho = \arccos(r_b / \rho)\), and the end lies \(\mathrm{inv}\,\alpha_\rho = \tan\alpha_\rho - \alpha_\rho\) around the base circle from where the string left it, where \(\mathrm{inv}\) is the involute function.

On the pitch circle, a tooth is half a pitch thick, \(\pi m / 2\), so its flanks lie \(\pi / (2 z)\) on either side of the tooth’s middle there, and \(\pi / (2 z) + \mathrm{inv}\,\alpha\) at the base circle, the angle beta.

Unwound by the angle \(u\) in radians, the string’s end lies at \(r_b\,(\cos u + u \sin u,\ \sin u - u \cos u)\). The lower flank is this involute turned back by beta, and the upper flank is its mirror image across the \(x\) axis. Curve takes both as formulas. Its angles are in degrees, so \(u\) appears in radians only where it multiplies. Both run from the base circle at \(u = 0\) out to the tip circle at \(u_a = \sqrt{(r_a / r_b)^2 - 1}\):

[4]:
def inv(a):
    return math.tan(a) - a


beta = math.pi / (2 * z) + inv(alpha)  # half the tooth's angle at the base circle
ua = math.degrees(math.sqrt((ra / rb) ** 2 - 1))  # the roll angle at the tip circle, in degrees
b = math.degrees(beta)
lower = (f"{rb}*(cos(t - {b}) + t*pi/180*sin(t - {b}))", f"{rb}*(sin(t - {b}) - t*pi/180*cos(t - {b}))")
upper = (lower[0], f"-({lower[1]})")


def polar(rho, angle):
    return (rho * math.cos(angle), rho * math.sin(angle))

One pitch

One pitch, from the middle of the gap below the tooth to the middle of the gap above it, is a chain in a QuickSketch, with the tooth’s middle on the \(x\) axis. It runs along the root circle from the gap’s middle, up a foot to the base circle, out along the lower flank to the tip circle, over the tip circle to the upper flank, back down the upper flank, down the other foot and along the root circle to the next gap’s middle. The root circle here lies inside the base circle, where there is no involute, so the feet run radially. The base, pitch and tip circles are drawn dashed, as construction (Figure 1):

[5]:
tip = 2 * (beta - inv(math.acos(rb / ra)))  # the tooth's angle at the tip circle
gear = px.QuickSketch()
for radius in (rb, r, ra):
    gear.Circle(radius, construction=True)
gear.Move(polar(rf, -math.pi / z))
gear.Arc(center=(0, 0), sweep=math.degrees(math.pi / z - beta), id="root_low")  # around the gear's center
gear.Line(polar(rb, -beta), id="foot_low")
gear.Curve(lower, (0, ua), id="flank_low")  # from the pen at its start, out along the involute
gear.Arc(center=(0, 0), sweep=math.degrees(tip), id="tip")
gear.Curve(upper, (ua, 0), id="flank_up")  # from the tip back down to the base circle
gear.Line(polar(rf, beta), id="foot_up")
gear.Arc(center=(0, 0), sweep=math.degrees(math.pi / z - beta), id="root_up");
One pitch, the base, pitch and tip circles dashed
Figure 1: One pitch

The root fillets

The corners where the feet meet the root circle are rounded with a radius of 0.8. Fillet takes them as points, the feet’s ends where the chain put them, and keeps the pieces it cuts off as construction (Figure 2):

[7]:
gear.Fillet([polar(rf, -beta), polar(rf, beta)], 0.8);  # the corners as points, exactly on the feet's ends
The root fillets of the pitch
Figure 2: The root fillets

The teeth

CircularPattern repeats the pitch around the gear’s center, 24 times in all, and the pitches join into one closed outline (Figure 3):

[9]:
pitch = ["root_low", "Fillet.1", "foot_low", "flank_low", "tip", "flank_up", "foot_up", "Fillet.2", "root_up"]
gear.CircularPattern(pitch, "origin", z, id="teeth")  # the pitch and 23 copies
face = gear.Face()
print("edges", len(face.edges), "| area", round(face.mass, 4), "mm²")
edges 216 | area 1781.635 mm²
The gear's face, 24 teeth
Figure 3: The teeth

The span over three teeth

A gear is checked by its span \(W_k\) over \(k\) teeth, measured with a caliper whose jaws touch the flanks of \(k\) teeth. The jaws touch where a line tangent to the base circle crosses the flanks, and that line crosses every involute at a right angle, so \(W_k = m \cos\alpha\,\bigl(\pi\,(k - \tfrac{1}{2}) + z\,\mathrm{inv}\,\alpha\bigr)\), here for \(k = 3\). The face cut by the tangent to the base circle at \((0, -r_b)\) gives the chords of that line through the teeth. The span runs from the left flank of the tooth left of the middle chord to the right flank of the tooth right of it (Figure 4):

[11]:
k = 3
w = m * math.cos(alpha) * (math.pi * (k - 0.5) + z * inv(alpha))
chords = px.Line((-30, -rb), (30, -rb)) * face  # the tangent's pieces inside the teeth
ends = sorted(sorted((e.start.x, e.end.x)) for e in chords.edges)
middle = min(range(len(ends)), key=lambda i: abs(sum(ends[i])))  # the chord through the tooth at the bottom
span = ends[middle + 1][1] - ends[middle - 1][0]
print("span over 3 teeth", round(span, 6), "| formula", round(w, 6))
span over 3 teeth 15.432923 | formula 15.432923
The span along the tangent to the base circle
Figure 4: The span over three teeth

The gear body

The face is padded 20, the gear’s width, along \(z\). The hub, 40 across and 12 long, is padded from the gear’s top face. The bore of 20 and the keyway, 6 wide and 22.8 deep from the far side of the bore, are pocketed from the hub’s top. The bore goes to the last face it crosses, and the keyway runs through hub and gear, 32 deep (Figure 5):

[13]:
body = px.Pad(face, 20)
hub = px.QuickSketch(body.faces.Max(occ.Z)).Circle(20)
body = body + px.Pad(hub, 12)
bore = px.QuickSketch(body.faces.Max(occ.Z)).Circle(10)
body = px.Pocket(body, bore, until=px.last)
keyway = px.QuickSketch(body.faces.Max(occ.Z)).Move((-3, 0)).Rectangle(6, 22.8 - 10)  # from the axis to its top
body = px.Pocket(body, keyway, 12 + 20)
The gear with its hub and keyed bore
Figure 5: The gear

The checks

The span over three teeth above checks the flanks. The solid’s volume is compared with the volume from the areas, the face times the width of 20 and the hub’s disc times 12, less the bore and the keyway over their length of 32. The keyway is the rectangle 6 wide from the axis up to its top, \(22.8 - 10\), less the bore’s area under it. The mass is for steel 42CrMo4 (7.85 g/cm³), and the center of mass is measured with the origin at the gear’s center on its bottom face, to compare with your own model:

[15]:
under = 3 * math.sqrt(10**2 - 3**2) + 10**2 * math.asin(3 / 10)  # the bore's area above the axis, |x| < 3
volume = face.mass * 20 + math.pi * 20**2 * 12 - math.pi * 10**2 * 32 - (6 * (22.8 - 10) - under) * 32
c = body.center
print("volume", round(body.mass), "mm³, from the areas", round(volume))
print("mass", round(volume * 7.85e-6, 3), "kg")
print("center of mass", round(c.z, 2), "above the bottom face,", round(-c.y, 3), "off the axis, away from the keyway")
volume 40092 mm³, from the areas 40092
mass 0.315 kg
center of mass 14.43 above the bottom face, 0.16 off the axis, away from the keyway

The gear as STEP, for another CAD system:

[16]:
body.WriteStep("spur_gear.step")

The gear as STEP: spur_gear.step