先说原理,就是用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)
cd /home mkdir emqx-single cd emqx-single mkdir emqx_data emqx_log vim docker-compose.yml文件内容如下:
version: '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 -
启动项目
docker compose up -d查看容器是否创建成功
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
[env:esp12e] platform = espressif8266 board = esp12e framework = arduino ; 通过 lib_deps 添加PubSubClient库 lib_deps = pubsubclient upload_speed = 115200 upload_port = COM8 monitor_speed = 115200main.cpp
#include <Arduino.h> #include <ESP8266WiFi.h> #include <PubSubClient.h> #include <Servo.h> // ************************** 配置区 ************************** 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会自动添加DNS记录,你不用管,只需要点击激活域即可,过一会就可以使用https域名访问了
-
这个样子就说明配置完成了,可以访问了
-
访问



























