Chain sprocket
A sprocket drives a roller chain. Each roller of the chain drops into a gap between two teeth and sits in its seat, an arc around the roller, while the flanks of the teeth guide it in and out. The seats’ centers lie on the pitch circle, one chain pitch apart, so the chain’s pitch and the number of teeth set the sprocket’s size. As a sketch, one gap is drawn, a seat with two flanks tangent to it and the tip of the next tooth, and a circular pattern repeats it around the wheel. Model the sprocket from the drawing in planex2d or in any CAD system, then check its area against the value at the end of the page. A solution in planex2d follows.

[1]:
import math
import planex as px
The tooth gap
The sprocket has 18 teeth for a chain of pitch 12.7 with rollers of 8.51. Its tip circle of 78 is a construction circle around the origin. The first gap lies on the \(x\) axis, and its chain runs counterclockwise around the origin, drawn roughly. It runs down the lower flank from the tip circle, around the roller’s place in the seat, back up the upper flank, and along the tip circle for the tip of the next tooth. With auto_constraint=True, the flanks stay tangent to the seat, and the tip
meets the upper flank at a corner (Figure 1):
[3]:
sprocket = px.Sketch(auto_constraint=True)
sprocket.Circle(78 / 2, id="tip_circle", construction=True)
sprocket.Move((38.5, -6), dir=(-0.6, 0.8)).Arc(25, 15, id="flank_low")
sprocket.Arc(4.3, -125, id="seat") # a negative sweep turns right: around the roller's place
sprocket.Arc(25, 15, id="flank_up")
sprocket.Turn(80).Arc(39, 12, id="tip"); # Turn(80): a corner, the tooth's tip
The dimensions
The seat has a radius of 4.3, a little larger than the roller’s 4.255, and spans the seating angle of 125°, symmetric about the \(x\) axis, its center on the axis. The flanks have a radius of 25, the second equal to the first, and the upper one ends on the tip circle, where the tip begins around the origin. The seat’s distance from the origin and the lower flank’s start stay free until the pattern, which leaves 3 degrees of freedom (Figure 2):
[5]:
sprocket.Constrain("tip_circle.center", "origin", px.Coincident)
sprocket.Constrain("tip_circle", px.Diameter, 78, id="tip_d")
sprocket.Constrain("seat.center", "H", px.Coincident)
sprocket.Constrain("seat.mid", "H", px.Coincident)
sprocket.Constrain("seat", px.Radius, 4.3, id="seat_r")
sprocket.Constrain("seat", px.Angle, -125, id="seat_angle") # an arc's sweep, negative: clockwise
sprocket.Constrain("flank_up", px.Radius, 25, id="flank_r")
sprocket.Constrain("flank_low", "flank_up", px.Equal)
sprocket.Constrain("flank_up.end", "tip_circle", px.Coincident) # a point on a circle
sprocket.Constrain("tip.center", "origin", px.Coincident)
print("status", sprocket.status, "| degrees of freedom", sprocket.dof)
status under | degrees of freedom 3
The pattern
CircularPattern repeats the gap and the tip around the origin, 18 times in all, 20° apart. The copies are teeth.1.flank_low and so on to teeth.17.tip. The tip’s end tied to the start of the first copy’s lower flank closes the outline, and the chain’s pitch of 12.7 between the first two seats’ centers puts the seats on the pitch circle. Nothing in the sketch is left free (Figure 3):
[7]:
sprocket.CircularPattern(["flank_low", "seat", "flank_up", "tip"], "origin", 18, id="teeth")
sprocket.Constrain("tip.end", "teeth.1.flank_low.start", px.Coincident)
sprocket.Constrain("seat.center", "teeth.1.seat.center", px.Distance, 12.7, id="pitch")
print("status", sprocket.status, "| degrees of freedom", sprocket.dof)
status full | degrees of freedom 0
The bore and the holes
The bore is 25 across. The four holes of 6.6, for the screws that hold the sprocket on its hub, lie on a bolt circle of 46, the first one on the \(x\) axis, and a second circular pattern repeats it, 90° apart (Figure 4):
[9]:
sprocket.Circle(25 / 2, id="bore")
sprocket.Constrain("bore.center", "origin", px.Coincident)
sprocket.Constrain("bore", px.Diameter, 25, id="bore_d")
sprocket.Circle(46 / 2, id="bolt_circle", construction=True)
sprocket.Constrain("bolt_circle.center", "origin", px.Coincident)
sprocket.Constrain("bolt_circle", px.Diameter, 46, id="bolt_circle_d")
sprocket.Circle(6.6 / 2, center=(23, 2), id="hole")
sprocket.Constrain("hole.center", "bolt_circle", px.Coincident)
sprocket.Constrain("hole.center", "H", px.Coincident)
sprocket.Constrain("hole", px.Diameter, 6.6, id="hole_d")
sprocket.CircularPattern(["hole"], "origin", 4, id="holes")
print("status", sprocket.status, "| degrees of freedom", sprocket.dof)
status full | degrees of freedom 0
The checks
The seats’ centers lie on the pitch circle, whose diameter follows from the pitch \(p\) and the number of teeth \(z\) as \(p / \sin(180^\circ / z)\), here 73.136. This is the area, to compare with your own model. The sprocket is symmetric under a half turn, so its centroid is the center (Figure 5):
[11]:
d = 12.7 / math.sin(math.pi / 18) # the pitch diameter
face = sprocket.Face()
c = face.center
print("seats on a circle of", round(2 * math.hypot(*sprocket.Location("teeth.5.seat.center")[:2]), 6),
"| pitch diameter", round(d, 6))
print("area", round(face.mass, 2), "mm²")
print("centroid", tuple(round(v, 6) for v in c[:2]))
seats on a circle of 73.136385 | pitch diameter 73.136385
area 3145.1 mm²
centroid (-0.0, 0.0)
The sprocket as DXF in millimeters, for another CAD system or a laser cutter:
[13]:
sprocket.WriteDXF("chain_sprocket.dxf", unit=px.mm, scale=1) # scale=1: the numbers as they are
The sprocket as DXF: chain_sprocket.dxf