diff --git a/HPPA/CaptureCoordinator.cpp b/HPPA/CaptureCoordinator.cpp index f1d5510..95232f0 100644 --- a/HPPA/CaptureCoordinator.cpp +++ b/HPPA/CaptureCoordinator.cpp @@ -724,3 +724,158 @@ void DarkAndWhiteCaptureCoordinator::handleCaptureComplete(double index) { QMutexLocker locker(&m_dataMutex); } + + +TwoMotor1PosCoordinator::TwoMotor1PosCoordinator( + IrisMultiMotorController* motorCtrl, + QObject* parent) + : QObject(parent) + , m_motorCtrl(motorCtrl) + , m_isMoving2Target(false) + , m_isMoving2Origin(false) + , m_targetX(0) + , m_targetY(0) + , m_speedX(0) + , m_speedY(0) + , m_actualX(0) + , m_actualY(0) + , m_retryTimesX(0) + , m_retryTimesY(0) + , m_xReached(false) + , m_yReached(false) +{ + //因为IrisMultiMotorController::moveTo有多个重载版本,所以使用信号槽连接时需要使用SIGNAL和SLOT宏来指定参数类型,避免编译器无法推断出正确的函数签名。 + //connect(this, &TwoMotor1PosCoordinator::moveTo, m_motorCtrl, &IrisMultiMotorController::moveTo);//这行代码会报错,因为moveTo有多个重载版本,编译器无法推断出正确的函数签名。 + connect(this, SIGNAL(moveTo(int, double, double, int)), m_motorCtrl, SLOT(moveTo(int, double, double, int))); + connect(this, SIGNAL(moveTo(const std::vector, const std::vector, int)), m_motorCtrl, SLOT(moveTo(const std::vector, const std::vector, int))); + + + connect(this, &TwoMotor1PosCoordinator::stopMotorSignal, m_motorCtrl, &IrisMultiMotorController::stop); + + connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal, this, &TwoMotor1PosCoordinator::handlePositionReached); +} + +TwoMotor1PosCoordinator::~TwoMotor1PosCoordinator() +{ + +} + +void TwoMotor1PosCoordinator::moveToTarget(double xTarget, double yTarget, double xSpeed, double ySpeed) +{ + m_isMoving2Target = true; + m_isMoving2Origin = false; + + moveToTargetPrivate(xTarget, yTarget, xSpeed, ySpeed); +} + +void TwoMotor1PosCoordinator::back2origin() +{ + m_isMoving2Target = false; + m_isMoving2Origin = true; + + moveToTargetPrivate(0, 0, m_speedX, m_speedY); +} + +void TwoMotor1PosCoordinator::moveToTargetPrivate(double xTarget, double yTarget, double xSpeed, double ySpeed) +{ + m_targetX = xTarget; + m_targetY = yTarget; + m_speedX = xSpeed; + m_speedY = ySpeed; + + m_xReached = false; + m_yReached = false; + m_retryTimesX = 0; + m_retryTimesY = 0; + + std::vector loc = { m_targetX, m_targetY }; + std::vector speed = { m_speedX, m_speedY }; + + std::cout << "TwoMotor1PosCoordinator: moving to (" << m_targetX << ", " << m_targetY << ")" << std::endl; + emit moveTo(loc, speed, 1000); +} + +void TwoMotor1PosCoordinator::handlePositionReached(int motorID, double pos) +{ + if (!m_isMoving2Target && !m_isMoving2Origin) + { + return; + } + + double errorRateThreshold = 5; + if (motorID == 0) + { + m_actualX = pos; + + double errorRate = getErrorRate(m_targetX, m_actualX); + + if (errorRate > errorRateThreshold && m_retryTimesX < m_retryLimit) + { + m_retryTimesX++; + std::cout << "X motor retry " << m_retryTimesX << ", target: " << m_targetX << ", actual: " << m_actualX << std::endl; + emit moveTo(0, m_targetX, m_speedX, 1000); + return; + } + m_retryTimesX = 0; + m_xReached = true; + + std::cout << "X motor reached: " << m_actualX << std::endl; + } + else if (motorID == 1) + { + m_actualY = pos; + + double errorRate = getErrorRate(m_targetY, m_actualY); + if (errorRate > errorRateThreshold && m_retryTimesY < m_retryLimit) + { + m_retryTimesY++; + std::cout << "Y motor retry " << m_retryTimesY << ", target: " << m_targetY << ", actual: " << m_actualY << std::endl; + emit moveTo(1, m_targetY, m_speedY, 1000); + return; + } + m_retryTimesY = 0; + m_yReached = true; + + std::cout << "Y motor reached: " << m_actualY << std::endl; + } + + if (checkArrival()) + { + std::cout << "TwoMotor1PosCoordinator: Arrived at (" << m_actualX << ", " << m_actualY << ")" << std::endl; + + if (m_isMoving2Origin) + { + m_isMoving2Origin = false; + + emit back2OriginSignal(); + } + + if (m_isMoving2Target) + { + m_isMoving2Target = false; + + emit ArrivalSignal(m_actualX, m_actualY); + } + } +} + +double TwoMotor1PosCoordinator::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; +} + +bool TwoMotor1PosCoordinator::checkArrival() +{ + return m_xReached && m_yReached; +} diff --git a/HPPA/CaptureCoordinator.h b/HPPA/CaptureCoordinator.h index faf3dae..0a4a066 100644 --- a/HPPA/CaptureCoordinator.h +++ b/HPPA/CaptureCoordinator.h @@ -213,3 +213,55 @@ private: void getLocBeforeStart(); void move2LocBeforeStart(); }; + + +class TwoMotor1PosCoordinator : public QObject +{ + Q_OBJECT +public: + TwoMotor1PosCoordinator(IrisMultiMotorController* motorCtrl, + QObject* parent = nullptr); + ~TwoMotor1PosCoordinator(); + +public slots: + void moveToTarget(double xTarget, double yTarget, double xSpeed, double ySpeed); + void back2origin(); + +signals: + void ArrivalSignal(double xPos, double yPos); + void back2OriginSignal(); + void errorOccurred(const QString& error); + void moveTo(int, double, double, int); + void moveTo(const std::vector, const std::vector, int); + void stopMotorSignal(int axis); + +private slots: + void handlePositionReached(int motorID, double pos); + +private: + void moveToTargetPrivate(double xTarget, double yTarget, double xSpeed, double ySpeed); + double getErrorRate(double targetLoc, double actualLoc); + bool checkArrival(); + void move2Origin(); + + IrisMultiMotorController* m_motorCtrl; + mutable QMutex m_dataMutex; + + bool m_isMoving2Target; + bool m_isMoving2Origin; + + double m_targetX; + double m_targetY; + double m_speedX; + double m_speedY; + + double m_actualX; + double m_actualY; + + int m_retryLimit = 3; + int m_retryTimesX; + int m_retryTimesY; + + bool m_xReached; + bool m_yReached; +}; diff --git a/HPPA/DepthCameraWindow.cpp b/HPPA/DepthCameraWindow.cpp index e9ceb06..a1f9ef2 100644 --- a/HPPA/DepthCameraWindow.cpp +++ b/HPPA/DepthCameraWindow.cpp @@ -14,6 +14,7 @@ DepthCameraWindow::DepthCameraWindow(QWidget* parent) connect(ui.closeDepthCamera_btn, &QPushButton::clicked, this, &DepthCameraWindow::closeDepthCamera); connect(this, &DepthCameraWindow::openDepthCameraSignal, m_DepthCameraOperation, &DepthCameraOperation::OpenDepthCamera); + connect(this, &DepthCameraWindow::OpenDepthCamera_getDepthValueSignal, m_DepthCameraOperation, &DepthCameraOperation::OpenDepthCamera_getDepthValue); connect(m_DepthCameraOperation, &DepthCameraOperation::CamOpenedSignal, this, &DepthCameraWindow::onCamOpened); connect(m_DepthCameraOperation, &DepthCameraOperation::CamClosedSignal, this, &DepthCameraWindow::onCamClosed); @@ -66,6 +67,14 @@ void DepthCameraWindow::openDepthCamera() } } +void DepthCameraWindow::OpenDepthCamera_getDepthValue() +{ + if (!m_DepthCameraOperation->getRecordStatus()) + { + emit OpenDepthCamera_getDepthValueSignal(); + } +} + void DepthCameraWindow::onCamOpened() { ui.openDepthCamera_btn->setEnabled(false); @@ -279,6 +288,107 @@ void DepthCameraOperation::OpenDepthCamera() m_pipe = nullptr; } +void DepthCameraOperation::OpenDepthCamera_getDepthValue() +{ + if (m_pipe) + { + return; + } + m_pipe = new ob::Pipeline(); + + std::shared_ptr config = std::make_shared(); + + // Get device from pipeline. + auto device = m_pipe->getDevice(); + auto devInfo = device->getDeviceInfo(); + auto pid = devInfo->getPid(); + auto vid = devInfo->getVid(); + + config->enableVideoStream(OB_STREAM_DEPTH, 640, 480, 15, OB_FORMAT_Y16); + config->setFrameAggregateOutputMode(OB_FRAME_AGGREGATE_OUTPUT_ALL_TYPE_FRAME_REQUIRE); + + m_pipe->enableFrameSync(); + + m_pipe->start(config); + + // Drop several frames + for (int i = 0; i < 15; ++i) { + auto lost = m_pipe->waitForFrameset(m_captureIntervalMilliseconds); + } + + auto pointCloud = std::make_shared(); + + int frameIndex = 0; + record = true; + QString fileNamePrefix = AppSettings::instance().depthCameraDataFolder() + QDir::separator() + "Gemini336L"; + + double depthValue_all = 0.0; + for (size_t i = 0; i < m_averageNumberOfTimes; i++) + { + if(frameIndex==0) + { + emit CamOpenedSignal(); + std::cout << "Start recording..." << std::endl; + } + + auto frameSet = m_pipe->waitForFrameset(m_captureIntervalMilliseconds); + if (frameSet == nullptr) + { + std::cout << "No frames received in 100ms..." << std::endl; + continue; + } + + std::cout << "DepthCamera frameIndex:"<< frameIndex << std::endl; + + // 彩色和深度图像 + auto depthFrame = frameSet->getFrame(OB_FRAME_DEPTH)->as(); + + //是否需要保存深度图像???????? + //saveDepthFrame(depthFrame, frameIndex, fileNamePrefix.toStdString()); + + cv::Mat depthMat(depthFrame->height(), depthFrame->width(), CV_16UC1, depthFrame->data()); + + //裁剪边缘区域 + int cropRows = static_cast(depthMat.rows * (1 - m_percentageOfEffectiveArea) / 2); + int cropCols = static_cast(depthMat.cols * (1 - m_percentageOfEffectiveArea) / 2); + cv::Rect roi(cropCols, cropRows, + depthMat.cols - 2 * cropCols, + depthMat.rows - 2 * cropRows); + cv::Mat depthRoi = depthMat(roi); + + //计算平均深度值并累加 + cv::Scalar meanDepth = cv::mean(depthRoi); + double depthValue = meanDepth[0] / 1000.0; // 转换为米 + depthValue_all += depthValue; + std::cout << "Depth value: " << depthValue << " m, accumulated: " << depthValue_all << std::endl; + + cv::Mat depthMat8U; + depthMat.convertTo(depthMat8U, CV_8UC1, 255.0 / 4096.0); + cv::Mat depthColorMap; + cv::applyColorMap(depthMat8U, depthColorMap, cv::COLORMAP_JET); + cv::Mat depthRgbMat; + cv::cvtColor(depthColorMap, depthRgbMat, cv::COLOR_BGR2RGB); + m_depthImage = QImage(depthRgbMat.data, depthRgbMat.cols, depthRgbMat.rows, static_cast(depthRgbMat.step), QImage::Format_RGB888).copy(); + //m_depthImage = QImage(depthMat.data, depthMat.cols, depthMat.rows, static_cast(depthMat.step), QImage::Format_Grayscale16).copy(); + + emit PlotSignal(); + + frameIndex++; + } + + //计算平均深度值 + double depthValue_avg = depthValue_all / m_averageNumberOfTimes; + std::cout << "Average depth value: " << depthValue_avg << " m" << std::endl; + emit DepthValueSignal(depthValue_avg); + + m_pipe->stop(); + + delete m_pipe; + m_pipe = nullptr; + + record = false; +} + void DepthCameraOperation::saveDepthFrame(const std::shared_ptr depthFrame, const uint32_t frameIndex, std::string fileNamePrefix_) { std::vector params; diff --git a/HPPA/DepthCameraWindow.h b/HPPA/DepthCameraWindow.h index 0053037..93bb823 100644 --- a/HPPA/DepthCameraWindow.h +++ b/HPPA/DepthCameraWindow.h @@ -35,6 +35,9 @@ public: void setCaptureInterval(int captureIntervalSeconds); + void setAverageNumberOfTimes(double averageNumberOfTimes) { m_averageNumberOfTimes = averageNumberOfTimes; } + void setPercentageOfEffectiveArea(double percentageOfEffectiveArea) { m_percentageOfEffectiveArea = percentageOfEffectiveArea; } + private: ob::Pipeline* m_pipe; cv::Mat frame; @@ -50,13 +53,18 @@ private: int m_captureIntervalMilliseconds; + double m_averageNumberOfTimes; + double m_percentageOfEffectiveArea; + public slots: void OpenDepthCamera(); + void OpenDepthCamera_getDepthValue(); void OpenDepthCamera_callback();//不使用信号而使用回调函数来通知界面刷新视频 void CloseDepthCamera(); signals: void PlotSignal(); + void DepthValueSignal(double depthValue); void CamOpenedSignal(); void CamClosedSignal(); @@ -77,6 +85,7 @@ public: public Q_SLOTS: void openDepthCamera(); + void OpenDepthCamera_getDepthValue(); void onCamOpened(); void closeDepthCamera(); void onCamClosed(); @@ -84,9 +93,10 @@ public Q_SLOTS: void onSelectDataFolder(); signals: -void openDepthCameraSignal(); -void PlotDepthImageSignal(); -void DepthCamClosedSignal(); + void openDepthCameraSignal(); + void OpenDepthCamera_getDepthValueSignal(); + void PlotDepthImageSignal(); + void DepthCamClosedSignal(); private: Ui::DepthCameraClass ui; diff --git a/HPPA/HPPA.cpp b/HPPA/HPPA.cpp index 0ab5799..3dc38fc 100644 --- a/HPPA/HPPA.cpp +++ b/HPPA/HPPA.cpp @@ -666,6 +666,8 @@ void HPPA::initTimedDataCollection() connect(m_tdc, &TimedDataCollection::motorParm, this, &HPPA::setTimedDataCollectionMotorParm); connect(m_tdc, &TimedDataCollection::startRecordSignal, this, &HPPA::onStartTimedDataCollection); + connect(m_tdc, &TimedDataCollection::ObtainingDepthInformationSignals, this, &HPPA::onObtainTargetDepthInformation); + connect(m_tdc, &TimedDataCollection::switchHalogenLampSignal, m_pc3D, &PowerControl3D::switchHalogenLampPower); connect(m_tdc, &TimedDataCollection::switchD65LampSignal, m_pc3D, &PowerControl3D::switchD65LampPower); connect(m_tdc, &TimedDataCollection::switchSlrSignal, m_pc3D, &PowerControl3D::switchSlrPower); @@ -772,6 +774,11 @@ void HPPA::onStartTimedDataCollection(int camType) } } +void HPPA::onObtainTargetDepthInformation(SubTask subTaskParams) +{ + m_tmc->run4_ObtainTargetDepthInfo(m_depthCameraWindow, subTaskParams.depthInfoX, subTaskParams.depthInfoY, subTaskParams.averageNumberOfTimes, subTaskParams.percentageOfEffectiveArea); +} + void HPPA::onTimedDataCollection() { QAction* checkedScenario = m_ScenarioActionGroup->checkedAction(); diff --git a/HPPA/HPPA.h b/HPPA/HPPA.h index 43c20a2..973559d 100644 --- a/HPPA/HPPA.h +++ b/HPPA/HPPA.h @@ -449,6 +449,7 @@ public Q_SLOTS: void setTimedDataCollectionCamParm(int camType, int captureIntervalSeconds, QString folder); void setTimedDataCollectionMotorParm(QString pathLineFilePath); void onStartTimedDataCollection(int camType); + void onObtainTargetDepthInformation(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/HPPA.vcxproj.filters b/HPPA/HPPA.vcxproj.filters index a8980ad..5a882a7 100644 --- a/HPPA/HPPA.vcxproj.filters +++ b/HPPA/HPPA.vcxproj.filters @@ -21,6 +21,24 @@ {639EADAA-A684-42e4-A9AD-28FC9BCB8F7C} ts + + {3777a3c2-8d8a-4414-b6c9-ac20640f7b2e} + + + {ea004f0d-34de-4b29-8ce2-57dd8aa01c03} + + + {25329ee3-f78c-4dd9-9170-e64ccb4ccd9e} + + + {18072152-2a29-4ad8-be97-d097af97eeec} + + + {b3f08410-c140-42db-bcfd-24efba860cfb} + + + {205ec088-0286-42ca-862c-2870928a46f5} + @@ -70,9 +88,6 @@ Source Files - - Source Files - Source Files @@ -88,12 +103,6 @@ Source Files - - Source Files - - - Source Files - Source Files @@ -139,21 +148,6 @@ Source Files - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - Source Files @@ -175,12 +169,6 @@ Source Files - - Source Files - - - Source Files - Source Files @@ -226,18 +214,9 @@ Source Files - - Source Files - Source Files - - Source Files - - - Source Files - Source Files @@ -247,9 +226,6 @@ Source Files - - Source Files - Source Files @@ -265,6 +241,48 @@ Source Files + + Source Files\TimedDataCollection + + + Source Files\TimedDataCollection + + + Source Files\TimedDataCollection + + + Source Files\LayerTree + + + Source Files\LayerTree + + + Source Files\LayerTree + + + Source Files\LayerTree + + + Source Files\LayerTree + + + Source Files\LayerTree + + + Source Files\LayerTree + + + Source Files\LayerTree + + + Source Files\hyperImagerCtl + + + Source Files\hyperImagerCtl + + + Source Files\hyperImagerCtl + @@ -291,18 +309,12 @@ Header Files - - Header Files - Header Files Header Files - - Header Files - Header Files @@ -339,21 +351,6 @@ Header Files - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - Header Files @@ -363,9 +360,6 @@ Header Files - - Header Files - Header Files @@ -405,15 +399,6 @@ Header Files - - Header Files - - - Header Files - - - Header Files - Header Files @@ -423,9 +408,6 @@ Header Files - - Header Files - Header Files @@ -435,6 +417,42 @@ Header Files + + Header Files\TimedDataCollection + + + Header Files\TimedDataCollection + + + Header Files\TimedDataCollection + + + Header Files\LayerTree + + + Header Files\LayerTree + + + Header Files\LayerTree + + + Header Files\LayerTree + + + Header Files\LayerTree + + + Header Files\LayerTree + + + Header Files\LayerTree + + + Header Files\hyperImagerCtl + + + Header Files\hyperImagerCtl + @@ -455,9 +473,6 @@ Header Files - - Header Files - Header Files @@ -482,9 +497,6 @@ Header Files - - Header Files - Header Files @@ -497,6 +509,12 @@ Header Files + + Header Files\LayerTree + + + Header Files\hyperImagerCtl + diff --git a/HPPA/TaskTreeModel.cpp b/HPPA/TaskTreeModel.cpp index 2973124..ed978fa 100644 --- a/HPPA/TaskTreeModel.cpp +++ b/HPPA/TaskTreeModel.cpp @@ -588,10 +588,12 @@ QString TaskTreeModel::statusToString(TaskStatus status) const QString TaskTreeModel::subTaskTypeToString(SubTaskType type) const { switch (type) { - case SubTaskType::HyperSpectual400_1000nm: return QString::fromLocal8Bit("高光谱 400-1000nm"); - case SubTaskType::HyperSpectual1000_1700nm: return QString::fromLocal8Bit("高光谱 1000-1700nm"); - case SubTaskType::SingleLensReflex: return QString::fromLocal8Bit("单反相机"); - case SubTaskType::DepthCamera: return QString::fromLocal8Bit("深度相机"); + case SubTaskType::HyperSpectual400_1000nm: return QString::fromLocal8Bit("高光谱 400-1000nm"); + case SubTaskType::HyperSpectual1000_1700nm: return QString::fromLocal8Bit("高光谱 1000-1700nm"); + case SubTaskType::SingleLensReflex: return QString::fromLocal8Bit("单反相机"); + case SubTaskType::DepthCamera: return QString::fromLocal8Bit("深度相机"); + case SubTaskType::ObtainingDepthInformation: return QString::fromLocal8Bit("探测深度信息"); + case SubTaskType::AutoFocus: return QString::fromLocal8Bit("自动调焦"); } return "未知类型"; } diff --git a/HPPA/TimedDataCollection.cpp b/HPPA/TimedDataCollection.cpp index 15c0c47..cd2f10e 100644 --- a/HPPA/TimedDataCollection.cpp +++ b/HPPA/TimedDataCollection.cpp @@ -112,6 +112,8 @@ void TimedDataCollection::setupConnections() connect(m_scheduler, &TaskScheduler::startRecordSignal, this, &TimedDataCollection::startRecordSignal); + connect(m_scheduler, &TaskScheduler::ObtainingDepthInformationSignals, this, &TimedDataCollection::ObtainingDepthInformationSignals); + connect(m_scheduler, &TaskScheduler::switchHalogenLampSignal, this, &TimedDataCollection::switchHalogenLampSignal); connect(m_scheduler, &TaskScheduler::switchD65LampSignal, diff --git a/HPPA/TimedDataCollection.h b/HPPA/TimedDataCollection.h index 93c6d2f..1e8775f 100644 --- a/HPPA/TimedDataCollection.h +++ b/HPPA/TimedDataCollection.h @@ -52,6 +52,8 @@ Q_SIGNALS: void motorParm(QString pathLineFilePath); void startRecordSignal(int camType); + void ObtainingDepthInformationSignals(SubTask info); + void switchHalogenLampSignal(int state); void switchD65LampSignal(int state); void switchSlrSignal(int state); diff --git a/HPPA/TimedDataCollectionDataStructures.cpp b/HPPA/TimedDataCollectionDataStructures.cpp index bbf469a..d652ab7 100644 --- a/HPPA/TimedDataCollectionDataStructures.cpp +++ b/HPPA/TimedDataCollectionDataStructures.cpp @@ -113,6 +113,10 @@ SubTaskType TimedDataCollectionDataStructuresReaderWriter::stringToSubTaskType(c if (str == "HyperSpectual1000_1700nm") return SubTaskType::HyperSpectual1000_1700nm; if (str == "SingleLensReflex") return SubTaskType::SingleLensReflex; if (str == "DepthCamera") return SubTaskType::DepthCamera; + + if (str == "ObtainingDepthInformation") return SubTaskType::ObtainingDepthInformation; + if (str == "AutoFocus") return SubTaskType::AutoFocus; + return SubTaskType::SingleLensReflex; } @@ -132,6 +136,15 @@ QJsonObject TimedDataCollectionDataStructuresReaderWriter::subTaskToJson(const S obj["exposureTime"] = subTask.exposureTime; obj["defaultRenderBand"] = subTask.defaultRenderBand; obj["captureIntervalSeconds"] = subTask.captureIntervalSeconds; + + obj["autoFocusMotorConfigFilePath"] = subTask.autoFocusMotorConfigFilePath; + obj["autoFocusX"] = subTask.autoFocusX; + obj["autoFocusY"] = subTask.autoFocusY; + + obj["depthInfoX"] = subTask.depthInfoX; + obj["depthInfoY"] = subTask.depthInfoY; + obj["averageNumberOfTimes"] = subTask.averageNumberOfTimes; + obj["percentageOfEffectiveArea"] = subTask.percentageOfEffectiveArea; return obj; } @@ -148,6 +161,15 @@ bool TimedDataCollectionDataStructuresReaderWriter::jsonToSubTask(const QJsonObj subTask.exposureTime = json["exposureTime"].toDouble(); subTask.defaultRenderBand = json["defaultRenderBand"].toInt(); subTask.captureIntervalSeconds = json["captureIntervalSeconds"].toDouble(); + + subTask.autoFocusMotorConfigFilePath = json["autoFocusMotorConfigFilePath"].toString(); + subTask.autoFocusX = json["autoFocusX"].toDouble(); + subTask.autoFocusY = json["autoFocusY"].toDouble(); + + subTask.depthInfoX = json["depthInfoX"].toDouble(); + subTask.depthInfoY = json["depthInfoY"].toDouble(); + subTask.averageNumberOfTimes = json["averageNumberOfTimes"].toInt(); + subTask.percentageOfEffectiveArea = json["percentageOfEffectiveArea"].toDouble(); return true; } @@ -229,21 +251,16 @@ void TaskExecutor::execute(const TimedTask& task) emit taskUpdated(m_task); - + m_currentSubTaskIndex = -1; m_isRunning = true; qDebug() << "TaskExecutor: Starting task" << task.id; - // 打开卤素灯预热 - emit switchHalogenLampSignal(1); - printMsgAndTime("open HalogenLamp"); - makeFolder(m_task.savePath); - // 开始执行第一个子任务 - double sleepTimeSecond = m_task.HalogenLampPreheatingTime_Minute * 60; - QTimer::singleShot(sleepTimeSecond *1000, this, &TaskExecutor::executeNextSubTask); + double sleepTimeSecond = 1; + QTimer::singleShot(sleepTimeSecond * 1000, this, &TaskExecutor::executeNextSubTask); } void TaskExecutor::printMsgAndTime(QString msg) @@ -269,10 +286,12 @@ void TaskExecutor::makeFolder(QString savePath) if (!dir.exists()) { if (dir.mkpath(".")) { qDebug() << "TaskExecutor: Created data folder:" << savePath; - } else { + } + else { qWarning() << "TaskExecutor: Failed to create data folder:" << savePath; } - } else { + } + else { qDebug() << "TaskExecutor: Data folder already exists:" << savePath; } } @@ -299,7 +318,7 @@ void TaskExecutor::onSequenceComplete(int status) subTask.endTime = QDateTime::currentDateTime(); subTask.durationMinutes = (double)subTask.startTime.secsTo(subTask.endTime) / 60; - qDebug() << "TaskExecutor: subtask "<< m_currentSubTaskIndex<< " time consuming(Minutes): "<< subTask.durationMinutes; + qDebug() << "TaskExecutor: subtask " << m_currentSubTaskIndex << " time consuming(Minutes): " << subTask.durationMinutes; // 拷贝subTask.pathLineFilePath到m_currentFolder if (!subTask.pathLineFilePath.isEmpty() && QFile::exists(subTask.pathLineFilePath)) { @@ -307,7 +326,8 @@ void TaskExecutor::onSequenceComplete(int status) QString destPath = m_currentFolder + QDir::separator() + fileInfo.fileName(); if (QFile::copy(subTask.pathLineFilePath, destPath)) { qDebug() << "TaskExecutor: Copied path line file to" << destPath; - } else { + } + else { qDebug() << "TaskExecutor: Failed to copy path line file from" << subTask.pathLineFilePath << "to" << destPath; } } @@ -315,23 +335,38 @@ void TaskExecutor::onSequenceComplete(int status) emit subTaskFinished(m_currentSubTaskIndex, subTask.type, (status == 0)); emit taskUpdated(m_task); } + //当前任务已经完成,正确关闭灯光或者电源 + ensurePostTaskLighting(); - // - switch (m_task.subTasks[m_currentSubTaskIndex].type) + emit taskUpdated(m_task); +} + +void TaskExecutor::ensurePreTaskLighting() +{ + SubTaskType currentTaskType = m_task.subTasks[m_currentSubTaskIndex].type; + if (currentTaskType != SubTaskType::HyperSpectual400_1000nm && + currentTaskType != SubTaskType::HyperSpectual1000_1700nm) { - case SubTaskType::SingleLensReflex: - { - emit switchD65LampSignal(0); - break; - } - case SubTaskType::DepthCamera: - { - emit switchD65LampSignal(0); - break; - } + emit switchHalogenLampSignal(0); + } + if (currentTaskType != SubTaskType::SingleLensReflex && + currentTaskType != SubTaskType::DepthCamera && + currentTaskType != SubTaskType::ObtainingDepthInformation) + { + emit switchD65LampSignal(0); + } +} + +void TaskExecutor::ensurePostTaskLighting() +{ + SubTaskType currentTaskType = m_task.subTasks[m_currentSubTaskIndex].type; + if (currentTaskType == SubTaskType::SingleLensReflex || + currentTaskType == SubTaskType::DepthCamera || + currentTaskType == SubTaskType::ObtainingDepthInformation) + { + emit switchD65LampSignal(0); } - // 判断下一次的任务是否为高光谱任务,如果不是关闭卤素灯 int nestSubTaskIndex = m_currentSubTaskIndex + 1; if (nestSubTaskIndex >= m_task.subTasks.size()) { @@ -340,21 +375,13 @@ void TaskExecutor::onSequenceComplete(int status) emit switchHalogenLampSignal(0); return; } - switch (m_task.subTasks[nestSubTaskIndex].type) + // 判断下一次的任务是否为高光谱任务,如果不是就关闭卤素灯 + SubTaskType nestTaskType = m_task.subTasks[nestSubTaskIndex].type; + if (nestTaskType != SubTaskType::HyperSpectual400_1000nm && + nestTaskType != SubTaskType::HyperSpectual1000_1700nm) { - case SubTaskType::SingleLensReflex: - { - emit switchHalogenLampSignal(0); - break; - } - case SubTaskType::DepthCamera: - { - emit switchHalogenLampSignal(0); - break; - } + emit switchHalogenLampSignal(0); } - - emit taskUpdated(m_task); } void TaskExecutor::onBack2Origin() @@ -362,23 +389,23 @@ void TaskExecutor::onBack2Origin() // 关闭单反电源 switch (m_task.subTasks[m_currentSubTaskIndex].type) { - case SubTaskType::SingleLensReflex: - { - emit switchSlrSignal(0); - break; - } + case SubTaskType::SingleLensReflex: + { + emit switchSlrSignal(0); + break; + } } // 检查是否还有更多子任务 int nestSubTaskIndex = m_currentSubTaskIndex + 1; if (nestSubTaskIndex < m_task.subTasks.size()) { // 执行下一个子任务 - if(m_task.subTasks[nestSubTaskIndex].type== SubTaskType::SingleLensReflex) + if (m_task.subTasks[nestSubTaskIndex].type == SubTaskType::SingleLensReflex) { printMsgAndTime("Slr task,for weak up,please wait 135 seconds!"); emit switchSlrSignal(0); - QTimer::singleShot(135*1000, this, &TaskExecutor::executeNextSubTask); + QTimer::singleShot(135 * 1000, this, &TaskExecutor::executeNextSubTask); } else { @@ -433,54 +460,88 @@ void TaskExecutor::executeNextSubTask() // << "type:" << static_cast(subTask.type); emit subTaskStarted(m_currentSubTaskIndex, subTask.type); - - emit motorParm(subTask.pathLineFilePath); - int camType; switch (subTask.type) { - case SubTaskType::HyperSpectual400_1000nm: - { - camType = 0; - m_currentFolder = makeSubTaskDataFolder("L"); - emit hyperCamParm(camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "L"); - - break; - } - case SubTaskType::HyperSpectual1000_1700nm: - { - camType = 1; - m_currentFolder = makeSubTaskDataFolder("NIR"); - emit hyperCamParm(camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "NIR"); - - break; - } - case SubTaskType::SingleLensReflex: - { - camType = 2; - m_currentFolder = makeSubTaskDataFolder("SLR"); - emit camParm(camType, 3, m_currentFolder); - - emit switchD65LampSignal(1); - - - emit switchSlrSignal(1); - - break; - } - case SubTaskType::DepthCamera: - { - camType = 3; - m_currentFolder = makeSubTaskDataFolder("DepthCamera"); - emit camParm(camType, 3, m_currentFolder); - - emit switchD65LampSignal(1); - - break; - } + case SubTaskType::ObtainingDepthInformation: + { + //(1)移动到指定位置并通过深度相机获取深度信息(2)调整升降板高度(白板+调焦板)(3)回到零位(0,0) + emit switchD65LampSignal(1); + emit ObtainingDepthInformationSignals(subTask); + break; } + case SubTaskType::AutoFocus: + { + //先判断高光谱相机类型,然后发送相机参数hyperCamParm连接相机 - emit startRecordSignal(camType); + //执行自动调焦任务 + break; + } + case SubTaskType::HyperSpectual400_1000nm: + { + m_camType = 0; + m_currentFolder = makeSubTaskDataFolder("L"); + emit hyperCamParm(m_camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "L"); + + emit motorParm(subTask.pathLineFilePath); + + // 打开卤素灯预热 + emit switchHalogenLampSignal(1); + printMsgAndTime("open HalogenLamp"); + double sleepTimeSecond = m_task.HalogenLampPreheatingTime_Minute * 60; + QTimer::singleShot(sleepTimeSecond * 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"); + + emit motorParm(subTask.pathLineFilePath); + + QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitRecordSignal); + + break; + } + case SubTaskType::SingleLensReflex: + { + m_camType = 2; + m_currentFolder = makeSubTaskDataFolder("SLR"); + emit camParm(m_camType, 3, m_currentFolder); + + emit motorParm(subTask.pathLineFilePath); + + emit switchD65LampSignal(1); + + emit switchSlrSignal(1); + + QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitRecordSignal); + + break; + } + case SubTaskType::DepthCamera: + { + m_camType = 3; + m_currentFolder = makeSubTaskDataFolder("DepthCamera"); + emit camParm(m_camType, 3, m_currentFolder); + + emit motorParm(subTask.pathLineFilePath); + + emit switchD65LampSignal(1); + + QTimer::singleShot(3 * 1000, this, &TaskExecutor::emitRecordSignal); + + break; + } + } + ensurePreTaskLighting(); +} + +void TaskExecutor::emitRecordSignal() +{ + emit startRecordSignal(m_camType); } // ==================== TaskScheduler 实现 ==================== @@ -581,7 +642,7 @@ void TaskScheduler::checkTasks() if (task.scheduledTime > now) continue; qint64 fireThreSecs = 5; - if (task.scheduledTime.addSecs(-1*fireThreSecs) < now && task.scheduledTime.addSecs(fireThreSecs) > now)// 到达计划时间,启动任务 + if (task.scheduledTime.addSecs(-1 * fireThreSecs) < now && task.scheduledTime.addSecs(fireThreSecs) > now)// 到达计划时间,启动任务 { std::cerr << "TaskScheduler::checkTasks,到达计划时间,启动任务" << std::endl; executeTask(task); @@ -639,23 +700,25 @@ void TaskScheduler::executeTask(TimedTask& task) // 连接信号 connect(m_currentExecutor, &TaskExecutor::finished, - this, &TaskScheduler::onTaskFinished); + this, &TaskScheduler::onTaskFinished); connect(m_currentExecutor, &TaskExecutor::subTaskStarted, - this, &TaskScheduler::onSubTaskStarted); + this, &TaskScheduler::onSubTaskStarted); connect(m_currentExecutor, &TaskExecutor::subTaskFinished, - this, &TaskScheduler::onSubTaskFinished); + this, &TaskScheduler::onSubTaskFinished); connect(m_currentExecutor, &TaskExecutor::errorOccurred, - this, &TaskScheduler::onExecutorError); + this, &TaskScheduler::onExecutorError); // 采集相关信号透传 connect(m_currentExecutor, &TaskExecutor::hyperCamParm, - this, &TaskScheduler::hyperCamParm); + this, &TaskScheduler::hyperCamParm); connect(m_currentExecutor, &TaskExecutor::camParm, - this, &TaskScheduler::camParm); + this, &TaskScheduler::camParm); connect(m_currentExecutor, &TaskExecutor::motorParm, - this, &TaskScheduler::motorParm); + this, &TaskScheduler::motorParm); connect(m_currentExecutor, &TaskExecutor::startRecordSignal, - this, &TaskScheduler::startRecordSignal); + this, &TaskScheduler::startRecordSignal); + + connect(m_currentExecutor, &TaskExecutor::ObtainingDepthInformationSignals, this, &TaskScheduler::ObtainingDepthInformationSignals); connect(m_currentExecutor, &TaskExecutor::switchHalogenLampSignal, this, &TaskScheduler::switchHalogenLampSignal); connect(m_currentExecutor, &TaskExecutor::switchD65LampSignal, this, &TaskScheduler::switchD65LampSignal); @@ -687,7 +750,8 @@ void TaskScheduler::updateTaskStatus(int taskId, TaskStatus status) task.status = status; if (status == TaskStatus::Running) { task.startTime = QDateTime::currentDateTime(); - } else if (status == TaskStatus::Finished) { + } + else if (status == TaskStatus::Finished) { task.endTime = QDateTime::currentDateTime(); } break; diff --git a/HPPA/TimedDataCollectionDataStructures.h b/HPPA/TimedDataCollectionDataStructures.h index bb94bd9..084ea91 100644 --- a/HPPA/TimedDataCollectionDataStructures.h +++ b/HPPA/TimedDataCollectionDataStructures.h @@ -25,7 +25,9 @@ enum class SubTaskType { HyperSpectual400_1000nm, // 400nm-1000nm高光谱相机 HyperSpectual1000_1700nm, // 1000nm-1700nm高光谱相机 SingleLensReflex, // 单反相机 - DepthCamera // 深度相机 + DepthCamera, // 深度相机采集任务 + ObtainingDepthInformation, //通过深度相机获取被测物体的深度信息 + AutoFocus // 自动对焦 }; // ==================== 统一子任务封装 ==================== @@ -46,6 +48,17 @@ struct SubTask { double exposureTime = 0.0; // 高光谱相机用 int defaultRenderBand = 550; // 1000-1700nm高光谱用 int captureIntervalSeconds = 5; // 单反/深度相机用 + + //任务ObtainingDepthInformation所需的x和y坐标 + double depthInfoX = 0.0; + double depthInfoY = 0.0; + int averageNumberOfTimes = 1; //任务ObtainingDepthInformation所需的平均次数 + double percentageOfEffectiveArea = 50.0; //深度图像的有效范围百分比 + + //高光谱自动调焦 + QString autoFocusMotorConfigFilePath;//马达配置文件 + double autoFocusX = 0.0; + double autoFocusY = 0.0; }; // ==================== 定时任务 ==================== @@ -151,6 +164,8 @@ signals: void motorParm(QString pathLineFilePath); void startRecordSignal(int camType); + void ObtainingDepthInformationSignals(SubTask info); + void switchHalogenLampSignal(int state); void switchD65LampSignal(int state); void switchSlrSignal(int state); @@ -160,15 +175,21 @@ public slots: void onBack2Origin(); void onError(const QString& error); + void emitRecordSignal(); + private: QString m_currentFolder; void executeNextSubTask(); + void ensurePreTaskLighting(); + void ensurePostTaskLighting(); void printMsgAndTime(QString msg); TimedTask m_task; int m_currentSubTaskIndex; bool m_isRunning; + + int m_camType; }; // ==================== 任务调度器 ==================== @@ -214,6 +235,8 @@ signals: void motorParm(QString pathLineFilePath); void startRecordSignal(int camType); + void ObtainingDepthInformationSignals(SubTask info); + void switchHalogenLampSignal(int state); void switchD65LampSignal(int state); void switchSlrSignal(int state); diff --git a/HPPA/TwoMotorControl.cpp b/HPPA/TwoMotorControl.cpp index 6c0689c..d3eb038 100644 --- a/HPPA/TwoMotorControl.cpp +++ b/HPPA/TwoMotorControl.cpp @@ -210,6 +210,32 @@ void TwoMotorControl::onBack2Origin2() emit back2OriginSignal_TimedDataCollection(); } +void TwoMotorControl::run4_ObtainTargetDepthInfo(DepthCameraWindow* window, double depthInfoX, double depthInfoY, int averageNumberOfTimes, double percentageOfEffectiveArea) +{ + window->m_DepthCameraOperation->setAverageNumberOfTimes(averageNumberOfTimes); + window->m_DepthCameraOperation->setPercentageOfEffectiveArea(percentageOfEffectiveArea); + + m_ObtainTargetDepthInfoCoordinator = new TwoMotor1PosCoordinator(m_multiAxisController); + connect(m_ObtainTargetDepthInfoCoordinator, &TwoMotor1PosCoordinator::ArrivalSignal, window, &DepthCameraWindow::OpenDepthCamera_getDepthValue); + + connect(window->m_DepthCameraOperation, &DepthCameraOperation::DepthValueSignal, m_ObtainTargetDepthInfoCoordinator, &TwoMotor1PosCoordinator::back2origin); + connect(window->m_DepthCameraOperation, &DepthCameraOperation::DepthValueSignal, this, &TwoMotorControl::sequenceComplete);//关灯 + + connect(m_ObtainTargetDepthInfoCoordinator, &TwoMotor1PosCoordinator::back2OriginSignal, this, &TwoMotorControl::onBack2Origin3); + + double xmotor_move_speed = ui.xmotor_move_speed_lineEdit->text().toDouble(); + double ymotor_move_speed = ui.ymotor_move_speed_lineEdit->text().toDouble(); + + m_ObtainTargetDepthInfoCoordinator->moveToTarget(depthInfoX, depthInfoY, xmotor_move_speed, ymotor_move_speed); +} + +void TwoMotorControl::onBack2Origin3() +{ + m_ObtainTargetDepthInfoCoordinator->deleteLater(); + m_ObtainTargetDepthInfoCoordinator = nullptr; + emit back2OriginSignal_TimedDataCollection(); +} + void TwoMotorControl::run() { if (getState()) diff --git a/HPPA/TwoMotorControl.h b/HPPA/TwoMotorControl.h index 06e16dc..c639bf4 100644 --- a/HPPA/TwoMotorControl.h +++ b/HPPA/TwoMotorControl.h @@ -82,7 +82,9 @@ public Q_SLOTS: void run2(SingleLensReflexCameraWindow* w); void run3(DepthCameraWindow* window); + void run4_ObtainTargetDepthInfo(DepthCameraWindow* window, double depthInfoX, double depthInfoY, int averageNumberOfTimes, double percentageOfEffectiveArea); void onBack2Origin2(); + void onBack2Origin3(); void stop_record(); @@ -111,6 +113,7 @@ private: QThread m_coordinatorThread; TwoMotionCaptureCoordinator* m_coordinator = nullptr; TwoMotionCaptureCoordinator* m_coordinator_TimedDataCollection = nullptr; + TwoMotor1PosCoordinator* m_ObtainTargetDepthInfoCoordinator = nullptr; DarkAndWhiteCaptureCoordinator* m_darkCaptureCoordinator = nullptr; DarkAndWhiteCaptureCoordinator* m_whiteCaptureCoordinator = nullptr;