Files
HPPA/HPPA/CaptureCoordinator.cpp
tangchao0503 33e34aa125 add,计划采集19,上海农科院3D植物表型:
1、新增任务类型LiftingPlatform:基于深度相机探测的植被深度,调整升降台的高度;
2026-08-12 15:17:17 +08:00

975 lines
24 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "CaptureCoordinator.h"
TwoMotionCaptureCoordinator::TwoMotionCaptureCoordinator(
IrisMultiMotorController* motorCtrl,
QObject* parent)
: QObject(parent)
, m_motorCtrl(motorCtrl)
, m_isRunning(false)
, m_isValidCapturing(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);
}
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 finishRecordLineNumSignal(m_numCurrentPathLine);
emit stopRecordHSISignal(m_numCurrentPathLine);
move2LocBeforeStart();
emit sequenceComplete(1);
}
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;
std::cout << "start pos: "<< pos[0] <<", " << pos[1] << std::endl;
received = true;
loop.quit();
});
QMetaObject::invokeMethod(m_motorCtrl, "getLoc", Qt::QueuedConnection);
timer.start(3000);
loop.exec();
std::vector<double> pos;
pos.push_back(0);
pos.push_back(0);
m_locBeforeStart = pos;
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_isValidCapturing = 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);
if (motorID == 1)//y马达
{
if (m_isMoving2YTargeLoc)
{
PathLine& tmp = m_pathLines[m_numCurrentPathLine];
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;
isBack2Origin();
return;
}
}
if (motorID == 0)//x马达
{
if (m_isMoving2XMin)
{
PathLine& tmp = m_pathLines[m_numCurrentPathLine];
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)
{
PathLine& tmp = m_pathLines[m_numCurrentPathLine];
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);
m_isMoving2XMax = false;
m_isImagerFrameNumberMeet = false;
m_numCurrentPathLine++;
processNextPathLine();
return;
}
if (m_isMoving2XStartLoc)
{
m_isMoving2XStartLoc = false;
isBack2Origin();
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);
emit startRecordLineNumSignal(m_numCurrentPathLine);
}
}
void TwoMotionCaptureCoordinator::isBack2Origin()
{
if (!m_isRunning) return;
//QMutexLocker locker(&m_dataMutex);
if (!m_isMoving2XStartLoc && !m_isMoving2YStartLoc)
{
m_isRunning = false;
emit back2OriginSignal();
}
}
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 gotoRecordLineNumSignal(m_numCurrentPathLine);
m_isValidCapturing = true;
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()
{
disconnect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal,
this, &OneMotionCaptureCoordinator::handleMotorStoped);
}
void OneMotionCaptureCoordinator::startStepMotion(OneMotionCapturePathLine pathLine)//这个函数为啥被调用了2次?
{
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);
m_isHypercamStopRecord = true;
}
void OneMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet()
{
emit stopMotorSignal(0);
m_isHypercamStopRecord = true;
}
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);
std::vector<double> pos;
pos.push_back(0);
m_locBeforeStart = pos;
}
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)
{
QMutexLocker locker(&m_dataMutex);
if (m_isHypercamStopRecord == true)
{
m_isHypercamStopRecord = false;
// 记录位置信息
m_pathLine.stopPosition = pos;
m_pathLine.timestamp2 = QDateTime::currentDateTime();
//光谱仪停止采集,马达回到初始位置
emit stopRecordHSISignal();
if (m_cameraCtrl != nullptr)
{
m_cameraCtrl->stop_record();
}
move2LocBeforeStart();
emit sequenceComplete_cam_stop_before_motorback(0);
}
else
{
// emit sequenceComplete last: the slot connected to it may delete this object,
// so no member access is allowed after this point.
emit sequenceComplete(0);
}
}
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);
}
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<double>, const std::vector<double>, int)), m_motorCtrl, SLOT(moveTo(const std::vector<double>, const std::vector<double>, 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<double> loc = { m_targetX, m_targetY };
std::vector<double> 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;
}
//---------------------------------------------------------------------------------------------------------------------------------------------
OneMotionCoordinator::OneMotionCoordinator(IrisMultiMotorController* motorCtrl, QObject* parent)
: QObject(parent)
, m_motorCtrl(motorCtrl)
, m_targetPosition(0)
, m_speed(0)
, m_actualPosition(0)
, m_isMoving(false)
, m_retryTimes(0)
, m_reached(false)
{
connect(this, SIGNAL(moveTo(int, double, double, int)), m_motorCtrl, SLOT(moveTo(int, double, double, int)));
connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal, this, &OneMotionCoordinator::handlePositionReached);
}
OneMotionCoordinator::~OneMotionCoordinator()
{
}
void OneMotionCoordinator::moveToTarget(double position, double speed)
{
QMutexLocker locker(&m_dataMutex);
m_targetPosition = position;
m_speed = speed;
m_retryTimes = 0;
m_reached = false;
m_isMoving = true;
qDebug() << "OneMotionCoordinator: moving to" << position;
emit moveTo(0, position, speed, 1000);
}
void OneMotionCoordinator::handlePositionReached(int motorID, double position)
{
if (!m_isMoving || motorID != 0)
{
return;
}
QMutexLocker locker(&m_dataMutex);
m_actualPosition = position;
double errorRate = getErrorRate(m_targetPosition, m_actualPosition);
if (errorRate > 5 && m_retryTimes < m_retryLimit)
{
m_retryTimes++;
qDebug() << "OneMotionCoordinator: retry" << m_retryTimes << ", target:" << m_targetPosition << ", actual:" << m_actualPosition;
emit moveTo(0, m_targetPosition, m_speed, 1000);
return;
}
m_retryTimes = 0;
m_reached = true;
m_isMoving = false;
qDebug() << "OneMotionCoordinator: Arrived at" << m_actualPosition;
emit sequenceComplete(0);
emit ArrivalSignal(m_actualPosition);
}
double OneMotionCoordinator::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;
}