--- jupyter: description: 'A roller chain sprocket as a 2D CAD exercise: a dimensioned drawing with its sprocket data to model in planex2d or any CAD system, a solution from one tooth gap of a seat and two tangent flanks repeated around the wheel and tied to the chain''s pitch, and the area to check a model against.' --- # 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. ![The chain sprocket exercise: a dimensioned drawing of a plate sprocket with 18 teeth, a bore and four holes, with its sprocket data in a table](../_static/gallery/chain-sprocket.png){.result} ```python import math import planex as px ``` ```python nbsphinx="hidden" from docs_figures import Row ``` ## 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): ```python 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 ``` ```python nbsphinx="hide-input" Row((sprocket, "The first gap and the next tooth's tip, drawn roughly", {"fill": False, "view": ((26, 42), (-12, 12))}), caption="The tooth gap") ``` ## 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): ```python 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) ``` ```python nbsphinx="hide-input" Row((sprocket, "Every dimension and tie of the gap", {"constraints": True}), caption="The gap's dimensions") ``` ## 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): ```python 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) ``` ```python nbsphinx="hide-input" Row((sprocket, "The 18 teeth, the tip circle dashed", {"fill": False}), caption="The teeth") ``` ## 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): ```python 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) ``` ```python nbsphinx="hide-input" Row((sprocket, "Every dimension and tie of the sketch", {"constraints": True}), caption="The fully constrained sketch") ``` ## 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): ```python 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])) ``` ```python nbsphinx="hide-input" Row((face, "The chain sprocket", {}), caption="The chain sprocket") ``` The sprocket as DXF in millimeters, for another CAD system or a laser cutter: ```python sprocket.WriteDXF("chain_sprocket.dxf", unit=px.mm, scale=1) # scale=1: the numbers as they are ``` The sprocket as DXF: [chain_sprocket.dxf](chain_sprocket.dxf) ```python nbsphinx="hidden" import sys sys.path.insert(0, "..") import matplotlib.pyplot as plt from drawings import LANDSCAPE, SheetFigure, Table, View from gallery import save_figure # the pitch circle and the bolt circle as center lines; the tooth form too small to dimension at 1:1, so it goes into # the sprocket data table with the chain's sizes, beside the view on a landscape sheet view = View([(sprocket, {"tip_d": (90, "across", -52), "bore_d": 135, "bolt_circle_d": 45, "hole_d": (300, "leader", 4)}, {"bolt_circle": "pitch", "bore": "lines", "hole": "lines"})], circles=[((0, 0), d / 2, "pitch")], axes=[((-44, 0), (44, 0), (0, 0)), ((0, -44), (0, 44), (0, 0))]) data = Table([("Number of teeth z", 18), ("Chain pitch p", 12.7), ("Roller diameter", 8.51), ("Pitch diameter d", round(d, 3)), ("Seat radius", 4.3), ("Seating angle", "125°"), ("Flank radius", 25)], at=(58, 24.5), widths=(46, 18)) drawing = SheetFigure([view, data], margin=20, notes=("planex2d.org", "2D exercise 19"), sheet=LANDSCAPE) print("scale", drawing.planex_scale, "| paper", [round(v * 25.4) for v in drawing.get_size_inches()], "mm") save_figure(drawing, "chain-sprocket", dpi=200) plt.close(drawing) ```