使用ESP8266+SG90舵机实现物理远程开机
先说原理,就是用ESP8266连接SG90舵机,8266连上网络后接收服务器的命令控制舵机。
我一开始使用的是这个up主-Sha达不溜的方法【开源】笔记本远程开机(纯物理解决方案)_哔哩哔哩_bilibili,利用点灯科技app实现远程开机,不过不知道是不是点灯科技服务器的问题,有的时候设备不在线,而且延迟比较大,所以问了问AI,转而使用自己的服务器搭建mqtt服务,让8266连接自己的mqtt实现远程开机功能。
有需要云服务器的小伙伴推荐使用雨云 - 新一代云服务提供商,功能很多、很实惠,适合长期使用。除了服务器还提供云应用,云应用可以直接部署EMQX
准备工作
先说一下,本人没有单片机经验,以下过程纯靠网上教程+AI🤣
拥有自己的服务器
去雨云或者其他服务商处买最便宜的一个服务器就行,如果不买服务器的话就看我最开始说的那个up主的视频操作,使用点灯科技,就不用往下看我的文章了。
购买ESP8266和SG90舵机
舵机没啥说的,肯定买不错,8266买这个ch340芯片typec口的,直接用typec线就能烧录,不需要usb转ttl了

电脑安装vscode+platformIO
按照教程安装即可VSCode 下 PlatformIO 的安装教程-CSDN博客
如果过程中安装platform core或者新建项目卡在project wizard请不要关闭vscode,耐心等待即可
电脑安装CH340串口驱动
下载地址:CH340
服务器安装EMQX
系统为Debian12
安装docker、docker compose
- 使用ssh客户端连接服务器,我这里使用的是WindTerm
- 安装docker,按照这个大佬的教程安装即可Debian / Ubuntu 安装 Docker 以及 Docker Compose 教程 - 烧饼博客
部署EMQX
使用 Docker Compose 部署 EMQX(有1Panel的话可以直接用1Panel部署EMQX)
1
2
3
4
5cd /home
mkdir emqx-single
cd emqx-single
mkdir emqx_data emqx_log
vim docker-compose.yml文件内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32version: '3'
services:
emqx:
image: emqx/emqx:6.0.0 # 使用开源版,更轻量
container_name: emqx
environment:
- "EMQX_NODE_NAME=emqx@single-node" # 随意
- "EMQX_DASHBOARD__DEFAULT_USERNAME=用户名"
- "EMQX_DASHBOARD__DEFAULT_PASSWORD=密码"
- "EMQX_ALLOW_ANONYMOUS=false" # 禁用匿名连接,提高安全性
healthcheck:
test: ["CMD", "/opt/emqx/bin/emqx_ctl", "status"]
interval: 10s
timeout: 30s
retries: 3
ports:
- "1883:1883" # MQTT TCP端口
- "8083:8083" # MQTT WebSocket端口
- "8084:8084" # MQTT SSL端口
- "8883:8883" # MQTT TCP/SSL端口
- "18083:18083" # 管理控制台端口
volumes:
- ./emqx_data:/opt/emqx/data # 数据持久化
- ./emqx_log:/opt/emqx/log # 日志持久化
restart: unless-stopped # 自动重启
networks:
emqx-net:
networks:
emqx-net:
driver: bridge启动项目
1
docker compose up -d
查看容器是否创建成功
1
docker ps

放行1883、8083、8084、8883、18083端口
访问http://ip:18083,即可进入控制台,使用docker-compose.yml文件中配置的用户名密码登录即可
我这里是已经连上我之前的8286了,所以显示会话是1,刚安装应该都是0才对

创建用户

点击添加用户,不需要超级用户权限

这个用户就是8266和网页登录所需要的用户名和密码
开始操作单片机
修改波特率
使用typec线将8266与电脑相连
连接后点击此电脑➡️管理➡️设备管理器➡️端口,可以看到CH340对应的COM几,比如我这里是COM9

修改波特率
右键这个端口设备➡️属性➡️端口设置,将
每秒位数改为115200
编写程序
打开platformIO➡️PIO Home➡️Platforms,安装Espressif 8266

新建项目

新建项目时间可能会很长,等着就行,可以挂着然后去干别的,项目创建好会自动弹出vscode
项目创建好后只需要改两个文件
platformiio.ini
1
2
3
4
5
6
7
8
9[env:esp12e]
platform = espressif8266
board = esp12e
framework = arduino
; 通过 lib_deps 添加PubSubClient库
lib_deps = pubsubclient
upload_speed = 115200
upload_port = COM8
monitor_speed = 115200main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// ************************** 配置区 **************************
const char* ssid = "想让8266连接的wifi名称";
const char* password = "wifi密码";
const char* mqtt_server = "服务器IP";
const int mqtt_port = 1883; //EMQX的MQTT的端口号
const char* mqtt_user = "test"; //添加的用户名
const char* mqtt_password = "test123"; //添加的用户名对应的密码
// ************************** 舵机参数 **************************
Servo myServo;
int servoPin = D5; // 您使用的是D5引脚
int currentAngle = 90;
int centerAngle = 90;
int returnDelay = 500; //自动回中延迟
unsigned long lastMoveTime = 0;
bool autoReturnEnabled = true;
// ************************** 全局变量 **************************
WiFiClient espClient;
PubSubClient client(espClient);
bool servoAttached = false;
// ************************** 函数声明 **************************
void setupWifi();
void callback(char* topic, byte* payload, unsigned int length);
void reconnect();
void setServoAngle(int angle);
void returnToCenter();
void checkAutoReturn();
void publishStatus();
// ************************** 初始化设置 **************************
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("初始化S90舵机控制器...");
Serial.println("引脚配置: D5 (GPIO14)");
// 初始化舵机
servoAttached = myServo.attach(servoPin, 500, 2400); // 调整脉宽范围以适应S90
if (servoAttached) {
Serial.println("舵机初始化成功");
setServoAngle(centerAngle);
} else {
Serial.println("舵机初始化失败!请检查连接");
}
setupWifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
Serial.println("初始化完成,等待MQTT连接...");
}
// ************************** 主循环 **************************
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
checkAutoReturn();
delay(50);
}
// ************************** 自定义函数 **************************
void setupWifi() {
delay(10);
Serial.println();
Serial.print("正在连接WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("");
Serial.println("WiFi连接成功!");
Serial.print("IP地址: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("");
Serial.println("WiFi连接失败!");
}
}
// 设置舵机角度(核心函数)
void setServoAngle(int angle) {
if (!servoAttached) {
Serial.println("舵机未正确连接,无法设置角度");
return;
}
angle = constrain(angle, 0, 180);
Serial.print("尝试设置舵机角度: ");
Serial.println(angle);
// 实际控制舵机
myServo.write(angle);
delay(100); // 给舵机时间响应
currentAngle = angle;
lastMoveTime = millis();
Serial.print("舵机角度设置为: ");
Serial.println(angle);
// 发布状态
publishStatus();
}
// 发布状态信息
void publishStatus() {
if (client.connected()) {
char statusMsg[100];
snprintf(statusMsg, sizeof(statusMsg), "角度: %d, 自动回中: %s",
currentAngle, autoReturnEnabled ? "开启" : "关闭");
client.publish("home/servo/status", statusMsg);
Serial.print("发布状态: ");
Serial.println(statusMsg);
}
}
// 自动回到中心位置
void returnToCenter() {
if (currentAngle != centerAngle) {
Serial.println("执行回中...");
setServoAngle(centerAngle);
}
}
// 检查是否需要自动回中
void checkAutoReturn() {
if (autoReturnEnabled &&
currentAngle != centerAngle &&
(millis() - lastMoveTime) > returnDelay) {
Serial.println("自动回中触发");
returnToCenter();
}
}
// MQTT消息接收回调函数
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("收到主题消息 [");
Serial.print(topic);
Serial.print("]: ");
// 将payload转换为字符串
String message = "";
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println(message);
// 调试信息
Serial.print("当前舵机状态: 已连接=");
Serial.print(servoAttached);
Serial.print(", 当前角度=");
Serial.println(currentAngle);
// 处理数字角度指令
int angle = message.toInt();
if (angle >= 0 && angle <= 180) {
Serial.print("解析为角度指令: ");
Serial.println(angle);
setServoAngle(angle);
return;
}
// 处理特殊指令
if (message == "GET") {
Serial.println("收到获取状态指令");
publishStatus();
}
else if (message == "AUTO_ON") {
autoReturnEnabled = true;
Serial.println("自动回中已开启");
publishStatus();
}
else if (message == "AUTO_OFF") {
autoReturnEnabled = false;
Serial.println("自动回中已关闭");
publishStatus();
}
else if (message == "RETURN_NOW") {
Serial.println("收到立即回中指令");
returnToCenter();
}
else {
Serial.print("未知指令: ");
Serial.println(message);
}
}
void reconnect() {
static unsigned long lastAttempt = 0;
if (millis() - lastAttempt < 5000) {
return;
}
lastAttempt = millis();
Serial.print("尝试连接MQTT服务器...");
String clientId = "ESP8266Servo-" + String(random(0xffff), HEX);
if (client.connect(clientId.c_str(), mqtt_user, mqtt_password)) {
Serial.println("MQTT连接成功!");
client.subscribe("home/servo/control");
Serial.println("已订阅主题: home/servo/control");
// 连接成功后发布一次状态
publishStatus();
} else {
Serial.print("连接失败,错误代码: ");
Serial.println(client.state());
}
}点击vscode左下角这个按钮,选择8266对应的那个口,比如我这里是COM9

点击左侧的upload按钮上传到8266
如果出现了进度提示,说明正在上传,如果没有进度提示,而是等待,那么需要你操作一下8266:按住flash情况下按一下rst,然后都松开就行了。


出现SUCCESS就是上传成功了

测试
微软商店下载串口调试助手

打开后选择COM9,波特率115200,然后点击打开按钮

按一下RST键重启8266,8266会重新连接wifi、mqtt服务,并将代码中输出的内容回显出来,可以看到wifi和mqtt都已连接成功
如果没成功就重新上传一下或者让AI看看代码有啥问题,上传之前记得先把调试助手的端口关闭,不然vscode连不上8266

编写web页面
就是个静态页面,所以可部署的方式有很多,我先把代码给出来,然后再说怎么部署
代码可在此下载:8266操控电脑页面
需要改动的地方就是hanshu.js中的config部分,这里配置的连接emqx的ws的信息,要改成你自己的

外层的index.html是入口页面,computer-control文件夹内的才是8266的控制台

入口页面样式如下,computer-control对应的就是【电脑开机】功能,进入页面会让你输入密码,密码随便填就行,因为我自己有个密码校验接口,不过在文件里我给注释了,你们需要的话可以自己配置密码校验

8266控制台如下,需要先点击【连接服务器】,连接上emqx的mqtt后连接状态会变为【已连接】,然后就可以操作了(目前立即回中、开关自动回中功能、获取状态这几个功能貌似有问题,不过不影响使用)
部署页面
想用域名访问的话可选择的方式有很多,cloudflare或者腾讯的pages、如果有已备案的域名那就直接部署在自己的服务器、没备案的可以使用frp或者cloudflare的tunnels
最简单的就是直接放到cf的pages中,简单说一下pages怎么弄
登录cloudflare,选择workers和pages

创建应用程序,选择pages、拖放文件


部署站点后点击添加自定义域(这里没添加的话没事,之后在项目中也可以设置)

设置绑定在cloudflare中的域名的二级域名
比如你在cloudflare中绑定了域名abcd.com,那么这里自定义域就可以填diannao.abcd.com

点击继续,cloudflare会自动添加DNS记录,你不用管,只需要点击激活域即可,过一会就可以使用https域名访问了

这个样子就说明配置完成了,可以访问了

访问






