2026-03-28 10:49:55 +08:00
|
|
|
|
#include "ScrewPositionPresenter.h"
|
2026-04-15 11:08:31 +08:00
|
|
|
|
|
|
|
|
|
|
#include "DetectPresenter.h"
|
|
|
|
|
|
#include "PathManager.h"
|
|
|
|
|
|
#include "ScrewPositionTCPProtocol.h"
|
|
|
|
|
|
#include "Version.h"
|
|
|
|
|
|
#include "VrConvert.h"
|
2026-03-28 10:49:55 +08:00
|
|
|
|
#include "VrError.h"
|
|
|
|
|
|
#include "VrLog.h"
|
2026-04-15 11:08:31 +08:00
|
|
|
|
#include "VrTimeUtils.h"
|
|
|
|
|
|
|
2026-03-28 10:49:55 +08:00
|
|
|
|
#include <QtCore/QCoreApplication>
|
|
|
|
|
|
#include <QtCore/QDateTime>
|
2026-04-15 11:08:31 +08:00
|
|
|
|
#include <QtCore/QString>
|
2026-03-28 10:49:55 +08:00
|
|
|
|
#include <algorithm>
|
2026-04-15 11:08:31 +08:00
|
|
|
|
#include <cstdio>
|
|
|
|
|
|
#include <cstring>
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
|
|
|
|
|
ScrewPositionPresenter::ScrewPositionPresenter(QObject *parent)
|
|
|
|
|
|
: BasePresenter(parent)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ScrewPositionPresenter::~ScrewPositionPresenter()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_pConfigManager) {
|
|
|
|
|
|
delete m_pConfigManager;
|
|
|
|
|
|
m_pConfigManager = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_pTCPServer) {
|
|
|
|
|
|
m_pTCPServer->Deinitialize();
|
|
|
|
|
|
delete m_pTCPServer;
|
|
|
|
|
|
m_pTCPServer = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (m_pDetectPresenter) {
|
2026-03-28 10:49:55 +08:00
|
|
|
|
delete m_pDetectPresenter;
|
|
|
|
|
|
m_pDetectPresenter = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ScrewPositionPresenter::InitApp()
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_DEBUG("Start APP Version: %s\n", SCREWPOSITION_FULL_VERSION_STRING);
|
|
|
|
|
|
SetWorkStatus(WorkStatus::InitIng);
|
|
|
|
|
|
|
|
|
|
|
|
m_pDetectPresenter = new DetectPresenter();
|
|
|
|
|
|
|
|
|
|
|
|
m_pConfigManager = new ConfigManager();
|
|
|
|
|
|
if (!m_pConfigManager) {
|
|
|
|
|
|
LOG_ERROR("Failed to create ConfigManager instance\n");
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnStatusUpdate("配置管理器创建失败");
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
return ERR_CODE(DEV_CONFIG_ERR);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!m_pConfigManager->Initialize()) {
|
|
|
|
|
|
LOG_ERROR("Failed to initialize ConfigManager\n");
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnStatusUpdate("配置管理器初始化失败");
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
return ERR_CODE(DEV_CONFIG_ERR);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const ConfigResult configResult = m_pConfigManager->GetConfigResult();
|
|
|
|
|
|
SetDebugParam(configResult.debugParam);
|
|
|
|
|
|
m_modbusRegistersInitialized = false;
|
|
|
|
|
|
m_modbusWorkStatus = 0;
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
std::vector<DeviceInfo> cameraList = configResult.cameraList;
|
|
|
|
|
|
InitCamera(cameraList, false, true);
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
|
|
|
|
|
LOG_INFO("Camera initialization completed. Connected cameras: %zu, default camera index: %d\n",
|
|
|
|
|
|
m_vrEyeDeviceList.size(), m_currentCameraIndex);
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
int nRet = InitTCPServer();
|
|
|
|
|
|
if (nRet != SUCCESS) {
|
|
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnStatusUpdate("TCP服务器初始化失败");
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
m_bTCPConnected = false;
|
|
|
|
|
|
} else {
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnStatusUpdate("TCP服务器初始化成功");
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnStatusUpdate("设备初始化完成");
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
|
|
|
|
|
CheckAndUpdateWorkStatus();
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnStatusUpdate("配置初始化成功");
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ScrewPositionPresenter::InitAlgoParams()
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_DEBUG("initializing algorithm parameters\n");
|
|
|
|
|
|
|
|
|
|
|
|
m_clibMatrixList.clear();
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const ConfigResult configResult = m_pConfigManager->GetConfigResult();
|
|
|
|
|
|
SetDebugParam(configResult.debugParam);
|
|
|
|
|
|
const VrAlgorithmParams& xmlParams = configResult.algorithmParams;
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const double initClibMatrix[16] = {
|
|
|
|
|
|
1.0, 0.0, 0.0, 0.0,
|
|
|
|
|
|
0.0, 1.0, 0.0, 0.0,
|
|
|
|
|
|
0.0, 0.0, 1.0, 0.0,
|
|
|
|
|
|
0.0, 0.0, 0.0, 1.0
|
|
|
|
|
|
};
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (!configResult.handEyeCalibMatrixList.empty()) {
|
|
|
|
|
|
int cameraCount = static_cast<int>(configResult.cameraList.size());
|
|
|
|
|
|
for (const auto& matrixInfo : configResult.handEyeCalibMatrixList) {
|
|
|
|
|
|
cameraCount = std::max(cameraCount, matrixInfo.cameraIndex);
|
|
|
|
|
|
}
|
|
|
|
|
|
cameraCount = std::max(cameraCount, 1);
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
m_clibMatrixList.resize(static_cast<size_t>(cameraCount));
|
|
|
|
|
|
for (auto& calibMatrix : m_clibMatrixList) {
|
|
|
|
|
|
std::memcpy(calibMatrix.clibMatrix, initClibMatrix, sizeof(initClibMatrix));
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
for (const auto& matrixInfo : configResult.handEyeCalibMatrixList) {
|
|
|
|
|
|
if (matrixInfo.cameraIndex <= 0 || matrixInfo.cameraIndex > cameraCount) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
std::memcpy(m_clibMatrixList[static_cast<size_t>(matrixInfo.cameraIndex - 1)].clibMatrix,
|
|
|
|
|
|
matrixInfo.matrix,
|
|
|
|
|
|
sizeof(matrixInfo.matrix));
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
LOG_INFO("Loaded %zu hand-eye matrices from config.xml\n",
|
|
|
|
|
|
configResult.handEyeCalibMatrixList.size());
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const QString clibPath = PathManager::GetInstance().GetCalibrationFilePath();
|
|
|
|
|
|
LOG_INFO("Loading hand-eye matrices from legacy ini: %s\n", clibPath.toStdString().c_str());
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const int nExistMatrixNum = CVrConvert::GetClibMatrixCount(clibPath.toStdString().c_str());
|
|
|
|
|
|
LOG_INFO("Found %d legacy hand-eye calibration matrices\n", nExistMatrixNum);
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
for (int matrixIndex = 0; matrixIndex < nExistMatrixNum; ++matrixIndex) {
|
|
|
|
|
|
char matrixIdent[64];
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
|
sprintf_s(matrixIdent, "CalibMatrixInfo_%d", matrixIndex);
|
|
|
|
|
|
#else
|
|
|
|
|
|
sprintf(matrixIdent, "CalibMatrixInfo_%d", matrixIndex);
|
|
|
|
|
|
#endif
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
CalibMatrix calibMatrix;
|
|
|
|
|
|
std::memcpy(calibMatrix.clibMatrix, initClibMatrix, sizeof(initClibMatrix));
|
|
|
|
|
|
if (CVrConvert::LoadClibMatrix(clibPath.toStdString().c_str(),
|
|
|
|
|
|
matrixIdent,
|
|
|
|
|
|
"dCalibMatrix",
|
|
|
|
|
|
calibMatrix.clibMatrix)) {
|
|
|
|
|
|
LOG_INFO("Successfully loaded legacy matrix %d\n", matrixIndex);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
LOG_WARNING("Failed to load legacy matrix %d, using identity matrix\n", matrixIndex);
|
2026-03-28 10:49:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
m_clibMatrixList.push_back(calibMatrix);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (m_clibMatrixList.empty()) {
|
|
|
|
|
|
const int cameraCount = std::max(1, static_cast<int>(configResult.cameraList.size()));
|
|
|
|
|
|
m_clibMatrixList.resize(static_cast<size_t>(cameraCount));
|
|
|
|
|
|
for (auto& calibMatrix : m_clibMatrixList) {
|
|
|
|
|
|
std::memcpy(calibMatrix.clibMatrix, initClibMatrix, sizeof(initClibMatrix));
|
|
|
|
|
|
}
|
|
|
|
|
|
LOG_INFO("No hand-eye matrix found, using identity matrix for %d camera(s)\n", cameraCount);
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
|
|
|
|
|
LOG_INFO("Loaded XML params - Screw: rodDiameter=%.1f, isHorizonScan=%s\n",
|
|
|
|
|
|
xmlParams.screwParam.rodDiameter,
|
|
|
|
|
|
xmlParams.screwParam.isHorizonScan ? "true" : "false");
|
|
|
|
|
|
LOG_INFO("Loaded XML params - Filter: continuityTh=%.1f, outlierTh=%.1f\n",
|
|
|
|
|
|
xmlParams.filterParam.continuityTh, xmlParams.filterParam.outlierTh);
|
|
|
|
|
|
LOG_INFO("Algorithm parameters initialized successfully\n");
|
|
|
|
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CalibMatrix ScrewPositionPresenter::GetClibMatrix(int index) const
|
|
|
|
|
|
{
|
|
|
|
|
|
CalibMatrix clibMatrix;
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const double initClibMatrix[16] = {
|
|
|
|
|
|
1.0, 0.0, 0.0, 0.0,
|
|
|
|
|
|
0.0, 1.0, 0.0, 0.0,
|
|
|
|
|
|
0.0, 0.0, 1.0, 0.0,
|
|
|
|
|
|
0.0, 0.0, 0.0, 1.0
|
2026-03-28 10:49:55 +08:00
|
|
|
|
};
|
2026-04-15 11:08:31 +08:00
|
|
|
|
std::memcpy(clibMatrix.clibMatrix, initClibMatrix, sizeof(initClibMatrix));
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
|
|
|
|
|
if (index >= 0 && index < static_cast<int>(m_clibMatrixList.size())) {
|
2026-04-15 11:08:31 +08:00
|
|
|
|
std::memcpy(clibMatrix.clibMatrix, m_clibMatrixList[index].clibMatrix, sizeof(initClibMatrix));
|
2026-03-28 10:49:55 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
LOG_WARNING("Invalid hand-eye calibration matrix\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return clibMatrix;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ScrewPositionPresenter::CheckAndUpdateWorkStatus()
|
|
|
|
|
|
{
|
2026-04-15 11:08:31 +08:00
|
|
|
|
SetWorkStatus(m_bCameraConnected ? WorkStatus::Ready : WorkStatus::Error);
|
2026-03-28 10:49:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ScrewPositionPresenter::ProcessAlgoDetection(std::vector<std::pair<EVzResultDataType, SVzLaserLineData>>& detectionDataCache)
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_INFO("[Algo Thread] Start real detection task using algorithm\n");
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const unsigned int lineNum = detectionDataCache.size();
|
|
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnStatusUpdate(QString("扫描线数:%1,正在算法检测...").arg(lineNum).toStdString());
|
2026-03-28 10:49:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!m_pDetectPresenter) {
|
|
|
|
|
|
LOG_ERROR("DetectPresenter is null, cannot proceed with detection\n");
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnStatusUpdate("检测处理器未初始化");
|
2026-03-28 10:49:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
return ERR_CODE(DEV_NOT_FIND);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CVrTimeUtils oTimeUtils;
|
|
|
|
|
|
const CalibMatrix currentClibMatrix = GetClibMatrix(m_currentCameraIndex - 1);
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const VrAlgorithmParams algorithmParams = m_pConfigManager->GetAlgorithmParams();
|
|
|
|
|
|
const ConfigResult configResult = m_pConfigManager->GetConfigResult();
|
|
|
|
|
|
const VrDebugParam debugParam = configResult.debugParam;
|
2026-04-17 10:18:03 +08:00
|
|
|
|
const int poseOutputOrder = configResult.poseOutputOrder;
|
|
|
|
|
|
|
2026-04-20 16:37:25 +08:00
|
|
|
|
// 每台相机独立:欧拉角顺序 + 绕 XYZ 三轴的补偿旋转 + 接近点偏移
|
|
|
|
|
|
HandEyeExtrinsic extrinsic;
|
|
|
|
|
|
for (const auto& calibMatrix : configResult.handEyeCalibMatrixList) {
|
|
|
|
|
|
if (calibMatrix.cameraIndex == m_currentCameraIndex) {
|
|
|
|
|
|
extrinsic.eulerOrder = calibMatrix.eulerOrder;
|
|
|
|
|
|
extrinsic.rotX = calibMatrix.rotX;
|
|
|
|
|
|
extrinsic.rotY = calibMatrix.rotY;
|
|
|
|
|
|
extrinsic.rotZ = calibMatrix.rotZ;
|
|
|
|
|
|
extrinsic.approachOffset = calibMatrix.approachOffset;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LOG_INFO("[Algo Thread] camera=%d eulerOrder=%d poseOutputOrder=%d rot=(%.3f, %.3f, %.3f) approachOffset=%.3f\n",
|
|
|
|
|
|
m_currentCameraIndex, extrinsic.eulerOrder, poseOutputOrder,
|
|
|
|
|
|
extrinsic.rotX, extrinsic.rotY, extrinsic.rotZ, extrinsic.approachOffset);
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
|
|
|
|
|
DetectionResult detectionResult;
|
2026-04-15 11:08:31 +08:00
|
|
|
|
detectionResult.cameraIndex = m_currentCameraIndex;
|
|
|
|
|
|
|
|
|
|
|
|
int nRet = SUCCESS;
|
|
|
|
|
|
if (m_currentDetectionType == DETECTION_TYPE_TOOL_DISK) {
|
|
|
|
|
|
nRet = m_pDetectPresenter->DetectToolDisk(
|
|
|
|
|
|
m_currentCameraIndex,
|
|
|
|
|
|
detectionDataCache,
|
|
|
|
|
|
algorithmParams,
|
|
|
|
|
|
debugParam,
|
|
|
|
|
|
m_dataLoader,
|
|
|
|
|
|
currentClibMatrix.clibMatrix,
|
|
|
|
|
|
m_currentRobotPose,
|
2026-04-20 16:37:25 +08:00
|
|
|
|
extrinsic,
|
2026-04-17 10:18:03 +08:00
|
|
|
|
poseOutputOrder,
|
2026-04-15 11:08:31 +08:00
|
|
|
|
detectionResult);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
nRet = m_pDetectPresenter->DetectScrew(
|
|
|
|
|
|
m_currentCameraIndex,
|
|
|
|
|
|
detectionDataCache,
|
|
|
|
|
|
algorithmParams,
|
|
|
|
|
|
debugParam,
|
|
|
|
|
|
m_dataLoader,
|
|
|
|
|
|
currentClibMatrix.clibMatrix,
|
|
|
|
|
|
m_currentRobotPose,
|
2026-04-20 16:37:25 +08:00
|
|
|
|
extrinsic,
|
2026-04-17 10:18:03 +08:00
|
|
|
|
poseOutputOrder,
|
2026-04-15 11:08:31 +08:00
|
|
|
|
detectionResult);
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (nRet != SUCCESS) {
|
|
|
|
|
|
detectionResult.success = false;
|
|
|
|
|
|
if (detectionResult.errorCode == 0) {
|
|
|
|
|
|
detectionResult.errorCode = nRet;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (detectionResult.message.isEmpty() || detectionResult.message == QStringLiteral("检测成功")) {
|
|
|
|
|
|
detectionResult.message = QString("检测失败:%1").arg(nRet);
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
LOG_INFO("[Algo Thread] detection type=%d objects=%zu time : %.2f ms\n",
|
|
|
|
|
|
static_cast<int>(m_currentDetectionType),
|
|
|
|
|
|
detectionResult.positions.size(),
|
|
|
|
|
|
oTimeUtils.GetElapsedTimeInMilliSec());
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
|
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnDetectionResult(detectionResult);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
QString statusMsg;
|
|
|
|
|
|
if (!detectionResult.success) {
|
|
|
|
|
|
statusMsg = detectionResult.message;
|
|
|
|
|
|
} else if (m_currentDetectionType == DETECTION_TYPE_TOOL_DISK) {
|
|
|
|
|
|
statusMsg = QString("工具盘检测完成,定位点数:%1").arg(detectionResult.positions.size());
|
|
|
|
|
|
} else {
|
|
|
|
|
|
statusMsg = QString("检测完成,发现%1个螺杆").arg(detectionResult.positions.size());
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnStatusUpdate(statusMsg.toStdString());
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
_SendDetectionResultToTCP(detectionResult, m_currentCameraIndex);
|
|
|
|
|
|
_PublishDetectionResultToModbus(detectionResult);
|
|
|
|
|
|
return nRet;
|
2026-03-28 10:49:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ScrewPositionPresenter::OnConfigChanged(const ConfigResult& configResult)
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_INFO("Configuration changed notification received, reloading algorithm parameters\n");
|
2026-04-15 11:08:31 +08:00
|
|
|
|
SetDebugParam(configResult.debugParam);
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
|
|
|
|
|
int result = InitAlgoParams();
|
2026-04-15 11:08:31 +08:00
|
|
|
|
stopServer();
|
|
|
|
|
|
const int tcpResult = InitTCPServer();
|
2026-03-28 10:49:55 +08:00
|
|
|
|
if (result == SUCCESS) {
|
|
|
|
|
|
LOG_INFO("Algorithm parameters reloaded successfully after config change\n");
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnStatusUpdate("配置已更新,算法参数重新加载成功");
|
2026-03-28 10:49:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
LOG_ERROR("Failed to reload algorithm parameters after config change, error: %d\n", result);
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnStatusUpdate("配置更新后算法参数重新加载失败");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (tcpResult != SUCCESS) {
|
|
|
|
|
|
LOG_ERROR("Failed to restart TCP server after config change, error: %d\n", tcpResult);
|
|
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnStatusUpdate("TCP server restart failed");
|
2026-03-28 10:49:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SSG_planeCalibPara ScrewPositionPresenter::_GetCameraCalibParam(int cameraIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
SSG_planeCalibPara calibParam;
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const double identityMatrix[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
|
|
|
|
|
|
for (int i = 0; i < 9; ++i) {
|
2026-03-28 10:49:55 +08:00
|
|
|
|
calibParam.planeCalib[i] = identityMatrix[i];
|
|
|
|
|
|
calibParam.invRMatrix[i] = identityMatrix[i];
|
|
|
|
|
|
}
|
2026-04-15 11:08:31 +08:00
|
|
|
|
calibParam.planeHeight = -1.0;
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const VrAlgorithmParams algorithmParams = m_pConfigManager->GetAlgorithmParams();
|
2026-03-28 10:49:55 +08:00
|
|
|
|
for (const auto& cameraParam : algorithmParams.planeCalibParam.cameraCalibParams) {
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (cameraParam.cameraIndex == cameraIndex && cameraParam.isCalibrated) {
|
|
|
|
|
|
for (int i = 0; i < 9; ++i) {
|
|
|
|
|
|
calibParam.planeCalib[i] = cameraParam.planeCalib[i];
|
|
|
|
|
|
calibParam.invRMatrix[i] = cameraParam.invRMatrix[i];
|
2026-03-28 10:49:55 +08:00
|
|
|
|
}
|
2026-04-15 11:08:31 +08:00
|
|
|
|
calibParam.planeHeight = cameraParam.planeHeight;
|
2026-03-28 10:49:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-04-15 11:08:31 +08:00
|
|
|
|
|
2026-03-28 10:49:55 +08:00
|
|
|
|
return calibParam;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ScrewPositionPresenter::OnCameraStatusChanged(int cameraIndex, bool isConnected)
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_INFO("Camera %d status changed: %s\n", cameraIndex, isConnected ? "connected" : "disconnected");
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
2026-03-28 10:49:55 +08:00
|
|
|
|
if (cameraIndex == 1) {
|
2026-04-15 11:08:31 +08:00
|
|
|
|
pStatus->OnCamera1StatusChanged(isConnected);
|
2026-03-28 10:49:55 +08:00
|
|
|
|
} else if (cameraIndex == 2) {
|
2026-04-15 11:08:31 +08:00
|
|
|
|
pStatus->OnCamera2StatusChanged(isConnected);
|
2026-03-28 10:49:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString cameraName;
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const int arrayIndex = cameraIndex - 1;
|
2026-03-28 10:49:55 +08:00
|
|
|
|
if (arrayIndex >= 0 && arrayIndex < static_cast<int>(m_vrEyeDeviceList.size())) {
|
|
|
|
|
|
cameraName = QString::fromStdString(m_vrEyeDeviceList[arrayIndex].first);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cameraName = QString("相机%1").arg(cameraIndex);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const QString statusMsg = QString("%1%2").arg(cameraName).arg(isConnected ? "已连接" : "已断开");
|
|
|
|
|
|
pStatus->OnStatusUpdate(statusMsg.toStdString());
|
2026-03-28 10:49:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CheckAndUpdateWorkStatus();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ScrewPositionPresenter::OnWorkStatusChanged(WorkStatus status)
|
|
|
|
|
|
{
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
2026-03-28 10:49:55 +08:00
|
|
|
|
pStatus->OnWorkStatusChanged(status);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (!m_modbusRegistersInitialized && status == WorkStatus::Ready) {
|
|
|
|
|
|
_InitializeModbusRegisters();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (status == WorkStatus::Working) {
|
|
|
|
|
|
_UpdateModbusWorkStatus(1);
|
|
|
|
|
|
} else if (status == WorkStatus::Error) {
|
|
|
|
|
|
_UpdateModbusWorkStatus(3);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
|
|
|
|
|
void ScrewPositionPresenter::OnCameraCountChanged(int count)
|
|
|
|
|
|
{
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
2026-03-28 10:49:55 +08:00
|
|
|
|
pStatus->OnCameraCountChanged(count);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ScrewPositionPresenter::OnStatusUpdate(const std::string& statusMessage)
|
|
|
|
|
|
{
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
2026-03-28 10:49:55 +08:00
|
|
|
|
pStatus->OnStatusUpdate(statusMessage);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
void ScrewPositionPresenter::OnModbusServerStatusChanged(bool isConnected)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnRobotConnectionChanged(isConnected);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ScrewPositionPresenter::OnModbusWriteCallback(uint16_t startAddress, const uint16_t* data, uint16_t count)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!data || count == 0) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
constexpr uint16_t kTriggerAddress = 0;
|
|
|
|
|
|
constexpr uint16_t kRobotPoseAddress = 2;
|
|
|
|
|
|
constexpr uint16_t kRobotPoseRegCount = 12;
|
|
|
|
|
|
|
|
|
|
|
|
// 缓存机械臂位姿写入(地址2~13,6个float32)
|
|
|
|
|
|
for (uint16_t i = 0; i < count; ++i) {
|
|
|
|
|
|
uint16_t addr = startAddress + i;
|
|
|
|
|
|
if (addr >= kRobotPoseAddress && addr < kRobotPoseAddress + kRobotPoseRegCount) {
|
|
|
|
|
|
m_modbusRobotPoseRegs[addr - kRobotPoseAddress] = data[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查触发
|
|
|
|
|
|
uint16_t triggerValue = 0;
|
|
|
|
|
|
bool hasTrigger = false;
|
|
|
|
|
|
|
|
|
|
|
|
for (uint16_t i = 0; i < count; ++i) {
|
|
|
|
|
|
if (startAddress + i == kTriggerAddress) {
|
|
|
|
|
|
triggerValue = data[i];
|
|
|
|
|
|
hasTrigger = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!hasTrigger) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const uint16_t resetValue = 0;
|
|
|
|
|
|
WriteModbusRegisters(kTriggerAddress, &resetValue, 1);
|
|
|
|
|
|
|
|
|
|
|
|
if (triggerValue == static_cast<uint16_t>(DETECTION_TYPE_SCREW) ||
|
|
|
|
|
|
triggerValue == static_cast<uint16_t>(DETECTION_TYPE_TOOL_DISK)) {
|
|
|
|
|
|
// 从缓存的寄存器中解析机械臂位姿
|
|
|
|
|
|
RobotPose6D robotPose;
|
|
|
|
|
|
auto regToFloat = [this](int offset) -> float {
|
2026-04-19 12:28:59 +08:00
|
|
|
|
uint32_t raw = (static_cast<uint32_t>(m_modbusRobotPoseRegs[offset]) << 16) | static_cast<uint32_t>(m_modbusRobotPoseRegs[offset + 1]);
|
2026-04-15 11:08:31 +08:00
|
|
|
|
float val = 0;
|
|
|
|
|
|
std::memcpy(&val, &raw, sizeof(val));
|
|
|
|
|
|
return val;
|
|
|
|
|
|
};
|
|
|
|
|
|
robotPose.x = regToFloat(0);
|
|
|
|
|
|
robotPose.y = regToFloat(2);
|
|
|
|
|
|
robotPose.z = regToFloat(4);
|
2026-04-19 12:28:59 +08:00
|
|
|
|
robotPose.a = regToFloat(6);
|
|
|
|
|
|
robotPose.b = regToFloat(8);
|
|
|
|
|
|
robotPose.c = regToFloat(10);
|
2026-04-15 11:08:31 +08:00
|
|
|
|
|
|
|
|
|
|
LOG_INFO("Modbus trigger: type=%u, robotPose=(%.3f, %.3f, %.3f, %.3f, %.3f, %.3f)\n",
|
2026-04-19 12:28:59 +08:00
|
|
|
|
triggerValue, robotPose.x, robotPose.y, robotPose.z, robotPose.a, robotPose.b, robotPose.c);
|
2026-04-15 11:08:31 +08:00
|
|
|
|
|
|
|
|
|
|
TriggerDetection(-1, static_cast<DetectionType>(triggerValue), robotPose);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LOG_WARNING("Unsupported Modbus trigger value: %u\n", triggerValue);
|
|
|
|
|
|
_UpdateModbusWorkStatus(3);
|
|
|
|
|
|
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
|
|
|
|
|
|
pStatus->OnStatusUpdate(QString("Modbus触发值无效:%1").arg(triggerValue).toStdString());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-28 10:49:55 +08:00
|
|
|
|
|
|
|
|
|
|
bool ScrewPositionPresenter::CalculatePlaneCalibration(
|
|
|
|
|
|
const std::vector<std::pair<EVzResultDataType, SVzLaserLineData>>& scanData,
|
|
|
|
|
|
double planeCalib[9],
|
|
|
|
|
|
double& planeHeight,
|
|
|
|
|
|
double invRMatrix[9])
|
|
|
|
|
|
{
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (scanData.empty()) {
|
|
|
|
|
|
LOG_ERROR("No scan data available for plane calibration\n");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LaserDataLoader dataLoader;
|
|
|
|
|
|
std::vector<std::vector<SVzNL3DPosition>> xyzData;
|
|
|
|
|
|
int convertResult = dataLoader.ConvertToSVzNL3DPosition(scanData, xyzData);
|
|
|
|
|
|
if (convertResult != SUCCESS || xyzData.empty()) {
|
|
|
|
|
|
LOG_WARNING("Failed to convert data to XYZ format or no XYZ data available\n");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const double identity[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
|
|
|
|
|
|
std::memcpy(planeCalib, identity, sizeof(double) * 9);
|
|
|
|
|
|
std::memcpy(invRMatrix, identity, sizeof(double) * 9);
|
2026-03-28 10:49:55 +08:00
|
|
|
|
planeHeight = -1.0;
|
|
|
|
|
|
LOG_INFO("Plane calibration calculated successfully: height=%.3f\n", planeHeight);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
|
LOG_ERROR("Exception in CalculatePlaneCalibration: %s\n", e.what());
|
|
|
|
|
|
return false;
|
|
|
|
|
|
} catch (...) {
|
|
|
|
|
|
LOG_ERROR("Unknown exception in CalculatePlaneCalibration\n");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool ScrewPositionPresenter::SaveLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9],
|
2026-04-15 11:08:31 +08:00
|
|
|
|
int cameraIndex, const QString& cameraName)
|
2026-03-28 10:49:55 +08:00
|
|
|
|
{
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (!m_pConfigManager) {
|
|
|
|
|
|
LOG_ERROR("ConfigManager is null, cannot save leveling results\n");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (cameraIndex <= 0 || cameraName.isEmpty()) {
|
|
|
|
|
|
LOG_ERROR("Invalid camera info when saving leveling results\n");
|
2026-03-28 10:49:55 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const QString configPath = PathManager::GetInstance().GetConfigFilePath();
|
2026-03-28 10:49:55 +08:00
|
|
|
|
SystemConfig systemConfig = m_pConfigManager->GetConfig();
|
|
|
|
|
|
|
|
|
|
|
|
VrCameraPlaneCalibParam cameraParam;
|
|
|
|
|
|
cameraParam.cameraIndex = cameraIndex;
|
|
|
|
|
|
cameraParam.cameraName = cameraName.toStdString();
|
|
|
|
|
|
cameraParam.planeHeight = planeHeight;
|
|
|
|
|
|
cameraParam.isCalibrated = true;
|
2026-04-15 11:08:31 +08:00
|
|
|
|
for (int i = 0; i < 9; ++i) {
|
2026-03-28 10:49:55 +08:00
|
|
|
|
cameraParam.planeCalib[i] = planeCalib[i];
|
|
|
|
|
|
cameraParam.invRMatrix[i] = invRMatrix[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
systemConfig.configResult.algorithmParams.planeCalibParam.SetCameraCalibParam(cameraParam);
|
|
|
|
|
|
if (!m_pConfigManager->UpdateFullConfig(systemConfig)) {
|
|
|
|
|
|
LOG_ERROR("Failed to update config with leveling results\n");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!m_pConfigManager->SaveConfigToFile(configPath.toStdString())) {
|
|
|
|
|
|
LOG_ERROR("Failed to save config file with leveling results\n");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
LOG_INFO("Leveling results saved successfully for camera %d (%s)\n",
|
|
|
|
|
|
cameraIndex, cameraName.toUtf8().constData());
|
2026-03-28 10:49:55 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
|
LOG_ERROR("Exception in SaveLevelingResults: %s\n", e.what());
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool ScrewPositionPresenter::LoadLevelingResults(int cameraIndex, const QString& cameraName,
|
2026-04-15 11:08:31 +08:00
|
|
|
|
double planeCalib[9], double& planeHeight, double invRMatrix[9])
|
2026-03-28 10:49:55 +08:00
|
|
|
|
{
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (!m_pConfigManager) {
|
|
|
|
|
|
LOG_ERROR("ConfigManager is null, cannot load calibration data\n");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const ConfigResult configResult = m_pConfigManager->GetConfigResult();
|
2026-03-28 10:49:55 +08:00
|
|
|
|
VrCameraPlaneCalibParam cameraParamValue;
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (!configResult.algorithmParams.planeCalibParam.GetCameraCalibParam(cameraIndex, cameraParamValue) ||
|
|
|
|
|
|
!cameraParamValue.isCalibrated) {
|
|
|
|
|
|
LOG_INFO("No calibration data found for camera %d (%s)\n",
|
|
|
|
|
|
cameraIndex, cameraName.toUtf8().constData());
|
2026-03-28 10:49:55 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
for (int i = 0; i < 9; ++i) {
|
2026-03-28 10:49:55 +08:00
|
|
|
|
planeCalib[i] = cameraParamValue.planeCalib[i];
|
|
|
|
|
|
invRMatrix[i] = cameraParamValue.invRMatrix[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
planeHeight = cameraParamValue.planeHeight;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
|
LOG_ERROR("Exception in LoadLevelingResults: %s\n", e.what());
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ScrewPositionPresenter::DeinitApp()
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_DEBUG("Deinitializing ScrewPositionPresenter\n");
|
|
|
|
|
|
|
|
|
|
|
|
StopDetection();
|
|
|
|
|
|
|
|
|
|
|
|
if (m_pTCPServer) {
|
|
|
|
|
|
m_pTCPServer->Deinitialize();
|
|
|
|
|
|
delete m_pTCPServer;
|
|
|
|
|
|
m_pTCPServer = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_pConfigManager) {
|
|
|
|
|
|
delete m_pConfigManager;
|
|
|
|
|
|
m_pConfigManager = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_pDetectPresenter) {
|
|
|
|
|
|
delete m_pDetectPresenter;
|
|
|
|
|
|
m_pDetectPresenter = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
bool ScrewPositionPresenter::TriggerDetection(int cameraIndex, DetectionType detectionType, const RobotPose6D& robotPose)
|
2026-03-28 10:49:55 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (cameraIndex > 0) {
|
|
|
|
|
|
SetDefaultCameraIndex(cameraIndex);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
m_currentDetectionType = detectionType;
|
|
|
|
|
|
m_currentRobotPose = robotPose;
|
|
|
|
|
|
m_requestTimestamp = QDateTime::currentMSecsSinceEpoch();
|
|
|
|
|
|
|
2026-03-28 10:49:55 +08:00
|
|
|
|
if (!m_bCameraConnected) {
|
|
|
|
|
|
LOG_WARNING("Camera not connected, cannot trigger detection\n");
|
2026-04-15 11:08:31 +08:00
|
|
|
|
_UpdateModbusWorkStatus(3);
|
2026-03-28 10:49:55 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
if (GetCurrentWorkStatus() == WorkStatus::Working) {
|
|
|
|
|
|
LOG_WARNING("Detection is already running, skip duplicated trigger\n");
|
|
|
|
|
|
_UpdateModbusWorkStatus(1);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_InitializeModbusRegisters();
|
|
|
|
|
|
_ResetModbusResultRegisters();
|
|
|
|
|
|
_UpdateModbusWorkStatus(1);
|
|
|
|
|
|
|
2026-03-28 10:49:55 +08:00
|
|
|
|
int ret = StartDetection(cameraIndex, false);
|
|
|
|
|
|
if (ret != SUCCESS) {
|
|
|
|
|
|
LOG_ERROR("Failed to trigger detection, error: %d\n", ret);
|
2026-04-15 11:08:31 +08:00
|
|
|
|
_UpdateModbusWorkStatus(3);
|
2026-03-28 10:49:55 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 11:08:31 +08:00
|
|
|
|
int ScrewPositionPresenter::LoadAndDetect(const QString& fileName, DetectionType detectionType)
|
2026-03-28 10:49:55 +08:00
|
|
|
|
{
|
2026-04-15 11:08:31 +08:00
|
|
|
|
LOG_INFO("Loading data from file: %s, detectionType: %d\n",
|
|
|
|
|
|
fileName.toStdString().c_str(), static_cast<int>(detectionType));
|
|
|
|
|
|
m_currentDetectionType = detectionType;
|
2026-03-28 10:49:55 +08:00
|
|
|
|
return LoadDebugDataAndDetect(fileName.toStdString());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ScrewPositionPresenter::ReconnectCamera()
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_INFO("Attempting to reconnect cameras\n");
|
|
|
|
|
|
TryReconnectCameras();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ScrewPositionPresenter::AlgoParams ScrewPositionPresenter::GetAlgoParams() const
|
|
|
|
|
|
{
|
|
|
|
|
|
AlgoParams params;
|
|
|
|
|
|
if (m_pConfigManager) {
|
2026-04-15 11:08:31 +08:00
|
|
|
|
const VrAlgorithmParams algorithmParams = m_pConfigManager->GetAlgorithmParams();
|
2026-03-28 10:49:55 +08:00
|
|
|
|
params.screwParam = algorithmParams.screwParam;
|
|
|
|
|
|
params.cornerParam = algorithmParams.cornerParam;
|
|
|
|
|
|
params.filterParam = algorithmParams.filterParam;
|
|
|
|
|
|
params.growParam = algorithmParams.growParam;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.screwParam.rodDiameter = 10.0;
|
|
|
|
|
|
params.screwParam.isHorizonScan = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return params;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-08 22:12:47 +08:00
|
|
|
|
QString ScrewPositionPresenter::GetAlgoVersion() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return DetectPresenter::GetAlgoVersion();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-28 10:49:55 +08:00
|
|
|
|
void ScrewPositionPresenter::SetAlgoParams(const AlgoParams& params)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!m_pConfigManager) {
|
|
|
|
|
|
LOG_WARNING("ConfigManager not initialized, cannot set algorithm params\n");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VrAlgorithmParams algorithmParams = m_pConfigManager->GetAlgorithmParams();
|
|
|
|
|
|
algorithmParams.screwParam = params.screwParam;
|
|
|
|
|
|
algorithmParams.cornerParam = params.cornerParam;
|
|
|
|
|
|
algorithmParams.filterParam = params.filterParam;
|
|
|
|
|
|
algorithmParams.growParam = params.growParam;
|
|
|
|
|
|
m_pConfigManager->UpdateAlgorithmParams(algorithmParams);
|
|
|
|
|
|
|
|
|
|
|
|
LOG_INFO("Algorithm parameters updated\n");
|
|
|
|
|
|
}
|