diff --git a/HPPA/HPPA.cpp b/HPPA/HPPA.cpp index b581fde..8ca7fa3 100644 --- a/HPPA/HPPA.cpp +++ b/HPPA/HPPA.cpp @@ -682,6 +682,9 @@ void HPPA::initTimedDataCollection() connect(m_omc_LiftingPlatform, &OneMotorControl_LiftingPlatform::sequenceComplete, m_tdc, &TimedDataCollection::subTaskCompleted); connect(m_omc_LiftingPlatform, &OneMotorControl_LiftingPlatform::back2OriginSignal_TimedDataCollection, m_tdc, &TimedDataCollection::onBack2Origin); + //自动调焦 + connect(m_tdc, &TimedDataCollection::AutoFocusSignals, this, &HPPA::onAutoFocus_TimedDataCollection); + m_tdc->show(); } @@ -790,6 +793,13 @@ void HPPA::onLiftingPlatform(SubTask subTaskParams) m_omc_LiftingPlatform->run(); } +void HPPA::onAutoFocus_TimedDataCollection(SubTask subTaskParams) +{ + m_tmc->setImager(m_Imager); + //先使用subTaskParams.autoFocusMotorConfigFilePath替换文件oneMotorConfigFile_focus.cfg + m_tmc->run5_AutoFocus(subTaskParams.autoFocusX, subTaskParams.autoFocusY); +} + void HPPA::onTimedDataCollection() { QAction* checkedScenario = m_ScenarioActionGroup->checkedAction(); diff --git a/HPPA/HPPA.h b/HPPA/HPPA.h index dddf433..339a2dd 100644 --- a/HPPA/HPPA.h +++ b/HPPA/HPPA.h @@ -452,6 +452,7 @@ public Q_SLOTS: void onStartTimedDataCollection(int camType); void onObtainTargetDepthInformation(SubTask subTaskParams); void onLiftingPlatform(SubTask subTaskParams); + void onAutoFocus_TimedDataCollection(SubTask subTaskParams); void onStretchedImageReady(int fileNumber, const QString& filePath, QPixmap& pixmap); void onStretchProcessingError(int fileNumber, const QString& filePath, const QString& error); diff --git a/HPPA/TaskTreeModel.cpp b/HPPA/TaskTreeModel.cpp index 73e8fa9..cc0b382 100644 --- a/HPPA/TaskTreeModel.cpp +++ b/HPPA/TaskTreeModel.cpp @@ -131,70 +131,70 @@ QVariant TaskTreeModel::data(const QModelIndex& index, int role) const if (node->nodeType == TreeNodeType::Task && node->taskData) { const TimedTask& task = *node->taskData; switch (index.column()) { - case ColName: - return QString::fromLocal8Bit("定时任务 %1").arg(task.id); - case ColScheduledTime: - return task.scheduledTime.toString("yyyy-MM-dd HH:mm:ss"); - case ColCountdown: { - if (task.status == TaskStatus::Finished || task.status == TaskStatus::Running) - { - return QString::fromLocal8Bit("0"); + case ColName: + return QString::fromLocal8Bit("定时任务 %1").arg(task.id); + case ColScheduledTime: + return task.scheduledTime.toString("yyyy-MM-dd HH:mm:ss"); + case ColCountdown: { + if (task.status == TaskStatus::Finished || task.status == TaskStatus::Running) + { + return QString::fromLocal8Bit("0"); + } + qint64 seconds = QDateTime::currentDateTime().secsTo(task.scheduledTime); + if (seconds < 0) + { + return QString::fromLocal8Bit("已超时"); + } + return formatCountdown(seconds); } - qint64 seconds = QDateTime::currentDateTime().secsTo(task.scheduledTime); - if (seconds < 0) - { - return QString::fromLocal8Bit("已超时"); + case ColStartTime: + return task.startTime.isValid() ? + task.startTime.toString("HH:mm:ss") : "-"; + case ColEndTime: + return task.endTime.isValid() ? + task.endTime.toString("HH:mm:ss") : "-"; + case ColDuration: + return formatDuration(task.durationMinutes); + case ColEstimatedDuration: + return formatDuration(task.estimatedDurationMinutes); + case ColStatus: + return statusToString(task.status); + case ColProgress: { + int finished = 0; + for (const auto& sub : task.subTasks) { + if (sub.status == TaskStatus::Finished) finished++; + } + return QString("%1/%2").arg(finished).arg(task.subTasks.size()); } - return formatCountdown(seconds); - } - case ColStartTime: - return task.startTime.isValid() ? - task.startTime.toString("HH:mm:ss") : "-"; - case ColEndTime: - return task.endTime.isValid() ? - task.endTime.toString("HH:mm:ss") : "-"; - case ColDuration: - return formatDuration(task.durationMinutes); - case ColEstimatedDuration: - return formatDuration(task.estimatedDurationMinutes); - case ColStatus: - return statusToString(task.status); - case ColProgress: { - int finished = 0; - for (const auto& sub : task.subTasks) { - if (sub.status == TaskStatus::Finished) finished++; - } - return QString("%1/%2").arg(finished).arg(task.subTasks.size()); - } - case ColPath: - return task.savePath; + case ColPath: + return task.savePath; } } else if (node->nodeType == TreeNodeType::SubTask && node->subTaskData) { const SubTask& subTask = *node->subTaskData; switch (index.column()) { - case ColName: - return subTaskTypeToString(subTask.type); - case ColScheduledTime: - return "-"; - case ColCountdown: - return "-"; - case ColStartTime: - return subTask.startTime.isValid() ? - subTask.startTime.toString("HH:mm:ss") : "-"; - case ColEndTime: - return subTask.endTime.isValid() ? - subTask.endTime.toString("HH:mm:ss") : "-"; - case ColDuration: - return formatDuration(subTask.durationMinutes); - case ColEstimatedDuration: - return formatDuration(subTask.estimatedDurationMinutes); - case ColStatus: - return statusToString(subTask.status); - case ColProgress: - return "-"; - case ColPath: - return "-"; + case ColName: + return subTaskTypeToString(subTask.type); + case ColScheduledTime: + return "-"; + case ColCountdown: + return "-"; + case ColStartTime: + return subTask.startTime.isValid() ? + subTask.startTime.toString("HH:mm:ss") : "-"; + case ColEndTime: + return subTask.endTime.isValid() ? + subTask.endTime.toString("HH:mm:ss") : "-"; + case ColDuration: + return formatDuration(subTask.durationMinutes); + case ColEstimatedDuration: + return formatDuration(subTask.estimatedDurationMinutes); + case ColStatus: + return statusToString(subTask.status); + case ColProgress: + return "-"; + case ColPath: + return "-"; } } } diff --git a/HPPA/TimedDataCollection.cpp b/HPPA/TimedDataCollection.cpp index 68531de..746ffe7 100644 --- a/HPPA/TimedDataCollection.cpp +++ b/HPPA/TimedDataCollection.cpp @@ -114,6 +114,7 @@ void TimedDataCollection::setupConnections() connect(m_scheduler, &TaskScheduler::ObtainingDepthInformationSignals, this, &TimedDataCollection::ObtainingDepthInformationSignals); connect(m_scheduler, &TaskScheduler::LiftingPlatformSignals, this, &TimedDataCollection::LiftingPlatformSignals); + connect(m_scheduler, &TaskScheduler::AutoFocusSignals, this, &TimedDataCollection::AutoFocusSignals); connect(m_scheduler, &TaskScheduler::switchHalogenLampSignal, this, &TimedDataCollection::switchHalogenLampSignal); @@ -419,6 +420,7 @@ void TimedDataCollection::readTimedTaskFromFile(const QString& filePath) double totalEstimatedMinutes = 0.0; for (int j = 0; j < loadedTasks[i].subTasks.size(); ++j) { + loadedTasks[i].subTasks[j].durationMinutes = 0.0; // 初始化实际耗时为0 QString pathLineFilePath = loadedTasks[i].subTasks[j].pathLineFilePath; if (!pathLineFilePath.isEmpty()) { @@ -429,6 +431,7 @@ void TimedDataCollection::readTimedTaskFromFile(const QString& filePath) } double slrTimeMinute = 135 / 60; loadedTasks[i].estimatedDurationMinutes = totalEstimatedMinutes + loadedTasks[i].HalogenLampPreheatingTime_Minute + slrTimeMinute; + loadedTasks[i].durationMinutes = 0.0; // 初始化实际耗时为0 } m_taskModel->setTasks(loadedTasks); diff --git a/HPPA/TimedDataCollection.h b/HPPA/TimedDataCollection.h index 020b95b..c57c494 100644 --- a/HPPA/TimedDataCollection.h +++ b/HPPA/TimedDataCollection.h @@ -54,6 +54,7 @@ Q_SIGNALS: void ObtainingDepthInformationSignals(SubTask info); void LiftingPlatformSignals(SubTask info); + void AutoFocusSignals(SubTask info); void switchHalogenLampSignal(int state); void switchD65LampSignal(int state); diff --git a/HPPA/TimedDataCollectionDataStructures.cpp b/HPPA/TimedDataCollectionDataStructures.cpp index 7894a42..9f5be95 100644 --- a/HPPA/TimedDataCollectionDataStructures.cpp +++ b/HPPA/TimedDataCollectionDataStructures.cpp @@ -121,6 +121,23 @@ SubTaskType TimedDataCollectionDataStructuresReaderWriter::stringToSubTaskType(c return SubTaskType::SingleLensReflex; } +QString TimedDataCollectionDataStructuresReaderWriter::hyperImagerTypeToString(HyperImagerType type) +{ + switch (type) { + case HyperImagerType::Pika_L: return "Pika_L"; + case HyperImagerType::Pika_NIR: return "Pika_NIR"; + default: return "Unknown"; + } +} + +HyperImagerType TimedDataCollectionDataStructuresReaderWriter::stringToHyperImagerType(const QString& str) +{ + if (str == "Pika_L") return HyperImagerType::Pika_L; + if (str == "Pika_NIR") return HyperImagerType::Pika_NIR; + + return HyperImagerType::Pika_L; +} + // ==================== SubTask序列化 ==================== QJsonObject TimedDataCollectionDataStructuresReaderWriter::subTaskToJson(const SubTask& subTask) @@ -138,6 +155,7 @@ QJsonObject TimedDataCollectionDataStructuresReaderWriter::subTaskToJson(const S obj["defaultRenderBand"] = subTask.defaultRenderBand; obj["captureIntervalSeconds"] = subTask.captureIntervalSeconds; + obj["autoFocusHyperImagerType"] = hyperImagerTypeToString(subTask.autoFocusHyperImagerType); obj["autoFocusMotorConfigFilePath"] = subTask.autoFocusMotorConfigFilePath; obj["autoFocusX"] = subTask.autoFocusX; obj["autoFocusY"] = subTask.autoFocusY; @@ -164,6 +182,7 @@ bool TimedDataCollectionDataStructuresReaderWriter::jsonToSubTask(const QJsonObj subTask.defaultRenderBand = json["defaultRenderBand"].toInt(); subTask.captureIntervalSeconds = json["captureIntervalSeconds"].toDouble(); + subTask.autoFocusHyperImagerType = stringToHyperImagerType(json["autoFocusHyperImagerType"].toString()); subTask.autoFocusMotorConfigFilePath = json["autoFocusMotorConfigFilePath"].toString(); subTask.autoFocusX = json["autoFocusX"].toDouble(); subTask.autoFocusY = json["autoFocusY"].toDouble(); @@ -466,84 +485,102 @@ void TaskExecutor::executeNextSubTask() switch (subTask.type) { - case SubTaskType::ObtainingDepthInformation: - { - //(1)移动到指定位置并通过深度相机获取深度信息(2)调整升降板高度(白板+调焦板)(3)回到零位(0,0) - emit switchD65LampSignal(1); - emit ObtainingDepthInformationSignals(subTask); - break; - } - case SubTaskType::AutoFocus: - { - //先判断高光谱相机类型,然后发送相机参数hyperCamParm连接相机 + case SubTaskType::ObtainingDepthInformation: + { + //(1)移动到指定位置并通过深度相机获取深度信息(2)调整升降板高度(白板+调焦板)(3)回到零位(0,0) + emit switchD65LampSignal(1); + emit ObtainingDepthInformationSignals(subTask); + break; + } + case SubTaskType::AutoFocus: + { + switch (subTask.autoFocusHyperImagerType) + { + case HyperImagerType::Pika_L: + m_camType = 0; + m_currentFolder = makeSubTaskDataFolder("L"); + emit hyperCamParm(m_camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "L"); - //执行自动调焦任务 - break; - } - case SubTaskType::LiftingPlatform: - { - //执行升降平台任务 - emit LiftingPlatformSignals(subTask); - break; - } - case SubTaskType::HyperSpectual400_1000nm: - { - m_camType = 0; - m_currentFolder = makeSubTaskDataFolder("L"); - emit hyperCamParm(m_camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "L"); + break; + case HyperImagerType::Pika_NIR: + m_camType = 1; + m_currentFolder = makeSubTaskDataFolder("NIR"); + emit hyperCamParm(m_camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "NIR"); - emit motorParm(subTask.pathLineFilePath); + break; + default: + break; + } + emit switchHalogenLampSignal(1); - // 打开卤素灯预热 - emit switchHalogenLampSignal(1); - printMsgAndTime("open HalogenLamp"); - double sleepTimeSecond = m_task.HalogenLampPreheatingTime_Minute * 60; - QTimer::singleShot(sleepTimeSecond * 1000, this, &TaskExecutor::emitRecordSignal); + //执行自动调焦任务 + QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitAutoFocusSignal); + break; + } + case SubTaskType::LiftingPlatform: + { + //执行升降平台任务 + emit LiftingPlatformSignals(subTask); + break; + } + case SubTaskType::HyperSpectual400_1000nm: + { + m_camType = 0; + m_currentFolder = makeSubTaskDataFolder("L"); + emit hyperCamParm(m_camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "L"); - break; - } - case SubTaskType::HyperSpectual1000_1700nm: - { - m_camType = 1; - m_currentFolder = makeSubTaskDataFolder("NIR"); - emit hyperCamParm(m_camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "NIR"); + emit motorParm(subTask.pathLineFilePath); - emit motorParm(subTask.pathLineFilePath); + // 打开卤素灯预热 + emit switchHalogenLampSignal(1); + printMsgAndTime("open HalogenLamp"); + double sleepTimeSecond = m_task.HalogenLampPreheatingTime_Minute * 60; + QTimer::singleShot(sleepTimeSecond * 1000, this, &TaskExecutor::emitRecordSignal); - QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitRecordSignal); + break; + } + case SubTaskType::HyperSpectual1000_1700nm: + { + m_camType = 1; + m_currentFolder = makeSubTaskDataFolder("NIR"); + emit hyperCamParm(m_camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "NIR"); - break; - } - case SubTaskType::SingleLensReflex: - { - m_camType = 2; - m_currentFolder = makeSubTaskDataFolder("SLR"); - emit camParm(m_camType, 3, m_currentFolder); + emit motorParm(subTask.pathLineFilePath); - emit motorParm(subTask.pathLineFilePath); + QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitRecordSignal); - emit switchD65LampSignal(1); + break; + } + case SubTaskType::SingleLensReflex: + { + m_camType = 2; + m_currentFolder = makeSubTaskDataFolder("SLR"); + emit camParm(m_camType, 3, m_currentFolder); - emit switchSlrSignal(1); + emit motorParm(subTask.pathLineFilePath); - QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitRecordSignal); + emit switchD65LampSignal(1); - break; - } - case SubTaskType::DepthCamera: - { - m_camType = 3; - m_currentFolder = makeSubTaskDataFolder("DepthCamera"); - emit camParm(m_camType, 3, m_currentFolder); + emit switchSlrSignal(1); - emit motorParm(subTask.pathLineFilePath); + QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitRecordSignal); - emit switchD65LampSignal(1); + break; + } + case SubTaskType::DepthCamera: + { + m_camType = 3; + m_currentFolder = makeSubTaskDataFolder("DepthCamera"); + emit camParm(m_camType, 3, m_currentFolder); - QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitRecordSignal); + emit motorParm(subTask.pathLineFilePath); - break; - } + emit switchD65LampSignal(1); + + QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitRecordSignal); + + break; + } } ensurePreTaskLighting(); } @@ -553,6 +590,12 @@ void TaskExecutor::emitRecordSignal() emit startRecordSignal(m_camType); } +void TaskExecutor::emitAutoFocusSignal() +{ + SubTask& subTask = m_task.subTasks[m_currentSubTaskIndex]; + emit AutoFocusSignals(subTask); +} + // ==================== TaskScheduler 实现 ==================== TaskScheduler::TaskScheduler(QObject* parent) @@ -729,6 +772,7 @@ void TaskScheduler::executeTask(TimedTask& task) connect(m_currentExecutor, &TaskExecutor::ObtainingDepthInformationSignals, this, &TaskScheduler::ObtainingDepthInformationSignals); connect(m_currentExecutor, &TaskExecutor::LiftingPlatformSignals, this, &TaskScheduler::LiftingPlatformSignals); + connect(m_currentExecutor, &TaskExecutor::AutoFocusSignals, this, &TaskScheduler::AutoFocusSignals); connect(m_currentExecutor, &TaskExecutor::switchHalogenLampSignal, this, &TaskScheduler::switchHalogenLampSignal); connect(m_currentExecutor, &TaskExecutor::switchD65LampSignal, this, &TaskScheduler::switchD65LampSignal); diff --git a/HPPA/TimedDataCollectionDataStructures.h b/HPPA/TimedDataCollectionDataStructures.h index 6e66b51..4d9be2b 100644 --- a/HPPA/TimedDataCollectionDataStructures.h +++ b/HPPA/TimedDataCollectionDataStructures.h @@ -30,6 +30,10 @@ enum class SubTaskType { AutoFocus, // 自动对焦 LiftingPlatform // 升降平台 }; +enum class HyperImagerType { + Pika_L, + Pika_NIR +}; // ==================== 统一子任务封装 ==================== @@ -58,6 +62,7 @@ struct SubTask { double percentageOfEffectiveArea = 50.0; //深度图像的有效范围百分比 //高光谱自动调焦 + HyperImagerType autoFocusHyperImagerType;//取值范围:L、NIR QString autoFocusMotorConfigFilePath;//马达配置文件 double autoFocusX = 0.0; double autoFocusY = 0.0; @@ -124,6 +129,9 @@ private: static QString subTaskTypeToString(SubTaskType type); static SubTaskType stringToSubTaskType(const QString& str); + + static QString hyperImagerTypeToString(HyperImagerType type); + static HyperImagerType stringToHyperImagerType(const QString& str); }; // ==================== 任务执行器 ==================== @@ -168,6 +176,7 @@ signals: void ObtainingDepthInformationSignals(SubTask info); void LiftingPlatformSignals(SubTask info); + void AutoFocusSignals(SubTask info); void switchHalogenLampSignal(int state); void switchD65LampSignal(int state); @@ -179,6 +188,7 @@ public slots: void onError(const QString& error); void emitRecordSignal(); + void emitAutoFocusSignal(); private: QString m_currentFolder; @@ -240,6 +250,7 @@ signals: void ObtainingDepthInformationSignals(SubTask info); void LiftingPlatformSignals(SubTask info); + void AutoFocusSignals(SubTask info); void switchHalogenLampSignal(int state); void switchD65LampSignal(int state); diff --git a/HPPA/TwoMotorControl.cpp b/HPPA/TwoMotorControl.cpp index 90596bd..e722e06 100644 --- a/HPPA/TwoMotorControl.cpp +++ b/HPPA/TwoMotorControl.cpp @@ -232,6 +232,25 @@ void TwoMotorControl::run4_ObtainTargetDepthInfo(DepthCameraWindow* window, int m_ObtainTargetDepthInfoCoordinator->moveToTarget(depthInfoX, depthInfoY, xmotor_move_speed, ymotor_move_speed); } +void TwoMotorControl::run5_AutoFocus(double autoFocusX, double autoFocusY) +{ + m_focusWindow = new focusWindow(this, m_Imager); + m_focusWindow->onConnectMotor(); + m_focusWindow->show(); + + //自动调焦的协调器添加功能:先归零 + m_autoFocusCoordinator = new TwoMotor1PosCoordinator(m_multiAxisController); + connect(m_autoFocusCoordinator, &TwoMotor1PosCoordinator::ArrivalSignal, m_focusWindow, &focusWindow::onAutoFocus); + connect(m_focusWindow, &focusWindow::AutoFocusFinishedSignal, m_autoFocusCoordinator, &TwoMotor1PosCoordinator::back2origin); + connect(m_focusWindow, &focusWindow::AutoFocusFinishedSignal, this, &TwoMotorControl::sequenceComplete, Qt::UniqueConnection); + connect(m_autoFocusCoordinator, &TwoMotor1PosCoordinator::back2OriginSignal, this, &TwoMotorControl::onBack2Origin4); + + + double xmotor_move_speed = ui.xmotor_move_speed_lineEdit->text().toDouble(); + double ymotor_move_speed = ui.ymotor_move_speed_lineEdit->text().toDouble(); + m_autoFocusCoordinator->moveToTarget(autoFocusX, autoFocusY, xmotor_move_speed, ymotor_move_speed); +} + void TwoMotorControl::saveDepthValue(double depthValue) { if (m_depthType == 0)//0表示植被深度,1表示白板/调焦版深度 @@ -251,6 +270,16 @@ void TwoMotorControl::onBack2Origin3() emit back2OriginSignal_TimedDataCollection(); } +void TwoMotorControl::onBack2Origin4() +{ + m_focusWindow->deleteLater(); + m_focusWindow = nullptr; + + m_autoFocusCoordinator->deleteLater(); + m_autoFocusCoordinator = nullptr; + emit back2OriginSignal_TimedDataCollection(); +} + void TwoMotorControl::run() { if (getState()) diff --git a/HPPA/TwoMotorControl.h b/HPPA/TwoMotorControl.h index 4d27bb4..355471a 100644 --- a/HPPA/TwoMotorControl.h +++ b/HPPA/TwoMotorControl.h @@ -17,6 +17,8 @@ #include "DepthValueLogger.h" +#include "focusWindow.h" + #define PI 3.1415926 class TwoMotorControl : public QDialog, public MotorWindowBase @@ -85,9 +87,11 @@ public Q_SLOTS: void run2(SingleLensReflexCameraWindow* w); void run3(DepthCameraWindow* window); void run4_ObtainTargetDepthInfo(DepthCameraWindow* window, int depthType, double depthInfoX, double depthInfoY, int averageNumberOfTimes, double percentageOfEffectiveArea); + void run5_AutoFocus(double autoFocusX, double autoFocusY); void onBack2Origin2(); void saveDepthValue(double depthValue); void onBack2Origin3(); + void onBack2Origin4(); void stop_record(); @@ -117,6 +121,7 @@ private: TwoMotionCaptureCoordinator* m_coordinator = nullptr; TwoMotionCaptureCoordinator* m_coordinator_TimedDataCollection = nullptr; TwoMotor1PosCoordinator* m_ObtainTargetDepthInfoCoordinator = nullptr; + TwoMotor1PosCoordinator* m_autoFocusCoordinator = nullptr; DarkAndWhiteCaptureCoordinator* m_darkCaptureCoordinator = nullptr; DarkAndWhiteCaptureCoordinator* m_whiteCaptureCoordinator = nullptr; @@ -125,4 +130,6 @@ private: IrisMultiMotorController* m_multiAxisController = nullptr; int m_depthType; + + focusWindow* m_focusWindow = nullptr; }; diff --git a/HPPA/focusWindow.cpp b/HPPA/focusWindow.cpp index 56accca..9bd7383 100644 --- a/HPPA/focusWindow.cpp +++ b/HPPA/focusWindow.cpp @@ -299,7 +299,7 @@ void focusWindow::connectMotor(bool isNotification)//需要修改这个函数 if (m_coordinator) { disconnect(&m_MotionCaptureCoordinatorThread, SIGNAL(finished()), m_coordinator, SLOT(deleteLater())); - disconnect(this, SIGNAL(startStepMotion(double, int, double, double)), m_coordinator, SLOT(startStepMotion(double, int, double, double))); + disconnect(this, SIGNAL(startStepMotionSignal(double, int, double, double)), m_coordinator, SLOT(startStepMotion(double, int, double, double))); disconnect(m_coordinator, SIGNAL(progressChanged(int)), this, SLOT(onAutoFocusProgress(int))); disconnect(m_coordinator, SIGNAL(sequenceComplete()), this, SLOT(onAutoFocusFinished())); @@ -343,7 +343,7 @@ void focusWindow::connectMotor(bool isNotification)//需要修改这个函数 m_coordinator = new MotionCaptureCoordinator(m_multiAxisController, m_Imager); m_coordinator->moveToThread(&m_MotionCaptureCoordinatorThread); connect(&m_MotionCaptureCoordinatorThread, SIGNAL(finished()), m_coordinator, SLOT(deleteLater())); - connect(this, SIGNAL(startStepMotion(double, int, double, double)), m_coordinator, SLOT(startStepMotion(double, int, double, double))); + connect(this, SIGNAL(startStepMotionSignal(double, int, double, double)), m_coordinator, SLOT(startStepMotion(double, int, double, double))); connect(m_coordinator, SIGNAL(progressChanged(int)), this, SLOT(onAutoFocusProgress(int))); connect(m_coordinator, SIGNAL(sequenceComplete()), this, SLOT(onAutoFocusFinished())); m_MotionCaptureCoordinatorThread.start(); @@ -475,7 +475,7 @@ void focusWindow::onAutoFocus() //获取马达最大位置 std::vector maxRangeLocations = m_multiAxisController->getMaxPos(); double maxPos = maxRangeLocations[0]; - emit startStepMotion(m_dSpeed, m_iStepSize, 0, maxPos); + emit startStepMotionSignal(m_dSpeed, m_iStepSize, 0, maxPos); } else { @@ -649,26 +649,48 @@ void focusWindow::moveAfterAutoFocus(int motorID, double location) std::cout << "\n已经到达位置:" << location << std::endl; - double tmp = abs(location - m_goodPos) / m_goodPos * 100; - if (tmp < 5 || m_goodPos == 0) + double errorRate = getErrorRate(m_goodPos, location); + if (errorRate < 5|| m_moveRetryCount > MAX_MOVE_RETRY) { m_isMoveAfterAutoFocus = false; + m_moveRetryCount = 0; if (!m_isAutoFocusSuccess) { - showMessageBox(QString::fromLocal8Bit("纹理较弱,自动调焦效果不佳!请使用调焦纸进行自动调焦!")); + qDebug() << "纹理较弱,自动调焦效果不佳!请使用调焦纸进行自动调焦!"; + //showMessageBox(QString::fromLocal8Bit("纹理较弱,自动调焦效果不佳!请使用调焦纸进行自动调焦!")); } else { - showMessageBox(QString::fromLocal8Bit("自动调焦成功!")); + qDebug() << "自动调焦成功!"; + //showMessageBox(QString::fromLocal8Bit("自动调焦成功!")); } + emit AutoFocusFinishedSignal(0); } else { + m_moveRetryCount++; + qDebug() << "自动调焦后目标马达位置,重试次数:" << m_moveRetryCount; //移动马达到最佳位置 emit move2LocSignal(0, (double)m_goodPos, m_dSpeed, 1000); } } +double focusWindow::getErrorRate(double targetLoc, double actualLoc) +{ + double targetLocTmp; + if (targetLoc == 0) + { + targetLocTmp = 0.001; + } + else + { + targetLocTmp = targetLoc; + } + double errorRate = abs(targetLoc - actualLoc) / targetLocTmp * 100; + + return errorRate; +} + void focusWindow::getGaussianInitParam(const std::vector& pos, const std::vector& index, double& a_init, double& mu_init, double& sigma_init, double& c_init) { auto minmax_element = std::minmax_element(index.begin(), index.end()); @@ -819,11 +841,15 @@ MotionCaptureCoordinator::MotionCaptureCoordinator( , m_currentPos(0) , m_endPos(0) , m_isRunning(false) + , m_isZeroing(false) { //这些信号槽是按照逻辑顺序的 connect(this, SIGNAL(moveTo(int, double, double, int)), m_motorCtrl, SLOT(moveTo(int, double, double, int))); + connect(this, &MotionCaptureCoordinator::zeroStart, + m_motorCtrl, &IrisMultiMotorController::zeroStart); + connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal, this, &MotionCaptureCoordinator::handlePositionReached); //connect(m_motorCtrl, &IrisMultiMotorController::moveFailed, @@ -860,15 +886,37 @@ void MotionCaptureCoordinator::startStepMotion(double speed, int stepInterval, d m_speed = speed; m_iStepInterval = stepInterval; m_iStepIntervalRealTime = 1; - m_currentPos = startPos; + m_startPos = startPos; m_endPos = endPos; m_posInternal = (endPos - startPos) / stepInterval; m_isRunning = true; + m_isZeroing = true; + + // 先执行归零操作 + emit zeroStart(0); + qDebug() << "MotionCaptureCoordinator::startStepMotion: Zeroing started."; +} + +void MotionCaptureCoordinator::startMotionSequence() +{ + QMutexLocker locker(&m_dataMutex); + + m_currentPos = m_startPos; + m_isZeroing = false; + qDebug() << "MotionCaptureCoordinator::startMotionSequence: Zeroing complete. Starting motion sequence."; processNextPosition(); } +void MotionCaptureCoordinator::handleZeroComplete(int motorID, double pos) +{ + if (!m_isRunning || !m_isZeroing) return; + + // 归零完成,开始分步运动 + startMotionSequence(); +} + void MotionCaptureCoordinator::stopStepMotion() { QMutexLocker locker(&m_dataMutex); @@ -911,6 +959,13 @@ void MotionCaptureCoordinator::handlePositionReached(int motorID, double pos) { if (!m_isRunning) return; + // 如果正在等待归零完成,调用归零完成处理 + if (m_isZeroing) + { + handleZeroComplete(motorID, pos); + return; + } + QMutexLocker locker(&m_dataMutex); //验证马达运动位置是否到达指定位置 diff --git a/HPPA/focusWindow.h b/HPPA/focusWindow.h index 5893fb9..52c1768 100644 --- a/HPPA/focusWindow.h +++ b/HPPA/focusWindow.h @@ -70,14 +70,17 @@ signals: void errorOccurred(const QString& error); void moveTo(int, double, double, int); void getFocusIndexSobel(); + void zeroStart(int motorID); private slots: void handlePositionReached(int motorID, double pos); void handleCaptureComplete(double index); void handleError(const QString& error); + void handleZeroComplete(int motorID, double pos); private: void processNextPosition(); + void startMotionSequence(); IrisMultiMotorController* m_motorCtrl; ImagerOperationBase* m_cameraCtrl; @@ -86,6 +89,7 @@ private: double m_posInternal; double m_currentPos; + double m_startPos; double m_endPos; bool m_isRunning; double m_speed; @@ -93,6 +97,7 @@ private: int m_iStepInterval; int m_iStepIntervalRealTime; int m_counter; + bool m_isZeroing; }; class focusWindow:public QDialog @@ -134,6 +139,8 @@ private: double m_goodPos; bool m_isAutoFocusSuccess; bool m_isMoveAfterAutoFocus = false; + int m_moveRetryCount = 0; + static constexpr int MAX_MOVE_RETRY = 3; void getGaussianInitParam(const std::vector& pos, const std::vector& index, double& a_init, double& mu_init, double& sigma_init, double& c_init); void gaussian_fit(const std::vector& x_data, const std::vector& y_data, double& a, double& mu, double& sigma, double& c); @@ -142,6 +149,8 @@ private: void connectMotor(bool isNotification); void showMessageBox(QString msg, QString title = QString::fromLocal8Bit("提示")); + + double getErrorRate(double targetLoc, double actualLoc); public Q_SLOTS: void onConnectMotor(); @@ -176,8 +185,10 @@ signals: void zeroStartSignal(int); void testConnectivitySignal(int, int); - void startStepMotion(double speed, int stepInterval = 100, double startPos = 0, double endPos = -1); + void startStepMotionSignal(double speed, int stepInterval = 100, double startPos = 0, double endPos = -1); void closeSignal(); + + void AutoFocusFinishedSignal(int status); }; class WorkerThread2 : public QThread