Bootstrap

ESP32-摇杆控制舵机

一、读取摇杆数值

为了使用ESP32读取XY摇杆的值,可以按照以下步骤操作。这里使用Arduino IDE进行编程。

所需材料

  1. ESP32开发板
  2. 摇杆模块
  3. 面包板和跳线

接线

  1. 将摇杆模块的VCC连接到ESP32的3.3V,GND连接到ESP32的GND。
  2. 将摇杆模块的VRx连接到ESP32的GPIO 34(可以选择任意ADC引脚),VRy连接到GPIO 35。!!!!注意注意,35、34、36、39只能输入,别踩坑
  3. 如果需要读取摇杆按键状态,可以将SW引脚连接到ESP32的一个数字输入引脚。

代码

int VRx = 34; // X轴引脚
int VRy = 35; // Y轴引脚
int SW = 32;  // 按键引脚

void setup() {
  Serial.begin(115200);
  pinMode(VRx, INPUT);
  pinMode(VRy, INPUT);
  pinMode(SW, INPUT_PULLUP); // 如果使用按键引脚
}

void loop() {
  int xValue = analogRead(VRx); // 读取X轴的值
  int yValue = analogRead(VRy); // 读取Y轴的值
  int swState = digitalRead(SW); // 读取按键状态(如果有)

  // 打印读取的值
  Serial.print("X-axis: ");
  Serial.print(xValue);
  Serial.print(" | Y-axis: ");
  Serial.print(yValue);
  Serial.print(" | Switch: ");
  Serial.println(swState);

  delay(500); // 延迟0.5秒
}

解释

  1. int VRx = 34;int VRy = 35; 分别定义了摇杆的X轴和Y轴引脚。
  2. int SW = 32; 定义了摇杆按键引脚(如果使用)。
  3. setup() 中初始化串口通信,并设置引脚模式。
  4. loop() 中,使用 analogRead() 读取摇杆的X轴和Y轴的模拟值,并使用 digitalRead() 读取按键状态。
  5. 打印读取的值到串口监视器。

调试与调整

  1. 检查接线是否正确。
  2. 确保摇杆模块的VCC和GND正确连接。
  3. 如果读取的值不正确或有噪声,可以尝试增加电源滤波电容。

这样,通过读取摇杆模块的X轴和Y轴的值,你可以在ESP32上实现各种与摇杆相关的控制和互动功能。

二、控制舵机

这里使用别人封装好的库,因为用pwm脉冲信号周期控制太麻烦了(不过可以控制LED做呼吸灯)

下一步试一下吧

使用ESP32Servo.h库来控制舵机,可以简化控制舵机的代码,并与读取摇杆的值结合起来实现更方便的控制。以下是如何实现这一功能的详细步骤和示例代码。

安装ESP32Servo

  1. 打开Arduino IDE。
  2. 选择 工具 > 库管理器
  3. 搜索 ESP32Servo,然后点击 安装

所需材料

  1. ESP32开发板
  2. 摇杆模块
  3. 舵机
  4. 面包板和跳线

接线

  1. 将摇杆模块的VCC连接到ESP32的3.3V,GND连接到ESP32的GND。
  2. 将摇杆模块的VRx连接到ESP32的GPIO 34(可以选择任意ADC引脚),VRy连接到GPIO 35。
  3. 将舵机的VCC连接到ESP32的5V,GND连接到ESP32的GND,信号线连接到ESP32的GPIO 13(可以选择任意PWM引脚)。

代码

#include <ESP32Servo.h>

Servo myservo;  // 创建舵机对象
int VRx = 34;   // X轴引脚
int VRy = 35;   // Y轴引脚
int SW = 32;    // 按键引脚
int servoPin = 13; // 舵机控制引脚

void setup() {
  Serial.begin(115200);
  myservo.attach(servoPin); // 将舵机附加到指定的引脚上
  pinMode(VRx, INPUT);
  pinMode(VRy, INPUT);
  pinMode(SW, INPUT_PULLUP); // 如果使用按键引脚
}

void loop() {
  int xValue = analogRead(VRx); // 读取X轴的值
  int yValue = analogRead(VRy); // 读取Y轴的值
  int swState = digitalRead(SW); // 读取按键状态(如果有)

  // 将X轴和Y轴的值映射到0-180度范围内
  int angleX = map(xValue, 0, 4095, 0, 180);
  int angleY = map(yValue, 0, 4095, 0, 180);

  // 控制舵机
  myservo.write(angleX);

  // 打印读取的值和映射后的角度值
  Serial.print("X-axis value: ");
  Serial.print(xValue);
  Serial.print(" | Mapped X-axis angle: ");
  Serial.print(angleX);
  Serial.print(" | Y-axis value: ");
  Serial.print(yValue);
  Serial.print(" | Mapped Y-axis angle: ");
  Serial.print(angleY);
  Serial.print(" | Switch: ");
  Serial.println(swState);

  delay(500); // 延迟0.5秒
}
 

解释

  1. #include <ESP32Servo.h> 引入了ESP32Servo库。
  2. Servo myservo; 创建了一个舵机对象。
  3. myservo.attach(servoPin); 将舵机附加到指定的引脚上。
  4. loop() 中,读取摇杆的X轴和Y轴的模拟值,并将这些值映射到舵机的角度范围内。
  5. 使用 myservo.write(angleX); 控制舵机。

调试与调整

  1. 检查接线是否正确。
  2. 如果舵机抖动或反应不灵敏,可以调整代码中的映射范围和延迟时间。
  3. 确保舵机使用的电源足够稳定,避免电源不足导致的抖动问题。

通过这种方式,你可以使用ESP32和ESP32Servo库通过摇杆来控制舵机,实现各种有趣的项目。

选择引脚的考虑因素

有4个引脚只能输入

  1. PWM功能: ESP32的几乎所有GPIO引脚都支持PWM输出功能,这是控制舵机所必需的。常用的PWM引脚有GPIO 12、GPIO 13、GPIO 14、GPIO 15等。
  2. 引脚冲突: 避免使用已经占用或有特殊功能的引脚。例如,GPIO 0、GPIO 2、GPIO 15在启动时有特定功能,可能会导致冲突。
  3. 硬件布局: 根据你的硬件布局和方便程度选择引脚。选择一个方便连接和调试的引脚。

三、XY摇杆控制两个舵机

引脚都可以自己定义,记得对照引脚图

视频

ESP32摇杆控制两个舵机

代码

里面有控制LED灯和点灯科技的物联网相关东西,可以忽略

#include "OneButton.h"  //引用库函数 按钮
#include <WiFi.h>
#include <DNSServer.h>
#include <WebServer.h>
#include <WiFiManager.h>
#define BLINKER_MIOT_LIGHT
#define BLINKER_WIFI
#include <Blinker.h>
#define SERVO_PIN_1 32  //舵机接GPIO33(需要ADC引脚)
#define SERVO_PIN_2 33  //舵机接GPIO25(需要ADC引脚)
#define YJOY_PIN 35     //从双轴读取的 Y 轴将接入模拟引脚 (需要ADC引脚)
#define XJOY_PIN 34     //从双轴读取的 X 轴将接入模拟引脚 (需要ADC引脚)
#define RedLed 14       // esp32开发版的引脚号 要对照开发板引脚图 GPIO来
#define GreeLed 12
#define BlueLed 13
#include <ESP32Servo.h>
Servo myservo1;
Servo myservo2;
// 建立WiFiManager对象
WiFiManager wifiManager;
int isWifi = 1;
int isOk = 0;
volatile int a = 1000, b = 3000;
int statemachine = 0;
BlinkerButton Button1("btn1");  //这里需要根据自己在BLINKER里面设置的名字进行更改
void setup() {
  // 初始化串口
  Serial.begin(115200);
  // rgb红色 定义输出引脚
  pinMode(RedLed, OUTPUT);
  // rgb绿色 定义输出引脚
  pinMode(GreeLed, OUTPUT);
  // rgb蓝色 定义输出引脚
  pinMode(BlueLed, OUTPUT);
  pinMode(XJOY_PIN, INPUT);
  pinMode(YJOY_PIN, INPUT);
  // pinMode(SERVO_PIN_1, OUTPUT);
  // pinMode(SERVO_PIN_2, OUTPUT);
  // 初始LED关闭
  digitalWrite(RedLed, LOW);
  digitalWrite(GreeLed, LOW);
  digitalWrite(BlueLed, LOW);




  myservo1.attach(SERVO_PIN_1);
  myservo2.attach(SERVO_PIN_2);

  // ledcSetup(1, 50, 8);            // 设置通道1
  // ledcAttachPin(SERVO_PIN_1, 1);  // 将通道与对应的引脚连接
  // ledcSetup(2, 50, 8);            // 设置通道2
  // ledcAttachPin(SERVO_PIN_2, 2);  // 将通道与对应的引脚连接
  initWifi();
  initBlinker();
}
// int calculatePWM(int degree) {  //0-180度
//                                 //20ms周期,高电平0.5-2.5ms,对应0-180度角度
//   const float deadZone = 6.4;   //对应0.5ms(0.5ms/(20ms/256)) 舵机转动角度与占空比的关系:(角度/90+0.5)*1023/20
//   const float max = 32;         //对应2.5ms
//   if (degree < 0)
//     degree = 0;
//   if (degree > 180)
//     degree = 180;
//   return (int)(((max - deadZone) / 180) * degree + deadZone);
// }
void initBlinker() {
  BLINKER_DEBUG.stream(Serial);
  String ssid = WiFi.SSID();
  const char* ssid_char = ssid.c_str();
  String psk = WiFi.psk();
  const char* psk_char = psk.c_str();
  Blinker.begin("c14dba82695f", ssid_char, psk_char);
  Serial.print("要链接的wifi账号:");
  Serial.println(ssid_char);
  Serial.print("wifi密码:");
  Serial.println(psk_char);
  Button1.attach(button1_callback);
}
void loop() {
  int XVal = analogRead(XJOY_PIN);  //读取引脚 XJOY_PIN 上的双轴输入
  int YVal = analogRead(YJOY_PIN);  //读取引脚 YJOY_PIN 上的双轴输入
  //                                   // 打印读取的值
  // Serial.print("X-axis: ");
  // Serial.print(XVal);
  // Serial.print(" | Y-axis: ");
  // Serial.println(YVal);

  // 在串口监视器进行串口绘图
  Serial.print("X:");
  Serial.println(XVal);
  Serial.print("Y:");
  Serial.println(YVal);
  // Serial.print(" | Switch: ");
  // Serial.println(swState);

  // Serial.print(" 输出1舵机=");
  // XVal = map(XVal, 0, 1023, 0, 179);  // 转换读取数值到角度 ,1023约等于180°  179约等于0°
  // Serial.println(YVal);
  // Serial.print(" 输出2舵机=");
  // YVal = map(YVal, 0, 1023, 0, 179);
  // Serial.println(YVal);
  // 将X轴和Y轴的值映射到0-180度范围内
  int angleX = map(XVal, 0, 4095, 0, 180);
  int angleY = map(YVal, 0, 4095, 0, 180);
  myservo1.write(angleX);
  myservo2.write(angleY);
  Serial.print("angleX:");
  Serial.println(angleX);
  Serial.print("angleY:");
  Serial.println(angleY);
  // ledcWrite(1, calculatePWM(XVal));  // 输出PWM,设置 LEDC 通道的占空比。
  // ledcWrite(2, calculatePWM(YVal));  // 输出PWM,设置 LEDC 通道的占空比。
  if (isOk == 1) {
    RedLedFun();
    GreeLedFun();
    BuleLedFun();
  }
  delay(30);
  // 一直循环点灯科技的东西
  Blinker.run();
}
void RedLedFun() {
  digitalWrite(RedLed, 1);
  delay(500);
  digitalWrite(RedLed, 0);
}
void GreeLedFun() {
  digitalWrite(GreeLed, 1);
  delay(500);
  digitalWrite(GreeLed, 0);
}
void BuleLedFun() {
  digitalWrite(BlueLed, 1);
  delay(500);
  digitalWrite(BlueLed, 0);
}
void button1_callback(const String& state) {
  BLINKER_LOG("get button state: ", state);
  Blinker.vibrate();
  if (state == "on" && isWifi == 1) {
    isOk = 1;
    // 给app反馈开关状态
    Button1.print("on");
    // 给app按钮变成绿色
    Button1.color("#00cc00");
  } else if (state == "off" && isWifi == 1) {
    isOk = 0;
    Button1.print("off");
    // 给app按钮变灰色
    Button1.color("#00EE00");
  }
}

void initWifi() {
  // wifiManager.resetSettings();

  // 自动连接WiFi。以下语句的参数是连接ESP8266时的WiFi名称
  wifiManager.autoConnect("33的热水壶");

  // 如果您希望该WiFi添加密码,可以使用以下语句:
  // wifiManager.autoConnect("AutoConnectAP", "12345678");
  // 以上语句中的12345678是连接AutoConnectAP的密码

  // WiFi连接成功后将通过串口监视器输出连接成功信息
  Serial.println("");
  Serial.print("ESP8266 Connected to ");
  Serial.println(WiFi.SSID());  // WiFi名称
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());  // IP
}

;