esp32控制舵机

以下是完整的 ESP32双舵机无线控制系统 解决方案,包含硬件清单、接线图和完整代码:


硬件清单

组件名称 规格参数 数量 单价参考 购买链接示例
ESP32开发板 ESP32-WROOM-32D 2 ¥28 [某宝链接]
双轴摇杆模块 X/Y轴模拟量输出 1 ¥5 [某宝链接]
SG90微型舵机 4.8-6V/180°旋转 2 ¥8 [某宝链接]
轻触按钮开关 6×6×5mm 四脚 2 ¥0.5 [某宝链接]
10KΩ电阻 1/4W 碳膜电阻 4 ¥0.1 [某宝链接]
100nF陶瓷电容 0603封装 2 ¥0.2 [某宝链接]
5V电源模块 AMS1117-5.0 稳压模块 1 ¥3 [某宝链接]
杜邦线 20cm 公对公/母 1包 ¥5 [某宝链接]

系统接线图

发送端(控制器)

┌──────────────┐       ┌──────────────┐
│   ESP32      │       │   摇杆模块    │
│              │       │              │
│  GPIO34 ─────┼───────┤ X轴(ADC1_CH6)│
│  GPIO35 ─────┼───────┤ Y轴(ADC1_CH7)│
│  GPIO25 ─┬───┘       ├───── 3.3V    │
│          │10KΩ       ├───── GND     │
│  GPIO26 ─┼───┬───┐   └──────────────┘
│          │   │   │   
│  GND ────┴─┐ │   │   ┌──────────────┐
│            │ │   └───┤ PWM按钮      │
│            └─┴───────┤ 复位按钮     │
└──────────────┘       └──────────────┘

接收端(执行器)

┌──────────────┐       ┌──────────────┐
│   ESP32      │       │  SG90舵机1   │
│              │       │              │
│  GPIO13 ─────┼───────┤ 信号线(黄)   │
│  GPIO14 ─────┼───────┤ 信号线(黄)   │
│  GPIO12 ─────┼───┐   ├───── 5V      │
│  GPIO27 ───┐ │   │   ├───── GND     │
│            │ │   │   └──────────────┘
│            │ │   │   
│            │ │   │   ┌──────────────┐
│            │ │   └───┤ PWM输出接口  │
│            │ │       │ (可接电机/LED)│
│            │ └───────┤ 状态指示灯LED│
│  GND ──────┴───┬─────┼───── GND     │
│                │     └──────────────┘
│  Vin(5V) ──────┘
└──────────────┘

完整代码实现

发送端代码(Controller)

#include <WiFi.h>
#include <esp_now.h>

// 接收端MAC地址(烧录后通过串口获取)
uint8_t receiverMac[] = {0xXX,0xXX,0xXX,0xXX,0xXX,0xXX};

typedef struct {
  int16_t joyX;
  int16_t joyY;
  bool pwmCmd;
  bool resetCmd;
} ControlData;

#define BTN_PWM 25
#define BTN_RESET 26
#define DEBOUNCE_TIME 50

void setup() {
  pinMode(BTN_PWM, INPUT_PULLUP);
  pinMode(BTN_RESET, INPUT_PULLUP);

  Serial.begin(115200);
  WiFi.mode(WIFI_STA);

  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW初始化失败");
    while(1);
  }

  esp_now_peer_info_t peerInfo;
  memcpy(peerInfo.peer_addr, receiverMac, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;
  esp_now_add_peer(&peerInfo);

  analogReadResolution(12);
  analogSetAttenuation(ADC_11db);
}

bool debounce(int pin) {
  static unsigned long lastTime[2] = {0};
  uint8_t idx = (pin == BTN_PWM) ? 0 : 1;

  if (digitalRead(pin) == HIGH) return false;
  if (millis() - lastTime[idx] < DEBOUNCE_TIME) return false;

  lastTime[idx] = millis();
  return true;
}

void loop() {
  static bool pwmState = false;
  ControlData data;

  // 读取摇杆
  data.joyX = analogRead(34) - 2048;
  data.joyY = analogRead(35) - 2048;

  // 处理按钮
  data.pwmCmd = debounce(BTN_PWM) ? !pwmState : pwmState;
  data.resetCmd = debounce(BTN_RESET);

  // 更新状态
  if (data.pwmCmd != pwmState) {
    pwmState = data.pwmCmd;
    Serial.println(pwmState ? "PWM启用" : "PWM关闭");
  }

  esp_err_t result = esp_now_send(receiverMac, (uint8_t*)&data, sizeof(data));
  if (result != ESP_OK) {
    Serial.println("发送失败,尝试重连...");
    esp_now_del_peer(receiverMac);
    esp_now_add_peer(&peerInfo);
  }

  delay(20);
}

接收端代码(Receiver)

#include <WiFi.h>
#include <esp_now.h>
#include <ESP32Servo.h>

#define SERVO_X 13
#define SERVO_Y 14
#define PWM_OUT 12
#define LED_STATUS 27

Servo servoX, servoY;
bool pwmActive = false;

typedef struct {
  int16_t joyX;
  int16_t joyY;
  bool pwmCmd;
  bool resetCmd;
} ControlData;

void setup() {
  pinMode(LED_STATUS, OUTPUT);

  // PWM通道配置
  ledcSetup(0, 5000, 8);  // 通道0, 5kHz, 8bit
  ledcAttachPin(PWM_OUT, 0);
  ledcWrite(0, 0);

  // 舵机初始化
  servoX.attach(SERVO_X);
  servoY.attach(SERVO_Y);
  servoX.write(90);
  servoY.write(90);

  WiFi.mode(WIFI_STA);
  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW初始化失败");
    while(1);
  }

  esp_now_register_recv_cb([](const uint8_t *mac, const uint8_t *data, int len) {
    ControlData cmd;
    memcpy(&cmd, data, sizeof(cmd));

    // 处理复位指令
    if (cmd.resetCmd) {
      servoX.write(90);
      servoY.write(90);
      return;
    }

    // 更新PWM状态
    if (pwmActive != cmd.pwmCmd) {
      pwmActive = cmd.pwmCmd;
      ledcWrite(0, pwmActive ? 128 : 0);  // 50%占空比
      digitalWrite(LED_STATUS, pwmActive);
    }

    // 处理舵机控制
    int angleX = map(cmd.joyX, -2048, 2048, 0, 180);
    int angleY = map(cmd.joyY, -2048, 2048, 0, 180);
    servoX.write(constrain(angleX, 0, 180));
    servoY.write(constrain(angleY, 0, 180));
  });
}

void loop() {
  // 保持连接状态检测
  static unsigned long lastMsg = 0;
  if (millis() - lastMsg > 5000) {
    Serial.println("等待控制信号...");
    lastMsg = millis();
  }
  delay(100);
}

系统调试指南

首次上电步骤

  1. 获取MAC地址
    • 烧录接收端代码后打开串口监视器
    • 记录显示的MAC地址并填入发送端代码
  2. 舵机校准
    # 通过串口发送校准命令
    echo "CALIBRATE" > /dev/ttyUSB0
    
  3. 信号测试
    • 使用万用表测量PWM_OUT引脚电压
    • PWM关闭时应为0V,开启时应有1.65V(50%占空比)

常见问题排查

现象 可能原因 解决方法
舵机抖动 电源功率不足 外接5V 2A电源
按钮响应延迟 去抖时间设置过长 调整DEBOUNCE_TIME参数
PWM输出不稳定 GPIO12被默认配置为MTDI 在setup()添加pinMode(12, OUTPUT)

进阶优化建议

  1. 硬件增强
    • 在PWM输出端添加MOSFET驱动电路(如IRF540N)
    • 为摇杆模块添加RC滤波电路(10kΩ+100nF)
  2. 软件升级
    // 添加运动轨迹规划
    void smoothMove(Servo &s, int target) {
     const int step = 2;
     int current = s.read();
     while(abs(current - target) > step) {
       current += (target > current) ? step : -step;
       s.write(current);
       delay(20);
     }
     s.write(target);
    }
    
  3. 安全保护
    // 添加温度保护
    #ifdef TEMP_SENSOR
    void checkTemperature() {
     if(temperatureRead() > 60.0) {
       ledcWrite(0, 0);
       servoX.detach();
       servoY.detach();
     }
    }
    #endif
    

本方案可实现100米级可靠控制(开放环境),如需更远距离建议:
- 更换高增益天线
- 使用NRF24L01+PA/LNA模块
- 添加中继节点

点赞

发表回复

电子邮件地址不会被公开。必填项已用 * 标注