🎵 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
🎛️ 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?