重构相机调平逻辑,增加状态回调功能以优化扫描完成检测,调整UI元素布局。

This commit is contained in:
杰仔 2025-06-29 13:06:47 +08:00
parent c9b7ad4642
commit e4d42c5a72
13 changed files with 272 additions and 55 deletions

View File

@ -44,12 +44,18 @@ public:
void GetCameraListWithNames(std::vector<IVrEyeDevice*>& cameraList, std::vector<QString>& cameraNames); void GetCameraListWithNames(std::vector<IVrEyeDevice*>& cameraList, std::vector<QString>& cameraNames);
bool IsCameraConnected(int index); bool IsCameraConnected(int index);
// 为所有相机设置状态回调
void SetCameraStatusCallback(VzNL_OnNotifyStatusCBEx fNotify, void* param);
// 获取配置对象 // 获取配置对象
IVrConfig* GetConfig() { return m_vrConfig; } IVrConfig* GetConfig() { return m_vrConfig; }
// 实现IVrConfigChangeNotify接口 // 实现IVrConfigChangeNotify接口
virtual void OnConfigChanged(const ConfigResult& configResult) override; virtual void OnConfigChanged(const ConfigResult& configResult) override;
// 静态回调函数,供外部使用
static void _StaticCameraNotify(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
private: private:
// 机械臂协议相关方法 // 机械臂协议相关方法
int InitRobotProtocol(); int InitRobotProtocol();
@ -64,9 +70,6 @@ private:
// 连接状态检查和更新 // 连接状态检查和更新
void CheckAndUpdateWorkStatus(); void CheckAndUpdateWorkStatus();
// 静态回调函数用于传递给SDK
static void _StaticCameraNotify(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
// 实例方法,处理回调 // 实例方法,处理回调
void _CameraNotify(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam); void _CameraNotify(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);

View File

@ -120,7 +120,12 @@ int GrabBagPresenter::Init()
nRet = pDevice->InitDevice(); nRet = pDevice->InitDevice();
ERR_CODE_RETURN(nRet); ERR_CODE_RETURN(nRet);
nRet = pDevice->OpenDevice(configResult.cameraList[0].ip.c_str(), &GrabBagPresenter::_StaticCameraNotify, this); // 先设置状态回调
nRet = pDevice->SetStatusCallback(&GrabBagPresenter::_StaticCameraNotify, this);
ERR_CODE_RETURN(nRet);
// 再打开设备
nRet = pDevice->OpenDevice(configResult.cameraList[0].ip.c_str());
// 通过回调更新相机1状态 // 通过回调更新相机1状态
bool camera1Connected = (SUCCESS == nRet); bool camera1Connected = (SUCCESS == nRet);
if(camera1Connected){ if(camera1Connected){
@ -141,15 +146,19 @@ int GrabBagPresenter::Init()
m_pStatus->OnCamera1StatusChanged(false); m_pStatus->OnCamera1StatusChanged(false);
m_bCameraConnected = false; m_bCameraConnected = false;
} }
ERR_CODE_RETURN(nRet);
if (cameraCount >= 2) { if (cameraCount >= 2) {
IVrEyeDevice* pDevice = nullptr; IVrEyeDevice* pDevice = nullptr;
IVrEyeDevice::CreateObject(&pDevice); IVrEyeDevice::CreateObject(&pDevice);
nRet = pDevice->InitDevice(); nRet = pDevice->InitDevice();
ERR_CODE_RETURN(nRet); ERR_CODE_RETURN(nRet);
// 先设置状态回调
nRet = pDevice->SetStatusCallback(&GrabBagPresenter::_StaticCameraNotify, this);
ERR_CODE_RETURN(nRet);
// 尝试打开相机2 // 尝试打开相机2
nRet = pDevice->OpenDevice(configResult.cameraList[1].ip.c_str(), &GrabBagPresenter::_StaticCameraNotify, this); nRet = pDevice->OpenDevice(configResult.cameraList[1].ip.c_str());
// 通过回调更新相机2状态 // 通过回调更新相机2状态
bool camera2Connected = (SUCCESS == nRet); bool camera2Connected = (SUCCESS == nRet);
if(camera2Connected) if(camera2Connected)
@ -167,14 +176,18 @@ int GrabBagPresenter::Init()
// 如果只有一个相机则将相机2状态设为未连接 // 如果只有一个相机则将相机2状态设为未连接
m_pStatus->OnCamera2StatusChanged(false); m_pStatus->OnCamera2StatusChanged(false);
} }
ERR_CODE_RETURN(nRet);
} else { } else {
IVrEyeDevice* pDevice = nullptr; IVrEyeDevice* pDevice = nullptr;
IVrEyeDevice::CreateObject(&pDevice); IVrEyeDevice::CreateObject(&pDevice);
nRet = pDevice->InitDevice(); nRet = pDevice->InitDevice();
ERR_CODE_RETURN(nRet); ERR_CODE_RETURN(nRet);
// 先设置状态回调
nRet = pDevice->SetStatusCallback(&GrabBagPresenter::_StaticCameraNotify, this);
ERR_CODE_RETURN(nRet);
// 尝试打开相机1 // 尝试打开相机1
nRet = pDevice->OpenDevice(nullptr, &GrabBagPresenter::_StaticCameraNotify, this); nRet = pDevice->OpenDevice(nullptr);
// 通过回调更新相机1状态 // 通过回调更新相机1状态
bool camera1Connected = (SUCCESS == nRet); bool camera1Connected = (SUCCESS == nRet);
if(camera1Connected) if(camera1Connected)
@ -572,6 +585,18 @@ bool GrabBagPresenter::IsCameraConnected(int index)
return (pDevice != nullptr); return (pDevice != nullptr);
} }
// 为所有相机设置状态回调
void GrabBagPresenter::SetCameraStatusCallback(VzNL_OnNotifyStatusCBEx fNotify, void* param)
{
for (size_t i = 0; i < m_vrEyeDeviceList.size(); i++) {
IVrEyeDevice* pDevice = m_vrEyeDeviceList[i];
if (pDevice) {
pDevice->SetStatusCallback(fNotify, param);
LOG_DEBUG("Status callback set for camera %zu\n", i + 1);
}
}
}
// 静态回调函数实现 // 静态回调函数实现
void GrabBagPresenter::_StaticCameraNotify(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam) void GrabBagPresenter::_StaticCameraNotify(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)

View File

@ -3,8 +3,8 @@
#define GRABBAG_VERSION_STRING "1.0.0" #define GRABBAG_VERSION_STRING "1.0.0"
#define GRABBAG_BUILD_STRING "6" #define GRABBAG_BUILD_STRING "7"
#define GRABBAG_FULL_VERSION_STRING "V1.0.0_6" #define GRABBAG_FULL_VERSION_STRING "V1.0.0_7"
// 获取版本信息的便捷函数 // 获取版本信息的便捷函数
inline const char* GetGrabBagVersion() { inline const char* GetGrabBagVersion() {
@ -20,3 +20,4 @@ inline const char* GetGrabBagFullVersion() {
} }
#endif // VERSION_H #endif // VERSION_H

View File

@ -11,14 +11,12 @@
#include "StyledMessageBox.h" #include "StyledMessageBox.h"
#ifdef LEVEL_DEBUG_MODE
#include "LaserDataLoader.h" #include "LaserDataLoader.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QFileInfo> #include <QFileInfo>
#include <QTimer> #include <QTimer>
#include <QFileDialog> #include <QFileDialog>
#include <QStandardPaths> #include <QStandardPaths>
#endif
DialogCameraLevel::DialogCameraLevel(QWidget *parent) DialogCameraLevel::DialogCameraLevel(QWidget *parent)
: QDialog(parent) : QDialog(parent)
@ -42,6 +40,9 @@ DialogCameraLevel::~DialogCameraLevel()
// 清理扫描数据缓存 // 清理扫描数据缓存
clearScanDataCache(); clearScanDataCache();
// 确保恢复Presenter的状态回调
restorePresenterStatusCallback();
delete ui; delete ui;
} }
@ -105,14 +106,11 @@ void DialogCameraLevel::on_btn_apply_clicked()
try { try {
// 执行相机调平 // 执行相机调平
if (performCameraLeveling()) { if (performCameraLeveling()) {
// StyledMessageBox::information(this, "成功", "相机调平完成!标定结果已保存。"); // 调平成功,关闭对话框(这会触发析构函数中的回调恢复)
// 关闭对话框
// accept(); // accept();
} else { } else {
// 显示失败信息到界面 // 显示失败信息到界面
ui->label_level_result->setText("调平失败!\n\n请检查:\n1. 相机连接是否正常\n2. 地面扫描数据是否充足\n3. 扫描区域是否有足够的地面"); ui->label_level_result->setText("调平失败!\n\n请检查:\n1. 相机连接是否正常\n2. 地面扫描数据是否充足\n3. 扫描区域是否有足够的地面");
// StyledMessageBox::critical(this, "失败", "相机调平失败!请检查相机连接和地面扫描数据。");
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG_ERROR("Camera leveling failed with exception: %s\n", e.what()); LOG_ERROR("Camera leveling failed with exception: %s\n", e.what());
@ -135,6 +133,9 @@ bool DialogCameraLevel::performCameraLeveling()
// 获取选中的相机索引 // 获取选中的相机索引
int selectedIndex = ui->combo_camera->currentIndex(); int selectedIndex = ui->combo_camera->currentIndex();
// 1. 设置调平状态回调
setLevelingStatusCallback();
#ifdef LEVEL_DEBUG_MODE #ifdef LEVEL_DEBUG_MODE
// Debug模式使用文件对话框选择测试数据 // Debug模式使用文件对话框选择测试数据
LOG_INFO("=== DEBUG MODE ENABLED ===\n"); LOG_INFO("=== DEBUG MODE ENABLED ===\n");
@ -160,30 +161,36 @@ bool DialogCameraLevel::performCameraLeveling()
LOG_INFO("Performing camera leveling with camera %d (index %d)\n", selectedIndex + 1, selectedIndex); LOG_INFO("Performing camera leveling with camera %d (index %d)\n", selectedIndex + 1, selectedIndex);
// 1. 清空之前的扫描数据 // 2. 清空之前的扫描数据
clearScanDataCache(); clearScanDataCache();
m_scanCompleted = false;
// 2. 启动相机扫描地面数据 // 3. 启动相机扫描地面数据
if (!startCameraScan(selectedIndex)) { if (!startCameraScan(selectedIndex)) {
LOG_ERROR("Failed to start camera scan for leveling\n"); LOG_ERROR("Failed to start camera scan for leveling\n");
return false; return false;
} }
// 3. 等待数据收集完成 // 4. 等待扫描完成(使用状态回调判断)
LOG_INFO("Collecting ground scan data...\n"); LOG_INFO("Collecting ground scan data, waiting for swing finish signal...\n");
int waitTime = 0; int waitTime = 0;
const int maxWaitTime = 5000; // 最大等待5 const int maxWaitTime = 10000; // 最大等待10
const int checkInterval = 100; // 每100ms检查一次 const int checkInterval = 100; // 每100ms检查一次
while (!m_scanCompleted && waitTime < maxWaitTime) { while (!m_swingFinished && waitTime < maxWaitTime) {
QThread::msleep(checkInterval); QThread::msleep(checkInterval);
QApplication::processEvents(); // 处理UI事件 QApplication::processEvents(); // 处理UI事件
waitTime += checkInterval; waitTime += checkInterval;
} }
// 4. 停止扫描 // 5. 停止扫描
stopCameraScan(selectedIndex); stopCameraScan(selectedIndex);
// 检查是否通过状态回调收到了扫描完成信号
if (m_swingFinished) {
LOG_INFO("Camera swing finished signal received, scan completed\n");
} else if (waitTime >= maxWaitTime) {
LOG_WARNING("Timeout waiting for camera swing finish signal\n");
}
#endif #endif
// 5. 检查是否收集到足够的数据 // 5. 检查是否收集到足够的数据
@ -225,11 +232,14 @@ bool DialogCameraLevel::performCameraLeveling()
return false; return false;
} }
clearScanDataCache();
LOG_INFO("Camera leveling completed successfully\n"); LOG_INFO("Camera leveling completed successfully\n");
return true; return true;
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG_ERROR("Exception in performCameraLeveling: %s\n", e.what()); LOG_ERROR("Exception in performCameraLeveling: %s\n", e.what());
return false; return false;
} }
} }
@ -330,6 +340,33 @@ void DialogCameraLevel::StaticDetectionCallback(EVzResultDataType eDataType, SVz
} }
} }
// 静态状态回调函数
void DialogCameraLevel::StaticStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)
{
DialogCameraLevel* pThis = reinterpret_cast<DialogCameraLevel*>(pInfoParam);
if (pThis) {
pThis->StatusCallback(eStatus, pExtData, nDataLength, pInfoParam);
}
}
// 状态回调函数实例版本
void DialogCameraLevel::StatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)
{
LOG_DEBUG("[Leveling Status Callback] received: status=%d\n", (int)eStatus);
switch (eStatus) {
case EVzDeviceWorkStatus::keDeviceWorkStatus_Device_Swing_Finish:
{
LOG_INFO("[Leveling Status Callback] Camera swing finished, scan completed\n");
m_swingFinished = true; // 摆动完成即表示扫描完成
break;
}
default:
LOG_DEBUG("[Leveling Status Callback] Other status: %d\n", (int)eStatus);
break;
}
}
// 检测数据回调函数实例版本 // 检测数据回调函数实例版本
void DialogCameraLevel::DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint) void DialogCameraLevel::DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint)
{ {
@ -363,12 +400,6 @@ void DialogCameraLevel::DetectionCallback(EVzResultDataType eDataType, SVzLaserL
// 将转换后的数据保存到缓存中 // 将转换后的数据保存到缓存中
std::lock_guard<std::mutex> lock(m_scanDataMutex); std::lock_guard<std::mutex> lock(m_scanDataMutex);
m_scanDataCache.push_back(laser3DLine); m_scanDataCache.push_back(laser3DLine);
// 当收集到足够的数据时,标记扫描完成
if (m_scanDataCache.size() >= 50) { // 假设需要至少50条扫描线
m_scanCompleted = true;
LOG_INFO("Scan completed with %zu lines collected\n", m_scanDataCache.size());
}
} }
// 调平算法计算 // 调平算法计算
@ -571,7 +602,6 @@ bool DialogCameraLevel::loadDebugDataAndSimulateScan(const QString& filePath)
try { try {
// 清空之前的扫描数据 // 清空之前的扫描数据
clearScanDataCache(); clearScanDataCache();
m_scanCompleted = false;
// 使用LaserDataLoader加载测试数据 // 使用LaserDataLoader加载测试数据
LaserDataLoader dataLoader; LaserDataLoader dataLoader;
@ -650,7 +680,7 @@ void DialogCameraLevel::simulateScanProcess()
// 连接定时器信号 // 连接定时器信号
connect(simulationTimer, &QTimer::timeout, [this, simulationTimer]() { connect(simulationTimer, &QTimer::timeout, [this, simulationTimer]() {
LOG_INFO("Scan simulation completed\n"); LOG_INFO("Scan simulation completed\n");
m_scanCompleted = true; m_swingFinished = true; // Debug模式下模拟摆动完成
// 显示调试信息 // 显示调试信息
{ {
@ -765,3 +795,41 @@ void DialogCameraLevel::checkAndDisplayCalibrationStatus(int cameraIndex)
} }
} }
// 设置调平时的状态回调
void DialogCameraLevel::setLevelingStatusCallback()
{
if (!m_presenter) {
LOG_ERROR("Presenter is null, cannot set leveling status callback\n");
return;
}
// 为所有相机设置调平状态回调
m_presenter->SetCameraStatusCallback(&DialogCameraLevel::StaticStatusCallback, this);
// 重置状态标志
m_swingFinished = false;
m_callbackRestored = false; // 重置恢复标志,允许稍后恢复
LOG_INFO("Leveling status callback set for all cameras\n");
}
// 恢复Presenter的状态回调
void DialogCameraLevel::restorePresenterStatusCallback()
{
// 检查是否已经恢复过回调,避免重复调用
if (m_callbackRestored.exchange(true)) {
LOG_DEBUG("Presenter status callback already restored, skipping\n");
return;
}
if (!m_presenter) {
LOG_ERROR("Presenter is null, cannot restore status callback\n");
return;
}
// 恢复Presenter的状态回调 - 使用GrabBagPresenter的静态回调
m_presenter->SetCameraStatusCallback(&GrabBagPresenter::_StaticCameraNotify, m_presenter);
LOG_INFO("Presenter status callback restored for all cameras\n");
}

View File

@ -14,7 +14,7 @@
#include "VZNL_Types.h" #include "VZNL_Types.h"
#define LEVEL_DEBUG_MODE // #define LEVEL_DEBUG_MODE
namespace Ui { namespace Ui {
class DialogCameraLevel; class DialogCameraLevel;
@ -29,8 +29,7 @@ public:
~DialogCameraLevel(); ~DialogCameraLevel();
// 设置相机列表和presenter // 设置相机列表和presenter
void setCameraList(const std::vector<IVrEyeDevice*>& cameraList, void setCameraList(const std::vector<IVrEyeDevice*>& cameraList, const std::vector<QString>& cameraNames,
const std::vector<QString>& cameraNames,
GrabBagPresenter* presenter); GrabBagPresenter* presenter);
private slots: private slots:
@ -49,7 +48,10 @@ private:
// 扫描数据缓存 // 扫描数据缓存
std::vector<SVzNL3DLaserLine> m_scanDataCache; std::vector<SVzNL3DLaserLine> m_scanDataCache;
std::mutex m_scanDataMutex; std::mutex m_scanDataMutex;
bool m_scanCompleted = false;
// 状态回调相关
std::atomic<bool> m_swingFinished = false; // 摆动完成标志,同时表示扫描完成
std::atomic<bool> m_callbackRestored = false;
// 初始化相机选择框 // 初始化相机选择框
void initializeCameraCombo(); void initializeCameraCombo();
@ -65,18 +67,24 @@ private:
static void StaticDetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pUserData); static void StaticDetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pUserData);
void DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint); void DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint);
// 状态回调函数
static void StaticStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
void StatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
// 设置和恢复状态回调
void setLevelingStatusCallback();
void restorePresenterStatusCallback();
// 处理扫描到的地面数据进行调平计算 // 处理扫描到的地面数据进行调平计算
bool calculatePlaneCalibration(double planeCalib[9], double& planeHeight, double invRMatrix[9]); bool calculatePlaneCalibration(double planeCalib[9], double& planeHeight, double invRMatrix[9]);
// 清空扫描数据缓存 // 清空扫描数据缓存
void clearScanDataCache(); void clearScanDataCache();
#ifdef LEVEL_DEBUG_MODE
// Debug模式方法 // Debug模式方法
QString selectDebugDataFile(); QString selectDebugDataFile();
bool loadDebugDataAndSimulateScan(const QString& filePath); bool loadDebugDataAndSimulateScan(const QString& filePath);
void simulateScanProcess(); void simulateScanProcess();
#endif
// 更新调平结果显示 // 更新调平结果显示
void updateLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9]); void updateLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9]);

View File

@ -6,6 +6,7 @@
#include <QSystemSemaphore> #include <QSystemSemaphore>
#include <QMessageBox> #include <QMessageBox>
#include <QDebug> #include <QDebug>
#include <QObject>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -14,7 +15,52 @@ int main(int argc, char *argv[])
// 设置应用程序图标 // 设置应用程序图标
a.setWindowIcon(QIcon(":/resource/logo.png")); a.setWindowIcon(QIcon(":/resource/logo.png"));
// 使用应用程序名称作为唯一标识符
const QString appKey = "GrabBagApp_SingleInstance_Key";
// 创建系统信号量,用于同步访问共享内存
QSystemSemaphore semaphore(appKey + "_semaphore", 1);
semaphore.acquire(); // 获取信号量
// 创建共享内存对象
QSharedMemory sharedMemory(appKey + "_memory");
bool isRunning = false;
// 尝试附加到现有的共享内存
if (sharedMemory.attach()) {
// 如果能够附加,说明已有实例在运行
isRunning = true;
} else {
// 尝试创建新的共享内存
if (!sharedMemory.create(1)) {
// 创建失败,可能是因为已经存在
qDebug() << "Unable to create shared memory segment:" << sharedMemory.errorString();
isRunning = true;
}
}
semaphore.release(); // 释放信号量
if (isRunning) {
// 已有实例在运行,显示提示信息并退出
QMessageBox::information(nullptr,
QObject::tr("应用程序已运行"),
QObject::tr("编织袋拆垛应用程序已经在运行中,请勿重复启动!"),
QMessageBox::Ok);
return 0;
}
// 没有其他实例运行,正常启动应用程序
MainWindow w; MainWindow w;
w.show(); w.show();
return a.exec();
int result = a.exec();
// 应用程序退出时,清理共享内存
if (sharedMemory.isAttached()) {
sharedMemory.detach();
}
return result;
} }

View File

@ -770,7 +770,7 @@ void MainWindow::setupSingleCameraLayout()
// 日志: 位于右下方 // 日志: 位于右下方
ui->detect_log->setGeometry(1344, 852, 556, 178); ui->detect_log->setGeometry(1344, 850, 556, 176);
updateStatusLog(tr("页面布局已调整为单相机模式")); updateStatusLog(tr("页面布局已调整为单相机模式"));
} }
@ -787,16 +787,11 @@ void MainWindow::setupMultiCameraLayout()
ui->detect_image_2->setGeometry(964, 140, 934, 660); ui->detect_image_2->setGeometry(964, 140, 934, 660);
// 设备状态框架: 移动到下方左侧,调整为更高的尺寸以适应纵向排布 // 设备状态框架: 移动到下方左侧,调整为更高的尺寸以适应纵向排布
ui->frame_dev->setGeometry(20, 806, 180, 198); ui->frame_dev->setGeometry(20, 806, 180, 200);
// 检测结果列表: 移动到下方中间 // 检测结果列表: 移动到下方中间
ui->detect_result_list->setGeometry(206, 806, 1380, 220); ui->detect_result_list->setGeometry(206, 806, 1380, 200);
// 多相机模式下设置detect_result_list为横向滚动
ui->detect_result_list->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->detect_result_list->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
ui->detect_result_list->setFlow(QListView::LeftToRight); // 改为从上到下排列
ui->detect_result_list->setWrapping(false); // 禁用换行,实现横向滚动
// 多相机模式设置gridSizegridHeight = 200 // 多相机模式设置gridSizegridHeight = 200
int gridWidth = 230; int gridWidth = 230;
@ -806,7 +801,7 @@ void MainWindow::setupMultiCameraLayout()
m_deviceStatusWidget->setCameraCount(2); m_deviceStatusWidget->setCameraCount(2);
// 日志: 移动到下方右侧 // 日志: 移动到下方右侧
ui->detect_log->setGeometry(1592, 806, 308, 198); ui->detect_log->setGeometry(1592, 806, 308, 200);
updateStatusLog(tr("页面布局已调整为多相机模式")); updateStatusLog(tr("页面布局已调整为多相机模式"));
} }

View File

@ -0,0 +1,33 @@
# 1.0.0.7 2025-06-29
1. 增加双相机界面: 通过配置文件config.xml 配置双相机参数,如果没有没有配置,搜索相机进行打开
配置示例
```
<Cameras>
<Camera name="摄像头1" ip="192.168.1.100" />
<Camera name="摄像头2" ip="192.168.1.101" />
</Cameras>
```
2. 相机调平功能, config.xml 有修改。主要涉及到双相机的调平
3. 修改log, config的目录。 存储在用户目录下->应用名下
4. 增加应用只能启动一个
5. 手眼标定矩阵
```
[clib]
clib_0=1
clib_1=0
clib_2=0
clib_3=0
clib_4=0
clib_5=1
clib_6=0
clib_7=0
clib_8=0
clib_9=0
clib_10=1
clib_11=0
clib_12=0
clib_13=0
clib_14=0
clib_15=1
```

17
VrConfig/config/clib.ini Normal file
View File

@ -0,0 +1,17 @@
[clib]
clib_0=1
clib_1=0
clib_2=0
clib_3=1
clib_4=0
clib_5=1
clib_6=0
clib_7=1
clib_8=0
clib_9=0
clib_10=1
clib_11=1
clib_12=0
clib_13=0
clib_14=0
clib_15=1

View File

@ -18,10 +18,15 @@ public:
*/ */
virtual int InitDevice() = 0; virtual int InitDevice() = 0;
/**
*
*/
virtual int SetStatusCallback(VzNL_OnNotifyStatusCBEx fNotify, void *param) = 0;
/** /**
* Open设备 * Open设备
*/ */
virtual int OpenDevice(const char* sIP, VzNL_OnNotifyStatusCBEx fNotify, void *param) = 0; virtual int OpenDevice(const char* sIP) = 0;
/** /**
* *

View File

@ -18,7 +18,20 @@ int CVrEyeDevice::InitDevice()
return CVrEyeCommon::GetInstance()->InitDevice(); return CVrEyeCommon::GetInstance()->InitDevice();
} }
int CVrEyeDevice::OpenDevice(const char* sIP, VzNL_OnNotifyStatusCBEx fNotify, void *param) int CVrEyeDevice::SetStatusCallback(VzNL_OnNotifyStatusCBEx fNotify, void *param)
{
// 如果设备已经打开,立即设置回调
if (m_pHandle) {
VzNL_SetDeviceStatusNotifyEx(m_pHandle, fNotify, param);
LOG_DEBUG("Status callback set for opened device\n");
} else {
LOG_DEBUG("Status callback stored, will be set when device opens\n");
}
return SUCCESS;
}
int CVrEyeDevice::OpenDevice(const char* sIP)
{ {
int nErrCode = SUCCESS; int nErrCode = SUCCESS;
// 搜索设备 // 搜索设备
@ -116,8 +129,6 @@ int CVrEyeDevice::OpenDevice(const char* sIP, VzNL_OnNotifyStatusCBEx fNotify, v
} }
LOG_DEBUG("RGBAutoExposeThres : %f [%d]\n", exposeThres, nnnRet); LOG_DEBUG("RGBAutoExposeThres : %f [%d]\n", exposeThres, nnnRet);
#endif #endif
//设置回调
VzNL_SetDeviceStatusNotifyEx(m_pHandle,fNotify, param);
//获取内部接口类 //获取内部接口类
VzNL_QueryDeviceData(m_pHandle, (void **)(&m_pDeviceCore)); VzNL_QueryDeviceData(m_pHandle, (void **)(&m_pDeviceCore));

View File

@ -22,10 +22,15 @@ public:
// 初始化设备 // 初始化设备
int InitDevice() override; int InitDevice() override;
/**
*
*/
int SetStatusCallback(VzNL_OnNotifyStatusCBEx fNotify, void *param) override;
/** /**
* Open设备 * Open设备
*/ */
int OpenDevice(const char* sIP, VzNL_OnNotifyStatusCBEx fNotify, void *param) override; int OpenDevice(const char* sIP) override;
/** /**
* *

View File

@ -100,7 +100,7 @@ static std::string GetLogPath()
#ifdef __ANDROID__ #ifdef __ANDROID__
return "/sdcard/" + appName + "/Log"; return "/sdcard/" + appName + "/Log";
#else #else
return "~/" + appName + "/Log"; return appName + "/Log";
#endif #endif
#endif #endif
} }