From 2e33dcb1d37101363b4238bdc8fea2d9a92ba908 Mon Sep 17 00:00:00 2001 From: zhaohe Date: Sun, 7 Jul 2024 16:31:24 +0800 Subject: [PATCH] update --- .gitmodules | 3 + CMakeLists.txt | 7 ++ README.md | 13 ++- a8k_optalgo | 1 + libzqt/zui/zqui.hpp | 4 +- src/basic/widgetplot2d.cpp | 10 +- src/basic/zcsv.cpp | 16 +++- src/basic/zcsv.hpp | 5 +- src/mainwindow.cpp | 2 +- src/tab/a8k_opt_tab.cpp | 228 ++++++++++++++++++++++++++++++++++++++++----- src/ui/dialog.cpp | 12 +++ src/ui/dialog.h | 24 +++++ src/ui/dialog.ui | 78 ++++++++++++++++ 13 files changed, 366 insertions(+), 37 deletions(-) create mode 160000 a8k_optalgo create mode 100644 src/ui/dialog.cpp create mode 100644 src/ui/dialog.h create mode 100644 src/ui/dialog.ui diff --git a/.gitmodules b/.gitmodules index a95cf63..da97aa9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "a8000_protocol"] path = a8000_protocol url = zwsd@192.168.1.3:project_boditech_vidas_a8000_v3/a8000_protocol.git +[submodule "a8k_optalgo"] + path = a8k_optalgo + url = zwsd@192.168.1.3:project_boditech_vidas_a8000_v3/a8k_optalgo.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 7facabb..629f6f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,8 +75,15 @@ set(PROJECT_SOURCES src/basic/a8k_id_card_writer.cpp src/tab/a8k_opt_tab.cpp + a8k_optalgo/a8k_opt_algo.cpp + app.rc + + + src/ui/dialog.ui + src/ui/dialog.cpp + ) diff --git a/README.md b/README.md index e99ab91..cfd2597 100644 --- a/README.md +++ b/README.md @@ -224,9 +224,6 @@ ID地址: - - - @@ -245,4 +242,14 @@ T光学 lasterGain 100 scanGain 20 +F光学 + lasterGain 0 (数值越大,功率越小) + scanGain 0 + + 第一次扫描,0,0 + + +实验材料: + Fx3-23 -> F光学,位置80,120,160 + ``` \ No newline at end of file diff --git a/a8k_optalgo b/a8k_optalgo new file mode 160000 index 0000000..f1e84f5 --- /dev/null +++ b/a8k_optalgo @@ -0,0 +1 @@ +Subproject commit f1e84f5f99f42f6e810a77611cf197826a430271 diff --git a/libzqt/zui/zqui.hpp b/libzqt/zui/zqui.hpp index 385609f..92e9a6b 100644 --- a/libzqt/zui/zqui.hpp +++ b/libzqt/zui/zqui.hpp @@ -66,4 +66,6 @@ class ZQUI : public QObject { void doinui_signal(QFunction); }; -extern void DoInUi(std::function dowhat); \ No newline at end of file +extern void DoInUi(std::function dowhat); + +#define ISHOW(fmt, ...) ZQUI::ins()->ishow(fmt, ##__VA_ARGS__) \ No newline at end of file diff --git a/src/basic/widgetplot2d.cpp b/src/basic/widgetplot2d.cpp index 9c776ee..f08489c 100644 --- a/src/basic/widgetplot2d.cpp +++ b/src/basic/widgetplot2d.cpp @@ -1,9 +1,9 @@ #include "widgetplot2d.h" -#include -#include #include +#include #include +#include #include #include "ui_widgetplot2d.h" @@ -406,10 +406,10 @@ void WidgetPlot2D::savePlotPng() { ZCSV csv; int datacnt = ui->customPlot->graph(0)->dataCount(); csv.setdata(1, 1, "pointIndex"); - csv.setdata(1, 2, "value"); + csv.setdata(2, 1, "value"); for (size_t i = 0; i < datacnt; i++) { - csv.setdata(i + 1, 1, QString::number(ui->customPlot->graph(0)->data()->at(i)->key).toStdString()); - csv.setdata(i + 1, 2, QString::number(ui->customPlot->graph(0)->data()->at(i)->value).toStdString()); + csv.setdata(1, i + 1, QString::number(ui->customPlot->graph(0)->data()->at(i)->key).toStdString()); + csv.setdata(2, i + 1, QString::number(ui->customPlot->graph(0)->data()->at(i)->value).toStdString()); } csv.dumpCSV(fileName.toStdString()); } diff --git a/src/basic/zcsv.cpp b/src/basic/zcsv.cpp index c5cfd06..d064b34 100644 --- a/src/basic/zcsv.cpp +++ b/src/basic/zcsv.cpp @@ -1,5 +1,8 @@ #include "zcsv.hpp" + +#include + using namespace std; using namespace iflytop; @@ -63,7 +66,7 @@ ZCSVCell* ZCSV::findCell(int rowNum, int colNum) { return NULL; } -void ZCSV::setdata(int rowNum, int colNum, string data) { +void ZCSV::setdata(int colNum, int rowNum, string data) { ZCSVCell* cell = findCell(rowNum, colNum); if (cell != NULL) { cell->data = data; @@ -84,7 +87,16 @@ void ZCSV::setdata(int rowNum, int colNum, string data) { csvData.push_back(newCell); } } -string ZCSV::getdata(int rowNum, int colNum) { +void ZCSV::setdata(int colNum, int rowNum, const char* fmt, ...) { + char buffer[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, 1024, fmt, args); + va_end(args); + setdata(colNum, rowNum, string(buffer)); +} + +string ZCSV::getdata(int colNum, int rowNum) { ZCSVCell* cell = findCell(rowNum, colNum); if (cell != NULL) { return cell->data; diff --git a/src/basic/zcsv.hpp b/src/basic/zcsv.hpp index fe86d66..bf352ee 100644 --- a/src/basic/zcsv.hpp +++ b/src/basic/zcsv.hpp @@ -32,8 +32,9 @@ class ZCSV { bool parseCSV(string filename); - void setdata(int rowNum, int colNum, string data); - string getdata(int rowNum, int colNum); + void setdata(int colNum, int rowNum, string data); + void setdata(int colNum, int rowNum, const char* fmt, ...); + string getdata(int colNum, int rowNum); int maxRowNum() { return m_maxRowNum; } int maxColNum() { return m_maxColNum; } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 268dad0..1bc6930 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -185,7 +185,7 @@ void MainWindow::parse_ptv2_cmd(zcr_cmd_header_t *frame, int32_t packetlen) { } else { // if (cmdId == kpipette_write_cmd_direct || cmdId == ka8000_idcard_write_raw) { - ZQUI::ins()->rawshow("[CMD ] %d mid:%d cmdid:%s(0x%04x) param:%s", frame->packetindex, cmdid2str(cmdId), cmdId, mid, // + ZQUI::ins()->rawshow("[CMD ] %d mid:%d cmdid:%s(0x%04x) param:%s", frame->packetindex, mid, cmdid2str(cmdId), cmdId, // zhex2str(frame->data, packetlen - sizeof(zcr_cmd_header_t)).c_str()); } else { int32_t paramNum = (packetlen - sizeof(zcr_cmd_header_t)) / 4; diff --git a/src/tab/a8k_opt_tab.cpp b/src/tab/a8k_opt_tab.cpp index 888f6c2..b572639 100644 --- a/src/tab/a8k_opt_tab.cpp +++ b/src/tab/a8k_opt_tab.cpp @@ -12,12 +12,16 @@ #include "../basic/format_memory.hpp" #include "../basic/stm32_pin.hpp" +#include "../ui/dialog.h" #include "./mainwindow.h" +#include "a8k_optalgo\a8k_opt_algo.hpp" #include "basic\widgetplot2d.h" +#include "zcsv.hpp" #include "zui\zqui.hpp" // using namespace iflytop; using namespace std; +using namespace a8k_opt_algo; extern Ui::MainWindow *main_ui; @@ -31,6 +35,63 @@ typedef struct { int dataNum; } opt_result_t; +typedef enum { + kfopt = 1, + ktopt = 2, +} opt_type_t; + +static const char *optType2Str(opt_type_t type) { + switch (type) { + case kfopt: + return "F光学"; + case ktopt: + return "T光学"; + default: + return "未知"; + } +} + +static vector array2vector(opt_result_t result) { + vector ret; + ret.reserve(result.dataNum); + for (int i = 0; i < result.dataNum; i++) { + ret.push_back(result.data[i]); + } + return ret; +} + +opt_result_t m_optData; +opt_type_t m_optType; +int32_t m_scanGain; +int32_t m_laserGain; + +void dumpRawData() { + ZQUI::ins()->ishow("---------------------opt result(%d)---------------------", m_optData.dataNum); + ISHOW("laster gain:%d", m_laserGain); + ISHOW("scan gain:%d", m_scanGain); + ISHOW("opt Type:%s", optType2Str(m_optType)); + + for (size_t i = 0; i < m_optData.dataNum; i++) { + ZQUI::ins()->ishow("%5d,%d", i, m_optData.data[i]); + } + DoInUi([]() { + WidgetPlot2D *plot2d = new WidgetPlot2D(); + QStringList lines; + lines.push_back("line1"); + plot2d->initGraphName(lines); + + for (int i = 0; i < m_optData.dataNum; i++) { + plot2d->addData("line1", m_optData.data[i]); + } + // 250 个点的情况下,峰的标准位置在 40 80 120 160 200 + // 1200个点的情况下,峰的标准位置在 40*4.8 80*4.8 120*4.8 160*4.8 200*4.8 + for (int i = 1; i < 6; i++) { + plot2d->addRefLine(4.8 * 40 * i); + } + plot2d->show(); + }); +} + A8kOptTab *A8kOptTab::inst() { static A8kOptTab *ins = new A8kOptTab(); return ins; @@ -41,6 +102,29 @@ void A8kOptTab::construct(QTabWidget *fathertab) { * 模块操作 * ***********************************************************************************************************************/ ZQVTabPage *tab = new ZQVTabPage(fathertab, "光学模组"); + { + ZQFunctionListBox *box = new ZQFunctionListBox(tab, "说明文档", 4); + + box->newSubButton("说明", [this](int argn, const char **args) { // + DoInUi([this]() { + Dialog *dialog = new Dialog(); + dialog->show(); + dialog->setHelpInfo( + "" // + "扫描位置:\n" + "推杆电机: 52\n" + " F光学扫描位置:kreg_a8k_opt_f_pos_offset\n" + " kreg_a8k_opt_f_reverse_scan_pos_offset\n" + " T光学扫描位置:kreg_a8k_opt_t_pos_offset\n" + " kreg_a8k_opt_t_reverse_scan_pos_offset\n" + "详细说明参考:\n" + " https://iflytop1.feishu.cn/wiki/LbfHwPFmki3G1uk9p0KcA9lvnSd?fromScene=spaceOverview \n" + ""); + }); + }); + + // ModuleNameText->setObjectName(QString::fromUtf8("ModuleNameText")); + } { ZQFunctionListBox *box = new ZQFunctionListBox(tab, "光学测试", 4); @@ -63,7 +147,7 @@ void A8kOptTab::construct(QTabWidget *fathertab) { ICM->callcmd1(PUSH_AND_PULL_MOTOR, kstep_motor_easy_move_to, 1100); }); box->newSubButtonEnd(); - box->newSubButton("丢板", [this](int argn, const char **args) { ICM->callcmd1(CAMERA_MOTOR, kstep_motor_easy_move_to, 0); }); + box->newSubButton("丢板", [this](int argn, const char **args) { ICM->callcmd1(CAMERA_MOTOR, kstep_motor_easy_move_to, -350); }); box->newSubButtonEnd(); box->newFunc("T光学-开始扫描", {"scanDirection", "lasterGain", "scanGain"}, [this](int argn, const char **args) { @@ -71,6 +155,9 @@ void A8kOptTab::construct(QTabWidget *fathertab) { int32_t lasterGain = atoi(args[1]); int32_t scanGain = atoi(args[2]); ICM->callcmd3(getDeviceId(), ka8k_opt_v2_t_start_scan, scanDirection, lasterGain, scanGain); + m_optType = ktopt; + m_scanGain = scanGain; + m_laserGain = lasterGain; }); box->newFunc("F光学-开始扫描", {"scanDirection", "lasterGain", "scanGain"}, [this](int argn, const char **args) { @@ -78,11 +165,13 @@ void A8kOptTab::construct(QTabWidget *fathertab) { int32_t lasterGain = atoi(args[1]); int32_t scanGain = atoi(args[2]); ICM->callcmd3(getDeviceId(), ka8k_opt_v2_f_start_scan, scanDirection, lasterGain, scanGain); + m_optType = kfopt; + m_scanGain = scanGain; + m_laserGain = lasterGain; }); box->newSubButton("读取扫描结果", [this](int argn, const char **args) { // ka8000_optical_read_raw - uint8_t rdbuf[5000]; int32_t readsize = 0; int i = 0; @@ -95,39 +184,132 @@ void A8kOptTab::construct(QTabWidget *fathertab) { readsize += ICM->getAckBufLen(); i++; } - int16_t *data = (int16_t *)rdbuf; - ZQUI::ins()->ishow("---------------------opt result(%d)---------------------", readsize / 2); + memcpy(m_optData.data, data, readsize); + m_optData.dataNum = readsize / 2; - for (size_t i = 0; i < readsize / 2; i++) { - ZQUI::ins()->ishow("%5d,%d", i, data[i]); - } + dumpRawData(); + }); - opt_result_t optdata; - memcpy(optdata.data, data, readsize); - optdata.dataNum = readsize / 2; + box->newSubButton("保存数据", [this](int argn, const char **args) { + DoInUi([this]() { + QString savePath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); + QString fileName = QFileDialog::getSaveFileName(nullptr, + "保存波形数据", // 对话框的标题 + savePath, // 保存的默认路径为程序运行路径 + "Save Picture (*.csv)"); // 打开文件的类型,;隔开 + if (fileName.isNull()) return; + + ZCSV csv; + int datacnt = m_optData.dataNum; + csv.setdata(1, 1, "Index"); + csv.setdata(2, 1, "Data"); + csv.setdata(3, 1, "OptType(1:f,2:t)"); + csv.setdata(4, 1, "ScanGain(0...255)"); + csv.setdata(5, 1, "LasterGain(0...255)"); + + for (int i = 0; i < datacnt; i++) { + csv.setdata(1, i + 2, QString::number(i + 1).toStdString()); // 第一列数据 + csv.setdata(2, i + 2, QString::number(m_optData.data[i]).toStdString()); // 第二列数据 + } - DoInUi([this, optdata]() { - WidgetPlot2D *plot2d = new WidgetPlot2D(); - QStringList lines; - lines.push_back("line1"); - plot2d->initGraphName(lines); + csv.setdata(3, 2, "%d", m_optType); + csv.setdata(4, 2, "%d", m_scanGain); + csv.setdata(5, 2, "%d", m_laserGain); - for (int i = 0; i < optdata.dataNum; i++) { - plot2d->addData("line1", optdata.data[i]); + csv.dumpCSV(fileName.toStdString()); + ISHOW("保存成功"); + }); + }); + box->newSubButton("载入数据", [this](int argn, const char **args) { + DoInUi([]() { + QString filePath = QFileDialog::getOpenFileName(nullptr, "Select a file"); + if (!filePath.isEmpty()) { + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + ZQUI::ins()->ishow("open file fail"); + return; + } } - // 250 个点的情况下,峰的标准位置在 40 80 120 160 200 - // 1200个点的情况下,峰的标准位置在 40*4.8 80*4.8 120*4.8 160*4.8 200*4.8 - for (int i = 1; i < 6; i++) { - plot2d->addRefLine(4.8 * 40 * i); + ZCSV csv; + csv.parseCSV(filePath.toStdString()); + + int datacnt = csv.maxRowNum() - 1; + m_optData.dataNum = datacnt; + for (int i = 0; i < datacnt; i++) { + m_optData.data[i] = atoi(csv.getdata(2, i + 2).c_str()); } - plot2d->show(); + m_optType = (opt_type_t)atoi(csv.getdata(3, 2).c_str()); + m_scanGain = atoi(csv.getdata(4, 2).c_str()); + m_laserGain = atoi(csv.getdata(5, 2).c_str()); + dumpRawData(); }); + }); + } + { + // + ZQFunctionListBox *box = new ZQFunctionListBox(tab, "结果处理", 4); + // 预分析结果 + + box->newSubButton("光学结果预分析", [this](int argn, const char **args) { + int32_t lasterGain = atoi(args[0]); + int32_t scanGain = atoi(args[1]); + ICM->callcmd2(getDeviceId(), ka8k_opt_v2_t_open_laster, lasterGain, scanGain); + + if (m_optData.dataNum == 0) { + ZQUI::ins()->ishow("请先进行光学分析,并读取扫描结果"); + return; + } + + ISHOW("------ OptRawResultInfo ------"); + ISHOW("laster gain:%d", lasterGain); + ISHOW("scan gain:%d", scanGain); + ISHOW("opt Type:%s", optType2Str(m_optType)); + + // 1. 预分析 + OptAlgoPreProcessResult result; + if (m_optType == kfopt) { + F_A8kOptAlgoPreProcess(array2vector(m_optData), scanGain, 2600, 2800, result); + } else if (m_optType == ktopt) { + T_A8kOptAlgoPreProcess(array2vector(m_optData), scanGain, 2600, 2800, result); + } + ISHOW("------ OptPreParseResult ------"); + ISHOW("scanAgain :%s", result.scanAgain ? "true" : "false"); + ISHOW("suggestScanGain:%d", result.suggestScanGain); + }); + box->newSubButtonEnd(); + // 分析结果 - // 打印读取到的结果 + box->newSubButton("光学结果分析", [this](int argn, const char **args) { + int32_t lasterGain = atoi(args[0]); + int32_t scanGain = atoi(args[1]); + ICM->callcmd2(getDeviceId(), ka8k_opt_v2_t_open_laster, lasterGain, scanGain); + + if (m_optData.dataNum == 0) { + ZQUI::ins()->ishow("请先进行光学分析,并读取扫描结果"); + return; + } + + ISHOW("------ OptRawResultInfo ------"); + ISHOW("laster gain:%d", lasterGain); + ISHOW("scan gain:%d", scanGain); + ISHOW("opt Type:%s", optType2Str(m_optType)); + + // 1. 预分析 + OptAlgoPreProcessResult result; + if (m_optType == kfopt) { + F_A8kOptAlgoPreProcess(array2vector(m_optData), scanGain, 2600, 2800, result); + } else if (m_optType == ktopt) { + T_A8kOptAlgoPreProcess(array2vector(m_optData), scanGain, 2600, 2800, result); + } + ISHOW("------ OptPreParseResult ------"); + ISHOW("scanAgain :%s", result.scanAgain ? "true" : "false"); + ISHOW("suggestScanGain:%d", result.suggestScanGain); }); + box->newSubButtonEnd(); + // 打印分析报告 } { diff --git a/src/ui/dialog.cpp b/src/ui/dialog.cpp new file mode 100644 index 0000000..271ffce --- /dev/null +++ b/src/ui/dialog.cpp @@ -0,0 +1,12 @@ +#include "dialog.h" + +#include "ui_dialog.h" + +Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) { ui->setupUi(this); } + +Dialog::~Dialog() { delete ui; } + +void Dialog::setHelpInfo(QString info) { + + ui->helpInfo->setText(info); +} diff --git a/src/ui/dialog.h b/src/ui/dialog.h new file mode 100644 index 0000000..6ad614c --- /dev/null +++ b/src/ui/dialog.h @@ -0,0 +1,24 @@ +#ifndef DIALOG_H +#define DIALOG_H + +#include + +namespace Ui { +class Dialog; +} + +class Dialog : public QDialog +{ + Q_OBJECT + +public: + explicit Dialog(QWidget *parent = nullptr); + ~Dialog(); + + void setHelpInfo(QString info); + +private: + Ui::Dialog *ui; +}; + +#endif // DIALOG_H diff --git a/src/ui/dialog.ui b/src/ui/dialog.ui new file mode 100644 index 0000000..a0cfd98 --- /dev/null +++ b/src/ui/dialog.ui @@ -0,0 +1,78 @@ + + + Dialog + + + + 0 + 0 + 640 + 480 + + + + Dialog + + + + + 10 + 440 + 621 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 30 + 40 + 571 + 371 + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +