豆爸 发表于 2025-2-17 05:14:01

义教信息科技 基于行空板 K10 的奶牛产奶监测系统实践

本帖最后由 豆爸 于 2025-2-21 00:20 编辑

## 义教信息科技课程 物联网实践与探索 第24课 农业生产新模式——基于行空板 K10 的奶牛产奶监测系统实践



https://www.bilibili.com/video/BV1RpAceoEs8/?spm_id_from=333.1387.homepage.video_card.click

## 项目来源

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

## 项目目标


### 学习目标

1. 深入理解物联网在农业生产中的应用原理和价值。
2. 掌握利用物联网技术解决实际问题的方法,如奶牛产奶监测。
3. 学会分析系统功能需求,设计并优化物联网应用系统。

### 实操目标

1. 成功搭建基于行空板 K10 的奶牛产奶监测系统硬件环境。
2. 实现奶牛身份识别、产奶量采集、数据传输与存储以及结果反馈控制等功能。
3. 能够根据实际需求对系统进行拓展和优化。

## 项目简介

本项目旨在运用行空板 K10 开发一套奶牛产奶监测系统,通过电子标签、RFID 读卡器、超声波传感器等设备,实现对奶牛身份的自动识别和产奶量的精准测量。采集到的数据经行空板 K10 处理后,传输至物联网服务平台进行存储,同时在本地显示屏实时显示奶牛编号和产奶量,并可通过按键控制数据上传。

| **需求环节**   | **功能描述**                     |
| -------------- | -------------------------------- |
| 采集数据       | 采集奶牛的身份、产奶量数据       |
| 传输与存储数据 | 将采集的数据发送到物联网服务平台 |
| 分析处理数据   | 本项目不涉及分析数据的环节       |
| 反馈与控制   | 显示奶牛编号和产奶量             |


### 项目知识点

1. **物联网技术基础**:包括传感器应用、数据传输与存储、物联网服务平台配置等。
2. **电子标签与 RFID 技术**:利用电子标签作为奶牛 “身份证”,通过 RFID 读卡器识别奶牛身份。
3. **超声波测距原理**:运用超声波传感器测量产奶桶液面变化,计算产奶量。
4. **编程与算法设计**:使用编程实现系统功能,如数据采集、处理、传输及控制逻辑。

## 项目原理

奶牛耳朵佩戴电子标签,产奶处安装 RFID 读卡器,当奶牛产奶时,读卡器自动识别电子标签获取奶牛身份信息。产奶桶顶部的超声波传感器测量产奶前后液面高度差,根据体积计算公式得出产奶量。行空板 K10 读取传感器数据,通过无线网络将数据传输至物联网服务平台,并在本地显示屏显示相关信息,按键控制数据上传操作。

## 硬件简介

1. **行空板 K10**:作为主控板,负责数据处理、与传感器通信、网络连接以及控制显示等功能。



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


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



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


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

## 接线原理图


### 接线实物图


## 流程图



## 重点程序及说明

### 1. 头文件包含

```cpp
#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. 动态变量定义

```cpp
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. 函数声明

```cpp
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. 静态常量定义

```cpp
const String topics = {"siot/CowMilkRecords","","","",""};
```

定义了一个包含 5 个字符串的数组`topics`,其中第一个元素为 MQTT 发布消息的主题`siot/CowMilkRecords`,其余元素为空。

### 5. 对象创建

```cpp
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()`函数

```cpp
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()`函数

```cpp
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);
}
```

- `DF_ShiBieNaiNiu()`:调用奶牛识别函数,尝试识别奶牛 ID。

- - 如果 isMilking 为 true ,表示识别到奶牛并开始产奶:

    - 在屏幕上显示 “产奶开始”,并更新画布。
    - 在串口输出 “产奶开始!”。
    - 进入一个循环,不断调用`DF_ChanNaiKaiShi()`函数进行产奶监测。
    - 检测按钮 A 是否被按下,如果按下,延迟 200 毫秒后再次检测,如果仍然按下,则调用`DF_JieShuChanNai()`函数结束产奶过程,并将`isMilking`设置为`false`。
    - 等待按钮 A 释放。
    - 延迟 200 毫秒。

- 延迟 100 毫秒后,再次进入循环。

### 8. 自定义函数

#### `DF_ChuShiHua()`

```cpp
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()`

```cpp
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()`

```cpp
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)));
    }
}
```

- 使用超声波传感器测量距离,并存储到`mind_n_distance`中。

- 如果测量的距离在有效范围内(0 到mind_n_MAX_DISTANCE ):

- 根据测量的距离计算牛奶体积:`mind_n_volume = (mind_n_MAX_DISTANCE - mind_n_distance) * mind_n_CALIBRATION_FACTOR`。
- 将牛奶体积转换为字符串,并存储到`mind_s_milkVolume`中。
- 在屏幕上显示 “当前产量:” 和牛奶体积(单位为毫升),并更新画布。
- 在串口输出当前产奶量。

#### `DF_JieShuChanNai()`

```cpp
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.数据发送完毕





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

## 附件

1. **程序代码**










页: [1]
查看完整版本: 义教信息科技 基于行空板 K10 的奶牛产奶监测系统实践