IoT-For-Beginners 数字农业实战:用 CounterFit 虚拟硬件读取土壤湿度(ADC 模拟传感器入门)
【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners
本指南对应 IoT-For-Beginners 课程「2-farm」第 2 课「检测土壤湿度」中的虚拟物联网硬件路线。你将学习如何在不购买任何实体硬件的前提下,用 CounterFit 在本地模拟一个 Grove 电容式土壤湿度传感器,用与 Raspberry Pi 完全一致的 Python 代码读取 10 位 ADC 模拟量,并掌握后续作物自动灌溉项目所需的土壤湿度采集能力。
课程定位:为什么要检测土壤湿度
本课位于 2-farm 数字农业模块的第 2 课。上一课已经介绍了通过测量环境温度来预测植物生长,而土壤湿度是另一项决定植物生长质量的关键指标:土壤中水分过少,植物根系无法吸收足够的水分;水分过多,根系又无法获得足够氧气,最终导致根系死亡、植物无法摄取养分。因此,对农民而言,既不能太湿也不能太干的土壤状态才是最优解,而 IoT 设备的作用就是持续测量土壤湿度,帮助农民只在需要时浇水,为下一课「自动化植物灌溉」打下基础。
在动手之前,先理解土壤湿度传感器的两种常见实现:
- 电阻式(Resistive):两根探针插入土壤,电流从一根探针出发、在另一根探针处测量电流衰减,从而得到土壤电阻。水是良导体,土壤含水量越高,电阻越低。
- 电容式(Capacitive):测量土壤这块「介质」存储电荷的能力(电容)。土壤湿度变化会引起电容变化,并被转换为 IoT 设备可读取的电压。土壤越湿,输出电压越低。
本课使用的 Grove 电容式土壤湿度传感器属于模拟传感器,它返回电压来表示湿度。为了让电压变成代码里的数字,虚拟设备使用一个模拟的10 位 ADC(模数转换器),将电压映射为 1~1,023 的整数值(课程作业中亦按 0~1,023 描述该范围)。
虚拟硬件方案:CounterFit 模拟 Grove 传感器
在 1-getting-started 第 1 课中,你已经在本地安装了 Python、VS Code 和 CounterFit 相关 Pip 包。CounterFit 是一个在本机运行的模拟 IoT 硬件应用:它在浏览器中提供传感器/执行器的模拟界面,你的 Python 代码通过counterfit-shims-grove垫片层(shim)以「在真实 Grove 生态上编程」完全相同的方式访问这些虚拟设备。
💡 采用这种方案的好处是:整个练习与「Raspberry Pi + 实体 Grove 电容式土壤湿度传感器」的接线与代码保持一致——同一个读取逻辑,既能在虚拟环境运行,也能无缝迁移到真实硬件。
任务一:在 CounterFit 中添加土壤湿度传感器
在开始写代码前,先把虚拟传感器注册到 CounterFit 应用中:
- 在电脑上新建一个名为
soil-moisture-sensor的文件夹,其中只包含一个app.py文件;为它创建 Python 虚拟环境,并安装 CounterFit 系列 Pip 包。若需要回顾项目创建与安装过程,可参考 第 1 课虚拟设备指南(关键安装命令为pip install CounterFit、pip install counterfit-connection、pip install counterfit-shims-grove)。 - 确保 CounterFit 网页应用正在运行(默认监听
127.0.0.1:5000)。 - 创建土壤湿度传感器:
- 在Sensors面板的Create sensor区域,打开Sensor type下拉框,选择Soil Moisture;
- Units保持NoUnits不变(该传感器输出的是 ADC 原始读数,没有物理单位);
- 确保Pin为0;
- 点击Add按钮,在 Pin 0 上创建 Soil Moisture 传感器。
创建完成后,传感器会出现在传感器列表中:
编写土壤湿度传感器程序
任务二:编写 app.py
在 VS Code 中打开
soil-moisture-sensor应用文件夹。打开
app.py,在文件顶部加入连接 CounterFit 的代码:from counterfit_connection import CounterFitConnection CounterFitConnection.init('127.0.0.1', 5000)CounterFitConnection.init('127.0.0.1', 5000)将应用连接到本机 5000 端口上运行的 CounterFit 服务。注意:这条初始化调用必须出现在任何 shim 类实例化之前,否则虚拟硬件连接尚未建立。继续添加所需的库导入:
import time from counterfit_shims_grove.adc import ADCimport time导入time模块,稍后用于控制读取间隔;from counterfit_shims_grove.adc import ADC从 Grove 垫片库导入ADC类,用于与 CounterFit 中可连接的虚拟模拟数字转换器交互。
创建
ADC类实例:adc = ADC()添加一个无限循环:从该 ADC 的 Pin 0 读取数值并打印到控制台,每次读取后休眠 10 秒:
while True: soil_moisture = adc.read(0) print("Soil moisture:", soil_moisture) time.sleep(10)adc.read(0)中的参数0与第 1 步在 CounterFit 中设置的 Pin 值一一对应——这也是为什么创建传感器时必须把 Pin 设为 0。
本课的完整示例代码存放在 code/virtual-device/soil-moisture-sensor/app.py,与上文逐行一致。
任务三:运行并模拟不同湿度
在 CounterFit 应用中修改传感器值,CounterFit 提供两种方式:
- 固定值:在传感器的Value输入框中输入数字,点击Set按钮,传感器即返回该数值;
- 随机值:勾选Random复选框,设置Min和Max,点击Set。此后每次传感器被读取时,都会返回 Min 与 Max 之间的随机数——这对模拟「土壤湿度随时间波动」的场景非常有用。
运行 Python 应用:
(.venv) ➜ soil-moisture-sensor $ python app.py控制台将不断输出土壤湿度读数:
Soil moisture: 615 Soil moisture: 612 Soil moisture: 498 Soil moisture: 493 Soil moisture: 490 Soil Moisture: 388在上面的示例输出中,可以看到随着虚拟「浇水」值被调低,读数从 615 逐渐下降到 388——这正是电容式传感器「土壤越湿、电压越低」特性的数字化体现。
原理纵深:同一套代码,三种硬件
从源码结构看,本课虚拟设备的读取 API 刻意与真实硬件保持一致,便于日后平滑迁移:
| 维度 | 虚拟设备(本课) | Raspberry Pi | Wio Terminal |
|---|---|---|---|
| 导入 | from counterfit_shims_grove.adc import ADC | from grove.adc import ADC | 无(Arduino 内建) |
| 读取 | adc.read(0) | adc.read(0)(接 A0 口) | analogRead(A0) |
| 间隔 | time.sleep(10) | time.sleep(10) | delay(5000) |
| 对应文档 | virtual-device-soil-moisture.md | pi-soil-moisture.md | wio-terminal-soil-moisture.md |
对照可见:
- Raspberry Pi 版:
grove.adc.ADC通过 Grove Base Hat 上集成的 ADC 读取 A0 模拟口,再经 I²C 总线送回 Pi 的 GPIO 引脚(Pi 本身只有数字引脚,模拟值靠 Base Hat 的 ADC 转换)。 - Wio Terminal 版:参考 main.cpp,直接在
setup()中pinMode(A0, INPUT),在loop()中analogRead(A0),读取间隔为 5 秒。 - 虚拟设备版:
counterfit_shims_grove.adc.ADC是 Grove 库的垫片实现,read(0)底层从 CounterFit 服务拉取 Pin 0 的模拟量。由于接口签名一致,本课的while True循环无需任何改动即可换用grove.adc跑在真实树莓派上。
这段 10 位 ADC 读数(0~1,023)本质上只是「土壤的电压映射」,并不是可直接使用的物理湿度值。要把它变成「含水量百分比」,就需要对传感器做校准。
拓展:校准传感器,把 ADC 读数变成真实湿度
课程作业 assignment.md 给出了一套标准校准流程。核心思想是重量法(gravimetric soil moisture):用传感器读数对照实验室测得的真实含水量,拟合出换算关系。
校准步骤(需要多次重复,每次使用不同湿度的土壤):
- 用土壤湿度传感器读取一次读数并记录下来;
- 取一份土壤样本并称重,记录湿重 W_wet;
- 烘干土壤——最佳方式是用 110°C(230°F)的烤箱烘数小时(实验室精度要求 48~72 小时),或用阳光晾晒直到土壤完全干燥、呈粉末状;
- 再次称重,记录干重 W_dry。
重量含水量的计算公式为:土壤湿度% = (W_wet − W_dry) / W_dry × 100。
例如:湿样重 212g,干样重 197g,则 (212 − 197) / 197 × 100 ≈7.6%。
完成至少 3 个样本后,将「土壤湿度%」对「传感器读数」绘制散点图并拟合一条最佳拟合线,之后任意一个新读数都能通过这条线换算成真实含水量。校准结果的验收标准参见 assignment.md 中的 Rubric 表格(至少 3 个校准样本为优秀档)。
小结
在本课中,你完成了三件事:
- 在 CounterFit 中添加并配置了一个 Grove 电容式土壤湿度模拟传感器(Pin 0,无单位);
- 用
counterfit_connection+counterfit_shims_grove.adc.ADC编写了与 Raspberry Pi 完全一致的土壤湿度读取程序,验证了「固定值」与「Random 随机值」两种模拟模式; - 理解了 10 位 ADC 读数与真实湿度之间的差距,以及用重量法校准传感器的完整流程。
这套「模拟传感器 → 读取 ADC 原始值 → 校准换算」的能力链,正是下一课「自动化植物浇水」中判断「该不该浇水」的核心数据来源——届时你会用相同的土壤湿度读数去控制继电器和抽水泵,构建完整的数字农业闭环。
【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考