add,计划采集20,上海农科院3D植物表型:
1、新增任务类型AutoFocus:执行自动调焦过程;
This commit is contained in:
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 "-";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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<double> 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<double>& pos, const std::vector<double>& 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);
|
||||
|
||||
//验证马达运动位置是否到达指定位置
|
||||
|
||||
@ -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<double>& pos, const std::vector<double>& index, double& a_init, double& mu_init, double& sigma_init, double& c_init);
|
||||
void gaussian_fit(const std::vector<double>& x_data, const std::vector<double>& y_data, double& a, double& mu, double& sigma, double& c);
|
||||
|
||||
@ -143,6 +150,8 @@ private:
|
||||
|
||||
void showMessageBox(QString msg, QString title = QString::fromLocal8Bit("提示"));
|
||||
|
||||
double getErrorRate(double targetLoc, double actualLoc);
|
||||
|
||||
public Q_SLOTS:
|
||||
void onConnectMotor();
|
||||
void onMove2MotorLogicZero();
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user