🛠 Piloter un micro-servo avec le PWM
Objectives
Generate a servo PWM signal with the RP2040: the chip features 16 PWM channels (8 slices × 2 channels). A standard micro-servo (SG90, MG90S…) expects a frequency of 50 Hz and a 1 ms pulse for the center position (0.5 ms ≈ -90°, 2.5 ms ≈ +90°). You will configure a PWM slice in "phase-correct" mode using the Pico SDK and smoothly sweep the angle.
Hardware
- 1 × Raspberry Pi Pico
- 1 × micro-servo (SG90 or MG90S)
- External 4.8-6 V power supply for the servo (do not power it from the Pico's 3V3 pin: the inrush current at startup exceeds what the board can comfortably provide)
- Cables: signal (orange/yellow) to GP1, servo negative to Pico GND AND to the power supply negative (common ground is mandatory!)
Complete Code
// servo.c — GP1, 50 Hz, pulse 0,5..2,5 ms (mode phase-correct)
#include "pico/stdlib.h"
#include "hardware/pwm.h"
#define SERVO_PIN 1
#define PERIOD_US 20000u // 50 Hz
static uint16_t angle_to_pulse_us(int angle) { // 0..180 -> 500..2500 us
return 500 + (uint16_t)(angle * 2000 / 180);
}
int main(void) {
gpio_set_function(SERVO_PIN, GPIO_FUNC_PWM);
uint slice = pwm_gpio_to_slice_num(SERVO_PIN);
pwm_set_clkdiv_mode(slice, PWM_DIV_FREE_RUNNING);
pwm_set_clkdiv(slice, 125.0f); // 125 MHz / 125 = 1 MHz (1 us/tick)
pwm_set_wrap(slice, PERIOD_US - 1);
pwm_set_enabled(slice, true);
while (true) {
for (int a = 0; a <= 180; a += 5) {
pwm_set_gpio_level(SERVO_PIN, angle_to_pulse_us(a));
sleep_ms(20);
}
for (int a = 180; a >= 0; a -= 5) {
pwm_set_gpio_level(SERVO_PIN, angle_to_pulse_us(a));
sleep_ms(20);
}
}
}
Expected Verification
The servo slowly sweeps from 0° to 180° and then returns, without jerking. When disconnecting the signal, the servo must remain stationary (no pulse = no torque). Also verify that the board's 3.3 V rail does not "dip" when the servo draws current: symptom = Pico restarting, so check the servo's ground/power connections.
Common Errors
- Forgetting the common ground between the Pico and the servo power supply: the servo jitters frantically.
- Powering the servo from the Pico's 3V3 pin: brown-out and reboots.
- Incorrect slice clock: without the appropriate
clkdiv, the period is wrong and the servo does not respond — remember that the PWM is derived from the 125 MHz clock. - Confusing level (
level) and period: the level must remain below the wrap, otherwise the output stays stuck at 1. - Powering the servo with 5 V on the signal pin: the control PWM must remain at 3.3 V, the Pico is not 5 V-tolerant.
Other tutorials for this board
Code examples for this board
clignotante.pyPythonbouton-interruption.pyPythonpwm-servo.pyPythonlecture-adc.pyPythonneopixel.pyPythonoled-i2c.pyPython