Browse Source

修改一致性检测的配置方式

master
zhaohe 3 months ago
parent
commit
e552c33bda
  1. 1
      .gitignore
  2. 0
      sh/deply.bat
  3. 0
      sh/mkexe.bat
  4. 2
      sh/sync_from_board.bat
  5. 2
      src/main/java/a8k/app/constant/AppConstant.java
  6. 18
      src/main/java/a8k/app/controler/api/v1/engineer/ExperimentConsistencyTestingControler.java
  7. 205
      src/main/java/a8k/app/engineer/service/qatest/ExperimentConsistencyTestingService.java
  8. 12
      src/main/java/a8k/app/engineer/service/qatest/QATemperatureCtrlTestService.java
  9. 5
      src/main/java/a8k/app/engineer/service/type/TubeExConfig.java
  10. 16
      src/main/java/a8k/app/engineer/service/type/TubeHolderExConfig.java
  11. 2
      src/main/java/a8k/app/hardware/driver/CodeScanerDriver.java
  12. 19
      src/main/java/a8k/app/service/background/SensorDataUpdateService.java
  13. 1
      src/main/java/a8k/app/service/background/TemperatureCtrlService.java
  14. 12
      src/main/java/a8k/app/service/lowerctrl/HbotMoveExCtrlService.java
  15. 3
      src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrlService.java
  16. 6
      src/main/java/a8k/app/service/lowerctrl/OptScanModuleCtrlService.java
  17. 9
      src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgrService.java
  18. 5
      src/main/java/a8k/app/service/statemgr/TubeStateMgrService.java
  19. 6
      src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java
  20. 228
      src/main/java/a8k/extui/page/extapp/P01PipetteGunVerification.java
  21. 97
      src/main/java/a8k/extui/page/extapp/profession_test/ExperimentConsistencyTestingPage.java
  22. 80
      src/main/java/a8k/extui/page/extapp/profession_test/P01PipetteGunVerification.java
  23. 0
      src/main/java/a8k/extui/page/extapp/profession_test/P02A8kTemperaturaVerfication.java

1
.gitignore

@ -38,3 +38,4 @@ tmp/
app.db
!/bak/app.db
/logs/*
appresource/static/app/

0
deply.bat → sh/deply.bat

0
mkexe.bat → sh/mkexe.bat

2
sh/sync_from_board.bat

@ -0,0 +1,2 @@
scp -r root@192.168.8.10://app/appresource/static/app .\appresource\static/
scp root@192.168.8.10://app/appresource/db/app.db .\appresource\db/

2
src/main/java/a8k/app/constant/AppConstant.java

@ -2,11 +2,13 @@ package a8k.app.constant;
public class AppConstant {
public static final int CONSUMABLE_NUM = 25;
public static final int TUBEHOLER_SIZE = 10;//试管架中可容纳的试管的数量
public static final int CONSUMABLE_COL_NUM = 5;
public static final int CONSUMABLE_ROW_NUM = 5;
public static final int TIP_NUM = 120;
public static final String APP_VERSION = "1.3.1";
public static final int CONSUMABLE_CHANNEL_NUM = 6;
}

18
src/main/java/a8k/app/controler/api/v1/engineer/ExperimentConsistencyTestingControler.java

@ -2,6 +2,7 @@ package a8k.app.controler.api.v1.engineer;
import a8k.app.engineer.service.qatest.ExperimentConsistencyTestingService;
import a8k.app.engineer.service.type.TubeHolderExConfig;
import a8k.app.type.exception.AppException;
import a8k.app.type.ui.ApiRet;
import io.swagger.v3.oas.annotations.Operation;
@ -24,9 +25,22 @@ public class ExperimentConsistencyTestingControler {
@Operation(summary = "开始测试(所有配置从应用获得)")
@PostMapping("/startTest")
public ApiRet<Void> startTest(Integer repeatTimes) throws AppException {
experimentConsistencyTestingService.startTest(repeatTimes);
public ApiRet<Void> startTest() throws AppException {
experimentConsistencyTestingService.startTest();
return ApiRet.success();
}
@Operation(summary = "提交配置")
@PostMapping("/submitConfig")
public ApiRet<Void> submitConfig(TubeHolderExConfig tubeHolderExConfig) {
experimentConsistencyTestingService.submitTubeExConfig(tubeHolderExConfig);
return ApiRet.success();
}
@Operation(summary = "获取配置")
@PostMapping("/getConfig")
public ApiRet<TubeHolderExConfig> getConfig() {
TubeHolderExConfig tubeHolderExConfig = experimentConsistencyTestingService.getTubeExConfig();
return ApiRet.success(tubeHolderExConfig);
}
}

205
src/main/java/a8k/app/engineer/service/qatest/ExperimentConsistencyTestingService.java

@ -1,12 +1,14 @@
package a8k.app.engineer.service.qatest;
import a8k.OS;
import a8k.app.constant.AppConstant;
import a8k.app.dao.type.combination.ProjBuildinInfo;
import a8k.app.dao.type.db.ProjExtInfoCard;
import a8k.app.dao.type.db.ReactionReport;
import a8k.app.engineer.service.executor.EngineerModeActionExecutor;
import a8k.app.engineer.service.state.EngineerModeStateMgrService;
import a8k.app.engineer.service.type.A8kCmdRunnable;
import a8k.app.engineer.service.type.TubeHolderExConfig;
import a8k.app.engineer.service.utils.BeforeDoEngineerActionChecker;
import a8k.app.hardware.driver.OptModuleDriver;
import a8k.app.hardware.type.A8kEcode;
@ -56,6 +58,7 @@ import java.util.Objects;
@Slf4j
@RequiredArgsConstructor
public class ExperimentConsistencyTestingService {
final private A8kTubeHolderType expectedTubeHolderType = A8kTubeHolderType.BulletTube1P5;
final private Integer expectedProjId = 1;
final private Integer takeSampleUl = 10;
@ -96,18 +99,39 @@ public class ExperimentConsistencyTestingService {
final private LiquidOperationCtrlService liquidOperationCtrlService;
final private HbotMoveExCtrlService hbotMoveExCtrlService;
private final OptModuleDriver optModuleDriver;
private final HbotMoveCtrlService hbotMoveCtrlService;
private TubeHolderSetting curTubeHolderSetting;
private TubeHolderExConfig tubeHolderExConfig = new TubeHolderExConfig();
synchronized public void submitTubeExConfig(TubeHolderExConfig tubeExTubeHolderExConfig) {
if (tubeExTubeHolderExConfig != null) {
this.tubeHolderExConfig = tubeExTubeHolderExConfig;
}
}
synchronized public TubeHolderExConfig getTubeExConfig() {
return tubeHolderExConfig;
}
public Integer getRepeatTimes(Integer tubeoff) {
if (tubeoff < 0 || tubeoff >= AppConstant.TUBEHOLER_SIZE) {
throw new IllegalArgumentException("tubeoff is out of range");
}
if (tubeoff >= tubeHolderExConfig.tubeExConfigs.size()) {
return 1;
}
return getTubeExConfig().tubeExConfigs.get(tubeoff).repeatTimes;
}
private TubeHolderSetting curTubeHolderSetting;
private Integer repeatTimes = 1;
/**
* 开始测试
* @param repeatTimes 重复次数
* @param
* @throws AppException
*/
public void startTest(Integer repeatTimes) throws AppException {
this.repeatTimes = repeatTimes;
public void startTest() throws AppException {
/*
* 检查当前是否有其他项目正在进行测试
*/
@ -174,15 +198,17 @@ public class ExperimentConsistencyTestingService {
try {
log.error("Catch exception: ", e);
UISender.txErrorPrompt(e);
docmd("HBOT复位", hbotMoveCtrlService::moveToZero);
docmd("推出试管架", tubeFeedingCtrlService::ejectTubeHolder);
//清空光学模组
optScanModuleStateMgrService.changeOptScanModuleStateToEmpty();
docmd("丢反应板", () -> optScanModuleCtrlService.dropPlate());
docmd("丢反应板", optScanModuleCtrlService::dropPlate);
//清空孵育盘
List<IncubationSubTank> all = incubationPlateStateMgrService.getAllNotFreeIncubationSubTanks();
for (IncubationSubTank notFreeTank : all) {
docmd("拉取反应板", () -> {optScanModuleCtrlService.pullPlate(notFreeTank.pos);});
docmd("丢反应板", () -> {optScanModuleCtrlService.dropPlate();});
docmd("拉取反应板", () -> optScanModuleCtrlService.pullPlate(notFreeTank.pos));
docmd("丢反应板", optScanModuleCtrlService::dropPlate);
}
incubationPlateStateMgrService.resetAll();
} catch (AppException ex) {
@ -228,7 +254,7 @@ public class ExperimentConsistencyTestingService {
hasTubeHolder = false;
docmd("入料", () -> {
hasTubeHolder = tubeFeedingCtrlService.enterTubeHolder();
}, () -> {hasTubeHolder = true;});
}, () -> hasTubeHolder = true);
if (!hasTubeHolder) {
throw AppException.of(A8kEcode.ERROR_OPERATION, "入料超时,未检测到试管架");
}
@ -250,56 +276,68 @@ public class ExperimentConsistencyTestingService {
verifyTubeHolderSettingAndTubeHolderScanResult(curTubeHolderSetting, scanResult);
//
for (int i = 0; i < curTubeHolderSetting.tubeSettings.length; i++) {
TubeSetting tubeSetting = curTubeHolderSetting.tubeSettings[i];
//构建试管架
// setTubeHolderDirect
for (int tubeoff = 0; tubeoff < curTubeHolderSetting.tubeSettings.length; tubeoff++) {
TubeSetting tubeSetting = curTubeHolderSetting.tubeSettings[tubeoff];
if (tubeSetting.projId.isEmpty()) {
continue;
}
Assert.isTrue(scanResult.tube[i].isTubeExist, String.format("位置[%d]未放入是试管", i + 1));
Assert.isTrue(scanResult.tube[tubeoff].isTubeExist, String.format("位置[%d]未放入是试管", tubeoff + 1));
//移动试管架到预处理位置
int finalTubeoff = tubeoff;
docmd("移动试管到处理位", () -> tubeFeedingCtrlService.moveTubeToPreProcessPos(finalTubeoff));
//尝试处理孵育完成的反应板
incubationPlateProcess(false);
//申请耗材
var consumableInfo = consumablesMgrService.reserveConsumable(expectedProjId);
if (consumableInfo == null) {
throw AppException.of(A8kEcode.CODEERROR, "耗材不足?"); //理论上开始阶段已经核对过了耗材数量此时应该不会不足
}
consumablesMgrService.useReserveConsumable(consumableInfo);
//构造项目信息
ProjBuildinInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(expectedProjId);
ProjExtInfoCard projExtInfoCard = projInfoMgrService.getProjExtInfoCard(consumableInfo.lotid);
ProjBriefInfo projBriefInfo = ProjInfoUtils.buildProjBrefInfo(projBuildinInfo);
Assert.notNull(projBuildinInfo, "projBuildInInfo is null");
Assert.notNull(projExtInfoCard, "projExtInfoCard is null");
//处理样本
for (int j = 0; j < repeatTimes; j++) {
Tube tube = new Tube(tubeoff);
tube.setIsHighTube(false);
tube.setIsEmergency(false);
tube.setBloodType(BloodType.WHOLE_BLOOD);
tube.setSampleBarcode(tubeSetting.sampleBarcode);
tube.setUserid(tubeSetting.userid);
tube.setProjInfo(ZList.of(projBriefInfo));
tube.setProjIds(ZList.of(expectedProjId));
String sampleId = tubeStateMgrService.newSample(tube);
tube.setSampleId(sampleId);
for (int j = 0; j < getRepeatTimes(tubeoff); j++) {
//处理试管
processTube(i, tubeSetting);
processTube(tube, tubeoff, consumableInfo, tubeSetting);
if (!tube.getErrors().isEmpty()) {
log.warn("样本异常,跳过当前样本");
break;
}
}
}
}
private void processTube(Integer offset, TubeSetting tubeSetting) throws AppException {
//移动试管架到预处理位置
docmd("移动试管到处理位", () -> {
tubeFeedingCtrlService.moveTubeToPreProcessPos(offset);
});
//尝试处理孵育完成的反应板
incubationPlateProcess();
incubationPlateProcess(true);
}
//申请耗材
var consumableInfo = consumablesMgrService.reserveConsumable(expectedProjId);
if (consumableInfo == null) {
throw AppException.of(A8kEcode.CODEERROR, "耗材不足?"); //理论上开始阶段已经核对过了耗材数量此时应该不会不足
}
consumablesMgrService.useReserveConsumable(consumableInfo);
private void processTube(Tube tube, Integer offset, ConsumablesMgrService.ConsumableInfo consumableInfo, TubeSetting tubeSetting) throws AppException {
//构造项目信息
ProjBuildinInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(expectedProjId);
ProjExtInfoCard projExtInfoCard = projInfoMgrService.getProjExtInfoCard(consumableInfo.lotid);
ProjBriefInfo projBriefInfo = ProjInfoUtils.buildProjBrefInfo(projBuildinInfo);
Assert.notNull(projBuildinInfo, "projBuildInInfo is null");
Assert.notNull(projExtInfoCard, "projExtInfoCard is null");
Tube tube = new Tube(offset);
tube.setIsHighTube(false);
tube.setIsEmergency(false);
tube.setBloodType(BloodType.WHOLE_BLOOD);
tube.setSampleBarcode(tubeSetting.sampleBarcode);
tube.setUserid(tubeSetting.userid);
tube.setProjInfo(ZList.of(projBriefInfo));
tube.setProjIds(ZList.of(expectedProjId));
String sampleId = tubeStateMgrService.newSample(tube);
tube.setSampleId(sampleId);
//拉取一个板夹到孵育盘
@ -315,9 +353,9 @@ public class ExperimentConsistencyTestingService {
// optScanModuleCtrlService.pullPlate(freeIncubationPos);
// optScanModuleCtrlService.dropPlate();
docmd("丢反应板", () -> optScanModuleCtrlService.dropPlate());
docmd("丢反应板", optScanModuleCtrlService::dropPlate);
docmd("拉取反应板", () -> optScanModuleCtrlService.pullPlate(freeIncubationPos));
docmd("丢反应板", () -> optScanModuleCtrlService.dropPlate());
docmd("丢反应板", optScanModuleCtrlService::dropPlate);
// plateBoxCtrlService.pushPlateQuick(consumableInfo.group, freeIncubationPos);
@ -328,38 +366,58 @@ public class ExperimentConsistencyTestingService {
docmd("样本处理", () -> {
liquidOperationCtrlService.setProjContext(projBuildinInfo, projExtInfoCard);
var preProcessPos = new PreReactionPos(ConsumableType.SmallBottleBuffer, consumableInfo.group, consumableInfo.pos);
//取tip
liquidOperationCtrlService.forceTakeTip();
//刺破缓冲液
hbotMoveExCtrlService.moveToLittleBufferPiercePos(consumableInfo.group, consumableInfo.pos);
//取样品
Assert.isTrue(expectedTubeHolderType.equals(A8kTubeHolderType.BulletTube1P5), "expectedTubeHolderType != BulletTube1P5");
hbotMoveExCtrlService.moveToSamplePosXY(A8kSamplePos.Bulltube1P5Pos);
liquidOperationCtrlService.takeSample(A8kSamplePos.Bulltube1P5Pos, preProcessPos, takeSampleUl);
//取混合液到预反应位
liquidOperationCtrlService.takePreReactionLiquidToReation(preProcessPos);
try {
liquidOperationCtrlService.setProjContext(projBuildinInfo, projExtInfoCard);
var preProcessPos = new PreReactionPos(ConsumableType.SmallBottleBuffer, consumableInfo.group, consumableInfo.pos);
//取tip
liquidOperationCtrlService.forceTakeTip();
//刺破缓冲液
hbotMoveExCtrlService.moveToLittleBufferPiercePos(consumableInfo.group, consumableInfo.pos);
//取样品
Assert.isTrue(expectedTubeHolderType.equals(A8kTubeHolderType.BulletTube1P5), "expectedTubeHolderType != BulletTube1P5");
hbotMoveExCtrlService.moveToSamplePosXY(A8kSamplePos.Bulltube1P5Pos);
liquidOperationCtrlService.takeSample(A8kSamplePos.Bulltube1P5Pos, preProcessPos, takeSampleUl);
//取混合液到预反应位
liquidOperationCtrlService.takePreReactionLiquidToReation(preProcessPos);
incubationPlateStateMgrService.startIncubating(freeIncubationPos, System.currentTimeMillis(), projBuildinInfo.reactionPlateIncubationTimeMin * 60);
} catch (AppException e) {
if (e.getError().eq(A8kEcode.APPE_TAKE_SAMPLE_FAIL)) {
hbotMoveExCtrlService.moveQuickToZero();
tube.setErrors(ZList.of(e.getError()));
incubationPlateStateMgrService.resetIncubatorPos(freeIncubationPos);
//丢反应板
optScanModuleCtrlService.forceDropPlate(freeIncubationPos);
UISender.txErrorMsg(log, e, "取样失败");
} else {
throw e;
}
}
}, () -> {
incubationPlateStateMgrService.startIncubating(freeIncubationPos, System.currentTimeMillis(), projBuildinInfo.reactionPlateIncubationTimeMin * 60);
});
{//开始孵育
incubationPlateStateMgrService.startIncubating(freeIncubationPos, System.currentTimeMillis(), projBuildinInfo.reactionPlateIncubationTimeMin * 60);
}
}
private void incubationPlateProcess() throws AppException {
private void incubationPlateProcess(Boolean waittingForAll) throws AppException {
do {
IncubationSubTank tankPos = incubationPlateStateMgrService.getOneExpiredPlate();
if (incubationPlateStateMgrService.isHasEnoughIncubationIDLEPos(1) && tankPos == null) {
break;
if (!waittingForAll) {
if (incubationPlateStateMgrService.isHasEnoughIncubationIDLEPos(1) && tankPos == null) {
break;
}
} else {
if (incubationPlateStateMgrService.isAllIncubationSubTanksFree()) {
break;
}
}
//拉取反应板到光学模组
{
//执行动作
if (tankPos != null) {
//拉取反应板到光学模组
docmd("拉取反应板到光学模块", () -> {optScanModuleCtrlService.pullPlate(tankPos.getPos());});
//设置光学模组状态
@ -367,21 +425,22 @@ public class ExperimentConsistencyTestingService {
optScanModuleStateMgrService.syncProjInfo(tankPos.projBuildinInfo, tankPos.projExtInfoCard);
//复位孵育盘状态
incubationPlateStateMgrService.resetIncubatorPos(tankPos.getPos());
}
//光学扫描
{
//
//光学扫描
//
//光学扫描
optScanModuleStateMgrService.changeOptScanModuleStateToScanning();
doOptScan();
//丢板
docmd("丢弃反应板", () -> {optScanModuleCtrlService.dropPlate();});
docmd("丢弃反应板", optScanModuleCtrlService::dropPlate);
optScanModuleStateMgrService.changeOptScanModuleStateToEmpty();
}
actionExecutor.sleep(100);
} while (true);
}
@ -420,7 +479,7 @@ public class ExperimentConsistencyTestingService {
private void verifyTubeHolderSettingAndTubeHolderScanResult(TubeHolderSetting tubeHolderSetting, TubeFeedingCtrlService.TubeHolderScanResult scanResult) throws AppException {
A8kTubeHolderType tubeHolderType = A8kTubeHolderType.of(scanResult.tubeHolderType);
if (expectedTubeHolderType.equals(tubeHolderType)) {
if (!expectedTubeHolderType.equals(tubeHolderType)) {
throw AppException.of(A8kEcode.APPE_TUBE_HOLDER_TYPE_IS_NOT_SUPPORT, "请使用子弹头1.5ml试管架");
}

12
src/main/java/a8k/app/engineer/service/qatest/QATemperatureCtrlTestService.java

@ -3,6 +3,7 @@ package a8k.app.engineer.service.qatest;
import a8k.app.service.background.SensorDataUpdateService;
import a8k.app.service.background.TemperatureCtrlService;
import a8k.app.service.setting.AppSettingsMgrService;
import a8k.app.service.statemgr.GStateMgrService;
import a8k.app.type.TemperatureRecordPoint;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -22,12 +23,13 @@ public class QATemperatureCtrlTestService {
private final TemperatureCtrlService temperatureCtrlService;
private final AppSettingsMgrService appSettingsMgrService;
private final SensorDataUpdateService sensorDataUpdateService;
private final GStateMgrService gStateMgrService;
/**
* 修改温度控制目标温度
*/
synchronized public void setTargetVal(Integer targetIncubatorBoxTemperature, Integer targetPlatesBoxTemperature) {
synchronized public void setTargetVal(Integer targetIncubatorBoxTemperature, Integer targetPlatesBoxTemperature) {
log.info("changeTemperatureCtrlTargetVal: targetIncubatorBoxTemperature = {}, targetPlatesBoxTemperature = {}", targetIncubatorBoxTemperature, targetPlatesBoxTemperature);
appSettingsMgrService.setIncubateBoxTemperature(targetIncubatorBoxTemperature);
appSettingsMgrService.setPlateBoxTemperature(targetPlatesBoxTemperature);
@ -49,6 +51,14 @@ public class QATemperatureCtrlTestService {
return temperatureCtrlService.getTargetPlatesBoxTemperatureSetVal();
}
synchronized public Double getIncubateBoxTemp() {
return sensorDataUpdateService.getIncubateBoxTemperature();
}
synchronized public Double getPlateBoxTemp() {
return sensorDataUpdateService.getPlateBoxTemperature();
}
/**
* 获取孵育盘温度曲线
* @return curve

5
src/main/java/a8k/app/engineer/service/type/TubeExConfig.java

@ -0,0 +1,5 @@
package a8k.app.engineer.service.type;
public class TubeExConfig {
public Integer repeatTimes = 1;
}

16
src/main/java/a8k/app/engineer/service/type/TubeHolderExConfig.java

@ -0,0 +1,16 @@
package a8k.app.engineer.service.type;
import a8k.app.constant.AppConstant;
import java.util.ArrayList;
import java.util.List;
public class TubeHolderExConfig {
public List<TubeExConfig> tubeExConfigs = new ArrayList<>();
public TubeHolderExConfig() {
for (int i = 0; i < AppConstant.TUBEHOLER_SIZE; i++) {
tubeExConfigs.add(new TubeExConfig());
}
}
}

2
src/main/java/a8k/app/hardware/driver/CodeScanerDriver.java

@ -27,7 +27,7 @@ public class CodeScanerDriver {
}
public String pipetteModCodeScannerScanCode() throws AppException {
return pipetteModCodeScannerScanCode(500);
return pipetteModCodeScannerScanCode(300);
}
public void pipetteModCodeScannerStartScan() throws AppException {

19
src/main/java/a8k/app/service/background/SensorDataUpdateService.java

@ -24,7 +24,6 @@ import java.util.List;
public class SensorDataUpdateService {
private final GStateMgrService gStateMgrService;
private final TemperatureControlDriver temperatureControlDriver;
private final OptScanModuleStateMgrService optScanModuleStateMgrService;
@ -39,6 +38,9 @@ public class SensorDataUpdateService {
List<TemperatureRecordPoint> incubateBoxTemperatureCurve = new ArrayList<>();
List<TemperatureRecordPoint> plateBoxTemperatureCurve = new ArrayList<>();
Double incubateBoxTemperature = 0.0;
Double plateBoxTemperature = 0.0;
public void setErrorFlag(AppException e) {
if (!errorFlag) {
appEventBusService.pushAppExceptionEvent(e);
@ -56,11 +58,21 @@ public class SensorDataUpdateService {
error = null;
}
synchronized public Double getIncubateBoxTemperature() {
return incubateBoxTemperature;
}
synchronized public Double getPlateBoxTemperature() {
return plateBoxTemperature;
}
synchronized private void addIncubateBoxTemperatureCurve(Double temperature) {
TemperatureRecordPoint point = new TemperatureRecordPoint();
point.tp = System.currentTimeMillis();
point.val = temperature;
incubateBoxTemperatureCurve.add(point);
incubateBoxTemperature = temperature;
if (incubateBoxTemperatureCurve.size() > 2000) {
incubateBoxTemperatureCurve.remove(0);
}
@ -68,8 +80,9 @@ public class SensorDataUpdateService {
synchronized private void addPlateBoxTemperatureCurve(Double temperature) {
TemperatureRecordPoint point = new TemperatureRecordPoint();
point.tp = System.currentTimeMillis();
point.val = temperature;
point.tp = System.currentTimeMillis();
point.val = temperature;
plateBoxTemperature = temperature;
plateBoxTemperatureCurve.add(point);
if (plateBoxTemperatureCurve.size() > 2000) {
plateBoxTemperatureCurve.remove(0);

1
src/main/java/a8k/app/service/background/TemperatureCtrlService.java

@ -119,6 +119,7 @@ public class TemperatureCtrlService {
}
private void startCtrlTemperature(Integer incubatorTemperature, Integer platesBoxTemperature) throws AppException {
log.info("start control incubatorTemperature: {},platesBoxTemperature: {}", incubatorTemperature, platesBoxTemperature);
temperatureControlDriver.startCtrlTemperature(incubatorTemperature.doubleValue(), platesBoxTemperature.doubleValue());

12
src/main/java/a8k/app/service/lowerctrl/HbotMoveExCtrlService.java

@ -56,6 +56,12 @@ public class HbotMoveExCtrlService {
Pos3d tipPos = hbotConsumableExParamMgr.getTipPos(tipGroupPos, index);
hbotMoveCtrlService.hbotMoveTo(tipPos);
if (!pipetteCtrlDriver.isHasTip()) {
//TODO:单片机支持移动以mm为单位的距离的方法
pipetteCtrlDriver.zMotorMoveByBlock(-100);
pipetteCtrlDriver.pipetteInitDeviceBlock();
}
pipetteCtrlDriver.zMotorMoveToZeroPointQuickBlock();
}
@ -215,7 +221,6 @@ public class HbotMoveExCtrlService {
}
// public void moveToProbeSubstanceSamplePos(ConsumableGroup group, Integer off) throws AppException {
// hbotBaseMoveExDriver.hbotMoveTo(hbotConsumableParamMgr.getProbeSubstanceSamplePos(group, off));
// }
@ -247,14 +252,13 @@ public class HbotMoveExCtrlService {
}
public void moveToSampleStartPos(A8kSamplePos pos) throws AppException {
hbotMoveCtrlService.hbotMoveTo(hbotSamplePosParamMgr.getSampleStartPos(pos));
}
public void moveToSampleEndPos(A8kSamplePos pos) throws AppException {
Pos3d startpos = hbotSamplePosParamMgr.getSampleStartPos(pos);
Integer endpos = hbotSamplePosParamMgr.getSampleEndPos(pos);
Pos3d startpos = hbotSamplePosParamMgr.getSampleStartPos(pos);
Integer endpos = hbotSamplePosParamMgr.getSampleEndPos(pos);
startpos.z = endpos;
hbotMoveCtrlService.hbotMoveTo(startpos);
}

3
src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrlService.java

@ -110,6 +110,7 @@ public class LiquidOperationCtrlService {
}
while (true) {
hbotMoveExCtrlService.takeTip(consumablesMgrService.takeNextTipPos());
if (gstate.isInMode(DeviceRunMode.RunOnlyMode)) {
break;
}
@ -339,7 +340,7 @@ public class LiquidOperationCtrlService {
private void ldd(Integer startpos, Integer maxpos, Integer p_threshold) throws AppException {
log.info("lld: startpos={}, maxpos={}, p_threshold={}", startpos, maxpos, p_threshold);
pipetteCtrlDriver.zMotorMoveToBlock(startpos);
//
pipetteCtrlDriver.liquidOperationClearParams();

6
src/main/java/a8k/app/service/lowerctrl/OptScanModuleCtrlService.java

@ -97,6 +97,12 @@ public class OptScanModuleCtrlService {
stepMotorCtrlDriver.stepMotorEasyMoveToBlock(StepMotorMId.OptModScannerM, optModuleParamsMgr.getOptScanerScandbyPos());
}
public void forceDropPlate(IncubatorPos turntablePosIndex) throws AppException {
dropPlate();
pullPlate(turntablePosIndex);
dropPlate();
}
public Integer[] startOptScan(A8kOptType optType, Integer lasterGain, Integer rawScanGain) throws AppException {
Integer forwardScanPos = optModuleExtParamsMgr.getOptScanStartPos(optType);

9
src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgrService.java

@ -214,6 +214,15 @@ public class IncubationPlateStateMgrService {
return list;
}
synchronized public Boolean isAllIncubationSubTanksFree() {
for (IncubationSubTank subtank : incubationPlate.subtanks) {
if (!subtank.state.equals(IncubationSubTankState.EMPTY)) {
return false;
}
}
return true;
}
@Scheduled(fixedDelay = 500)
synchronized public void updateRemainTime() {

5
src/main/java/a8k/app/service/statemgr/TubeStateMgrService.java

@ -176,6 +176,11 @@ public class TubeStateMgrService {
return null;
}
public synchronized void setTubeHolderDirect(TubeHolder tubeHolder) throws AppException {
this.tubeHolder = tubeHolder;
}
//
// 急诊试管状态管理
//

6
src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java

@ -4,7 +4,10 @@ import a8k.app.utils.ZList;
import a8k.extui.page.debug.*;
import a8k.extui.page.driver.*;
import a8k.extui.page.extapp.*;
import a8k.extui.page.extapp.P02A8kTemperaturaVerfication;
import a8k.extui.page.extapp.debug_assistant.IDCardDataGeneratorPage;
import a8k.extui.page.extapp.profession_test.ExperimentConsistencyTestingPage;
import a8k.extui.page.extapp.profession_test.P01PipetteGunVerification;
import a8k.extui.page.extsetting.db.A8kSubModuleParameterInitDebugPage;
import a8k.extui.page.extsetting.db.DeviceActionParameterSettingPage;
import a8k.extui.page.extsetting.db.ProjInfoMgrPage;
@ -140,7 +143,8 @@ public class ExtApiPageGroupCfgMgr {
)),
new Menu("过检专用", ZList.of(
new Menu(P01PipetteGunVerification.class, "移液枪验证"),
new Menu(P02A8kTemperaturaVerfication.class, "温度控制验证")
new Menu(P02A8kTemperaturaVerfication.class, "温度控制验证"),
new Menu(ExperimentConsistencyTestingPage.class, "一致性测试")
)),
new Menu("坐标测量", ZList.of(
new Menu(HbotPosMeasurePage.class, "HBOT测量(电控)"),

228
src/main/java/a8k/extui/page/extapp/P01PipetteGunVerification.java

@ -1,228 +0,0 @@
package a8k.extui.page.extapp;
import a8k.app.constant.AppConstant;
import a8k.app.service.lowerctrl.LiquidOperationCtrlService;
import a8k.app.service.param.exparam.HbotConsumableExParamMgr;
import a8k.app.service.param.hbotpos.HbotTipPosMgr;
import a8k.app.service.param.pipetteparam.PipetteGunExParamMgr;
import a8k.extui.mgr.ExtApiPageMgr;
import a8k.extui.type.ExtUIPageCfg;
import a8k.app.hardware.type.LldType;
import a8k.app.service.lowerctrl.HbotMoveExCtrlService;
import a8k.app.hardware.driver.PipetteCtrlDriver;
import a8k.app.hardware.type.PipetteRegIndex;
import a8k.app.service.lowerctrl.HbotMoveCtrlService;
import a8k.app.type.a8k.ConsumableGroup;
import a8k.app.type.a8k.Pos3d;
import a8k.app.type.exception.AppException;
import a8k.app.type.a8k.pos.TipPos;
import a8k.app.type.a8k.pos.TipGroupPos;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class P01PipetteGunVerification {
@Resource
HbotTipPosMgr hbotTipPosMgr;
@Resource
PipetteCtrlDriver pipetteCtrlDriver;
@Resource
HbotMoveCtrlService hbotMoveCtrlService;
@Resource
HbotMoveExCtrlService hbotMoveExCtrlService;
@Resource
HbotConsumableExParamMgr hbotConsumableExParamMgr;
@Resource
PipetteGunExParamMgr pipetteGunExParamMgr;
@Resource
ExtApiPageMgr extApiPageMgr;
Integer tipNum = 0;
Integer liquidPos = null;
Boolean stopFlag = false;
@PostConstruct
void init() {
ExtUIPageCfg page = new ExtUIPageCfg(this);
page.newGroup("基础");
page.addFunction("测试准备", this::initTestMode);
page.addFunction("停止测试", this::stopTest);
page.addFunction("设置校准系数", this::calibration)
.setParamVal("coefficientA", () -> pipetteGunExParamMgr.getCoefficientA())
.setParamVal("coefficientB", () -> pipetteGunExParamMgr.getCoefficientB());
page.newGroup("测试0");
page.addFunction("取一次10ul", this::aspirate10ul);
page.addFunction("取一次75ul", this::aspirate75ul);
page.newGroup("测试1");
page.addFunction("取一次5ul", this::aspirate5ul);
page.addFunction("取一次30ul", this::aspirate30ul);
page.addFunction("取一次50ul", this::aspirate50ul);
page.addFunction("停止测试", this::stopTest);
extApiPageMgr.addPage(page);
}
public void pipetteGunInit() throws AppException {
pipetteCtrlDriver.pipetteInitDeviceBlock();
}
public void initTestMode() throws AppException {
pipetteCtrlDriver.zMotorEnable(1);
hbotMoveCtrlService.enable(1);
pipetteCtrlDriver.zMotorMoveZeroBlock();
hbotMoveCtrlService.moveToZero();
hbotMoveCtrlService.hbotMoveTo(hbotTipPosMgr.getDropTipPos());
pipetteGunInit();
hbotMoveCtrlService.hbotMoveTo(new Pos3d(0, 0, 0));
tipNum = AppConstant.TIP_NUM;
}
public void stopTest() throws AppException {
pipetteCtrlDriver.zMotorEnable(0);
hbotMoveCtrlService.enable(0);
}
public void calibration(Double coefficientA, Double coefficientB) {
pipetteGunExParamMgr.setVolumeCalibrationCoefficient(coefficientA, coefficientB);
}
Boolean takeOneTip() throws AppException {
hbotMoveCtrlService.hbotMoveTo(hbotTipPosMgr.getDropTipPos());
pipetteGunInit();
TipPos tipPos = new TipPos();
tipPos.group = TipGroupPos.TipG1;
if (tipNum == 0) {
tipNum = 120;
}
tipPos.index = AppConstant.TIP_NUM - tipNum;
tipNum--;
log.info(" 取TIP {}", tipPos);
return hbotMoveExCtrlService.takeTipNoCheck(tipPos.group, tipPos.index);
}
void takeTip() throws AppException {
while (!pipetteCtrlDriver.isHasTip()) {
if (takeOneTip()) {
break;
}
}
}
public void pumpMoveTo(Integer pumpvmax, Double ul) throws AppException {
pipetteCtrlDriver.liquidOperationClearParams();
pipetteCtrlDriver.liquidOperationSetGunRunParams(14, 14, 0, 1000, pumpvmax);
pipetteCtrlDriver.liquidOperationFreshParams();
pipetteCtrlDriver.pipettePumpMoveTo(ul);
}
public Integer lld() throws AppException {
liquidPos = 0;
hbotMoveExCtrlService.moveToLargeBSSamplePosXY(ConsumableGroup.CG1);
pipetteCtrlDriver.zMotorMoveToBlock(0);
pumpMoveTo(8000, 0.0);
pumpMoveTo(300, 100.0);
pumpMoveTo(8000, 0.0);
pumpMoveTo(300, 50.0);
Pos3d toPos = hbotConsumableExParamMgr.getLargeBufferSamplePos(ConsumableGroup.CG1);
Pos3d maxPos = hbotConsumableExParamMgr.getLargeBufferSamplePosEnd(ConsumableGroup.CG1);
pipetteCtrlDriver.zMotorMoveToBlock(toPos.z);
pipetteCtrlDriver.liquidOperationClearParams();
pipetteCtrlDriver.liquidOperationSetGunRunParams(14, 14, 0, 900, 30);
pipetteCtrlDriver.liquidOperationSetZMotorRunParams(toPos.z, maxPos.z, 60 * 80 / LiquidOperationCtrlService.helicalPitch);
pipetteCtrlDriver.liquidOperationFreshParams();
pipetteCtrlDriver.pipetteLld(LldType.kplld, 0, 30);
if (pipetteCtrlDriver.lldIsDetectLiquid()) {
liquidPos = pipetteCtrlDriver.getReg(PipetteRegIndex.kreg_pipette_zm_pos);
}
pipetteCtrlDriver.zMotorMoveToBlock(0);
pumpMoveTo(8000, 0.0);
return liquidPos;
}
public void takeLiquid(Double ul) throws AppException {
hbotMoveExCtrlService.moveToLargeBSSamplePosXY(ConsumableGroup.CG1);
pipetteCtrlDriver.zMotorMoveToBlock(0);
pumpMoveTo(8000, 0.0);
pumpMoveTo(8000, 150.0);
pipetteCtrlDriver.zMotorMoveToBlock(liquidPos);
pipetteCtrlDriver.liquidOperationClearParams();
pipetteCtrlDriver.liquidOperationSetGunRunParams(14, 14, 0, 900, 100);
pipetteCtrlDriver.liquidOperationSetZMotorRunParams(0, 300, 10 * 80 / LiquidOperationCtrlService.helicalPitch);
pipetteCtrlDriver.liquidOperationFreshParams();
ul = pipetteGunExParamMgr.calibrateVolume(ul);
log.info("取液体 {}", ul);
pipetteCtrlDriver.pipetteAspirate(ul);
pipetteCtrlDriver.zMotorMoveToBlock(0);
}
public void distributeLiquid() throws AppException {
hbotMoveExCtrlService.moveToLargeBSSamplePosXY(ConsumableGroup.CG6);
pipetteCtrlDriver.zMotorMoveToBlock(50);
pumpMoveTo(8000, 0.0);
pipetteCtrlDriver.zMotorMoveToBlock(0);
}
public void resetPos() throws AppException {
hbotMoveExCtrlService.moveToLargeBSSamplePosXY(ConsumableGroup.CG2);
}
public void aspirate10ul() throws AppException {
takeTip();
lld();
if (liquidPos == 0)
throw AppException.ofAECodeError("未检测到液体");
takeLiquid(10.0);
distributeLiquid();
resetPos();
}
public void aspirate75ul() throws AppException {
takeTip();
lld();
if (liquidPos == 0)
throw AppException.ofAECodeError("未检测到液体");
takeLiquid(75.0);
distributeLiquid();
resetPos();
}
public void aspirate5ul() throws AppException {
takeTip();
lld();
if (liquidPos == 0)
throw AppException.ofAECodeError("未检测到液体");
takeLiquid(5.0);
distributeLiquid();
resetPos();
}
public void aspirate30ul() throws AppException {
takeTip();
lld();
if (liquidPos == 0)
throw AppException.ofAECodeError("未检测到液体");
takeLiquid(30.0);
distributeLiquid();
resetPos();
}
public void aspirate50ul() throws AppException {
takeTip();
lld();
if (liquidPos == 0)
throw AppException.ofAECodeError("未检测到液体");
takeLiquid(50.0);
distributeLiquid();
resetPos();
}
}

97
src/main/java/a8k/extui/page/extapp/profession_test/ExperimentConsistencyTestingPage.java

@ -0,0 +1,97 @@
package a8k.extui.page.extapp.profession_test;
import a8k.app.engineer.service.qatest.ExperimentConsistencyTestingService;
import a8k.app.engineer.service.type.TubeExConfig;
import a8k.app.engineer.service.type.TubeHolderExConfig;
import a8k.app.type.exception.AppException;
import a8k.extui.mgr.ExtApiPageMgr;
import a8k.extui.type.ExtApiStatu;
import a8k.extui.type.ExtUIPageCfg;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@RequiredArgsConstructor
public class ExperimentConsistencyTestingPage {
private final ExtApiPageMgr extApiPageMgr;
private final ExperimentConsistencyTestingService experimentConsistencyTestingService;
@ExtApiStatu(name = "", group = "试管1", order = 1)
public TubeExConfig getTubeExConfig1() {
return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(0);
}
@ExtApiStatu(name = "", group = "试管2", order = 2)
public TubeExConfig getTubeExConfig2() {
return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(1);
}
@ExtApiStatu(name = "", group = "试管3", order = 3)
public TubeExConfig getTubeExConfig3() {
return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(2);
}
@ExtApiStatu(name = "", group = "试管4", order = 4)
public TubeExConfig getTubeExConfig4() {
return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(3);
}
@ExtApiStatu(name = "", group = "试管5", order = 5)
public TubeExConfig getTubeExConfig5() {
return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(4);
}
@ExtApiStatu(name = "", group = "试管6", order = 6)
public TubeExConfig getTubeExConfig6() {
return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(5);
}
@ExtApiStatu(name = "", group = "试管7", order = 7)
public TubeExConfig getTubeExConfig7() {
return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(6);
}
@ExtApiStatu(name = "", group = "试管8", order = 8)
public TubeExConfig getTubeExConfig8() {
return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(7);
}
@ExtApiStatu(name = "", group = "试管9", order = 9)
public TubeExConfig getTubeExConfig9() {
return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(8);
}
@ExtApiStatu(name = "", group = "试管10", order = 10)
public TubeExConfig getTubeExConfig10() {
return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(9);
}
@PostConstruct
void init() {
ExtUIPageCfg page = new ExtUIPageCfg(this);
page.newGroup("配置");
page.addFunction("设置配置", this::setTubeRepeatTime).setParamVal("tubeOff", () -> 1).setParamVal("repeatTimes", () -> 1);
page.newGroup("基础");
page.addFunction("开始测试", this::startTest);
extApiPageMgr.addPage(page);
}
public void startTest() throws AppException {
experimentConsistencyTestingService.startTest();
}
public void setTubeRepeatTime(Integer tubeOff, Integer repeatTimes) {
tubeOff = tubeOff + 1;
TubeHolderExConfig tubeHolderExConfig = experimentConsistencyTestingService.getTubeExConfig();
tubeHolderExConfig.tubeExConfigs.get(tubeOff).repeatTimes = repeatTimes;
log.info("setTubeRepeatTime: tubeOff = {}, repeatTimes = {}", tubeOff, repeatTimes);
}
}

80
src/main/java/a8k/extui/page/extapp/profession_test/P01PipetteGunVerification.java

@ -0,0 +1,80 @@
package a8k.extui.page.extapp.profession_test;
import a8k.app.constant.AppConstant;
import a8k.app.engineer.service.qatest.LiquidAbsorptionAndDistributionTestService;
import a8k.app.service.lowerctrl.LiquidOperationCtrlService;
import a8k.app.service.param.exparam.HbotConsumableExParamMgr;
import a8k.app.service.param.hbotpos.HbotTipPosMgr;
import a8k.app.service.param.pipetteparam.PipetteGunExParamMgr;
import a8k.extui.mgr.ExtApiPageMgr;
import a8k.extui.type.ExtUIPageCfg;
import a8k.app.hardware.type.LldType;
import a8k.app.service.lowerctrl.HbotMoveExCtrlService;
import a8k.app.hardware.driver.PipetteCtrlDriver;
import a8k.app.hardware.type.PipetteRegIndex;
import a8k.app.service.lowerctrl.HbotMoveCtrlService;
import a8k.app.type.a8k.ConsumableGroup;
import a8k.app.type.a8k.Pos3d;
import a8k.app.type.exception.AppException;
import a8k.app.type.a8k.pos.TipPos;
import a8k.app.type.a8k.pos.TipGroupPos;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@RequiredArgsConstructor
public class P01PipetteGunVerification {
private final PipetteGunExParamMgr pipetteGunExParamMgr;
private final ExtApiPageMgr extApiPageMgr;
private final LiquidAbsorptionAndDistributionTestService liquidAbsorptionAndDistributionTestService;
@PostConstruct
void init() {
ExtUIPageCfg page = new ExtUIPageCfg(this);
page.newGroup("基础");
page.addFunction("设置校准系数", this::setCalibrationParam)
.setParamVal("coefficientA", pipetteGunExParamMgr::getCoefficientA)
.setParamVal("coefficientB", pipetteGunExParamMgr::getCoefficientB);
page.newGroup("测试0");
page.addFunction("取一次10ul", this::aspirate10ul);
page.addFunction("取一次75ul", this::aspirate75ul);
page.newGroup("测试1");
page.addFunction("取一次5ul", this::aspirate5ul);
page.addFunction("取一次30ul", this::aspirate30ul);
page.addFunction("取一次50ul", this::aspirate50ul);
extApiPageMgr.addPage(page);
}
public void setCalibrationParam(Double coefficientA, Double coefficientB) {
pipetteGunExParamMgr.setVolumeCalibrationCoefficient(coefficientA, coefficientB);
}
public void aspirate10ul() throws AppException {
liquidAbsorptionAndDistributionTestService.absorbAndDistribute(10);
}
public void aspirate75ul() throws AppException {
liquidAbsorptionAndDistributionTestService.absorbAndDistribute(75);
}
public void aspirate5ul() throws AppException {
liquidAbsorptionAndDistributionTestService.absorbAndDistribute(5);
}
public void aspirate30ul() throws AppException {
liquidAbsorptionAndDistributionTestService.absorbAndDistribute(30);
}
public void aspirate50ul() throws AppException {
liquidAbsorptionAndDistributionTestService.absorbAndDistribute(50);
}
}

0
src/main/java/a8k/extui/page/extapp/P02A8kTemperaturaVerfication.java → src/main/java/a8k/extui/page/extapp/profession_test/P02A8kTemperaturaVerfication.java

Loading…
Cancel
Save