一、项目前言
本着以实际问题促进我的综合工程应用能力,一直在想一个能够联动机械、电气、计算机三大现代工科于一体的实际问题项目,并且能够赚点小外快。
- 项目规划
- 低速LayOut设计
- PCB(A)制作
- 曲柄摆杆机构
- 材料&理论力学分析
- ESP系列开发
- Alot&RF控制
二、项目目的
我们大学很多寝室晚上都可能忘记关灯,导致第二天被五点钟的等给亮醒的(比如我)。即使在床上想起来了这件事,我也不太想去关,因为往往那时候我都在补番呢!为了解决这么一个对我来说尤为致命的问题,故特地立项以解决。
【基本要求】
- 能够联网,接入MQTT服务,在手机上进行控制86面板进行灯的开关
【进阶要求】
- 设计AI开关功能:配合AI学习,感知用户的生活习惯。AI感知到用户夜晚进入房间时,自动下发开启命令使其受控开启
三、方案制定
3.1 方案调查
链接 | 图片 | 优点 | 缺点 |
参考链接1 |  | 方案简单;开发简易;价钱实惠 | 完整性欠缺;断电无法工作;安装不便;适用范围小; |
参考链接2 |  | 适用简单;安装便捷;适用范围广; | 价钱昂贵;不能联网; |
参考链接3 |  | 结构简单;气动液压结构可以很方便的传递主动力 | 无法联网;控制方式单一;不够智能 |
3.2 方案构建
引言:下述三个方案,分别是复刻属性、改进属性、创新属性性质的,方案三为我独创(从开关开关为自旋运动受到启发),但是不确定性较大,实现难度方案一>方案二>方案三,下面我打算逐个逐个去实现
方案一:摆杆方案
1. 硬件架构
1. 机械架构
【固定机构】
受到上图启发
<div style="display: grid; place-items: center;" ><img src="https://pic-cdn.creality.com/model/d3d4c95640207414ee2c015dab11824b.png?x-oss-process=image/resize,m_fill,w_380/format,webp"/></div>
受到上图启发
【调整机构】
【动力机构】
【传动机构】
2. 电气架构
3.3.2 软件架构
3.3.3 系统逻辑
方案二:气动方案
3.3.1 硬件架构
3.3.2 软件架构
3.3.3 系统逻辑
方案三:动量矩方案
3.3.1 硬件架构
3.3.2 软件架构
3.3.3 系统逻辑
四、方案一实施
4.1 硬件设计
引言:在正式实施的过程中大家会遇上“先完成谁”这么一个问题,关于这个问题我一开始也没有头绪,所以我向AI进行了咨询
4.1.1 步骤分析
1. 需求分析
- 功能需求:明确智能开关的基本功能,如远程控制、定时开关、场景模式等。
- 性能需求:确定性能指标,如响应时间、耐用性、功耗等。
- 安全需求:确保设计符合电气安全标准,避免短路、过载等风险。
2. 系统设计
- 模块化设计:将系统分解为可管理的模块,如ESP01S最小系统、电池管理系统(BMS)、电机驱动系统等,便于逐步开发和测试。
- 接口设计:定义各模块之间的接口,包括电气接口和机械接口,确保模块间能够正确连接和通信。
<div style="display: grid; place-items: center;" ><img src="https://www.helloimg.com/i/2025/01/14/678658c83729c.png"/></div>
<center>图4-1-1-2-1:架构设计</center>
<div style="display: grid; place-items: center;" ><img src="https://www.helloimg.com/i/2025/01/14/67866caf3ad44.png"/></div>
<center>图4-1-1-2-2:逻辑设计</center>
3. 优先级排序
- 核心功能优先:先实现核心功能,如基本的开关控制和远程通信功能。
- 稳定性和安全性优先:在开发初期,优先考虑系统的稳定性和安全性,特别是电气系统的电源管理和安全保护。
4. 开发顺序
- 机械系统:
- 灯座紧固机构:首先设计和实现灯座紧固机构,确保灯具能够稳定安装。
- 机械摆动机构:接着设计机械摆动机构,实现开关的物理摆动功能。
- 电气系统:
- ESP01S最小系统:开发ESP01S最小系统,实现基本的通信功能。
- 电池充放电管理:设计电池管理系统,包括电池充放电管理,确保电源的稳定供应。
- BMS系统:实现电池管理系统,监控电池状态,防止过充、过放和过热。
- 电机驱动系统:最后,开发电机驱动系统,控制机械摆动机构的动作。
5. 测试与验证
- 单元测试:对每个模块进行单独测试,确保其功能正确。
- 集成测试:将各模块集成后进行测试,验证模块间的接口和协同工作。
- 系统测试:进行完整的系统测试,包括功能测试、性能测试和安全测试。
6. 迭代优化
- 收集反馈:在测试过程中收集反馈,发现问题和不足。
- 优化设计:根据反馈对设计进行优化,提升性能和用户体验。
7. 文档和维护
- 编写文档:为系统编写详细的设计文档和用户手册。
- 维护更新:在产品发布后,根据用户反馈进行维护和更新。
4.1.2 机械设计
(1)设计要求
- 基本要求:完成电机、PCBA、电池三者固定外壳的设计;完成电机直角曲柄摆动机构的设计
(2)器件选型
引言:在明确设计要求后,依次单独考虑独立设计部分的器件选型
【驱动电机】:体积小、扭矩大、力效高、易控制
- SG90:易控制、易实现:根据转动的角速度减速量进行力反馈控制
- N20:体积小、扭矩大:能够很好的控制其体积
(3)结构设计
1)思考路线
引言:在明确元器件选取后,需要独立思考设计路线的选取,我认为先从重要的结构件开始,在往次要的结构件去过渡。
2)固定结构
固定结构主要分为电机固定结构;PCBA固定结构;电池仓固定结构

<center>图4-1-2-3-2-1:电机仓设计</center>

<center>图4-1-2-3-2-2:PCBA仓设计</center>
3)摆臂结构
4.1.3 电气设计
(1)设计要求
(2)IC选型
【MCU】
- ESP12F:IO多;体积大;成本高;资料多
- ESP01S:IO少;体积小;成本低;资料多
- ESP8265:IO多;体积小;成本小;资料少
考虑:优先考虑ESP01S实现其次是ESP8265再是ESP12F(8265与01S同体积)
【驱动IC】由于SG90内部自带驱动IC,故不需考虑
【充电IC】
- TP5400:充放及升压一体芯片;升压到5V(超出ESP01S承受范围)
- IP3012A:充放管理芯片;SOT23-5封装;无电量指示;
- XB5306A:充放管理芯片;SOT23-6封装;无电量指示;
考虑:TP5400本能实现更少的外围元件,但不巧的是是升压到5V而非3.3V,MCU仍然需要一枚LDO进行降压,增加了外围元件。考虑IP3012A为先,再是XB5306A
【相关资料】
(3)原理图设计
1)思考路线
【按照实现功能前后】
- 先依据选取的元件找参考电机驱动电路,解读参考电路后,根据需要迁移设计本次驱动电路<label class="ob-comment" title="" style=""> 原理图 <input type="checkbox"> <span style=""> Comment </span></label>,设计好了后(可选进行仿真)在面包板上进行分立元件搭建试验电路
- 先依据选取的元件找参考充电电路,解读参考电路后,根据需要迁移设计本次充电电路<label class="ob-comment" title="" style=""> 原理图 <input type="checkbox"> <span style=""> Comment </span></label>,设计好了后(可选进行仿真)在面包板上进行分立元件搭建试验电路
- 将两个分立电路进行合并,在同一块面包板上对该两个电路进行测试验证,验证无问题后进行PCB的设计
【按照实际设计前后】
- 先设计电源路径
<div style="display: grid; place-items: center;" ><img src="https://www.helloimg.com/i/2025/01/17/678a4c7517859.png"/></div>
<center>图4-1-3-3-3-1:电流路径</center>
- 在设计功能实现
- 在进行元件选型
2)充放部分
- 查阅分析充放IC手册示例电路
<div style="display: grid; place-items: center;" ><img src="https://www.helloimg.com/i/2025/01/17/678a4fb3ea5a0.png"/></div>
<center>图1:IP3012A手册参考充放电路原理图</center>
【解读】
- 充电:
- IP3012一路电流分支从P+-->R1-->VDD-->VM-->P-
- Battery一路电流分支从P+-->Battery-->GND--IP3012A-->VM--P-(IP3012通过VDD与VS检测Battery的电压控制GND-VM端的等效阻抗改变其充电电流)
- 放电
- IP3012一路电流分支从Battery(+)-->R1-->VDD-->GND-->Battery(-)
- 负载一路电流分支从Battery(+)-->P+-->P- --> VM -->IP3012A-->GND-->Battery(-)(IP3012通过VDD与VS检测Battery的电压控制GND-VM端的等效阻抗改变其放电电流)
- 总结:IP3012通过控制GND-VM的等效阻值以及通断来改变充放电流的
- 嘉立创复刻+修改电路
<div style="display: grid; place-items: center;" ><img src="https://www.helloimg.com/i/2025/01/17/678a4e8ee7f9f.png"/></div>
<center>图2:第一版充放电路原理图</center>
【解读】主要充放电部分保持不变,增加一路充电(0603LED元件)指示灯电路,R7用于限流用
【犯错】无论是否充电,指示灯都能够亮起
【思考】充电不充电引起的电路状态是电流路径的改变,而电流路径的改变会引起电压下降的方向改变。有这个分析可以在记忆中联想到还需要增加一个二极管来防止电池在断开电源后继续向该LED供电。
注意:在画完后自己先进行电路解读看看有没有明显的错误(原理错误、绘制错误等),以免等到仿真再来返工
<div style="display: grid; place-items: center;" ><img src="https://www.helloimg.com/i/2025/01/17/678a5f67c04e2.png"/></div>
<center>图3:第二版充放电路原理图参考</center>
【解读】
- 充电:先判管型:PNP-->判放大类型:共射放大-->判偏置状态,$U{eb}<0V$为反偏,$U{ec}>0V$为正偏,PNP管导通,be脚间仅存在导通压降。

<center>图4:第二版充放电路原理图</center>
【解读】充电时红灯亮起,不充电时红灯关闭
【问题】1N5406体积过大,改换1N55819,且该电路不支持充满灭掉指示灯;
【思考】存不存在一种方法使得能够达到充满绿灯亮,未充满红灯亮呢?或许我们可以用借用逻辑关系图进行模电设计的指导?下面我们在第三版电路中探索一下

<center>图5:第三版充放电路原理图逻辑思考</center>

<center>图6:第三版充放电路原理图</center>

<center>图7:第三版充放电路原理图</center>
【解读】该版本电路实现了充电启停,但是有一个缺点就是,得加入一个开关额外控制指示电路的通断,引入MOS管控制通断发现太麻烦了,故做出一定的妥协
【资料】
3)电源部分
【0603LED参数】


【1N5406参数】


【2N5401参数】


4)整体预览
5)后续改进
(4)电路仿真
引言:仿真可以帮我们快速的验证电路原理图设计是否有问题,如果有设计问题可以及时去解决。试想一下,当你打板完成后你才发现原理设计错误导致PCBA无法正常工作,这个时候再去返工,在财力物力人力上都是一笔巨大的消耗。
1)指示灯电路
1. V1版本仿真


2. V2版本仿真

<center>图7:第三版充放电路原理图</center>
(4)PCB设计
1)思考路线
- 确定板框尺寸:在Solidworks中查看固定结构可容纳空间为32.40x19.80mm,由于单层PCB尺寸较薄,即使不测量深度也有空余空间

- 确定元件布局:
- 分析功能模块:MCU部分/充电管理部分/供电部分
- 摆放功能模块:
【参考连接】
4)需求反馈
4.1.2 程序设计
注意:此步骤本应该在硬件设计完成后进行,但是由于PCBA制作出现了点问题,故提前开发
<div style="display: grid; place-items: center;" ><img src="https://www.helloimg.com/i/2025/01/14/67866caf3ad44.png"/></div>
<center>图4-1-1-2-2:逻辑设计</center>
(1)底层硬件
1)设计要求
【基本功能】实现受控用户开关指令动作点击,并且返回动作消息;受控于AI完成AI指令响应并返回响应结果。
【用户人群】人类用户/AI
- 对于面向用户设计:通过ESP8266模块接入WIFI网络,并与MQTT服务器建立连接,在Home Assistant构建MQTT灯光开关控制实例,通过发布灯光的开/关状态和命令主题,来控制继电器吸合/释放,实现对灯光的开/关控制。

<center>图2:MQTT与Homeassitant的交互</center>
- 对于面向AI设计:Home Assistant 从 2024.6 版本开始,正式支持与 AI 代理的集成,允许通过大型语言模型(LLM)如 Google Gemini 和 OpenAI ChatGPT 来控制智能家居设备。这些 AI 代理可以通过 Home Assistant 的 Assist API 与设备交互,支持语音控制和自动化脚本中的决策逻辑
2)技术评判
【参考链接】
- 【实现ESP01S与EMQX的基本交互】
graph TD
A[开始] --> B[初始化串口]
B-->D[连接WiFi]
D -->|未连接| D
D -->|已连接| E[连接MQTT服务器]
E -->|未连接| F[延时并重试]
F --> E
E -->|已连接| G[发布准备消息]
G --> H[订阅主题]
H --> I[设置回调函数]
I --> J[打印MQTT信息]
J --> K[进入循环]
K --> L[处理MQTT消息]
L --> M[接收消息]
M --> N[解析JSON]
N --> O{JSON格式正确?}
O -->|是| P[获取maidcode, status, angle]
P --> Q{maidcode匹配且status为on?}
Q -->|是| R[LED开]
R --> S[逐渐增加PWM占空比]
S --> T[延时]
T --> U[循环结束]
U -->K
Q -->|否| V{maidcode匹配且status为off?}
V -->|是| W[LED关]
W --> X[逐渐减少PWM占空比]
X --> Y[延时]
Y --> U
V -->|否| Z[忽略消息]
Z --> U
O -->|否| AA[打印错误信息]
AA --> U
#include <ESP8266WiFi.h>
#include <PubSubClient.h> // 引入
#include <ArduinoJson.h> // 引入ArduinoJson库,解析JSON用
WiFiClient espClient;
PubSubClient client(espClient);
// GPIO Pin Configuration
#define PWM_Pin 0 // corresonding GPIO 0 as the PWM_PIN
// Maid Property
String maidcode="01"; //swithing maid code number
// WiFi
const char *ssid = "TP-LINK_39A2"; // Enter your WiFi name
const char *password = "nie88888888"; // Enter WiFi password
// MQTT Server
const char *mqtt_broker = ""; //MQTT服务器的IPV4地址,不需要加http前缀
const int mqtt_port = 1883; //MQTT服务器的IPV4地址开放端口
// MQTT User
// 用于改写的String类
String mqtt_username_str = "swithingmaid" + maidcode;
String mqtt_password_str = "swithingmaid" + maidcode;
String topic_str = "swithing_maid_" + maidcode + "_state";
// 实际传入函数的字符串指针变量
const char *mqtt_username = mqtt_username_str.c_str(); //调用.c_str()方法把字符串变为字符串指针
const char *mqtt_password = mqtt_password_str.c_str();
const char *topic = topic_str.c_str();
long int currentMillis=0;
long int period_ms=0;
long int Task_curentMillis=0;
bool ledState =false;
void callback(char *topic, byte *payload, unsigned int length); // 回调函数,用于Loop消息函数的回调处理
void setup() {
//setup阶段做一些前提准备
Serial.begin(115200); // Set software serial baud to 115200;
delay(1000); // Delay for stability
// Connecting to a WiFi network
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to the WiFi network");
// Connecting to an MQTT broker
client.setServer(mqtt_broker, mqtt_port); // 设置IPV4地址及端口并尝试连接目标MQTT Server
while (!client.connected())
{
String client_id = "ESP01S";
client_id += String(WiFi.macAddress());
Serial.printf("The client %s connects to the public MQTT broker\n", client_id.c_str()); //client_id.c_str()
if (client.connect("ESP01S", mqtt_username, mqtt_password)) {
Serial.println("Public EMQX MQTT Server connected");
client.publish(topic, "swithing maid is ready"); //发布主题
client.subscribe(topic); //订阅主题
client.setCallback(callback); //设置对订阅主题新消息的回调处理函数
// 打印调试信息
Serial.print("MQTT Username: ");
Serial.println(mqtt_username);
Serial.print("MQTT Password: ");
Serial.println(mqtt_password);
Serial.print("MQTT Topic: ");
Serial.println(topic);
} else {
Serial.print("Failed with state ");
Serial.print(client.state());
delay(2000);
}
}
}
void loop()
{
client.loop();// 周期性处理 MQTT 客户端的网络通信和消息维护,如果有消息则会调用一次回调函数
delay(100); // Delay for a short period in each loop iteration
}
//The parameters of the callback function are passed in automatically
void callback(char *topic, byte *payload, unsigned int length)
{
// Notice the message is received by maid
Serial.print("Message arrived\n");
// Start Receive the message
String message; //message用于所订阅接收目标主题的状态消息
for (int i = 0; i < length; i++)
{
message += (char) payload[i]; // Convert *byte to string
}
Serial.println("Message is"+message);
// Analysis the received message
StaticJsonDocument<200> jsonDoc; // 创建200字节大小的jsonDoc对象,用于存储解析后的JSON数据
deserializeJson(jsonDoc, message); // 解析这个message字符串,并将结果存储在 jsonDoc
// Judge if jsonDoc has the correct format data like standard json data,then process the mission
// used json data content sample
//
// {
// "maidcode":"01",
// "status":"on",
// "angle":0
// }
if (jsonDoc.is<JsonObject>())
{
JsonObject jsonObj = jsonDoc.as<JsonObject>();
const char* recieved_maid_code = jsonObj["maidcode"];
const char* recieved_maid_status=jsonObj["status"];
const char* recieved_maid_rotate_angle=jsonObj["angle"];
if (strcmp(recieved_maid_code, maidcode.c_str()) == 0 &&strcmp(recieved_maid_status, "on")==0 ) // Notice:strcmp匹配完全相同才返回0
{
Serial.print("on");
for(int dutyCycle = 0; dutyCycle < 1023; dutyCycle++)
{
analogWrite(PWM_Pin, 200);
delay(1);
}
} else if (strcmp(recieved_maid_code, maidcode.c_str()) == 0 && strcmp(recieved_maid_status, "off")==0)
{
Serial.print("off");
for(int dutyCycle = 0; dutyCycle < 1023; dutyCycle++)
{
analogWrite(PWM_Pin, 128);
delay(1);
}
}
}
}
4)后续改进
(2)云上服务
引言:云服务是作为连接用户与硬件的中转站,也是连接AI与硬件的中转站。前面完成了底层代码的初步编写,下面我们来完善云端服务的部署以及配置
<center>图4-1-2-2-1:云上服务角色作用</center>
1)部署要求
【平台环境】
【任务目标】
- 部署服务:部署EMQX服务以及HomeAssitant服务
- 配置服务:配置EMQX与HomeAssitant,使得HomeAssitant能够与EMQX进行通信
2)执行部署
- 部署服务阶段:
- 研究方案:
- 分析方案:对于云上服务的部署有Docker方案和非Dokcer方案,对于本人来讲,Docker方案要远远胜于非Docker方案——理由主要有:容器之间互相隔离,安全可靠;容器部署方案简便迅速,方便与运维面板进行管理交互。
- 执行方案:
【参考教程】
- 配置服务阶段:
【参考教程】
3)完善部署
(3)用户/AI
1)设计要求
4.2 硬件仿真
4.2.1 机械仿真
4.3 软件编写
4.4 整体验证
五、项目完善
六、项目总结