Back to Hub | RP2040 MicroPython Lab
Metronome Stopped

🎵 Servo Motor Musical Metronome & PWM Timing

Learn how RP2040 50 Hz PWM duty cycles (duty_u16) drive a physical servo pendulum arm to oscillate at precise musical tempos (BPM) and time signatures.

⏱️ Mechanical Servo Metronome Beat: 1 / 4 • DOWNBEAT
45° 90° 135° SG90 SERVO Angle: 90.0° duty_u16: 4915 (1.50ms)
🎛️ Tempo & Servo Motion Parameters
120 BPM
40 (Largo) 120 (Moderato) 240 (Presto)
📊 50 Hz PWM Servo Duty Conversion Period T = 20ms

Standard servos run on a $50\text{ Hz}$ PWM carrier frequency ($20\text{ ms}$ period). $0.5\text{ ms}$ ($0^\circ$) maps to `duty_u16(1638)`, while $2.5\text{ ms}$ ($180^\circ$) maps to `duty_u16(8192)`.

Active Servo Position Formula:
Pulse Width = 1.50 ms
duty_u16 = int((Pulse / 20.0) × 65535) = 4915
Beat Duration: 500 ms / beat RP2040 PWM: 16-bit Hardware
🐍 MicroPython Hardware Loop Code RP2040 Physical Code
💡 Hardware Implementation Tip: In physical hardware, a servo cannot jump instantly! You must command LEFT motion, pause for the beat delay, then command RIGHT motion in a continuous loop:
import machine, time

# Configure 50Hz PWM Servo on GP15
servo = machine.PWM(machine.Pin(15))
servo.freq(50)

# Define Swing Duty Limits (45° & 135°)
DUTY_LEFT = 3276 # 1.0ms pulse (45°)
DUTY_RIGHT = 6553 # 2.0ms pulse (135°)
bpm = 120
delay = 60.0 / bpm # Beat interval in sec

while True:
  # 1. Swing Servo LEFT (Beat Downbeat)
  servo.duty_u16(DUTY_LEFT)
  time.sleep(delay)

  # 2. Swing Servo RIGHT (Upbeat)
  servo.duty_u16(DUTY_RIGHT)
  time.sleep(delay)
📝 Servo PWM & Tempo Timing Quiz
Why do we set the MicroPython PWM frequency to exactly 50 Hz when driving RC servo motors?