You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32 S3中Servo.write与analogWrite组合引发PWM频率异常问题

问题分析与解决方案

问题根源

这是ESP32Servo库与Arduino核心analogWrite的PWM通道/定时器资源冲突导致的:

  • ESP32的PWM功能依赖有限的定时器和通道,ESP32Servo库默认会自动为每个attach()的舵机分配未被占用的PWM通道,并配置为舵机所需的50Hz。
  • Arduino环境下的analogWrite函数在ESP32平台上默认使用100Hz的PWM频率(符合你的直流电机需求),但它会直接修改对应通道的定时器配置——当attach3个舵机时,第三个舵机被分配的通道恰好和analogWrite使用的通道重叠,因此被强制改成100Hz。
  • 当attach4个舵机时,ESP32Servo会占用更多通道,analogWrite只能选择未被舵机占用的通道,因此不会覆盖舵机的配置。

解决方法

方法1:手动指定舵机的PWM通道(推荐)

在attach()时手动指定舵机使用的PWM通道,避开analogWrite可能使用的通道。ESP32共有16个PWM通道(0-15),可以给舵机分配独立的通道,彻底避免冲突:

#include <Arduino.h>
#include <ESP32Servo.h>

const int servo1Pin = 45;
const int servo2Pin = 48;
const int servo3Pin = 2;
const int servo4Pin = 36;

const int enable1Pin = 9;
const int enable2Pin = 10;

Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;

void setup() {
  Serial.begin(115200);

  // 手动指定舵机使用的PWM通道(0、1、2),参数依次为引脚、最小脉宽、最大脉宽、通道号
  servo1.attach(servo1Pin, 544, 2400, 0);
  servo2.attach(servo2Pin, 544, 2400, 1);
  servo3.attach(servo3Pin, 544, 2400, 2);
  // 不再需要虚拟舵机
}

void loop(){
  analogWrite(enable1Pin, abs(90));
  analogWrite(enable2Pin, abs(90));
  servo1.write(90);
  servo2.write(90);
  servo3.write(90);
}

方法2:使用ESP32原生PWM API控制直流电机

放弃Arduino的analogWrite,改用ESP-IDF原生PWM配置函数,手动指定直流电机的PWM参数,彻底隔离舵机和电机的PWM资源:

#include <Arduino.h>
#include <ESP32Servo.h>
#include <driver/ledc.h>

const int servo1Pin = 45;
const int servo2Pin = 48;
const int servo3Pin = 2;

const int enable1Pin = 9;
const int enable2Pin = 10;

// 为直流电机分配独立的PWM通道
#define MOTOR_CH1 10
#define MOTOR_CH2 11

Servo servo1;
Servo servo2;
Servo servo3;

void setup() {
  Serial.begin(115200);

  // 初始化舵机
  servo1.attach(servo1Pin);
  servo2.attach(servo2Pin);
  servo3.attach(servo3Pin);

  // 配置直流电机PWM:100Hz频率,10位分辨率(占空比范围0-1023)
  ledcSetup(MOTOR_CH1, 100, 10);
  ledcSetup(MOTOR_CH2, 100, 10);
  // 将电机引脚绑定到对应通道
  ledcAttachPin(enable1Pin, MOTOR_CH1);
  ledcAttachPin(enable2Pin, MOTOR_CH2);
}

void loop(){
  // 将原analogWrite的0-255范围转换为10位分辨率的0-1023
  ledcWrite(MOTOR_CH1, map(abs(90), 0, 255, 0, 1023));
  ledcWrite(MOTOR_CH2, map(abs(90), 0, 255, 0, 1023));
  
  servo1.write(90);
  servo2.write(90);
  servo3.write(90);
}

方法3:保留虚拟舵机(临时方案)

如果不想修改太多代码,可以继续保留servo4.attach()的操作,让ESP32Servo占用额外通道,避免analogWrite覆盖第三个舵机的配置,但这只是绕过问题,并非根本解决方法。


内容的提问来源于stack exchange,提问作者yhq80

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 12:30:55