Skip to content

第 3 章:PWM 舵机与 ESC 控制

📂 示例代码03_pwm_servo

3.1 知识要点

  • 标准 RC PWM 协议:50 Hz 周期,1000–2000 µs 脉宽
  • LEDC 14-bit 分辨率下的占空比计算
  • ESC 上电解锁流程(中立位保持 2 秒)
  • 双通道同步配置(油门 + 转向)

3.2 课程内容

电调(ESC)和舵机均使用标准 RC PWM 协议控制:50 Hz 重复频率,脉宽 1000 µs 对应最小值,1500 µs 对应中立,2000 µs 对应最大值。OSRCORE 使用 LEDC TIMER0 的两个通道分别驱动 GPIO1(油门)和 GPIO2(转向)。

3.3 基础学习

RC PWM 时序

周期 = 20 ms (50 Hz)
脉宽范围:1000 µs(最小)~ 2000 µs(最大)
中立位:1500 µs

14-bit 分辨率下的占空比计算

14-bit 寄存器的最大值为 2¹⁴ − 1 = 16383,对应 100% 占空比(即完整的 20 ms 周期)。正确公式:

duty = pulse_us / 20000.0 * 16383

例:1500 µs → 1500/20000 × 16383 ≈ 1228;2000 µs → 2000/20000 × 16383 ≈ 1638

旧写法 duty = pulse_us × 80 是错误的:1500 × 80 = 120000,远超 14-bit 寄存器上限 16383,会导致寄存器溢出截断,输出脉宽完全错误。

正确实现:

c
/* pulse_us / 20000.0 * (2^14 - 1),结果在 [0, 16383] 范围内 */
static int duty_from_pulse(int pulse_us)
{
    if (pulse_us < 1000) pulse_us = 1000;
    if (pulse_us > 2000) pulse_us = 2000;
    return (int)((float)pulse_us / 20000.0f * ((1 << 14) - 1));
}

ESC 解锁流程

大多数 ESC 上电后需要检测到中立位信号(1500 µs)才会解锁,通常需要保持 1–3 秒。未解锁的 ESC 不响应油门指令。

3.4 程序学习

定时器与双通道初始化:

c
ledc_timer_config_t timer = {
    .speed_mode      = LEDC_LOW_SPEED_MODE,
    .duty_resolution = LEDC_TIMER_14_BIT,
    .timer_num       = LEDC_TIMER_0,
    .freq_hz         = 50,
    .clk_cfg         = LEDC_AUTO_CLK,
};
ledc_timer_config(&timer);

ledc_channel_config_t ch_throttle = {
    .gpio_num = 1, .channel = LEDC_CHANNEL_0,
    .timer_sel = LEDC_TIMER_0, .duty = duty_from_pulse(1500),
};
ledc_channel_config(&ch_throttle);

ledc_channel_config_t ch_steering = {
    .gpio_num = 2, .channel = LEDC_CHANNEL_1,
    .timer_sel = LEDC_TIMER_0, .duty = duty_from_pulse(1500),
};
ledc_channel_config(&ch_steering);

设置脉宽与 ESC 解锁:

c
static void set_pulse(ledc_channel_t ch, uint32_t pulse_us)
{
    ledc_set_duty(LEDC_LOW_SPEED_MODE, ch, duty_from_pulse((int)pulse_us));
    ledc_update_duty(LEDC_LOW_SPEED_MODE, ch);
}

// ESC 解锁:中立位保持 2 秒
set_pulse(CH_THROTTLE, 1500);
set_pulse(CH_STEERING, 1500);
vTaskDelay(pdMS_TO_TICKS(2000));

3.5 课程总结

本章掌握了 RC PWM 协议的原理和 LEDC 14-bit 精度配置,实现了 ESC 解锁和舵机扫描。duty_from_pulse() 函数将物理脉宽正确映射为 14-bit 寄存器值(公式:pulse_us / 20000.0 * 16383),是后续 PID 控制输出的基础接口。


Built for OSRCORE robot development board.