4. 土壤湿度闭环灌溉控制实现
闭环控制对象与信号链
本节实现一个以土壤湿度为反馈量的闭环灌溉控制器。核心思路是:把湿度传感器输出的模拟电压换算成体积含水率,经滑动平均滤波抑制噪声,再送入带滞回的阈值比较器,决定电磁阀开或关。滞回的作用是避免湿度在阈值附近抖动时电磁阀频繁通断。
控制对象与信号链如下:传感器探头埋设在根区深度,输出 0.5~3.0 V 电压(对应 0~60% 体积含水率);ADC 采样后换算为湿度百分比;滤波窗口取 8 个采样点;启动阈值设为 35%,停止阈值设为 45%,即湿度低于 35% 开阀灌溉,高于 45% 关阀,中间区间保持当前状态。
采样换算与滤波实现
传感器输出经 12 位 ADC 采集,参考电压 3.3 V。按线性标定:含水率 θ(%) = (V − 0.5) / (3.0 − 0.5) × 60,其中 V 为传感器电压。滤波采用环形缓冲的滑动平均,窗口 8 点,每 1 秒采样一次,即滤波输出滞后约 4 秒,对灌溉这种慢过程完全可接受。
#define ADC_MAX 4095.0f
#define VREF 3.3f
#define V_DRY 0.5f
#define V_WET 3.0f
#define THETA_SPAN 60.0f
#define FILTER_N 8
static float buf[FILTER_N];
static int idx = 0;
static int cnt = 0;
/* 单次采样:ADC 原始值 → 电压 → 含水率(%) */
float read_moisture(void) {
int raw = adc_read_channel(0); /* 0..4095 */
float v = raw / ADC_MAX * VREF;
float theta = (v - V_DRY) / (V_WET - V_DRY) * THETA_SPAN;
if (theta < 0.0f) theta = 0.0f;
if (theta > 60.0f) theta = 60.0f;
return theta;
}
/* 滑动平均滤波 */
float filter_moisture(float x) {
buf[idx] = x;
idx = (idx + 1) % FILTER_N;
if (cnt < FILTER_N) cnt++;
float sum = 0.0f;
for (int i = 0; i < cnt; i++) sum += buf[i];
return sum / cnt;
}
滞回比较与阀门输出
滞回比较器用两个阈值和一个状态变量实现:当前阀门关闭时,只有湿度低于 35% 才开阀;当前阀门开启时,只有湿度高于 45% 才关阀。这样在 35%~45% 区间内阀门状态保持不变,避免频繁启停。
#define TH_ON 35.0f /* 低于此值开阀 */
#define TH_OFF 45.0f /* 高于此值关阀 */
static int valve_on = 0;
void control_step(float theta_f) {
if (!valve_on && theta_f < TH_ON) {
valve_on = 1;
valve_set(1); /* 继电器吸合,电磁阀通电 */
} else if (valve_on && theta_f > TH_OFF) {
valve_on = 0;
valve_set(0); /* 断电关阀 */
}
/* 35% ≤ θ ≤ 45%:保持原状态,不动作 */
}
/* 主循环:1 秒周期 */
void loop_1s(void) {
float raw = read_moisture();
float theta_f = filter_moisture(raw);
control_step(theta_f);
}
参数选择与验证判据
滞回带宽(45% − 35% = 10%)应大于滤波后湿度的波动幅度,否则仍会抖动。若实测灌溉后湿度上升速率约 1.5%/分钟,则从 35% 升到 45% 约需 6~7 分钟,单次灌溉时长合理。验证时可用串口打印滤波后湿度与阀门状态,观察以下判据:
- 湿度从 40% 缓慢下降穿越 35% 时,阀门应恰好开启一次,不出现反复通断。
- 灌溉过程中湿度上升穿越 45% 时,阀门应关闭,且此后在 35%~45% 区间内保持关闭。
- 人为在传感器附近浇水使湿度快速跳变,滤波输出应平滑过渡,不引起阀门误动作。
若现场电磁阀为 24 V 交流供电,继电器触点需加 RC 吸收或选用固态继电器,避免感性负载关断时干扰 ADC 采样;可在采样前短暂关闭阀驱动或增加采样延时。