资讯详情

IoT-For-Beginners 农场项目实战:标定“泵运行秒数—土壤湿度”曲线,构建更高效的自动浇花循环

📅 2026/9/16 18:51:37 | 华诺云谱 👁 阅读
IoT-For-Beginners 农场项目实战:标定“泵运行秒数—土壤湿度”曲线,构建更高效的自动浇花循环
IoT-For-Beginners 农场项目实战标定“泵运行秒数—土壤湿度”曲线构建更高效的自动浇花循环【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners本篇基于 IoT-For-Beginners 仓库中第 2 项目Digital Agriculture / 智能农业第 3 课的课后任务 Build a more efficient watering cycle 展开在已实现“继电器—水泵”联动浇水的基础上通过实测标定“泵每运行 1 秒对应土壤湿度读数下降多少”的线性关系并据此改造服务器端代码让水泵只运行到刚好补足土壤湿度所需的时长。读完后你将掌握一套完整的 IoT 执行器标定方法定水量多次测量、均值估算、闭环反馈并能把固定时长浇水策略升级为按需计算的时长策略。任务背景继电器控制水泵为什么需要“标定”本仓库第 2 项目第 3 课自动浇花课 README先讲了三个前置知识点它们是理解本任务的必要背景继电器relay是低压设备控制高功率负载的标准方案。IoT 开发板只能输出 3.3V/5V、小于 1A 的电流无法直接驱动水泵继电器控制回路只需低压信号即可吸合电磁铁输出回路可承载 250V/10A 级别的负载从而让单片机“像手指按开关一样”接通水泵电源。课程提供了一个继电器接线样例水泵串联在继电器的输出回路中继电器吸合即通电抽水。土壤湿度传感器的读数方向是“反的”。课程使用的是 Grove 电容式土壤湿度传感器读数越高代表土壤越干、读数越低代表土壤越湿见 virtual-device-relay.md 中的说明。这也是为什么课程中所有控制逻辑都写成“读数大于 450 就开继电器”。传感器与执行器之间存在时间差。水从水泵流出、渗入土壤、到达传感器探针需要时间课程中观察到的稳定时间约为 20 秒所以不能“读到干燥就一直开泵”而应采用“开泵一小段时间 → 关闭 → 等待稳定 → 重新测量”的循环策略。课程给出的参考实现 code-timing/server/app.py 采用了固定时长策略water_time 5开泵 5 秒wait_time 20等待 20 秒。这能工作但有两个明显问题如果土壤只比阈值干一点点5 秒可能浇过头如果土壤非常干5 秒又远远不够。本任务要解决的正是用实测数据算出“目标湿度提升需要泵运行多少秒”把固定 5 秒替换成按当前读数计算的时长。标定实验测量“泵运行秒数 → 土壤湿度读数”的映射关系任务文档assignment.md给出的核心原理是对于同一份固定体积的土壤泵运行固定时长对土壤湿度的影响应当是可重复的。因此可以离线测量出“每 1 秒泵运行对应读数下降多少”再用于在线控制。操作步骤从干燥的土壤开始测量并记录初始土壤湿度读数。加入固定量的水让泵运行 1 秒或手动倒入固定的水量。关键前提泵必须始终以恒定速率运行即每运行 1 秒输送的水量必须相同否则标定数据不可用。等待土壤湿度稳定后再读数。土壤湿度传感器不是瞬时响应的——水需要时间渗入并扩散到探针位置课程 README 中提到若浇水太靠近传感器可能先看到读数快速下降又回升近处水被整体土壤摊薄的缘故所以要等数值稳定。重复多次把结果整理成一张标定表。文档给出的示例表如下读数为 ADC 0-1023 量程数值越大越干| 累计泵运行时间 | 土壤湿度读数 | 相对上次下降量 | | --- | --: | -: | | 干初始 | 643 | 0 | | 1s | 621 | 22 | | 2s | 601 | 20 | | 3s | 579 | 22 | | 4s | 560 | 19 | | 5s | 539 | 21 | | 6s | 521 | 18 |计算平均下降量示例中 6 秒内读数共下降 643 − 521 122平均每秒下降 122 / 6 ≈20.3。用这个系数改造服务器代码让泵运行到土壤湿度达到目标值所需的时长见下文。使用虚拟硬件时的模拟方法任务文档特别提示如果你没有实体土壤和泵可以使用虚拟 IoT 硬件CounterFit 仿真平台完成整个流程方法是在继电器开启期间手动把土壤湿度读数按固定步长每秒递减以此模拟泵加水对土壤的影响。仓库提供的虚拟设备代码 code-mqtt/virtual-device/soil-moisture-sensor/app.py 就是为此准备的它通过CounterFitConnection.init(127.0.0.1, 5000)连接本地 CounterFit 服务用counterfit_shims_grove里的ADC和GroveRelay(5)模拟 Grove 土壤湿度传感器和继电器继电器挂在 Pin 5每 10 秒把{soil_moisture: ...}发布到ID/telemetry主题同时订阅ID/commands主题收到relay_on: true/false就调用relay.on()/relay.off()。你只需要在 CounterFit 的 Web 界面里手动调整传感器 Value 滑块来“加水”即可完成标定实验并观察虚拟继电器的通断。改造服务器代码从固定 5 秒到按需计算时长先看课程现有的服务器端时序控制逻辑。code-timing/server/app.py 的核心结构是id ID client_telemetry_topic id /telemetry server_command_topic id /commands client_name id soilmoisturesensor_server mqtt_client mqtt.Client(client_name) mqtt_client.connect(test.mosquitto.org) mqtt_client.loop_start() water_time 5 # 继电器泵开启时长秒 wait_time 20 # 等待土壤湿度稳定秒 def send_relay_command(client, state): command { relay_on : state } print(Sending message:, command) client.publish(server_command_topic, json.dumps(command)) def control_relay(client): print(Unsubscribing from telemetry) mqtt_client.unsubscribe(client_telemetry_topic) # 浇水期间取消订阅遥测 send_relay_command(client, True) time.sleep(water_time) send_relay_command(client, False) time.sleep(wait_time) print(Subscribing to telemetry) mqtt_client.subscribe(client_telemetry_topic) # 稳定后重新订阅 def handle_telemetry(client, userdata, message): payload json.loads(message.payload.decode()) print(Message received:, payload) if payload[soil_moisture] 450: threading.Thread(targetcontrol_relay, args(client,)).start()其中有两个设计点在改造时都要保留浇水期间取消订阅遥测unsubscribe防止 10 秒一条的遥测消息在 25 秒的浇水周期内再次触发新的浇水循环课程 README 明确说明之所以不把设备端改成“每分钟才发一次遥测”是因为农场场景下可能需要完整保留浇水过程中的湿度数据供其他服务分析取消订阅只影响本服务器遥测数据仍在 broker 上供其他订阅者使用。在独立线程中执行control_relaythreading.Thread(...).start()避免阻塞 MQTT 主事件循环。在此基础上结合标定的平均下降量可以把固定water_time替换为按读数计算的时长。以示例数据为例目标湿度阈值 450、平均每秒下降 20.3则当前读数 643 时所需泵运行时长为 (643 − 450) / 20.3 ≈9.5 秒而不是固定 5 秒。改造后的关键代码如下完整基础结构沿用上述code-timing版本仅替换时长计算与control_relay的签名moisture_change_per_second 20.3 # 标定结果泵每运行 1 秒读数平均下降量 target_soil_moisture 450 # 目标土壤湿度读数阈值 wait_time 20 # 等待土壤湿度稳定的时间秒 def control_relay(client, water_seconds): print(Unsubscribing from telemetry) mqtt_client.unsubscribe(client_telemetry_topic) send_relay_command(client, True) time.sleep(water_seconds) # 按标定计算的时长开泵 send_relay_command(client, False) time.sleep(wait_time) print(Subscribing to telemetry) mqtt_client.subscribe(client_telemetry_topic) def handle_telemetry(client, userdata, message): payload json.loads(message.payload.decode()) print(Message received:, payload) if payload[soil_moisture] target_soil_moisture: # 需要的泵运行秒数 读数超出目标的幅度 / 每秒下降量 water_seconds (payload[soil_moisture] - target_soil_moisture) \ / moisture_change_per_second threading.Thread(targetcontrol_relay, args(client, water_seconds)).start()需要注意的适用前提与限制线性假设只在标定范围内成立。土壤从很干到很湿单位水量对应的读数变化并不严格恒定示例表里 18~22 之间也在波动。计算出的时长本质上是一个初估课程 README 强调的正确做法是“先试、看传感器数据、再用恒定反馈循环调整”——即保留“湿度仍高于阈值就再浇一轮”的循环用多轮短浇水逼近目标宁可少浇不可浇多水无法从土壤里抽走。moisture_change_per_second与具体土壤强绑定。换一盆土、换一种土壤介质标定表需要重做这也是课程把它列为独立课后任务的原因。参考实现使用公共 brokertest.mosquitto.org客户端 ID 约定为IDsoilmoisturesensor_server服务器端与IDsoilmoisturesensor_client设备端运行前需将代码中的ID替换为你自己的前缀避免与他人冲突。作为对照改造前无时序控制的服务器版本见 code-mqtt/server/app.py它在handle_telemetry中每收到一条遥测就无条件发布relay_on指令而设备端直接控制继电器的版本见 code-relay/pi/soil-moisture-sensor/app.pyRaspberry Pi Grove ADCsoil_moisture 450时relay.on()。三者对照可以清楚看到控制逻辑从“设备端单点判断”演进到“服务器端集中决策 时序控制 标定时长”的完整路径。评分标准Rubric任务文档给出的评分表如下可作为自查清单评分项优秀Exemplary合格Adequate待改进Needs Improvement采集土壤湿度数据能在每次加入固定水量后采集多次读数能用固定水量采集部分读数只能采集一两次读数或无法使用固定水量标定服务器代码能计算平均下降量并更新服务器代码使用该值能计算平均下降量但无法更新服务器代码或平均计算有误但能正确用该值更新代码无法计算平均下降量也无法更新服务器代码小结这篇任务把 IoT 中一个非常通用的工程问题——执行器作用到被测量之间存在延迟且幅度未知——落到了一套可复现的操作流程上固定输入每秒泵量、等待稳定避开传感器/介质的响应时间、多次测量取均值对抗单次读数噪声、把均值写回控制回路water_seconds (当前读数 − 目标读数) / 每秒下降量。配合仓库中 code-timing 的 MQTT 时序骨架你可以在实体设备或 CounterFit 虚拟环境中完整验证这条从标定时域数据到闭环控制代码的路径。【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。