8.8
【写在前面】
在B站看到很多伙伴做那个AI宠物小狗的,4个舵机,可能做出各种好玩的动作,心中就有种下种子了,当然现在还是不会做,做些准备吧。
所以这个帖子就记录用ESP32 S3控制舵机的学习,从控制一个舵机到两个舵机。
我的学习就是学习读代码,学习改代码,所记都是笔记,营养自己。

材料清单
- K10小智AI X1
- ESP32 S3-DevKitC-1开发板(N16R8) X1
- SG90舵机 X2
步骤1 安装ESP32Servo舵机库
工具-库管理,查找esp32servo,安装舵机库。


步骤2 例程学习,为小智自然语言控制舵机做准备
#include <ESP32Servo.h> // 使用官方推荐库[2,6](@ref)
Servo myServo; // 创建舵机对象
const int servoPin = 5; // 信号线接GPIO5(ESP32-S3推荐引脚1-21,35-45,47)[4](@ref)
void setup() {
// 初始化舵机(SG90需校准脉宽)
myServo.attach(servoPin, 500, 2400); // 设置脉冲范围500-2400μs(适配SG90)[3,6](@ref)
myServo.write(90); // 初始位置设为90°
}
void loop() {
// 0°→180°平滑扫描(步进1°)
for (int angle = 0; angle <= 180; angle++) {
myServo.write(angle); // 设置角度
delay(15); // 延时15ms(SG90转动60°约需60ms)[3](@ref)
}
// 180°→0°回扫
for (int angle = 180; angle >= 0; angle--) {
myServo.write(angle);
delay(15);
}
}
1、脉宽校准
attach(servoPin, 500, 2400)显式设置 SG90 的脉冲范围(0°=500μs, 180°=2400μs)。
若角度偏差,调整参数:
0°不到位 → 提高500值(如550)
180°超限 → 降低2400值(如2350)
2、ESP32-S3 引脚选择
推荐 PWM 引脚:GPIO1-21, 35-45, 47(避开板载LED的GPIO48)
禁用引脚:GPIO0(板载按钮)、GPIO48(LED)
3、供电方案(⚠️必看)

严禁使用ESP32的3.3V直接供电(电流不足会导致重启)
大功率动作时,在舵机电源端并联100μF电容防抖
步骤3 编写程序
程序重点
设定舵机引脚

设置舵机角度0-108
舵机角度控制工具

初始化舵机

#include <WiFi.h>
#include <WebSocketMCP.h>
#include <ESP32Servo.h> // 使用兼容ESP32的舵机库
#define SERVO_PIN 12 // 舵机控制引脚(GPIO12)
// WiFi配置
const char* ssid = "*****";
const char* password = "*****";
// MCP服务器配置
const char* mcpEndpoint = "ws://api.xiaozhi.me/mcp/?token=*****";
// 创建舵机对象
Servo myServo;
// 创建WebSocketMCP实例
WebSocketMCP mcpClient;
// 连接状态回调函数
void onConnectionStatus(bool connected) {
if (connected) {
Serial.println("[MCP] 已连接到服务器");
registerMcpTools(); // 注册舵机控制工具
} else {
Serial.println("[MCP] 与服务器断开连接");
}
}
// 设置舵机角度(0-180°)
void setServoAngle(int angle) {
angle = constrain(angle, 0, 180); // 限制角度范围
myServo.write(angle); // 使用库函数设置角度
Serial.printf("舵机角度设置: %d°\n", angle);
}
// 注册MCP工具
void registerMcpTools() {
// 舵机角度控制工具
mcpClient.registerTool(
"servo_control",
"控制舵机角度(0-180°)",
"{\"type\":\"object\",\"properties\":{\"angle\":{\"type\":\"integer\",\"minimum\":0,\"maximum\":180}},\"required\":[\"angle\"]}",
[](const String& args) {
DynamicJsonDocument doc(256);
deserializeJson(doc, args);
int angle = doc["angle"]; // 解析角度值
setServoAngle(angle); // 调用舵机控制函数
// 返回成功响应
return WebSocketMCP::ToolResponse("{\"success\":true,\"angle\":" + String(angle) + "}");
}
);
Serial.println("[MCP] 舵机控制工具已注册");
}
void setup() {
Serial.begin(115200);
// 初始化舵机(500-2500μs脉宽范围对应0-180°)
ESP32PWM::allocateTimer(0); // 分配定时器资源
myServo.setPeriodHertz(50); // 标准舵机频率50Hz
myServo.attach(SERVO_PIN, 500, 2500); // 引脚和脉宽范围
setServoAngle(90); // 初始设为90度(中间位置)
// 连接WiFi
Serial.print("连接到WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi已连接");
Serial.println("IP地址: " + WiFi.localIP().toString());
// 初始化MCP客户端
mcpClient.begin(mcpEndpoint, onConnectionStatus);
}
void loop() {
// 处理MCP客户端事件
mcpClient.loop();
delay(10);
}
上传代码,测试通过。
小智后台

以下为笔记存档备用。
进阶优化技巧
多舵机控制添加更多舵机对象并分配不同引脚(最多支持16个):
Servo servo2;
void setup() {
servo2.attach(6, 500, 2400); // 第二个舵机接GPIO6
}
#include <ESP32Servo.h> // 使用ESP32专用舵机库
#define SERVO_PIN 5 // 推荐使用GPIO5(ESP32-S3最佳PWM引脚)
Servo myServo; // 创建舵机对象
void setup() {
Serial.begin(115200); // 初始化串口通信
// 分配硬件定时器资源(ESP32Servo必需)
ESP32PWM::allocateTimer(0);
ESP32PWM::allocateTimer(1);
ESP32PWM::allocateTimer(2);
ESP32PWM::allocateTimer(3);
// 配置SG90舵机参数[1,2](@ref)
myServo.setPeriodHertz(50); // 标准50Hz舵机频率
myServo.attach(SERVO_PIN, 500, 2400); // 校准脉宽范围(500-2400μs对应0-180°)
myServo.write(90); // 初始位置设为90°
Serial.println("舵机初始化完成");
}
void loop() {
// 0°→180°平滑扫描(步进1°)
for (int angle = 0; angle <= 180; angle++) {
myServo.write(angle); // 设置舵机角度
Serial.print("当前角度: "); Serial.println(angle);
delay(15); // SG90转动60°约需60ms[2](@ref)
}
// 180°→0°回扫
for (int angle = 180; angle >= 0; angle--) {
myServo.write(angle);
Serial.print("当前角度: "); Serial.println(angle);
delay(15);
}
// 返回中间位置并暂停
myServo.write(90);
Serial.println("返回中位");
delay(1000);
}
步骤4 改写代码控制两个舵机
#include <WiFi.h>
#include <WebSocketMCP.h>
#include <ESP32Servo.h> // 使用兼容ESP32的舵机库
#define SERVO1_PIN 5
#define SERVO2_PIN 6
// WiFi配置
const char* ssid = "******";
const char* password = "******";
// MCP服务器配置
const char* mcpEndpoint = "ws://api.xiaozhi.me/mcp/?token=********";
// 创建舵机对象
Servo myServo1; // 舵机1
Servo myServo2; // 舵机2
// 创建WebSocketMCP实例
WebSocketMCP mcpClient;
// 连接状态回调函数
void onConnectionStatus(bool connected) {
if (connected) {
Serial.println("[MCP] 已连接到服务器");
registerMcpTools(); // 注册舵机控制工具
} else {
Serial.println("[MCP] 与服务器断开连接");
}
}
// 设置舵机角度(0-180°)
void setServo1Angle(int angle) {
angle = constrain(angle, 0, 180); // 限制角度范围
myServo1.write(angle); // 使用库函数设置角度
Serial.printf("舵机1角度设置: %d°\n", angle);
}
void setServo2Angle(int angle) {
angle = constrain(angle, 0, 180); // 限制角度范围
myServo2.write(angle); // 使用库函数设置角度
Serial.printf("舵机2角度设置: %d°\n", angle);
}
// 注册MCP工具
void registerMcpTools() {
// 舵机1角度控制工具
mcpClient.registerTool(
"servo1_control",
"控制1号舵机小明角度(0-180°)",
"{\"type\":\"object\",\"properties\":{\"angle\":{\"type\":\"integer\",\"minimum\":0,\"maximum\":180}},\"required\":[\"angle\"]}",
[](const String& args) {
DynamicJsonDocument doc(256);
deserializeJson(doc, args);
int angle = doc["angle"]; // 解析角度值
setServo1Angle(angle); // 调用舵机1控制函数
// 返回成功响应
return WebSocketMCP::ToolResponse("{\"success\":true,\"angle\":" + String(angle) + "}");
}
);
// 舵机2角度控制工具
mcpClient.registerTool(
"servo2_control",
"控制2号舵机小红角度(0-180°)",
"{\"type\":\"object\",\"properties\":{\"angle\":{\"type\":\"integer\",\"minimum\":0,\"maximum\":180}},\"required\":[\"angle\"]}",
[](const String& args) {
DynamicJsonDocument doc(256);
deserializeJson(doc, args);
int angle = doc["angle"]; // 解析角度值
setServo2Angle(angle); // 调用舵机2控制函数
// 返回成功响应
return WebSocketMCP::ToolResponse("{\"success\":true,\"angle\":" + String(angle) + "}");
}
);
Serial.println("[MCP] 双舵机控制工具已注册");
}
void setup() {
Serial.begin(115200);
// 初始化舵机(500-2500μs脉宽范围对应0-180°)
ESP32PWM::allocateTimer(0); // 分配定时器资源
ESP32PWM::allocateTimer(1);
myServo1.setPeriodHertz(50); // 标准舵机频率50Hz
myServo1.attach(SERVO1_PIN, 500, 2500); // 引脚和脉宽范围
setServo1Angle(90); // 初始设为90度(中间位置)
myServo2.setPeriodHertz(50); // 标准舵机频率50Hz
myServo2.attach(SERVO2_PIN, 500, 2500); // 引脚和脉宽范围
setServo2Angle(90); // 初始设为90度(中间位置)
// 连接WiFi
Serial.print("连接到WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi已连接");
Serial.println("IP地址: " + WiFi.localIP().toString());
// 初始化MCP客户端
mcpClient.begin(mcpEndpoint, onConnectionStatus);
}
void loop() {
// 处理MCP客户端事件
mcpClient.loop();
delay(10);
}
上传,测试通过。

评论