🛠 Piloter un micro-servo avec le PWM
Objectives
Configure a PWM slice on the RP2350 (16 PWM channels, 8 double slices) at 50 Hz with sufficient resolution to generate 1 to 2 ms pulses, and drive a micro-servo in angle sweeping. Difference with the RP2040: same PWM principles, but the RP2350 allows for finer clock divisions at 150 MHz.
Hardware
- 1 × Raspberry Pi Pico 2
- 1 × micro-servo (SG90/MG90S)
- External power supply recommended for more than 2 servos; 1 servo is supported from USB 5 V with common grounds
- Pin: GP2 (PWM slice 1A output, confirmed by official Pico 2 examples)
Complete Code
/* servo.c — balayage 0..180 deg sur GP2, PWM 50 Hz */
#include "pico/stdlib.h"
#include "hardware/pwm.h"
#define SERVO_PIN 2
#define WRAP 19999 /* 125 MHz / (125 * 20000) = 50 Hz */
static void servo_angle(float deg) {
/* 0 deg -> 1 ms, 180 deg -> 2 ms ; 1 pas = 10 ns avec clkdiv 125 */
uint32_t level = 100 + (uint32_t)(deg * 5.0f); /* 100..1000 */
pwm_set_chan_level(pwm_gpio_to_slice_num(SERVO_PIN), PWM_CHAN_A, level);
}
int main(void) {
gpio_set_function(SERVO_PIN, GPIO_FUNC_PWM);
uint slice = pwm_gpio_to_slice_num(SERVO_PIN);
pwm_set_clkdiv(slice, 125.0f); /* 1 pas = 1 us / 100 ? voir texte */
pwm_set_wrap(slice, WRAP);
pwm_set_enabled(slice, true);
for (float a = 0; ; a += 5) { /* triangle 0->180->0 */
float ang = (a <= 180.0f) ? a : 360.0f - a;
servo_angle(ang);
if (a >= 355.0f) a = 0;
sleep_ms(20);
}
}
Expected Verification
The servo regularly sweeps from 0° to 180° and returns, in a loop. On an oscilloscope: 20 ms period (50 Hz), pulse width varying from approximately 1 ms to 2 ms. Adjust the level limits according to your servo.
Common Errors
- Incorrect clock divider: with a wrap of 19999, a clkdiv of 125 yields 50 Hz; a forgotten clkdiv produces a kHz signal that causes the servo to buzz and overheat.
- Powering multiple servos from the board's 3V3 pin: the limit is ~300 mA on the 3V3 pin; use an external 5 V supply and connect the grounds.
- Exceeding mechanical limits: limit to 0–180° (some standard servos are 170°) to prevent stalling.
- Forgetting
pwm_set_enabled: the counter runs but the output remains inactive.
Other tutorials for this board
Code examples for this board
clignotante.pyPythonbouton-interruption.pyPythonpwm-servo.pyPythonlecture-adc.pyPythonneopixel.pyPythonoled-i2c.pyPython