Skip to content

Involute Gear Systems

Involute Gear Systems hero image
Modified:
Published:

Generate mathematically precise involute spur gears directly from parametric equations using CadQuery. This lesson walks through tooth profile derivation, meshing geometry, Lewis bending stress verification, and full gear train assembly with housing, all exportable as 3D-printable STEP files. #InvoluteGears #GearTrain #PythonCAD

Learning Objectives

By the end of this lesson, you will be able to:

  1. Derive involute curve equations from first principles (base circle, pressure angle, parametric form)
  2. Implement a parametric spur gear generator: make_spur_gear(module, num_teeth, width)
  3. Calculate center distances and backlash for meshing gear pairs
  4. Verify tooth strength using the Lewis bending stress equation
  5. Assemble a multi-stage gear train with shafts, bearing bores, and housing
  6. Export a complete 3D-printable gear train as STEP and STL files

Involute Gear Mathematics



Before writing any code, you need to understand the geometry that makes involute gears work. The involute curve has a remarkable property: when two involute gears mesh, the contact point always lies on a straight line (the line of action), producing a constant velocity ratio regardless of small center-distance errors. This is why involute gears dominate mechanical engineering.

Fundamental Gear Parameters

Module (m)

The fundamental size parameter. Module equals the pitch circle diameter divided by the number of teeth: . Standard modules (ISO 54): 0.5, 0.8, 1.0, 1.25, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0 mm.

Pressure Angle (alpha)

The angle between the tooth face and a radial line at the pitch circle. Standard value: (ISO 53). This defines the shape of the involute curve and the direction of force transmission.

Number of Teeth (z)

Determines the gear ratio when paired with another gear. Minimum practical value is about 17 teeth for 20-degree pressure angle (below this, undercutting occurs unless profile shift is applied).

Face Width (b)

The gear thickness in the axial direction. Typical rule of thumb: to for general-purpose gears. Wider face = higher load capacity but more sensitive to misalignment.

Circle Definitions

Every gear has four concentric circles that define its geometry:

CircleSymbolFormulaDescription
Pitch circleWhere gears “roll” against each other
Base circleWhere the involute curve originates
Addendum circleOuter tip of the teeth
Dedendum circleRoot of the teeth (includes clearance)

The addendum (tooth height above pitch circle) is:

The dedendum (tooth depth below pitch circle, including clearance) is:

The total tooth height is therefore .

The Involute Curve

The involute of a circle is the path traced by the end of a taut string unwinding from that circle. Mathematically, for a base circle of radius :

where is the parameter (the “unwinding angle” in radians, starting from 0).

The involute function (used for angular positioning of teeth) is:

This function appears when calculating the angular thickness of a tooth at any given radius.

Tooth Angular Thickness

At the pitch circle, the angular thickness of one tooth (in radians) is:

This means each tooth occupies half of the angular pitch at the pitch circle, and the gap occupies the other half (for zero backlash).

Involute Profile Generation in Python



The first step is to implement the involute curve as a Python function that returns a list of points suitable for CadQuery:

import cadquery as cq
import math
import numpy as np
def involute_point(r_base, t):
"""
Calculate a single point on the involute of a circle.
Parameters:
r_base (float): Base circle radius in mm
t (float): Involute parameter (unwinding angle in radians)
Returns:
tuple: (x, y) coordinates of the involute point
"""
x = r_base * (math.cos(t) + t * math.sin(t))
y = r_base * (math.sin(t) - t * math.cos(t))
return (x, y)
def involute_function(alpha):
"""
The involute function: inv(alpha) = tan(alpha) - alpha.
Parameters:
alpha (float): Angle in radians
Returns:
float: Involute function value
"""
return math.tan(alpha) - alpha
def generate_involute_profile(r_base, r_tip, num_points=20):
"""
Generate a list of points along an involute curve from the
base circle to the tip circle.
Parameters:
r_base (float): Base circle radius (mm)
r_tip (float): Addendum (tip) circle radius (mm)
num_points (int): Number of points to generate
Returns:
list: List of (x, y) tuples along the involute
"""
# Calculate the parameter t at the tip circle
# At any point on the involute, the distance from center is:
# r = r_base * sqrt(1 + t^2)
# So: t_tip = sqrt((r_tip/r_base)^2 - 1)
t_tip = math.sqrt((r_tip / r_base) ** 2 - 1)
points = []
for i in range(num_points + 1):
t = t_tip * i / num_points
pt = involute_point(r_base, t)
points.append(pt)
return points

Building a Complete Tooth Profile

A single gear tooth consists of two involute flanks (left and right), connected by the tip arc at the top and the root fillet at the bottom:

def generate_tooth_profile(module, num_teeth, pressure_angle_deg=20.0,
num_points=20):
"""
Generate the 2D profile of a single gear tooth centered at
the positive X-axis.
Returns left flank, tip arc, and right flank as point lists.
"""
alpha = math.radians(pressure_angle_deg)
# Circle radii
r_pitch = module * num_teeth / 2.0
r_base = r_pitch * math.cos(alpha)
r_tip = r_pitch + module # addendum circle
r_root = r_pitch - 1.25 * module # dedendum circle
# Handle case where base circle is larger than root circle
r_start = max(r_base, r_root)
# Generate the right flank involute (positive side)
right_flank = generate_involute_profile(r_base, r_tip, num_points)
# Tooth angular half-thickness at the pitch circle
# theta_pitch = pi/(2*z) + 2*inv(alpha)/z (for standard gears)
inv_alpha = involute_function(alpha)
# Angular half-thickness at the base circle
# The involute starts at angle 0 on the base circle.
# At pitch circle: angle = inv(alpha)
# Tooth half-thickness at pitch circle = pi/(2*z)
# So the tooth center offset = pi/(2*z) + inv(alpha)
tooth_half_angle = math.pi / (2 * num_teeth) + inv_alpha
# Rotate the right flank so the tooth is centered on the X-axis
right_rotated = []
for (x, y) in right_flank:
angle = tooth_half_angle
xr = x * math.cos(angle) - y * math.sin(angle)
yr = x * math.sin(angle) + y * math.cos(angle)
right_rotated.append((xr, yr))
# Mirror to get the left flank
left_rotated = [(x, -y) for (x, y) in right_rotated]
left_rotated.reverse() # reverse order for continuous path
return left_rotated, right_rotated, r_root, r_tip

Single Gear Function: make_spur_gear()



def make_spur_gear(module, num_teeth, width, pressure_angle_deg=20.0,
bore_diameter=0, hub_diameter=0, hub_length=0,
num_points=20):
"""
Generate a complete involute spur gear.
Parameters:
module (float): Gear module in mm (e.g., 2.0)
num_teeth (int): Number of teeth (e.g., 20)
width (float): Face width (gear thickness) in mm
pressure_angle_deg (float): Pressure angle in degrees (default 20)
bore_diameter (float): Central bore diameter in mm (0 = no bore)
hub_diameter (float): Hub outer diameter in mm (0 = no hub)
hub_length (float): Hub length extending from face in mm
num_points (int): Involute curve resolution
Returns:
cq.Workplane: Complete spur gear solid
"""
alpha = math.radians(pressure_angle_deg)
# ─── Calculate circle radii ───
r_pitch = module * num_teeth / 2.0
r_base = r_pitch * math.cos(alpha)
r_tip = r_pitch + module
r_root = r_pitch - 1.25 * module
# Ensure root radius is positive and reasonable
if r_root < 0:
raise ValueError(
f"Root circle is negative (r_root={r_root:.2f}). "
f"Increase module or num_teeth."
)
r_start = max(r_base, r_root)
# ─── Involute function value at pressure angle ───
inv_alpha = involute_function(alpha)
# Tooth half-angle at the base circle
tooth_half_angle = math.pi / (2 * num_teeth) + inv_alpha
# ─── Generate one tooth profile ───
# Right flank: involute from base circle to tip
t_tip = math.sqrt((r_tip / r_base) ** 2 - 1)
right_pts = []
for i in range(num_points + 1):
t = t_tip * i / num_points
pt = involute_point(r_base, t)
# Rotate by tooth_half_angle to center tooth on X-axis
x = pt[0] * math.cos(tooth_half_angle) \
- pt[1] * math.sin(tooth_half_angle)
y = pt[0] * math.sin(tooth_half_angle) \
+ pt[1] * math.cos(tooth_half_angle)
right_pts.append((x, y))
# Left flank: mirror of right flank
left_pts = [(x, -y) for (x, y) in right_pts]
left_pts.reverse()
# ─── Build the complete gear outline ───
# Strategy: for each tooth, draw left_flank -> tip_arc -> right_flank
# then root_arc to the next tooth
angular_pitch = 2 * math.pi / num_teeth
all_points = []
for i in range(num_teeth):
angle = i * angular_pitch
cos_a = math.cos(angle)
sin_a = math.sin(angle)
# Rotate left flank points
for (x, y) in left_pts:
xr = x * cos_a - y * sin_a
yr = x * sin_a + y * cos_a
all_points.append((xr, yr))
# Tip arc point (at the tip of the tooth)
# Use the last point of left flank and first of right flank
# to interpolate across the tip
tip_mid_x = r_tip * math.cos(angle)
tip_mid_y = r_tip * math.sin(angle)
all_points.append((tip_mid_x, tip_mid_y))
# Rotate right flank points
for (x, y) in right_pts:
xr = x * cos_a - y * sin_a
yr = x * sin_a + y * cos_a
all_points.append((xr, yr))
# Root arc: connect to next tooth's left flank
# Midpoint of root arc between this tooth and the next
next_angle = angle + angular_pitch / 2.0
root_x = r_root * math.cos(next_angle + angular_pitch * 0.05)
root_y = r_root * math.sin(next_angle + angular_pitch * 0.05)
all_points.append((root_x, root_y))
# ─── Create the 2D profile as a CadQuery wire ───
# Close the loop by repeating the first point, then use polyline
all_points.append(all_points[0])
wp = cq.Workplane("XY")
gear_profile = wp.polyline(all_points).close()
# Extrude to create the 3D gear body
gear = gear_profile.extrude(width)
# ─── Add bore if specified ───
if bore_diameter > 0:
gear = (
gear
.faces(">Z")
.workplane()
.hole(bore_diameter)
)
# ─── Add hub if specified ───
if hub_diameter > 0 and hub_length > 0:
hub = (
cq.Workplane("XY")
.workplane(offset=width)
.circle(hub_diameter / 2.0)
.extrude(hub_length)
)
gear = gear.union(hub)
# Bore through the hub as well
if bore_diameter > 0:
hub_bore = (
cq.Workplane("XY")
.workplane(offset=width)
.circle(bore_diameter / 2.0)
.extrude(hub_length)
)
gear = gear.cut(hub_bore)
# ─── Add keyway (optional, for shaft coupling) ───
# Standard DIN 6885 keyway dimensions could be added here
return gear

Meshing Gear Pair



Two involute gears mesh correctly when they share the same module and pressure angle. The center distance is determined by their pitch circle radii.

Center Distance Calculation

For a pair of gears with teeth counts (pinion) and (gear), both with module :

This is the standard center distance, the exact distance between shaft centers for zero backlash. In practice, you add a small amount of backlash to prevent binding:

where is typically 0.05 to 0.1 mm for 3D-printed gears and 0.02 to 0.05 mm for machined gears.

Contact Ratio

The contact ratio is the average number of teeth in contact at any time. For smooth operation, is required:

where are the addendum radii and are the base circle radii of the two gears. A contact ratio above 1.0 means there is always at least one pair of teeth in contact, ensuring continuous power transmission.

Backlash

Backlash is the gap between meshing teeth when one gear is held stationary. Some backlash is necessary to prevent jamming from thermal expansion, manufacturing tolerances, and lubrication space. For 3D-printed gears, typical backlash values are:

Printing MethodRecommended Backlash
FDM (0.4mm nozzle)0.15 - 0.25 mm
SLA (standard resin)0.08 - 0.15 mm
SLS (nylon)0.10 - 0.20 mm
CNC machined0.02 - 0.05 mm

Backlash can be introduced by either increasing the center distance or reducing the tooth thickness.

def make_gear_pair(module, z1, z2, width, pressure_angle_deg=20.0,
backlash=0.1, bore1=0, bore2=0):
"""
Generate a meshing pair of involute spur gears.
Parameters:
module (float): Common module in mm
z1 (int): Number of teeth on pinion (smaller gear)
z2 (int): Number of teeth on gear (larger gear)
width (float): Face width in mm (same for both)
pressure_angle_deg (float): Common pressure angle
backlash (float): Backlash allowance in mm
bore1 (float): Pinion bore diameter (0 = no bore)
bore2 (float): Gear bore diameter (0 = no bore)
Returns:
tuple: (pinion, gear, center_distance) — both positioned for meshing
"""
alpha = math.radians(pressure_angle_deg)
# ─── Standard center distance ───
r1 = module * z1 / 2.0 # pinion pitch radius
r2 = module * z2 / 2.0 # gear pitch radius
center_distance = r1 + r2 + backlash
# ─── Contact ratio check ───
r_a1 = r1 + module # pinion addendum radius
r_b1 = r1 * math.cos(alpha) # pinion base radius
r_a2 = r2 + module # gear addendum radius
r_b2 = r2 * math.cos(alpha) # gear base radius
eps_num = (
math.sqrt(r_a1**2 - r_b1**2) +
math.sqrt(r_a2**2 - r_b2**2) -
center_distance * math.sin(alpha)
)
eps_den = math.pi * module * math.cos(alpha)
contact_ratio = eps_num / eps_den
print(f"Gear pair: z1={z1}, z2={z2}, m={module}")
print(f" Center distance: {center_distance:.3f} mm")
print(f" Gear ratio: {z2/z1:.3f}:1")
print(f" Contact ratio: {contact_ratio:.3f}")
if contact_ratio < 1.2:
print(f" WARNING: Contact ratio < 1.2 — consider more teeth")
# ─── Generate both gears ───
pinion = make_spur_gear(
module, z1, width,
pressure_angle_deg=pressure_angle_deg,
bore_diameter=bore1,
)
gear = make_spur_gear(
module, z2, width,
pressure_angle_deg=pressure_angle_deg,
bore_diameter=bore2,
)
# ─── Position the gears for meshing ───
# Pinion at origin, gear offset by center distance along X
# Rotate the gear so teeth interleave properly
# The angular offset for meshing:
# half-tooth rotation on the gear to fit between pinion teeth
mesh_angle = math.pi / z2 # rotate gear by half a tooth pitch
gear = (
gear
.rotate((0, 0, 0), (0, 0, 1), math.degrees(mesh_angle))
.translate((center_distance, 0, 0))
)
return pinion, gear, center_distance

Lewis Bending Stress Verification



The Lewis equation is the classical method for estimating bending stress at the root of a gear tooth. It treats each tooth as a cantilever beam loaded at its tip.

The Lewis Equation

where:

  • = bending stress at the tooth root (MPa)
  • = tangential force on the tooth (N)
  • = face width (mm)
  • = module (mm)
  • = Lewis form factor (dimensionless, depends on tooth count and pressure angle)

The tangential force relates to transmitted torque:

where is the torque in N-mm.

Lewis Form Factor

The Lewis form factor depends on the number of teeth and the pressure angle. For standard full-depth teeth:

Number of Teeth Lewis Form Factor
120.245
140.276
170.303
200.320
250.340
300.358
400.389
500.408
600.421
750.435
1000.447
1500.460
3000.472
Rack (inf)0.484

Stress Calculation Function

def lewis_bending_stress(module, num_teeth, width, torque_Nm,
pressure_angle_deg=20.0):
"""
Calculate the Lewis bending stress at the tooth root.
Parameters:
module (float): Gear module in mm
num_teeth (int): Number of teeth
width (float): Face width in mm
torque_Nm (float): Applied torque in N-m
pressure_angle_deg (float): Pressure angle in degrees
Returns:
dict: Stress analysis results
"""
# Lewis form factor lookup (20-degree pressure angle)
lewis_table = {
12: 0.245, 14: 0.276, 17: 0.303, 20: 0.320,
25: 0.340, 30: 0.358, 35: 0.374, 40: 0.389,
45: 0.399, 50: 0.408, 60: 0.421, 75: 0.435,
100: 0.447, 150: 0.460, 200: 0.468, 300: 0.472,
}
# Interpolate Lewis form factor
keys = sorted(lewis_table.keys())
if num_teeth <= keys[0]:
Y = lewis_table[keys[0]]
elif num_teeth >= keys[-1]:
Y = lewis_table[keys[-1]]
else:
# Linear interpolation
for i in range(len(keys) - 1):
if keys[i] <= num_teeth <= keys[i+1]:
t = (num_teeth - keys[i]) / (keys[i+1] - keys[i])
Y = lewis_table[keys[i]] * (1 - t) \
+ lewis_table[keys[i+1]] * t
break
# Pitch circle diameter
d = module * num_teeth # mm
# Tangential force
torque_Nmm = torque_Nm * 1000.0 # convert to N-mm
F_t = 2 * torque_Nmm / d # tangential force in N
# Lewis bending stress
sigma_b = F_t / (width * module * Y) # MPa
# Common material allowable stresses
materials = {
"PLA (3D printed)": 25, # MPa
"ABS (3D printed)": 30,
"Nylon PA12 (SLS)": 45,
"Acetal (POM)": 60,
"Steel (case hardened)": 250,
"Steel (through hardened)": 350,
}
results = {
"module": module,
"num_teeth": num_teeth,
"width": width,
"torque_Nm": torque_Nm,
"pitch_diameter": d,
"lewis_factor_Y": Y,
"tangential_force_N": F_t,
"bending_stress_MPa": sigma_b,
}
print(f"{'='*55}")
print(f"Lewis Bending Stress Analysis")
print(f"{'='*55}")
print(f"Module: {module} mm")
print(f"Teeth: {num_teeth}")
print(f"Face width: {width} mm")
print(f"Torque: {torque_Nm} N-m")
print(f"Pitch diameter: {d:.1f} mm")
print(f"Lewis factor Y: {Y:.3f}")
print(f"Tangential force: {F_t:.1f} N")
print(f"Bending stress: {sigma_b:.1f} MPa")
print(f"{''*55}")
print(f"Material Comparison:")
for mat, allowable in materials.items():
safety = allowable / sigma_b if sigma_b > 0 else float('inf')
status = "OK" if safety >= 1.5 else "FAIL"
print(f" {mat:30s} "
f"allow={allowable:>4d} MPa "
f"SF={safety:.2f} [{status}]")
print(f"{'='*55}")
return results
# Analyze a 3D-printed gear for a small robot arm
# Module 2, 25 teeth, 12mm wide, transmitting 2 N-m torque
results = lewis_bending_stress(
module=2.0,
num_teeth=25,
width=12.0,
torque_Nm=2.0,
)
# The function prints the full analysis automatically
# Check a higher-torque application
results_high = lewis_bending_stress(
module=3.0,
num_teeth=30,
width=20.0,
torque_Nm=15.0,
)

Multi-Stage Gear Train with Housing



The final project brings everything together: a two-stage gear reduction with shafts, bearing bores, and an enclosing housing, producing a complete 3D-printable assembly.

Gear Train Design Parameters

For this example, we will design a gear train with:

  • Input speed: 1000 RPM (from a small DC motor)
  • Output speed: approximately 110 RPM
  • Total reduction ratio: approximately 9:1 (achieved in two stages)
  • Stage 1: 18:54 teeth (3:1 ratio)
  • Stage 2: 20:60 teeth (3:1 ratio)
  • Module: 2.0 mm for both stages
  • Face width: 10 mm

The intermediate shaft carries both the stage 1 gear (54 teeth) and the stage 2 pinion (20 teeth) on the same shaft.

# ─── Gear Train Design Calculation ───
m = 2.0 # module (mm)
z1 = 18 # stage 1 pinion teeth
z2 = 54 # stage 1 gear teeth
z3 = 20 # stage 2 pinion teeth
z4 = 60 # stage 2 gear teeth
face_width = 10.0 # mm
# Gear ratios
ratio_1 = z2 / z1 # 3.0
ratio_2 = z4 / z3 # 3.0
total_ratio = ratio_1 * ratio_2 # 9.0
# Center distances
cd_1 = m * (z1 + z2) / 2.0 # stage 1: 72.0 mm
cd_2 = m * (z3 + z4) / 2.0 # stage 2: 80.0 mm
# Shaft positions (X coordinates, Y=0 for all)
x_input = 0.0
x_intermediate = cd_1
x_output = cd_1 + cd_2
# Shaft and bearing sizes
shaft_dia = 8.0 # mm (shaft diameter)
bearing_od = 16.0 # mm (bearing outer diameter)
bearing_width = 5.0 # mm (bearing width)
print(f"Two-stage gear train design:")
print(f" Stage 1 ratio: {ratio_1:.1f}:1 ({z1}:{z2})")
print(f" Stage 2 ratio: {ratio_2:.1f}:1 ({z3}:{z4})")
print(f" Total ratio: {total_ratio:.1f}:1")
print(f" Center distance 1: {cd_1:.1f} mm")
print(f" Center distance 2: {cd_2:.1f} mm")
print(f" Total width: {x_output:.1f} mm")

Gear Train Assembly Function

def make_gear_train():
"""
Generate a complete two-stage gear train assembly:
4 gears, 3 shafts, and a housing with bearing bores.
Returns:
dict: Dictionary of named components
"""
# ─── Design parameters ───
m = 2.0 # module
z1, z2 = 18, 54 # stage 1 teeth
z3, z4 = 20, 60 # stage 2 teeth
fw = 10.0 # face width
backlash = 0.15 # for 3D printing
shaft_dia = 8.0
bore_dia = 8.2 # slight clearance for shaft
bearing_od = 16.0
bearing_width = 5.0
wall = 4.0 # housing wall thickness
# ─── Center distances ───
cd1 = m * (z1 + z2) / 2.0 + backlash
cd2 = m * (z3 + z4) / 2.0 + backlash
# Shaft X positions
x_in = 0.0
x_mid = cd1
x_out = cd1 + cd2
# ─── Generate the four gears ───
gear1 = make_spur_gear(m, z1, fw, bore_diameter=bore_dia)
gear2 = make_spur_gear(m, z2, fw, bore_diameter=bore_dia)
gear3 = make_spur_gear(m, z3, fw, bore_diameter=bore_dia)
gear4 = make_spur_gear(m, z4, fw, bore_diameter=bore_dia)
# Position gears:
# Stage 1: gear1 at input shaft, gear2 at intermediate shaft
# Stage 2: gear3 at intermediate shaft (offset in Z), gear4 at output
gear1_z = bearing_width + wall # first gear layer Z position
gear3_z = gear1_z + fw + 3.0 # second stage Z offset (3mm gap)
# Rotate gear2 for meshing with gear1
mesh_angle_1 = 180.0 / z2
gear2 = gear2.rotate((0, 0, 0), (0, 0, 1), mesh_angle_1)
# Rotate gear4 for meshing with gear3
mesh_angle_2 = 180.0 / z4
gear4 = gear4.rotate((0, 0, 0), (0, 0, 1), mesh_angle_2)
# Translate to positions
gear1 = gear1.translate((x_in, 0, gear1_z))
gear2 = gear2.translate((x_mid, 0, gear1_z))
gear3 = gear3.translate((x_mid, 0, gear3_z))
gear4 = gear4.translate((x_out, 0, gear3_z))
# ─── Shafts ───
total_length = gear3_z + fw + wall + bearing_width
shaft_in = (
cq.Workplane("XY")
.circle(shaft_dia / 2.0)
.extrude(total_length)
.translate((x_in, 0, 0))
)
shaft_mid = (
cq.Workplane("XY")
.circle(shaft_dia / 2.0)
.extrude(total_length)
.translate((x_mid, 0, 0))
)
shaft_out = (
cq.Workplane("XY")
.circle(shaft_dia / 2.0)
.extrude(total_length)
.translate((x_out, 0, 0))
)
# ─── Housing ───
housing = make_gear_housing(
x_in, x_mid, x_out,
m, z1, z2, z3, z4,
fw, wall, bearing_od, bearing_width,
gear1_z, gear3_z,
)
return {
"gear1_input_pinion": gear1,
"gear2_stage1_gear": gear2,
"gear3_stage2_pinion": gear3,
"gear4_output_gear": gear4,
"shaft_input": shaft_in,
"shaft_intermediate": shaft_mid,
"shaft_output": shaft_out,
"housing": housing,
}

Complete Stress Verification for the Gear Train



With the gear train designed, verify that every gear in the system can handle the required torque:

def verify_gear_train(input_torque_Nm, input_rpm):
"""
Run Lewis bending stress analysis on all four gears
in the two-stage gear train.
"""
m = 2.0
z1, z2 = 18, 54
z3, z4 = 20, 60
fw = 10.0
ratio_1 = z2 / z1
ratio_2 = z4 / z3
# Stage 1: input pinion carries input torque
T1 = input_torque_Nm
rpm1 = input_rpm
# Stage 1 gear (and stage 2 pinion) carries amplified torque
T2 = T1 * ratio_1
rpm2 = rpm1 / ratio_1
# Stage 2 gear carries final torque
T3 = T2 * ratio_2
rpm3 = rpm2 / ratio_2
print(f"\n{'='*60}")
print(f"GEAR TRAIN STRESS VERIFICATION")
print(f"Input: {input_torque_Nm} N-m at {input_rpm} RPM")
print(f"Output: {T3:.2f} N-m at {rpm3:.1f} RPM")
print(f"{'='*60}\n")
print("─── Stage 1 Pinion (z=18) ───")
lewis_bending_stress(m, z1, fw, T1)
print("\n─── Stage 1 Gear (z=54) ───")
lewis_bending_stress(m, z2, fw, T2)
print("\n─── Stage 2 Pinion (z=20) ───")
lewis_bending_stress(m, z3, fw, T2)
print("\n─── Stage 2 Gear (z=60) ───")
lewis_bending_stress(m, z4, fw, T3)
# Verify: 0.5 N-m input at 1000 RPM (small DC motor)
verify_gear_train(0.5, 1000)

Design Guidelines for 3D-Printed Gears



Minimum Teeth

For 20-degree pressure angle, use at least 17 teeth to avoid undercutting. For 3D printing, 20+ teeth is recommended to ensure the tooth tips are thick enough to print cleanly.

Module Selection

For FDM printing with a 0.4mm nozzle, use module 1.5 or larger. The tooth tip width at the addendum circle must be at least 2 nozzle widths (0.8mm) for strength.

Print Orientation

Print gears flat (face on the build plate) for strongest teeth. Printing on edge gives better surface finish on the tooth flanks but weaker layer adhesion across the tooth root.

Post-Processing

Lightly sand the tooth flanks with 400-grit paper and apply a thin coat of lithium grease. This dramatically reduces wear and noise. For nylon (SLS) gears, no post-processing is typically needed.

ApplicationModuleMin TeethMaterialExpected Life
Educational model2.0-3.017PLALow duty
Hobby robot1.5-2.520PETG/NylonMedium duty
Light-duty mechanism1.5-2.025Nylon PA12 (SLS)Thousands of cycles
Prototype testing2.0-3.020Acetal (POM)High duty
Production (low volume)1.0-2.020+Steel (CNC)Continuous

Advanced Topics: Profile Shift



When the number of teeth is below 17 (for ), the cutting tool undercuts the tooth root, weakening the tooth. Profile shift (also called addendum modification) moves the cutting tool radially outward, preventing undercutting at the cost of a non-standard center distance.

The profile shift coefficient modifies the gear geometry:

For a pinion with 14 teeth, a typical profile shift of eliminates undercutting:

def make_shifted_gear(module, num_teeth, width, shift_x,
pressure_angle_deg=20.0, bore_diameter=0):
"""
Generate a spur gear with profile shift correction.
Parameters:
shift_x (float): Profile shift coefficient
(positive = outward, typical 0 to +0.5)
"""
alpha = math.radians(pressure_angle_deg)
# Modified circle radii
r_pitch = module * num_teeth / 2.0
r_base = r_pitch * math.cos(alpha)
r_tip = (module * (num_teeth + 2 + 2 * shift_x)) / 2.0
r_root = (module * (num_teeth - 2.5 + 2 * shift_x)) / 2.0
print(f"Profile-shifted gear: z={num_teeth}, x={shift_x}")
print(f" Tip diameter: {2*r_tip:.2f} mm "
f"(standard: {module*(num_teeth+2):.2f} mm)")
print(f" Root diameter: {2*r_root:.2f} mm "
f"(standard: {module*(num_teeth-2.5):.2f} mm)")
# Use the same involute generation as make_spur_gear
# but with modified tip and root radii
gear = make_spur_gear(
module, num_teeth, width,
pressure_angle_deg=pressure_angle_deg,
bore_diameter=bore_diameter,
)
# Note: for a full implementation, the involute generation
# inside make_spur_gear would need to use r_tip and r_root
# from the shifted values. This is left as an exercise.
return gear

Summary



What You Built

In this lesson, you built a complete involute gear system from mathematical first principles:

  • Involute mathematics: parametric equations, base circle, pressure angle, involute function
  • Single gear generator: make_spur_gear() with configurable module, teeth, width, bore, and hub
  • Meshing pair: center distance calculation, contact ratio verification, backlash control
  • Lewis bending stress: tooth root stress analysis with material safety factors
  • Two-stage gear train: four gears, three shafts, housing with bearing bores, mounting feet
  • Export: individual STEP/STL files and a complete colored assembly

Every parameter is a Python variable. Change the module, tooth count, or torque requirement and the entire design regenerates with updated geometry and stress verification.

Comments

Loading comments...


© 2021-2026 SiliconWit®. All rights reserved.