本篇博客将完整记录如何使用 ESP8266 (NodeMCU) 固件,利用Lua 语言配合巴法云,最终实现小爱同学语音控制舵机转动的全流程。
文章目录
- 准备工作
- 一、开发lua环境搭建
- 二、代码编写
- 1.舵机初始化与控制
- 2.巴法云 MQTT 连接逻辑
- 3. WiFi 连接
- 完整代码
- 总结
准备工作
- 硬件接线 (以 SG90 舵机为例)
红线 (VCC) ➡️ ESP8266 的 3V3(若动力不足可接 VIN)
棕线 (GND) ➡️ ESP8266 的 GND
橙线 (信号线) ➡️ ESP8266 的 D1 引脚(对应 Lua 底层 GPIO 5) - 巴法云与米家端配置
由于米家生态不对个人开发者直接开放,我们需要通过巴法云进行 MQTT/TCP中转:
a. 注册巴法云:登录后台拿到你的唯一密钥 Private_Key(私钥)。
b. 新建 MQTT设备云:新建一个主题,命名为 9nfwp3dxs002。
c. 修改昵称:在巴法云后台将该主题的昵称修改为 “舵机” 或 “灯”等随便名字(小爱同学以此名字来识别语音指令控制舵机)。
d. 绑定米家:打开手机 米家App ➡️ 我的 ➡️ 其他平台设备 ➡️ 绑定“巴法” 账号。随后在列表中找到该设备,分配房间并同步。
一、开发lua环境搭建
- 如果要使用nodemcu固件的烧录且使用Lua在esp8266上跑,需要先下载定制固件,由于我需要连接mqtt和使用舵机,所以我额外勾选MQTT和PWM。
然后填写自己的邮箱就可以Start your bulid,注意是第二封finish邮件中找到
上述两个的bin文件任意一个都行,integer稍微大小要小一点。 - 使用 NodeMCU PyFlasher 写入固件。
NodeMCU firmware:点击 Browse,选择你下载好的 .bin 固件文件
Baud rate波特率:选择 115200
Flash mode:选择 Dual I/O (DIO) - 直接在VS Code左侧扩展市场搜索并安装NodeMCU-Tools插件,然后再 VS Code 中打开一个空文件夹(作为你的项目工作区),并在里面新建一个文件,命名为init.lua。
为什么要以 init.lua命名? NodeMCU 芯片在上电开机后,底层系统会自动寻找并第一个执行名为 init.lua 的文件,它是整个程序的入口。
二、代码编写
local WIFI_SSID = “WIFI名称”
local WIFI_PASS = “WIFI密码”
local BEMFA_UID = “巴法云个人私钥”
local TOPIC = “巴法云订阅MQTT主题”
1.舵机初始化与控制
这里我就假设转动两个角度一个是90和0来模拟开灯和关灯,代码如下:
--50Hz 周期(20ms)--90度(1.5ms)->占空比约76pwm.setup(SERVO_PIN,50,76)pwm.start(SERVO_PIN)functionsetServoAngle(angle)ifangle==90then pwm.setduty(SERVO_PIN,76)--90度 elseif angle==0then pwm.setduty(SERVO_PIN,25)--0度 endprint("执行动作: 舵机转动到 "..angle.." 度")end关于占空比的数学换算:
NodeMCU 的 PWM 分辨率为 10 bit(范围 0 - 1023)。
0 ∘ 0^\circ0∘对应0.5 ms 0.5\text{ms}0.5ms脉宽:0.5 ms 20 ms × 1023 ≈ 25.5 \frac{0.5\text{ms}}{20\text{ms}} \times 1023 \approx 25.520ms0.5ms×1023≈25.5(代码取 25)
90 ∘ 90^\circ90∘对应1.5 ms 1.5\text{ms}1.5ms脉宽:1.5 ms 20 ms × 1023 ≈ 76.7 \frac{1.5\text{ms}}{20\text{ms}} \times 1023 \approx 76.720ms1.5ms×1023≈76.7(代码取 76)
这里我进行软件的粗略计算
2.巴法云 MQTT 连接逻辑
巴法云是一个个人开发者的免费物联网云平台。本段函数处理了从“握手连接”到“订阅监听”的全套逻辑。代码如下:
local mqtt_client=nil functionconnectBemfa()ifmqtt_client~=nil then mqtt_client:close()--清理旧实例,防止内存泄漏 endprint("正在连接巴法云 MQTT 服务器...")mqtt_client=mqtt.Client(BEMFA_UID,120,BEMFA_UID,BEMFA_UID)--事件1:收到云端指令 mqtt_client:on("message",function(client,topic,data)print("收到控制指令 ["..topic.."]: "..data)ifdata=="on"thensetServoAngle(90)elseif data=="off"thensetServoAngle(0)end end)--事件2:掉线重连 mqtt_client:on("offline",function(client)print("MQTT 已断开连接,5秒后尝试重连...")tmr.create():alarm(5000,tmr.ALARM_SINGLE,connectBemfa)end)--发起 TCP 连接 mqtt_client:connect("bemfa.com",9501,false,function(client)print("已成功建立 MQTT TCP 连接!")--核心:连接后必须订阅主题 client:subscribe(TOPIC,0,function(client)print("成功订阅主题: "..TOPIC)end)end,function(client,reason)print("MQTT 连接失败,底层错误码: "..reason)end)end3. WiFi 连接
wifi.setmode(wifi.STATION)wifi.sta.config({ssid=WIFI_SSID,pwd=WIFI_PASS,auto=true})-- 监听1:物理连接成功 wifi.eventmon.register(wifi.eventmon.STA_CONNECTED, function(T)print("已物理连接到路由器,等待 DHCP 分配 IP...")end)-- 监听2:成功获取 IP(真正的联网成功) wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, function(T)print("WiFi 连接彻底成功! 设备 IP 地址: "..T.IP)connectBemfa()-- 联动触发巴法云连接 end)-- 监听3:断开或失败(智能诊断) wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED, function(T)print("WiFi 连接断开或失败! -> 底层错误代码 (Reason): "..T.reason)ifT.reason==201thenprint(" -> 诊断: 找不到指定的 WiFi。请检查是否误填了 5G 信号,或名字拼写错误!")elseif T.reason==202thenprint(" -> 诊断: WiFi 密码错误!")elseif T.reason==200or T.reason==203thenprint(" -> 诊断: 路由器拒绝接入或信号太弱。")end end)完整代码
--==========================================--1. 全局参数配置 --==========================================localWIFI_SSID="WIFI名称"localWIFI_PASS="WIFI密码"localBEMFA_UID="巴法云个人私钥"localTOPIC="巴法云订阅MQTT主题"localSERVO_PIN=1-- 对应esp8266的D1引脚 --==========================================--2. 舵机初始化与控制函数 --==========================================-- 50Hz 周期(20ms)--0度(0.5ms)->占空比约25--90度(1.5ms)->占空比约76pwm.setup(SERVO_PIN,50,76)pwm.start(SERVO_PIN)functionsetServoAngle(angle)ifangle==90thenpwm.setduty(SERVO_PIN,76)--90度 elseif angle==0thenpwm.setduty(SERVO_PIN,25)--0度 end print("执行动作: 舵机转动到 "..angle.." 度")end --==========================================--3. 巴法云 MQTT 连接逻辑 --==========================================localmqtt_client=nilfunctionconnectBemfa()-- 如果旧实例存在,先清理避免内存泄漏ifmqtt_client ~=nilthenmqtt_client:close()end print("正在连接巴法云 MQTT 服务器...")-- 初始化 Client(Client_ID, KeepAlive, Username, Password)-- 巴法云规则:这四个参数除了 KeepAlive,其余全部填UIDmqtt_client=mqtt.Client(BEMFA_UID,120, BEMFA_UID, BEMFA_UID)-- 注册:收到云端指令事件 mqtt_client:on("message", function(client, topic, data)print("收到控制指令 ["..topic.."]: "..data)ifdata=="on"thensetServoAngle(90)-- 例如:小爱同学下发打开指令 $\rightarrow$ 舵机转到90度 elseif data=="off"thensetServoAngle(0)-- 例如:小爱同学下发关闭指令 $\rightarrow$ 舵机转到0度 end end)-- 注册:掉线重连事件 mqtt_client:on("offline", function(client)print("MQTT 已断开连接,5秒后尝试重连...")tmr.create():alarm(5000, tmr.ALARM_SINGLE, connectBemfa)end)-- 发起连接(域名: bemfa.com, 端口:9501, false表示明文非加密)mqtt_client:connect("bemfa.com",9501, false, function(client)print("已成功建立 MQTT TCP 连接!")-- 核心步骤:成功连接后必须订阅主题,巴法云才会显示设备在线 client:subscribe(TOPIC,0, function(client)print("成功订阅主题: "..TOPIC)print("设备已完全上线!现在可以去巴法云网页端或联动音箱发送 on/off 测试了。")end)end, function(client, reason)print("MQTT 连接失败,底层错误码: "..reason)end)end --==========================================--4. WiFi 连接 --==========================================print("====================================")print("开始配置 WiFi...")wifi.setmode(wifi.STATION)wifi.sta.config({ssid=WIFI_SSID,pwd=WIFI_PASS,auto=true})-- 监听事件:WiFi 成功连接到路由器(尚未获取IP)wifi.eventmon.register(wifi.eventmon.STA_CONNECTED, function(T)print("已物理连接到路由器,等待 DHCP 分配 IP...")end)-- 监听事件:成功获取到 IP(此时真正具备网络通信能力)wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, function(T)print("WiFi 连接彻底成功! 设备 IP 地址: "..T.IP)connectBemfa()-- 网络通畅后,自动触发巴法云连接 end)-- 监听事件:WiFi 断开或连接失败(诊断助手)wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED, function(T)print("WiFi 连接断开或失败!")print(" -> 底层错误代码 (Reason): "..T.reason)ifT.reason==201thenprint(" -> 诊断: 找不到指定的 WiFi。请检查是否误填了 5G 信号,或名字拼写错误!")elseif T.reason==202thenprint(" -> 诊断: WiFi 密码错误!")elseif T.reason==200or T.reason==203thenprint(" -> 诊断: 路由器拒绝接入或信号太弱。")end end)总结
先烧录好bin文件到esp8266后,在restart,通过vscode打开上面的lua代码文件右键选择Upload activate file to device,就可以连接小爱同学进行语音控制舵机转动!