Rocker
The rocker, or bell crank, of a small race car’s pushrod suspension turns the travel of the pushrod into the stroke of the damper. It pivots on a bearing in its hub, the rod end of the pushrod sits in the fork of its lower arm, and the damper is bolted to its upper boss. Its outline is one chain of tangent arcs and lines around the hub, the boss and the eye. The bosses stand proud of both faces, and the fork is a slot through the middle of the thickness. Model the rocker from the drawing in planex2d or in any CAD system, then check its volume, mass and center of mass against the values at the end of the page. A solution in planex2d follows.

[1]:
import math
import netgen.occ as occ
import planex as px
The outline
The outline is the rocker’s plan, sketched in the xy plane, which becomes the middle plane of its thickness. It is one chain, drawn roughly from the hub out. It runs along the lower arm’s underside, a concave arc that turns right, then around the eye and back along the lower arm’s top. A convex arc of large radius follows, a small arc turning right into the inner corner, the upper arm’s right flank, the boss, the left flank, and the hub back to the start. With auto_constraint=True, every
joint of the chain becomes a tangency, and where the chain closes, a coincidence and a tangency are added. The arcs and lines carry ids for the dimensions, which the interactive plot shows under the mouse (Figure 1).
[3]:
rocker = px.Sketch(auto_constraint=True)
rocker.Move((14, -17), dir=(1, 0.8)).Arc(50, -80, id="lower") # a negative sweep turns right: a concave arc
rocker.Arc(11, 185, id="eye")
rocker.Arc(110, 33, id="upper")
rocker.Arc(10, -72, id="corner")
rocker.Line(42, id="right_flank")
rocker.Arc(14, 162, id="boss")
rocker.Line(65, id="left_flank")
rocker.Arc(22, 132, id="hub")
rocker.Constrain("hub.end", "lower.start", px.Coincident)
rocker.Constrain("hub", "lower", px.Tangent)
rocker.Plot(backend="plotly")
The dimensions
The hub’s center is the origin. The boss, the eye and the center of the inner corner’s arc are placed by their distances from the hub’s center lines, and the radii give the arcs their sizes. The convex arc of 110 and the corner’s arc of 10 could still slide along the eye and the boss together. The corner’s center, 28 across and 32 up from the hub’s center, holds them. With these, nothing in the sketch is left free (Figure 1):
[4]:
rocker.Constrain("hub.center", "origin", px.Coincident)
rocker.Constrain("boss.center", "V", px.Distance, 5, id="boss_x")
rocker.Constrain("boss.center", "H", px.Distance, 70, id="boss_y")
rocker.Constrain("eye.center", "V", px.Distance, 85, id="eye_x")
rocker.Constrain("eye.center", "H", px.Distance, 10, id="eye_y")
rocker.Constrain("corner.center", "V", px.Distance, 28, id="corner_x")
rocker.Constrain("corner.center", "H", px.Distance, 32, id="corner_y")
rocker.Constrain("hub", px.Radius, 22, id="hub_r")
rocker.Constrain("boss", px.Radius, 14, id="boss_r")
rocker.Constrain("eye", px.Radius, 11, id="eye_r")
rocker.Constrain("lower", px.Radius, 50, id="lower_r")
rocker.Constrain("upper", px.Radius, 110, id="upper_r")
rocker.Constrain("corner", px.Radius, 10, id="corner_r")
print("status", rocker.status, "| degrees of freedom", rocker.dof)
status full | degrees of freedom 0
The plate and the bosses
px.Pad extrudes the outline 10 to both sides of the xy plane, 20 in all. The bosses, the hub’s of 44 and the upper one of 28, are circles in the same middle plane at the solved centers of the hub’s and the boss’s arcs, which Location gives. px.Fix holds each where it is drawn, with its size. Padded 15 to both sides, they are 30 long and stand 5 proud of each face, and + fuses them with the plate (Figure 2):
[6]:
block = px.Pad(rocker, 10, length2=10)
bosses = px.Sketch()
bosses.Circle(44 / 2, px.Fix, center=rocker.Location("hub.center"), id="hub_boss")
bosses.Circle(28 / 2, px.Fix, center=rocker.Location("boss.center"), id="upper_boss")
block = block + px.Pad(bosses, 15, length2=15)
The fork
The fork’s slot, 8 wide, runs through the middle of the thickness from the eye’s end to an arc of radius 60 around the hub, clear of the inner corner. Its profile is a region in the middle plane, a rectangle over the lower arm’s end less a disc of radius 60 around the hub. px.Pocket with length2 cuts 4 to each side of the plane, only where the region meets the rocker (Figure 3):
[8]:
region = px.QuickSketch().Move((30, -40)).Rectangle(90, 80).Face() - px.Face([px.Circle((0, 0), 60)])
block = px.Pocket(block, region, 4, length2=4) # 4 to each side of the middle plane: a slot 8 wide
(a) The region of the slot in the middle plane
(b) The slot through the middle of the lower arm
The holes
The bearing seat of 26 in the hub, the hole of 10 for the damper’s bolt in the upper boss and the hole of 8 for the rod end’s bolt in the eye are circles in the middle plane too. Like the bosses, they are fixed at the arcs’ centers. Pocketed 20 to both sides, they go through everything, the eye’s hole through both cheeks of the fork (Figure 4):
[10]:
holes = px.Sketch()
holes.Circle(26 / 2, px.Fix, center=rocker.Location("hub.center"), id="bearing_seat")
holes.Circle(10 / 2, px.Fix, center=rocker.Location("boss.center"), id="damper_hole")
holes.Circle(8 / 2, px.Fix, center=rocker.Location("eye.center"), id="eye_hole")
block = px.Pocket(block, holes, 20, length2=20)
The checks
These are the volume, the mass in aluminum EN AW-7075 (2.81 g/cm³) and the center of mass, with the origin at the hub’s center in the middle plane, to compare with your own model. The volume is the outline’s area times 20, plus the bosses’ 10 of length beyond the plate, less the holes and the slot. The eye’s hole runs through the two cheeks, 12 of the thickness, and the slot’s area in plan is where the region and the outline overlap, their intersection *. The rocker is symmetric about its
middle plane, so its center of mass lies in it:
[12]:
outline = rocker.Face()
slot = (outline * region).mass # the slot's area in plan
exact = (outline.mass * 20 + math.pi * (22**2 + 14**2) * 10 - math.pi * (13**2 + 5**2) * 30 - math.pi * 4**2 * 12
- slot * 8)
c = block.center
print("volume", round(block.mass, 1), "mm³, exact", round(exact, 1))
print("mass", round(block.mass * 2.81e-6, 3), "kg")
print("center of mass", tuple(round(v, 2) for v in (c.x, c.y)), "in the middle plane, off it by", round(abs(c.z), 6))
volume 107811.3 mm³, exact 107811.3
mass 0.303 kg
center of mass (13.22, 22.13) in the middle plane, off it by 0.0
The rocker as STEP, for another CAD system:
[13]:
block.WriteStep("rocker.step")
The rocker as STEP: rocker.step