fix:协议汇总结果上报bug修复
tcp汇总信息只保留最大的5个撕裂信息
This commit is contained in:
parent
d75e739615
commit
e43ddc15c3
@ -60,9 +60,9 @@ isEmpty(TARGET_APP) {
|
||||
} else:equals(TARGET_APP, "StatorPosition") {
|
||||
SUBDIRS += StatorPosition/StatorPosition.pro
|
||||
} else:equals(TARGET_APP, "WorkpieceTapered") {
|
||||
SUBDIRS += StatorWorkpiecePosition/WorkpieceTapered.pro
|
||||
SUBDIRS += StatorWorkpiecePosition/StatorWorkpiecePosition.pro
|
||||
} else:equals(TARGET_APP, "WorkpieceRotor") {
|
||||
SUBDIRS += StatorWorkpiecePosition/WorkpieceRotor.pro
|
||||
SUBDIRS += StatorWorkpiecePosition/StatorWorkpiecePosition.pro
|
||||
} else:equals(TARGET_APP, "HoleDetection") {
|
||||
SUBDIRS += HoleDetection/HoleDetection.pro
|
||||
} else:equals(TARGET_APP, "HolePitPosition") {
|
||||
|
||||
@ -376,7 +376,7 @@ void BeltTearingPresenter::sendSimulationData()
|
||||
SendDetectionResultToRobot(alarmResults);
|
||||
|
||||
if (m_tearingProtocol) {
|
||||
m_tearingProtocol->sendDetectResult(alarmResults, QImage());
|
||||
m_tearingProtocol->sendDetectResult(filteredResults, QImage(), !alarmResults.empty());
|
||||
m_tearingProtocol->sendRealtimeResult(filteredResults, QImage());
|
||||
}
|
||||
}
|
||||
@ -1896,7 +1896,7 @@ int BeltTearingPresenter::_DetectTask()
|
||||
|
||||
// 使用TearingTcpProtocol发送DETECT_RESULT消息(新协议)
|
||||
if (m_tearingProtocol) {
|
||||
m_tearingProtocol->sendDetectResult(alarmTearings, image);
|
||||
m_tearingProtocol->sendDetectResult(filteredTearings, image, !alarmTearings.empty());
|
||||
}
|
||||
|
||||
// 发送实时检测结果(新协议)
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include "Version.h"
|
||||
#include <QDataStream>
|
||||
#include <QJsonArray>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
TearingTcpProtocol::TearingTcpProtocol(QObject *parent)
|
||||
@ -16,6 +17,7 @@ TearingTcpProtocol::TearingTcpProtocol(QObject *parent)
|
||||
, m_historyMaxLength(0)
|
||||
, m_historyMaxId(0)
|
||||
, m_historyMaxWidth(0)
|
||||
, m_hasLastDetectResult(false)
|
||||
{
|
||||
// 连接心跳定时器
|
||||
connect(m_heartbeatTimer, &QTimer::timeout, this, &TearingTcpProtocol::onHeartbeatTimeout);
|
||||
@ -97,18 +99,20 @@ void TearingTcpProtocol::stop()
|
||||
LOG_INFO("TearingTcpProtocol stopped\n");
|
||||
}
|
||||
|
||||
void TearingTcpProtocol::sendDetectResult(const std::vector<SSG_beltTearingInfo>& results, const QImage& visImage)
|
||||
void TearingTcpProtocol::sendDetectResult(const std::vector<SSG_beltTearingInfo>& results,
|
||||
const QImage& visImage, bool alarm)
|
||||
{
|
||||
if (!m_tcpServer) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> sendLock(m_detectSendMutex);
|
||||
|
||||
// 计算撕裂个数和本次检测的最大撕裂长度
|
||||
int count = static_cast<int>(results.size());
|
||||
int currentMaxLength = 0;
|
||||
int currentMaxId = 0;
|
||||
int currentMaxWidth = 0;
|
||||
QJsonArray tearsArray;
|
||||
std::vector<QJsonObject> currentTearObjects;
|
||||
currentTearObjects.reserve(results.size());
|
||||
|
||||
for (const auto& result : results) {
|
||||
int tearLength = static_cast<int>(std::round(std::abs(result.roi.right - result.roi.left)));
|
||||
@ -125,12 +129,13 @@ void TearingTcpProtocol::sendDetectResult(const std::vector<SSG_beltTearingInfo>
|
||||
tearObj["length"] = tearLength;
|
||||
tearObj["width"] = tearWidth;
|
||||
tearObj["depth"] = result.tearDepth;
|
||||
tearsArray.append(tearObj);
|
||||
currentTearObjects.push_back(tearObj);
|
||||
}
|
||||
|
||||
int historyMaxLength = 0;
|
||||
int historyMaxId = 0;
|
||||
int historyMaxWidth = 0;
|
||||
QJsonArray tearsArray;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_historyMutex);
|
||||
// 更新历史最大值(从开流开始的最大值)
|
||||
@ -142,6 +147,55 @@ void TearingTcpProtocol::sendDetectResult(const std::vector<SSG_beltTearingInfo>
|
||||
historyMaxLength = m_historyMaxLength;
|
||||
historyMaxId = m_historyMaxId;
|
||||
historyMaxWidth = m_historyMaxWidth;
|
||||
|
||||
for (const auto& tearObj : currentTearObjects) {
|
||||
m_historyTears[tearObj.value("id").toInt()] = tearObj;
|
||||
}
|
||||
std::vector<QJsonObject> historyTearObjects;
|
||||
historyTearObjects.reserve(m_historyTears.size());
|
||||
for (auto it = m_historyTears.cbegin(); it != m_historyTears.cend(); ++it) {
|
||||
historyTearObjects.push_back(it.value());
|
||||
}
|
||||
std::sort(historyTearObjects.begin(), historyTearObjects.end(), [](const QJsonObject& lhs, const QJsonObject& rhs) {
|
||||
const int lhsLength = lhs.value("length").toInt();
|
||||
const int rhsLength = rhs.value("length").toInt();
|
||||
if (lhsLength != rhsLength) {
|
||||
return lhsLength > rhsLength;
|
||||
}
|
||||
return lhs.value("id").toInt() < rhs.value("id").toInt();
|
||||
});
|
||||
if (historyTearObjects.size() > 5) {
|
||||
historyTearObjects.resize(5);
|
||||
}
|
||||
m_historyTears.clear();
|
||||
for (const auto& tearObj : historyTearObjects) {
|
||||
m_historyTears.insert(tearObj.value("id").toInt(), tearObj);
|
||||
tearsArray.append(tearObj);
|
||||
}
|
||||
}
|
||||
|
||||
const int count = tearsArray.size();
|
||||
|
||||
// Timestamp and image are deliberately excluded: only tearing information
|
||||
// and the accumulated maximum values trigger a DETECT_RESULT report.
|
||||
QJsonObject signatureObj;
|
||||
signatureObj["count"] = count;
|
||||
signatureObj["maxLength"] = historyMaxLength;
|
||||
signatureObj["maxWidth"] = historyMaxWidth;
|
||||
signatureObj["maxId"] = historyMaxId;
|
||||
signatureObj["tears"] = tearsArray;
|
||||
const QByteArray signature = QJsonDocument(signatureObj).toJson(QJsonDocument::Compact);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_historyMutex);
|
||||
const bool hasCurrentInfo = count > 0 || historyMaxLength > 0 ||
|
||||
historyMaxWidth > 0 || historyMaxId > 0;
|
||||
if (!hasCurrentInfo && !m_hasLastDetectResult) {
|
||||
return;
|
||||
}
|
||||
if (m_hasLastDetectResult && signature == m_lastDetectSignature) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 构造JSON消息(使用历史最大值)
|
||||
@ -149,7 +203,7 @@ void TearingTcpProtocol::sendDetectResult(const std::vector<SSG_beltTearingInfo>
|
||||
addProtocolVersion(jsonObj);
|
||||
jsonObj["msgType"] = "DETECT_RESULT";
|
||||
jsonObj["timestamp"] = QDateTime::currentMSecsSinceEpoch();
|
||||
jsonObj["alarm"] = count > 0;
|
||||
jsonObj["alarm"] = alarm;
|
||||
jsonObj["count"] = count;
|
||||
jsonObj["max"] = historyMaxLength; // 保留1.4版本字段
|
||||
jsonObj["maxLength"] = historyMaxLength;
|
||||
@ -171,10 +225,13 @@ void TearingTcpProtocol::sendDetectResult(const std::vector<SSG_beltTearingInfo>
|
||||
// 构造数据帧
|
||||
QByteArray frame = buildFrame(jsonData);
|
||||
|
||||
// DETECT_RESULT is the baseline result stream and is always broadcast to
|
||||
// every connected client, independent of SET_REALTIME.
|
||||
// DETECT_RESULT is the baseline result stream and is broadcast to every
|
||||
// connected client when its tearing summary changes, independent of SET_REALTIME.
|
||||
bool success = m_tcpServer->SendAllData(frame.constData(), frame.size());
|
||||
if (success) {
|
||||
std::lock_guard<std::mutex> lock(m_historyMutex);
|
||||
m_lastDetectSignature = signature;
|
||||
m_hasLastDetectResult = true;
|
||||
LOG_DEBUG("Sent DETECT_RESULT to all clients, count=%d, historyMax=%d, historyMaxId=%d\n",
|
||||
count, historyMaxLength, historyMaxId);
|
||||
} else {
|
||||
@ -360,6 +417,9 @@ void TearingTcpProtocol::clearHistoryMaxData()
|
||||
m_historyMaxLength = 0;
|
||||
m_historyMaxId = 0;
|
||||
m_historyMaxWidth = 0;
|
||||
m_historyTears.clear();
|
||||
m_lastDetectSignature.clear();
|
||||
m_hasLastDetectResult = false;
|
||||
}
|
||||
LOG_INFO("Cleared history max data (开流清除)\n");
|
||||
}
|
||||
|
||||
@ -94,7 +94,8 @@ public:
|
||||
* @param visImage 可视化图像
|
||||
* @note 发送的JSON消息包含:count(撕裂个数)、max(最大撕裂长度)、maxId(最大撕裂ID)、visimg(Base64图像)
|
||||
*/
|
||||
void sendDetectResult(const std::vector<SSG_beltTearingInfo>& results, const QImage& visImage);
|
||||
void sendDetectResult(const std::vector<SSG_beltTearingInfo>& results,
|
||||
const QImage& visImage, bool alarm = true);
|
||||
|
||||
/**
|
||||
* @brief 发送实时检测结果
|
||||
@ -293,6 +294,10 @@ private:
|
||||
int m_historyMaxLength; // 历史最大撕裂长度
|
||||
int m_historyMaxId; // 历史最大撕裂对应的ID
|
||||
int m_historyMaxWidth; // 历史最大撕裂对应的宽度
|
||||
mutable std::mutex m_detectSendMutex;
|
||||
QMap<int, QJsonObject> m_historyTears;
|
||||
QByteArray m_lastDetectSignature;
|
||||
bool m_hasLastDetectResult;
|
||||
};
|
||||
|
||||
#endif // TEARINGTCPPROTOCOL_H
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
|
||||
#define BELTTEARING_VERSION_STRING "2.1.0"
|
||||
#define BELTTEARING_VERSION_STRING "2.1.1"
|
||||
#define BELTTEARING_VERSION_BUILD "1"
|
||||
#define BELTTEARING_PRODUCT_NAME "BeltTearingServer"
|
||||
#define BELTTEARING_COMPANY_NAME "VisionRobot"
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
# 2.1.1
|
||||
## build_1 2026-08-27
|
||||
1. 协议汇总结果上报bug修复
|
||||
|
||||
# 2.1.0
|
||||
## build_1 2026-08-10
|
||||
1.
|
||||
1. 协议修改
|
||||
2. 生成图像使用伪彩
|
||||
|
||||
# 2.0.9
|
||||
## build_1 2026-07-27
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
| 版本 | 日期 | 修改内容 |
|
||||
|------|------------|------------------|
|
||||
| 1.6 | 2026-08-10 | 增加激光线点云二进制实时发送,以及可配置的抽线、抽点功能;<br/>算法和成像仍使用完整点云;<br/>DETECT_RESULT 始终广播,REALTIME_RESULT 由 SET_REALTIME 单独开启 |
|
||||
| 1.6 | 2026-08-10 | 增加激光线点云二进制实时发送,以及可配置的抽线、抽点功能;<br/>算法和成像仍使用完整点云;<br/>DETECT_RESULT 始终开启但仅在历史汇总变化时广播,REALTIME_RESULT 由 SET_REALTIME 单独开启 |
|
||||
| 1.5 | 2026-08-05 | 增加协议版本字段、完整报警数据、报警复位、重新检测、配置读写和协议能力查询;保留1.4字段兼容旧客户端 |
|
||||
| 1.4 | 2026-02-21 | 增加CMD汇总表格(实时消息关系以1.6定义为准) |
|
||||
| 1.3 | 2026-02-12 | 增加实时传输检测结果功能(SET_REALTIME/REALTIME_RESULT) |
|
||||
@ -43,7 +43,7 @@
|
||||
|
||||
| msgType | 方向 | 说明 | 详细章节 |
|
||||
|---------|------|------|----------|
|
||||
| `DETECT_RESULT` | 服务器 → 客户端 | 基础撕裂检测结果上报(历史最大值),始终发送给所有客户端 | 4.1 |
|
||||
| `DETECT_RESULT` | 服务器 → 客户端 | 基础撕裂检测结果上报(历史最大值),结果发生变化时发送给所有客户端 | 4.1 |
|
||||
| `REALTIME_RESULT` | 服务器 → 客户端 | 实时检测结果上报(所有撕裂详细数据),<br/>仅发送给**已开启**实时传输的客户端 | 4.2 |
|
||||
| `SET_SPEED` | 客户端 → 服务器 | 设置皮带速度(mm/s) | 5.1 |
|
||||
| `SET_CONTROL` | 客户端 → 服务器 | 启动/停止检测 | 5.2 |
|
||||
@ -117,7 +117,7 @@
|
||||
|
||||
**消息类型**: `DETECT_RESULT`
|
||||
|
||||
服务器始终向所有已连接客户端发送本消息,不受 `SET_REALTIME` 状态影响;无撕裂时 `count` 为0且 `tears` 为空数组。
|
||||
服务器始终开启本消息上报逻辑,向所有已连接客户端发送;不受 `SET_REALTIME` 状态影响。仅当当前汇总中的撕裂信息或历史最大值发生变化时发送,重复结果不连续发送;无撕裂时 `count` 为0且 `tears` 为空数组。
|
||||
**JSON格式**:
|
||||
```json
|
||||
{
|
||||
@ -144,13 +144,13 @@
|
||||
| msgType | string | 是 | 固定值 `DETECT_RESULT` |
|
||||
| timestamp | int64 | 是 | 检测时间戳(毫秒) |
|
||||
| protocolVersion | string | 是 | 当前协议版本 `1.6` |
|
||||
| alarm | bool | 是 | 本次消息是否包含未确认报警 |
|
||||
| alarm | bool | 是 | 本次检测是否存在尚未被 `RESET_ALARM` 确认的撕裂 |
|
||||
| count | int | 是 | 撕裂个数 |
|
||||
| max | int | 是 | 历史最大X方向长度,兼容1.4客户端 |
|
||||
| maxLength | int | 是 | 历史最大X方向长度(毫米) |
|
||||
| maxWidth | int | 是 | 历史最大长度对应撕裂的Y方向宽度(毫米) |
|
||||
| maxId | int | 是 | 最大撕裂对应的撕裂ID(唯一标识符) |
|
||||
| tears | array | 是 | 当前未确认的完整撕裂列表,字段同4.2 |
|
||||
| tears | array | 是 | 从本次开流或最近一次 `RESET_ALARM` 起累计的撕裂结果;最多保留长度最大的5条,字段同4.2 |
|
||||
| visimg | string | 是 | Base64编码的检测结果图片(JPEG格式) |
|
||||
|
||||
**示例**:
|
||||
@ -230,7 +230,7 @@
|
||||
- 实时传输功能需要客户端通过 `SET_REALTIME` 命令开启
|
||||
- 开启后,服务器每次完成一帧检测即上报一次结果
|
||||
- 关闭实时传输后,服务器停止上报 `REALTIME_RESULT` 消息
|
||||
- `DETECT_RESULT` 始终发送;开启实时传输的客户端会在此基础上额外收到 `REALTIME_RESULT`
|
||||
- `DETECT_RESULT` 始终开启上报逻辑,但仅在撕裂信息或汇总值变化时发送;开启实时传输的客户端会在此基础上额外收到 `REALTIME_RESULT`
|
||||
- 当 count 为 0 时,tears 为空数组 `[]`
|
||||
|
||||
**示例**(无撕裂时):
|
||||
@ -523,6 +523,8 @@
|
||||
|
||||
### 10.1 报警复位与重新检测
|
||||
|
||||
`RESET_ALARM` 的“确认”由服务端执行:客户端发送命令后,服务端将当时仍存在的撕裂 ID 加入已确认集合,并据此抑制后续同 ID 的报警状态;该 ID 消失后再次出现,才可重新报警。
|
||||
|
||||
```json
|
||||
{"msgType":"RESET_ALARM","protocolVersion":"1.6","timestamp":1699776000000}
|
||||
```
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user