PetBoxX 育雏喷雾系统设计:区间湿度控制 + 水位自动补水
记录 PetBoxX ESP32-S3 固件中喷雾育雏模块的完整设计思路,方便日后查阅。
涉及两个相互独立但协同工作的子系统:湿度区间状态机(humidity_ctrl)和水位自动补水任务(mist_autofill)。
整体架构
育雏期的湿度管理分两层,职责完全分离:
| 模块 | 职责 | 控制的硬件 |
|---|---|---|
humidity_ctrl | 按湿度区间决定什么时候喷雾 | 雾化器 PWM + 供水泵 |
mist_autofill | 检测雾化器工作状态,按时向水箱补水 | 仅供水泵 |
两者共用同一个供水泵(GPIO39 PWM),但时机不同,不会冲突:
humidity_ctrl喷雾时,泵和雾化器同时开启,为雾化器供水;mist_autofill补水时,雾化器不工作,泵单独运行,往水箱里加水。
一、湿度区间控制(humidity_ctrl)
设计思路
传统单点目标控制("低于目标就开泵")在湿度传感器有轻微抖动时会导致频繁启停。区间滞回控制(Hysteresis)能解决这个问题:
- 低于下限(humi_low)才启动:留有缓冲,不会在目标附近抖动
- 高于上限(humi_high)才停止:喷够了再停,不会刚启动就关
- 中间区间维持当前状态:既不触发新喷雾,也不打断正在进行的喷雾
状态机
humi < low && temp_ok
IDLE ──────────────────────────→ MISTING
↑ │
│ cooldown 结束 │ humi >= high
│ │ 或超时 max_on_s
└──── COOLDOWN ←──────────────────┘
等待 cooldown_s 秒
三个状态:
- IDLE:等待启动条件(湿度低于下限 + 温度允许)
- MISTING:喷雾中,雾化器和供水泵同时运行
- COOLDOWN:喷完后等待冷却,防止反复触发
温度保护
育雏箱升温阶段不应喷雾——低温加湿会让雏鸟受凉。设置 temp_guard 参数:
当 temp < setpoint - temp_guard 时,禁止启动喷雾
默认 0.5°C,即温度还差 0.5°C 没到目标时,不允许喷雾。
硬件动作
// 喷雾启动:泵先开,雾化器随后
static void mist_on(void) {
set_pump_pwm_output_percent(pump_pct); // 供水
set_mist_pwm_output_percent(mist_pct); // 雾化
}
// 喷雾停止:两者同时关
static void mist_off(void) {
set_mist_pwm_output_percent(0);
set_pump_pwm_output_percent(0);
}
PWM 占空比使用用户标定的 PUMP_CAL / MIST_CAL 值,未标定时默认 100%。
可配置参数
| 参数 | 默认值 | 说明 |
|---|---|---|
| humi_low | 55% | 启动阈值 |
| humi_high | 65% | 停止阈值 |
| temp_guard | 0.5°C | 温度保护阈值 |
| max_on_s | 5s | 单次最长喷雾时间(超时强制停止) |
| cooldown_s | 90s | 喷雾结束后的冷却等待时间 |
所有参数持久化到 NVS,重启后自动恢复。
UART 命令(屏→ESP32)
HUMI_TARGET=600 # 目标 60%,自动构建 ±5% 区间 [55, 65]
HUMI_BAND=550,650 # 直接设置上下限(×10 整数避免浮点)
HUMI_GUARD=5 # 温度保护 0.5°C
HUMI_TIMING=5,90 # 喷雾最长 5s,冷却 90s
HUMI_STAGE=1 # 快速应用阶段预设
阶段预设:
| Stage | 区间 | 适用期 |
|---|---|---|
| 1 | 55%~65% | 出壳早期 |
| 2 | 50%~60% | 中期 |
| 3 | 45%~55% | 后期 |
ESP32 → 屏推送
每次参数变更后主动推送到串口屏:
hc.low_x10 # 下限 ×10
hc.high_x10 # 上限 ×10
hc.guard_x10 # 温度保护 ×10
hc.max_on # 最长喷雾秒数
hc.cooldown # 冷却等待秒数
hc.state # 0=IDLE 1=MISTING 2=COOLDOWN
二、水位自动补水(mist_autofill)
设计思路
雾化器消耗水,水箱水位会持续下降。mist_autofill 的职责是定期往水箱里补水,与喷雾控制完全解耦。
它通过 XKT201 超声波雾化模块的工作状态引脚(GPIO21)判断雾化器当前是否在工作——XKT201 工作时该引脚会产生高频边沿跳变。
XKT201 工作状态检测
ISR(任意边沿中断)→ 边沿计数
↓ 每 100ms 采样一次
100ms 内边沿数 ≥ 2 → working = true
300ms 内有边沿 → working = true(recent edge 保持)
否则 → working = false
这个检测是补水逻辑的输入:
- working = true:雾化器在工作,水正在消耗,但现在不补(避免干扰喷雾)
- working = false 且需要加湿:雾化器停了,可以开泵补水
补水流程
条件满足?
需要加湿(当前 RH < 目标 RH)
&& 雾化器当前不工作(XKT201 边沿静默)
&& 不在冷却期(上次补水已过 interval_min)
&& 不在锁定期
↓
开泵运行 duration_s 秒
↓
进入冷却期 interval_min 分钟
↓
冷却结束 → 检查本次补水是否有效(RH 变化 ≥ 1%)
├─ 有效 → 正常继续
└─ 无效 → 失败计数 +1
失败 ≥ 3 次 → 进入锁定(300s)
锁定期间 XKT201 恢复工作 → 自动解锁
失败检测与锁定
每次补水后记录当时的 RH 值,下次补水前比较:
if (RH_now - RH_after_last_refill) < 1.0%:
refill_failures++
if failures >= 3:
lockout = true # 停止补水 300s
这能检测"水箱已空、管路堵塞、泵失效"等异常:水泵转了但湿度没变化,就认为补水失败。
锁定自动解除条件:
- 300s 后自动过期
- XKT201 边沿重新出现(说明雾化器恢复工作)
- 手动发送
MIST_REFILL_NOW命令强制解锁
可配置参数
| 参数 | 默认值 | 范围 |
|---|---|---|
| refill_interval_min | 15 分钟 | 1~180 分钟 |
| refill_duration_s | 6 秒 | 1~60 秒 |
通过 UART 命令 PUMP_CAL=<pct>,<interval_min>,<duration_s> 一次性配置。
三、两系统的协作关系
SHT30 传感器(~1s 采样)
│
├── humidity_ctrl_tick(humi, temp, setpoint)
│ │
│ ├── IDLE: humi < low && temp_ok → mist_on()
│ │ └── pump ON + mist ON(喷雾供水)
│ │
│ └── MISTING: humi >= high || timeout || temp_fail → mist_off()
│ └── pump OFF + mist OFF
│
└── mist_autofill(独立任务,1s tick)
│
├── XKT201 working? → 雾化器在工作,跳过补水
└── NOT working && need_humi && cooldown done
└── pump ON(仅泵,雾化器关)→ 补水 duration_s
两者通过硬件信号松耦合:
humidity_ctrl直接控制硬件输出(泵 + 雾化器)mist_autofill通过检测 XKT201 硬件引脚边沿感知喷雾状态,而不是读软件标志
这意味着即使软件状态出现异常,补水逻辑仍然能正确判断硬件实际状态,不会在喷雾时同时补水。
小结
| 特性 | humidity_ctrl | mist_autofill |
|---|---|---|
| 触发源 | 湿度传感器(SHT30) | 时间间隔 + 湿度需求 |
| 控制目标 | 雾化器 + 供水泵(喷雾时) | 仅供水泵(补水时) |
| 状态判断 | 湿度区间滞回 | XKT201 硬件信号 |
| 保护机制 | 温度保护 + 单次超时 | 失败计数 + 自动锁定 |
| 参数持久化 | NVS | NVS |
| 独立性 | 完全解耦,互不调用 | ← 同左 |
许可协议:
CC BY 4.0