diff --git a/App/WheelMeasure/Doc/ModbusTCP_Protocol.md b/App/WheelMeasure/Doc/ModbusTCP_Protocol.md
index 20714fa..00d2f77 100644
--- a/App/WheelMeasure/Doc/ModbusTCP_Protocol.md
+++ b/App/WheelMeasure/Doc/ModbusTCP_Protocol.md
@@ -25,6 +25,7 @@
| 18,19 | 下点X | R | FLOAT32 | 轮毂下点X坐标 (mm) |
| 20,21 | 下点Y | R | FLOAT32 | 轮毂下点Y坐标 (mm) |
| 22,23 | 下点Z | R | FLOAT32 | 轮毂下点Z坐标 (mm) |
+| 24,25 | 到地面高度 | R | FLOAT32 | 轮眉到地面高度 (mm) |
## FLOAT32 格式
@@ -50,5 +51,5 @@
```
1. 写寄存器0 = 设备序号 (1-4)
2. 读寄存器1 等待状态变为 4 (完成)
-3. 读地址2-23获取检测结果
+3. 读地址2-25获取检测结果
```
diff --git a/App/WheelMeasure/Doc/wheelmeasure.mthings b/App/WheelMeasure/Doc/wheelmeasure.mthings
index 1639336..fcabfc3 100644
--- a/App/WheelMeasure/Doc/wheelmeasure.mthings
+++ b/App/WheelMeasure/Doc/wheelmeasure.mthings
@@ -79,6 +79,11 @@
+
+
+
+
+
diff --git a/App/WheelMeasure/WheelMeasureApp/Presenter/Src/WheelMeasurePresenter.cpp b/App/WheelMeasure/WheelMeasureApp/Presenter/Src/WheelMeasurePresenter.cpp
index 5593231..3407d2c 100644
--- a/App/WheelMeasure/WheelMeasureApp/Presenter/Src/WheelMeasurePresenter.cpp
+++ b/App/WheelMeasure/WheelMeasureApp/Presenter/Src/WheelMeasurePresenter.cpp
@@ -19,11 +19,11 @@ WheelMeasurePresenter::WheelMeasurePresenter(QObject* parent)
{
// 创建配置接口
IVrWheelMeasureConfig::CreateInstance(&m_config);
+ LOG_INFO("ALGO_VERSION: %s \n", wd_wheelArchHeigthMeasureVersion());
}
WheelMeasurePresenter::~WheelMeasurePresenter()
{
- // 释放配置接口
if (m_config) {
delete m_config;
m_config = nullptr;
@@ -79,23 +79,27 @@ void WheelMeasurePresenter::OnCameraStatusChanged(int cameraIndex, bool isConnec
{
LOG_INFO("Camera[%d] status changed: %s\n", cameraIndex, isConnected ? "connected" : "disconnected");
- if (m_statusUpdate) {
- // 从配置中获取相机名称(cameraIndex从1开始)
- QString cameraName;
- int enabledIndex = 0;
- for (const auto& cameraConfig : m_configResult.cameras) {
- if (cameraConfig.enabled) {
- enabledIndex++;
- if (enabledIndex == cameraIndex) {
- cameraName = QString::fromStdString(cameraConfig.name);
- break;
- }
+ if (!m_statusUpdate) return;
+
+ // 从配置中获取相机名称(cameraIndex从1开始)
+ QString cameraName;
+ int enabledIndex = 0;
+ for (const auto& cameraConfig : m_configResult.cameras) {
+ if (cameraConfig.enabled) {
+ enabledIndex++;
+ if (enabledIndex == cameraIndex) {
+ cameraName = QString::fromStdString(cameraConfig.name);
+ break;
}
}
- if (cameraName.isEmpty()) {
- cameraName = QString("Camera%1").arg(cameraIndex);
- }
+ }
+ if (cameraName.isEmpty()) {
+ cameraName = QString("Camera%1").arg(cameraIndex);
+ }
+ // 切换到主线程更新UI
+ QMetaObject::invokeMethod(this, [this, cameraName, isConnected]() {
+ if (!m_statusUpdate) return;
if (isConnected) {
m_statusUpdate->OnCameraConnected(cameraName);
m_statusUpdate->OnDeviceStatusChanged(cameraName, static_cast(DeviceStatus::Online));
@@ -103,13 +107,12 @@ void WheelMeasurePresenter::OnCameraStatusChanged(int cameraIndex, bool isConnec
m_statusUpdate->OnCameraDisconnected(cameraName);
m_statusUpdate->OnDeviceStatusChanged(cameraName, static_cast(DeviceStatus::Offline));
}
- }
+ }, Qt::QueuedConnection);
}
void WheelMeasurePresenter::OnWorkStatusChanged(WorkStatus status)
{
// 写入Modbus工作状态 (地址1)
- // 0=空闲, 1=初始化中, 2=就绪, 3=检测中, 4=完成, 5=错误
uint16_t statusValue = 0;
switch (status) {
case WorkStatus::InitIng: statusValue = 1; break;
@@ -122,32 +125,45 @@ void WheelMeasurePresenter::OnWorkStatusChanged(WorkStatus status)
}
WriteModbusRegisters(1, &statusValue, 1);
- // 直接使用公用的 WorkStatus,不再需要转换
- if (m_statusUpdate) {
- m_statusUpdate->OnWorkStatusChanged(status);
- }
+ // 切换到主线程更新UI
+ QMetaObject::invokeMethod(this, [this, status]() {
+ if (m_statusUpdate) {
+ m_statusUpdate->OnWorkStatusChanged(status);
+ }
+ }, Qt::QueuedConnection);
}
void WheelMeasurePresenter::OnCameraCountChanged(int count)
{
- if (m_statusUpdate) {
- // 使用配置中的相机名称,因为此时 m_vrEyeDeviceList 可能还未填充
- QStringList cameraNames;
- for (const auto& cameraConfig : m_configResult.cameras) {
- if (cameraConfig.enabled) {
- cameraNames.append(QString::fromStdString(cameraConfig.name));
- }
+ if (!m_statusUpdate) return;
+
+ QStringList cameraNames;
+ for (const auto& cameraConfig : m_configResult.cameras) {
+ if (cameraConfig.enabled) {
+ cameraNames.append(QString::fromStdString(cameraConfig.name));
}
- LOG_INFO("OnCameraCountChanged: count=%d, cameraNames=%d\n", count, cameraNames.size());
- m_statusUpdate->OnNeedShowImageCount(cameraNames);
}
+ LOG_INFO("OnCameraCountChanged: count=%d, cameraNames=%d\n", count, cameraNames.size());
+
+ // 切换到主线程更新UI
+ QMetaObject::invokeMethod(this, [this, cameraNames]() {
+ if (m_statusUpdate) {
+ m_statusUpdate->OnNeedShowImageCount(cameraNames);
+ }
+ }, Qt::QueuedConnection);
}
void WheelMeasurePresenter::OnStatusUpdate(const std::string& statusMessage)
{
- if (m_statusUpdate) {
- m_statusUpdate->OnStatusUpdate(QString::fromStdString(statusMessage));
- }
+ if (!m_statusUpdate) return;
+
+ QString msg = QString::fromStdString(statusMessage);
+ // 切换到主线程更新UI
+ QMetaObject::invokeMethod(this, [this, msg]() {
+ if (m_statusUpdate) {
+ m_statusUpdate->OnStatusUpdate(msg);
+ }
+ }, Qt::QueuedConnection);
}
bool WheelMeasurePresenter::initializeConfig(const QString& configPath)
@@ -465,10 +481,15 @@ void WheelMeasurePresenter::processScanData(std::vectorplaneHeight;
LOG_INFO("Using calibrated plane parameters for camera %d\n", m_currentCameraIndex);
-
+ LOG_INFO(" planeHeight: %.3f, errorCompensation: %.2f\n", calibParam->planeHeight, calibParam->errorCompensation);
+
if(calibParam){
+ // 计算调平使用的地面高度(加上该相机的误差补偿)
+ double adjustedPlaneHeight = groundCalibPara.planeHeight + calibParam->errorCompensation;
+ LOG_INFO(" adjustedPlaneHeight (with compensation): %.3f\n", adjustedPlaneHeight);
+
for(size_t i = 0; i < scanLines.size(); i++){
- wd_horizonCamera_lineDataR(scanLines[i], calibParam->planeCalib, groundCalibPara.planeHeight);
+ wd_horizonCamera_lineDataR(scanLines[i], calibParam->planeCalib, adjustedPlaneHeight);
}
}
} else {
@@ -531,17 +552,18 @@ void WheelMeasurePresenter::processScanData(std::vectorOnStatusUpdate(statusMsg);
}
// 填充测量结果数据
WheelMeasureData measureData;
measureData.archToCenterHeight = wheelArchResult.archToCenterHeigth;
+ measureData.archToGroundHeight = wheelArchResult.archToGroundHeigth;
measureData.wheelArchPosX = wheelArchResult.wheelArchPos.x;
measureData.wheelArchPosY = wheelArchResult.wheelArchPos.y;
measureData.wheelArchPosZ = wheelArchResult.wheelArchPos.z;
@@ -581,7 +603,7 @@ void WheelMeasurePresenter::processScanData(std::vector(bits & 0xFFFF);
};
- uint16_t modbusData[22];
+ uint16_t modbusData[24];
memset(modbusData, 0, sizeof(modbusData));
// 地址2: 设备序号
@@ -599,7 +621,7 @@ void WheelMeasurePresenter::processScanData(std::vector(wheelArchResult.archToCenterHeigth), modbusData[2], modbusData[3]);
// 地址6-7: 轮眉X
floatToUint16(static_cast(wheelArchResult.wheelArchPos.x), modbusData[4], modbusData[5]);
@@ -619,10 +641,12 @@ void WheelMeasurePresenter::processScanData(std::vector(wheelArchResult.wheelDownPos.y), modbusData[18], modbusData[19]);
// 地址22-23: 下点Z
floatToUint16(static_cast(wheelArchResult.wheelDownPos.z), modbusData[20], modbusData[21]);
+ // 地址24-25: 到地面高度
+ floatToUint16(static_cast(wheelArchResult.archToGroundHeigth), modbusData[22], modbusData[23]);
}
- WriteModbusRegisters(2, modbusData, 22);
- LOG_INFO("Modbus: 写入检测结果到地址2-23, 设备=%d, 有效=%d\n", m_currentCameraIndex, modbusData[1]);
+ WriteModbusRegisters(2, modbusData, 24);
+ LOG_INFO("Modbus: 写入检测结果到地址2-25, 设备=%d, 有效=%d\n", m_currentCameraIndex, modbusData[1]);
// 检测完成后清零"检测控制"(地址0)
uint16_t zero = 0;
@@ -638,7 +662,6 @@ void WheelMeasurePresenter::processScanData(std::vector= 0 && m_currentCameraIndex < static_cast(m_cameraList.size())) {
+ checkAndDisplayCalibrationStatus(m_currentCameraIndex);
+ }
}
void DialogCameraLevel::initializeCameraCombo()
@@ -182,9 +188,7 @@ bool DialogCameraLevel::performCameraLeveling()
// 获取选中的相机索引
int selectedIndex = ui->combo_camera->currentIndex();
- // 1. 设置调平状态回调
- setLevelingStatusCallback();
-
+ // 先检查索引有效性,再设置回调
if (selectedIndex < 0 || selectedIndex >= static_cast(m_cameraList.size())) {
LOG_ERROR("Invalid camera index: %d\n", selectedIndex);
return false;
@@ -192,12 +196,16 @@ bool DialogCameraLevel::performCameraLeveling()
LOG_INFO("Performing camera leveling with camera %d (index %d)\n", selectedIndex + 1, selectedIndex);
+ // 1. 设置调平状态回调(在索引检查之后)
+ setLevelingStatusCallback();
+
// 2. 清空之前的扫描数据
clearScanDataCache();
// 3. 启动相机扫描地面数据
if (!startCameraScan(selectedIndex)) {
LOG_ERROR("Failed to start camera scan for leveling\n");
+ restorePresenterStatusCallback(); // 恢复回调
return false;
}
@@ -229,6 +237,7 @@ bool DialogCameraLevel::performCameraLeveling()
if (!calculatePlaneCalibration(planeCalib, planeHeight, invRMatrix)) {
LOG_ERROR("Failed to calculate plane calibration\n");
+ restorePresenterStatusCallback(); // 恢复回调
return false;
}
@@ -249,16 +258,22 @@ bool DialogCameraLevel::performCameraLeveling()
if (!saveLevelingResults(planeCalib, planeHeight, invRMatrix, cameraIndex, cameraName)) {
LOG_ERROR("Failed to save leveling results\n");
+ restorePresenterStatusCallback(); // 恢复回调
return false;
}
clearScanDataCache();
+
+ // 9. 调平完成后恢复回调
+ restorePresenterStatusCallback();
+
LOG_INFO("Camera leveling completed successfully\n");
return true;
} catch (const std::exception& e) {
LOG_ERROR("Exception in performCameraLeveling: %s\n", e.what());
+ restorePresenterStatusCallback(); // 异常时也恢复回调
return false;
}
}
@@ -471,12 +486,16 @@ bool DialogCameraLevel::saveLevelingResults(double planeCalib[9], double planeHe
return false;
}
+ // 获取UI中的误差补偿值
+ double errorCompensation = ui->edit_error_compensation->text().toDouble();
+
// 创建或更新相机调平参数
WheelCameraPlaneCalibParam cameraParam;
cameraParam.cameraIndex = cameraIndex;
cameraParam.cameraName = cameraName.toStdString();
cameraParam.planeHeight = planeHeight;
cameraParam.isCalibrated = true;
+ cameraParam.errorCompensation = errorCompensation;
// 复制校准矩阵
for (int i = 0; i < 9; i++) {
@@ -508,7 +527,7 @@ bool DialogCameraLevel::saveLevelingResults(double planeCalib[9], double planeHe
LOG_INFO("Leveling results saved successfully for camera %d (%s)\n",
cameraIndex, cameraName.toUtf8().constData());
- LOG_INFO("Plane height: %.3f\n", planeHeight);
+ LOG_INFO("Plane height: %.3f, Error compensation: %.2f\n", planeHeight, errorCompensation);
return true;
@@ -536,12 +555,18 @@ bool DialogCameraLevel::loadCameraCalibrationData(int cameraIndex, const QString
}
planeHeight = param.planeHeight;
+ // 加载该相机的误差补偿值到UI
+ ui->edit_error_compensation->setText(QString::number(param.errorCompensation, 'f', 1));
+
LOG_INFO("Calibration data loaded successfully for camera %d (%s)\n",
cameraIndex, cameraName.toUtf8().constData());
return true;
}
}
+ // 没有找到标定数据时,设置默认误差补偿值
+ ui->edit_error_compensation->setText(QString::number(-5.0, 'f', 1));
+
LOG_INFO("No calibration data found for camera %d (%s)\n",
cameraIndex, cameraName.toUtf8().constData());
return false;
@@ -627,3 +652,54 @@ void DialogCameraLevel::restorePresenterStatusCallback()
LOG_INFO("Presenter status callback restored for all cameras\n");
}
+
+void DialogCameraLevel::on_btn_save_compensation_clicked()
+{
+ // 保存误差补偿值到当前相机的调平参数
+ if (!m_pConfig || !m_pConfigResult) {
+ LOG_ERROR("Config is null, cannot save error compensation\n");
+ return;
+ }
+
+ if (m_currentCameraIndex < 0 || m_currentCameraIndex >= static_cast(m_cameraList.size())) {
+ LOG_WARNING("Invalid camera index: %d\n", m_currentCameraIndex);
+ return;
+ }
+
+ // 获取UI中的误差补偿值
+ double errorCompensation = ui->edit_error_compensation->text().toDouble();
+ int cameraIndex = m_currentCameraIndex + 1; // 转换为1-based索引
+ QString cameraName = QString::fromStdString(m_cameraList[m_currentCameraIndex].first);
+
+ LOG_INFO("Saving error compensation for camera %d (%s): %.2f\n",
+ cameraIndex, cameraName.toUtf8().constData(), errorCompensation);
+
+ // 查找或创建相机调平参数
+ bool found = false;
+ for (auto& param : m_pConfigResult->planeCalibParams) {
+ if (param.cameraIndex == cameraIndex) {
+ param.errorCompensation = errorCompensation;
+ found = true;
+ break;
+ }
+ }
+
+ // 如果没有找到现有记录,创建一个新的(仅包含误差补偿,其他值为默认)
+ if (!found) {
+ WheelCameraPlaneCalibParam newParam;
+ newParam.cameraIndex = cameraIndex;
+ newParam.cameraName = cameraName.toStdString();
+ newParam.errorCompensation = errorCompensation;
+ newParam.isCalibrated = false; // 尚未标定
+ m_pConfigResult->planeCalibParams.push_back(newParam);
+ }
+
+ // 保存配置到文件
+ QString configPath = PathManager::GetInstance().GetConfigFilePath();
+ bool saveResult = m_pConfig->SaveConfig(configPath.toStdString(), *m_pConfigResult);
+ if (saveResult) {
+ LOG_INFO("Error compensation saved successfully for camera %d: %.2f\n", cameraIndex, errorCompensation);
+ } else {
+ LOG_ERROR("Failed to save error compensation\n");
+ }
+}
diff --git a/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.h b/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.h
index f73ab59..b2ff263 100644
--- a/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.h
+++ b/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.h
@@ -48,6 +48,7 @@ private slots:
void on_btn_apply_clicked();
void on_btn_cancel_clicked();
void on_combo_camera_currentIndexChanged(int index);
+ void on_btn_save_compensation_clicked();
private:
Ui::DialogCameraLevel *ui;
diff --git a/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.ui b/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.ui
index 1d8c4f9..9a72e57 100644
--- a/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.ui
+++ b/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.ui
@@ -180,6 +180,111 @@ background-color: rgb(47, 48, 52);
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 16
+
+
+
+ color: rgb(221, 225, 233);
+
+
+ 误差补偿:
+
+
+
+ -
+
+
+
+ 100
+ 35
+
+
+
+
+ 100
+ 16777215
+
+
+
+
+ 16
+
+
+
+ color: rgb(221, 225, 233);
+background-color: rgb(47, 48, 52);
+
+
+ -5.0
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 14
+
+
+
+ color: rgb(221, 225, 233);
+
+
+ mm
+
+
+
+ -
+
+
+
+ 60
+ 35
+
+
+
+
+ 60
+ 35
+
+
+
+
+ 14
+
+
+
+ QPushButton {
+ color: rgb(221, 225, 233);
+ background-color: rgb(60, 63, 65);
+ border: 1px solid #3B3D47;
+ border-radius: 4px;
+}
+QPushButton:hover {
+ background-color: rgb(80, 83, 85);
+}
+QPushButton:pressed {
+ background-color: rgb(45, 48, 50);
+}
+
+
+ 保存
+
+
+
-
diff --git a/App/WheelMeasure/WheelMeasureApp/mainwindow.cpp b/App/WheelMeasure/WheelMeasureApp/mainwindow.cpp
index 3f4843f..e336137 100644
--- a/App/WheelMeasure/WheelMeasureApp/mainwindow.cpp
+++ b/App/WheelMeasure/WheelMeasureApp/mainwindow.cpp
@@ -78,12 +78,10 @@ MainWindow::MainWindow(QWidget *parent)
connect(m_presenter, &WheelMeasurePresenter::configUpdated, this, &MainWindow::onConfigSaved);
// 连接设备点击信号到重新检测槽函数
- connect(m_deviceStatusWidget, &DeviceStatusWidget::deviceClicked,
- this, &MainWindow::onDeviceClicked);
+ connect(m_deviceStatusWidget, &DeviceStatusWidget::deviceClicked, this, &MainWindow::onDeviceClicked);
// 连接图像右键点击信号到保存数据槽函数
- connect(m_gridView, &ImageGridWidget::tileRightClicked,
- this, &MainWindow::onTileRightClicked);
+ connect(m_gridView, &ImageGridWidget::tileRightClicked, this, &MainWindow::onTileRightClicked);
// 设置版本信息显示
setupVersionDisplay();
@@ -100,6 +98,11 @@ MainWindow::MainWindow(QWidget *parent)
MainWindow::~MainWindow()
{
+ // 先清除回调,防止后台线程继续调用
+ if (m_presenter) {
+ m_presenter->setStatusUpdate(nullptr);
+ }
+
if (m_gridView) {
delete m_gridView;
m_gridView = nullptr;
@@ -141,6 +144,7 @@ MainWindow::~MainWindow()
}
delete ui;
+ LOG_DEBUG("~MainWindow finish \n");
}
void MainWindow::resizeEvent(QResizeEvent* event)
@@ -353,9 +357,9 @@ void MainWindow::onDeviceClicked(const QString& deviceName)
void MainWindow::onConfigSaved()
{
- if (m_presenter) {
- m_presenter->Init();
- }
+ // 配置已在 WheelMeasurePresenter::OnConfigChanged 中更新
+ // 算法参数和调平参数的修改不需要重新初始化相机
+ LOG_INFO("Config saved, configuration updated in memory\n");
}
void MainWindow::onTileRightClicked(int index, const QString& alias)
diff --git a/App/WheelMeasure/WheelMeasureApp/mainwindow.ui b/App/WheelMeasure/WheelMeasureApp/mainwindow.ui
index b4713e4..e3c56c8 100644
--- a/App/WheelMeasure/WheelMeasureApp/mainwindow.ui
+++ b/App/WheelMeasure/WheelMeasureApp/mainwindow.ui
@@ -322,9 +322,9 @@ border: none;
1340
- 760
+ 800
560
- 230
+ 190
@@ -347,7 +347,7 @@ border: none;
1340
230
560
- 520
+ 560
diff --git a/App/WheelMeasure/WheelMeasureApp/widgets/MeasureResultListWidget.cpp b/App/WheelMeasure/WheelMeasureApp/widgets/MeasureResultListWidget.cpp
index e63d316..36bb288 100644
--- a/App/WheelMeasure/WheelMeasureApp/widgets/MeasureResultListWidget.cpp
+++ b/App/WheelMeasure/WheelMeasureApp/widgets/MeasureResultListWidget.cpp
@@ -22,29 +22,29 @@ void DeviceResultCard::setupUI()
" background-color: rgb(47, 48, 52); "
" border: 1px solid rgb(60, 62, 68); "
" border-radius: 8px; "
- " padding: 10px; "
+ " padding: 6px; "
"} "
"DeviceResultCard:hover { "
" border: 1px solid rgb(80, 82, 88); "
"}"
);
- setMinimumHeight(120);
- setMaximumHeight(160);
+ setMinimumHeight(130);
+ setMaximumHeight(170);
// 主布局:水平布局(左侧名称 | 右侧数据)
QHBoxLayout* mainLayout = new QHBoxLayout(this);
- mainLayout->setContentsMargins(12, 8, 12, 8);
- mainLayout->setSpacing(15);
+ mainLayout->setContentsMargins(8, 4, 8, 4);
+ mainLayout->setSpacing(10);
// 左侧:设备名称和状态
QVBoxLayout* leftLayout = new QVBoxLayout();
- leftLayout->setSpacing(4);
+ leftLayout->setSpacing(2);
m_nameLabel = new QLabel(m_deviceName, this);
m_nameLabel->setStyleSheet("QLabel { color: rgb(221, 225, 233); font-size: 16px; background: transparent; }");
m_nameLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
- m_nameLabel->setMinimumWidth(80);
+ m_nameLabel->setMinimumWidth(60);
m_statusLabel = new QLabel(QString::fromUtf8("等待检测"), this);
m_statusLabel->setStyleSheet("QLabel { color: rgb(150, 150, 150); font-size: 16px; background: transparent; }");
@@ -65,21 +65,25 @@ void DeviceResultCard::setupUI()
// 右侧:纵向显示数据
QVBoxLayout* rightLayout = new QVBoxLayout();
- rightLayout->setSpacing(2);
+ rightLayout->setSpacing(4);
// 拱高
m_heightLabel = new QLabel(QString::fromUtf8("拱高: -- mm"), this);
m_heightLabel->setStyleSheet("QLabel { color: rgb(100, 200, 100); font-size: 16px; background: transparent; }");
+ // 到地面高度
+ m_groundHeightLabel = new QLabel(QString::fromUtf8("到地面: -- mm"), this);
+ m_groundHeightLabel->setStyleSheet("QLabel { color: rgb(100, 180, 220); font-size: 16px; background: transparent; }");
+
// 拱点位置
m_archPosLabel = new QLabel(QString::fromUtf8("拱点: X:-- Y:-- Z:--"), this);
m_archPosLabel->setStyleSheet("QLabel { color: rgb(180, 180, 180); font-size: 14px; background: transparent; }");
- // 上位置
+ // 上点位置
m_upPosLabel = new QLabel(QString::fromUtf8("上点: X:-- Y:-- Z:--"), this);
m_upPosLabel->setStyleSheet("QLabel { color: rgb(180, 180, 180); font-size: 14px; background: transparent; }");
- // 下位置
+ // 下点位置
m_downPosLabel = new QLabel(QString::fromUtf8("下点: X:-- Y:-- Z:--"), this);
m_downPosLabel->setStyleSheet("QLabel { color: rgb(180, 180, 180); font-size: 14px; background: transparent; }");
@@ -89,6 +93,7 @@ void DeviceResultCard::setupUI()
rightLayout->addStretch();
rightLayout->addWidget(m_heightLabel);
+ rightLayout->addWidget(m_groundHeightLabel);
rightLayout->addWidget(m_archPosLabel);
rightLayout->addWidget(m_upPosLabel);
rightLayout->addWidget(m_downPosLabel);
@@ -105,6 +110,10 @@ void DeviceResultCard::updateResult(const WheelMeasureData& data, bool isValid)
m_heightLabel->setText(QString::fromUtf8("拱高: %1 mm").arg(data.archToCenterHeight, 0, 'f', 2));
m_heightLabel->setStyleSheet("QLabel { color: rgb(100, 200, 100); font-size: 16px; background: transparent; }");
+ // 更新到地面高度
+ m_groundHeightLabel->setText(QString::fromUtf8("到地面: %1 mm").arg(data.archToGroundHeight, 0, 'f', 2));
+ m_groundHeightLabel->setStyleSheet("QLabel { color: rgb(100, 180, 220); font-size: 16px; background: transparent; }");
+
// 更新拱点位置
QString archPosText = QString::fromUtf8("拱点: X:%1 Y:%2 Z:%3")
.arg(data.wheelArchPosX, 0, 'f', 2)
@@ -112,14 +121,14 @@ void DeviceResultCard::updateResult(const WheelMeasureData& data, bool isValid)
.arg(data.wheelArchPosZ, 0, 'f', 2);
m_archPosLabel->setText(archPosText);
- // 更新上位置
+ // 更新上点位置
QString upPosText = QString::fromUtf8("上点: X:%1 Y:%2 Z:%3")
.arg(data.wheelUpPosX, 0, 'f', 2)
.arg(data.wheelUpPosY, 0, 'f', 2)
.arg(data.wheelUpPosZ, 0, 'f', 2);
m_upPosLabel->setText(upPosText);
- // 更新下位置
+ // 更新下点位置
QString downPosText = QString::fromUtf8("下点: X:%1 Y:%2 Z:%3")
.arg(data.wheelDownPosX, 0, 'f', 2)
.arg(data.wheelDownPosY, 0, 'f', 2)
@@ -140,6 +149,9 @@ void DeviceResultCard::updateResult(const WheelMeasureData& data, bool isValid)
m_heightLabel->setText(QString::fromUtf8("拱高: -- mm"));
m_heightLabel->setStyleSheet("QLabel { color: rgb(200, 100, 100); font-size: 16px; background: transparent; }");
+ m_groundHeightLabel->setText(QString::fromUtf8("到地面: -- mm"));
+ m_groundHeightLabel->setStyleSheet("QLabel { color: rgb(200, 100, 100); font-size: 16px; background: transparent; }");
+
m_archPosLabel->setText(QString::fromUtf8("拱点: X:-- Y:-- Z:--"));
m_upPosLabel->setText(QString::fromUtf8("上点: X:-- Y:-- Z:--"));
m_downPosLabel->setText(QString::fromUtf8("下点: X:-- Y:-- Z:--"));
@@ -156,6 +168,8 @@ void DeviceResultCard::clearResult()
{
m_heightLabel->setText(QString::fromUtf8("拱高: -- mm"));
m_heightLabel->setStyleSheet("QLabel { color: rgb(150, 150, 150); font-size: 16px; background: transparent; }");
+ m_groundHeightLabel->setText(QString::fromUtf8("到地面: -- mm"));
+ m_groundHeightLabel->setStyleSheet("QLabel { color: rgb(150, 150, 150); font-size: 16px; background: transparent; }");
m_archPosLabel->setText(QString::fromUtf8("拱点: X:-- Y:-- Z:--"));
m_upPosLabel->setText(QString::fromUtf8("上点: X:-- Y:-- Z:--"));
m_downPosLabel->setText(QString::fromUtf8("下点: X:-- Y:-- Z:--"));
diff --git a/App/WheelMeasure/WheelMeasureApp/widgets/MeasureResultListWidget.h b/App/WheelMeasure/WheelMeasureApp/widgets/MeasureResultListWidget.h
index a2c877e..e8b6dbf 100644
--- a/App/WheelMeasure/WheelMeasureApp/widgets/MeasureResultListWidget.h
+++ b/App/WheelMeasure/WheelMeasureApp/widgets/MeasureResultListWidget.h
@@ -31,9 +31,10 @@ private:
QString m_deviceName;
QLabel* m_nameLabel = nullptr;
QLabel* m_heightLabel = nullptr;
+ QLabel* m_groundHeightLabel = nullptr; // 到地面高度
QLabel* m_archPosLabel = nullptr; // 拱点位置
- QLabel* m_upPosLabel = nullptr; // 上位置
- QLabel* m_downPosLabel = nullptr; // 下位置
+ QLabel* m_upPosLabel = nullptr; // 上点位置
+ QLabel* m_downPosLabel = nullptr; // 下点位置
QLabel* m_timestampLabel = nullptr;
QLabel* m_statusLabel = nullptr;
};
diff --git a/App/WheelMeasure/WheelMeasureConfig/Inc/IVrWheelMeasureConfig.h b/App/WheelMeasure/WheelMeasureConfig/Inc/IVrWheelMeasureConfig.h
index 49e34ab..e80d9f0 100644
--- a/App/WheelMeasure/WheelMeasureConfig/Inc/IVrWheelMeasureConfig.h
+++ b/App/WheelMeasure/WheelMeasureConfig/Inc/IVrWheelMeasureConfig.h
@@ -60,6 +60,7 @@ struct WheelCameraPlaneCalibParam
double planeHeight = -1; // 地面高度
double invRMatrix[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1}; // 逆旋转矩阵(回到原坐标系)
bool isCalibrated = false; // 是否已标定
+ double errorCompensation = -5.0; // 误差补偿(mm)
};
/**
@@ -154,6 +155,7 @@ struct WheelMeasureData
{
int id = 0; // 测量ID
double archToCenterHeight = 0.0; // 拱高到中心的高度
+ double archToGroundHeight = 0.0; // 拱高到地面的高度
double wheelArchPosX = 0.0; // 拱点X坐标
double wheelArchPosY = 0.0; // 拱点Y坐标
double wheelArchPosZ = 0.0; // 拱点Z坐标
diff --git a/App/WheelMeasure/WheelMeasureConfig/Src/VrWheelMeasureConfig.cpp b/App/WheelMeasure/WheelMeasureConfig/Src/VrWheelMeasureConfig.cpp
index 556bbb6..c827ebb 100644
--- a/App/WheelMeasure/WheelMeasureConfig/Src/VrWheelMeasureConfig.cpp
+++ b/App/WheelMeasure/WheelMeasureConfig/Src/VrWheelMeasureConfig.cpp
@@ -84,6 +84,12 @@ WheelMeasureConfigResult VrWheelMeasureConfig::LoadConfig(const std::string& fil
calibParam.cameraName = xml.attributes().value("name").toString().toStdString();
calibParam.planeHeight = xml.attributes().value("planeHeight").toDouble();
calibParam.isCalibrated = xml.attributes().value("isCalibrated").toInt() != 0;
+ // 读取误差补偿参数,默认值为-5.0
+ if (xml.attributes().hasAttribute("errorCompensation")) {
+ calibParam.errorCompensation = xml.attributes().value("errorCompensation").toDouble();
+ } else {
+ calibParam.errorCompensation = -5.0;
+ }
// 读取planeCalib矩阵
QString planeCalibStr = xml.attributes().value("planeCalib").toString();
@@ -321,6 +327,7 @@ bool VrWheelMeasureConfig::SaveConfig(const std::string& filePath, WheelMeasureC
xml.writeAttribute("name", QString::fromStdString(calibParam.cameraName));
xml.writeAttribute("planeHeight", QString::number(calibParam.planeHeight, 'f', 6));
xml.writeAttribute("isCalibrated", QString::number(calibParam.isCalibrated ? 1 : 0));
+ xml.writeAttribute("errorCompensation", QString::number(calibParam.errorCompensation, 'f', 2));
// 保存planeCalib矩阵
QStringList planeCalibList;
diff --git a/App/WheelMeasure/WheelMeasureConfig/config/config.xml b/App/WheelMeasure/WheelMeasureConfig/config/config.xml
index 1a8c8ee..1fbdce0 100644
--- a/App/WheelMeasure/WheelMeasureConfig/config/config.xml
+++ b/App/WheelMeasure/WheelMeasureConfig/config/config.xml
@@ -8,7 +8,7 @@
-
diff --git a/AppAlgo/wheelArchHeigthMeasure/Inc/wheelArchHeigthMeasure_Export.h b/AppAlgo/wheelArchHeigthMeasure/Inc/wheelArchHeigthMeasure_Export.h
index add0cba..d2b8912 100644
--- a/AppAlgo/wheelArchHeigthMeasure/Inc/wheelArchHeigthMeasure_Export.h
+++ b/AppAlgo/wheelArchHeigthMeasure/Inc/wheelArchHeigthMeasure_Export.h
@@ -15,6 +15,7 @@ typedef struct
SVzNL3DPoint downLine[2];
SVzNL3DPoint centerLine[2];
double archToCenterHeigth;
+ double archToGroundHeigth;
}WD_wheelArchInfo;
//汾
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.dll b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.dll
index ac8f6f0..554b2e6 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.dll and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.dll differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.pdb b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.pdb
index a56c4c9..6949361 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.pdb and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.pdb differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.dll b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.dll
index bdde987..d82f70a 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.dll and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.dll differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.pdb b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.pdb
index ed2cd4b..7ad9709 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.pdb and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.pdb differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.dll b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.dll
index 68ca831..ba323d3 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.dll and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.dll differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.pdb b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.pdb
index f9aaa84..367770d 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.pdb and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.pdb differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.dll b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.dll
index bb7d363..5ccbe29 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.dll and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.dll differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.pdb b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.pdb
index e99f746..e4ce5d9 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.pdb and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.pdb differ
diff --git a/AppUtils/AppCommon/Inc/BasePresenter.h b/AppUtils/AppCommon/Inc/BasePresenter.h
index 374f7c4..e8a784f 100644
--- a/AppUtils/AppCommon/Inc/BasePresenter.h
+++ b/AppUtils/AppCommon/Inc/BasePresenter.h
@@ -509,6 +509,9 @@ protected:
// ModbusTCP服务器
IYModbusTCPServer* m_modbusServer = nullptr;
+ // 初始化线程
+ std::thread m_initThread;
+
private:
// 启动ModbusTCP服务(在Init中调用)
int StartModbusServer(int port = 502);
diff --git a/AppUtils/AppCommon/Src/BasePresenter.cpp b/AppUtils/AppCommon/Src/BasePresenter.cpp
index 9005105..954e994 100644
--- a/AppUtils/AppCommon/Src/BasePresenter.cpp
+++ b/AppUtils/AppCommon/Src/BasePresenter.cpp
@@ -22,8 +22,10 @@ BasePresenter::BasePresenter(QObject *parent)
BasePresenter::~BasePresenter()
{
- // 停止ModbusTCP服务器
- StopModbusServer();
+ // 等待初始化线程完成
+ if (m_initThread.joinable()) {
+ m_initThread.join();
+ }
// 停止检测线程
StopAlgoDetectThread();
@@ -31,8 +33,12 @@ BasePresenter::~BasePresenter()
// 停止重连定时器
StopCameraReconnectTimer();
+ // 停止ModbusTCP服务器
+ StopModbusServer();
+
// 清理相机设备
- for (auto& camera : m_vrEyeDeviceList) {
+ for (size_t i = 0; i < m_vrEyeDeviceList.size(); ++i) {
+ auto& camera = m_vrEyeDeviceList[i];
if (camera.second) {
camera.second->CloseDevice();
delete camera.second;
@@ -46,24 +52,30 @@ int BasePresenter::Init()
{
LOG_INFO("BasePresenter::Init()\n");
- int nRet = SUCCESS;
+ // 在后台线程中执行初始化
+ m_initThread = std::thread([this]() {
+ int nRet = InitApp();
+ if (nRet != SUCCESS) {
+ LOG_ERROR("InitApp failed: %d\n", nRet);
+ return;
+ }
- nRet = InitApp();
- ERR_CODE_RETURN(nRet);
+ // 初始化算法参数
+ nRet = InitAlgoParams();
+ LOG_INFO("Algorithm parameters initialization result: %d\n", nRet);
- // 初始化算法参数
- nRet = InitAlgoParams();
- LOG_INFO("Algorithm parameters initialization result : %d\n", nRet);
+ // 启动ModbusTCP服务
+ int modbusRet = StartModbusServer(5020);
+ if (modbusRet == SUCCESS) {
+ LOG_INFO("ModbusTCP server started on port 5020\n");
+ } else {
+ LOG_WARNING("Failed to start ModbusTCP server\n");
+ }
- // 启动ModbusTCP服务
- int modbusRet = StartModbusServer(5020);
- if (modbusRet == SUCCESS) {
- LOG_INFO("ModbusTCP server started on port 502(0)\n");
- } else {
- LOG_WARNING("Failed to start ModbusTCP server\n");
- }
+ SetWorkStatus(WorkStatus::Ready);
+ });
- return nRet;
+ return SUCCESS;
}
int BasePresenter::StartDetection(int cameraIndex, bool isAuto)
@@ -462,9 +474,8 @@ void BasePresenter::StartAlgoDetectThread()
m_bAlgoDetectThreadRunning = true;
- // 启动检测线程
+ // 启动检测线程(不再detach,使用joinable线程)
m_algoDetectThread = std::thread(&BasePresenter::AlgoDetectThreadFunc, this);
- m_algoDetectThread.detach(); // 分离线程,让其独立运行
LOG_INFO("[BasePresenter] 算法检测线程已启动\n");
}
@@ -482,7 +493,10 @@ void BasePresenter::StopAlgoDetectThread()
// 唤醒可能在等待的线程
m_algoDetectCondition.notify_all();
- // 注意:因为线程使用了 detach(),所以不需要 join()
+ // 等待线程退出
+ if (m_algoDetectThread.joinable()) {
+ m_algoDetectThread.join();
+ }
LOG_INFO("[BasePresenter] 算法检测线程已停止\n");
}
@@ -628,29 +642,23 @@ void BasePresenter::StartCameraReconnectTimer()
// 使用QMetaObject::invokeMethod确保在正确的线程中操作定时器
QMetaObject::invokeMethod(this, [this]() {
if (!m_pCameraReconnectTimer) {
- LOG_ERROR("[BasePresenter] m_pCameraReconnectTimer is nullptr!\n");
return;
}
if (m_pCameraReconnectTimer->isActive()) {
- LOG_DEBUG("[BasePresenter] 相机重连定时器已在运行\n");
return;
}
m_pCameraReconnectTimer->start();
- LOG_INFO("[BasePresenter] 启动相机重连定时器(间隔: %d ms)\n", m_pCameraReconnectTimer->interval());
}, Qt::QueuedConnection);
}
void BasePresenter::StopCameraReconnectTimer()
{
- // 使用QMetaObject::invokeMethod确保在正确的线程中操作定时器
- QMetaObject::invokeMethod(this, [this]() {
- if (m_pCameraReconnectTimer && m_pCameraReconnectTimer->isActive()) {
- m_pCameraReconnectTimer->stop();
- LOG_INFO("[BasePresenter] 停止相机重连定时器\n");
- }
- }, Qt::QueuedConnection);
+ // 直接停止定时器(析构时需要立即停止,不能用QueuedConnection)
+ if (m_pCameraReconnectTimer) {
+ m_pCameraReconnectTimer->stop();
+ }
}
// ============ OnCameraReconnectTimer 实现 ============
@@ -768,7 +776,6 @@ int BasePresenter::StartModbusServer(int port)
void BasePresenter::StopModbusServer()
{
if (m_modbusServer) {
- LOG_INFO("[BasePresenter] 停止ModbusTCP服务器\n");
m_modbusServer->stop();
delete m_modbusServer;
m_modbusServer = nullptr;
diff --git a/Device/VrEyeDevice/Src/VrEyeDevice.cpp b/Device/VrEyeDevice/Src/VrEyeDevice.cpp
index d190655..6a8e18b 100644
--- a/Device/VrEyeDevice/Src/VrEyeDevice.cpp
+++ b/Device/VrEyeDevice/Src/VrEyeDevice.cpp
@@ -427,7 +427,11 @@ void CVrEyeDevice::DebugThreadFunc()
// 固定的点云文件路径
// const std::string debugFilePath = "C:\\project\\QT\\GrabBag\\TestData\\workpiece\\new\\test\\9_LazerData_Hi229229.txt";
// const std::string debugFilePath = "C:\\project\\QT\\GrabBag\\TestData\\bag\\LaserLine1_grid.txt";
+#ifdef _WIN32
const std::string debugFilePath = "C:\\project\\QT\\GrabBag\\TestData\\eye_test.txt";
+#else
+ const std::string debugFilePath = "/home/linaro/eye_test.txt";
+#endif
LaserDataLoader loader;
std::vector> laserLines;
@@ -438,24 +442,24 @@ void CVrEyeDevice::DebugThreadFunc()
// 加载点云文件
int ret = loader.LoadLaserScanData(debugFilePath, laserLines, lineNum, scanSpeed, maxTimeStamp, clockPerSecond);
- if (ret != SUCCESS) {
+ if (ret == SUCCESS) {
LOG_DEBUG("VR_EYE_DEBUG_MODE: Failed to load laser data from %s, error: %s\n",debugFilePath.c_str(), loader.GetLastError().c_str());
- return;
- }
// 循环读取并回调
- auto iter = laserLines.begin();
+ auto iter = laserLines.begin();
- while (iter != laserLines.end()) {
- if (m_debugCallback) {
- auto& dataPair = *iter;
- m_debugCallback(dataPair.first, &dataPair.second, m_debugCallbackParam);
+ while (iter != laserLines.end()) {
+ if (m_debugCallback) {
+ auto& dataPair = *iter;
+ m_debugCallback(dataPair.first, &dataPair.second, m_debugCallbackParam);
+ }
+
+ iter++;
+ // 模拟采集间隔,约30ms
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
}
-
- iter++;
- // 模拟采集间隔,约30ms
- std::this_thread::sleep_for(std::chrono::milliseconds(2));
}
+
if (m_debugStatusCallback) {
m_debugStatusCallback(keDeviceWorkStatus_Device_Swing_Finish, nullptr, 0, m_debugStatusCallbackParam);
m_debugStatusCallback(keDeviceWorkStatus_Device_Auto_Stop, nullptr, 0, m_debugStatusCallbackParam);
diff --git a/Module/ModbusTCPServer/Src/ModbusTCPServer.cpp b/Module/ModbusTCPServer/Src/ModbusTCPServer.cpp
index 17494e6..d08df67 100644
--- a/Module/ModbusTCPServer/Src/ModbusTCPServer.cpp
+++ b/Module/ModbusTCPServer/Src/ModbusTCPServer.cpp
@@ -95,8 +95,10 @@ void ModbusTCPServer::stop()
return;
}
+ LOG_INFO("[ModbusTCPServer] stop()\n");
+
m_shouldStop.store(true);
-
+
// 关闭服务器socket以中断accept调用
if (m_serverSocket != -1) {
#ifdef _WIN32
@@ -135,57 +137,69 @@ void ModbusTCPServer::stop()
void ModbusTCPServer::serverLoop()
{
fd_set readfds;
- int maxfd = m_serverSocket;
-
+
while (!m_shouldStop.load()) {
+ // 检查服务器socket是否有效
+ int serverSock = m_serverSocket;
+ if (serverSock == -1) {
+ break; // socket已关闭,退出循环
+ }
+
FD_ZERO(&readfds);
- FD_SET(m_serverSocket, &readfds);
-
- maxfd = m_serverSocket;
-
+ FD_SET(serverSock, &readfds);
+
+ int maxfd = serverSock;
+
// 添加所有客户端socket到监听集合
{
std::lock_guard lock(m_clientsMutex);
for (const auto& pair : m_clients) {
int clientSocket = pair.first;
- FD_SET(clientSocket, &readfds);
- if (clientSocket > maxfd) {
- maxfd = clientSocket;
+ if (clientSocket >= 0) {
+ FD_SET(clientSocket, &readfds);
+ if (clientSocket > maxfd) {
+ maxfd = clientSocket;
+ }
}
}
}
-
+
// 设置超时时间(1秒),避免阻塞太久
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
-
+
int selectResult = select(maxfd + 1, &readfds, nullptr, nullptr, &timeout);
-
+
+ // 再次检查是否应该停止
+ if (m_shouldStop.load()) {
+ break;
+ }
+
if (selectResult == -1) {
if (!m_shouldStop.load()) {
LOG_WARNING("select error: %s\n", strerror(errno));
}
break;
}
-
+
if (selectResult == 0) {
// 超时,继续循环
continue;
}
-
+
// 检查服务器socket是否有新连接
- if (FD_ISSET(m_serverSocket, &readfds)) {
+ if (serverSock >= 0 && FD_ISSET(serverSock, &readfds)) {
handleNewConnection();
}
-
+
// 检查客户端socket是否有数据
std::vector socketsToRemove;
{
std::lock_guard lock(m_clientsMutex);
for (const auto& pair : m_clients) {
int clientSocket = pair.first;
- if (FD_ISSET(clientSocket, &readfds)) {
+ if (clientSocket >= 0 && FD_ISSET(clientSocket, &readfds)) {
try {
handleClientData(pair.second);
} catch (...) {
@@ -195,7 +209,7 @@ void ModbusTCPServer::serverLoop()
}
}
}
-
+
// 删除有问题的客户端连接
for (int socket : socketsToRemove) {
removeClient(socket);