add,计划采集5:

实现部分计划采集功能:
This commit is contained in:
tangchao0503
2026-06-04 10:55:12 +08:00
parent a8760652bd
commit 3607913f13
12 changed files with 314 additions and 143 deletions

View File

@ -41,11 +41,21 @@ void DepthCameraWindow::onSelectDataFolder()
QString::fromLocal8Bit("选择数据保存路径"), QString::fromLocal8Bit("选择数据保存路径"),
ui.dataFolderLineEdit->text()); ui.dataFolderLineEdit->text());
if (!dir.isEmpty()) setDataFolder(dir);
{ }
ui.dataFolderLineEdit->setText(dir);
AppSettings::instance().setDepthCameraDataFolder(dir); void DepthCameraWindow::setDataFolder(QString dir)
} {
if (!dir.isEmpty())
{
ui.dataFolderLineEdit->setText(dir);
AppSettings::instance().setDepthCameraDataFolder(dir);
}
}
void DepthCameraWindow::setCaptureInterval(int captureIntervalSeconds)
{
m_DepthCameraOperation->setCaptureInterval(captureIntervalSeconds);
} }
void DepthCameraWindow::openDepthCamera() void DepthCameraWindow::openDepthCamera()
@ -83,6 +93,8 @@ DepthCameraOperation::DepthCameraOperation()
m_pipe = nullptr; m_pipe = nullptr;
m_func = nullptr; m_func = nullptr;
record = false; record = false;
m_captureIntervalMilliseconds = 3000;
} }
DepthCameraOperation::~DepthCameraOperation() DepthCameraOperation::~DepthCameraOperation()
@ -96,6 +108,11 @@ DepthCameraOperation::~DepthCameraOperation()
} }
} }
void DepthCameraOperation::setCaptureInterval(int captureIntervalSeconds)
{
m_captureIntervalMilliseconds = captureIntervalSeconds * 1000;
}
void DepthCameraOperation::OpenDepthCamera() void DepthCameraOperation::OpenDepthCamera()
{ {
if (m_pipe) if (m_pipe)
@ -142,14 +159,14 @@ void DepthCameraOperation::OpenDepthCamera()
// Drop several frames // Drop several frames
for (int i = 0; i < 15; ++i) { for (int i = 0; i < 15; ++i) {
auto lost = m_pipe->waitForFrameset(100); auto lost = m_pipe->waitForFrameset(m_captureIntervalMilliseconds);
} }
auto pointCloud = std::make_shared<ob::PointCloudFilter>(); auto pointCloud = std::make_shared<ob::PointCloudFilter>();
int frameIndex = 0; int frameIndex = 0;
record = true; record = true;
QString fileNamePrefix = AppSettings::instance().depthCameraDataFolder() + QDir::separator() + AppSettings::instance().fileName(); QString fileNamePrefix = AppSettings::instance().depthCameraDataFolder() + QDir::separator() + "Gemini336L";
QString imuFilePath = fileNamePrefix + "_IMU.txt"; QString imuFilePath = fileNamePrefix + "_IMU.txt";
std::ofstream imuFile(imuFilePath.toStdString(), std::ios::out | std::ios::trunc); std::ofstream imuFile(imuFilePath.toStdString(), std::ios::out | std::ios::trunc);
while (record) while (record)
@ -160,7 +177,7 @@ void DepthCameraOperation::OpenDepthCamera()
std::cout << "Start recording..." << std::endl; std::cout << "Start recording..." << std::endl;
} }
auto frameSet = m_pipe->waitForFrameset(100); auto frameSet = m_pipe->waitForFrameset(m_captureIntervalMilliseconds);
if (frameSet == nullptr) if (frameSet == nullptr)
{ {
std::cout << "No frames received in 100ms..." << std::endl; std::cout << "No frames received in 100ms..." << std::endl;
@ -218,7 +235,7 @@ void DepthCameraOperation::OpenDepthCamera()
pointCloud->setCreatePointFormat(OB_FORMAT_RGB_POINT); pointCloud->setCreatePointFormat(OB_FORMAT_RGB_POINT);
std::shared_ptr<ob::Frame> frame = pointCloud->process(frameSet); std::shared_ptr<ob::Frame> frame = pointCloud->process(frameSet);
QString plyPath = fileNamePrefix + "_"+ QString::number(frameIndex) + ".ply"; QString plyPath = fileNamePrefix + "_PointCloud_"+ QString::number(frameIndex) + ".ply";
ob::PointCloudHelper::savePointcloudToPly(plyPath.toStdString().c_str(), frame, false, false, 50); ob::PointCloudHelper::savePointcloudToPly(plyPath.toStdString().c_str(), frame, false, false, 50);
//惯导数据 //惯导数据

View File

@ -33,6 +33,8 @@ public:
void setCallback(void(*func)()); void setCallback(void(*func)());
bool getRecordStatus() const { return record; } bool getRecordStatus() const { return record; }
void setCaptureInterval(int captureIntervalSeconds);
private: private:
ob::Pipeline* m_pipe; ob::Pipeline* m_pipe;
cv::Mat frame; cv::Mat frame;
@ -46,6 +48,8 @@ private:
bool record; bool record;
int m_captureIntervalMilliseconds;
public slots: public slots:
void OpenDepthCamera(); void OpenDepthCamera();
void OpenDepthCamera_callback();//不使用信号而使用回调函数来通知界面刷新视频 void OpenDepthCamera_callback();//不使用信号而使用回调函数来通知界面刷新视频
@ -68,6 +72,9 @@ public:
DepthCameraOperation* m_DepthCameraOperation; DepthCameraOperation* m_DepthCameraOperation;
void setDataFolder(QString dir);
void setCaptureInterval(int captureIntervalSeconds);
public Q_SLOTS: public Q_SLOTS:
void openDepthCamera(); void openDepthCamera();
void onCamOpened(); void onCamOpened();

View File

@ -576,8 +576,7 @@ HPPA::HPPA(QWidget* parent)
initMapTools(); initMapTools();
//定时采集 //定时采集
connect(this->ui.mActionTimedDataCollection, SIGNAL(triggered()), this, SLOT(onTimedDataCollection())); initTimedDataCollection();
mTimedDataCollectionWindow = new TimedDataCollection(m_tmc);
QString strPath = QCoreApplication::applicationDirPath() + "/UILayout.ini"; QString strPath = QCoreApplication::applicationDirPath() + "/UILayout.ini";
QFile file(strPath); QFile file(strPath);
@ -592,6 +591,114 @@ HPPA::HPPA(QWidget* parent)
this->showMaximized(); this->showMaximized();
} }
void HPPA::initTimedDataCollection()
{
connect(this->ui.mActionTimedDataCollection, SIGNAL(triggered()), this, SLOT(onTimedDataCollection()));
mTimedDataCollectionWindow = new TimedDataCollection();
// 定时采集控制器 → 相机/马达
connect(mTimedDataCollectionWindow, &TimedDataCollection::hyperCamParm, this, &HPPA::setTimedDataCollectionHyperCamParm);
connect(mTimedDataCollectionWindow, &TimedDataCollection::camParm, this, &HPPA::setTimedDataCollectionCamParm);
connect(mTimedDataCollectionWindow, &TimedDataCollection::motorParm, this, &HPPA::setTimedDataCollectionMotorParm);
connect(mTimedDataCollectionWindow, &TimedDataCollection::startRecordSignal, this, &HPPA::onStartTimedDataCollection);
// 相机/马达 → 定时采集控制器
connect(m_tmc, &TwoMotorControl::sequenceComplete, mTimedDataCollectionWindow, &TimedDataCollection::subTaskCompleted);
//连接马达控制和单反/深度
}
void HPPA::setTimedDataCollectionHyperCamParm(int camType, double f, double e, QString filePath, QString fileName)
{
switch (camType)
{
case 0:
{
disconnectImagerAndCleanup();
ui.mActionPica_L->setChecked(true);
AppSettings::instance().setFrameRate(f);
AppSettings::instance().setIntegrationTime(e);
AppSettings::instance().setDataFolder(filePath);
AppSettings::instance().setFileName(fileName);
this->frame_number->setText("100000");
onconnect();
break;
}
case 1:
{
disconnectImagerAndCleanup();
ui.mActionPica_NIR->setChecked(true);
AppSettings::instance().setFrameRate(f);
AppSettings::instance().setIntegrationTime(e);
AppSettings::instance().setDataFolder(filePath);
AppSettings::instance().setFileName(fileName);
this->frame_number->setText("100000");
onconnect();
break;
}
}
}
void HPPA::setTimedDataCollectionCamParm(int camType, int captureIntervalSeconds, QString folder)
{
switch (camType)
{
case 2:
{
m_singleLensReflexCameraWindow->setDataFolder(folder);
m_singleLensReflexCameraWindow->setCaptureInterval(captureIntervalSeconds);
break;
}
case 3:
{
m_depthCameraWindow->setDataFolder(folder);
m_depthCameraWindow->setCaptureInterval(captureIntervalSeconds);
break;
}
}
}
void HPPA::setTimedDataCollectionMotorParm(QString pathLineFilePath)
{
m_tmc->readRecordLineFile(pathLineFilePath);
//m_tmc->onConnectMotor();
//QThread::msleep(1000);
}
void HPPA::onStartTimedDataCollection(int camType)
{
switch (camType)
{
case 0:
{
onStartRecordStep1();
break;
}
case 1:
{
onStartRecordStep1();
break;
}
case 2:
{
break;
}
case 3:
{
break;
}
}
}
void HPPA::onTimedDataCollection() void HPPA::onTimedDataCollection()
{ {
QAction* checkedScenario = m_ScenarioActionGroup->checkedAction(); QAction* checkedScenario = m_ScenarioActionGroup->checkedAction();
@ -609,6 +716,7 @@ void HPPA::onTimedDataCollection()
} }
} }
void HPPA::initMenubarToolbar() void HPPA::initMenubarToolbar()
{ {
//自定义菜单栏和工具栏 //自定义菜单栏和工具栏
@ -868,7 +976,7 @@ void HPPA::initControlTabwidget()
//2轴马达控制 //2轴马达控制
m_tmc = new TwoMotorControl(this); m_tmc = new TwoMotorControl(this);
//connect(m_tmc, SIGNAL(startLineNumSignal(int)), this, SLOT(onCreateTab(int))); //connect(m_tmc, SIGNAL(startLineNumSignal(int)), this, SLOT(onCreateTab(int)));
connect(m_tmc, SIGNAL(sequenceComplete()), this, SLOT(onsequenceComplete())); connect(m_tmc, &TwoMotorControl::sequenceComplete, this, &HPPA::onsequenceComplete);
m_tmc->setWindowFlags(Qt::Widget); m_tmc->setWindowFlags(Qt::Widget);
ui.controlTabWidget->addTab(m_tmc, QString::fromLocal8Bit("2轴控制")); ui.controlTabWidget->addTab(m_tmc, QString::fromLocal8Bit("2轴控制"));

View File

@ -319,6 +319,7 @@ private:
void disconnectImagerAndCleanup(); void disconnectImagerAndCleanup();
TimedDataCollection* mTimedDataCollectionWindow; TimedDataCollection* mTimedDataCollectionWindow;
void initTimedDataCollection();
public Q_SLOTS: public Q_SLOTS:
void onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber, QString filePath); void onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber, QString filePath);
@ -399,6 +400,10 @@ public Q_SLOTS:
void onMapToolSpectralTriggered(); void onMapToolSpectralTriggered();
void onTimedDataCollection(); void onTimedDataCollection();
void setTimedDataCollectionHyperCamParm(int camType, double f, double e, QString filePath, QString fileName);
void setTimedDataCollectionCamParm(int camType, int captureIntervalSeconds, QString folder);
void setTimedDataCollectionMotorParm(QString pathLineFilePath);
void onStartTimedDataCollection(int camType);
protected: protected:
void closeEvent(QCloseEvent* event) override; void closeEvent(QCloseEvent* event) override;

View File

@ -81,6 +81,11 @@ void SingleLensReflexCameraWindow::onSelectDataFolder()
QString::fromLocal8Bit("选择数据保存路径"), QString::fromLocal8Bit("选择数据保存路径"),
ui.dataFolderLineEdit->text()); ui.dataFolderLineEdit->text());
setDataFolder(dir);
}
void SingleLensReflexCameraWindow::setDataFolder(QString dir)
{
if (!dir.isEmpty()) if (!dir.isEmpty())
{ {
ui.dataFolderLineEdit->setText(dir); ui.dataFolderLineEdit->setText(dir);
@ -92,6 +97,11 @@ void SingleLensReflexCameraWindow::onSelectDataFolder()
} }
} }
void SingleLensReflexCameraWindow::setCaptureInterval(int captureIntervalSeconds)
{
m_SingleLensReflexCameraOperation->setCaptureInterval(captureIntervalSeconds);
}
void SingleLensReflexCameraWindow::openSLRCamera() void SingleLensReflexCameraWindow::openSLRCamera()
{ {
if (!m_SingleLensReflexCameraOperation->getRecordStatus()) if (!m_SingleLensReflexCameraOperation->getRecordStatus())
@ -200,6 +210,7 @@ SingleLensReflexCameraOperation::SingleLensReflexCameraOperation()
m_isSessionOpen = false; m_isSessionOpen = false;
m_isLiveViewActive = false; m_isLiveViewActive = false;
m_imageCounter = 0; m_imageCounter = 0;
m_captureIntervalMilliseconds = 3000;
// 设置保存路径(从 AppSettings 获取,如果为空则使用默认的 CapturedImages 目录) // 设置保存路径(从 AppSettings 获取,如果为空则使用默认的 CapturedImages 目录)
m_savePath = AppSettings::instance().slrDataFolder(); m_savePath = AppSettings::instance().slrDataFolder();
@ -780,13 +791,18 @@ void SingleLensReflexCameraOperation::takePhoto()
// 启动拍照定时器每3秒拍一张 // 启动拍照定时器每3秒拍一张
if (m_captureTimer && !m_captureTimer->isActive()) if (m_captureTimer && !m_captureTimer->isActive())
{ {
m_captureTimer->start(3000); m_captureTimer->start(m_captureIntervalMilliseconds);
std::cout << "capture timer started (1 photo 3 second)" << std::endl; //std::cout << "capture timer started (1 photo 3 second)" << std::endl;
emit CaptureStartedSignal(); emit CaptureStartedSignal();
} }
} }
void SingleLensReflexCameraOperation::setCaptureInterval(int captureIntervalSeconds)
{
m_captureIntervalMilliseconds = captureIntervalSeconds * 1000;
}
void SingleLensReflexCameraOperation::stopTakePhoto() void SingleLensReflexCameraOperation::stopTakePhoto()
{ {
if (m_captureTimer && m_captureTimer->isActive()) if (m_captureTimer && m_captureTimer->isActive())

View File

@ -46,6 +46,8 @@ public:
// 获取当前实时取景图像 // 获取当前实时取景图像
QImage getCurrentLiveViewImage(); QImage getCurrentLiveViewImage();
void setCaptureInterval(int captureIntervalSeconds);
private: private:
cv::Mat frame; cv::Mat frame;
func m_func; func m_func;
@ -62,6 +64,7 @@ private:
QString m_savePath; QString m_savePath;
int m_imageCounter; int m_imageCounter;
int m_captureIntervalMilliseconds;
QMutex m_mutex; QMutex m_mutex;
QMutex m_liveViewMutex; QMutex m_liveViewMutex;
@ -127,6 +130,8 @@ public:
~SingleLensReflexCameraWindow(); ~SingleLensReflexCameraWindow();
SingleLensReflexCameraOperation* m_SingleLensReflexCameraOperation; SingleLensReflexCameraOperation* m_SingleLensReflexCameraOperation;
void setDataFolder(QString dir);
void setCaptureInterval(int captureIntervalSeconds);
public Q_SLOTS: public Q_SLOTS:
void onSelectDataFolder(); void onSelectDataFolder();

View File

@ -1,11 +1,9 @@
#include "TimedDataCollection.h" #include "TimedDataCollection.h"
#include <QDateTime> #include <QDateTime>
#include <QDebug> #include <QDebug>
#include "TwoMotorControl.h"
TimedDataCollection::TimedDataCollection(TwoMotorControl* motorControl, QWidget* parent) TimedDataCollection::TimedDataCollection(QWidget* parent)
: QDialog(parent) : QDialog(parent)
, m_motorControl(nullptr)
, m_scheduler(nullptr) , m_scheduler(nullptr)
{ {
ui.setupUi(this); ui.setupUi(this);
@ -23,9 +21,16 @@ TimedDataCollection::TimedDataCollection(TwoMotorControl* motorControl, QWidget*
connect(m_scheduler, &TaskScheduler::taskFinished, this, &TimedDataCollection::taskFinished); connect(m_scheduler, &TaskScheduler::taskFinished, this, &TimedDataCollection::taskFinished);
connect(m_scheduler, &TaskScheduler::subTaskStarted, this, &TimedDataCollection::subTaskStarted); connect(m_scheduler, &TaskScheduler::subTaskStarted, this, &TimedDataCollection::subTaskStarted);
connect(m_scheduler, &TaskScheduler::subTaskFinished, this, &TimedDataCollection::subTaskFinished); connect(m_scheduler, &TaskScheduler::subTaskFinished, this, &TimedDataCollection::subTaskFinished);
connect(m_scheduler, &TaskScheduler::motorPositionUpdated, this, &TimedDataCollection::motorPositionUpdated);
connect(m_scheduler, &TaskScheduler::errorOccurred, this, &TimedDataCollection::errorOccurred); connect(m_scheduler, &TaskScheduler::errorOccurred, this, &TimedDataCollection::errorOccurred);
// 采集相关信号透传
connect(m_scheduler, &TaskScheduler::hyperCamParm, this, &TimedDataCollection::hyperCamParm);
connect(m_scheduler, &TaskScheduler::camParm, this, &TimedDataCollection::camParm);
connect(m_scheduler, &TaskScheduler::motorParm, this, &TimedDataCollection::motorParm);
connect(m_scheduler, &TaskScheduler::startRecordSignal, this, &TimedDataCollection::startRecordSignal);
connect(this, &TimedDataCollection::sequenceCompleteSignal, m_scheduler, &TaskScheduler::sequenceCompleteSignal);
//writeRead(); //writeRead();
readTimedTaskFromFile("D:/0tmp/3Dtest/task.json"); readTimedTaskFromFile("D:/0tmp/3Dtest/task.json");
@ -33,6 +38,8 @@ TimedDataCollection::TimedDataCollection(TwoMotorControl* motorControl, QWidget*
m_scheduler->loadTasks(m_loadedTasks); m_scheduler->loadTasks(m_loadedTasks);
connect(ui.run_btn, &QPushButton::clicked, this, &TimedDataCollection::startScheduler); connect(ui.run_btn, &QPushButton::clicked, this, &TimedDataCollection::startScheduler);
startScheduler();
} }
TimedDataCollection::~TimedDataCollection() TimedDataCollection::~TimedDataCollection()
@ -42,6 +49,11 @@ TimedDataCollection::~TimedDataCollection()
} }
} }
void TimedDataCollection::subTaskCompleted(int status)
{
emit sequenceCompleteSignal(status);
}
void TimedDataCollection::startScheduler() void TimedDataCollection::startScheduler()
{ {
if (m_scheduler) { if (m_scheduler) {
@ -56,13 +68,6 @@ void TimedDataCollection::stopScheduler()
} }
} }
void TimedDataCollection::setMotorControl(TwoMotorControl* motorControl)
{
if (m_scheduler) {
m_scheduler->setMotorControl(motorControl);
}
}
void TimedDataCollection::readTimedTaskFromFile(const QString& filePath) void TimedDataCollection::readTimedTaskFromFile(const QString& filePath)
{ {
// 从文件读取 // 从文件读取

View File

@ -8,36 +8,40 @@
#include "ui_TimedDataCollection_ui.h" #include "ui_TimedDataCollection_ui.h"
#include "TimedDataCollectionDataStructures.h" #include "TimedDataCollectionDataStructures.h"
class TwoMotorControl;
class TimedDataCollection : public QDialog class TimedDataCollection : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
TimedDataCollection(TwoMotorControl* motorControl, QWidget* parent = nullptr); TimedDataCollection(QWidget* parent = nullptr);
~TimedDataCollection(); ~TimedDataCollection();
void readTimedTaskFromFile(const QString& filePath); void readTimedTaskFromFile(const QString& filePath);
// 设置马达控制器供调度器使用
void setMotorControl(TwoMotorControl* motorControl);
public Q_SLOTS: public Q_SLOTS:
void startScheduler(); void startScheduler();
void stopScheduler(); void stopScheduler();
void subTaskCompleted(int status);
Q_SIGNALS: Q_SIGNALS:
void taskStarted(int taskId); void taskStarted(int taskId);
void taskFinished(int taskId, bool success); void taskFinished(int taskId, bool success);
void subTaskStarted(int taskId, int subTaskIndex); void subTaskStarted(int taskId, int subTaskIndex);
void subTaskFinished(int taskId, int subTaskIndex); void subTaskFinished(int taskId, int subTaskIndex);
void motorPositionUpdated(double x, double y);
void errorOccurred(const QString& error); void errorOccurred(const QString& error);
// 采集相关信号 (透传 TaskScheduler)
void hyperCamParm(int camType, double f, double e, QString filePath, QString fileName);
void camParm(int camType, int captureIntervalSeconds, QString folder);
void motorParm(QString pathLineFilePath);
void startRecordSignal(int camType);
// 马达反馈的信号
void sequenceCompleteSignal(int status);
private: private:
Ui::TimedDataCollection_ui ui; Ui::TimedDataCollection_ui ui;
TwoMotorControl* m_motorControl;
void writeRead(); void writeRead();

View File

@ -197,20 +197,11 @@ bool TimedDataCollectionDataStructuresReaderWriter::jsonToTimedTask(const QJsonO
// ==================== TaskExecutor 实现 ==================== // ==================== TaskExecutor 实现 ====================
TaskExecutor::TaskExecutor(TwoMotorControl* motorControl, QObject* parent) TaskExecutor::TaskExecutor(QObject* parent)
: QObject(parent) : QObject(parent)
, m_motorControl(motorControl)
, m_currentSubTaskIndex(0) , m_currentSubTaskIndex(0)
, m_isRunning(false) , m_isRunning(false)
{ {
if (m_motorControl) {
connect(m_motorControl, &TwoMotorControl::broadcastLocationSignal,
this, &TaskExecutor::onMotorLocationUpdate);
//connect(m_motorControl, &TwoMotorControl::sequenceComplete,
// this, &TaskExecutor::onSequenceComplete);
//connect(m_motorControl, &TwoMotorControl::errorOccurred,
// this, &TaskExecutor::onError);
}
} }
TaskExecutor::~TaskExecutor() TaskExecutor::~TaskExecutor()
@ -232,6 +223,7 @@ void TaskExecutor::execute(const TimedTask& task)
qDebug() << "TaskExecutor: Starting task" << task.id; qDebug() << "TaskExecutor: Starting task" << task.id;
// 开始执行第一个子任务 // 开始执行第一个子任务
makeFolder(m_task.savePath);
executeNextSubTask(); executeNextSubTask();
} }
@ -241,14 +233,33 @@ void TaskExecutor::stop()
qDebug() << "TaskExecutor: Stopping task" << m_task.id; qDebug() << "TaskExecutor: Stopping task" << m_task.id;
if (m_motorControl) {
m_motorControl->stop();
}
m_isRunning = false; m_isRunning = false;
emit finished(false); emit finished(false);
} }
void TaskExecutor::makeFolder(QString savePath)
{
QDir dir(savePath);
if (!dir.exists()) {
if (dir.mkpath(".")) {
qDebug() << "TaskExecutor: Created data folder:" << savePath;
} else {
qWarning() << "TaskExecutor: Failed to create data folder:" << savePath;
}
} else {
qDebug() << "TaskExecutor: Data folder already exists:" << savePath;
}
}
QString TaskExecutor::makeSubTaskDataFolder(QString suffix)
{
QString dateStr = QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss");
QString folderPath = m_task.savePath + QDir::separator() + dateStr + "_" + suffix;
makeFolder(folderPath);
return folderPath;
}
void TaskExecutor::onSequenceComplete(int status) void TaskExecutor::onSequenceComplete(int status)
{ {
if (!m_isRunning) return; if (!m_isRunning) return;
@ -276,13 +287,6 @@ void TaskExecutor::onSequenceComplete(int status)
} }
} }
void TaskExecutor::onMotorLocationUpdate(std::vector<double> loc)
{
if (loc.size() >= 2) {
emit motorPositionUpdated(loc[0], loc[1]);
}
}
void TaskExecutor::onError(const QString& error) void TaskExecutor::onError(const QString& error)
{ {
if (!m_isRunning) return; if (!m_isRunning) return;
@ -299,6 +303,8 @@ void TaskExecutor::executeNextSubTask()
return; return;
} }
std::cerr << "TaskExecutor::executeNextSubTask执行子任务" << std::endl;
SubTask& subTask = m_task.subTasks[m_currentSubTaskIndex]; SubTask& subTask = m_task.subTasks[m_currentSubTaskIndex];
subTask.status = TaskStatus::Running; subTask.status = TaskStatus::Running;
subTask.startTime = QDateTime::currentDateTime(); subTask.startTime = QDateTime::currentDateTime();
@ -307,55 +313,43 @@ void TaskExecutor::executeNextSubTask()
<< "type:" << static_cast<int>(subTask.type); << "type:" << static_cast<int>(subTask.type);
emit subTaskStarted(m_currentSubTaskIndex, subTask.type); emit subTaskStarted(m_currentSubTaskIndex, subTask.type);
emit motorParm(subTask.pathLineFilePath);
//根据任务类型切换相机类型,还需要考虑相关信号和槽 int camType;
switch (subTask.type)
// 如果有路径线文件,加载路径线并启动马达 {
if (!subTask.pathLineFilePath.isEmpty()) { case SubTaskType::HyperSpectual400_1000nm:
loadPathLinesFromFile(subTask.pathLineFilePath); {
} else { camType = 0;
qDebug() << "TaskExecutor: No path line file for subtask"; emit hyperCamParm(camType, subTask.frameRate, subTask.exposureTime, makeSubTaskDataFolder("L"), "test");
}
} break;
void TaskExecutor::loadPathLinesFromFile(const QString& filePath)
{
// 从 .RecordLine3 文件加载路径线
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "TaskExecutor: Failed to open path line file:" << filePath;
emit errorOccurred("Failed to open path line file: " + filePath);
return;
}
double number;
file.read(reinterpret_cast<char*>(&number), sizeof(double));
QVector<PathLine> pathLines;
for (int i = 0; i < static_cast<int>(number) / 6; ++i) {
PathLine line;
for (int j = 0; j < 6; ++j) {
double value;
file.read(reinterpret_cast<char*>(&value), sizeof(double));
switch (j) {
case 0: line.targetYPosition = value; break;
case 1: line.speedTargetYPosition = value; break;
case 2: line.targetXMinPosition = value; break;
case 3: line.speedTargetXMinPosition = value; break;
case 4: line.targetXMaxPosition = value; break;
case 5: line.speedTargetXMaxPosition = value; break;
}
} }
pathLines.append(line); case SubTaskType::HyperSpectual1000_1700nm:
} {
file.close(); camType = 1;
emit hyperCamParm(camType, subTask.frameRate, subTask.exposureTime, makeSubTaskDataFolder("NIR"), "test");
qDebug() << "TaskExecutor: Loaded" << pathLines.size() << "path lines from" << filePath; break;
}
case SubTaskType::SingleLensReflex:
{
camType = 2;
emit camParm(camType, 3, makeSubTaskDataFolder("SLR"));
// 通知马达控制器开始执行 break;
if (m_motorControl) { }
emit m_motorControl->start(pathLines); case SubTaskType::DepthCamera:
{
camType = 3;
emit camParm(camType, 3, makeSubTaskDataFolder("DepthCamera"));
break;
}
} }
emit startRecordSignal(camType);
} }
// ==================== TaskScheduler 实现 ==================== // ==================== TaskScheduler 实现 ====================
@ -363,7 +357,6 @@ void TaskExecutor::loadPathLinesFromFile(const QString& filePath)
TaskScheduler::TaskScheduler(QObject* parent) TaskScheduler::TaskScheduler(QObject* parent)
: QObject(parent) : QObject(parent)
, m_timer(nullptr) , m_timer(nullptr)
, m_motorControl(nullptr)
, m_currentExecutor(nullptr) , m_currentExecutor(nullptr)
, m_currentTaskId(-1) , m_currentTaskId(-1)
{ {
@ -374,11 +367,6 @@ TaskScheduler::~TaskScheduler()
stop(); stop();
} }
void TaskScheduler::setMotorControl(TwoMotorControl* motorControl)
{
m_motorControl = motorControl;
}
void TaskScheduler::loadTasks(const QVector<TimedTask>& tasks) void TaskScheduler::loadTasks(const QVector<TimedTask>& tasks)
{ {
m_tasks = tasks; m_tasks = tasks;
@ -421,15 +409,22 @@ void TaskScheduler::stop()
void TaskScheduler::checkTasks() void TaskScheduler::checkTasks()
{ {
if (!m_motorControl) return;
QDateTime now = QDateTime::currentDateTime(); QDateTime now = QDateTime::currentDateTime();
for (auto& task : m_tasks) { for (auto& task : m_tasks) {
if (task.status != TaskStatus::Waiting) continue; if (task.status != TaskStatus::Waiting) continue;
// 超过计划时间1分钟以上认为任务已过时跳过
if (task.scheduledTime.addSecs(60) < now) {
std::cerr << "TaskScheduler::checkTasks任务已过时跳过:" << task.id << std::endl;
task.status = TaskStatus::Finished;
continue;
}
if (task.scheduledTime > now) continue; if (task.scheduledTime > now) continue;
// 到达计划时间,启动任务 // 到达计划时间,启动任务
std::cerr << "TaskScheduler::checkTasks到达计划时间启动任务" << std::endl;
executeTask(task); executeTask(task);
break; // 一次只执行一个任务 break; // 一次只执行一个任务
} }
@ -470,18 +465,8 @@ void TaskScheduler::onExecutorError(const QString& error)
emitError(error); emitError(error);
} }
void TaskScheduler::onExecutorMotorPositionUpdated(double x, double y)
{
emit motorPositionUpdated(x, y);
}
void TaskScheduler::executeTask(TimedTask& task) void TaskScheduler::executeTask(TimedTask& task)
{ {
if (!m_motorControl) {
emitError("Motor control not set");
return;
}
qDebug() << "TaskScheduler: Executing task" << task.id; qDebug() << "TaskScheduler: Executing task" << task.id;
updateTaskStatus(task.id, TaskStatus::Running); updateTaskStatus(task.id, TaskStatus::Running);
@ -490,7 +475,7 @@ void TaskScheduler::executeTask(TimedTask& task)
emit taskStarted(task.id); emit taskStarted(task.id);
// 创建任务执行器 // 创建任务执行器
m_currentExecutor = new TaskExecutor(m_motorControl, this); m_currentExecutor = new TaskExecutor(this);
// 连接信号 // 连接信号
connect(m_currentExecutor, &TaskExecutor::finished, connect(m_currentExecutor, &TaskExecutor::finished,
@ -501,8 +486,18 @@ void TaskScheduler::executeTask(TimedTask& task)
this, &TaskScheduler::onSubTaskFinished); this, &TaskScheduler::onSubTaskFinished);
connect(m_currentExecutor, &TaskExecutor::errorOccurred, connect(m_currentExecutor, &TaskExecutor::errorOccurred,
this, &TaskScheduler::onExecutorError); this, &TaskScheduler::onExecutorError);
connect(m_currentExecutor, &TaskExecutor::motorPositionUpdated,
this, &TaskScheduler::onExecutorMotorPositionUpdated); // 采集相关信号透传
connect(m_currentExecutor, &TaskExecutor::hyperCamParm,
this, &TaskScheduler::hyperCamParm);
connect(m_currentExecutor, &TaskExecutor::camParm,
this, &TaskScheduler::camParm);
connect(m_currentExecutor, &TaskExecutor::motorParm,
this, &TaskScheduler::motorParm);
connect(m_currentExecutor, &TaskExecutor::startRecordSignal,
this, &TaskScheduler::startRecordSignal);
connect(this, &TaskScheduler::sequenceCompleteSignal, m_currentExecutor, &TaskExecutor::onSequenceComplete);
// 开始执行 // 开始执行
m_currentExecutor->execute(task); m_currentExecutor->execute(task);

View File

@ -6,7 +6,6 @@
#include <QMetaType> #include <QMetaType>
#include <QTimer> #include <QTimer>
#include "TwoMotorControl.h"
#include "CaptureCoordinator.h" #include "CaptureCoordinator.h"
// ==================== 枚举定义 ==================== // ==================== 枚举定义 ====================
@ -107,10 +106,6 @@ private:
static SubTaskType stringToSubTaskType(const QString& str); static SubTaskType stringToSubTaskType(const QString& str);
}; };
// ==================== 前向声明 ====================
class TwoMotorControl;
// ==================== 任务执行器 ==================== // ==================== 任务执行器 ====================
class TaskExecutor : public QObject class TaskExecutor : public QObject
@ -118,11 +113,13 @@ class TaskExecutor : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit TaskExecutor(TwoMotorControl* motorControl, QObject* parent = nullptr); explicit TaskExecutor(QObject* parent = nullptr);
~TaskExecutor(); ~TaskExecutor();
// 执行任务 // 执行任务
void execute(const TimedTask& task); void execute(const TimedTask& task);
void makeFolder(QString savePath);
QString makeSubTaskDataFolder(QString suffix);
// 获取当前执行的子任务索引 // 获取当前执行的子任务索引
int currentSubTaskIndex() const { return m_currentSubTaskIndex; } int currentSubTaskIndex() const { return m_currentSubTaskIndex; }
@ -140,19 +137,21 @@ signals:
void finished(bool success); // 任务完成 void finished(bool success); // 任务完成
void subTaskStarted(int subTaskIndex, SubTaskType type); // 子任务开始 void subTaskStarted(int subTaskIndex, SubTaskType type); // 子任务开始
void subTaskFinished(int subTaskIndex, SubTaskType type, bool success); // 子任务完成 void subTaskFinished(int subTaskIndex, SubTaskType type, bool success); // 子任务完成
void motorPositionUpdated(double x, double y); // 马达位置更新
void errorOccurred(const QString& error); // 错误发生 void errorOccurred(const QString& error); // 错误发生
private slots: // 采集相关信号
void hyperCamParm(int camType, double f, double e, QString filePath, QString fileName);
void camParm(int camType, int captureIntervalSeconds, QString folder);
void motorParm(QString pathLineFilePath);
void startRecordSignal(int camType);
public slots:
void onSequenceComplete(int status); void onSequenceComplete(int status);
void onMotorLocationUpdate(std::vector<double> loc);
void onError(const QString& error); void onError(const QString& error);
private: private:
void executeNextSubTask(); void executeNextSubTask();
void loadPathLinesFromFile(const QString& filePath);
TwoMotorControl* m_motorControl;
TimedTask m_task; TimedTask m_task;
int m_currentSubTaskIndex; int m_currentSubTaskIndex;
bool m_isRunning; bool m_isRunning;
@ -168,9 +167,6 @@ public:
explicit TaskScheduler(QObject* parent = nullptr); explicit TaskScheduler(QObject* parent = nullptr);
~TaskScheduler(); ~TaskScheduler();
// 设置马达控制器
void setMotorControl(TwoMotorControl* motorControl);
// 加载任务列表 // 加载任务列表
void loadTasks(const QVector<TimedTask>& tasks); void loadTasks(const QVector<TimedTask>& tasks);
@ -189,19 +185,28 @@ public:
signals: signals:
void taskStarted(int taskId); // 任务开始 void taskStarted(int taskId); // 任务开始
void taskFinished(int taskId, bool success); // 任务完成 void taskFinished(int taskId, bool success); // 任务完成
// 子任务的信号
void subTaskStarted(int taskId, int subTaskIndex); // 子任务开始 void subTaskStarted(int taskId, int subTaskIndex); // 子任务开始
void subTaskFinished(int taskId, int subTaskIndex); // 子任务完成 void subTaskFinished(int taskId, int subTaskIndex); // 子任务完成
void motorPositionUpdated(double x, double y); // 马达位置更新
void errorOccurred(const QString& error); // 错误发生 void errorOccurred(const QString& error); // 错误发生
void schedulerStateChanged(bool running); // 调度器状态变化 void schedulerStateChanged(bool running); // 调度器状态变化
// 采集相关信号 (透传 TaskExecutor)
void hyperCamParm(int camType, double f, double e, QString filePath, QString fileName);
void camParm(int camType, int captureIntervalSeconds, QString folder);
void motorParm(QString pathLineFilePath);
void startRecordSignal(int camType);
// 马达反馈的信号
void sequenceCompleteSignal(int status);
private slots: private slots:
void checkTasks(); // 检查任务是否该启动 void checkTasks(); // 检查任务是否该启动
void onTaskFinished(bool success); void onTaskFinished(bool success);
void onSubTaskStarted(int subTaskIndex, SubTaskType type); void onSubTaskStarted(int subTaskIndex, SubTaskType type);
void onSubTaskFinished(int subTaskIndex, SubTaskType type, bool success); void onSubTaskFinished(int subTaskIndex, SubTaskType type, bool success);
void onExecutorError(const QString& error); void onExecutorError(const QString& error);
void onExecutorMotorPositionUpdated(double x, double y);
private: private:
void executeTask(TimedTask& task); void executeTask(TimedTask& task);
@ -210,7 +215,6 @@ private:
QTimer* m_timer; QTimer* m_timer;
QVector<TimedTask> m_tasks; QVector<TimedTask> m_tasks;
TwoMotorControl* m_motorControl;
TaskExecutor* m_currentExecutor; TaskExecutor* m_currentExecutor;
int m_currentTaskId; int m_currentTaskId;
}; };

View File

@ -116,7 +116,7 @@ void TwoMotorControl::run()
{ {
QMessageBox::information(this, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("请至少添加一行采集线!")); QMessageBox::information(this, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("请至少添加一行采集线!"));
emit sequenceComplete(); emit sequenceComplete(0);
return; return;
} }
@ -129,7 +129,7 @@ void TwoMotorControl::run()
connect(this, SIGNAL(stopSignal()), m_coordinator, SLOT(stop())); connect(this, SIGNAL(stopSignal()), m_coordinator, SLOT(stop()));
connect(m_coordinator, SIGNAL(startRecordLineNumSignal(int)), this, SLOT(receiveStartRecordLineNum(int))); connect(m_coordinator, SIGNAL(startRecordLineNumSignal(int)), this, SLOT(receiveStartRecordLineNum(int)));
connect(m_coordinator, SIGNAL(finishRecordLineNumSignal(int)), this, SLOT(receiveFinishRecordLineNum(int))); connect(m_coordinator, SIGNAL(finishRecordLineNumSignal(int)), this, SLOT(receiveFinishRecordLineNum(int)));
connect(m_coordinator, SIGNAL(sequenceComplete(int)), this, SLOT(onSequenceComplete())); connect(m_coordinator, SIGNAL(sequenceComplete(int)), this, SLOT(onSequenceComplete(int)));
connect(m_coordinator, &TwoMotionCaptureCoordinator::startRecordHSISignal, m_Imager, &ImagerOperationBase::start_record); connect(m_coordinator, &TwoMotionCaptureCoordinator::startRecordHSISignal, m_Imager, &ImagerOperationBase::start_record);
connect(m_coordinator, &TwoMotionCaptureCoordinator::stopRecordHSISignal, this, &TwoMotorControl::stop_record); connect(m_coordinator, &TwoMotionCaptureCoordinator::stopRecordHSISignal, this, &TwoMotorControl::stop_record);
@ -263,7 +263,7 @@ void TwoMotorControl::receiveFinishRecordLineNum(int lineNum)
} }
} }
void TwoMotorControl::onSequenceComplete() void TwoMotorControl::onSequenceComplete(int status)
{ {
isWritePosFile = false; isWritePosFile = false;
fclose(m_posFileHandle); fclose(m_posFileHandle);
@ -272,7 +272,7 @@ void TwoMotorControl::onSequenceComplete()
m_coordinatorThread.wait(); m_coordinatorThread.wait();
m_coordinator = nullptr; m_coordinator = nullptr;
emit sequenceComplete(); emit sequenceComplete(status);
} }
bool TwoMotorControl::getMotorsConnectionStatus() bool TwoMotorControl::getMotorsConnectionStatus()
@ -551,7 +551,10 @@ void TwoMotorControl::onReadRecordLineFile_btn()
{ {
return; return;
} }
readRecordLineFile(RecordLineFilePath);
}
void TwoMotorControl::readRecordLineFile(QString RecordLineFilePath)
{
FILE* RecordLineFileHandle = fopen(RecordLineFilePath.toStdString().c_str(), "rb"); FILE* RecordLineFileHandle = fopen(RecordLineFilePath.toStdString().c_str(), "rb");
double number; double number;

View File

@ -27,6 +27,8 @@ public:
void record_white(); void record_white();
bool getMotorsConnectionStatus(); bool getMotorsConnectionStatus();
void readRecordLineFile(QString RecordLineFilePath);
private: private:
ImagerOperationBase* m_Imager; ImagerOperationBase* m_Imager;
@ -68,7 +70,7 @@ public Q_SLOTS:
void stop(); void stop();
void receiveStartRecordLineNum(int lineNum); void receiveStartRecordLineNum(int lineNum);
void receiveFinishRecordLineNum(int lineNum); void receiveFinishRecordLineNum(int lineNum);
void onSequenceComplete(); void onSequenceComplete(int status);
void stop_record(); void stop_record();
@ -86,7 +88,7 @@ signals:
void stopSignal(); void stopSignal();
void startLineNumSignal(int lineNum); void startLineNumSignal(int lineNum);
void sequenceComplete();//所有采集线正常运行完成 void sequenceComplete(int status);//所有采集线正常运行完成
void broadcastLocationSignal(std::vector<double>); void broadcastLocationSignal(std::vector<double>);