TL;DR:
PWM switches power fully on and fully off many times a second. The duty cycle, on-time divided by the period, sets the average.
Frequency is how many on-off cycles happen per second. It must be high enough that the load only responds to the average.
A microcontroller pin cannot power a motor. It drives a transistor or motor driver, which does the switching of the real current.
Your robot's motor runs at one speed when you connect it to the battery: full. A microcontroller pin only outputs fully high or fully low, so it cannot give a voltage of 0.4 of the supply either. Pulse-width modulation, or PWM, gets around this by switching so fast that the motor only feels the average.
Duty cycle
A PWM signal repeats a cycle. In each cycle the output is high for a time t_on, then low for the rest. The length of the whole cycle is the period T. The duty cycle is D = t_on / T, a number between 0 (always off) and 1 (always on). People often quote it as a percentage.
The average voltage the load sees is about V_avg = D × V_supply, as long as the switching is fast enough. That is why PWM is efficient: the switch is either fully on, with almost no voltage across it, or fully off, with no current, so very little power is wasted as heat in the switch.
Frequency
The frequency is the number of cycles per second, f = 1 / T, in hertz. A 1 kHz signal has a period of 1 / 1000 = 1 ms. Common Arduino-style boards default to roughly 490 Hz on most PWM pins, and some pins run at about 980 Hz, but check your board's documentation.
Worked example: a duty cycle of one quarter, shown as on-time over period
Say a 12 V motor is switched at 1 kHz with a duty cycle of 0.25. Work it out step by step.
Period:
T = 1 / 1000 Hz = 1 ms.On-time:
t_on = D × T = 0.25 × 1 ms = 0.25 ms. Off-time:1 − 0.25 = 0.75 ms.Average voltage:
V_avg = 0.25 × 12 V = 3 V.Check by drawing it: over 1 ms the line is at 12 V for the first quarter, then 0 V. Area under the line is
12 × 0.25 = 3volt-milliseconds per millisecond, which is the same as a flat 3 V.
On an 8-bit PWM output, the number you write runs from 0 to 255, and the duty cycle is value / 255. For D = 0.25 the value is 0.25 × 255 = 63.75, so write 64, which gives 64 / 255 ≈ 0.251. In Arduino code that is analogWrite(pin, 64).
Why does the motor not just jerk on and off? A motor winding has inductance, which resists sudden changes in current, and the rotor and wheel have inertia. At 1 kHz the current ripples a little around its average, and the speed changes far too slowly to follow each pulse. At 5 Hz you would see and feel the pulsing.
Motors and LEDs
An LED gets dimmer as its duty cycle drops, because your eye averages the light. Keep the frequency well above a few hundred hertz to avoid visible flicker, which can be seen on cameras even when it is hidden to the eye.
For motors, the frequency is a trade-off. Too low and the motor hums, buzzes or runs rough. Frequencies in the audible range, up to about 20 kHz, can produce a whine, so many motor drivers use around 20 kHz. Too high and the switching transistors waste more energy in the moments when they change state. Fast PWM is also a source of electrical noise, so keep power wires apart from sensor wires.
Speed is not exactly proportional to duty cycle. A motor needs a minimum voltage to overcome friction before it turns at all, so there is a dead zone at low duty cycles. And with a load, speed falls for the same duty cycle. That is why robots add a speed sensor and feedback to hold a target speed, which is the idea behind a PID controller.
Do not drive a motor from a pin: A microcontroller pin can supply only a small current, typically a few tens of milliamps at most, and a motor can draw amps. Use a motor driver board or a transistor rated for the motor current, with a diode or a driver that handles the voltage spike when the motor is switched off. Wheels lifted off the ground for first tests, battery fused, and no mains power anywhere.
Where it goes wrong
Pin used directly. Overloading a pin can damage the chip.
No flyback protection. Switching an inductive load off causes a voltage spike that can destroy a bare transistor.
Hot driver. A driver running near its current limit heats up. Check the rating and add heat sinking if needed.
Shared timer. On many boards, changing the frequency of one PWM pin changes others, or breaks functions like
millis()if you pick the wrong timer.Noise in sensors. PWM current spikes in shared wires cause jumpy sensor readings.
How real robots use it
Almost every small motor, servo, heater and LED driver in a robot uses PWM. Hobby servos use a different kind of pulse: the width of a pulse about every 20 ms sets the angle, not the average power. Speed control built on encoder feedback, as in interrupts and timing on a microcontroller, turns a target speed into a duty cycle many times a second. The signals between parts are covered next in I2C, SPI and UART.
Try it yourself
Connect an LED with a resistor to a PWM pin and step analogWrite through 0, 64, 128, 192 and 255. If you have an oscilloscope or a logic analyzer, measure t_on and the period and confirm D = t_on / T. Without one, film the LED with a phone camera at a low duty cycle and see whether stripes of flicker show up.
Frequently asked questions
Is PWM the same as an analog voltage?
No. The output is only ever fully on or fully off. It behaves like an average voltage for loads that respond slowly, such as motors and LEDs seen by the eye.
Does a higher frequency always help?
Not always. It smooths the current but increases switching losses and electrical noise. Pick a value the driver and motor suit.
