ESP8266 舵机持续异响问题分析与优化实践
·
问题现象
在使用 NodeMCU(ESP8266)控制 SG90 舵机时,项目已经能够正常接收 MQTT 指令并完成动作,例如:
1.小爱同学控制开关
2.巴法云 MQTT 下发 on/off 指令
3.舵机执行转动角度动作
但运行后发现一个明显问题:
即使舵机已经停止转动,仍然持续发出滋滋滋声音,
同时伴随着:
1.舵机发热
2.电流持续消耗
3.偶尔轻微抖动
下面分析一下原始的方案。
原始方案分析
在代码一开始就把PWM启动
pwm.setup(SERVO_PIN, 50, 76)
pwm.start(SERVO_PIN)
得到的效果就是
ESP8266
↓
持续输出50Hz PWM
↓
舵机持续接收控制信号
↓
持续保持当前位置
这就导致整个运行过程中 PWM 从未停止。即使舵机已经转到目标位置,ESP8266 仍然每 20ms 输出一次控制脉冲。
所以,更合理的方案是下发命令在调用启动PWM,运行结束后在关闭PWM,通过事件驱动控制舵机转动。
事件驱动控制
其实我们就是想实现的是当我们下发命令后舵机再启动,然后执行完就关闭
优化后的控制流程:
收到MQTT指令
↓
启动PWM
↓
舵机转动
↓
等待到位
↓
停止PWM
↓
释放舵机
实现思路
收到 MQTT 指令:
if data == "on" then
moveServo(...)
elseif data == "off" then
moveServo(...)
end
执行函数:
pwm.setup(...)
pwm.start(...)
延时:
tmr.create():alarm(...)
到达预定时间后:
pwm.stop(...)
释放控制信号。
最后得到的效果是,动作完成后,PWM停止,舵机不再接收脉冲,不会继续修正位置而导致舵机发热。
完整代码
-- ==========================================
-- 1. 全局参数配置
-- ==========================================
local WIFI_SSID = "WIFI名称"
local WIFI_PASS = "WIFI密码"
local BEMFA_UID = "巴法云个人私钥"
local TOPIC = "巴法云订阅MQTT主题"
local SERVO_PIN = 1 -- 对应esp8266的D1引脚
-- ==========================================
-- 2. 舵机初始化与控制函数
-- ==========================================
local SERVO_OPEN_DUTY = 76
local SERVO_CLOSE_DUTY = 25
-- 转动时间(毫秒)
local SERVO_MOVE_TIME = 800
local servo_busy = false -- 采用状态机码防止重复执行相同命令
-- ==========================================
-- 3. 舵机动作函数
-- ==========================================
function moveServo(duty, angle)
if servo_busy then
print("舵机正在执行动作,忽略重复命令")
return
end
servo_busy = true
print("舵机开始转动 -> " .. angle .. " 度")
pwm.setup(SERVO_PIN, 50, duty)
pwm.start(SERVO_PIN)
tmr.create():alarm(SERVO_MOVE_TIME, tmr.ALARM_SINGLE, function()
pwm.stop(SERVO_PIN)
print("舵机动作完成")
print("PWM已关闭,释放舵机")
servo_busy = false
end)
end
function setServoAngle(angle)
if angle == 90 then
moveServo(SERVO_OPEN_DUTY, 90)
elseif angle == 0 then
moveServo(SERVO_CLOSE_DUTY, 0)
else
print("未知角度")
end
end
-- ==========================================
-- 4. 连接巴法云 MQTT
-- ==========================================
local mqtt_client = nil
function connectBemfa()
if mqtt_client ~= nil then
mqtt_client:close()
end
print("正在连接巴法云 MQTT...")
mqtt_client = mqtt.Client(
BEMFA_UID,
120,
BEMFA_UID,
BEMFA_UID
)
mqtt_client:on("message", function(client, topic, data)
print("收到消息")
print("Topic : " .. topic)
print("Data : " .. data)
if data == "on" then
setServoAngle(90)
elseif data == "off" then
setServoAngle(0)
else
print("未知指令")
end
end)
mqtt_client:on("offline", function(client)
print("MQTT掉线")
print("5秒后重连")
tmr.create():alarm(
5000,
tmr.ALARM_SINGLE,
connectBemfa)
end)
mqtt_client:connect(
"bemfa.com",
9501,
false,
function(client)
print("MQTT连接成功")
client:subscribe(
TOPIC,
0,
function(client)
print("已订阅主题: " .. TOPIC)
print("设备在线")
end)
end,
function(client, reason)
print("MQTT连接失败")
print("错误码: " .. reason)
end)
end
-- ==========================================
-- 5. WiFi 与系统启动流程
-- ==========================================
function startSystem()
print("====================================")
print("开始连接 WiFi...")
wifi.setmode(wifi.STATION)
wifi.sta.config({
ssid = WIFI_SSID,
pwd = WIFI_PASS,
auto = true
})
wifi.eventmon.register(wifi.eventmon.STA_CONNECTED, function(T)
print("已连接路由器,等待获取 IP...")
end)
wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, function(T)
print("WiFi连接成功,IP: " .. T.IP)
connectBemfa()
end)
wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED, function(T)
print("WiFi断开,Reason: " .. T.reason)
-- (保留你原有的错误码诊断逻辑...)
end)
end
-- ==========================================
-- 6. 核心防锁死:开机延时启动
-- ==========================================
print("====================================")
print("系统上电就绪。")
print("进入 3 秒安全等待期,此时可使用 nodemcu-tool 强行打断...")
-- 开机后强制等待 3 秒,不执行任何业务逻辑
tmr.create():alarm(3000, tmr.ALARM_SINGLE, function()
print("安全等待结束,启动主控程序!")
startSystem()
end)
更多推荐



所有评论(0)