352 lines
11 KiB
C++
Raw Normal View History

2025-12-10 00:01:32 +08:00
#include "VrError.h"
#include "WorkpiecePositionPresenter.h"
#include "VrLog.h"
#include <QDebug>
#include <QDateTime>
WorkpiecePositionPresenter::WorkpiecePositionPresenter(QObject *parent)
2025-12-27 09:34:02 +08:00
: BasePresenter(parent)
, m_pMarkReconnectTimer(new QTimer(this))
, m_pEpicEyeReconnectTimer(new QTimer(this))
2025-12-10 00:01:32 +08:00
{
connect(m_pMarkReconnectTimer, &QTimer::timeout, this, &WorkpiecePositionPresenter::onMarkReconnectTimeout);
connect(m_pEpicEyeReconnectTimer, &QTimer::timeout, this, &WorkpiecePositionPresenter::onEpicEyeReconnectTimeout);
}
WorkpiecePositionPresenter::~WorkpiecePositionPresenter()
{
2025-12-27 09:34:02 +08:00
// 停止定时器
2025-12-10 00:01:32 +08:00
if (m_pMarkReconnectTimer) m_pMarkReconnectTimer->stop();
if (m_pEpicEyeReconnectTimer) m_pEpicEyeReconnectTimer->stop();
2025-12-27 09:34:02 +08:00
// 等待异步检测任务完成,防止访问已销毁的成员
if (m_detectionFuture && m_detectionFuture->valid()) {
LOG_DEBUG("等待检测任务完成...\n");
m_detectionFuture->wait();
LOG_DEBUG("检测任务已完成\n");
}
// 释放设备资源
2025-12-10 00:01:32 +08:00
if (m_pMarkReceiver) { m_pMarkReceiver->Disconnect(); delete m_pMarkReceiver; }
if (m_pEpicEyeDevice) { m_pEpicEyeDevice->Disconnect(); delete m_pEpicEyeDevice; }
if (m_pConfig) delete m_pConfig;
}
2025-12-27 09:34:02 +08:00
// ============ 实现 BasePresenter 纯虚函数 ============
int WorkpiecePositionPresenter::InitApp()
2025-12-10 00:01:32 +08:00
{
2025-12-27 09:34:02 +08:00
LOG_INFO("WorkpiecePositionPresenter InitApp\n");
2025-12-10 00:01:32 +08:00
int ret = InitConfig();
2025-12-27 09:34:02 +08:00
if (ret != SUCCESS) {
LOG_ERR("初始化配置失败: %d\n", ret);
return ret;
}
2025-12-10 00:01:32 +08:00
ret = InitBinocularMarkReceiver();
2025-12-27 09:34:02 +08:00
if (ret != SUCCESS) {
LOG_ERR("初始化BinocularMarkReceiver失败: %d\n", ret);
m_pMarkReconnectTimer->start(5000);
}
2025-12-10 00:01:32 +08:00
ret = InitEpicEyeDevice();
2025-12-27 09:34:02 +08:00
if (ret != SUCCESS) {
LOG_ERR("初始化EpicEyeDevice失败: %d\n", ret);
m_pEpicEyeReconnectTimer->start(5000);
}
LOG_INFO("WorkpiecePositionPresenter InitApp完成\n");
return SUCCESS;
}
int WorkpiecePositionPresenter::InitAlgoParams()
{
// 工件定位不需要额外的算法参数初始化
return SUCCESS;
}
2025-12-10 00:01:32 +08:00
2025-12-27 09:34:02 +08:00
int WorkpiecePositionPresenter::ProcessAlgoDetection(std::vector<std::pair<EVzResultDataType, SVzLaserLineData>>& detectionDataCache)
{
// 工件定位使用自己的检测流程不使用BasePresenter的激光数据检测
// 此方法不会被调用,因为我们重写了 StartDetection
2025-12-10 00:01:32 +08:00
return SUCCESS;
}
2025-12-27 09:34:02 +08:00
EVzResultDataType WorkpiecePositionPresenter::GetDetectionDataType()
2025-12-10 00:01:32 +08:00
{
2025-12-27 09:34:02 +08:00
// 工件定位不使用激光数据类型
return keResultDataType_Position;
2025-12-10 00:01:32 +08:00
}
2025-12-27 09:34:02 +08:00
void WorkpiecePositionPresenter::OnCameraStatusChanged(int cameraIndex, bool isConnected)
2025-12-10 00:01:32 +08:00
{
2025-12-27 09:34:02 +08:00
// 使用自定义的设备状态通知
auto pCallback = GetStatusCallback<IYWorkpiecePositionStatus>();
if (!pCallback) return;
if (cameraIndex == 1) {
pCallback->OnBinocularMarkConnectionChanged(isConnected);
} else if (cameraIndex == 2) {
pCallback->OnEpicEyeConnectionChanged(isConnected);
}
}
// ============ 重写 BasePresenter 虚函数 ============
void WorkpiecePositionPresenter::OnWorkStatusChanged(WorkStatus status)
{
auto pCallback = GetStatusCallback<IYWorkpiecePositionStatus>();
if (pCallback) {
pCallback->OnWorkStatusChanged(status);
}
}
void WorkpiecePositionPresenter::OnStatusUpdate(const std::string& statusMessage)
{
auto pCallback = GetStatusCallback<IYWorkpiecePositionStatus>();
if (pCallback) {
pCallback->OnStatusUpdate(statusMessage);
}
}
// ============ 重写检测方法 ============
int WorkpiecePositionPresenter::StartDetection(int cameraIndex, bool isAuto)
{
std::lock_guard<std::mutex> lock(m_detectMutex);
if (m_bDetecting) {
LOG_WARN("正在检测中\n");
return ERR_CODE(APP_ERR_EXEC);
}
if (!m_bMarkConnected) {
LOG_ERR("BinocularMarkApp未连接\n");
OnStatusUpdate("BinocularMarkApp未连接");
return -2;
}
if (!m_bEpicEyeConnected) {
LOG_ERR("EpicEye设备未连接\n");
OnStatusUpdate("EpicEye设备未连接");
return -3;
}
2025-12-10 00:01:32 +08:00
m_bDetecting = true;
2025-12-27 09:34:02 +08:00
SetWorkStatus(WorkStatus::Working);
2025-12-10 00:01:32 +08:00
LOG_INFO("开始检测\n");
2025-12-27 09:34:02 +08:00
// 使用后台线程调用同步方法 RequestSingleDetection
m_detectionFuture = std::make_shared<std::future<void>>(
std::async(std::launch::async, [this]() {
auto result = m_pMarkReceiver->RequestSingleDetection(5000);
if (result.timestamp > 0) {
OnMarkResult(result.marks, result.timestamp, result.errorCode);
} else {
LOG_ERR("BinocularMarkApp检测超时或失败\n");
OnMarkResult({}, 0, -1);
}
})
);
2025-12-10 00:01:32 +08:00
return SUCCESS;
}
int WorkpiecePositionPresenter::StopDetection()
{
2025-12-27 09:34:02 +08:00
std::lock_guard<std::mutex> lock(m_detectMutex);
2025-12-10 00:01:32 +08:00
if (!m_bDetecting) return SUCCESS;
m_bDetecting = false;
2025-12-27 09:34:02 +08:00
SetWorkStatus(WorkStatus::Ready);
2025-12-10 00:01:32 +08:00
LOG_INFO("停止检测\n");
return SUCCESS;
}
2025-12-27 09:34:02 +08:00
// ============ 私有方法实现 ============
2025-12-10 00:01:32 +08:00
int WorkpiecePositionPresenter::InitConfig()
{
2025-12-27 09:34:02 +08:00
if (!IVrConfig::CreateInstance((IVrConfig**)&m_pConfig)) {
LOG_ERR("创建配置管理器失败\n");
return ERR_CODE(APP_ERR_EXEC);
}
2025-12-10 00:01:32 +08:00
std::string configPath = "./config/config.xml";
int ret = m_pConfig->LoadConfig(configPath, m_configResult);
2025-12-27 09:34:02 +08:00
if (ret != SUCCESS) {
LOG_ERR("加载配置文件失败: %s\n", configPath.c_str());
return -2;
}
2025-12-10 00:01:32 +08:00
// 从 binocularMarkConfig 获取 BinocularMark 连接信息
m_binocularMarkIp = m_configResult.binocularMarkConfig.serverIP;
m_binocularMarkPort = m_configResult.binocularMarkConfig.serverPort;
// 从 epicEyeDeviceList 获取 EpicEye 设备信息
if (m_configResult.epicEyeDeviceList.size() > 0) {
m_epicEyeIp = m_configResult.epicEyeDeviceList[0].ip;
} else {
LOG_WARN("配置文件中未找到EpicEye设备使用默认IP: 192.168.1.100\n");
m_epicEyeIp = "192.168.1.100";
}
return SUCCESS;
}
int WorkpiecePositionPresenter::InitBinocularMarkReceiver()
{
int ret = IBinocularMarkReceiver::CreateInstance(&m_pMarkReceiver);
2025-12-27 09:34:02 +08:00
if (ret != SUCCESS) {
LOG_ERR("创建BinocularMarkReceiver实例失败\n");
return ERR_CODE(APP_ERR_EXEC);
}
2025-12-10 00:01:32 +08:00
m_pMarkReceiver->SetMarkResultCallback([this](const std::vector<VrMark3D>& marks, int64_t timestamp, int errorCode) {
2025-12-10 00:01:32 +08:00
this->OnMarkResult(marks, timestamp, errorCode);
});
m_pMarkReceiver->SetEventCallback([this](ReceiverEventType eventType, const std::string& errorMsg) {
this->OnMarkConnectionChanged(eventType == ReceiverEventType::CONNECTED);
});
2025-12-10 00:01:32 +08:00
return ConnectToBinocularMark();
}
int WorkpiecePositionPresenter::InitEpicEyeDevice()
{
int ret = IEpicEyeDevice::CreateObject(&m_pEpicEyeDevice);
2025-12-27 09:34:02 +08:00
if (ret != SUCCESS) {
LOG_ERR("创建EpicEyeDevice实例失败\n");
return ERR_CODE(APP_ERR_EXEC);
}
2025-12-10 00:01:32 +08:00
return ConnectToEpicEye();
}
void WorkpiecePositionPresenter::OnMarkResult(const std::vector<VrMark3D>& marks, qint64 timestamp, int errorCode)
{
LOG_INFO("收到BinocularMark检测结果Mark数量: %zu, 错误码: %d\n", marks.size(), errorCode);
if (errorCode != 0) {
LOG_ERR("BinocularMark检测失败: %d\n", errorCode);
2025-12-27 09:34:02 +08:00
SetWorkStatus(WorkStatus::Error);
OnStatusUpdate("BinocularMark检测失败");
2025-12-10 00:01:32 +08:00
m_bDetecting = false;
return;
}
2025-12-27 09:34:02 +08:00
{ std::lock_guard<std::mutex> lock(m_detectMutex); m_lastMarks = marks; }
2025-12-10 00:01:32 +08:00
PointCloudData pointCloud;
int ret = m_pEpicEyeDevice->CapturePointCloud(pointCloud, 5000);
if (ret != SUCCESS) {
LOG_ERR("获取EpicEye点云数据失败: %d\n", ret);
2025-12-27 09:34:02 +08:00
SetWorkStatus(WorkStatus::Error);
OnStatusUpdate("获取EpicEye点云数据失败");
2025-12-10 00:01:32 +08:00
m_bDetecting = false;
return;
}
WorkpieceCenterPosition centerPosition;
ret = CalculateWorkpieceCenter(marks, pointCloud, centerPosition);
if (ret != SUCCESS) {
LOG_ERR("计算工件中心点失败: %d\n", ret);
2025-12-27 09:34:02 +08:00
SetWorkStatus(WorkStatus::Error);
OnStatusUpdate("计算工件中心点失败");
2025-12-10 00:01:32 +08:00
m_bDetecting = false;
if (pointCloud.pData) delete[] pointCloud.pData;
return;
}
if (pointCloud.pData) delete[] pointCloud.pData;
WorkpiecePositionDetectionResult result;
result.positions.push_back(centerPosition);
result.marks = marks;
2025-12-27 09:34:02 +08:00
auto pCallback = GetStatusCallback<IYWorkpiecePositionStatus>();
if (pCallback) pCallback->OnDetectionResult(result);
SetWorkStatus(WorkStatus::Completed);
2025-12-10 00:01:32 +08:00
LOG_INFO("工件定位检测完成,中心点: (%.2f, %.2f, %.2f)\n", centerPosition.x, centerPosition.y, centerPosition.z);
m_bDetecting = false;
}
void WorkpiecePositionPresenter::OnMarkConnectionChanged(bool connected)
{
LOG_INFO("BinocularMark连接状态改变: %s\n", connected ? "已连接" : "断开连接");
m_bMarkConnected = connected;
2025-12-27 09:34:02 +08:00
auto pCallback = GetStatusCallback<IYWorkpiecePositionStatus>();
if (pCallback) pCallback->OnBinocularMarkConnectionChanged(connected);
2025-12-10 00:01:32 +08:00
if (connected) {
m_pMarkReconnectTimer->stop();
2025-12-27 09:34:02 +08:00
OnStatusUpdate("BinocularMarkApp已连接");
2025-12-10 00:01:32 +08:00
} else {
m_pMarkReconnectTimer->start(5000);
2025-12-27 09:34:02 +08:00
OnStatusUpdate("BinocularMarkApp连接断开正在重连...");
2025-12-10 00:01:32 +08:00
}
}
int WorkpiecePositionPresenter::CalculateWorkpieceCenter(const std::vector<VrMark3D>& marks, const PointCloudData& pointCloud, WorkpieceCenterPosition& centerPosition)
{
// TODO: 实现工件中心点计算算法(由用户后续填充)
// 示例实现简单地将所有Mark点的平均值作为中心点
2025-12-27 09:34:02 +08:00
if (marks.empty()) {
LOG_ERR("Mark数据为空\n");
return ERR_CODE(APP_ERR_EXEC);
}
2025-12-10 00:01:32 +08:00
double sumX = 0.0, sumY = 0.0, sumZ = 0.0;
for (const auto& mark : marks) {
sumX += mark.x;
sumY += mark.y;
sumZ += mark.z;
}
centerPosition.x = sumX / marks.size();
centerPosition.y = sumY / marks.size();
centerPosition.z = sumZ / marks.size();
centerPosition.roll = 0.0;
centerPosition.pitch = 0.0;
centerPosition.yaw = 0.0;
LOG_INFO("计算得到工件中心点: (%.2f, %.2f, %.2f)\n", centerPosition.x, centerPosition.y, centerPosition.z);
return SUCCESS;
}
int WorkpiecePositionPresenter::ConnectToBinocularMark()
{
LOG_INFO("连接BinocularMarkApp: %s:%d\n", m_binocularMarkIp.c_str(), m_binocularMarkPort);
return m_pMarkReceiver->Connect(m_binocularMarkIp, m_binocularMarkPort);
}
int WorkpiecePositionPresenter::ConnectToEpicEye()
{
LOG_INFO("连接EpicEye设备: %s\n", m_epicEyeIp.c_str());
int ret = m_pEpicEyeDevice->Connect(m_epicEyeIp);
if (ret != SUCCESS) {
LOG_ERR("连接EpicEye设备失败\n");
m_bEpicEyeConnected = false;
2025-12-27 09:34:02 +08:00
auto pCallback = GetStatusCallback<IYWorkpiecePositionStatus>();
if (pCallback) pCallback->OnEpicEyeConnectionChanged(false);
2025-12-10 00:01:32 +08:00
return ERR_CODE(APP_ERR_EXEC);
}
m_bEpicEyeConnected = true;
2025-12-27 09:34:02 +08:00
auto pCallback = GetStatusCallback<IYWorkpiecePositionStatus>();
if (pCallback) pCallback->OnEpicEyeConnectionChanged(true);
2025-12-10 00:01:32 +08:00
m_pEpicEyeReconnectTimer->stop();
2025-12-27 09:34:02 +08:00
OnStatusUpdate("EpicEye设备已连接");
2025-12-10 00:01:32 +08:00
return SUCCESS;
}
void WorkpiecePositionPresenter::onMarkReconnectTimeout()
{
LOG_INFO("尝试重连BinocularMarkApp\n");
ConnectToBinocularMark();
}
void WorkpiecePositionPresenter::onEpicEyeReconnectTimeout()
{
LOG_INFO("尝试重连EpicEye设备\n");
ConnectToEpicEye();
}