diff --git a/app.db b/app.db index c97ca00..afaa2c7 100644 Binary files a/app.db and b/app.db differ diff --git a/src/main/java/com/iflytop/digester/controller/LiquidController.java b/src/main/java/com/iflytop/digester/controller/LiquidController.java index 71bfc3e..a9d3e27 100644 --- a/src/main/java/com/iflytop/digester/controller/LiquidController.java +++ b/src/main/java/com/iflytop/digester/controller/LiquidController.java @@ -30,4 +30,12 @@ public class LiquidController extends UfApiControllerBase { bucket.setVolume(bucket.totalVolume); return this.success(); } + + @ResponseBody + @PostMapping("/api/liquid/new-bucket") + public UfApiResponse newBucket(@RequestBody Map params) { + Integer bucketIndex = (Integer)params.get("index"); + this.device.liquidAddition.liquidNewBucket(bucketIndex); + return this.success(); + } } diff --git a/src/main/java/com/iflytop/digester/controller/TestController.java b/src/main/java/com/iflytop/digester/controller/TestController.java index aca350a..78fc4ef 100644 --- a/src/main/java/com/iflytop/digester/controller/TestController.java +++ b/src/main/java/com/iflytop/digester/controller/TestController.java @@ -21,4 +21,14 @@ public class TestController extends UfApiControllerBase { this.device.transferArm.takeOutTubesFromErrorSlot(indexes); return this.success(); } + + @ResponseBody + @PostMapping("/api/test/liquid-add") + public UfApiResponse liquidAdd(@RequestBody Map params) { + List tubes = (List)params.get("tubes"); + String type = (String)params.get("type"); + Integer volume = (Integer)params.get("volume"); + this.device.liquidAddition.addLiquidToTubes(tubes, type, volume); + return this.success(); + } } diff --git a/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionInstance.java b/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionInstance.java index c37cb99..1ed8fe3 100644 --- a/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionInstance.java +++ b/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionInstance.java @@ -1,7 +1,12 @@ package com.iflytop.digester.deviceinstance; +import com.iflytop.digester.model.MdbRuntimeLog; +import com.iflytop.digester.underframework.UfActuatorCmdExecutor; +import com.iflytop.digester.underframework.UfApplication; import com.iflytop.digester.underframework.UfCmdSnippetExecutor; +import com.iflytop.digester.underframework.dao.model.UfMdbNotification; import com.iflytop.digester.underframework.dao.model.UfMdbOption; import com.iflytop.digester.underframework.dao.model.UfMdbRuntimeVariable; +import com.iflytop.digester.underframework.util.UfCommon; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; @@ -10,6 +15,8 @@ import java.util.Map; public class LiquidAdditionInstance { // list of liquids private List liquids; + // lock for bucket empty + private final Object bucketEmptyLock = new Object(); // setup public void setup() { @@ -38,9 +45,7 @@ public class LiquidAdditionInstance { public void addLiquidToTubes(List tubes, List pumpIndexes, int volume ) { var pumpGroupOutIndex = pumpIndexes.get(0); var pumpGroupInIndex = pumpIndexes.get(1); - var liquid = liquids.get(pumpGroupOutIndex/2); - var type = liquids.get(pumpGroupOutIndex/2).type; - var rotateDistance = this.convertVolumeToPumpRotationDistance(type, volume); + this.bucketVolumeCheck(pumpGroupOutIndex); for ( int batchIndex=0; batchIndex<4; batchIndex++ ) { // 外圈 @@ -49,16 +54,10 @@ public class LiquidAdditionInstance { if ( hasGoutTout || hasGoutTin ) { UfCmdSnippetExecutor.execute("LiquidAdditionPrepare.Out." + batchIndex); if ( hasGoutTout ) { - var snippetKey = "LiquidAdditionPump." + pumpGroupOutIndex; - Map snippetParams = Map.of("volume", rotateDistance); - UfCmdSnippetExecutor.execute(snippetKey, snippetParams); - liquid.volume -= volume; + this.pump(pumpGroupOutIndex, volume); } if ( hasGoutTin ) { - var snippetKey = "LiquidAdditionPump." + pumpGroupInIndex; - Map snippetParams = Map.of("volume", rotateDistance); - UfCmdSnippetExecutor.execute(snippetKey, snippetParams); - liquid.volume -= volume; + this.pump(pumpGroupInIndex, volume); } } @@ -68,16 +67,10 @@ public class LiquidAdditionInstance { if ( hasGinTout || hasGinTin ) { UfCmdSnippetExecutor.execute("LiquidAdditionPrepare.In." + batchIndex); if ( hasGinTout ) { - var snippetKey = "LiquidAdditionPump." + pumpGroupOutIndex; - Map snippetParams = Map.of("volume", rotateDistance); - UfCmdSnippetExecutor.execute(snippetKey, snippetParams); - liquid.volume -= volume; + this.pump(pumpGroupOutIndex, volume); } if ( hasGinTin ) { - var snippetKey = "LiquidAdditionPump." + pumpGroupInIndex; - Map snippetParams = Map.of("volume", rotateDistance); - UfCmdSnippetExecutor.execute(snippetKey, snippetParams); - liquid.volume -= volume; + this.pump(pumpGroupInIndex, volume); } } } @@ -85,6 +78,68 @@ public class LiquidAdditionInstance { UfCmdSnippetExecutor.execute("LiquidAdditionReset"); } + // add liquid to tubes by given pump indexes + private void pump( Integer pumpIndex, Integer volume ) { + var liquid = liquids.get((0==pumpIndex%2) ? pumpIndex/2 : (pumpIndex-1)/2); + var type = liquid.type; + + var snippetKey = "LiquidAdditionPump." + pumpIndex; + var rotateDistance = this.convertVolumeToPumpRotationDistance(type, volume); + Map snippetParams = Map.of("volume", rotateDistance); + UfCmdSnippetExecutor.execute(snippetKey, snippetParams); + + // update liquid volume + liquid.setVolumeByConsumed(volume); + MdbRuntimeLog.log("LiquidAdd", "酸液消耗:%s - %d [%d/%d]", type, volume, liquid.volume, liquid.totalVolume); + } + + // 检查液体量 + private void bucketVolumeCheck( Integer pumpIndex ) { + var liquid = liquids.get((0==pumpIndex%2) ? pumpIndex/2 : (pumpIndex-1)/2); + var stateStr = UfActuatorCmdExecutor.execute("LiquidBucketVolumeIO", "module_readio"); + var state = Integer.parseInt(stateStr); + MdbRuntimeLog.log("LiquidBucketVolumeIO", "液桶状态:[%s]", Integer.toString(state, 2)); + var bucketState = state >> liquid.bucketIndex & 1; + if ( 1 == bucketState ) { // 酸液足够 + return ; + } + + // 如果缺少的液体不是水, 则需要发送通知手动补充 + var env = UfApplication.getApp().getEnv(); + Integer waterBucketIndex = env.getProperty("app.liquidWaterBucketIndex", Integer.class); + assert waterBucketIndex != null; + if (!waterBucketIndex.equals(liquid.bucketIndex)) { + UfMdbNotification.action("LiquidBucketEmpty", Map.of("liquid", liquid)); + MdbRuntimeLog.log("LiquidBucketEmpty", "酸液不足,等待手动补充完成 : %s", liquid.type); + synchronized ( this.bucketEmptyLock ) { + try { + this.bucketEmptyLock.wait(); + MdbRuntimeLog.log("LiquidBucketEmpty", "酸液补充完成"); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + this.bucketVolumeCheck(pumpIndex); + return; + } + + // 水桶液位不足,自动补充 + MdbRuntimeLog.log("WaterBucketEmpty", "水桶液位不足,自动补充"); + UfActuatorCmdExecutor.execute("LiquidBucketVolumeIO", "module_writeio", "8,1"); + do { + // 检查上限位是否达到 + var waterStateStr = UfActuatorCmdExecutor.execute("LiquidBucketVolumeIO", "module_readio"); + var waterState = Integer.parseInt(waterStateStr); + boolean isBucketFull = 1 == (waterState >> 12 & 1); + if ( isBucketFull ) { + break; + } + UfCommon.delay(100); + } while ( true ); + UfActuatorCmdExecutor.execute("LiquidBucketVolumeIO", "module_writeio", "8,0"); + MdbRuntimeLog.log("WaterBucketEmpty", "水桶液位补充完成"); + } + // 针对试管加液 public void addLiquidToTubes(List tubes, String type, int volume ) { var pumpIndexes = this.getPumpIndexForGroupOutAndIn(type); @@ -132,4 +187,13 @@ public class LiquidAdditionInstance { } UfCmdSnippetExecutor.execute("LiquidAddShakeStop"); } + + // 酸液更换完成 + public void liquidNewBucket( Integer index ) { + var liquid = liquids.get(index); + liquid.setVolume(liquid.totalVolume); + synchronized ( this.bucketEmptyLock ) { + this.bucketEmptyLock.notify(); + } + } } diff --git a/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionLiquid.java b/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionLiquid.java index aed09ad..428c4bf 100644 --- a/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionLiquid.java +++ b/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionLiquid.java @@ -23,4 +23,9 @@ public class LiquidAdditionLiquid { this.volume = volume; UfMdbRuntimeVariable.setInteger(String.format("LiquidBucketVolume.%d", this.bucketIndex), volume); } + + // 通过消耗量设置剩余量 + public void setVolumeByConsumed( Integer volume ) { + this.setVolume( this.volume - volume); + } } diff --git a/src/main/java/com/iflytop/digester/underframework/util/UfCommon.java b/src/main/java/com/iflytop/digester/underframework/util/UfCommon.java new file mode 100644 index 0000000..ebf3c8b --- /dev/null +++ b/src/main/java/com/iflytop/digester/underframework/util/UfCommon.java @@ -0,0 +1,11 @@ +package com.iflytop.digester.underframework.util; +public class UfCommon { + // delay for ms + public static void delay( Integer ms ) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 28d6d86..3524b01 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -36,6 +36,7 @@ app : errorSlotIndex : 4 liquidPeristalticPumpPipeSetupEnable : false liquidPipeVolumn : 1 + liquidWaterBucketIndex : 2 opencv-library-path: D:/ProgramFiles/OpenCV/opencv/build/java/x64/opencv_java490.dll pylon-library-path: D:/ProgramFiles/Pylon5/Runtime/x64/PylonC_v5_2.dll pylon-wrapper-path: D:/Sige5193/digester/src/main/java/com/iflytop/digester/camera/x64/Debug/baslerCamera.dll