diff --git a/README.md b/README.md index 2ca8d8f..d9eaad3 100644 --- a/README.md +++ b/README.md @@ -244,4 +244,10 @@ TODO: ... 错误码 ... +``` + + +``` +TODO: + 单片机层添加急停指令,同时添加急停错误。 ``` \ No newline at end of file diff --git a/app.db b/app.db index a2b79c9..1fe34ab 100644 Binary files a/app.db and b/app.db differ diff --git a/src/main/java/a8k/extapi_controler/pagecontrol/ExtApiTabConfig.java b/src/main/java/a8k/extapi_controler/pagecontrol/ExtApiTabConfig.java index 6249665..59b4904 100644 --- a/src/main/java/a8k/extapi_controler/pagecontrol/ExtApiTabConfig.java +++ b/src/main/java/a8k/extapi_controler/pagecontrol/ExtApiTabConfig.java @@ -20,6 +20,7 @@ public enum ExtApiTabConfig { ReactionPlatesTransmitControlerCalibration("校准.反应板相关位置校准", true), HbotTipPosCalibration("校准.Tip耗材位置校准", true), HbotLittleBottleConsumableCalibration("校准.小瓶耗材位置校准", true), + HbotLargeBottleBSPosCalibration("校准.大瓶BS耗材位置校准", true), ActionReactorService("底层调试.单步调试", false),//OK Hbot2DCodeScanPos("参数.Hbot二维码扫描坐标参数", false), diff --git a/src/main/java/a8k/service/app/devicedriver/calibration/HbotLargeBottleBSPosCalibration.java b/src/main/java/a8k/service/app/devicedriver/calibration/HbotLargeBottleBSPosCalibration.java new file mode 100644 index 0000000..cdca599 --- /dev/null +++ b/src/main/java/a8k/service/app/devicedriver/calibration/HbotLargeBottleBSPosCalibration.java @@ -0,0 +1,200 @@ +package a8k.service.app.devicedriver.calibration; + + +import a8k.extapi_controler.pagecontrol.ExtApiTabConfig; +import a8k.extapi_controler.utils.ExtApiFn; +import a8k.extapi_controler.utils.ExtApiTab; +import a8k.service.app.devicedriver.basectrl.HbotModule; +import a8k.service.app.devicedriver.basectrl.PipetteCtrlModule; +import a8k.service.app.devicedriver.ctrl.HbotControler; +import a8k.service.app.devicedriver.pos.HbotConsumablePosMgr; +import a8k.type.*; +import a8k.type.cfg.Pos2d; +import a8k.type.cfg.Pos3d; +import a8k.type.exception.AppException; +import a8k.utils.ZJsonHelper; +import a8k.utils.ZSimplAlgo; +import com.fasterxml.jackson.databind.node.ObjectNode; +import jakarta.annotation.Resource; +import org.aspectj.lang.annotation.Aspect; +import org.slf4j.Logger; +import org.springframework.stereotype.Component; + +import java.util.List; + +@ExtApiTab(cfg = ExtApiTabConfig.HbotLargeBottleBSPosCalibration) +@Component +@Aspect +public class HbotLargeBottleBSPosCalibration { + static Logger logger = org.slf4j.LoggerFactory.getLogger(HbotLargeBottleBSPosCalibration.class); + + @Resource + PipetteCtrlModule pipetteCtrlModule; + @Resource + HbotModule hbotModule; + + + @Resource + HbotControler hbotControler; + @Resource + HbotConsumablePosMgr hbotConsumablePosMgr; + + Boolean stopFlag = false; + + Boolean checkStopFlag() { + if (stopFlag) { + stopFlag = false; + return true; + } + return false; + } + + void resetStopFlag() { + stopFlag = false; + } + + void setStopFlag() { + stopFlag = true; + } + + + @ExtApiFn(name = "获取坐标", group = "基础", order = 1) + public Object getPoss() throws AppException { + return hbotConsumablePosMgr.getParams(); + } + + + // 测试工具 + @ExtApiFn(name = "归零", group = "测试工具", order = 11) + public void moveToZero() throws AppException { + enableModule(); + pipetteCtrlModule.zMotorMoveZeroBlock(); + hbotModule.moveToZeroBlock(); + } + + @ExtApiFn(name = "使能相关模块", group = "测试工具", order = 12) + public void enableModule() throws AppException { + pipetteCtrlModule.zMotorEnable(1); + hbotModule.enable(1); + } + + @ExtApiFn(name = "失能相关模块", group = "测试工具", order = 13) + public void disableModule() throws AppException { + pipetteCtrlModule.zMotorEnable(0); + hbotModule.enable(0); + } + + + List refpoints = new java.util.ArrayList<>(); + + + @ExtApiFn(name = "开始标定大瓶坐标", group = "标定大瓶缓液XY坐标", order = 30) + public void startCalibrate() throws AppException { + refpoints = new java.util.ArrayList<>(); + moveToZero(); + disableModule(); + } + + @ExtApiFn(name = "添加大瓶参考点", group = "标定大瓶缓液XY坐标", order = 31) + public Object addRefPoint(ConsumableGroup group) throws AppException { + enableModule(); + Pos2d xypos = hbotModule.readPos(); + // pipetteCtrlModule.zMotorMeasureDistance(); + // Integer z = pipetteCtrlModule.zMotorReadMeasureDistanceResult(); + LargeBottleConsumableRefPoint refPoints = new LargeBottleConsumableRefPoint(group, new Pos3d(xypos.x, xypos.y, 0)); + this.refpoints.add(refPoints); + disableModule(); + ObjectNode node = ZJsonHelper.createObjectNode(); + node.put("newPoint", ZJsonHelper.createObjectNode(refPoints)); + node.put("computeResult", ZJsonHelper.createObjectNode(computeLittleBottlePosInfo())); + return node; + } + + @ExtApiFn(name = "移除最后一个参考点", group = "标定大瓶缓液XY坐标", order = 32) + public void removeTheLastRefPoint() { + if (!refpoints.isEmpty()) { + refpoints.remove(refpoints.size() - 1); + } + } + + + @ExtApiFn(name = "读取坐标计算结果", group = "标定大瓶缓液XY坐标", order = 33) + public LargeBottoleConsumablePosInfo computeLittleBottlePosInfo() { + //第一排x求平均 + // x[0] = ZSimplAlgo.computeAverage( + // littleBottleConsumableRefPoint.stream().filter(point -> point.group.ordinal() % 3 == 0 && point.index % 5 == 0). + // map(point -> point.pos.x).toList() + // ); + + var p00 = refpoints.stream().filter(point -> point.group == ConsumableGroup.GROUP0).findFirst().orElse(null); + Double x, y, dx = null, dy = null; + + x = ZSimplAlgo.computeAverage( + refpoints.stream().filter(point -> point.group.ordinal() / 3 == 0). + map(point -> point.pos.x).toList()); + //第一列y求平均 + y = ZSimplAlgo.computeAverage( + refpoints.stream().filter(point -> point.group.ordinal() % 3 == 0). + map(point -> point.pos.y).toList()); + //除了第一列的所有点,减少x,相加,求平均 + if (p00 != null) { + dx = ZSimplAlgo.computeAverage( + refpoints.stream().filter(point -> point.getCol() != 0). + map(point -> (point.pos.x - p00.pos.x) * 1.0 / point.getCol()).toList()); + //除了第一排的所有点,减少y,相加,求平均 + dy = ZSimplAlgo.computeAverage( + refpoints.stream().filter(point -> point.getRow() != 0). + map(point -> (point.pos.y - p00.pos.y) * 1.0 / point.getRow()).toList()); + } + + return new LargeBottoleConsumablePosInfo(new Pos3d(x.intValue(), y.intValue(), 0), dx, dy); + } + + @ExtApiFn(name = "保存计算结果", group = "标定大瓶缓液XY坐标", order = 34) + public void savePosInfo() throws AppException { + hbotConsumablePosMgr.setLargeBufferGroupPosInfo(computeLittleBottlePosInfo()); + } + + @ExtApiFn(name = "读取所有参考点", group = "标定大瓶缓液XY坐标", order = 35) + public Object readAllRefPoint() throws AppException { + return refpoints; + } + + // + // 标定Z轴 + // + public void setZPos(HbotConsumablePosParam posName) throws AppException { + enableModule(); + pipetteCtrlModule.zMotorMeasureDistance(); + hbotConsumablePosMgr.setParam(posName, pipetteCtrlModule.zMotorReadMeasureDistanceResult()); + disableModule(); + } + + @ExtApiFn(name = "校准.大瓶缓冲液Z轴位置", group = "标定Z轴", order = 104) + public void setLargeBSSSampleZPos() throws AppException {setZPos(HbotConsumablePosParam.LargeBSSSampleZPos);} + + @ExtApiFn(name = "校准.大瓶缓冲液Z轴结束位置", group = "标定Z轴", order = 105) + public void setLargeBSSSampleEndZPos() throws AppException {setZPos(HbotConsumablePosParam.LargeBSSSampleEndZPos);} + + // + // 校验 + // + + @ExtApiFn(name = "校验大瓶缓冲液坐标", group = "校验", order = 303) + public void testMoveToLargeBufferPos() throws AppException { + resetStopFlag(); + enableModule(); + for (ConsumableGroup group : ConsumableGroup.values()) { + hbotControler.moveToLargeBufferPos(group); + if (checkStopFlag()) + return; + } + } + + @ExtApiFn(name = "停止校验", group = "校验", order = 304) + public void stopTest() throws AppException { + setStopFlag(); + } + + +} diff --git a/src/main/java/a8k/service/app/devicedriver/calibration/HbotLittleBottleConsumableCalibration.java b/src/main/java/a8k/service/app/devicedriver/calibration/HbotLittleBottleConsumableCalibration.java index 4e490b9..2e63cc9 100644 --- a/src/main/java/a8k/service/app/devicedriver/calibration/HbotLittleBottleConsumableCalibration.java +++ b/src/main/java/a8k/service/app/devicedriver/calibration/HbotLittleBottleConsumableCalibration.java @@ -102,8 +102,8 @@ public class HbotLittleBottleConsumableCalibration { public Object addLittleBottleGroupRefPoint(ConsumableGroup group, Integer off0To24) throws AppException { enableModule(); Pos2d xypos = hbotModule.readPos(); -// pipetteCtrlModule.zMotorMeasureDistance(); -// Integer z = pipetteCtrlModule.zMotorReadMeasureDistanceResult(); + // pipetteCtrlModule.zMotorMeasureDistance(); + // Integer z = pipetteCtrlModule.zMotorReadMeasureDistanceResult(); LittleBottleConsumableRefPoint littleBufferRefPoint = new LittleBottleConsumableRefPoint(group, off0To24, new Pos3d(xypos.x, xypos.y, 0)); this.littleBottleConsumableRefPoint.add(littleBufferRefPoint); disableModule(); @@ -222,31 +222,32 @@ public class HbotLittleBottleConsumableCalibration { // 标定Z轴 // + // LittleBSSampleEndZPos("小瓶缓冲液取样结束Z坐标"), + // ProbeSubstanceSampleZPos("探测物质取样Z坐标"), + // ProbeSubstanceSampleEndZPos("探测物质取样结束Z坐标"), - @ExtApiFn(name = "校准.小瓶穿孔Z轴位置", group = "标定Z轴", order = 101) - public void setLittleBSPierceZPos() throws AppException { + public void setZPos(HbotConsumablePosParam posName) throws AppException { enableModule(); pipetteCtrlModule.zMotorMeasureDistance(); - hbotConsumablePosMgr.setParam(HbotConsumablePosParam.LittleBSPierceZPos, pipetteCtrlModule.zMotorReadMeasureDistanceResult()); + hbotConsumablePosMgr.setParam(posName, pipetteCtrlModule.zMotorReadMeasureDistanceResult()); disableModule(); } + + @ExtApiFn(name = "校准.小瓶穿孔Z轴位置", group = "标定Z轴", order = 101) + public void setLittleBSPierceZPos() throws AppException {setZPos(HbotConsumablePosParam.LittleBSPierceZPos);} + @ExtApiFn(name = "校准.小瓶取样Z轴位置", group = "标定Z轴", order = 102) - public void setLittleBSSampleZPos() throws AppException { - enableModule(); - pipetteCtrlModule.zMotorMeasureDistance(); - hbotConsumablePosMgr.setParam(HbotConsumablePosParam.LittleBSSampleZPos, pipetteCtrlModule.zMotorReadMeasureDistanceResult()); - disableModule(); - } + public void setLittleBSSampleZPos() throws AppException {setZPos(HbotConsumablePosParam.LittleBSSampleZPos);} + + @ExtApiFn(name = "校准.探测物质取样结束Z轴位置", group = "标定Z轴", order = 103) + public void setProbeSubstanceSampleEndZPos() throws AppException {setZPos(HbotConsumablePosParam.ProbeSubstanceSampleEndZPos);} @ExtApiFn(name = "校准.探测物质取样Z轴位置", group = "标定Z轴", order = 103) - public void setProbeSubstanceSampleZPos() throws AppException { - enableModule(); - pipetteCtrlModule.zMotorMeasureDistance(); - hbotConsumablePosMgr.setParam(HbotConsumablePosParam.ProbeSubstanceSampleZPos, pipetteCtrlModule.zMotorReadMeasureDistanceResult()); - disableModule(); - } + public void setProbeSubstanceSampleZPos() throws AppException {setZPos(HbotConsumablePosParam.ProbeSubstanceSampleZPos);} + @ExtApiFn(name = "校准.小瓶缓冲液取样结束Z轴位置", group = "标定Z轴", order = 104) + public void setLittleBSSampleEndZPos() throws AppException {setZPos(HbotConsumablePosParam.LittleBSSampleEndZPos);} // // 校验 diff --git a/src/main/java/a8k/service/app/devicedriver/pos/HbotConsumablePosMgr.java b/src/main/java/a8k/service/app/devicedriver/pos/HbotConsumablePosMgr.java index 1b3a947..ff77270 100644 --- a/src/main/java/a8k/service/app/devicedriver/pos/HbotConsumablePosMgr.java +++ b/src/main/java/a8k/service/app/devicedriver/pos/HbotConsumablePosMgr.java @@ -5,14 +5,9 @@ import a8k.extapi_controler.utils.ExtApiParamsTab; import a8k.extapi_controler.utils.ExtApiTab; import a8k.service.db.LowerDeviceParameterDBService; import a8k.service.db.utils.PosParameterReader; -import a8k.type.ConsumableGroup; -import a8k.type.HbotConsumablePosParam; -import a8k.type.LittleBottleConsumablePosInfo; -import a8k.type.LittleBottleConsumableType; +import a8k.type.*; import a8k.type.cfg.Pos3d; import a8k.type.type.TipGroup; -import a8k.utils.ZJsonHelper; -import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; import org.slf4j.Logger; @@ -20,8 +15,6 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.util.Assert; -import java.util.List; - /** * HBOT二维码扫描坐标参数 */ @@ -161,6 +154,21 @@ public class HbotConsumablePosMgr { return info; } + public LargeBottoleConsumablePosInfo getLargeBufferGroupPosInfo() { + LargeBottoleConsumablePosInfo info = new LargeBottoleConsumablePosInfo(); + info.pos00 = posReader.getPos(HbotConsumablePosParam.LargeBuffer_0Pos, Pos3d.class); + info.dx = posReader.getPos(HbotConsumablePosParam.LargeBuffer_DX, Double.class); + info.dy = posReader.getPos(HbotConsumablePosParam.LargeBuffer_DY, Double.class); + return info; + } + + + public void setLargeBufferGroupPosInfo(LargeBottoleConsumablePosInfo info) { + posReader.updatePos(HbotConsumablePosParam.LargeBuffer_0Pos, info.pos00); + posReader.updatePos(HbotConsumablePosParam.LargeBuffer_DX, info.dx); + posReader.updatePos(HbotConsumablePosParam.LargeBuffer_DY, info.dy); + } + public LittleBottleConsumablePosInfo getLittleBottleConsumablePosInfo(LittleBottleConsumableType type) { if (type.equals(LittleBottleConsumableType.BufferSolution)) { return getLittleBufferGroupPosInfo(); diff --git a/src/main/java/a8k/type/HbotConsumablePosParam.java b/src/main/java/a8k/type/HbotConsumablePosParam.java index 1ae446f..6ed963e 100644 --- a/src/main/java/a8k/type/HbotConsumablePosParam.java +++ b/src/main/java/a8k/type/HbotConsumablePosParam.java @@ -38,8 +38,11 @@ public enum HbotConsumablePosParam { LittleBSPierceZPos("小瓶缓冲液刺破Z坐标"), LittleBSSampleZPos("小瓶缓冲液取样Z坐标"), + LittleBSSampleEndZPos("小瓶缓冲液取样结束Z坐标"), ProbeSubstanceSampleZPos("探测物质取样Z坐标"), + ProbeSubstanceSampleEndZPos("探测物质取样结束Z坐标"), LargeBSSSampleZPos("大瓶缓冲液取样Z坐标"), + LargeBSSSampleEndZPos("大瓶缓冲液取样结束Z坐标"), ; diff --git a/src/main/java/a8k/type/LargeBottleConsumableRefPoint.java b/src/main/java/a8k/type/LargeBottleConsumableRefPoint.java new file mode 100644 index 0000000..69ca111 --- /dev/null +++ b/src/main/java/a8k/type/LargeBottleConsumableRefPoint.java @@ -0,0 +1,22 @@ +package a8k.type; + +import a8k.type.cfg.Pos3d; + +public class LargeBottleConsumableRefPoint { + public ConsumableGroup group; + + public Pos3d pos; + + public LargeBottleConsumableRefPoint(ConsumableGroup group, Pos3d pos) { + this.group = group; + this.pos = pos; + } + + public Integer getRow() { + return group.ordinal() / 3; + } + + public Integer getCol() { + return group.ordinal() % 3; + } +} diff --git a/src/main/java/a8k/type/LargeBottoleConsumablePosInfo.java b/src/main/java/a8k/type/LargeBottoleConsumablePosInfo.java new file mode 100644 index 0000000..87fa30b --- /dev/null +++ b/src/main/java/a8k/type/LargeBottoleConsumablePosInfo.java @@ -0,0 +1,17 @@ +package a8k.type; + +import a8k.type.cfg.Pos3d; + +public class LargeBottoleConsumablePosInfo { + public Pos3d pos00; + public Double dx; + public Double dy; + + public LargeBottoleConsumablePosInfo(Pos3d pos00, Double dx, Double dy) { + this.pos00 = pos00; + this.dx = dx; + this.dy = dy; + } + + public LargeBottoleConsumablePosInfo(){} +} diff --git a/src/main/java/a8k/utils/ZJsonHelper.java b/src/main/java/a8k/utils/ZJsonHelper.java index 73a4b94..ca83a14 100644 --- a/src/main/java/a8k/utils/ZJsonHelper.java +++ b/src/main/java/a8k/utils/ZJsonHelper.java @@ -49,6 +49,9 @@ public class ZJsonHelper { public static ObjectNode createObjectNode(Object obj) { ObjectMapper ObjectMapper = new ObjectMapper(); + if (obj == null) { + return null; + } if (obj instanceof Integer) { return ObjectMapper.createObjectNode().put("value", (Integer) obj); } diff --git a/src/main/java/a8k/utils/ZSqliteJdbcHelper.java b/src/main/java/a8k/utils/ZSqliteJdbcHelper.java index 613a949..797cbae 100644 --- a/src/main/java/a8k/utils/ZSqliteJdbcHelper.java +++ b/src/main/java/a8k/utils/ZSqliteJdbcHelper.java @@ -3,6 +3,7 @@ package a8k.utils; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import org.slf4j.Logger; import org.springframework.jdbc.core.JdbcTemplate; import java.lang.reflect.InvocationTargetException; @@ -17,6 +18,7 @@ import java.util.Date; import java.util.List; public class ZSqliteJdbcHelper { + static Logger logger = org.slf4j.LoggerFactory.getLogger(ZSqliteJdbcHelper.class); static public boolean isTableExist(JdbcTemplate jdbcTemplate, String tableName) { String sql = "select * from sqlite_master where type = 'table' and name = '" + tableName + "';"; @@ -74,6 +76,7 @@ public class ZSqliteJdbcHelper { static public Object rowMapper(ResultSet rs, Class tClass) throws SQLException, InstantiationException, IllegalAccessException { Object obj = tClass.newInstance(); for (java.lang.reflect.Field field : tClass.getDeclaredFields()) { + if (field.getType().equals(Integer.class)) { field.set(obj, rs.getInt(field.getName())); } else if (field.getType().equals(int.class)) { @@ -94,7 +97,13 @@ public class ZSqliteJdbcHelper { } else if (field.getType().equals(ObjectNode.class)) { ObjectMapper objectMapper = new ObjectMapper(); try { - field.set(obj, objectMapper.readTree(rs.getString(field.getName()))); + String val = rs.getString(field.getName()); + if (val != null && !val.isEmpty()) { +// logger.info("val: {}", val); + field.set(obj, objectMapper.readTree(val)); + } else { + field.set(obj, null); + } } catch (JsonProcessingException e) { throw new RuntimeException(e); } @@ -125,6 +134,11 @@ public class ZSqliteJdbcHelper { if (field.getName().equals("id")) continue; + if(field.get(obj) == null){ + args.add(null); + continue; + } + field.setAccessible(true); if (field.getType().equals(Integer.class) || field.getType().equals(int.class)) { // args[i] = field.getInt(obj); @@ -153,7 +167,6 @@ public class ZSqliteJdbcHelper { } else { ObjectMapper objectMapper = new ObjectMapper(); args.add(objectMapper.writeValueAsString(field.get(obj))); - } } catch (IllegalAccessException | JsonProcessingException e) { e.printStackTrace();