4. 传感器数据校准:干土与湿土实验

好了,到了这一步,你的土壤湿度传感器应该已经能读出数据了。但有个问题——你读到的数值到底代表什么?是湿还是干?

说实话,不同品牌、不同批次的传感器,甚至同一块传感器插在不同土里,读数都可能不一样。我刚开始做智能浇花项目时,就吃过这个亏。买了一批传感器,以为所有阈值都一样,结果有的花淹死了,有的旱死了。嗯,从那以后,我养成了一个习惯:每换一次传感器,必须重新校准

4.1 为什么需要校准?

土壤湿度传感器本质上是一个可变电阻。土壤含水量越高,导电性越好,输出的模拟值就越低(或越高,取决于你的接法)。但问题是:

  • 传感器个体差异:同一型号的传感器,输出值可能偏差10%~20%
  • 土壤类型不同:沙土、黏土、腐殖土的导电性完全不同
  • 温度影响:温度变化会影响土壤的导电率

说白了,你不能拿别人的阈值直接套用。我见过有人直接复制网上的代码,结果传感器一直报"土壤干燥",其实花盆里都快积水了。这就是没校准的后果。

4.2 校准实验:干土与湿土

校准的原理其实很简单:测出传感器在完全干燥和完全湿润时的读数,然后取中间值作为浇水临界点

我个人习惯做三次实验取平均值,这样更靠谱。下面是具体步骤:

实验一:干土测量

  1. 取一些干燥的土壤(可以放烤箱里100℃烘30分钟,或者阳光下晒一天)
  2. 将传感器完全插入干土中,深度约2~3厘米
  3. 等待10秒,让读数稳定
  4. 记录下此时的模拟值,记为 dryValue
  5. 重复三次,取平均值

实验二:湿土测量

  1. 将干土慢慢加水,直到土壤完全湿润(表面有水渗出但不要积水)
  2. 同样插入传感器,等待10秒
  3. 记录此时的模拟值,记为 wetValue
  4. 重复三次,取平均值
小技巧:我建议你用同一个花盆的土来做实验。因为不同花盆的土质可能不一样,用目标花盆的土校准,结果最准确。

4.3 计算浇水临界值

有了干土值和湿土值,临界值怎么算?很简单:

// 假设你的传感器是:越湿数值越低
// 干土值:2800,湿土值:1200
// 临界值取中间偏干一点的位置

int threshold = dryValue - (dryValue - wetValue) * 0.6;
// 或者更保守一点:
int threshold = dryValue - (dryValue - wetValue) * 0.7;

为什么取60%~70%的位置?你想想看,如果取50%,那土壤稍微干一点就触发浇水,容易浇过头。我一般取60%,也就是土壤含水量降到40%以下时开始浇水。这样既不会让植物旱着,也不会涝着。

经验值参考(以ESP32 ADC 12位分辨率为例,0~4095):
土壤状态典型数值范围
完全干燥3000~3500
正常偏干2500~3000
正常湿润1500~2500
完全湿润800~1500
水中300~800

注意:这只是参考值,你的传感器可能完全不同!

4.4 编写校准程序

接下来,我们写一个简单的校准程序。这个程序会读取传感器值,并打印到串口监视器上。你只需要观察数值变化,手动记录干湿阈值。

// 校准程序:土壤湿度传感器阈值测定
// 适用于ESP32 + 土壤湿度传感器(模拟输出)

#define SOIL_SENSOR_PIN 34   // ADC引脚

void setup() {
  Serial.begin(115200);
  Serial.println("=== 土壤湿度传感器校准程序 ===");
  Serial.println("请将传感器插入干土中,等待读数稳定...");
  Serial.println("10秒后开始读取数据");
  delay(10000);
}

void loop() {
  int sensorValue = analogRead(SOIL_SENSOR_PIN);
  
  // 将原始值转换为百分比(假设干土=0%,湿土=100%)
  // 注意:这里需要你手动填入干湿阈值
  // 先打印原始值,后面再计算百分比
  
  Serial.print("原始ADC值: ");
  Serial.print(sensorValue);
  
  // 简单的湿度百分比估算(临时用)
  // 等你知道干湿阈值后,替换下面的数值
  int dryThreshold = 3000;   // 临时值,需要你实际测量后修改
  int wetThreshold = 1200;   // 临时值,需要你实际测量后修改
  
  int moisturePercent = map(sensorValue, dryThreshold, wetThreshold, 0, 100);
  moisturePercent = constrain(moisturePercent, 0, 100);
  
  Serial.print(" | 湿度百分比: ");
  Serial.print(moisturePercent);
  Serial.println("%");
  
  delay(1000);  // 每秒读取一次
}
注意:上面的代码中,dryThresholdwetThreshold是临时值。你必须先运行程序,观察干土和湿土时的实际ADC值,然后替换掉这两个数值。我曾经见过有人直接复制代码没改,结果阈值完全不对,浇花系统直接罢工了。

4.5 避坑指南

做校准实验时,有几个坑我踩过,分享给你:

  • 传感器不要插太深:插到底容易碰到花盆底部的积水,读数会偏低。我一般插2~3厘米深。
  • 等待读数稳定:刚插入传感器时,数值会跳动。等5~10秒,数值稳定了再记录。
  • 不要用手捏传感器:手上的汗液会影响导电性。拿传感器时捏塑料部分,别碰金属探针。
  • 多次测量取平均:一次测量可能有误差。我习惯测三次,取平均值作为最终阈值。

4.6 最终确定临界值

假设你测出来的数据是这样的:

  • 干土平均值:dryAvg = 2850
  • 湿土平均值:wetAvg = 1150

那么浇水临界值可以这样算:

// 方法一:按比例取60%位置
int threshold = dryAvg - (dryAvg - wetAvg) * 0.6;
// = 2850 - (2850 - 1150) * 0.6
// = 2850 - 1700 * 0.6
// = 2850 - 1020
// = 1830

// 方法二:直接取中间值(更保守)
int threshold = (dryAvg + wetAvg) / 2;
// = (2850 + 1150) / 2
// = 2000

我个人推荐方法一,也就是取60%的位置。这样当土壤湿度降到40%以下时,系统就会启动浇水。既不会让植物干死,也不会因为频繁浇水导致烂根。

最终建议:把校准后的阈值写在代码注释里,方便以后查阅。我习惯在程序开头加一段注释,记录传感器型号、校准日期、干湿阈值。这样半年后换传感器时,还能找到参考。

好了,校准这一步做完,你的传感器就有了"灵魂"。它知道什么是干、什么是湿,什么时候该浇水。下一章,我们会把这些阈值写进自动灌溉的逻辑里,让ESP32真正开始"思考"什么时候该浇水。