Files
HPPA/HPPA/CaptureCoordinator.cpp
tangchao0503 52516d2f54 1、1轴/2轴:采集白板和暗电流时,移动马达;
2、移除以前的采集逻辑,马达控制全用多轴控制器,采集逻辑全放到采集逻辑控制器里;
3、删除了多余文件;
4、添加了辐亮度和反射率界面,并没有实现功能;
2025-09-26 14:52:02 +08:00

717 lines
18 KiB
C++

#include "CaptureCoordinator.h"
TwoMotionCaptureCoordinator::TwoMotionCaptureCoordinator(
IrisMultiMotorController* motorCtrl,
ImagerOperationBase* cameraCtrl,
QObject* parent)
: QObject(parent)
, m_motorCtrl(motorCtrl)
, m_cameraCtrl(cameraCtrl)
, m_isRunning(false)
{
//这些信号槽是按照逻辑顺序的
connect(this, SIGNAL(moveTo(int, double, double, int)),
m_motorCtrl, SLOT(moveTo(int, double, double, int)));
connect(this, SIGNAL(moveTo(const std::vector<double>, const std::vector<double>, int)),
m_motorCtrl, SLOT(moveTo(const std::vector<double>, const std::vector<double>, int)));
connect(this, &TwoMotionCaptureCoordinator::stopMotorSignal, m_motorCtrl, &IrisMultiMotorController::stop);
connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal,
this, &TwoMotionCaptureCoordinator::handlePositionReached);
//connect(m_motorCtrl, &IrisMultiMotorController::moveFailed,
// this, &TwoMotionCaptureCoordinator::handleError);
connect(this, &TwoMotionCaptureCoordinator::startRecordHSISignal,
m_cameraCtrl, &ImagerOperationBase::start_record);
connect(this, &TwoMotionCaptureCoordinator::stopRecordHSISignal,
m_cameraCtrl, &ImagerOperationBase::stop_record);
connect(m_cameraCtrl, &ImagerOperationBase::RecordFinishedSignal_WhenFrameNumberMeet,
this, &TwoMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet);
//connect(m_cameraCtrl, &ImagerOperationBase::RecordFinishedSignal_WhenFrameNumberNotMeet,
// this, &TwoMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberNotMeet);
//connect(m_cameraCtrl, &ImagerOperationBase::captureFailed,
// this, &TwoMotionCaptureCoordinator::handleError);
}
TwoMotionCaptureCoordinator::TwoMotionCaptureCoordinator(
IrisMultiMotorController* motorCtrl,
QObject* parent)
: QObject(parent)
, m_motorCtrl(motorCtrl)
, m_isRunning(false)
{
connect(this, SIGNAL(moveTo(int, double, double, int)),
m_motorCtrl, SLOT(moveTo(int, double, double, int)));
connect(this, SIGNAL(moveTo(const std::vector<double>, const std::vector<double>, int)),
m_motorCtrl, SLOT(moveTo(const std::vector<double>, const std::vector<double>, int)));
connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal,
this, &TwoMotionCaptureCoordinator::handlePositionReached);
//connect(m_motorCtrl, &IrisMultiMotorController::moveFailed,
// this, &TwoMotionCaptureCoordinator::handleError);
}
TwoMotionCaptureCoordinator::~TwoMotionCaptureCoordinator()
{
}
void TwoMotionCaptureCoordinator::start(QVector<PathLine> pathLines)
{
//QMutexLocker locker(&m_dataMutex);
if (m_isRunning)
{
emit errorOccurred("Sequence already running");
std::cout << "already running" << std::endl;
return;
}
getLocBeforeStart();
m_pathLines = pathLines;
m_isMoving2XMin = false;
m_isMoving2XMax = false;
m_isMoving2XStartLoc = false;
m_isMoving2YTargeLoc = false;
m_isMoving2YStartLoc = false;
m_isImagerFrameNumberMeet = false;
m_retryTimesMoving2XMin = 0;
m_retryTimesMoving2XMax = 0;
m_retryTimesMoving2YTargeLoc = 0;
m_isRunning = true;
m_numCurrentPathLine = 0;
processNextPathLine();
}
void TwoMotionCaptureCoordinator::stop()
{
if (!m_isRunning) return;
//QMutexLocker locker(&m_dataMutex);
std::cout << "The user manually stops the collection! " << std::endl;
savePathLinesToCsv();
emit sequenceComplete(1);
emit finishRecordLineNumSignal(m_numCurrentPathLine);
//emit stopRecordHSISignal(m_numCurrentPathLine);
if (m_cameraCtrl != nullptr)
{
m_cameraCtrl->stop_record();
}
move2LocBeforeStart();
}
void TwoMotionCaptureCoordinator::getLocBeforeStart()
{
QEventLoop loop;
bool received = false;
QTimer timer;
timer.setSingleShot(true);
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
QMetaObject::Connection conn = QObject::connect(m_motorCtrl, &IrisMultiMotorController::locationSignal,
[&](std::vector<double> pos) {
m_locBeforeStart = pos;
received = true;
loop.quit();
});
QMetaObject::invokeMethod(m_motorCtrl, "getLoc", Qt::QueuedConnection);
timer.start(3000);
loop.exec();
disconnect(conn);
}
void TwoMotionCaptureCoordinator::getRecordState()
{
emit recordState(m_isRunning);
}
void TwoMotionCaptureCoordinator::move2LocBeforeStart()
{
std::cout << "\nmove2LocBeforeStart." << std::endl;
PathLine& tmp = m_pathLines[0];
std::vector<double> speed;
speed.push_back(tmp.speedTargetXMinPosition);
speed.push_back(tmp.speedTargetYPosition);
emit moveTo(m_locBeforeStart, speed, 1000);
m_isRunning = false;
m_isMoving2XMin = false;
m_isMoving2XMax = false;
m_isMoving2YTargeLoc = false;
m_isMoving2XStartLoc = true;
m_isMoving2YStartLoc = true;
}
QVector<PathLine> TwoMotionCaptureCoordinator::pathLines() const
{
//QMutexLocker locker(&m_dataMutex);
return m_pathLines;
}
double TwoMotionCaptureCoordinator::getTimeDiffMinutes(QDateTime startTime, QDateTime endTime)
{
qint64 diffMillis = startTime.msecsTo(endTime);
double diffMinutes = (double)diffMillis / 60000;//min
return diffMinutes;
}
bool TwoMotionCaptureCoordinator::savePathLinesToCsv(QString filename)
{
//QMutexLocker locker(&m_dataMutex);
if (filename.isEmpty())
{
FileOperation* fileOperation = new FileOperation();
string directory = fileOperation->getDirectoryOfExe();
QDateTime now = QDateTime::currentDateTime();
QString format1 = "yyyyMMdd_HHmmss";
QString fileNameTmp = now.toString("yyyyMMdd_HHmmss");
filename = QDir::cleanPath(QString::fromStdString(directory) + QDir::separator() + "pathLines" + QDir::separator() + fileNameTmp + "_pathLines.csv");
}
QDir dir = QFileInfo(filename).absoluteDir();
// 如果目录不存在,则递归创建
if (!dir.exists()) {
if (!dir.mkpath(".")) {
qWarning() << "Failed to create directory:" << dir.path();
return false;
}
}
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
return false;
}
QTextStream out(&file);
out << "timestamp1,timestamp2,timestamp3,time consuming(min),targetYPosition,actualYPosition,targetXMinPosition,actualXMinPosition,targetXMaxPosition,actualXMaxPosition\n";
for (const auto& data : m_pathLines)
{
out << data.timestamp1.toString("yyyy-MM-dd HH:mm:ss.zzz") << ","
<< data.timestamp2.toString("yyyy-MM-dd HH:mm:ss.zzz") << ","
<< data.timestamp3.toString("yyyy-MM-dd HH:mm:ss.zzz") << ","
<< QString::number(getTimeDiffMinutes(data.timestamp2, data.timestamp3), 'f', 4) << ","
<< QString::number(data.targetYPosition, 'f', 4) << ","
<< QString::number(data.actualYPosition, 'f', 4) << ","
<< QString::number(data.targetXMinPosition, 'f', 4) << ","
<< QString::number(data.actualXMinPosition, 'f', 4) << ","
<< QString::number(data.targetXMaxPosition, 'f', 4) << ","
<< QString::number(data.actualXMaxPosition, 'f', 4)
<< "\n";
}
file.close();
return true;
}
void TwoMotionCaptureCoordinator::handlePositionReached(int motorID, double pos)
{
if (!m_isRunning) return;
//QMutexLocker locker(&m_dataMutex);
PathLine &tmp = m_pathLines[m_numCurrentPathLine];
if (motorID == 1)//y马达
{
if (m_isMoving2YTargeLoc)
{
double threshold = getThre(tmp.targetYPosition, pos);
if (threshold > 5)
{
//没到准确位置,再次给马达发送命令
if (m_retryTimesMoving2YTargeLoc < m_retryLimit)
{
m_retryTimesMoving2YTargeLoc++;
std::cout << "Y motor Moving2YTargeLoc error. Retry..." << std::endl;
emit moveTo(1, tmp.targetYPosition, tmp.speedTargetYPosition, 1000);
return;
}
}
m_retryTimesMoving2YTargeLoc = 0;
tmp.actualYPosition = pos;
m_isMoving2YTargeLoc = false;
std::cout << "y motor is reached!!!! " << std::endl;
startRecordHsi();
return;
}
if (m_isMoving2YStartLoc)
{
m_isMoving2YStartLoc = false;
return;
}
}
if (motorID == 0)//x马达
{
if (m_isMoving2XMin)
{
double threshold = getThre(tmp.targetXMinPosition, pos);
if (threshold > 5)
{
//没到准确位置,再次给马达发送命令
if (m_retryTimesMoving2XMin < m_retryLimit)
{
m_retryTimesMoving2XMin++;
std::cout << "X motor Moving2XMin error. Retry..." << std::endl;
emit moveTo(0, tmp.targetXMinPosition, tmp.speedTargetXMinPosition, 1000);
return;
}
}
m_retryTimesMoving2XMin = 0;
tmp.actualXMinPosition = pos;
m_isMoving2XMin = false;
std::cout << "x motor is reached!!!! " << std::endl;
startRecordHsi();
return;
}
if (m_isMoving2XMax)
{
double threshold = getThre(tmp.targetXMaxPosition, pos);
if (threshold > 5 && !m_isImagerFrameNumberMeet)//马达没到准确位置 && 【非】光谱仪因帧数限制主动停止采集
{
//没到准确位置,再次给马达发送命令
if (m_retryTimesMoving2XMax < m_retryLimit)
{
m_retryTimesMoving2XMax++;
std::cout << "X motor Moving2XMax error. Retry..." << std::endl;
emit moveTo(0, tmp.targetXMaxPosition, tmp.speedTargetXMaxPosition, 1000);
return;
}
}
m_retryTimesMoving2XMax = 0;
tmp.actualXMaxPosition = pos;
tmp.timestamp3 = QDateTime::currentDateTime();
std::cout << "Line " << m_numCurrentPathLine << " time span(min):" << getTimeDiffMinutes(tmp.timestamp2, tmp.timestamp3) << std::endl;
//停止采集高光谱数据
emit finishRecordLineNumSignal(m_numCurrentPathLine);
//emit stopRecordHSISignal(m_numCurrentPathLine);
if (m_cameraCtrl!=nullptr)
{
m_cameraCtrl->stop_record();
}
m_isMoving2XMax = false;
m_isImagerFrameNumberMeet = false;
m_numCurrentPathLine++;
processNextPathLine();
return;
}
if (m_isMoving2XStartLoc)
{
m_isMoving2XStartLoc = false;
return;
}
}
}
double TwoMotionCaptureCoordinator::getThre(double targetLoc,double actualLoc)
{
double targetLocTmp;
if (targetLoc == 0)
{
targetLocTmp = 0.001;
}
else
{
targetLocTmp = targetLoc;
}
double thre = abs(targetLoc - actualLoc) / targetLocTmp * 100;
return thre;
}
void TwoMotionCaptureCoordinator::startRecordHsi()
{
if (!m_isRunning) return;
//QMutexLocker locker(&m_dataMutex);
if (!m_isMoving2XMin && !m_isMoving2YTargeLoc)
{
//开始采集高光谱数据
PathLine &tmp = m_pathLines[m_numCurrentPathLine];
tmp.timestamp2 = QDateTime::currentDateTime();
std::cout << "start recording hsi, moving to " << tmp.targetXMaxPosition << std::endl;
m_isMoving2XMax = true;
emit moveTo(0, tmp.targetXMaxPosition, tmp.speedTargetXMaxPosition, 1000);
emit startRecordHSISignal(m_numCurrentPathLine);
}
}
void TwoMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet()
{
m_isImagerFrameNumberMeet = true;
emit stopMotorSignal(0);
}
void TwoMotionCaptureCoordinator::handleError(const QString& error)
{
//QMutexLocker locker(&m_dataMutex);
m_isRunning = false;
emit errorOccurred(error);
}
void TwoMotionCaptureCoordinator::processNextPathLine()
{
if (!m_isRunning) return;
int numPathLines = m_pathLines.size();
if (numPathLines == 0)
{
move2LocBeforeStart();
return;
}
if (m_isMoving2YTargeLoc || m_isMoving2XMin)
{
return;
}
if (m_numCurrentPathLine > numPathLines - 1)
{
std::cout << "\nAll path lines is finished! " << std::endl;
move2LocBeforeStart();
savePathLinesToCsv();
emit sequenceComplete(0);
return;
}
std::cout << "\nNew path line: " << m_numCurrentPathLine << std::endl;
emit startRecordLineNumSignal(m_numCurrentPathLine);
PathLine &tmp = m_pathLines[m_numCurrentPathLine];
tmp.timestamp1 = QDateTime::currentDateTime();
std::vector<double> loc;
loc.push_back(tmp.targetXMinPosition);
loc.push_back(tmp.targetYPosition);
std::vector<double> speed;
speed.push_back(tmp.speedTargetXMinPosition);
speed.push_back(tmp.speedTargetYPosition);
m_isMoving2YTargeLoc = true;
m_isMoving2XMin = true;
emit moveTo(loc, speed, 1000);
}
OneMotionCaptureCoordinator::OneMotionCaptureCoordinator(
IrisMultiMotorController* motorCtrl,
ImagerOperationBase* cameraCtrl,
QObject* parent)
: QObject(parent)
, m_motorCtrl(motorCtrl)
, m_cameraCtrl(cameraCtrl)
, m_isRunning(false)
{
connect(this, SIGNAL(moveTo(int, double, double, int)),
m_motorCtrl, SLOT(moveTo(int, double, double, int)));
connect(this, SIGNAL(moveSignal(int, bool, double, int)), m_motorCtrl, SLOT(move(int, bool, double, int)));
connect(this, &OneMotionCaptureCoordinator::stopMotorSignal, m_motorCtrl, &IrisMultiMotorController::stop);
connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal,
this, &OneMotionCaptureCoordinator::handleMotorStoped);
//connect(m_motorCtrl, &IrisMultiMotorController::moveFailed,
// this, &OneMotionCaptureCoordinator::handleError);
connect(this, &OneMotionCaptureCoordinator::startRecordHSISignal,
m_cameraCtrl, &ImagerOperationBase::start_record);
connect(this, &OneMotionCaptureCoordinator::stopRecordHSISignal,
m_cameraCtrl, &ImagerOperationBase::stop_record);
connect(m_cameraCtrl, &ImagerOperationBase::RecordFinishedSignal_WhenFrameNumberMeet,
this, &OneMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet);
}
OneMotionCaptureCoordinator::~OneMotionCaptureCoordinator()
{
}
void OneMotionCaptureCoordinator::startStepMotion(OneMotionCapturePathLine pathLine)
{
QMutexLocker locker(&m_dataMutex);
if (m_isRunning)
{
emit errorOccurred("Sequence already running");
return;
}
m_isRunning = true;
m_pathLine = pathLine;
getLocBeforeStart();
m_pathLine.startPosition = m_locBeforeStart[0];
m_pathLine.timestamp1 = QDateTime::currentDateTime();
//移动马达并开始采集高光谱
emit moveSignal(0, false, m_pathLine.speedRecord, 1000);
emit startRecordHSISignal();
}
void OneMotionCaptureCoordinator::stopStepMotion()
{
QMutexLocker locker(&m_dataMutex);
if (m_cameraCtrl != nullptr)
{
m_cameraCtrl->stop_record();
}
emit stopMotorSignal(0);
}
void OneMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet()
{
emit stopMotorSignal(0);
}
void OneMotionCaptureCoordinator::getLocBeforeStart()
{
QEventLoop loop;
bool received = false;
QTimer timer;
timer.setSingleShot(true);
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
QMetaObject::Connection conn = QObject::connect(m_motorCtrl, &IrisMultiMotorController::locationSignal,
[&](std::vector<double> pos) {
m_locBeforeStart = pos;
received = true;
loop.quit();
});
QMetaObject::invokeMethod(m_motorCtrl, "getLoc", Qt::QueuedConnection);
timer.start(3000);
loop.exec();
disconnect(conn);
}
void OneMotionCaptureCoordinator::move2LocBeforeStart()
{
std::cout << "\nmove2LocBeforeStart." << std::endl;
emit moveTo(0, m_locBeforeStart[0], m_pathLine.speedBack, 1000);
m_isRunning = false;
}
bool OneMotionCaptureCoordinator::saveToCsv(const QString& filename)
{
//QMutexLocker locker(&m_dataMutex);
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
return false;
}
QTextStream out(&file);
out << "startTime,stopTime,startPosition,stopPosition\n";
out << m_pathLine.timestamp1.toString("yyyy-MM-dd HH:mm:ss.zzz") << ","
<< m_pathLine.timestamp2.toString("yyyy-MM-dd HH:mm:ss.zzz") << ","
<< QString::number(m_pathLine.startPosition, 'f', 4) << ","
<< QString::number(m_pathLine.stopPosition, 'f', 4) << "\n";
file.close();
return true;
}
void OneMotionCaptureCoordinator::handleMotorStoped(int motorID, double pos)
{
if (!m_isRunning) return;
QMutexLocker locker(&m_dataMutex);
// 记录位置信息
m_pathLine.stopPosition = pos;
m_pathLine.timestamp2 = QDateTime::currentDateTime();
//光谱仪停止采集,马达回到初始位置
emit stopRecordHSISignal();
if (m_cameraCtrl != nullptr)
{
m_cameraCtrl->stop_record();
}
move2LocBeforeStart();
}
void OneMotionCaptureCoordinator::handleCaptureComplete(double index)
{
if (!m_isRunning) return;
QMutexLocker locker(&m_dataMutex);
}
void OneMotionCaptureCoordinator::handleError(const QString& error)
{
QMutexLocker locker(&m_dataMutex);
m_isRunning = false;
emit errorOccurred(error);
}
DarkAndWhiteCaptureCoordinator::DarkAndWhiteCaptureCoordinator(
int model,
IrisMultiMotorController* motorCtrl,
ImagerOperationBase* cameraCtrl,
QObject* parent)
: QObject(parent)
, m_model(model)
, m_motorCtrl(motorCtrl)
, m_cameraCtrl(cameraCtrl)
, m_isRunning(false)
{
connect(this, SIGNAL(moveTo(int, double, double, int)),
m_motorCtrl, SLOT(moveTo(int, double, double, int)));
connect(this, SIGNAL(moveSignal(int, bool, double, int)), m_motorCtrl, SLOT(move(int, bool, double, int)));
connect(this, &DarkAndWhiteCaptureCoordinator::stopMotorSignal, m_motorCtrl, &IrisMultiMotorController::stop);
connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal,
this, &DarkAndWhiteCaptureCoordinator::handleMotorStoped);
if (m_model == 0)//dark
{
connect(this, &DarkAndWhiteCaptureCoordinator::startRecordHSISignal,
m_cameraCtrl, &ImagerOperationBase::record_dark);
connect(m_cameraCtrl, &ImagerOperationBase::RecordDarlFinishSignal,
this, &DarkAndWhiteCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet);
}
else if(m_model == 1)//white
{
connect(this, &DarkAndWhiteCaptureCoordinator::startRecordHSISignal,
m_cameraCtrl, &ImagerOperationBase::record_white);
connect(m_cameraCtrl, &ImagerOperationBase::RecordWhiteFinishSignal,
this, &DarkAndWhiteCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet);
}
}
DarkAndWhiteCaptureCoordinator::~DarkAndWhiteCaptureCoordinator()
{
}
void DarkAndWhiteCaptureCoordinator::startStepMotion(double speed)
{
QMutexLocker locker(&m_dataMutex);
if (m_isRunning)
{
return;
}
m_isRunning = true;
m_speed = speed;
getLocBeforeStart();
//移动马达并开始采集高光谱
emit moveSignal(0, false, m_speed, 1000);
emit startRecordHSISignal();
}
void DarkAndWhiteCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet()
{
emit stopMotorSignal(0);
}
void DarkAndWhiteCaptureCoordinator::getLocBeforeStart()
{
QEventLoop loop;
bool received = false;
QTimer timer;
timer.setSingleShot(true);
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
QMetaObject::Connection conn = QObject::connect(m_motorCtrl, &IrisMultiMotorController::locationSignal,
[&](std::vector<double> pos) {
m_locBeforeStart = pos;
received = true;
loop.quit();
});
QMetaObject::invokeMethod(m_motorCtrl, "getLoc", Qt::QueuedConnection);
timer.start(3000);
loop.exec();
disconnect(conn);
}
void DarkAndWhiteCaptureCoordinator::move2LocBeforeStart()
{
std::cout << "\nmove2LocBeforeStart." << std::endl;
emit moveTo(0, m_locBeforeStart[0], m_speed, 1000);
m_isRunning = false;
}
void DarkAndWhiteCaptureCoordinator::handleMotorStoped(int motorID, double pos)
{
QMutexLocker locker(&m_dataMutex);
if (!m_isRunning) return;
move2LocBeforeStart();
}
void DarkAndWhiteCaptureCoordinator::handleCaptureComplete(double index)
{
QMutexLocker locker(&m_dataMutex);
}