From 1e46a7b36bbd531a0793e10e07741c70fa832560 Mon Sep 17 00:00:00 2001 From: zhaohe Date: Wed, 23 Oct 2024 19:30:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=85=89=E5=AD=A6=E6=A0=A1?= =?UTF-8?q?=E5=87=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.db | Bin 225280 -> 225280 bytes .../java/a8k/AppControlerExceptionProcesser.java | 2 +- src/main/java/a8k/constant/OptConstant.java | 6 + .../java/a8k/extapi_controler/ExtApiControler.java | 22 +- .../pagecontrol/ExtApiTabConfig.java | 2 + src/main/java/a8k/hardware/A8kCanBusService.java | 30 --- src/main/java/a8k/optalgo/A8kOptAlgo.java | 238 +++++++++++++++++++++ src/main/java/a8k/optalgo/A8kOptAlgoUtils.java | 36 ++++ src/main/java/a8k/optalgo/OptAlgo.java | 238 --------------------- src/main/java/a8k/optalgo/OptAlgoUtils.java | 106 --------- .../mainflowctrl/action/PLATE_OPT_SCAN.java | 8 + .../ctrlservice/OptScanModuleCtrlService.java | 32 +++ .../app/devicectrl/driver/OptModuleDriver.java | 59 +++++ .../devicectrl/driver/type/OptModuleRegIndex.java | 18 ++ .../devicectrl/exdriver/TubeTransportExDriver.java | 4 - .../calibration/OptModuleParamCalibration.java | 165 ++++++++++++++ .../param/param_mgr/OptModuleParamsMgr.java | 49 +++-- .../db/type/a8kidcard/zenum/A8kOptType.java | 4 +- .../a8k/service/test/fakeproj/FakeProjInfo.java | 2 +- src/main/java/a8k/type/A8kScanCurve.java | 11 +- src/main/java/a8k/type/OptScanDirection.java | 5 +- src/main/java/a8k/type/appret/AppRet.java | 21 +- 22 files changed, 630 insertions(+), 428 deletions(-) create mode 100644 src/main/java/a8k/constant/OptConstant.java create mode 100644 src/main/java/a8k/optalgo/A8kOptAlgo.java create mode 100644 src/main/java/a8k/optalgo/A8kOptAlgoUtils.java delete mode 100644 src/main/java/a8k/optalgo/OptAlgo.java delete mode 100644 src/main/java/a8k/optalgo/OptAlgoUtils.java create mode 100644 src/main/java/a8k/service/app/devicectrl/driver/OptModuleDriver.java create mode 100644 src/main/java/a8k/service/app/devicectrl/driver/type/OptModuleRegIndex.java create mode 100644 src/main/java/a8k/service/app/devicectrl/param/calibration/OptModuleParamCalibration.java diff --git a/app.db b/app.db index 28b8d329e78c8f275da9bcc7a564557f0d3c401e..d3971fa9efaf296300505bc75b053e4b6f95f71d 100644 GIT binary patch delta 102 zcmZp8z}xVEcY>5q*iQxq26G@b17c|g2EP3hb&Qz8er`-yUC*ennWy0`KO_I5q@L2{126G@b17c|g2EL6Gb&QyT&u&auUC*eznWy0`Kcm9tU;SJG z+gUy^{*hlS@WEl510&0Z%`6Z8$hQeFZ4+STc3|Y6&J)0#&dConL>Y+rx7P$Px5xtk DQBfW9 diff --git a/src/main/java/a8k/AppControlerExceptionProcesser.java b/src/main/java/a8k/AppControlerExceptionProcesser.java index be723db..ed9d4a1 100644 --- a/src/main/java/a8k/AppControlerExceptionProcesser.java +++ b/src/main/java/a8k/AppControlerExceptionProcesser.java @@ -14,7 +14,7 @@ public class AppControlerExceptionProcesser { @ResponseBody @ExceptionHandler(value = Exception.class) - public AppRet controllerExceptionHandler(Exception e) { + public AppRet controllerExceptionHandler(Exception e) { logger.info("捕获到异常 : ", e); return AppRet.fail(e); } diff --git a/src/main/java/a8k/constant/OptConstant.java b/src/main/java/a8k/constant/OptConstant.java new file mode 100644 index 0000000..b66e283 --- /dev/null +++ b/src/main/java/a8k/constant/OptConstant.java @@ -0,0 +1,6 @@ +package a8k.constant; + +public class OptConstant { + static public final Integer FOPT_LASTER_GAIN = 100; + static public final Integer TOPT_LASTER_GAIN = 100; +} diff --git a/src/main/java/a8k/extapi_controler/ExtApiControler.java b/src/main/java/a8k/extapi_controler/ExtApiControler.java index 6c86bad..117ffd2 100644 --- a/src/main/java/a8k/extapi_controler/ExtApiControler.java +++ b/src/main/java/a8k/extapi_controler/ExtApiControler.java @@ -23,7 +23,7 @@ import java.util.Map; public class ExtApiControler { @PostMapping("/api/service-config/service-list") @ResponseBody - public AppRet services() { + public AppRet services() { List> services = new ArrayList<>(); var classes = SpringBootBeanUtil.getBeans(); for (var clazz : classes) { @@ -43,7 +43,7 @@ public class ExtApiControler { @PostMapping("/api/service-config/service-params-list") @ResponseBody - public AppRet serviceParams(@RequestBody Map params) + public AppRet serviceParams(@RequestBody Map params) throws InvocationTargetException, IllegalAccessException { String serviceKey = (String) params.get("serviceKey"); var paramService = this.getServiceParamHandlerByServiceKey(serviceKey); @@ -77,7 +77,7 @@ public class ExtApiControler { @PostMapping("/api/service-config/service-params-update") @ResponseBody - public AppRet serviceParamsUpdate(@RequestBody Map params) throws Exception { + public AppRet serviceParamsUpdate(@RequestBody Map params) throws Exception { String serviceKey = (String) params.get("serviceKey"); Map newParams = (Map) params.get("params"); @@ -119,7 +119,7 @@ public class ExtApiControler { @PostMapping("/api/service-config/service-params-reset") @ResponseBody - public AppRet serviceParamsReset(@RequestBody Map params) throws Exception { + public AppRet serviceParamsReset(@RequestBody Map params) throws Exception { // String serviceKey = (String) params.get("serviceKey"); // HardwareServiceSetting.deleteAllByServiceName(serviceKey); return AppRet.success(); @@ -127,7 +127,7 @@ public class ExtApiControler { @PostMapping("/api/service-config/service-status-list") @ResponseBody - public AppRet serviceStatus(@RequestBody Map params) throws InvocationTargetException, IllegalAccessException { + public AppRet serviceStatus(@RequestBody Map params) throws InvocationTargetException, IllegalAccessException { String serviceKey = (String) params.get("serviceKey"); Class serviceClass = null; var classes = SpringBootBeanUtil.getBeans(); @@ -166,7 +166,7 @@ public class ExtApiControler { @PostMapping("/api/service-config/service-action-list") @ResponseBody - public AppRet serviceActionList(@RequestBody Map params) throws Exception { + public AppRet serviceActionList(@RequestBody Map params) throws Exception { String serviceKey = (String) params.get("serviceKey"); Class serviceClass = null; var classes = SpringBootBeanUtil.getBeans(); @@ -244,7 +244,7 @@ public class ExtApiControler { @PostMapping("/api/service-config/service-action-exec") @ResponseBody - public AppRet serviceActionExecute(@RequestBody Map params) throws Throwable { + public AppRet serviceActionExecute(@RequestBody Map params) throws Throwable { String serviceKey = (String) params.get("serviceKey"); var service = this.getServiceInstanceByServiceKey(serviceKey); Assert.isTrue(service != null, "service not found"); @@ -277,7 +277,7 @@ public class ExtApiControler { @PostMapping("/api/service-config/service-action-exec-by-map") @ResponseBody - public AppRet serviceActionExecuteByMap(@RequestBody Map params) throws Throwable { + public AppRet serviceActionExecuteByMap(@RequestBody Map params) throws Throwable { String serviceKey = (String) params.get("serviceKey"); var service = this.getServiceInstanceByServiceKey(serviceKey); Assert.isTrue(service != null, "service not found"); @@ -322,7 +322,7 @@ public class ExtApiControler { @PostMapping("/api/service-config/class-struct-info-get") @ResponseBody - public AppRet classStructInfoGet(@RequestBody Map params) throws Exception { + public AppRet classStructInfoGet(@RequestBody Map params) throws Exception { String className = (String) params.get("class"); Class clazz = Class.forName(className); List> struct = new ArrayList<>(); @@ -331,7 +331,7 @@ public class ExtApiControler { } // execute service action and get response - private AppRet executeServiceActionAndGetResponse(Object service, Method method, List actionParams) throws Throwable { + private AppRet executeServiceActionAndGetResponse(Object service, Method method, List actionParams) throws Throwable { Object actionResult = null; try { var actionParamList = actionParams.toArray(); @@ -353,7 +353,7 @@ public class ExtApiControler { } if (actionResult instanceof AppRet) { - return (AppRet) actionResult; + return (AppRet) actionResult; } return AppRet.success(actionResult); } diff --git a/src/main/java/a8k/extapi_controler/pagecontrol/ExtApiTabConfig.java b/src/main/java/a8k/extapi_controler/pagecontrol/ExtApiTabConfig.java index 878ea3f..04bea71 100644 --- a/src/main/java/a8k/extapi_controler/pagecontrol/ExtApiTabConfig.java +++ b/src/main/java/a8k/extapi_controler/pagecontrol/ExtApiTabConfig.java @@ -27,6 +27,7 @@ public enum ExtApiTabConfig { HbotProbeSubstancePosCalibration("校准.探测物质位置校准", true), PipetteGunLLDParamCalibration("校准.移液枪LLD参数校准", true), PipetteGunLLFParamCalibration("校准.移液枪LLF参数校准", true), + OptModuleParamCalibration("校准.光学模块参数校准", true), VirtualDeviceSimulationTest("测试.虚拟设备测试", true), @@ -35,6 +36,7 @@ public enum ExtApiTabConfig { A8kPipetteCtrlModule("硬件驱动测试.移液枪测试", true), + ActionReactorService("底层调试.单步调试", false),//OK ReactionPlatesTransmitCtrl("ReactionPlatesTransmitCtrl", false), HbotControlService("HbotControlService", false), diff --git a/src/main/java/a8k/hardware/A8kCanBusService.java b/src/main/java/a8k/hardware/A8kCanBusService.java index ab1baa1..706a4f9 100644 --- a/src/main/java/a8k/hardware/A8kCanBusService.java +++ b/src/main/java/a8k/hardware/A8kCanBusService.java @@ -168,37 +168,7 @@ public class A8kCanBusService { } - public void optTStartScan(MId id, OptScanDirection scanDirection, Integer lasterGain, Integer scanGain) throws AppException { - callcmd(id.toInt(), CmdId.a8k_opt_v2_t_start_scan.toInt(), scanDirection.getInteger(), lasterGain, scanGain); - } - - public void optTStartScanBlock(MId id, OptScanDirection scanDirection, Integer lasterGain, Integer scanGain, Integer actionOvertime) throws AppException { - optTStartScan(id, scanDirection, lasterGain, scanGain); - waitForMod(id, actionOvertime); - } - - public void optFStartScan(MId id, OptScanDirection scanDirection, Integer lasterGain, Integer scanGain) throws AppException { - callcmd(id.toInt(), CmdId.a8k_opt_v2_f_start_scan.toInt(), scanDirection.getInteger(), lasterGain, scanGain); - } - public void optFStartScanBlock(MId id, OptScanDirection scanDirection, Integer lasterGain, Integer scanGain, Integer actionOvertime) throws AppException { - optFStartScan(id, scanDirection, lasterGain, scanGain); - waitForMod(id, actionOvertime); - } - - public List optReadRaw(MId id) throws AppException { - int i = 0; - List result = new ArrayList<>(); - while (true) { - var rxPacket = callcmd(id.toInt(), CmdId.a8k_opt_v2_read_raw.toInt(), i++); - if (rxPacket.getCmdContent().length == 0) { - break; - } - var rawdata = ByteArray.readU16bitArray(rxPacket.getCmdContent()); - result.addAll(Arrays.asList(rawdata)); - } - return result; - } public void plateCodeScanerPushCardAndScan(MId id, Integer finalStopPos) throws AppException { diff --git a/src/main/java/a8k/optalgo/A8kOptAlgo.java b/src/main/java/a8k/optalgo/A8kOptAlgo.java new file mode 100644 index 0000000..f736d5b --- /dev/null +++ b/src/main/java/a8k/optalgo/A8kOptAlgo.java @@ -0,0 +1,238 @@ +package a8k.optalgo; + +import a8k.optalgo.type.LineProcessContext; +import a8k.optalgo.type.OptAlgoResult; +import a8k.optalgo.type.Peak; +import a8k.optalgo.type.PeakFindState; +import a8k.optalgo.utils.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.Assert; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +public class A8kOptAlgo { + public static OptAlgoResult processOptData(Integer expectPeakNum, Integer searchStart, double[] data) { + + LineProcessContext cxt = new LineProcessContext(); + + //过采样 + cxt.afSupperVal = SupperSampling.process(data, 5); + //中值滤波 + cxt.afSupperMedianVal = Filter.medianFiltering(cxt.afSupperVal, 25); + + //下采样到1000个点 + cxt.raw1000 = SubSampling.process(cxt.afSupperMedianVal, 6); + //生成1000个的平滑曲线 + cxt.avg1000 = Filter.smooth(cxt.raw1000, 13); + //生成1000个的斜率曲线 + cxt.diff1000 = LeastSquare.calculatedSlopeCurve(cxt.avg1000, 13); + //求数据的均值(巴迪泰A5000算法) + cxt.avgLine = findAvgLine(cxt.raw1000); + + //在曲线开始的位置第10个到15点的斜率 + cxt.baselineSlope = LeastSquare.linearLeastSquares(cxt.avg1000, 10 * 4, 5 * 4).slope; + + + List peaks = new ArrayList<>(); + Peak peak = null; + Peak lastPeak = null; + for (int i = 0; i < expectPeakNum; i++) { + if (i == 0) { + peak = findPeak(cxt, searchStart * 4, 80 * 4); + } else { + peak = findPeak(cxt, lastPeak.peakEndPos, 80 * 4); + } + peak.off = i; + peaks.add(peak); + if (!peak.state.equals(PeakFindState.FIND_PEAK)) { + break; + } + lastPeak = peak; + } + + OptAlgoResult result = new OptAlgoResult(); + result.resultData = SubSampling.process(cxt.avg1000, 4); + result.ogiginData = data; + result.peaks = peaks; + return result; + } + + /** + * 求数据的均值(巴迪泰A5000算法) + * @param inputRaw 输入数据 + * @return 均值线 + */ + static double findAvgLine(double[] inputRaw) { + double base_min = 500; + double fsum = 0; + int cnt = 0; + + int range = inputRaw.length; + + do { + fsum = cnt = 0; + for (int i = 1; i < range; i++) { + if (inputRaw[i] < base_min) { + fsum += inputRaw[i]; + cnt++; + } + } + + base_min = base_min + 50; + } while (cnt < range - 15 * inputRaw.length / 250); + + return fsum / cnt; + } + + static Peak findPeak(LineProcessContext cxt, int searchStart, int peakWidth) { + Peak peak = new Peak(); + /* + * @brief 查找峰的位置 + * + * 思路: + * 搜索所有大于均值的点,当点满足,其数值大于附近一定数量的点时,认为是峰的位置 + */ + + log.info("findpeak start:{} windth:{}", searchStart, peakWidth); + + // judge_win_size + int judge_win_size = 2 * (cxt.avg1000.length / 250) + 1; + + int peakoff = findPeakOff(cxt, searchStart, peakWidth, judge_win_size); + if (peakoff < 0) { + peak.state = PeakFindState.NOT_FIND_PEAK; + return peak; + } + peak.peakPos = peakoff; + + /* + * @brief 查找峰的起始位置 + * + * 思路: + * 从峰的位置开始,向前搜索,找到一个点,其值小于平均值。 + * 然后继续向前搜索,找到一个点,斜率接近基线斜率。 + * + */ + + int peak_start_pos = findPeakKneePoint(cxt, peak.peakPos, -1, peakWidth / 2); + int peak_end_pos = findPeakKneePoint(cxt, peak.peakPos, 1, peakWidth / 2); + + if (peak_start_pos < 0) { + peak.state = PeakFindState.NOT_FIND_PEAK_START; + return peak; + } + if (peak_end_pos < 0) { + peak.state = PeakFindState.NOT_FIND_PEAK_END; + return peak; + } + + peak.peakStartPos = peak_start_pos; + peak.peakEndPos = peak_end_pos; + + /* + * @brief + * 计算峰的面积 + */ + + double peak_full_area = 0; + for (int i = peak_start_pos; i <= peak_end_pos; i++) { + peak_full_area += cxt.raw1000[i]; + } + + double peak_base_line_area; + peak_base_line_area = + (cxt.raw1000[peak_start_pos] + cxt.raw1000[peak_end_pos]) * 0.5 * (peak_end_pos - peak_start_pos + 1); + + peak.peakFullArea = peak_full_area; + peak.peakBaseLineArea = peak_base_line_area; + peak.area = peak_full_area - peak_base_line_area; + if (peak.area <= 0) + peak.area = 0.0; + peak.state = PeakFindState.FIND_PEAK; + + return peak; + } + + static public int findPeakOff(LineProcessContext cxt, int start_off, int windos_size, int judge_win_size) { + double maxv = 0; + int peakoff = -1; + boolean findmax = false; + + for (int index = 0; index < windos_size; index++) { + int off = index + start_off; + // 从窗口的一半大小开始判断 + if (findmax && cxt.avg1000[off] <= cxt.avgLine) + break; + if (off < judge_win_size / 2) + continue; + // 查找的点要大于基线 + if (cxt.avg1000[off] <= cxt.avgLine) + continue; + // 判断的 + if ((off + judge_win_size / 2) > (cxt.avg1000.length - 1)) + break; + // 找到最大的峰值,这里判断用于去除一个波峰中的某个临时的小波峰 + if (maxv > cxt.avg1000[off]) + continue; + + /* + * @brief 检查当前位置的点,是否是附近最大的点 + */ + if (BasicAlgo.isMaxvalInWindows(cxt.avg1000, off, judge_win_size)) { + findmax = true; + maxv = cxt.avg1000[off]; + peakoff = off; + } + } + return peakoff; + } + + static int findPeakKneePoint(LineProcessContext cxt, + int search_start, // + int search_direction, // + int search_windows) { + /* + * @brief + * 通过波峰的位置查找波峰的起始位置 + * + * 逻辑: + * 1. 从波峰的位置开始,向前搜索,找到一个点,其值小于平均值。 + * 2. 然后继续向前搜索,找到一个点,斜率接近基线斜率。 + * + */ + + int off = -1; + log.info("find peakend top_pos:{} direction:{} windows:{}", search_start, search_direction, search_windows); + + // + Assert.isTrue(search_windows > 0, "search_windows <= 0"); + Assert.isTrue(search_direction == 1 || search_direction == -1, "search_direction != 1 && search_direction != -1"); + // + int index_dval = search_direction >= 0 ? 1 : -1; + int search_end = search_start + search_direction * search_windows; + + Assert.isTrue(search_end >= 0, "search_end < 0"); + Assert.isTrue(cxt.avg1000.length > search_end, "cxt.avg1000.size() <= search_start"); + + for (int i = search_start; i != search_end; i += index_dval) { + double now = cxt.avg1000[i]; + if (now >= cxt.avgLine) + continue; + + if (search_direction == 1) { + if (BasicAlgo.feq(cxt.diff1000[i], cxt.baselineSlope, 0.3) || cxt.diff1000[i] >= cxt.baselineSlope) { + off = i; + break; + } + } else { + if (BasicAlgo.feq(cxt.diff1000[i], cxt.baselineSlope, 0.3) || cxt.diff1000[i] <= cxt.baselineSlope) { + off = i; + break; + } + } + } + return off; + } +} diff --git a/src/main/java/a8k/optalgo/A8kOptAlgoUtils.java b/src/main/java/a8k/optalgo/A8kOptAlgoUtils.java new file mode 100644 index 0000000..c3bfd41 --- /dev/null +++ b/src/main/java/a8k/optalgo/A8kOptAlgoUtils.java @@ -0,0 +1,36 @@ +package a8k.optalgo; + +import a8k.optalgo.utils.Filter; +import a8k.optalgo.utils.SubSampling; +import a8k.optalgo.utils.SupperSampling; + +public class A8kOptAlgoUtils { + + static public Integer[] supperSamplingAndSubSampling(Integer[] data) { + double[] indata = new double[data.length]; + for (int i = 0; i < data.length; i++) { + indata[i] = data[i]; + } + + var result = supperSamplingAndSubSampling(indata); + Integer[] outdata = new Integer[result.length]; + for (int i = 0; i < result.length; i++) { + outdata[i] = (int) result[i]; + } + return outdata; + } + + static public double[] supperSamplingAndSubSampling(double[] data) { + //过采样 + var afSupperVal = SupperSampling.process(data, 5); + //中值滤波 + var afSupperMedianVal = Filter.medianFiltering(afSupperVal, 25); + + //下采样到1000个点 + var raw1000 = SubSampling.process(afSupperMedianVal, 6); + //生成1000个的平滑曲线 + var avg1000 = Filter.smooth(raw1000, 13); + + return SubSampling.process(avg1000, 4); + } +} diff --git a/src/main/java/a8k/optalgo/OptAlgo.java b/src/main/java/a8k/optalgo/OptAlgo.java deleted file mode 100644 index 0bcc5f8..0000000 --- a/src/main/java/a8k/optalgo/OptAlgo.java +++ /dev/null @@ -1,238 +0,0 @@ -package a8k.optalgo; - -import a8k.optalgo.type.LineProcessContext; -import a8k.optalgo.type.OptAlgoResult; -import a8k.optalgo.type.Peak; -import a8k.optalgo.type.PeakFindState; -import a8k.optalgo.utils.*; -import lombok.extern.slf4j.Slf4j; -import org.springframework.util.Assert; - -import java.util.ArrayList; -import java.util.List; - -@Slf4j -public class OptAlgo { - public static OptAlgoResult processOptData(Integer expectPeakNum, Integer searchStart, double[] data) { - - LineProcessContext cxt = new LineProcessContext(); - - //过采样 - cxt.afSupperVal = SupperSampling.process(data, 5); - //中值滤波 - cxt.afSupperMedianVal = Filter.medianFiltering(cxt.afSupperVal, 25); - - //下采样到1000个点 - cxt.raw1000 = SubSampling.process(cxt.afSupperMedianVal, 6); - //生成1000个的平滑曲线 - cxt.avg1000 = Filter.smooth(cxt.raw1000, 13); - //生成1000个的斜率曲线 - cxt.diff1000 = LeastSquare.calculatedSlopeCurve(cxt.avg1000, 13); - //求数据的均值(巴迪泰A5000算法) - cxt.avgLine = findAvgLine(cxt.raw1000); - - //在曲线开始的位置第10个到15点的斜率 - cxt.baselineSlope = LeastSquare.linearLeastSquares(cxt.avg1000, 10 * 4, 5 * 4).slope; - - - List peaks = new ArrayList<>(); - Peak peak = null; - Peak lastPeak = null; - for (int i = 0; i < expectPeakNum; i++) { - if (i == 0) { - peak = findPeak(cxt, searchStart * 4, 80 * 4); - } else { - peak = findPeak(cxt, lastPeak.peakEndPos, 80 * 4); - } - peak.off = i; - peaks.add(peak); - if (!peak.state.equals(PeakFindState.FIND_PEAK)) { - break; - } - lastPeak = peak; - } - - OptAlgoResult result = new OptAlgoResult(); - result.resultData = SubSampling.process(cxt.avg1000, 4); - result.ogiginData = data; - result.peaks = peaks; - return result; - } - - /** - * 求数据的均值(巴迪泰A5000算法) - * @param inputRaw 输入数据 - * @return 均值线 - */ - static double findAvgLine(double[] inputRaw) { - double base_min = 500; - double fsum = 0; - int cnt = 0; - - int range = inputRaw.length; - - do { - fsum = cnt = 0; - for (int i = 1; i < range; i++) { - if (inputRaw[i] < base_min) { - fsum += inputRaw[i]; - cnt++; - } - } - - base_min = base_min + 50; - } while (cnt < range - 15 * inputRaw.length / 250); - - return fsum / cnt; - } - - static Peak findPeak(LineProcessContext cxt, int searchStart, int peakWidth) { - Peak peak = new Peak(); - /* - * @brief 查找峰的位置 - * - * 思路: - * 搜索所有大于均值的点,当点满足,其数值大于附近一定数量的点时,认为是峰的位置 - */ - - log.info("findpeak start:{} windth:{}", searchStart, peakWidth); - - // judge_win_size - int judge_win_size = 2 * (cxt.avg1000.length / 250) + 1; - - int peakoff = findPeakOff(cxt, searchStart, peakWidth, judge_win_size); - if (peakoff < 0) { - peak.state = PeakFindState.NOT_FIND_PEAK; - return peak; - } - peak.peakPos = peakoff; - - /* - * @brief 查找峰的起始位置 - * - * 思路: - * 从峰的位置开始,向前搜索,找到一个点,其值小于平均值。 - * 然后继续向前搜索,找到一个点,斜率接近基线斜率。 - * - */ - - int peak_start_pos = findPeakKneePoint(cxt, peak.peakPos, -1, peakWidth / 2); - int peak_end_pos = findPeakKneePoint(cxt, peak.peakPos, 1, peakWidth / 2); - - if (peak_start_pos < 0) { - peak.state = PeakFindState.NOT_FIND_PEAK_START; - return peak; - } - if (peak_end_pos < 0) { - peak.state = PeakFindState.NOT_FIND_PEAK_END; - return peak; - } - - peak.peakStartPos = peak_start_pos; - peak.peakEndPos = peak_end_pos; - - /* - * @brief - * 计算峰的面积 - */ - - double peak_full_area = 0; - for (int i = peak_start_pos; i <= peak_end_pos; i++) { - peak_full_area += cxt.raw1000[i]; - } - - double peak_base_line_area; - peak_base_line_area = - (cxt.raw1000[peak_start_pos] + cxt.raw1000[peak_end_pos]) * 0.5 * (peak_end_pos - peak_start_pos + 1); - - peak.peakFullArea = peak_full_area; - peak.peakBaseLineArea = peak_base_line_area; - peak.area = peak_full_area - peak_base_line_area; - if (peak.area <= 0) - peak.area = 0.0; - peak.state = PeakFindState.FIND_PEAK; - - return peak; - } - - static public int findPeakOff(LineProcessContext cxt, int start_off, int windos_size, int judge_win_size) { - double maxv = 0; - int peakoff = -1; - boolean findmax = false; - - for (int index = 0; index < windos_size; index++) { - int off = index + start_off; - // 从窗口的一半大小开始判断 - if (findmax && cxt.avg1000[off] <= cxt.avgLine) - break; - if (off < judge_win_size / 2) - continue; - // 查找的点要大于基线 - if (cxt.avg1000[off] <= cxt.avgLine) - continue; - // 判断的 - if ((off + judge_win_size / 2) > (cxt.avg1000.length - 1)) - break; - // 找到最大的峰值,这里判断用于去除一个波峰中的某个临时的小波峰 - if (maxv > cxt.avg1000[off]) - continue; - - /* - * @brief 检查当前位置的点,是否是附近最大的点 - */ - if (BasicAlgo.isMaxvalInWindows(cxt.avg1000, off, judge_win_size)) { - findmax = true; - maxv = cxt.avg1000[off]; - peakoff = off; - } - } - return peakoff; - } - - static int findPeakKneePoint(LineProcessContext cxt, - int search_start, // - int search_direction, // - int search_windows) { - /* - * @brief - * 通过波峰的位置查找波峰的起始位置 - * - * 逻辑: - * 1. 从波峰的位置开始,向前搜索,找到一个点,其值小于平均值。 - * 2. 然后继续向前搜索,找到一个点,斜率接近基线斜率。 - * - */ - - int off = -1; - log.info("find peakend top_pos:{} direction:{} windows:{}", search_start, search_direction, search_windows); - - // - Assert.isTrue(search_windows > 0, "search_windows <= 0"); - Assert.isTrue(search_direction == 1 || search_direction == -1, "search_direction != 1 && search_direction != -1"); - // - int index_dval = search_direction >= 0 ? 1 : -1; - int search_end = search_start + search_direction * search_windows; - - Assert.isTrue(search_end >= 0, "search_end < 0"); - Assert.isTrue(cxt.avg1000.length > search_end, "cxt.avg1000.size() <= search_start"); - - for (int i = search_start; i != search_end; i += index_dval) { - double now = cxt.avg1000[i]; - if (now >= cxt.avgLine) - continue; - - if (search_direction == 1) { - if (BasicAlgo.feq(cxt.diff1000[i], cxt.baselineSlope, 0.3) || cxt.diff1000[i] >= cxt.baselineSlope) { - off = i; - break; - } - } else { - if (BasicAlgo.feq(cxt.diff1000[i], cxt.baselineSlope, 0.3) || cxt.diff1000[i] <= cxt.baselineSlope) { - off = i; - break; - } - } - } - return off; - } -} diff --git a/src/main/java/a8k/optalgo/OptAlgoUtils.java b/src/main/java/a8k/optalgo/OptAlgoUtils.java deleted file mode 100644 index 665459b..0000000 --- a/src/main/java/a8k/optalgo/OptAlgoUtils.java +++ /dev/null @@ -1,106 +0,0 @@ -package a8k.optalgo; - -import a8k.optalgo.type.LinearResult; -import a8k.optalgo.type.OptAlgoResult; -import org.springframework.util.Assert; - -public class OptAlgoUtils { - - OptAlgoResult processOptData(Integer expectPeakNum, Float[] data) { - return null; - } - - Boolean feq(double a, double b, double epsilon) { - double dv = a - b; - if (dv < 0) - dv = -dv; - return dv <= epsilon; - } - - - - - - - Float[] differentiate(Float[] inputRaw) { - /** - * @brief - * 巴迪泰源码,对原始数据添加了一些微小的值,原因未知 - */ - for (int i = 0; i <= inputRaw.length - 8; i += 8) { - inputRaw[i + 1] = inputRaw[i + 1] + 0.001f; - inputRaw[i + 2] = inputRaw[i + 2] + 0.002f; - inputRaw[i + 3] = inputRaw[i + 3] + 0.003f; - inputRaw[i + 4] = inputRaw[i + 4] + 0.004f; - inputRaw[i + 5] = inputRaw[i + 5] + 0.005f; - inputRaw[i + 6] = inputRaw[i + 6] + 0.004f; - inputRaw[i + 7] = inputRaw[i + 7] + 0.003f; - inputRaw[i + 8] = inputRaw[i + 8] + 0.002f; - } - - /** - * @brief - * @Warning: 此处求导和巴迪泰的存在差异, - * 巴迪泰的是当前数值减去下一个数值, - * 而此处是当前数值减去上一个数值 - */ - - Float[] differentiateRaw = new Float[inputRaw.length]; - for (int i = 1; i < differentiateRaw.length; i++) { - differentiateRaw[i] = inputRaw[i] - inputRaw[i - 1]; - } - differentiateRaw[0] = differentiateRaw[1]; - return differentiateRaw; - } - - Float[] least_square_method_differentiate(Float[] inputRaw, int windows_size) { - Assert.isTrue((windows_size > 0), "windows_size > 0"); - Assert.isTrue((windows_size % 2 == 1), "windows_size % 2 == 1"); - - Float[] differentiateRaw = new Float[inputRaw.length]; - Float[] windowsRaw = new Float[windows_size]; - - int windows_size_half = (windows_size - 1) / 2; - - for (int index = windows_size_half; index < inputRaw.length - windows_size_half; index++) { - // windowsRaw = getwindowspoint(inputRaw, index, windows_size); - float intercept = 0; - // linear_least_squares(windowsRaw, windows_size, differentiateRaw[index], - // intercept); - } - - for (int i = 0; i < windows_size_half; i++) { - differentiateRaw[i] = differentiateRaw[windows_size_half]; - } - - for (int i = inputRaw.length - windows_size_half; i < inputRaw.length; i++) { - differentiateRaw[i] = differentiateRaw[inputRaw.length - windows_size_half - 1]; - } - return differentiateRaw; - } - - float get_avg_in_windows(double[] src, int off, int windows) { - float sum = 0; - Assert.isTrue((windows % 2 == 1),"(windows % 2 == 1)"); - for (int i = off - windows / 2; i <= off + windows / 2; i++) { - sum += (float) src[i]; - } - return sum / windows; - } - - void sort_vector(Float[] src) { - // 实现冒泡排序 - for (int i = 0; i < src.length; i++) { - for (int j = 0; j < src.length - i - 1; j++) { - if (src[j] > src[j + 1]) { - float temp = src[j]; - src[j] = src[j + 1]; - src[j + 1] = temp; - } - } - } - } - - - -} diff --git a/src/main/java/a8k/service/app/appctrl/mainflowctrl/action/PLATE_OPT_SCAN.java b/src/main/java/a8k/service/app/appctrl/mainflowctrl/action/PLATE_OPT_SCAN.java index d1f8a8a..743dd7b 100644 --- a/src/main/java/a8k/service/app/appctrl/mainflowctrl/action/PLATE_OPT_SCAN.java +++ b/src/main/java/a8k/service/app/appctrl/mainflowctrl/action/PLATE_OPT_SCAN.java @@ -82,6 +82,14 @@ public class PLATE_OPT_SCAN extends A8kStepAction { return reactionResults; } + // + // 判断T光学是否需要扫描,T光学扫描方向,扫描范围 + // 判断F光学是否需要扫描,F光学扫描方向,扫描范围 + // 获取扫描起始位置,峰的数量,接收放大倍数,扫描放大倍数,是否自动调整放大倍数 + // 根据峰计算最终结果 + // + + //TODO 扫描反应板 //丢板 optScanModuleCtrlService.dropPlate(); diff --git a/src/main/java/a8k/service/app/devicectrl/ctrlservice/OptScanModuleCtrlService.java b/src/main/java/a8k/service/app/devicectrl/ctrlservice/OptScanModuleCtrlService.java index 67e3ea4..339551d 100644 --- a/src/main/java/a8k/service/app/devicectrl/ctrlservice/OptScanModuleCtrlService.java +++ b/src/main/java/a8k/service/app/devicectrl/ctrlservice/OptScanModuleCtrlService.java @@ -1,12 +1,17 @@ package a8k.service.app.devicectrl.ctrlservice; +import a8k.constant.OptConstant; import a8k.extapi_controler.pagecontrol.ExtApiTabConfig; import a8k.extapi_controler.utils.ExtApiTab; +import a8k.service.app.devicectrl.driver.OptModuleDriver; import a8k.service.app.devicectrl.driver.StepMotorCtrlDriver; +import a8k.service.app.devicectrl.driver.type.OptModuleRegIndex; import a8k.service.app.devicectrl.driver.type.StepMotorMId; import a8k.service.app.devicectrl.param.param_mgr.OptModuleParamsMgr; import a8k.service.bases.ActionReactorService; +import a8k.service.db.type.a8kidcard.zenum.A8kOptType; import a8k.type.IncubatorPos; +import a8k.type.OptScanDirection; import a8k.type.exception.AppException; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -23,6 +28,8 @@ public class OptScanModuleCtrlService { StepMotorCtrlDriver stepMotorCtrlDriver; @Resource ActionReactorService actionReactor; + @Resource + OptModuleDriver optModuleDriver; @Resource OptModuleParamsMgr optModuleParamsMgr; @@ -43,4 +50,29 @@ public class OptScanModuleCtrlService { stepMotorCtrlDriver.stepMotorEasyMoveToBlock(StepMotorMId.OptModScannerM, optModuleParamsMgr.getOptScanerScandbyPos(), overtime); } + + public Integer[] startOptScan(A8kOptType optType, OptScanDirection direction, Integer lasterGain, Integer scanGain) throws AppException { + Integer forwardScanPos = optModuleParamsMgr.getOptScanStartPos(optType); + switch (optType) { + case TOPT -> { + optModuleDriver.setReg(OptModuleRegIndex.kreg_a8k_opt_t_pos_offset, forwardScanPos); + optModuleDriver.setReg(OptModuleRegIndex.kreg_a8k_opt_t_reverse_scan_pos_offset, forwardScanPos - 1200); + optModuleDriver.setReg(OptModuleRegIndex.kreg_a8k_opt_scan_pointnum, 1200); + } + case FOPT -> { + optModuleDriver.setReg(OptModuleRegIndex.kreg_a8k_opt_f_pos_offset, forwardScanPos); + optModuleDriver.setReg(OptModuleRegIndex.kreg_a8k_opt_f_reverse_scan_pos_offset, forwardScanPos - 1200); + optModuleDriver.setReg(OptModuleRegIndex.kreg_a8k_opt_scan_pointnum, 1200); + } + } + + switch (optType) { + case TOPT -> optModuleDriver.optTStartScan(direction, lasterGain, scanGain); + case FOPT -> optModuleDriver.optFStartScan(direction, lasterGain, scanGain); + } + + return optModuleDriver.optReadRaw(); + } + + } diff --git a/src/main/java/a8k/service/app/devicectrl/driver/OptModuleDriver.java b/src/main/java/a8k/service/app/devicectrl/driver/OptModuleDriver.java new file mode 100644 index 0000000..f81e6b3 --- /dev/null +++ b/src/main/java/a8k/service/app/devicectrl/driver/OptModuleDriver.java @@ -0,0 +1,59 @@ +package a8k.service.app.devicectrl.driver; + +import a8k.hardware.A8kCanBusService; +import a8k.hardware.type.a8kcanprotocol.CmdId; +import a8k.hardware.type.a8kcanprotocol.MId; +import a8k.service.app.devicectrl.driver.type.OptModuleRegIndex; +import a8k.type.OptScanDirection; +import a8k.type.exception.AppException; +import a8k.utils.ByteArray; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Component +@Slf4j +public class OptModuleDriver { + + static Integer actionOvertime = 10000; + + @Resource + A8kCanBusService canBus; + + public void optTStartScan(OptScanDirection scanDirection, Integer lasterGain, Integer scanGain) throws AppException { + canBus.callcmd(MId.OptMod, CmdId.a8k_opt_v2_t_start_scan, scanDirection.getInteger(), lasterGain, scanGain); + canBus.waitForMod(MId.OptMod, actionOvertime); + } + + public void optFStartScan(OptScanDirection scanDirection, Integer lasterGain, Integer scanGain) throws AppException { + canBus.callcmd(MId.OptMod, CmdId.a8k_opt_v2_f_start_scan, scanDirection.getInteger(), lasterGain, scanGain); + canBus.waitForMod(MId.OptMod, actionOvertime); + } + + public Integer[] optReadRaw() throws AppException { + int i = 0; + List result = new ArrayList<>(); + while (true) { + var rxPacket = canBus.callcmd(MId.OptMod, CmdId.a8k_opt_v2_read_raw, i++); + if (rxPacket.getCmdContent().length == 0) { + break; + } + var rawdata = ByteArray.readU16bitArray(rxPacket.getCmdContent()); + result.addAll(Arrays.asList(rawdata)); + } + return result.toArray(new Integer[0]); + } + + public Integer readReg(OptModuleRegIndex regIndex) throws AppException { + return canBus.moduleGetReg(MId.OptMod, regIndex.regIndex); + } + + public void setReg(OptModuleRegIndex regIndex, Integer value) throws AppException { + canBus.moduleSetReg(MId.OptMod, regIndex.regIndex, value); + } + +} diff --git a/src/main/java/a8k/service/app/devicectrl/driver/type/OptModuleRegIndex.java b/src/main/java/a8k/service/app/devicectrl/driver/type/OptModuleRegIndex.java new file mode 100644 index 0000000..4f496e0 --- /dev/null +++ b/src/main/java/a8k/service/app/devicectrl/driver/type/OptModuleRegIndex.java @@ -0,0 +1,18 @@ +package a8k.service.app.devicectrl.driver.type; + +import a8k.hardware.type.regindex.RegIndex; + +public enum OptModuleRegIndex { + kreg_a8k_opt_t_pos_offset(RegIndex.kreg_a8k_opt_t_pos_offset), + kreg_a8k_opt_f_pos_offset(RegIndex.kreg_a8k_opt_f_pos_offset), + kreg_a8k_opt_t_reverse_scan_pos_offset(RegIndex.kreg_a8k_opt_t_reverse_scan_pos_offset), + kreg_a8k_opt_f_reverse_scan_pos_offset(RegIndex.kreg_a8k_opt_f_reverse_scan_pos_offset), + kreg_a8k_opt_scan_step_interval(RegIndex.kreg_a8k_opt_scan_step_interval), + kreg_a8k_opt_scan_pointnum(RegIndex.kreg_a8k_opt_scan_pointnum), + ; + + public final RegIndex regIndex; + OptModuleRegIndex(RegIndex regIndex) { + this.regIndex = regIndex; + } +} diff --git a/src/main/java/a8k/service/app/devicectrl/exdriver/TubeTransportExDriver.java b/src/main/java/a8k/service/app/devicectrl/exdriver/TubeTransportExDriver.java index 6e1be44..2d6ba2a 100644 --- a/src/main/java/a8k/service/app/devicectrl/exdriver/TubeTransportExDriver.java +++ b/src/main/java/a8k/service/app/devicectrl/exdriver/TubeTransportExDriver.java @@ -28,8 +28,6 @@ public class TubeTransportExDriver { @Resource MiniServoDriver miniServoDriver; - @Resource - TubeFeedingModuleParamMgr tubeScanPosMgr; @Resource StepMotorCtrlDriver stepMotorCtrlDriver; @@ -71,7 +69,6 @@ public class TubeTransportExDriver { } - @ExtApiFn(name = "扫描夹紧机构夹紧", group = "基础方法", order = 1) public void scanClampModClamp() throws AppException { logger.info("扫描夹紧机构夹紧"); miniServoDriver.miniServoEnable(MiniServoMId.ShakeModTubeScanerClampingSV, 1); @@ -81,7 +78,6 @@ public class TubeTransportExDriver { // canBus.waitForMod(MId.ShakeModTubeScanerClampingSV, overtime); } - @ExtApiFn(name = "扫描夹紧机构复位", group = "基础方法", order = 2) public void scanClampModRelease() throws AppException { logger.info("扫描夹紧机构复位"); miniServoDriver.miniServoEnable(MiniServoMId.ShakeModTubeScanerClampingSV, 1); diff --git a/src/main/java/a8k/service/app/devicectrl/param/calibration/OptModuleParamCalibration.java b/src/main/java/a8k/service/app/devicectrl/param/calibration/OptModuleParamCalibration.java new file mode 100644 index 0000000..a8f892a --- /dev/null +++ b/src/main/java/a8k/service/app/devicectrl/param/calibration/OptModuleParamCalibration.java @@ -0,0 +1,165 @@ +package a8k.service.app.devicectrl.param.calibration; + +import a8k.extapi_controler.pagecontrol.ExtApiTabConfig; +import a8k.extapi_controler.utils.ExtApiFn; +import a8k.extapi_controler.utils.ExtApiTab; +import a8k.optalgo.A8kOptAlgoUtils; +import a8k.service.app.devicectrl.ctrlservice.OptScanModuleCtrlService; +import a8k.service.app.devicectrl.ctrlservice.PlateBoxCtrlService; +import a8k.service.app.devicectrl.driver.OptModuleDriver; +import a8k.service.app.devicectrl.driver.StepMotorCtrlDriver; +import a8k.service.app.devicectrl.driver.type.StepMotorMId; +import a8k.service.app.devicectrl.exdriver.MotorEnableExDriver; +import a8k.service.app.devicectrl.param.param_mgr.OptModuleParamsMgr; +import a8k.service.db.type.Parameter; +import a8k.service.db.type.a8kidcard.zenum.A8kOptType; +import a8k.type.*; +import a8k.type.exception.AppException; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + + +/** + * + * + * 1.下面三个位置在ReactionPlatesTransmitControlerCalibration进行标定 + * PullerTargetPos("拉板目标位置"), + * OptScanerDropPos("丢板坐标"), + * OptScanerScandbyPos("扫描待机位"), + * + * 2. 该模块只用来标定 + * TOptScanStartPos (T光学扫描起始位置) + * FOptScanStartPos (F光学扫描起始位置) + */ +@ExtApiTab(cfg = ExtApiTabConfig.OptModuleParamCalibration) +@Component +public class OptModuleParamCalibration { + + Integer actionOvertime = 5000; + + @Resource + OptModuleParamsMgr optModuleParamsMgr; + + @Resource + MotorEnableExDriver motorEnableExDriver; + @Resource + StepMotorCtrlDriver stepMotorCtrlDriver; + @Resource + PlateBoxCtrlService plateBoxCtrlService; + @Resource + OptScanModuleCtrlService optScanModuleCtrlService; + @Resource + OptModuleDriver optModuleDriver; + + + @ExtApiFn(name = "获得参数", group = "基础", order = 1) + public List getParams() throws AppException { + return optModuleParamsMgr.getParams(); + } + + @ExtApiFn(name = "归零", group = "测试工具", order = 11) + public void deviceReset() throws AppException { + enableModule(); + //板夹仓初始化 + stepMotorCtrlDriver.stepMotorEasyMoveToZeroBlock(StepMotorMId.PlatesBoxYM, actionOvertime); + stepMotorCtrlDriver.stepMotorEasyMoveToZeroBlock(StepMotorMId.PlatesBoxPusherM, actionOvertime); + //光学模组初始化 + stepMotorCtrlDriver.stepMotorEasyMoveToZeroBlock(StepMotorMId.OptModPullM, actionOvertime); + stepMotorCtrlDriver.stepMotorEasyMoveToZeroBlock(StepMotorMId.OptModScannerM, actionOvertime); + //转盘归零 + stepMotorCtrlDriver.stepMotorEasyMoveToZeroBlock(StepMotorMId.IncubatorRotateCtrlM, actionOvertime); + } + + @ExtApiFn(name = "使能相关模块", group = "测试工具", order = 12) + public void enableModule() throws AppException { + motorEnableExDriver.enableAllMotor(); + } + + @ExtApiFn(name = "失能相关模块", group = "测试工具", order = 13) + public void disableModule() throws AppException { + motorEnableExDriver.forceDisableAllMotor(); + } + + // + // 辅助方法 + // + + /** + * From: 0号仓 + * TrunablePos:0号仓到 + */ + @ExtApiFn(name = "推板到光学模组", group = "测试工具", order = 100) + public void pushOnePlateToOptModule() throws AppException { + //先清空当前通道 + optScanModuleCtrlService.dropPlate(); + optScanModuleCtrlService.pullPlate(IncubatorPos.SPACE01); + optScanModuleCtrlService.dropPlate(); + + //推板到光学模组 + plateBoxCtrlService.pushPlateQuick(ConsumableGroup.GROUP0, IncubatorPos.SPACE01); + optScanModuleCtrlService.pullPlate(IncubatorPos.SPACE01); + } + + @ExtApiFn(name = "拉板到光学模组", group = "测试工具", order = 101) + public void dropPlate() throws AppException { + optScanModuleCtrlService.dropPlate(); + } + + // @ExtApiFn(name = "曲线显示测试", group = "测试工具", order = 102) + // public A8kScanCurve testCurveDisplay() { + // A8kScanCurve result = new A8kScanCurve(); + // result.refCurve = List.of(40, 80, 120, 160, 200); + // result.scanDataCurve = new ArrayList<>(); + // for (int i = 0; i < 250; i++) { + // result.scanDataCurve.add(i * 10); + // } + // return result; + // } + + A8kScanCurve createScanCurve1200Point(Integer[] optScanResult) { + // Integer[] optScanResult250 = A8kOptAlgoUtils.supperSamplingAndSubSampling(optScanResult); + List refCurve = new ArrayList<>(); + for (int i = 1; i < 6; i++) { + refCurve.add((int) (40 * 4.8 * i)); + } + + var result = new A8kScanCurve(); + result.refCurve = refCurve; + result.scanDataCurve = List.of(optScanResult); + return result; + } + + @ExtApiFn(name = "设置光学扫描参考点", group = "设置", order = 200) + public void setCurrentAsScanRefPos() throws AppException { + stepMotorCtrlDriver.stepMotorEnable(StepMotorMId.OptModScannerM, 1); + Integer pos = stepMotorCtrlDriver.stepMotorReadPosByMoveToZeroBlock(StepMotorMId.OptModScannerM, 10000); + optModuleParamsMgr.setOptScanRefPos(pos); + } + + @ExtApiFn(name = "设置F光学扫描偏移", group = "设置", order = 201) + public void setFOptScanShift(Integer shift) { + optModuleParamsMgr.setFOptScanShift(shift); + } + + @ExtApiFn(name = "设置T光学扫描偏移", group = "设置", order = 202) + public void setTOptScanShift(Integer shift) { + optModuleParamsMgr.setTOptScanShift(shift); + } + + + @ExtApiFn(name = "F光学扫描", group = "扫描", order = 102) + public A8kScanCurve FOptScan(Integer lasterGain, Integer scanGain) throws AppException { + var result = optScanModuleCtrlService.startOptScan(A8kOptType.FOPT, OptScanDirection.FORWARD, lasterGain, scanGain); + return createScanCurve1200Point(result); + } + + @ExtApiFn(name = "T光学扫描", group = "扫描", order = 102) + public A8kScanCurve TOptScan(Integer lasterGain, Integer scanGain) throws AppException { + var result = optScanModuleCtrlService.startOptScan(A8kOptType.TOPT, OptScanDirection.FORWARD, lasterGain, scanGain); + return createScanCurve1200Point(optModuleDriver.optReadRaw()); + } + +} diff --git a/src/main/java/a8k/service/app/devicectrl/param/param_mgr/OptModuleParamsMgr.java b/src/main/java/a8k/service/app/devicectrl/param/param_mgr/OptModuleParamsMgr.java index 6f8a128..d456a14 100644 --- a/src/main/java/a8k/service/app/devicectrl/param/param_mgr/OptModuleParamsMgr.java +++ b/src/main/java/a8k/service/app/devicectrl/param/param_mgr/OptModuleParamsMgr.java @@ -2,6 +2,8 @@ package a8k.service.app.devicectrl.param.param_mgr; import a8k.service.app.devicectrl.param.param_mgr.base.ParamMgr; +import a8k.service.db.type.a8kidcard.zenum.A8kOptType; +import a8k.type.OptScanDirection; import jakarta.annotation.PostConstruct; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,7 +13,7 @@ import org.springframework.stereotype.Component; * HBOT二维码扫描坐标参数 */ @Component -public class OptModuleParamsMgr extends ParamMgr { +public class OptModuleParamsMgr extends ParamMgr { static final Logger logger = LoggerFactory.getLogger(OptModuleParamsMgr.class); @@ -19,8 +21,9 @@ public class OptModuleParamsMgr extends ParamMgr { PullerTargetPos("拉板目标位置"), OptScanerDropPos("丢板坐标"), OptScanerScandbyPos("扫描待机位"), - TOptScanStartPos("T光学扫描起始坐标"), - FOptScanStartPos("F光学扫描起始坐标"), + OptScanRefPos("光学扫描参考坐标"), + TOptScanShift("T光学扫描偏移"), + FOptScanShift("F光学扫描偏移"), ; public final String chName; @@ -42,8 +45,9 @@ public class OptModuleParamsMgr extends ParamMgr { setParam(POS.PullerTargetPos, 1147); setParam(POS.OptScanerDropPos, -349); setParam(POS.OptScanerScandbyPos, 305); - setParam(POS.TOptScanStartPos, 3723); - setParam(POS.FOptScanStartPos, 2559); + setParam(POS.OptScanerScandbyPos, 4000); + setParam(POS.TOptScanShift, 277); + setParam(POS.FOptScanShift, 1441); } public Integer getPullerTargetPos() { @@ -58,13 +62,6 @@ public class OptModuleParamsMgr extends ParamMgr { return getParam(POS.OptScanerScandbyPos, Integer.class); } - public Integer getTOptScanStartPos() { - return getParam(POS.TOptScanStartPos, Integer.class); - } - - public Integer getFOptScanStartPos() { - return getParam(POS.FOptScanStartPos, Integer.class); - } public void setPullerTargetPos(Integer pos) { setParam(POS.PullerTargetPos, pos); @@ -78,12 +75,32 @@ public class OptModuleParamsMgr extends ParamMgr { setParam(POS.OptScanerScandbyPos, pos); } - public void setTOptScanStartPos(Integer pos) { - setParam(POS.TOptScanStartPos, pos); + + public void setOptScanRefPos(Integer pos) { + setParam(POS.OptScanRefPos, pos); } - public void setFOptScanStartPos(Integer pos) { - setParam(POS.FOptScanStartPos, pos); + public void setTOptScanShift(Integer pos) { + setParam(POS.TOptScanShift, pos); } + + public void setFOptScanShift(Integer pos) { + setParam(POS.FOptScanShift, pos); + } + + + public Integer getOptScanStartPos(A8kOptType type) { + Integer shift = switch (type) { + case TOPT -> getParam(POS.TOptScanShift, Integer.class); + case FOPT -> getParam(POS.FOptScanShift, Integer.class); + }; + + Integer scanStartPos = getParam(POS.OptScanRefPos, Integer.class); + scanStartPos = scanStartPos + shift; + + return scanStartPos; + } + + } diff --git a/src/main/java/a8k/service/db/type/a8kidcard/zenum/A8kOptType.java b/src/main/java/a8k/service/db/type/a8kidcard/zenum/A8kOptType.java index ede830d..5a944dd 100644 --- a/src/main/java/a8k/service/db/type/a8kidcard/zenum/A8kOptType.java +++ b/src/main/java/a8k/service/db/type/a8kidcard/zenum/A8kOptType.java @@ -1,6 +1,6 @@ package a8k.service.db.type.a8kidcard.zenum; public enum A8kOptType { - F, - T, + FOPT, + TOPT, } diff --git a/src/main/java/a8k/service/test/fakeproj/FakeProjInfo.java b/src/main/java/a8k/service/test/fakeproj/FakeProjInfo.java index 8815cdf..4d7130c 100644 --- a/src/main/java/a8k/service/test/fakeproj/FakeProjInfo.java +++ b/src/main/java/a8k/service/test/fakeproj/FakeProjInfo.java @@ -88,7 +88,7 @@ public class FakeProjInfo { /*光学配置*/ projOptConfig.subProjName = String.format("%s_%d", projName, subIndex); projOptConfig.subProjShortName = String.format("%s_%d", projShortName, subIndex); - projOptConfig.subProjOptType = A8kOptType.F; + projOptConfig.subProjOptType = A8kOptType.FOPT; projOptConfig.subProjScanRange = 200; projOptConfig.subProjScanDirection = OptScanDirection.Forward; projOptConfig.subProjPeakNum = 3; diff --git a/src/main/java/a8k/type/A8kScanCurve.java b/src/main/java/a8k/type/A8kScanCurve.java index be140fe..06a2df8 100644 --- a/src/main/java/a8k/type/A8kScanCurve.java +++ b/src/main/java/a8k/type/A8kScanCurve.java @@ -1,17 +1,14 @@ package a8k.type; +import java.util.ArrayList; import java.util.List; public class A8kScanCurve { - public List scanDataCurve; - public List refCurve; - public List refLine; + public List scanDataCurve = new ArrayList<>(); + public List refCurve = new ArrayList<>(); + public List refLine = new ArrayList<>(); public A8kScanCurve() { } - public A8kScanCurve(List scanDataCurve, List refLine) { - this.scanDataCurve = scanDataCurve; - this.refLine = refLine; - } } diff --git a/src/main/java/a8k/type/OptScanDirection.java b/src/main/java/a8k/type/OptScanDirection.java index 9e60e18..b243796 100644 --- a/src/main/java/a8k/type/OptScanDirection.java +++ b/src/main/java/a8k/type/OptScanDirection.java @@ -1,9 +1,10 @@ package a8k.type; public enum OptScanDirection { - POSITIVE, NEGATIVE; + FORWARD, //从左向右扫描 + BACKWARD; public Integer getInteger() { - return this == POSITIVE ? 1 : -1; + return this == FORWARD ? 1 : -1; } } diff --git a/src/main/java/a8k/type/appret/AppRet.java b/src/main/java/a8k/type/appret/AppRet.java index 9625af9..9b6c8d1 100644 --- a/src/main/java/a8k/type/appret/AppRet.java +++ b/src/main/java/a8k/type/appret/AppRet.java @@ -5,7 +5,7 @@ import a8k.hardware.type.a8kcanprotocol.A8kEcode; import a8k.type.exception.AppException; import lombok.Getter; -public class AppRet { +public class AppRet { public AppRetType appRetType = AppRetType.SUCCESS; // 错误信息 public AppError ecode = null; @@ -15,7 +15,7 @@ public class AppRet { public String traceInfo = null; // 携带的对象 public String dataType; - public T data; + public Object data; // 接口请求时间 @Getter @@ -29,32 +29,33 @@ public class AppRet { return !AppRetType.FAILURE.equals(appRetType); } - public static AppRet success(T data) { - AppRet r = new AppRet<>(); + public static AppRet success(T data) { + AppRet r = new AppRet(); r.appRetType = AppRetType.SUCCESS; r.data = data; + r.dataType = data.getClass().getSimpleName(); return r; } - public static AppRet success() { - AppRet r = new AppRet<>(); + public static AppRet success() { + AppRet r = new AppRet(); r.appRetType = AppRetType.SUCCESS; return r; } - public static AppRet fail(Exception e) { + public static AppRet fail(Exception e) { StringBuilder traceSb = new StringBuilder(); for (var trace : e.getStackTrace()) { traceSb.append(trace.toString()).append("\n"); } String trace = traceSb.toString(); - AppRet r = new AppRet<>(); + AppRet r = new AppRet(); r.appRetType = AppRetType.FAILURE; if (e instanceof AppException hexcep) { - r.ecode = hexcep.error; + r.ecode = hexcep.error; } else { - r.ecode = new AppError(A8kEcode.CODEERROR); + r.ecode = new AppError(A8kEcode.CODEERROR); } r.traceInfo = trace; r.message = e.getMessage();