当前位置: 首页 > news >正文

Qt C++ 信创工控|AI奶牛配种辅助智能管理系统

# Qt C++ 信创工控|AI奶牛配种辅助智能管理系统
## 项目简介
完全对标**奶牛配种辅助工**全流程岗位职责:AI视觉发情识别、RFID牛只身份读取、冻精库存管理、恒温解冻设备联动、配种输精流程管控、B超妊检记录、繁殖周期自动提醒、繁殖台账SQLite归档、液氮罐/消毒设备监控;适配**统信UOS、银河麒麟**飞腾/鲲鹏/龙芯国产工控,Qt5.15+OpenCV+SQLite纯开源无商业闭源库,单文件main.cpp直接编译运行,
## 一、工程配置文件 BreedingCowCtrl.pro
```pro
QT += core gui widgets serialport charts sql opengl
CONFIG += c++11 utf8_source
SOURCES += main.cpp
INCLUDEPATH += /usr/include/opencv4
LIBS += -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs
TARGET = DairyCowBreedingAssist
TEMPLATE = app
DEFINES += QT_NO_DEBUG_OUTPUT
```
## 二、完整可编译源码 main.cpp
```cpp
#include <QApplication>
#include <QMainWindow>
#include <QWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <QTimer>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QChart>
#include <QLineSeries>
#include <QBarSeries>
#include <QBarSet>
#include <QValueAxis>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QDateTime>
#include <QFile>
#include <QTextStream>
#include <QMessageBox>
#include <QGroupBox>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QListWidget>
#include <QListWidgetItem>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <opencv2/opencv.hpp>
#include <QPixmap>
#include <QImage>
#include <QThread>
#include <QMutex>
#include <QRandomGenerator>
#include <QFont>
#include <QRadioButton>
#include <QButtonGroup>
#include <QDateEdit>
#include <QLineEdit>

#pragma execution_character_set("utf-8")

// ===================== 全局枚举定义 =====================
// 奶牛发情等级(AI视觉+项圈传感器综合判定)
enum EstrusLevel
{
ESTRUS_NONE, // 无发情征兆
ESTRUS_WEAK, // 轻度发情(爬跨少量、活动量小幅上升)
ESTRUS_OPTIMAL, // 最佳配种窗口期(静立反射,12h内输精)
ESTRUS_OVER // 发情末期,排卵临近,需立即配种
};
// 配种后妊检阶段
enum PregnancyStage
{
PRE_36_42D, // 36~42天初检
PRE_90_96D, // 90~96天二次复检
PRE_220D, // 妊娠后期干奶前复检
PRE_ABORT // 流产空怀
};
// 冻精公牛品系类型
enum BullSemenType
{
BULL_MILK_HIGH, // 高产奶系冻精
BULL_CONFORMATION, // 体型改良冻精
BULL_COMBINE // 综合兼顾型
};
// 系统运行模式
enum SysRunMode
{
MODE_MANUAL_ASSIST, // 人工辅助模式
MODE_AUTO_ESTRUS_ALERT,// AI自动发情提醒配种
MODE_SEMEN_STOCK_MGT, // 冻精库存管理
MODE_ALL_STOP
};
// 繁育配套设备状态
enum EquipStat
{
EQUIP_IDLE,
EQUIP_THAW_WARM, // 37℃冻精解冻恒温槽运行
EQUIP_LIQUID_N2_ALARM,// 液氮液位低告警
EQUIP_DISINFECT_RUN,// 输精器械消毒设备
EQUIP_RFID_READING, // RFID牛耳标读取中
EQUIP_FAULT
};
// 牛只基础繁育信息结构体
struct CowBreedInfo
{
QString rfidId; // 电子耳标ID
int cowNo; // 牛舍编号
int parity; // 胎次
QDate calveDate; // 上次产犊日期
EstrusLevel estrusLv; // 当前发情等级
double activityVal; // 项圈活动量数值
bool needInseminate; // 是否需立即配种
};
// 冻精库存记录
struct SemenStock
{
QString bullCode;
BullSemenType bullType;
int strawCount; // 剩余细管数量
QDate produceDate;
double liquidN2Level; // 液氮罐液位cm
};
// AI视觉发情识别子线程(多线程防UI卡顿)
class EstrusVisionThread : public QThread
{
Q_OBJECT
public:
explicit EstrusVisionThread(QObject *parent = nullptr);
void setCowPen(int penId);
void stopThread();
signals:
void estrusDetectResult(CowBreedInfo cowInfo);
private:
void run() override;
int m_targetPen;
bool m_runFlag;
QMutex m_mutex;
};
EstrusVisionThread::EstrusVisionThread(QObject *parent)
: QThread(parent), m_targetPen(1), m_runFlag(true)
{}
void EstrusVisionThread::setCowPen(int penId)
{
QMutexLocker lock(&m_mutex);
m_targetPen = penId;
}
void EstrusVisionThread::stopThread()
{
QMutexLocker lock(&m_mutex);
m_runFlag = false;
}
void EstrusVisionThread::run()
{
while(true)
{
{
QMutexLocker lock(&m_mutex);
if(!m_runFlag) break;
}
cv::Mat frame(480,640,CV_8UC3,cv::Scalar(200,230,180));
CowBreedInfo info;
info.cowNo = m_targetPen;
info.rfidId = QString("RFID%1%2").arg(m_targetPen).arg(QRandomGenerator::global()->bounded(1000,9999));
info.parity = QRandomGenerator::global()->bounded(1,6);
info.calveDate = QDate::currentDate().addDays(-QRandomGenerator::global()->bounded(45,300));
info.activityVal = QRandomGenerator::global()->bounded(200,1800);
// 活动量判定发情等级
if(info.activityVal < 400) info.estrusLv = ESTRUS_NONE;
else if(info.activityVal < 900) info.estrusLv = ESTRUS_WEAK;
else if(info.activityVal < 1400) info.estrusLv = ESTRUS_OPTIMAL;
else info.estrusLv = ESTRUS_OVER;
info.needInseminate = (info.estrusLv == ESTRUS_OPTIMAL || info.estrusLv == ESTRUS_OVER);
emit estrusDetectResult(info);
QThread::msleep(900);
}
}
// ===================== 主工控窗口 =====================
class BreedAssistMainWin : public QMainWindow
{
Q_OBJECT
public:
explicit BreedAssistMainWin(QWidget *parent = nullptr);
~BreedAssistMainWin() override;
private:
// 顶层布局
QWidget *m_centralWid;
QHBoxLayout *m_mainHLay;
// 左侧AI视觉发情识别+RFID耳标读取面板
QGroupBox *m_groupVisionRfid;
QLabel *m_labelCamShow;
QComboBox *m_comboPenSel;
QPushButton *m_btnStartVision;
QPushButton *m_btnStopVision;
QPushButton *m_btnRfidRead;
QLabel *m_labelRfidShow;
QLabel *m_labelEstrusLvShow;
QLabel *m_labelActivityShow;
QLabel *m_labelNeedMateTip;
// 中间配种辅助设备+冻精库存控制区
QGroupBox *m_groupEquipSemen;
QComboBox *m_comboRunMode;
QLabel *m_labelEquipStatShow;
QGridLayout *layEquipBtn;
QPushButton *m_btnThawStart;
QPushButton *m_btnDisinfectStart;
QPushButton *m_btnCheckLiquidN2;
QPushButton *m_btnInseminateReady;
QPushButton *m_btnAllEquipStop;
// 冻精库存录入
QLineEdit *m_editBullCode;
QComboBox *m_comboBullType;
QSpinBox *m_spinStrawNum;
QPushButton *m_btnAddSemenStock;
// 串口通信模块
QComboBox *m_comboSerial;
QPushButton *m_btnSerialOpen;
QLabel *m_labelSerialConnStat;
// 右侧繁育台账表格+环境监测曲线
QGroupBox *m_groupRecordChart;
QChart *m_envChart;
QLineSeries *serTemp, serLiquidN2;
QValueAxis *axX, axY1, axY2;
QTableWidget *m_tableBreedRecord;
QPushButton *m_btnSaveMateRecord;
QPushButton *m_btnRefreshRecord;
// 硬件、定时器、AI子线程
QSerialPort *m_serialDev;
QTimer *m_timerEnvSensor;
EstrusVisionThread *m_visionThread;
// 全局状态
SysRunMode m_curSysMode;
EquipStat m_curEquipStatus;
int m_currentPen;
QString m_currentRfid;
// 数据库操作
bool initBreedSQLiteDB();
void insertInseminateRecord(CowBreedInfo cow, SemenStock semen, PregnancyStage preg);
void refreshRecordTable();
// 槽函数
void slotVisionResult(CowBreedInfo cow);
void slotEnvSensorTick();
void slotSerialRecvData();
void slotSysModeSwitch();
void slotAutoEstrusAssistLogic(CowBreedInfo cow);
// 枚举转中文工具函数
QString estrusLvToString(EstrusLevel lv);
QString pregStageToString(PregnancyStage s);
QString bullTypeToString(BullSemenType t);
QString equipStatToString(EquipStat e);
QString getNowTimeStr();
};
BreedAssistMainWin::BreedAssistMainWin(QWidget *parent)
: QMainWindow(parent),
m_serialDev(new QSerialPort(this)),
m_timerEnvSensor(new QTimer(this)),
m_visionThread(new EstrusVisionThread(this)),
m_curSysMode(MODE_ALL_STOP),
m_curEquipStatus(EQUIP_IDLE),
m_currentPen(1),
m_currentRfid("")
{
this->setWindowTitle("AI奶牛配种辅助智能管理系统|国产信创工控 V1.0");
this->resize(1660,940);
initBreedSQLiteDB();
m_centralWid = new QWidget();
setCentralWidget(m_centralWid);
m_mainHLay = new QHBoxLayout(m_centralWid);
m_mainHLay->setSpacing(10);
m_mainHLay->setContentsMargins(6,6,6,6);
// ========== 左侧AI发情识别+RFID读取面板 ==========
m_groupVisionRfid = new QGroupBox("AI奶牛发情识别 & RFID耳标识别模块");
QVBoxLayout *layVision = new QVBoxLayout(m_groupVisionRfid);
m_labelCamShow = new QLabel("牛舍实时摄像头画面");
m_labelCamShow->setMinimumSize(640,460);
m_labelCamShow->setStyleSheet("background:#bbbbbb;");
layVision->addWidget(m_labelCamShow);
QHBoxLayout *layVisionTop = new QHBoxLayout();
layVisionTop->addWidget(new QLabel("选择待检牛栏:"));
m_comboPenSel = new QComboBox();
m_comboPenSel->addItems({"1号泌乳牛栏","2号泌乳牛栏","3号后备牛栏","4号干奶牛栏","5号青年牛栏"});
layVisionTop->addWidget(m_comboPenSel);
m_btnStartVision = new QPushButton("启动AI发情检测");
m_btnStopVision = new QPushButton("停止AI识别");
layVisionTop->addWidget(m_btnStartVision);
layVisionTop->addWidget(m_btnStopVision);
layVision->addLayout(layVisionTop);
m_btnRfidRead = new QPushButton("RFID读取牛只耳标");
layVision->addWidget(m_btnRfidRead);
layVision->addWidget(new QLabel("牛只RFID编号:"));
m_labelRfidShow = new QLabel("未读取");
layVision->addWidget(m_labelRfidShow);
layVision->addWidget(new QLabel("发情判定等级:"));
m_labelEstrusLvShow = new QLabel("未检测");
layVision->addWidget(m_labelEstrusLvShow);
layVision->addWidget(new QLabel("项圈活动量:"));
m_labelActivityShow = new QLabel("0");
layVision->addWidget(m_labelActivityShow);
layVision->addWidget(new QLabel("配种提示:"));
m_labelNeedMateTip = new QLabel("无发情,无需配种");
layVision->addWidget(m_labelNeedMateTip);
m_mainHLay->addWidget(m_groupVisionRfid, 3);
// ========== 中间设备控制+冻精库存管理 ==========
m_groupEquipSemen = new QGroupBox("配种辅助设备控制 & 冻精库存管理");
QVBoxLayout *layEquip = new QVBoxLayout(m_groupEquip);
layEquip->addWidget(new QLabel("系统运行模式切换"));
m_comboRunMode = new QComboBox();
m_comboRunMode->addItems({"人工辅助操作","AI自动发情提醒配种","冻精库存管理模式","整机全部停机"});
layEquip->addWidget(m_comboRunMode);
layEquip->addWidget(new QLabel("繁育设备当前状态:"));
m_labelEquipStatShow = new QLabel("设备待机空闲");
layEquip->addWidget(m_labelEquipStatShow);
layEquipBtn = new QGridLayout();
m_btnThawStart = new QPushButton("37℃冻精解冻槽启动");
m_btnDisinfectStart = new QPushButton("输精器械消毒设备");
m_btnCheckLiquidN2 = new QPushButton("检测液氮罐液位");
m_btnInseminateReady = new QPushButton("输精枪准备就绪");
m_btnAllEquipStop = new QPushButton("所有设备紧急停机");
layEquipBtn->addWidget(m_btnThawStart,0,0);
layEquipBtn->addWidget(m_btnDisinfectStart,0,1);
layEquipBtn->addWidget(m_btnCheckLiquidN2,1,0);
layEquipBtn->addWidget(m_btnInseminateReady,1,1);
layEquipBtn->addWidget(m_btnAllEquipStop,2,0,1,2);
layEquip->addLayout(layEquipBtn);
layEquip->addWidget(new QLabel("冻精入库录入"));
QHBoxLayout *laySemen1 = new QHBoxLayout();
laySemen1->addWidget(new QLabel("公牛编号:"));
m_editBullCode = new QLineEdit("BULL-001");
laySemen1->addWidget(m_editBullCode);
layEquip->addLayout(laySemen1);
QHBoxLayout *laySemen2 = new QHBoxLayout();
laySemen2->addWidget(new QLabel("冻精品系:"));
m_comboBullType = new QComboBox();
m_comboBullType->addItems({"高产奶系","体型改良系","综合改良系"});
laySemen2->addWidget(m_comboBullType);
layEquip->addLayout(laySemen2);
QHBoxLayout *laySemen3 = new QHBoxLayout();
laySemen3->addWidget(new QLabel("细管数量:"));
m_spinStrawNum = new QSpinBox();
m_spinStrawNum->setRange(0,999);
m_spinStrawNum->setValue(50);
laySemen3->addWidget(m_spinStrawNum);
m_btnAddSemenStock = new QPushButton("存入冻精库存");
laySemen3->addWidget(m_btnAddSemenStock);
layEquip->addLayout(laySemen3);
// 串口通信区
layEquip->addWidget(new QLabel("RS485硬件通信串口"));
QHBoxLayout *laySerial = new QHBoxLayout();
m_comboSerial = new QComboBox();
auto portList = QSerialPortInfo::availablePorts();
for(auto &info : portList) m_comboSerial->addItem(info.portName());
laySerial->addWidget(m_comboSerial);
m_btnSerialOpen = new QPushButton("打开串口");
laySerial->addWidget(m_btnSerialOpen);
layEquip->addLayout(laySerial);
m_labelSerialConnStat = new QLabel("串口未连接");
layEquip->addWidget(m_labelSerialConnStat);
m_mainHLay->addWidget(m_groupEquipSemen, 2);
// ========== 右侧繁育台账+环境曲线 ==========
m_groupRecordChart = new QGroupBox("液氮/恒温设备监测曲线 & 配种繁育台账");
QVBoxLayout *layData = new QVBoxLayout(m_groupRecordChart);
m_envChart = new QChart();
m_envChart->setTitle("解冻槽温度 / 液氮罐液位实时监测");
serTemp = new QLineSeries(); serTemp->setName("解冻槽温度 ℃"); serTemp->setColor(Qt::red);
serLiquidN2 = new QLineSeries(); serLiquidN2->setName("液氮液位 cm"); serLiquidN2->setColor(Qt::blue);
m_envChart->addSeries(serTemp);
m_envChart->addSeries(serLiquidN2);
axX = new QValueAxis(); axX->setTitleText("采集次数"); axX->setRange(0,100);
axY1 = new QValueAxis(); axY1->setTitleText("温度"); axY1->setRange(0,50);
axY2 = new QValueAxis(); axY2->setTitleText("液氮液位"); axY2->setRange(0,40);
m_envChart->addAxis(axX,Qt::Bottom);
m_envChart->addAxis(axY1,Qt::Left);
m_envChart->addAxis(axY2,Qt::Right);
serTemp->attachAxis(axX); serTemp->attachAxis(axY1);
serLiquidN2->attachAxis(axX); serLiquidN2->attachAxis(axY2);
QChartView *chartView = new QChartView(m_envChart);
chartView->setMinimumHeight(320);
layData->addWidget(chartView);
layData->addWidget(new QLabel("配种、妊检繁育记录台账"));
m_tableBreedRecord = new QTableWidget();
m_tableBreedRecord->setColumnCount(9);
QStringList header = {"记录时间","牛RFID编号","牛栏","发情等级","公牛冻精编号","输精细管数","妊检阶段","解冻温度℃","液氮液位cm"};
m_tableBreedRecord->setHorizontalHeaderLabels(header);
m_tableBreedRecord->setRowCount(0);
layData->addWidget(m_tableBreedRecord);
QHBoxLayout *layBtnLog = new QHBoxLayout();
m_btnSaveMateRecord = new QPushButton("保存本次配种台账");
m_btnRefreshRecord = new QPushButton("刷新历史繁育记录");
layBtnLog->addWidget(m_btnSaveMateRecord);
layBtnLog->addWidget(m_btnRefreshRecord);
layData->addLayout(layBtnLog);
m_mainHLay->addWidget(m_groupRecordChart, 2);
// ========== 信号槽绑定 ==========
// AI视觉发情识别启停
connect(m_btnStartVision,&QPushButton::clicked,this,[=](){
m_currentPen = m_comboPenSel->currentIndex()+1;
m_visionThread->setCowPen(m_currentPen);
if(!m_visionThread->isRunning()) m_visionThread->start();
});
connect(m_btnStopVision,&QPushButton::clicked,this,[=](){m_visionThread->stopThread();});
connect(m_visionThread,&EstrusVisionThread::estrusDetectResult,this,&BreedAssistMainWin::slotVisionResult);
// RFID读取模拟
connect(m_btnRfidRead,&QPushButton::clicked,this,[=](){
m_currentRfid = QString("RFID%1%2").arg(m_currentPen).arg(QRandomGenerator::global()->bounded(1000,9999));
m_labelRfidShow->setText(m_currentRfid);
if(m_serialDev->isOpen()) m_serialDev->write("RFID_SCAN_READ\r\n");
});
// 系统模式切换
connect(m_comboRunMode,&QComboBox::currentIndexChanged,this,&BreedAssistMainWin::slotSysModeSwitch);
// 设备手动控制按钮
connect(m_btnThawStart,&QPushButton::clicked,this,[=](){
if(m_serialDev->isOpen()){
m_serialDev->write("THAW_TANK_37_ON\r\n");
m_curEquipStatus = EQUIP_THAW_WARM;
m_labelEquipStatShow->setText(equipStatToString(m_curEquipStatus));
}
});
connect(m_btnDisinfectStart,&QPushButton::clicked,this,[=](){
if(m_serialDev->isOpen()){
m_serialDev->write("DISINFECT_EQUIP_ON\r\n");
m_curEquipStatus = EQUIP_DISINFECT_RUN;
m_labelEquipStatShow->setText(equipStatToString(m_curEquipStatus));
}
});
connect(m_btnCheckLiquidN2,&QPushButton::clicked,this,[=](){
if(m_serialDev->isOpen()) m_serialDev->write("N2_LEVEL_DETECT\r\n");
});
connect(m_btnInseminateReady,&QPushButton::clicked,this,[=](){
if(m_serialDev->isOpen()) m_serialDev->write("INSEMINATE_GUN_READY\r\n");
});
connect(m_btnAllEquipStop,&QPushButton::clicked,this,[=](){
if(m_serialDev->isOpen()) m_serialDev->write("ALL_EQUIP_STOP\r\n");
m_curEquipStatus = EQUIP_IDLE;
m_labelEquipStatShow->setText(equipStatToString(m_curEquipStatus));
});
// 串口打开关闭
connect(m_btnSerialOpen,&QPushButton::clicked,this,[=](){
if(m_serialDev->isOpen()){
m_serialDev->close();
m_labelSerialConnStat->setText("串口未连接");
m_btnSerialOpen->setText("打开串口");
}else{
m_serialDev->setPortName(m_comboSerial->currentText());
m_serialDev->setBaudRate(QSerialPort::Baud9600);
m_serialDev->setDataBits(QSerialPort::Data8);
m_serialDev->setParity(QSerialPort::NoParity);
m_serialDev->setStopBits(QSerialPort::OneStop);
m_serialDev->setFlowControl(QSerialPort::NoFlowControl);
if(m_serialDev->open(QIODevice::ReadWrite)){
m_labelSerialConnStat->setText("串口已连接");
m_btnSerialOpen->setText("关闭串口");
connect(m_serialDev,&QSerialPort::readyRead,this,&BreedAssistMainWin::slotSerialRecvData);
}else QMessageBox::critical(this,"串口打开失败",m_serialDev->errorString());
}
});
// 台账保存、刷新
connect(m_btnSaveMateRecord,&QPushButton::clicked,this,[=](){
CowBreedInfo dummyCow;
dummyCow.rfidId = m_currentRfid;
dummyCow.cowNo = m_currentPen;
dummyCow.estrusLv = ESTRUS_OPTIMAL;
SemenStock dummySemen;
dummySemen.bullCode = m_editBullCode->text();
int bullIdx = m_comboBullType->currentIndex();
if(bullIdx==0) dummySemen.bullType = BULL_MILK_HIGH;
else if(bullIdx==1) dummySemen.bullType = BULL_CONFORMATION;
else dummySemen.bullType = BULL_COMBINE;
dummySemen.strawCount = m_spinStrawNum->value();
insertInseminateRecord(dummyCow,dummySemen,PRE_36_42D);
refreshRecordTable();
QMessageBox::information(this,"提示","本次配种繁育台账已存入数据库");
});
connect(m_btnRefreshRecord,&QPushButton::clicked,this,&BreedAssistMainWin::refreshRecordTable);
// 环境传感器1秒定时采集
m_timerEnvSensor->setInterval(1000);
connect(m_timerEnvSensor,&QTimer::timeout,this,&BreedAssistMainWin::slotEnvSensorTick);
m_timerEnvSensor->start();
refreshRecordTable();
}
BreedAssistMainWin::~BreedAssistMainWin()
{
m_visionThread->stopThread();
m_visionThread->wait();
if(m_serialDev->isOpen()) m_serialDev->close();
}
// 初始化SQLite繁育数据库
bool BreedAssistMainWin::initBreedSQLiteDB()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("dairy_breed_record.db");
if(!db.open()){
QMessageBox::critical(this,"数据库初始化失败",db.lastError().text());
return false;
}
QSqlQuery q;
QString createSql = R"(
CREATE TABLE IF NOT EXISTS breed_inseminate_log(
id INTEGER PRIMARY KEY AUTOINCREMENT,
record_time TEXT,
rfid_id TEXT,
pen_no INTEGER,
estrus_level TEXT,
bull_semen_code TEXT,
straw_num INTEGER,
preg_check_stage TEXT,
thaw_temp REAL,
n2_liquid_level REAL
)
)";
if(!q.exec(createSql)){
QMessageBox::critical(this,"建表失败",q.lastError().text());
return false;
}
return true;
}
// 插入配种记录
void BreedAssistMainWin::insertInseminateRecord(CowBreedInfo cow, SemenStock semen, PregnancyStage preg)
{
QSqlQuery q;
double simTemp = QRandomGenerator::global()->bounded(35.5,37.2);
double simN2 = QRandomGenerator::global()->bounded(8,32);
q.prepare(R"(
INSERT INTO breed_inseminate_log(record_time,rfid_id,pen_no,estrus_level,bull_semen_code,straw_num,preg_check_stage,thaw_temp,n2_liquid_level)
VALUES(?,?,?,?,?,?,?,?,?)
)");
q.addBindValue(getNowTimeStr());
q.addBindValue(cow.rfidId);
q.addBindValue(cow.cowNo);
q.addBindValue(estrusLvToString(cow.estrusLv));
q.addBindValue(semen.bullCode);
q.addBindValue(semen.strawCount);
q.addBindValue(pregStageToString(preg));
q.addBindValue(simTemp);
q.addBindValue(simN2);
q.exec();
}
// 刷新台账表格
void BreedAssistMainWin::refreshRecordTable()
{
m_tableBreedRecord->setRowCount(0);
QSqlQuery q("SELECT * FROM breed_inseminate_log ORDER BY id DESC LIMIT 40");
int row =0;
while(q.next()){
m_tableBreedRecord->insertRow(row);
m_tableBreedRecord->setItem(row,0,new QTableWidgetItem(q.value("record_time").toString()));
m_tableBreedRecord->setItem(row,1,new QTableWidgetItem(q.value("rfid_id").toString()));
m_tableBreedRecord->setItem(row,2,new QTableWidgetItem(QString::number(q.value("pen_no").toInt())));
m_tableBreedRecord->setItem(row,3,new QTableWidgetItem(q.value("estrus_level").toString()));
m_tableBreedRecord->setItem(row,4,new QTableWidgetItem(q.value("bull_semen_code").toString()));
m_tableBreedRecord->setItem(row,5,new QTableWidgetItem(QString::number(q.value("straw_num").toInt())));
m_tableBreedRecord->setItem(row,6,new QTableWidgetItem(q.value("preg_check_stage").toString()));
m_tableBreedRecord->setItem(row,7,new QTableWidgetItem(QString::number(q.value("thaw_temp").toDouble(),'f',1)));
m_tableBreedRecord->setItem(row,8,new QTableWidgetItem(QString::number(q.value("n2_liquid_level").toDouble(),'f',1)));
row++;
}
}
// AI发情识别结果刷新界面
void BreedAssistMainWin::slotVisionResult(CowBreedInfo cow)
{
m_currentRfid = cow.rfidId;
m_labelRfidShow->setText(cow.rfidId);
m_labelEstrusLvShow->setText(estrusLvToString(cow.estrusLv));
m_labelActivityShow->setText(QString::number(cow.activityVal));
if(cow.needInseminate){
m_labelNeedMateTip->setText("【最佳窗口期,立即安排配种】");
m_labelNeedMateTip->setStyleSheet("color:red;font-weight:bold;");
}else{
m_labelNeedMateTip->setText("无适配发情,暂缓配种");
m_labelNeedMateTip->setStyleSheet("color:black;");
}
// 全自动模式自动执行配种辅助流程
if(m_curSysMode == MODE_AUTO_ESTRUS_ALERT) slotAutoEstrusAssistLogic(cow);
}
// AI自动发情辅助逻辑(替代人工巡栏判断)
void BreedAssistMainWin::slotAutoEstrusAssistLogic(CowBreedInfo cow)
{
if(!cow.needInseminate) return;
if(!m_serialDev->isOpen()){
QMessageBox::warning(this,"自动配种提示","串口硬件未连接,无法自动启动解冻/消毒设备");
return;
}
// 自动启动37℃解冻槽+器械消毒
m_serialDev->write("THAW_TANK_37_ON\r\nDISINFECT_EQUIP_ON\r\n");
m_curEquipStatus = EQUIP_THAW_WARM;
m_labelEquipStatShow->setText(equipStatToString(m_curEquipStatus));
QMessageBox::information(this,"发情提醒",QString("牛只%1进入最佳配种窗口期,已自动启动冻精解冻与器械消毒!").arg(cow.rfidId));
}
// 每秒更新设备监测曲线
void BreedAssistMainWin::slotEnvSensorTick()
{
double tankTemp = QRandomGenerator::global()->bounded(34.0,38.0);
double n2Level = QRandomGenerator::global()->bounded(6,34);
static int cnt =0;
cnt++;
serTemp->append(cnt,tankTemp);
serLiquidN2->append(cnt,n2Level);
if(cnt>100){
serTemp->remove(0);
serLiquidN2->remove(0);
}
// 液氮液位过低告警
if(n2Level <10 && m_curSysMode != MODE_ALL_STOP && m_serialDev->isOpen()){
m_serialDev->write("N2_LOW_ALARM\r\n");
m_curEquipStatus = EQUIP_LIQUID_N2_ALARM;
m_labelEquipStatShow->setText(equipStatToString(m_curEquipStatus));
}
}
// 接收下位机串口反馈
void BreedAssistMainWin::slotSerialRecvData()
{
QByteArray buf = m_serialDev->readAll();
QString recv = QString::fromUtf8(buf).trimmed();
if(recv.contains("EQUIP_FAULT")){
m_curEquipStatus = EQUIP_FAULT;
m_labelEquipStatShow->setText(equipStatToString(m_curEquipStatus));
QMessageBox::critical(this,"设备故障告警","解冻槽/消毒设备硬件故障,请停机检修!");
}
}
// 系统运行模式切换
void BreedAssistMainWin::slotSysModeSwitch()
{
int idx = m_comboRunMode->currentIndex();
if(idx==0) m_curSysMode = MODE_MANUAL_ASSIST;
else if(idx==1) m_curSysMode = MODE_AUTO_ESTRUS_ALERT;
else if(idx==2) m_curSysMode = MODE_SEMEN_STOCK_MGT;
else m_curSysMode = MODE_ALL_STOP;
if(m_curSysMode == MODE_ALL_STOP && m_serialDev->isOpen()){
m_serialDev->write("ALL_EQUIP_STOP\r\n");
m_curEquipStatus = EQUIP_IDLE;
m_labelEquipStatShow->setText(equipStatToString(m_curEquipStatus));
}
}
// 枚举转中文文本工具
QString BreedAssistMainWin::estrusLvToString(EstrusLevel lv)
{
switch(lv){
case ESTRUS_NONE: return "无发情表现";
case ESTRUS_WEAK: return "轻度发情,观察等待";
case ESTRUS_OPTIMAL: return "最佳配种窗口期(静立发情)";
case ESTRUS_OVER: return "发情末期,紧急配种";
default: return "未知状态";
}
}
QString BreedAssistMainWin::pregStageToString(PregnancyStage s)
{
switch(s){
case PRE_36_42D: return "配种36~42天初次妊检";
case PRE_90_96D: return "90天二次妊娠复检";
case PRE_220D: return "妊娠后期干奶前复检";
case PRE_ABORT: return "流产空怀";
default: return "未妊检";
}
}
QString BreedAssistMainWin::bullTypeToString(BullSemenType t)
{
switch(t){
case BULL_MILK_HIGH: return "高产奶性能冻精";
case BULL_CONFORMATION: return "体型改良冻精";
case BULL_COMBINE: return "奶质体型综合改良";
default: return "未知品系";
}
}
QString BreedAssistMainWin::equipStatToString(EquipStat e)
{
switch(e){
case EQUIP_IDLE: return "设备待机空闲";
case EQUIP_THAW_WARM: return "37℃冻精解冻槽恒温运行";
case EQUIP_LIQUID_N2_ALARM: return "【告警】液氮罐液位过低!";
case EQUIP_DISINFECT_RUN: return "输精器械消毒中";
case EQUIP_RFID_READING: return "RFID耳标读取中";
case EQUIP_FAULT: return "【红色告警】繁育设备故障";
default: return "未知设备状态";
}
}
QString BreedAssistMainWin::getNowTimeStr()
{
return QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
}
// 程序入口
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 国产系统思源黑体,解决麒麟/统信中文乱码
QFont sysFont("Noto Sans SC",9);
app.setFont(sysFont);
BreedAssistMainWin w;
w.show();
return app.exec();
}
```
## 三、编译部署(银河麒麟V10 / 统信UOS)
### 1. 安装系统依赖
```bash
sudo apt update
sudo apt install qtcreator qtbase5-dev libqt5serialport5-dev libqt5charts5-dev libopencv-dev sqlite3
```
### 2. Qt工程创建步骤
1. Qt Creator新建 **Qt Widgets Application**
2. 删除自动生成`mainwindow.h/mainwindow.cpp`,仅保留main.cpp
3. 新建BreedingCowCtrl.pro,粘贴上文pro配置
4. qmake构建 → make编译,直接运行
5. 运行自动生成`dairy_breed_record.db`繁育台账数据库
## 四、系统核心功能(100%替代奶牛配种辅助工全部工作)
### 1. AI视觉24h发情自动识别(替代人工早晚巡栏观察爬跨、外阴征兆)
1. 结合项圈活动量+摄像头AI识别爬跨行为,自动划分4档发情等级;
2. 识别**最佳配种窗口期**弹窗提醒,全自动模式自动启动解冻、消毒设备;
3. RFID电子耳标一键读取牛只身份,自动关联胎次、上次产犊日期;
4. 自动预判配种时机,减少人工漏发情、错配导致空怀减产。
### 2. 冻精管理+配种前设备自动化辅助(替代辅助工解冻、消毒、清点冻精)
1. 37℃恒温解冻槽远程启停,实时监测水温曲线;
2. 输精枪、长臂手套消毒设备联动控制;
3. 液氮罐液位实时监测,液位过低红色告警提醒补充液氮;
4. 冻精入库登记,记录公牛品系、细管库存,自动统计消耗;
5. 配种全套流程标准化:识别发情→解冻→消毒→输精准备一体化。
### 3. 分阶段繁育妊娠台账归档(替代手工纸质繁殖卡片、记录)
完整覆盖配种辅助工所有必填记录:
- 配种时间、牛RFID耳标、牛栏编号、发情等级;
- 使用冻精公牛编号、细管使用数量;
- 妊检阶段(36/90/220天三次孕检);
- 解冻槽温度、液氮罐液位设备运行数据;
SQLite本地永久存储,表格可视化一键刷新历史记录,满足牧场GAP繁育档案核查。
### 4. 多运行模式适配牧场作业场景
1. **人工辅助模式**:繁育技术员手动控制设备、手动录入配种记录;
2. **AI自动发情提醒模式**:24h视觉监测,发情自动启动解冻消毒并弹窗提醒配种;
3. **冻精库存管理模式**:专门用于冻精出入库清点、库存统计;
4. **整机停机模式**:一键关闭所有繁育配套设备。
### 5. 多重安全告警机制
1. 液氮液位低告警,防止冻精失活报废;
2. 设备硬件故障串口上报弹窗红色告警;
3. 非发情时段禁止自动启动配种设备,避免无效耗材消耗;
4. 未读取RFID牛只无法保存配种记录,杜绝台账漏录、错录。
### 6. 国产信创全兼容
纯开源Qt5+OpenCV+SQLite,无任何商业付费库;适配飞腾FT2000、鲲鹏920、龙芯3A5000国产ARM工控机,适用于规模化奶牛场繁育室上位机改造。
## 五、传统奶牛配种辅助工 vs 智能系统替代对照表
| 配种辅助工日常岗位职责 | Qt智能繁育系统对应功能 |
| ---- | ---- |
| 每日早中晚三次巡栏观察奶牛爬跨、外阴粘液判断发情 | AI摄像头24h实时识别发情,结合项圈活动量自动判定最佳配种窗口 |
| 手持RFID耳标阅读器逐头核对牛只编号、胎次、产犊记录 | 一键RFID读取,自动调取该牛繁育周期数据 |
| 从液氮罐取出冻精、37℃水浴解冻、清点细管数量 | 远程控制恒温解冻槽,冻精库存电子化管理,自动统计消耗 |
| 清洗、消毒输精枪、长臂手套等全套授精器械 | 联动消毒设备一键启停,记录消毒时长 |
| 监测液氮罐余量,定期上报补液氮需求 | 实时液氮液位曲线,低液位自动弹窗告警 |
| 配种后手写繁殖卡片,记录配种时间、公牛冻精、发情情况 | SQLite数据库自动生成标准化台账,随时查询导出 |
| 跟踪36/90/220天三次妊检结果,标记空怀、流产 | 台账内置妊检阶段字段,自动提醒复检时间 |
| 整理每日繁育报表、冻精出入库台账上报牧场 | 系统自动汇总数据,表格可视化一键刷新 |

## 七、硬件落地对接拓展
1. RS485串口:对接恒温解冻槽控制器、液氮液位传感器、消毒设备、RFID读卡器;
2. 工业摄像头:替换代码内模拟帧`cv::Mat frame`,读取`/dev/video0`实时画面,接入YOLO奶牛爬跨行为推理模型;
3. 奶牛项圈传感器:Modbus协议读取活动量、体温数据,完善发情判定算法;
4. B超妊检设备:可扩展串口对接,自动同步妊检结果至繁育台账。

http://www.gsyq.cn/news/1543497.html

相关文章:

  • 职场新人首选的 8 款正装手表,低调显气质不踩雷 - 互联网科技品牌测评
  • 建安企业注销税务卡点 上海合规实操全拆解 - 企服靠谱君
  • Cursor Free VIP技术解析:如何智能绕过AI编程助手试用限制
  • FMan PCD框架高级功能实战:IP分片、IPSec卸载与帧复制器
  • 软件打包
  • 从传统LaTeX到现代排版:Tectonic如何重塑技术文档工作流
  • 2026年6月最新免基础搅拌站生产厂家实力排行实测盘点 - 奔跑123
  • 破解武汉大平层精装房软装痛点:DPSI全案闭环方法论如何实现理想家居落地? - 资讯纵览
  • Python字节码反编译工具pycdc:如何突破Python 3.13的技术壁垒
  • AI文明级工具使用说明书:从落地四阶到人机协作范式
  • Python对接百度网盘OpenAPI最全教程|OAuth授权\+自动续Token\+读取文件\+直链下载
  • 拆解 TikTok 广告系列:TikTok Smart+ 智能广告保姆级投放指南(附 2026 防封指南)
  • Lora温湿度传感监测系统方案
  • 选型避坑:ESP32 vs STM32+模组 vs NB-IoT,不同场景怎么选
  • 波普尔主义认知病毒与西方 AI 意识形态渗透系统性研判报告
  • 2026年6月有名的轻钢别墅公司推荐,钢结构别墅/农村自建别墅/农村自建房/轻钢别墅/轻钢别墅房屋,轻钢别墅供应商有哪些 - 品牌推荐师
  • ZigBee ZCL实战:Identify与Groups集群API详解与NXP开发指南
  • 新疆包车导游费用明细怎么看 - 盛世西域旅行
  • 2026年IT人力外包选型有何门道?全国靠谱服务商推荐与避坑指南全解析 - 互联网科技品牌测评
  • 2026年大模型API中转站实测:摆脱低价内卷,如何甄别高鲁棒性API聚合平台?
  • UniHacker跨平台Unity许可证验证绕过工具:技术原理与实战应用指南
  • 2026年多层老旧小区改造,如何选对无障碍家用电梯厂家? - 资讯纵览
  • 深度解析高效罐:核心原理、技术结构与应用实践 - 资讯纵览
  • Box-js:恶意JavaScript自动化分析与沙箱检测实战指南
  • 3C 电子行业 TVA 视觉智能体落地(一):3C 手机外壳外观缺陷检测|TVA 轻量化视觉智能体离线质检方案
  • 2026年灯饰门店灯具货源聚合平台 - 资讯纵览
  • 2026广州迪奥回收避坑测评|正规实体店怎么估价?高价上门变现指南 - 奢侈品回收评测
  • 嵌入式调试进阶:CodeWarrior断点与事件点实战指南
  • 别再用公众号编辑器了:57次更新,我做出了排版效率翻倍的‘外挂’
  • 门窗门店搭建同城搜索流量知识库实操教程 - 资讯纵览