Your microcontroller’s pins are either fully on or fully off. PWM is the clever trick that makes them behave like everything in between — and it’s behind almost every moving part on your robot.
What is PWM?
PWM stands for Pulse Width Modulation. Instead of outputting a steady voltage, a PWM pin rapidly switches between high and low many times per second. The ratio of time spent high versus the total cycle time is called the duty cycle, expressed as a percentage.
- 0 % duty cycle — pin stays low. No output.
- 50 % duty cycle — high half the time, low half the time.
- 100 % duty cycle — pin stays high. Full output.
Because the switching happens so fast (typically 50 Hz to 1 kHz or more), the receiving device effectively sees an average voltage. That’s how a digital chip can “fake” an analogue signal.
Why robot builders care
Servo motors expect a 50 Hz PWM signal where the pulse width (not the duty cycle percentage) sets the angle — typically 1 ms for 0°, 1.5 ms for 90°, and 2 ms for 180°. Get that pulse width right and you can position a servo arm exactly where you want it with a single line of code.
DC motors are different: you run them faster or slower by raising or lowering the duty cycle, usually through an H-bridge driver chip. A 30 % duty cycle spins the motor gently; 90 % and it’s flat out.
PWM also handles LEDs. Fading an LED in and out is just a duty-cycle sweep — the LED reacts to the average power, not the individual pulses.
Get started
The Raspberry Pi Pico has up to 16 PWM channels built in, accessible directly from MicroPython with just a few lines:
from machine import Pin, PWM
servo = PWM(Pin(0))
servo.freq(50) # 50 Hz for hobby servos
servo.duty_u16(4915) # ~1.5 ms pulse — centre position
The Raspberry Pi Pico GPIO Mastery course covers PWM hands-on, including how to calculate the correct duty values for servo positioning and motor speed control.
Once you need more than a couple of servos, you’ll hit the Pico’s channel limit fast. A PCA9685 breakout board solves this — it’s a dedicated 16-channel PWM driver that offloads all the timing work over I2C, freeing your microcontroller to think about the bigger picture. The Building a Robot Arm with Raspberry Pi and PCA9685 course builds exactly this kind of system from scratch.
For a complete robot project that puts PWM-controlled motors and sensors together, the MicroPython Robotics Projects course is a natural next step — it goes from GPIO basics to autonomous robots, with motor control via PWM throughout.
A good first mini-project: wire up a single hobby servo to pin 0 on a Pico, run the code above, then change the duty_u16 value between roughly 1638 (0°) and 8192 (180°) and watch it sweep.
Reacts well with
More Signals & Comms
Learn more on KevsRobots
Courses
Projects to build
Articles to read
Share this element
This page is awesome? Show some love!Did you find this content useful?
If you found this high quality content useful please consider supporting my work, so I can continue to create more content for you.
I give away all my content for free: Weekly video content on YouTube, 3d Printable designs, Programs and Code, Reviews and Project write-ups, but 98% of visitors don't give back, they simply read/watch, download and go. If everyone who reads or watches my content, who likes it, helps fund it just a little, my future would be more secure for years to come. A price of a cup of coffee is all I ask.
There are a couple of ways you can support my work financially:
If you can't afford to provide any financial support, you can also help me grow my influence by doing the following:
Thank you again for your support and helping me grow my hobby into a business I can sustain.
- Kevin McAleer
Comments