本篇博客将完整记录如何使用 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波特率选择 115200Flash 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)ifangle90then pwm.setduty(SERVO_PIN,76)--90度 elseif angle0then 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代码取 2590 ∘ 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_clientnil functionconnectBemfa()ifmqtt_client~nil then mqtt_client:close()--清理旧实例防止内存泄漏 endprint(正在连接巴法云 MQTT 服务器...)mqtt_clientmqtt.Client(BEMFA_UID,120,BEMFA_UID,BEMFA_UID)--事件1收到云端指令 mqtt_client:on(message,function(client,topic,data)print(收到控制指令 [..topic..]: ..data)ifdataonthensetServoAngle(90)elseif dataoffthensetServoAngle(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({ssidWIFI_SSID,pwdWIFI_PASS,autotrue})-- 监听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.reason201thenprint( - 诊断: 找不到指定的 WiFi。请检查是否误填了 5G 信号或名字拼写错误)elseif T.reason202thenprint( - 诊断: WiFi 密码错误)elseif T.reason200or T.reason203thenprint( - 诊断: 路由器拒绝接入或信号太弱。)end end)完整代码----1. 全局参数配置 --localWIFI_SSIDWIFI名称localWIFI_PASSWIFI密码localBEMFA_UID巴法云个人私钥localTOPIC巴法云订阅MQTT主题localSERVO_PIN1-- 对应esp8266的D1引脚 ----2. 舵机初始化与控制函数 ---- 50Hz 周期(20ms)--0度(0.5ms)-占空比约25--90度(1.5ms)-占空比约76pwm.setup(SERVO_PIN,50,76)pwm.start(SERVO_PIN)functionsetServoAngle(angle)ifangle90thenpwm.setduty(SERVO_PIN,76)--90度 elseif angle0thenpwm.setduty(SERVO_PIN,25)--0度 end print(执行动作: 舵机转动到 ..angle.. 度)end ----3. 巴法云 MQTT 连接逻辑 --localmqtt_clientnilfunctionconnectBemfa()-- 如果旧实例存在先清理避免内存泄漏ifmqtt_client ~nilthenmqtt_client:close()end print(正在连接巴法云 MQTT 服务器...)-- 初始化 Client(Client_ID, KeepAlive, Username, Password)-- 巴法云规则这四个参数除了 KeepAlive其余全部填UIDmqtt_clientmqtt.Client(BEMFA_UID,120, BEMFA_UID, BEMFA_UID)-- 注册收到云端指令事件 mqtt_client:on(message, function(client, topic, data)print(收到控制指令 [..topic..]: ..data)ifdataonthensetServoAngle(90)-- 例如小爱同学下发打开指令 $\rightarrow$ 舵机转到90度 elseif dataoffthensetServoAngle(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({ssidWIFI_SSID,pwdWIFI_PASS,autotrue})-- 监听事件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.reason201thenprint( - 诊断: 找不到指定的 WiFi。请检查是否误填了 5G 信号或名字拼写错误)elseif T.reason202thenprint( - 诊断: WiFi 密码错误)elseif T.reason200or T.reason203thenprint( - 诊断: 路由器拒绝接入或信号太弱。)end end)总结先烧录好bin文件到esp8266后在restart通过vscode打开上面的lua代码文件右键选择Upload activate file to device就可以连接小爱同学进行语音控制舵机转动
小爱同学语音控制 ESP8266 舵机转动(NodeMCU-tool Lua 开发实战记录)
发布时间:2026/6/25 12:41:09
本篇博客将完整记录如何使用 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波特率选择 115200Flash 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)ifangle90then pwm.setduty(SERVO_PIN,76)--90度 elseif angle0then 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代码取 2590 ∘ 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_clientnil functionconnectBemfa()ifmqtt_client~nil then mqtt_client:close()--清理旧实例防止内存泄漏 endprint(正在连接巴法云 MQTT 服务器...)mqtt_clientmqtt.Client(BEMFA_UID,120,BEMFA_UID,BEMFA_UID)--事件1收到云端指令 mqtt_client:on(message,function(client,topic,data)print(收到控制指令 [..topic..]: ..data)ifdataonthensetServoAngle(90)elseif dataoffthensetServoAngle(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({ssidWIFI_SSID,pwdWIFI_PASS,autotrue})-- 监听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.reason201thenprint( - 诊断: 找不到指定的 WiFi。请检查是否误填了 5G 信号或名字拼写错误)elseif T.reason202thenprint( - 诊断: WiFi 密码错误)elseif T.reason200or T.reason203thenprint( - 诊断: 路由器拒绝接入或信号太弱。)end end)完整代码----1. 全局参数配置 --localWIFI_SSIDWIFI名称localWIFI_PASSWIFI密码localBEMFA_UID巴法云个人私钥localTOPIC巴法云订阅MQTT主题localSERVO_PIN1-- 对应esp8266的D1引脚 ----2. 舵机初始化与控制函数 ---- 50Hz 周期(20ms)--0度(0.5ms)-占空比约25--90度(1.5ms)-占空比约76pwm.setup(SERVO_PIN,50,76)pwm.start(SERVO_PIN)functionsetServoAngle(angle)ifangle90thenpwm.setduty(SERVO_PIN,76)--90度 elseif angle0thenpwm.setduty(SERVO_PIN,25)--0度 end print(执行动作: 舵机转动到 ..angle.. 度)end ----3. 巴法云 MQTT 连接逻辑 --localmqtt_clientnilfunctionconnectBemfa()-- 如果旧实例存在先清理避免内存泄漏ifmqtt_client ~nilthenmqtt_client:close()end print(正在连接巴法云 MQTT 服务器...)-- 初始化 Client(Client_ID, KeepAlive, Username, Password)-- 巴法云规则这四个参数除了 KeepAlive其余全部填UIDmqtt_clientmqtt.Client(BEMFA_UID,120, BEMFA_UID, BEMFA_UID)-- 注册收到云端指令事件 mqtt_client:on(message, function(client, topic, data)print(收到控制指令 [..topic..]: ..data)ifdataonthensetServoAngle(90)-- 例如小爱同学下发打开指令 $\rightarrow$ 舵机转到90度 elseif dataoffthensetServoAngle(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({ssidWIFI_SSID,pwdWIFI_PASS,autotrue})-- 监听事件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.reason201thenprint( - 诊断: 找不到指定的 WiFi。请检查是否误填了 5G 信号或名字拼写错误)elseif T.reason202thenprint( - 诊断: WiFi 密码错误)elseif T.reason200or T.reason203thenprint( - 诊断: 路由器拒绝接入或信号太弱。)end end)总结先烧录好bin文件到esp8266后在restart通过vscode打开上面的lua代码文件右键选择Upload activate file to device就可以连接小爱同学进行语音控制舵机转动