在这里插入图片描述


在这里插入图片描述


DengFOC开环无刷电机控制代码完整解读

这是灯哥开源的纯手写ESP32无刷电机开环FOC控制代码,不依赖任何第三方FOC库,仅使用ESP32原生LED PWM外设实现三相PWM输出,是学习FOC原理的绝佳入门代码。

一、完整IO配置清单(核心问题)

代码中总共使用了4个GPIO引脚,全部配置为输出模式,具体如下:

引脚号 功能定义 工作模式 详细配置
GPIO12 电机驱动使能引脚 数字输出 初始电平:HIGH(高电平使能V4版本电机驱动板)
GPIO32 PWM A相输出 LED PWM输出 绑定通道0,频率30kHz,8位分辨率(0-255)
GPIO33 PWM B相输出 LED PWM输出 绑定通道1,频率30kHz,8位分辨率(0-255)
GPIO25 PWM C相输出 LED PWM输出 绑定通道2,频率30kHz,8位分辨率(0-255)

IO配置关键说明

  1. 30kHz PWM频率:选择这个频率是为了完全避开人耳听觉范围(20Hz-20kHz),消除电机运行时的高频啸叫声
  2. 8位分辨率:对应占空比范围0-255,对于开环FOC控制已经足够,同时能保证30kHz的高频率输出
  3. GPIO12使能逻辑:DengFOC V4驱动板采用高电平使能,低电平会切断电机电源
  4. ESP32 LED PWM特性:最多支持16个独立PWM通道,可任意映射到GPIO引脚,非常适合多相电机控制

二、代码整体结构与核心逻辑

1. 全局变量与宏定义

// 三相PWM输出引脚定义
int pwmA = 32;
int pwmB = 33;
int pwmC = 25;

// 数值约束宏,替代Arduino原生constrain函数
#define _constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))

// 系统参数
float voltage_power_supply = 12.6;  // 电源电压(3S锂电池满电电压)
float shaft_angle = 0;              // 电机机械角度(开环积分得到)
float open_loop_timestamp = 0;      // 上一次循环的时间戳
float zero_electric_angle = 0;      // 电角度零点偏移(开环时无需校准)

2. 初始化函数setup()

void setup() {
  Serial.begin(115200);  // 串口初始化,用于调试输出
  
  // 电机驱动使能
  pinMode(12, OUTPUT);
  digitalWrite(12, HIGH);  // 开启电机驱动电源
  
  // PWM引脚模式设置
  pinMode(pwmA, OUTPUT);
  pinMode(pwmB, OUTPUT);
  pinMode(pwmC, OUTPUT);
  
  // LED PWM控制器配置
  ledcSetup(0, 30000, 8);  // 通道0,30kHz,8位分辨率
  ledcSetup(1, 30000, 8);  // 通道1,30kHz,8位分辨率
  ledcSetup(2, 30000, 8);  // 通道2,30kHz,8位分辨率
  
  // 将PWM引脚绑定到对应的LED PWM通道
  ledcAttachPin(pwmA, 0);
  ledcAttachPin(pwmB, 1);
  ledcAttachPin(pwmC, 2);
  
  Serial.println("完成PWM初始化设置");
  delay(3000);  // 3秒延时,方便观察初始化完成
}

3. 核心数学辅助函数

// 机械角度转换为电角度
// 电角度 = 机械角度 × 极对数
float _electricalAngle(float shaft_angle, int pole_pairs) {
  return (shaft_angle * pole_pairs);
}

// 将任意角度归一化到 [0, 2π] 范围
// 解决角度溢出和负数问题
float _normalizeAngle(float angle) {
  float a = fmod(angle, 2 * PI);
  return a >= 0 ? a : (a + 2 * PI);
}

4. PWM输出设置函数

void setPwm(float Ua, float Ub, float Uc) {
  // 将三相电压转换为占空比(0-1)
  // 占空比 = 相电压 / 电源电压
  dc_a = _constrain(Ua / voltage_power_supply, 0.0f, 1.0f);
  dc_b = _constrain(Ub / voltage_power_supply, 0.0f, 1.0f);
  dc_c = _constrain(Uc / voltage_power_supply, 0.0f, 1.0f);

  // 写入PWM寄存器(8位分辨率对应0-255)
  ledcWrite(0, dc_a * 255);
  ledcWrite(1, dc_b * 255);
  ledcWrite(2, dc_c * 255);
}

5. FOC核心变换函数

void setPhaseVoltage(float Uq, float Ud, float angle_el) {
  // 电角度归一化,加上零点偏移
  angle_el = _normalizeAngle(angle_el + zero_electric_angle);

  // 帕克逆变换(d-q坐标系 → α-β坐标系)
  // 开环控制时Ud=0,只需要Uq分量
  Ualpha = -Uq * sin(angle_el);
  Ubeta = Uq * cos(angle_el);

  // 克拉克逆变换(α-β坐标系 → 三相静止坐标系)
  // 这里使用了中心对齐PWM的简化计算,加上电源电压的一半作为直流偏置
  Ua = Ualpha + voltage_power_supply / 2;
  Ub = (sqrt(3) * Ubeta - Ualpha) / 2 + voltage_power_supply / 2;
  Uc = (-Ualpha - sqrt(3) * Ubeta) / 2 + voltage_power_supply / 2;
  
  // 设置三相PWM输出
  setPwm(Ua, Ub, Uc);
}

6. 开环速度控制函数

float velocityOpenloop(float target_velocity) {
  // 获取当前系统时间(微秒)
  unsigned long now_us = micros();
  
  // 计算两次循环之间的时间间隔(秒)
  float Ts = (now_us - open_loop_timestamp) * 1e-6f;

  // 时间戳溢出保护(micros()约70分钟溢出一次)
  if (Ts <= 0 || Ts > 0.5f) Ts = 1e-3f;

  // 开环角度积分:通过目标速度和时间间隔计算当前机械角度
  // 这是开环控制的核心,没有编码器反馈,纯靠时间积分估算角度
  shaft_angle = _normalizeAngle(shaft_angle + target_velocity * Ts);

  // 设置q轴电压(决定输出力矩)
  // 最大安全值为 voltage_power_supply/2,超过会导致电压限幅失真
  float Uq = voltage_power_supply / 3;

  // 计算并输出三相电压
  // 极对数为7,对应DengFOC配套的2208电机
  setPhaseVoltage(Uq, 0, _electricalAngle(shaft_angle, 7));

  // 更新时间戳
  open_loop_timestamp = now_us;

  return Uq;
}

7. 主循环函数

void loop() {
  // 以5rad/s的角速度开环运行
  // 1rad/s ≈ 9.55rpm,5rad/s ≈ 47.75rpm(机械转速)
  velocityOpenloop(5);
}

三、代码关键特性与注意事项

  1. 纯手写无库依赖:代码不依赖SimpleFOC等任何第三方库,所有FOC算法都由基础数学运算实现,非常适合学习原理
  2. 开环控制特性
    • 不需要编码器或霍尔传感器
    • 低速力矩较小,高速容易丢步
    • 适合入门学习和简单应用
  3. 可修改参数
    • voltage_power_supply:根据实际电源电压修改(如12V电源改为12.0)
    • pole_pairs:根据电机极对数修改(代码中为7,对应2208电机)
    • Uq:调整输出力矩,最大不超过voltage_power_supply/2
    • target_velocity:修改电机目标转速(单位:rad/s)
  4. 硬件兼容性:仅在DengFOC V4开发板上测试过,其他ESP32开发板需要根据实际引脚定义修改

需要我帮你把这段代码改成支持正反转切换串口调速的版本吗?

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐