Geneva drive and its locking disc

The example is a Geneva drive, the Maltese cross of film projectors and watch movements. A driver turning steadily makes the wheel step a quarter turn and then holds it locked until the next step. The pin enters a slot along its axis, so the step starts and ends without a jolt, and between steps, a locking disc on the driver sits in a concave arc of the wheel. The driver’s locking disc is shaped with Boolean operations: it loses whatever the wheel sweeps through while it turns.

A Geneva drive stepping its wheel a quarter turn per turn of the driver

[1]:
import math
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import HTML
import planex as px

The dimensions

The wheel has n = 4 slots. The driver’s pin, of radius pin = 4, sits on a crank of a = 30, and the parts keep a clearance gap of 0.2. The rest follows:

  • the pin enters a slot along its axis, so the crank is at right angles to the slot there, and the center distance is c = a / sin(π / n);

  • the wheel reaches out to the pin’s sides there, so its radius is the hypotenuse of c cos(π / n) and the pin’s radius;

  • the pin is in a slot for 2 (90° − 180° / n) of each driver turn;

  • the locking disc has a radius of 0.72 a.

[3]:
n = 4
a = 30.0
pin = 4.0
gap = 0.2
c = a / math.sin(math.pi / n)
rim = math.hypot(c * math.cos(math.pi / n), pin)
span = 90 - 180 / n
lock = 0.72 * a
print("center distance", c, "wheel radius", rim, "pin in a slot for", 2 * span, "degrees")
center distance 42.42640687119285 wheel radius 30.265491900843116 pin in a slot for 90.0 degrees

The wheel

The wheel is a disc with n slots pointing at its center. Between the slots are concave arcs of the locking disc’s radius plus the clearance, centered where the driver’s axle is when that arc faces it. The slots are as wide as the pin plus the clearance and reach 1 deeper than the pin goes, and the wheel has a bore of 12 (Figure 1).

[4]:
def disc(x, y, r):
    return px.QuickSketch().Circle(x, y, r).Face()


def slot(q):
    w = pin + gap / 2
    depth = c - a - pin - 1.0
    s = px.QuickSketch((depth, -w)).Rectangle(2 * rim - depth, 2 * w).Face()
    return s.Rotated((0, 0), 180 + 360 * (q + 0.5) / n).Translated((c, 0))


def arc_cut(q):
    t = math.radians(180 + 360 * q / n)
    return disc(c + c * math.cos(t), c * math.sin(t), lock + gap)


wheel = px.Subtract([disc(c, 0, rim), *[slot(q) for q in range(n)], *[arc_cut(q) for q in range(n)], disc(c, 0, 6)])
The wheel
Figure 1: The Geneva wheel with four slots

The driver

The driver has the pin on a crank arm, which runs in a layer behind the wheel, and the locking disc in the wheel’s layer. While the wheel steps, the tips between its slots swing past the driver. The locking disc loses everything the wheel sweeps through: the wheel, grown by half the clearance, is placed at every half degree of the step, as the driver sees it, and the union of these positions is subtracted. wheel_angle gives the wheel’s angle for every angle of the driver; see Motion below. The driver has a bore of 12 too, and its arm is 8 wide (Figure 2).

[6]:
def wheel_angle(theta):
    turns, rest = divmod(theta + 180, 360)
    rest -= 180
    if -span <= rest <= span:
        t = math.radians(rest)
        psi = math.degrees(math.atan2(a * math.sin(t), a * math.cos(t) - c)) % 360
        return -turns * 360 / n + psi - (180 + span)
    return -(turns + (rest > span)) * 360 / n


grown = wheel.Offset(gap / 2, inplace=False)
steps = [q / 2 for q in range(-2 * round(span), 2 * round(span) + 1)]
sweep = px.Unify([grown.Rotated((c, 0), wheel_angle(t)).Rotated((0, 0), -t) for t in steps])
locking = disc(0, 0, lock) - sweep - disc(0, 0, 6)
pin_face = disc(a, 0, pin)
arm = px.QuickSketch((0, -pin)).Rectangle(a, 2 * pin).Face()
The wheel, the driver's arm, locking disc and pin
Figure 2: The Geneva drive in the position of the drawing

Motion

While the pin is in a slot, the slot points at the pin, and otherwise the wheel stands still, as wheel_angle above computes it (Figure 3).

wheel angle [°] over driver angle [°]: wheel -180 -0, -150 -0, -120 -0, -90 -0, -60 -0, -30 -2.63, 0 -45, 30 -87.4, 60 -90, 90 -90, 120 -90, 150 -90
Figure 3: A quarter turn of the wheel per turn of the driver

Checks over a full turn of the driver, in steps of half a degree:

  • the wheel steps exactly 360° / n per turn and stands still for the rest of it;

  • the parts in the wheel’s layer never overlap, and they come no closer than the clearance.

[9]:
def apart(t):
    placed = wheel.Rotated((c, 0), wheel_angle(t))
    return min(locking.Rotated((0, 0), t).Distance(placed), pin_face.Rotated((0, 0), t).Distance(placed))


def overlap(t):
    return ((locking.Rotated((0, 0), t) + pin_face.Rotated((0, 0), t)) * wheel.Rotated((c, 0), wheel_angle(t))).mass


standing = sum(1 for t in thetas if abs(wheel_angle(t + 0.5) - wheel_angle(t)) < 1e-12) / len(thetas)
print("step per driver turn", wheel_angle(-180) - wheel_angle(179.999), "degrees")
print("standing for", standing, "of the turn, exact", 1 - 2 * span / 360)
print("largest overlap", max(overlap(t) for t in thetas), "closest approach", round(min(apart(t) for t in thetas), 3),
      "clearance", gap / 2)
step per driver turn 90.0 degrees
standing for 0.75 of the turn, exact 0.75
largest overlap 0.0 closest approach 0.1 clearance 0.1

In motion

The drive through a full turn of the driver:

[10]: