项目来源
随着物联网技术在农业领域的广泛应用,智能化养殖成为提升农业生产效率和质量的重要手段。在奶牛养殖产业中,准确监测奶牛产奶量对于优化养殖管理、提高经济效益意义重大。本项目基于此背景,结合教育实践与技术应用需求,旨在利用行空板 K10 打造一套实用的奶牛产奶监测系统,探索物联网技术在农业生产中的具体应用。
项目目标

学习目标
- 深入理解物联网在农业生产中的应用原理和价值。
- 掌握利用物联网技术解决实际问题的方法,如奶牛产奶监测。
- 学会分析系统功能需求,设计并优化物联网应用系统。
实操目标
- 成功搭建基于行空板 K10 的奶牛产奶监测系统硬件环境。
- 实现奶牛身份识别、产奶量采集、数据传输与存储以及结果反馈控制等功能。
- 能够根据实际需求对系统进行拓展和优化。
项目简介
本项目旨在运用行空板 K10 开发一套奶牛产奶监测系统,通过电子标签、RFID 读卡器、超声波传感器等设备,实现对奶牛身份的自动识别和产奶量的精准测量。采集到的数据经行空板 K10 处理后,传输至物联网服务平台进行存储,同时在本地显示屏实时显示奶牛编号和产奶量,并可通过按键控制数据上传。
需求环节 |
功能描述 |
采集数据 |
采集奶牛的身份、产奶量数据 |
传输与存储数据 |
将采集的数据发送到物联网服务平台 |
分析处理数据 |
本项目不涉及分析数据的环节 |
反馈与控制 |
显示奶牛编号和产奶量 |

项目知识点
- 物联网技术基础:包括传感器应用、数据传输与存储、物联网服务平台配置等。
- 电子标签与 RFID 技术:利用电子标签作为奶牛 “身份证”,通过 RFID 读卡器识别奶牛身份。
- 超声波测距原理:运用超声波传感器测量产奶桶液面变化,计算产奶量。
- 编程与算法设计:使用编程实现系统功能,如数据采集、处理、传输及控制逻辑。
项目原理
奶牛耳朵佩戴电子标签,产奶处安装 RFID 读卡器,当奶牛产奶时,读卡器自动识别电子标签获取奶牛身份信息。产奶桶顶部的超声波传感器测量产奶前后液面高度差,根据体积计算公式得出产奶量。行空板 K10 读取传感器数据,通过无线网络将数据传输至物联网服务平台,并在本地显示屏显示相关信息,按键控制数据上传操作。
硬件简介
- 行空板 K10:作为主控板,负责数据处理、与传感器通信、网络连接以及控制显示等功能。

- NFC标签:存储奶牛基本信息,用于身份识别。

- NFC近场通讯模块:读取电子标签信息,获取奶牛身份。

- 超声波传感器:测量产奶桶内液面高度变化,以计算产奶量。

将电子标签固定在奶牛耳朵上,确保信息准确识别。RFID 读卡器安装在奶牛产奶处合适位置,保证能稳定读取电子标签信息。超声波传感器安装在产奶桶顶部,确保测量的准确性,其触发端(Trig)和回波端(Echo)按说明书连接至行空板 K10 对应引脚 。行空板 K10 连接无线网络,与物联网服务平台建立通信。
接线原理图

接线实物图

流程图

重点程序及说明
1. 头文件包含
#include <DFRobot_Iot.h>
#include "unihiker_k10.h"
#include <DFRobot_URM10.h>
#include <DFRobot_NFC0231.h>
DFRobot_Iot.h
:引入了 DFRobot 物联网相关的功能库,用于实现 WiFi 连接、MQTT 通信等功能。
unihiker_k10.h
:可能是 UniHiker K10 开发板相关的头文件,用于控制开发板的屏幕、按键等硬件资源。
DFRobot_URM10.h
:引入超声波测距传感器 URM10 的驱动库,用于测量距离。
DFRobot_NFC0231.h
:引入 NFC 模块的驱动库,用于进行近场通信,实现奶牛 ID 的识别。
2. 动态变量定义
String mind_s_cowID, mind_s_milkVolume, mind_s_message;
volatile float mind_n_startTime, mind_n_distance, mind_n_MAX_DISTANCE, mind_n_CALIBRATION_FACTOR,
mind_n_volume;
mind_s_cowID
:存储识别到的奶牛 ID,类型为字符串。
mind_s_milkVolume
:存储测量得到的牛奶产量,类型为字符串。
mind_s_message
:存储要通过 MQTT 发布的消息,类型为字符串。
mind_n_startTime
:记录开始时间,用于计时,类型为浮点型。
mind_n_distance
:存储超声波传感器测量的距离,类型为浮点型。
mind_n_MAX_DISTANCE
:奶桶的最大测量距离,单位为厘米,类型为浮点型。
mind_n_CALIBRATION_FACTOR
:用于将距离转换为牛奶体积的校准系数,类型为浮点型。
mind_n_volume
:存储计算得到的牛奶体积,类型为浮点型。
3. 函数声明
void DF_ChuShiHua();
void DF_ShiBieNaiNiu();
void DF_ChanNaiKaiShi();
void DF_JieShuChanNai();
DF_ChuShiHua()
:用于初始化系统,包括 WiFi 连接、MQTT 连接和 NFC 模块初始化。
DF_ShiBieNaiNiu()
:用于识别奶牛 ID。
DF_ChanNaiKaiShi()
:开始产奶监测,测量并计算牛奶产量。
DF_JieShuChanNai()
:结束产奶过程,将数据通过 MQTT 发布。
4. 静态常量定义
const String topics[5] = {"siot/CowMilkRecords","","","",""};
定义了一个包含 5 个字符串的数组topics
,其中第一个元素为 MQTT 发布消息的主题siot/CowMilkRecords
,其余元素为空。
5. 对象创建
DFRobot_Iot myIot;
UNIHIKER_K10 k10;
uint8_t screen_dir=2;
DFRobot_PN532_IIC pn532;
DFRobot_URM10 urm10;
bool isMilking = false;
myIot
:创建一个DFRobot_Iot
对象,用于处理物联网相关的操作,如 WiFi 连接和 MQTT 通信。
k10
:创建一个UNIHIKER_K10
对象,用于控制 UniHiker K10 开发板的硬件资源。
screen_dir
:定义屏幕的方向,初始值为 2。
pn532
:创建一个DFRobot_PN532_IIC
对象,用于控制 NFC 模块。
urm10
:创建一个DFRobot_URM10
对象,用于控制超声波测距传感器。
isMilking
:布尔型变量,用于标记是否正在产奶,初始值为false
。
6. setup()
函数
void setup() {
k10.begin();
Serial.begin(9600);
k10.initScreen(screen_dir);
k10.creatCanvas();
mind_n_MAX_DISTANCE = 465;
mind_n_CALIBRATION_FACTOR = 720;
DF_ChuShiHua();
}
k10.begin()
:初始化 UniHiker K10 开发板。
Serial.begin(9600)
:初始化串口通信,波特率为 9600。
k10.initScreen(screen_dir)
:初始化屏幕,设置屏幕方向。
k10.creatCanvas()
:创建画布,用于在屏幕上绘制文本和图形。
mind_n_MAX_DISTANCE = 465
:设置奶桶的最大测量距离为 465 厘米。
mind_n_CALIBRATION_FACTOR = 720
:设置校准系数为 720,即每厘米对应 720 毫升牛奶。
DF_ChuShiHua()
:调用初始化函数,完成系统的初始化工作。
7. loop()
函数
void loop() {
DF_ShiBieNaiNiu();
if (isMilking) {
k10.canvas->canvasText("产奶开始", 0, 150, 0x0000FF, k10.canvas->eCNAndENFont24, 50, true);
k10.canvas->updateCanvas();
Serial.println("产奶开始!");
while (!!isMilking) {
DF_ChanNaiKaiShi();
if ((k10.buttonA->isPressed())) {
delay(200);
if ((k10.buttonA->isPressed())) {
DF_JieShuChanNai();
isMilking = false;
}
while (!(!k10.buttonA->isPressed())) {
delay(10);
}
}
delay(200);
}
}
delay(100);
}
8. 自定义函数
DF_ChuShiHua()
void DF_ChuShiHua() {
myIot.wifiConnect("YMHKZZX", "4145631238520");
while (!myIot.wifiStatus()) {}
k10.canvas->canvasText(myIot.getWiFiLocalIP(), 0, 0, 0x0000FF, k10.canvas->eCNAndENFont24, 50, true);
k10.canvas->updateCanvas();
Serial.println(myIot.getWiFiLocalIP());
myIot.init("192.168.137.1","siot","22106076079390347","dfrobot", topics, 1883);
myIot.connect();
while (!myIot.connected()) {}
k10.canvas->canvasText("MQTT已连接", 0, 50, 0x0000FF, k10.canvas->eCNAndENFont24, 50, true);
k10.canvas->updateCanvas();
Serial.println("\"MQTT已连接\"");
pn532.begin();
Serial.println("\"初始化完成\"");
}
- 连接到指定的 WiFi 网络
YMHKZZX
,密码为4145631238520
。
- 等待 WiFi 连接成功。
- 在屏幕上显示设备的本地 IP 地址,并更新画布。
- 在串口输出设备的本地 IP 地址。
- 初始化 MQTT 客户端,连接到 MQTT 服务器
192.168.137.1
,使用指定的用户名和密码。
- 等待 MQTT 连接成功。
- 在屏幕上显示 “MQTT 已连接”,并更新画布。
- 在串口输出 “MQTT 已连接”。
- 初始化 NFC 模块。
- 在串口输出 “初始化完成”。
DF_ShiBieNaiNiu()
void DF_ShiBieNaiNiu() {
k10.canvas->canvasText("奶牛识别中...", 0, 100, 0x0000FF, k10.canvas->eCNAndENFont24, 50, true);
k10.canvas->updateCanvas();
Serial.println("奶牛识别中...");
mind_n_startTime = millis();
while (!(!((millis() - mind_n_startTime)<5000))) {
if (pn532.scan()) {
mind_s_cowID = pn532.readUid();
break;
}
delay(100);
}
if (((!(mind_s_cowID==String("no card!"))) && (!mind_s_cowID.isEmpty()))) {
isMilking = true;
k10.canvas->canvasText((String("识别到奶牛:") + String(mind_s_cowID)), 0, 100, 0x0000FF, k10.canvas->eCNAndENFont24, 50, true);
k10.canvas->updateCanvas();
Serial.println((String("奶牛ID:") + String(mind_s_cowID)));
}
else {
isMilking = false;
mind_s_cowID = "";
Serial.println("未识别到奶牛!");
}
}
- 在屏幕上显示 “奶牛识别中...”,并更新画布。
- 在串口输出 “奶牛识别中...”。
- 记录当前时间作为开始时间。
- 在 5 秒内不断尝试扫描 NFC 卡:
- 如果扫描到卡,读取卡的 UID 并存储到
mind_s_cowID
中,跳出循环。
- 每次扫描间隔 100 毫秒。
- 如果识别到有效的奶牛 ID:
- 将
isMilking
设置为true
,表示开始产奶。
- 在屏幕上显示识别到的奶牛 ID,并更新画布。
- 在串口输出识别到的奶牛 ID。
- 如果未识别到有效的奶牛 ID:
- 将
isMilking
设置为false
。
- 清空
mind_s_cowID
。
- 在串口输出 “未识别到奶牛!”。
DF_ChanNaiKaiShi()
void DF_ChanNaiKaiShi() {
mind_n_distance = (urm10.getDistanceCM(P1, P0));
if (((mind_n_distance>=0) && (mind_n_distance<=mind_n_MAX_DISTANCE))) {
mind_n_volume = ((mind_n_MAX_DISTANCE - mind_n_distance) * mind_n_CALIBRATION_FACTOR);
mind_s_milkVolume = (String(mind_n_volume));
k10.canvas->canvasText("当前产量:", 0, 150, 0x0000FF, k10.canvas->eCNAndENFont24, 50, true);
k10.canvas->canvasText((String(mind_s_milkVolume) + String("mL")), 0, 200, 0x0000FF, k10.canvas->eCNAndENFont24, 50, true);
k10.canvas->updateCanvas();
Serial.println((String("产奶量:") + String(mind_s_milkVolume)));
}
}
DF_JieShuChanNai()
void DF_JieShuChanNai() {
k10.canvas->canvasText("发送数据中...", 0, 250, 0x0000FF, k10.canvas->eCNAndENFont24, 50, true);
k10.canvas->updateCanvas();
mind_s_message = (String(mind_s_cowID) + String((String(":") + String(mind_s_milkVolume))));
myIot.publish(topic_0, mind_s_message, 1);
k10.canvas->canvasText("发送成功!", 0, 250, 0x0000FF, k10.canvas->eCNAndENFont24, 50, true);
k10.canvas->updateCanvas();
Serial.println("产奶结束!");
Serial.println((String("发布") + String((String(mind_s_message) + String("到 siot/CowMilkRecords 完成!")))));
mind_s_cowID = "";
mind_s_milkVolume = "";
delay(2000);
}
- 在屏幕上显示 “发送数据中...”,并更新画布。
- 构造要发布的消息,格式为
奶牛ID:牛奶体积
。
- 通过 MQTT 客户端将消息发布到主题
siot/CowMilkRecords
。
- 在屏幕上显示 “发送成功!”,并更新画布。
- 在串口输出 “产奶结束!” 和发布消息的信息。
- 清空
mind_s_cowID
和mind_s_milkVolume
。
- 延迟 2000 毫秒。
使用Mind+编程
1.选择主控板

2.添加库
依次添加下面库。




3.编写程序

4.上传程序

测试及活动记录
1.连接wifi

2.wifi成功

3.连接MQTT

4.识别奶牛芯片

5.开始产奶

6.产奶量显示

7.按下A键发送产奶记录到MQTT

8.数据发送完毕

- 测试过程:在模拟环境中,使用水桶模拟产奶桶,倒入不同量的水模拟产奶过程,测试系统对产奶量的测量准确性;多次扫描电子标签,测试身份识别功能;频繁按下按键,测试数据上传功能。
- 活动记录:记录每次测试的时间、测试结果、出现的问题及解决方法。如在测试初期,超声波传感器测量数据不稳定,经检查发现是安装位置晃动导致,重新固定后测量数据稳定。
附件
- 程序代码
程序代码.zip