Browse Source

优化泵机取样精度,修正websocketServiceBUG,添加新的广播包

tags/v0
zhaohe 8 months ago
parent
commit
557142cc1a
  1. BIN
      appresource/db/app.db
  2. 10
      doc/a8k移液泵优化方案.md
  3. 26
      src/main/java/a8k/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java
  4. 2
      src/main/java/a8k/hardware/A8kModParamInitializer.java
  5. 12
      src/main/java/a8k/hardware/type/a8kcanprotocol/CmdId.java
  6. 22
      src/main/java/a8k/hardware/type/regindex/RegIndex.java
  7. 20
      src/main/java/a8k/service/app/appctrl/mainflowctrl/action/SEQ5_PROCESS.java
  8. 7
      src/main/java/a8k/service/app/devicectrl/ctrlservice/HbotCtrlService.java
  9. 64
      src/main/java/a8k/service/app/devicectrl/driver/PipetteCtrlDriver.java
  10. 22
      src/main/java/a8k/service/app/devicectrl/driver/type/PipetteRegIndex.java
  11. 42
      src/main/java/a8k/service/app/devicectrl/exdriver/PipetteCtrlExDriver.java
  12. 178
      src/main/java/a8k/service/app/devicectrl/param/calibration/PipetteGunLLDParamCalibration.java
  13. 140
      src/main/java/a8k/service/app/devicectrl/param/calibration/PipetteGunLLFParamCalibration.java
  14. 19
      src/main/java/a8k/service/app/devicectrl/param/param_mgr/PipetteGunExParamMgr.java
  15. 116
      src/main/java/a8k/service/app/devicectrl/script/PipeGunCtrlScripter.java
  16. 275
      src/main/java/a8k/service/verification/PipetteGunVerificationV2.java

BIN
appresource/db/app.db

10
doc/a8k移液泵优化方案.md

@ -8,4 +8,14 @@ TODO:
lld启动时,先不移动步进电机,先读取压力值,如果压力值大于记录值,说明有液体
否则,移动步进电机,直到压力值大于记录值
```
```angular2html
1. 将液面探测做到最佳
```

26
src/main/java/a8k/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java

@ -1,25 +1,28 @@
package a8k.controler.api.v1.app.ws;
import a8k.service.app.appstate.GStateService;
import a8k.service.app.appstate.statemgr.DeviceWorkStateMgrService;
import a8k.service.app.appstate.statemgr.IncubationPlateStateMgrService;
import a8k.service.app.appstate.statemgr.OptScanModuleStateMgrService;
import a8k.service.app.appstate.statemgr.TubeStateMgrService;
import a8k.service.app.appstate.statemgr.*;
import a8k.service.bases.FrontEndEventRouter;
import a8k.utils.ZJsonHelper;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import jakarta.websocket.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
@Component
@EnableScheduling
public class AppWebSocketEndpointMgr {
private static final Logger log = LoggerFactory.getLogger(AppWebSocketEndpointMgr.class);
public static class Report {
public String messageType = "Report";
public String dataType;
@ -45,6 +48,8 @@ public class AppWebSocketEndpointMgr {
IncubationPlateStateMgrService incubationPlateStateMgrService;
@Resource
OptScanModuleStateMgrService optScanModuleStateMgrService;
@Resource
ConsumablesMgrService consumablesMgrService;
List<Session> stateWebsocketSessions = new ArrayList<>();
@ -70,13 +75,21 @@ public class AppWebSocketEndpointMgr {
synchronized void broadcastState(String message) {
for (Session session : stateWebsocketSessions) {
session.getAsyncRemote().sendText(message);
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
log.warn("broadcastState: session.getBasicRemote().sendText() failed: {}", e.getMessage());
}
}
}
synchronized void broadcastEvent(String message) {
for (Session session : eventWebsocketSessions) {
session.getAsyncRemote().sendText(message);
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
log.warn("broadcastEvent: session.getBasicRemote().sendText() failed: {}", e.getMessage());
}
}
}
@ -115,6 +128,7 @@ public class AppWebSocketEndpointMgr {
reportState("OptScanModuleState", optScanModuleStateMgrService.getOptScanModule());
reportState("EmergencyPosState", tubeStateMgrService.getEmergencyPosRunState());
reportState("SensorState", gstate.getSensorState());
reportState("ConsumablesStateService", consumablesMgrService.getState());
}

2
src/main/java/a8k/hardware/A8kModParamInitializer.java

@ -113,7 +113,7 @@ public class A8kModParamInitializer {
pipetteCtrlDriver.setReg(PipetteRegIndex.kreg_pipette_zm_default_velocity, 1500);
pipetteCtrlDriver.setReg(PipetteRegIndex.kreg_pipette_lld_motor_vel_rpm, 100);//80的时候刚好和液面齐平
// pipetteCtrlDriver.setReg(PipetteRegIndex.kreg_pipette_lld_motor_vel_rpm, 100);//80的时候刚好和液面齐平
canBus.moduleSetReg(MId.HbotM, RegIndex.kreg_xyrobot_look_zero_edge_speed, 10);

12
src/main/java/a8k/hardware/type/a8kcanprotocol/CmdId.java

@ -116,6 +116,18 @@ public enum CmdId {
pipette_zmotor_move_by(0x7405, "pipette_zmotor_move_by"),
pipette_zmotor_move_to(0x7406, "pipette_zmotor_move_to"),
// virtual int32_t liquid_operation_clear_params(); 0x7450
// virtual int32_t liquid_operation_set_gun_runparams(int32_t acc, int32_t dec, int32_t vstart, int32_t vstop, int32_t vmax); 0x7451
// virtual int32_t liquid_operation_set_zmotor_runparams(int32_t posmin, int32_t posmax, int32_t vmax); 0x7452
// virtual int32_t liquid_operation_enable_lld_record(); 0x7453
// virtual int32_t liquid_operation_fresh_params(); 0x7454
liquid_operation_clear_params(0x7450, "liquid_operation_clear_params"),
liquid_operation_set_gun_runparams(0x7451, "liquid_operation_set_gun_runparams"),
liquid_operation_set_zmotor_runparams(0x7452, "liquid_operation_set_zmotor_runparams"),
liquid_operation_enable_lld_record(0x7453, "liquid_operation_enable_lld_record"),
liquid_operation_fresh_params(0x7454, "liquid_operation_fresh_params"),
pipette_init_device(0x7501, "pipette_init_device"),
pipette_put_tip(0x7502, "pipette_put_tip"),
pipette_pump_move_to(0x7503, "pipette_pump_move_to"),

22
src/main/java/a8k/hardware/type/regindex/RegIndex.java

@ -40,17 +40,17 @@ public enum RegIndex {
kreg_pipette_tip_state(4002, false), // 移动液枪tip状态
// kreg_pipette_limit_ul(4051), //
kreg_pipette_pump_acc(4052), //
kreg_pipette_pump_dec(4053), //
kreg_pipette_pump_vstart(4054), //
kreg_pipette_pump_vstop(4055), //
kreg_pipette_pump_vmax(4056), //
kreg_pipette_aspirate_distribut_pump_vel(4057), //
kreg_pipette_lld_pump_vel(4058), //
kreg_pipette_lld_motor_vel_rpm(4059), //
kreg_pipette_lld_detect_period_ms(4060), //
kreg_pipette_lld_prepare_pos(4061), //
kreg_pipette_lld_prepare_distribut_pos(4062), //
// kreg_pipette_pump_acc(4052), //
// kreg_pipette_pump_dec(4053), //
// kreg_pipette_pump_vstart(4054), //
// kreg_pipette_pump_vstop(4055), //
// kreg_pipette_pump_vmax(4056), //
// kreg_pipette_aspirate_distribut_pump_vel(4057), //
// kreg_pipette_lld_pump_vel(4058), //
// kreg_pipette_lld_motor_vel_rpm(4059), //
// kreg_pipette_lld_detect_period_ms(4060), //
// kreg_pipette_lld_prepare_pos(4061), //
// kreg_pipette_lld_prepare_distribut_pos(4062), //
kreg_pipette_zm_pos(4101),
kreg_pipette_zm_is_enable(4102),

20
src/main/java/a8k/service/app/appctrl/mainflowctrl/action/SEQ5_PROCESS.java

@ -348,13 +348,13 @@ public class SEQ5_PROCESS extends A8kStepAction {
log.info(" FlowType2->移动到大缓冲液取液位 {}", consumableGroup);
hbotCtrlService.moveToLargeBSSamplePos(consumableGroup);//移动到取样位置
log.info(" FlowType2->液面探测准备");
pipeGunCtrlScripter.lld(PipetteGunBindActionType.TAKE_LARGE_BUFFER_SOLUTION, cxt); //优化这个方法的接口尽量去除掉cxt
// pipeGunCtrlScripter.lld(PipetteGunBindActionType.TAKE_LARGE_BUFFER_SOLUTION, cxt); //优化这个方法的接口尽量去除掉cxt
log.info(" FlowType2->取液 {}", largeBsVolume);
pipeGunCtrlScripter.aspirate(PipetteGunBindActionType.TAKE_LARGE_BUFFER_SOLUTION, cxt, largeBsVolume);//取液
// pipeGunCtrlScripter.aspirate(PipetteGunBindActionType.TAKE_LARGE_BUFFER_SOLUTION, cxt, largeBsVolume);//取液
log.info(" FlowType2->移动到探测物质吐液位 {}", consumableGroup);
hbotCtrlService.moveToProbeSubstanceSamplePos(consumableGroup, consumablePos);//移动到吐液位
log.info(" FlowType2->吐液 {}", largeBsVolume);
pipetteCtrlDriver.pipettePumpMoveTo(PipetteGunConstant.ASPIRATE_PUMP_V, 0);//这个步骤tip头最后是浸没在溶液中的
// pipetteCtrlDriver.pipettePumpMoveTo(PipetteGunConstant.ASPIRATE_PUMP_V, 0);//这个步骤tip头最后是浸没在溶液中的
log.info(" FlowType2->hbot归零");
hbotCtrlService.quickResetHbot();
}
@ -422,9 +422,9 @@ public class SEQ5_PROCESS extends A8kStepAction {
Integer sampleul = ProjProcessContextUtils.getSampleVol(cxt);
Integer reactionul = ProjProcessContextUtils.getReactionPlateDropletVolUl(cxt);
log.info(" FlowTypeX->吐液 {}", sampleul);
pipetteCtrlDriver.pipettePumpMoveTo(PipetteGunConstant.ASPIRATE_PUMP_V, 0);//
// pipetteCtrlDriver.pipettePumpMoveTo(PipetteGunConstant.ASPIRATE_PUMP_V, 0);//
log.info(" FlowTypeX->吸吐混匀 {}ul {} times", reactionul, ProjProcessContextUtils.getBSMixingCnt(cxt));
pipeGunCtrlScripter.mix(PipetteGunBindActionType.MIX_REACTION_LIQUOR, cxt, sampleul, ProjProcessContextUtils.getBSMixingCnt(cxt));
// pipeGunCtrlScripter.mix(PipetteGunBindActionType.MIX_REACTION_LIQUOR, cxt, sampleul, ProjProcessContextUtils.getBSMixingCnt(cxt));
}
//
@ -435,10 +435,10 @@ public class SEQ5_PROCESS extends A8kStepAction {
) {
Integer reactionul = ProjProcessContextUtils.getReactionPlateDropletVolUl(cxt);
log.info(" FlowTypeX->吸液 {}", reactionul);
pipetteCtrlDriver.pipetteAspirate(0, 0, PipetteGunConstant.ASPIRATE_PUMP_V, reactionul);
// pipetteCtrlDriver.pipetteAspirate(0, 0, PipetteGunConstant.ASPIRATE_PUMP_V, reactionul);
log.info(" FlowTypeX->吐液到反应板");
hbotCtrlService.moveTo(hbotFixedPosParamMgr.getDropLiquidPos());
pipetteCtrlDriver.pipettePumpMoveTo(PipetteGunConstant.DISTRIBU_ALL_VOL, 0);
// pipetteCtrlDriver.pipettePumpMoveTo(PipetteGunConstant.DISTRIBU_ALL_VOL, 0);
pipetteCtrlDriver.pipetteClearHangingLiquid(3);
pipetteCtrlDriver.zMotorMoveToZeroPointQuickBlock();
@ -462,14 +462,14 @@ public class SEQ5_PROCESS extends A8kStepAction {
log.info(" -->移动到取样位置 {}", samplePos);
hbotCtrlService.moveToSamplePosXY(samplePos);
log.info(" -->液面探测");
pipeGunCtrlScripter.lld(PipetteGunBindActionType.SAMPLE, ctx);
// pipeGunCtrlScripter.lld(PipetteGunBindActionType.SAMPLE, ctx);
log.info(" -->取液准备");
if (ProjProcessContextUtils.isDoMixTubeSample(ctx)) {
log.info(" -->吸吐混匀 {}", ProjProcessContextUtils.getTubeMixingCount(ctx));
pipeGunCtrlScripter.mix(PipetteGunBindActionType.MIX_SAMPLE, ctx, sampleul, ProjProcessContextUtils.getTubeMixingCount(ctx));
// pipeGunCtrlScripter.mix(PipetteGunBindActionType.MIX_SAMPLE, ctx, sampleul, ProjProcessContextUtils.getTubeMixingCount(ctx));
}
log.info(" -->取样 {}", sampleul);
pipeGunCtrlScripter.aspirate(PipetteGunBindActionType.SAMPLE, ctx, sampleul);
// pipeGunCtrlScripter.aspirate(PipetteGunBindActionType.SAMPLE, ctx, sampleul);
}

7
src/main/java/a8k/service/app/devicectrl/ctrlservice/HbotCtrlService.java

@ -163,6 +163,13 @@ public class HbotCtrlService {
hbotBaseMoveExDriver.hbotMoveTo(toPos);
}
public void moveToLargeBSSamplePosXY(ConsumableGroup group) throws AppException {
Pos3d toPos = hbotConsumableParamMgr.getLargeBufferSamplePos(group);
toPos.z = 0;
hbotBaseMoveExDriver.hbotMoveTo(toPos);
}
public void moveToLargeBSSampleEndPos(ConsumableGroup group) throws AppException {
Pos3d toPos = hbotConsumableParamMgr.getLargeBufferSamplePosEnd(group);
hbotBaseMoveExDriver.hbotMoveTo(toPos);

64
src/main/java/a8k/service/app/devicectrl/driver/PipetteCtrlDriver.java

@ -42,10 +42,6 @@ public class PipetteCtrlDriver {
@Resource
A8kCanBusService canBusService;
@Setter
@Getter
Double volumeCalibrationCoefficient = 1.0;
final Integer overtime = 10000;
static class FnOrder {
@ -60,6 +56,12 @@ public class PipetteCtrlDriver {
public static final int initDeviceBlock = 9;
public static final int putTipBlock = 11;
public static final int liquidOperationClearParams = 20;
public static final int liquidOperationSetGunRunParams = 21;
public static final int liquidOperationSetZMotorRunParams = 22;
public static final int liquidOperationEnableLldRecord = 23;
public static final int liquidOperationFreshParams = 24;
public static final int getSensorSampleData = 29;
public static final int readCapacitance = 30;
public static final int pipetteInitDevice = 31;
@ -166,6 +168,31 @@ public class PipetteCtrlDriver {
return dataList;
}
@ExtApiFn(name = "液体操作.清除参数", order = FnOrder.liquidOperationClearParams)
public void liquidOperationClearParams() throws AppException {
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.liquid_operation_clear_params.toInt());
}
@ExtApiFn(name = "液体操作.设置移液枪运行参数", order = FnOrder.liquidOperationSetGunRunParams)
public void liquidOperationSetGunRunParams(Integer acc, Integer dec, Integer vstart, Integer vstop, Integer vmax) throws AppException {
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.liquid_operation_set_gun_runparams.toInt(), acc, dec, vstart, vstop, vmax);
}
@ExtApiFn(name = "液体操作.设置z轴电机运行参数", order = FnOrder.liquidOperationSetZMotorRunParams)
public void liquidOperationSetZMotorRunParams(Integer posmin, Integer posmax, Integer vmax) throws AppException {
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.liquid_operation_set_zmotor_runparams.toInt(), posmin, posmax, vmax);
}
@ExtApiFn(name = "液体操作.使能LLD记录", order = FnOrder.liquidOperationEnableLldRecord)
public void liquidOperationEnableLldRecord() throws AppException {
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.liquid_operation_enable_lld_record.toInt());
}
@ExtApiFn(name = "液体操作.刷新参数", order = FnOrder.liquidOperationFreshParams)
public void liquidOperationFreshParams() throws AppException {
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.liquid_operation_fresh_params.toInt());
}
@ExtApiFn(name = "LLD.读取电容值", order = FnOrder.readCapacitance)
public Integer readCapacitance() throws AppException {
return getReg(PipetteRegIndex.kreg_pipette_capactitance_val);
@ -185,36 +212,37 @@ public class PipetteCtrlDriver {
}
@ExtApiFn(name = "泵移动到", order = FnOrder.pipettePumpMoveTo)
public void pipettePumpMoveTo(Integer pumpv, Integer ul) throws AppException {
double nl = ul * 1000 * volumeCalibrationCoefficient;
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.pipette_pump_move_to.toInt(), pumpv, (int) nl);
public void pipettePumpMoveTo(Double ul) throws AppException {
double nl = ul * 1000;
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.pipette_pump_move_to.toInt(), (int) nl);
canBusService.waitForMod(MId.PipetteMod, overtime);
}
@ExtApiFn(name = "LLD", order = FnOrder.pipetteLld)
public void pipetteLld(LldType lldtype, Integer maxzpos, Integer c_threshold, Integer p_threshold) throws AppException {
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.pipette_lld.toInt(), lldtype.getIndex(), maxzpos, c_threshold, p_threshold);
public void pipetteLld(LldType lldtype, Integer c_threshold, Integer p_threshold) throws AppException {
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.pipette_lld.toInt(), lldtype.getIndex(), c_threshold, p_threshold);
canBusService.waitForMod(MId.PipetteMod, overtime);
}
@ExtApiFn(name = "吸液", order = FnOrder.pipetteAspirate)
public void pipetteAspirate(Integer llfrpm, Integer llftpos, Integer pumpv, Integer ul) throws AppException {
double nl = ul * 1000 * volumeCalibrationCoefficient;
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.pipette_aspirate.toInt(), llfrpm, llftpos, pumpv, (int) nl);
public void pipetteAspirate(Double ul) throws AppException {
double nl = ul * 1000;
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.pipette_aspirate.toInt(), (int) nl);
canBusService.waitForMod(MId.PipetteMod, overtime);
}
@ExtApiFn(name = "分液", order = FnOrder.pipetteDistribu)
public void pipetteDistribu(Integer llfrpm, Integer pumpv, Integer ul) throws AppException {
double nl = ul * 1000 * volumeCalibrationCoefficient;
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.pipette_distribu.toInt(), llfrpm, pumpv, (int) nl);
public void pipetteDistribu(Double ul) throws AppException {
double nl = ul * 1000;
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.pipette_distribu.toInt(), (int) nl);
canBusService.waitForMod(MId.PipetteMod, overtime);
}
@ExtApiFn(name = "振荡", order = FnOrder.pipetteShakeUp)
public void pipetteShakeUp(Integer llfrpm, Integer maxzpos, Integer pumpv, Integer ul, Integer times) throws AppException {
double nl = ul * 1000 * volumeCalibrationCoefficient;
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.pipette_shake_up.toInt(), llfrpm, maxzpos, pumpv, (int) nl, times);
public void pipetteShakeUp(Double ul, Integer times) throws AppException {
double nl = ul * 1000;
canBusService.callcmd(MId.PipetteMod.toInt(), CmdId.pipette_shake_up.toInt(), (int) nl, times);
canBusService.waitForMod(MId.PipetteMod, overtime);
}
//pipette_clear_hanging_liquid

22
src/main/java/a8k/service/app/devicectrl/driver/type/PipetteRegIndex.java

@ -14,17 +14,17 @@ public enum PipetteRegIndex {
kreg_pipette_tip_state(RegIndex.kreg_pipette_tip_state), // 移动液枪tip状态
// kreg_pipette_limit_ul(RegIndex.kreg_pipette_limit_ul), //
kreg_pipette_pump_acc(RegIndex.kreg_pipette_pump_acc), //
kreg_pipette_pump_dec(RegIndex.kreg_pipette_pump_dec), //
kreg_pipette_pump_vstart(RegIndex.kreg_pipette_pump_vstart), //
kreg_pipette_pump_vstop(RegIndex.kreg_pipette_pump_vstop), //
kreg_pipette_pump_vmax(RegIndex.kreg_pipette_pump_vmax), //
kreg_pipette_aspirate_distribut_pump_vel(RegIndex.kreg_pipette_aspirate_distribut_pump_vel), //
kreg_pipette_lld_pump_vel(RegIndex.kreg_pipette_lld_pump_vel), //
kreg_pipette_lld_motor_vel_rpm(RegIndex.kreg_pipette_lld_motor_vel_rpm), //
kreg_pipette_lld_detect_period_ms(RegIndex.kreg_pipette_lld_detect_period_ms), //
kreg_pipette_lld_prepare_pos(RegIndex.kreg_pipette_lld_prepare_pos), //
kreg_pipette_lld_prepare_distribut_pos(RegIndex.kreg_pipette_lld_prepare_distribut_pos), //
// kreg_pipette_pump_acc(RegIndex.kreg_pipette_pump_acc), //
// kreg_pipette_pump_dec(RegIndex.kreg_pipette_pump_dec), //
// kreg_pipette_pump_vstart(RegIndex.kreg_pipette_pump_vstart), //
// kreg_pipette_pump_vstop(RegIndex.kreg_pipette_pump_vstop), //
// kreg_pipette_pump_vmax(RegIndex.kreg_pipette_pump_vmax), //
// kreg_pipette_aspirate_distribut_pump_vel(RegIndex.kreg_pipette_aspirate_distribut_pump_vel), //
// kreg_pipette_lld_pump_vel(RegIndex.kreg_pipette_lld_pump_vel), //
// kreg_pipette_lld_motor_vel_rpm(RegIndex.kreg_pipette_lld_motor_vel_rpm), //
// kreg_pipette_lld_detect_period_ms(RegIndex.kreg_pipette_lld_detect_period_ms), //
// kreg_pipette_lld_prepare_pos(RegIndex.kreg_pipette_lld_prepare_pos), //
// kreg_pipette_lld_prepare_distribut_pos(RegIndex.kreg_pipette_lld_prepare_distribut_pos), //
kreg_pipette_zm_pos(RegIndex.kreg_pipette_zm_pos),
kreg_pipette_zm_is_enable(RegIndex.kreg_pipette_zm_is_enable),

42
src/main/java/a8k/service/app/devicectrl/exdriver/PipetteCtrlExDriver.java

@ -0,0 +1,42 @@
package a8k.service.app.devicectrl.exdriver;
import a8k.extapi.utils.ExtApiTab;
import a8k.service.app.devicectrl.driver.PipetteCtrlDriver;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
@ExtApiTab()
public class PipetteCtrlExDriver {
@Resource
PipetteCtrlDriver pipetteCtrlDriver;
/*
*
* 取样(取样位置lld目标位置吸吐混匀)
* 1. 取大瓶缓冲液到探测物质位置 非接触分配取样一般比较大lld探测到液面后直接吸取即可
* 2. 取样本到探测物质 接触分配 取样比较小lld探测到液面后先排空再吸取
* 3. 取样本到小瓶缓冲液位置 接触分配
*
*
* 分配:(先接触分配后快速分配)
* 1. 从探测物质取混合液到反应板
* 2. 从小瓶缓冲液取混合液到反应板
*
*
*/
//
// 取大瓶缓冲液到探测物质位置
// 取样本到探测物质
// 取样本到小瓶缓冲液位置
//
// 从探测物质取混合液到
// 从小瓶缓冲液取混合液到
//
// 吸吐混匀
}

178
src/main/java/a8k/service/app/devicectrl/param/calibration/PipetteGunLLDParamCalibration.java

@ -17,93 +17,93 @@ import org.springframework.stereotype.Component;
@Component
public class PipetteGunLLDParamCalibration {
@Resource
PipetteGunLLDParamMgr pipetteGunLLDParamMgr;
@Resource
PipetteCtrlDriver pipetteCtrlDriver;
@Resource
HbotBaseMoveExDriver hbotBaseMoveExDriver;
@Resource
MotorEnableExDriver motorEnableExDriver;
// 测试工具
// @ExtApiFn(name = "归零", group = "基础", order = 1)
// public void moveToZero() throws AppException {
// enableModule();
// pipetteCtrlDriver.zMotorMoveZeroBlock();
// }
@ExtApiFn(name = "移液枪初始化(Tip会掉落)", group = "基础", order = 2)
public void pipetteInitDeviceBlock() throws AppException {
pipetteCtrlDriver.pipetteInitDeviceBlock();
}
@ExtApiFn(name = "使能相关模块", group = "基础", order = 3)
public void enableModule() throws AppException {
pipetteCtrlDriver.zMotorEnable(1);
}
@ExtApiFn(name = "失能相关模块", group = "基础", order = 4)
public void disableModule() throws AppException {
motorEnableExDriver.forceDisableAllMotor();
}
@ExtApiFn(name = "获取相关参数", group = "基础", order = 5)
public Object getParams() throws AppException {
return pipetteGunLLDParamMgr.getParams();
}
Integer lldStartPos;
Integer lldEndPos;
@ExtApiFn(name = "设置LLD开始位置", group = "测试", order = 100)
public void setStartTestPos() throws AppException {
pipetteCtrlDriver.zMotorEnable(1);
pipetteCtrlDriver.zMotorMeasureDistance();
lldStartPos = pipetteCtrlDriver.zMotorReadMeasureDistanceResult();
pipetteCtrlDriver.zMotorEnable(0);
}
@ExtApiFn(name = "设置LLD结束位置", group = "测试", order = 101)
public void setEndTestPos() throws AppException {
pipetteCtrlDriver.zMotorEnable(1);
pipetteCtrlDriver.zMotorMeasureDistance();
lldEndPos = pipetteCtrlDriver.zMotorReadMeasureDistanceResult();
pipetteCtrlDriver.zMotorEnable(0);
}
@ExtApiFn(name = "LDD测量液体属性", group = "测试", order = 103)
public Object lldCalibrate() throws AppException {
if (lldStartPos > lldEndPos) {
throw AppException.ofAECodeError("开始位置大于结束位置");
}
pipetteCtrlDriver.zMotorEnable(1);
pipetteCtrlDriver.zMotorMoveZeroBlock();
pipetteCtrlDriver.pipetteLld(LldType.kplld, lldEndPos, 100, 100);
return pipetteCtrlDriver.getSensorSampleData();
}
@ExtApiFn(name = "LLD测试", group = "测试", order = 104)
public void lldTest(LldType type, Integer c_val, Integer p_val) throws AppException {
pipetteCtrlDriver.zMotorEnable(1);
pipetteCtrlDriver.zMotorMoveZeroBlock();
pipetteCtrlDriver.pipetteLld(type, lldEndPos, c_val, p_val);
}
@ExtApiFn(name = "设置阈值", group = "设置", order = 200)
public void setThreshold(PipetteGunLLDThresholdParam param, Integer val) throws AppException {
pipetteGunLLDParamMgr.setParam(param, val);
}
@ExtApiFn(name = "设置默认LLD方式", group = "设置", order = 201)
public void setLLDType(PipetteGunLLDTypeParam param, LldType type) throws AppException {
pipetteGunLLDParamMgr.setParam(param, type.name());
}
// @Resource
// PipetteGunLLDParamMgr pipetteGunLLDParamMgr;
//
// @Resource
// PipetteCtrlDriver pipetteCtrlDriver;
// @Resource
// HbotBaseMoveExDriver hbotBaseMoveExDriver;
// @Resource
// MotorEnableExDriver motorEnableExDriver;
//
//
// // 测试工具
// // @ExtApiFn(name = "归零", group = "基础", order = 1)
// // public void moveToZero() throws AppException {
// // enableModule();
// // pipetteCtrlDriver.zMotorMoveZeroBlock();
// // }
//
// @ExtApiFn(name = "移液枪初始化(Tip会掉落)", group = "基础", order = 2)
// public void pipetteInitDeviceBlock() throws AppException {
// pipetteCtrlDriver.pipetteInitDeviceBlock();
//
// }
//
// @ExtApiFn(name = "使能相关模块", group = "基础", order = 3)
// public void enableModule() throws AppException {
// pipetteCtrlDriver.zMotorEnable(1);
// }
//
// @ExtApiFn(name = "失能相关模块", group = "基础", order = 4)
// public void disableModule() throws AppException {
// motorEnableExDriver.forceDisableAllMotor();
// }
//
// @ExtApiFn(name = "获取相关参数", group = "基础", order = 5)
// public Object getParams() throws AppException {
// return pipetteGunLLDParamMgr.getParams();
// }
//
//
// Integer lldStartPos;
// Integer lldEndPos;
//
// @ExtApiFn(name = "设置LLD开始位置", group = "测试", order = 100)
// public void setStartTestPos() throws AppException {
// pipetteCtrlDriver.zMotorEnable(1);
// pipetteCtrlDriver.zMotorMeasureDistance();
// lldStartPos = pipetteCtrlDriver.zMotorReadMeasureDistanceResult();
// pipetteCtrlDriver.zMotorEnable(0);
// }
//
// @ExtApiFn(name = "设置LLD结束位置", group = "测试", order = 101)
// public void setEndTestPos() throws AppException {
// pipetteCtrlDriver.zMotorEnable(1);
// pipetteCtrlDriver.zMotorMeasureDistance();
// lldEndPos = pipetteCtrlDriver.zMotorReadMeasureDistanceResult();
// pipetteCtrlDriver.zMotorEnable(0);
// }
//
// @ExtApiFn(name = "LDD测量液体属性", group = "测试", order = 103)
// public Object lldCalibrate() throws AppException {
// if (lldStartPos > lldEndPos) {
// throw AppException.ofAECodeError("开始位置大于结束位置");
// }
//
// pipetteCtrlDriver.zMotorEnable(1);
// pipetteCtrlDriver.zMotorMoveZeroBlock();
//
// pipetteCtrlDriver.pipetteLld(LldType.kplld, lldEndPos, 100, 100);
// return pipetteCtrlDriver.getSensorSampleData();
// }
//
// @ExtApiFn(name = "LLD测试", group = "测试", order = 104)
// public void lldTest(LldType type, Integer c_val, Integer p_val) throws AppException {
// pipetteCtrlDriver.zMotorEnable(1);
// pipetteCtrlDriver.zMotorMoveZeroBlock();
// pipetteCtrlDriver.pipetteLld(type, lldEndPos, c_val, p_val);
// }
//
//
// @ExtApiFn(name = "设置阈值", group = "设置", order = 200)
// public void setThreshold(PipetteGunLLDThresholdParam param, Integer val) throws AppException {
// pipetteGunLLDParamMgr.setParam(param, val);
// }
//
// @ExtApiFn(name = "设置默认LLD方式", group = "设置", order = 201)
// public void setLLDType(PipetteGunLLDTypeParam param, LldType type) throws AppException {
// pipetteGunLLDParamMgr.setParam(param, type.name());
// }
}

140
src/main/java/a8k/service/app/devicectrl/param/calibration/PipetteGunLLFParamCalibration.java

@ -15,75 +15,75 @@ import org.springframework.stereotype.Component;
@ExtApiTab()
@Component
public class PipetteGunLLFParamCalibration {
@Resource
PipetteGunLLFParamMgr pipetteGunLLFParamMgr;
@Resource
PipetteCtrlDriver pipetteCtrlDriver;
@Resource
MotorEnableExDriver motorEnableExDriver;
@ExtApiFn(name = "移液枪初始化(Tip会掉落)", group = "基础", order = 2)
public void pipetteInitDeviceBlock() throws AppException {
pipetteCtrlDriver.pipetteInitDeviceBlock();
}
@ExtApiFn(name = "使能相关模块", group = "基础", order = 3)
public void enableModule() throws AppException {
pipetteCtrlDriver.zMotorEnable(1);
}
@ExtApiFn(name = "失能相关模块", group = "基础", order = 4)
public void disableModule() throws AppException {
motorEnableExDriver.forceDisableAllMotor();
}
@ExtApiFn(name = "获取相关参数", group = "基础", order = 5)
public Object getParams() throws AppException {
return pipetteGunLLFParamMgr.getParams();
}
Integer llfStartPos;
Integer llfEndPos;
@ExtApiFn(name = "设置llf开始位置", group = "测试", order = 100)
public void setStartTestPos() throws AppException {
pipetteCtrlDriver.zMotorEnable(1);
pipetteCtrlDriver.zMotorMeasureDistance();
llfStartPos = pipetteCtrlDriver.zMotorReadMeasureDistanceResult();
pipetteCtrlDriver.zMotorEnable(0);
}
@ExtApiFn(name = "设置llf结束位置", group = "测试", order = 101)
public void setEndTestPos() throws AppException {
pipetteCtrlDriver.zMotorEnable(1);
pipetteCtrlDriver.zMotorMeasureDistance();
llfEndPos = pipetteCtrlDriver.zMotorReadMeasureDistanceResult();
pipetteCtrlDriver.zMotorEnable(0);
}
@ExtApiFn(name = "吸液", group = "测试", order = 104)
public void aspirate(Integer llfv, Integer ul) throws AppException {
pipetteCtrlDriver.zMotorMoveToBlock(llfStartPos);
pipetteCtrlDriver.pipetteAspirate(llfv, llfEndPos, PipetteGunConstant.ASPIRATE_PUMP_V, ul);
}
@ExtApiFn(name = "分液", group = "测试", order = 105)
public void distribute() throws AppException {
pipetteCtrlDriver.zMotorMoveToBlock(llfStartPos - 100);
pipetteCtrlDriver.pipetteDistribu(0, PipetteGunConstant.MAX_PUMP_V, PipetteGunConstant.DISTRIBU_ALL_VOL);
}
@ExtApiFn(name = "设置参数", group = "设置", order = 200)
public void setDefaultCThread(PipetteGunLLFParam param, Integer val) throws AppException {
pipetteGunLLFParamMgr.setParam(param, val);
}
//
// @Resource
// PipetteGunLLFParamMgr pipetteGunLLFParamMgr;
//
// @Resource
// PipetteCtrlDriver pipetteCtrlDriver;
//
// @Resource
// MotorEnableExDriver motorEnableExDriver;
//
//
// @ExtApiFn(name = "移液枪初始化(Tip会掉落)", group = "基础", order = 2)
// public void pipetteInitDeviceBlock() throws AppException {
// pipetteCtrlDriver.pipetteInitDeviceBlock();
//
// }
//
// @ExtApiFn(name = "使能相关模块", group = "基础", order = 3)
// public void enableModule() throws AppException {
// pipetteCtrlDriver.zMotorEnable(1);
// }
//
// @ExtApiFn(name = "失能相关模块", group = "基础", order = 4)
// public void disableModule() throws AppException {
// motorEnableExDriver.forceDisableAllMotor();
// }
//
// @ExtApiFn(name = "获取相关参数", group = "基础", order = 5)
// public Object getParams() throws AppException {
// return pipetteGunLLFParamMgr.getParams();
// }
//
//
// Integer llfStartPos;
// Integer llfEndPos;
//
//
// @ExtApiFn(name = "设置llf开始位置", group = "测试", order = 100)
// public void setStartTestPos() throws AppException {
// pipetteCtrlDriver.zMotorEnable(1);
// pipetteCtrlDriver.zMotorMeasureDistance();
// llfStartPos = pipetteCtrlDriver.zMotorReadMeasureDistanceResult();
// pipetteCtrlDriver.zMotorEnable(0);
// }
//
// @ExtApiFn(name = "设置llf结束位置", group = "测试", order = 101)
// public void setEndTestPos() throws AppException {
// pipetteCtrlDriver.zMotorEnable(1);
// pipetteCtrlDriver.zMotorMeasureDistance();
// llfEndPos = pipetteCtrlDriver.zMotorReadMeasureDistanceResult();
// pipetteCtrlDriver.zMotorEnable(0);
// }
//
//
// @ExtApiFn(name = "吸液", group = "测试", order = 104)
// public void aspirate(Integer llfv, Integer ul) throws AppException {
// pipetteCtrlDriver.zMotorMoveToBlock(llfStartPos);
// pipetteCtrlDriver.pipetteAspirate(llfv, llfEndPos, PipetteGunConstant.ASPIRATE_PUMP_V, ul);
// }
//
// @ExtApiFn(name = "分液", group = "测试", order = 105)
// public void distribute() throws AppException {
// pipetteCtrlDriver.zMotorMoveToBlock(llfStartPos - 100);
// pipetteCtrlDriver.pipetteDistribu(0, PipetteGunConstant.MAX_PUMP_V, PipetteGunConstant.DISTRIBU_ALL_VOL);
// }
//
// @ExtApiFn(name = "设置参数", group = "设置", order = 200)
// public void setDefaultCThread(PipetteGunLLFParam param, Integer val) throws AppException {
// pipetteGunLLFParamMgr.setParam(param, val);
// }
}

19
src/main/java/a8k/service/app/devicectrl/param/param_mgr/PipetteGunExParamMgr.java

@ -9,7 +9,8 @@ import org.springframework.stereotype.Component;
@Slf4j
public class PipetteGunExParamMgr extends ParamMgr {
enum PipetteGunParam {
VOLUME_CALIBRATION_COEFFICIENT("体积校准系数", Double.class),
VOLUME_CALIBRATION_COEFFICIENT_A("体积校准系数-A", Double.class),
VOLUME_CALIBRATION_COEFFICIENT_B("体积校准系数-B", Double.class),
;
public final String chName;
@ -29,16 +30,14 @@ public class PipetteGunExParamMgr extends ParamMgr {
}
}
public void setVolumeCalibrationCoefficient(Double value) {
setParam(PipetteGunParam.VOLUME_CALIBRATION_COEFFICIENT, value);
public void setVolumeCalibrationCoefficient(Double A, Double B) {
setParam(PipetteGunParam.VOLUME_CALIBRATION_COEFFICIENT_A, A);
setParam(PipetteGunParam.VOLUME_CALIBRATION_COEFFICIENT_B, B);
}
public Double getVolumeCalibrationCoefficient() {
Double val = getParam(PipetteGunParam.VOLUME_CALIBRATION_COEFFICIENT, Double.class);
if (val == null) {
return 1.0;
}
return val;
public double calibrateVolume(double rawVolume) {
Double A = getParam(PipetteGunParam.VOLUME_CALIBRATION_COEFFICIENT_A, Double.class);
Double B = getParam(PipetteGunParam.VOLUME_CALIBRATION_COEFFICIENT_B, Double.class);
return A * rawVolume + B;
}
}

116
src/main/java/a8k/service/app/devicectrl/script/PipeGunCtrlScripter.java

@ -30,63 +30,63 @@ import org.springframework.util.Assert;
@Component
@Slf4j
public class PipeGunCtrlScripter {
@Resource
PipetteCtrlDriver pipetteCtrlDriver;
@Resource
HbotSamplePosParamMgr hbotSamplePosParamMgr;
@Resource
HbotConsumableParamMgr hbotConsumableParamMgr;
@Resource
PipetteGunParamExMgr pipetteGunParamExMgr;
@Resource
TestModeState testModeState;
public void mix(PipetteGunBindActionType actionType, ProjectTaskContext ctx, Integer ul, Integer times) throws AppException {
LLFParamPack llfParamPack = pipetteGunParamExMgr.getLLFParam(actionType, ctx);
pipetteCtrlDriver.pipetteShakeUp(llfParamPack.llfVel, llfParamPack.llfEndPos, PipetteGunConstant.ASPIRATE_PUMP_V, ul, times);
}
public void aspirate(PipetteGunBindActionType actionType, ProjectTaskContext ctx, Integer ul) throws AppException {
LLFParamPack llfParamPack = pipetteGunParamExMgr.getLLFParam(actionType, ctx);
log.info("吸液 {} , llfvel {} , llfStartPos {} , llfEndPos {}", ul, llfParamPack.llfVel, llfParamPack.llfStartPos, llfParamPack.llfEndPos);
pipetteCtrlDriver.pipetteAspirate(llfParamPack.llfVel, llfParamPack.llfEndPos, PipetteGunConstant.ASPIRATE_PUMP_V, ul);
}
public void lld(PipetteGunBindActionType actionType, ProjectTaskContext ctx) throws AppException {
log.info("液面探测 {}", actionType);
LLDParamPack lldparm = pipetteGunParamExMgr.getLLDParam(actionType, ctx);
Pos3d sampleStartPos = null;
Pos3d sampleEndPos = null;
//取tip,移动到样本所在的位置,并液面探测
switch (actionType) {
case SAMPLE -> {
A8kSamplePos samplePos = ProjProcessContextUtils.getSamplePos(ctx);
sampleStartPos = hbotSamplePosParamMgr.getSampleStartPos(samplePos);
sampleEndPos = hbotSamplePosParamMgr.getSampleEndPos(samplePos);
}
case TAKE_LARGE_BUFFER_SOLUTION -> { //取大瓶缓冲液
var group = ctx.getConsumable().getGroup();
sampleStartPos = hbotConsumableParamMgr.getLargeBufferSamplePos(group);
sampleEndPos = hbotConsumableParamMgr.getLargeBufferSamplePosEnd(group);
}
}
Assert.notNull(sampleStartPos, "sampleStartPos is null");
Assert.notNull(sampleEndPos, "sampleEndPos is null");
pipetteCtrlDriver.pipetteLld(LldType.kplld, sampleEndPos.z, lldparm.cThreshold, lldparm.pThreshold);
if (!pipetteCtrlDriver.lldIsDetectLiquid()) {
if (testModeState.getNoCheckMode()) {
log.warn("没有液体");
} else {
throw new AppException(A8kEcode.APPE_DETECT_SAMPLE_FAIL);
}
}
}
//
//
// @Resource
// PipetteCtrlDriver pipetteCtrlDriver;
// @Resource
// HbotSamplePosParamMgr hbotSamplePosParamMgr;
// @Resource
// HbotConsumableParamMgr hbotConsumableParamMgr;
// @Resource
// PipetteGunParamExMgr pipetteGunParamExMgr;
// @Resource
// TestModeState testModeState;
//
// public void mix(PipetteGunBindActionType actionType, ProjectTaskContext ctx, Integer ul, Integer times) throws AppException {
// LLFParamPack llfParamPack = pipetteGunParamExMgr.getLLFParam(actionType, ctx);
// pipetteCtrlDriver.pipetteShakeUp(llfParamPack.llfVel, llfParamPack.llfEndPos, PipetteGunConstant.ASPIRATE_PUMP_V, ul, times);
// }
//
//
// public void aspirate(PipetteGunBindActionType actionType, ProjectTaskContext ctx, Integer ul) throws AppException {
// LLFParamPack llfParamPack = pipetteGunParamExMgr.getLLFParam(actionType, ctx);
// log.info("吸液 {} , llfvel {} , llfStartPos {} , llfEndPos {}", ul, llfParamPack.llfVel, llfParamPack.llfStartPos, llfParamPack.llfEndPos);
// pipetteCtrlDriver.pipetteAspirate(llfParamPack.llfVel, llfParamPack.llfEndPos, PipetteGunConstant.ASPIRATE_PUMP_V, ul);
// }
//
//
// public void lld(PipetteGunBindActionType actionType, ProjectTaskContext ctx) throws AppException {
// log.info("液面探测 {}", actionType);
// LLDParamPack lldparm = pipetteGunParamExMgr.getLLDParam(actionType, ctx);
// Pos3d sampleStartPos = null;
// Pos3d sampleEndPos = null;
//
// //取tip,移动到样本所在的位置,并液面探测
// switch (actionType) {
// case SAMPLE -> {
// A8kSamplePos samplePos = ProjProcessContextUtils.getSamplePos(ctx);
// sampleStartPos = hbotSamplePosParamMgr.getSampleStartPos(samplePos);
// sampleEndPos = hbotSamplePosParamMgr.getSampleEndPos(samplePos);
// }
// case TAKE_LARGE_BUFFER_SOLUTION -> { //取大瓶缓冲液
// var group = ctx.getConsumable().getGroup();
// sampleStartPos = hbotConsumableParamMgr.getLargeBufferSamplePos(group);
// sampleEndPos = hbotConsumableParamMgr.getLargeBufferSamplePosEnd(group);
// }
// }
//
// Assert.notNull(sampleStartPos, "sampleStartPos is null");
// Assert.notNull(sampleEndPos, "sampleEndPos is null");
//
// pipetteCtrlDriver.pipetteLld(LldType.kplld, sampleEndPos.z, lldparm.cThreshold, lldparm.pThreshold);
// if (!pipetteCtrlDriver.lldIsDetectLiquid()) {
// if (testModeState.getNoCheckMode()) {
// log.warn("没有液体");
// } else {
// throw new AppException(A8kEcode.APPE_DETECT_SAMPLE_FAIL);
// }
// }
// }
}

275
src/main/java/a8k/service/verification/PipetteGunVerificationV2.java

@ -1,9 +1,7 @@
package a8k.service.verification;
import a8k.constant.AppConstant;
import a8k.constant.PipetteGunConstant;
import a8k.extapi.utils.ExtApiFn;
import a8k.extapi.utils.ExtApiStatu;
import a8k.extapi.utils.ExtApiTab;
import a8k.hardware.type.LldType;
import a8k.service.app.devicectrl.ctrlservice.DeviceInitCtrlService;
@ -16,17 +14,14 @@ import a8k.service.app.devicectrl.param.ext_param_mgr.HbotConsumableParamMgr;
import a8k.service.app.devicectrl.param.ext_param_mgr.PipetteGunParamExMgr;
import a8k.service.app.devicectrl.param.param_mgr.*;
import a8k.type.ConsumableGroup;
import a8k.type.checkpoint.CheckResult;
import a8k.type.cfg.Pos3d;
import a8k.type.exception.AppException;
import a8k.type.pos.TipPos;
import a8k.type.type.TipGroup;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
@ExtApiTab()
@Component
@Slf4j
@ -65,56 +60,50 @@ public class PipetteGunVerificationV2 {
PipetteGunExParamMgr pipetteGunExParamMgr;
Integer tipNum = 0;
Integer m_loadUl = 0;
Integer lldpThreshold = 20;
Integer tipNum = 0;
Integer liquidPos = null;
@PostConstruct
void initialize() {
pipetteCtrlDriver.setVolumeCalibrationCoefficient(pipetteGunExParamMgr.getVolumeCalibrationCoefficient());
public void pipetteGunInit() throws AppException {
pipetteCtrlDriver.liquidOperationClearParams(); //
pipetteCtrlDriver.liquidOperationSetGunRunParams(14, 14, 0, 900, 8000); //pump param
pipetteCtrlDriver.liquidOperationFreshParams();
pipetteCtrlDriver.pipetteInitDeviceBlock();
}
@ExtApiFn(name = "初始化设备", group = "测试准备工作", order = 11)
public List<CheckResult> initDevice() throws AppException {
List<CheckResult> checkResult = deviceInitializationModule.initDevice();
for (CheckResult result : checkResult) {
if (!result.pass) {
return checkResult;
}
}
return checkResult;
}
@ExtApiFn(name = "初始化设备", group = "基础", order = 11)
public void initDevice() throws AppException {
pipetteCtrlDriver.zMotorEnable(1);
hbotBaseMoveExDriver.enable(1);
@ExtApiFn(name = "加载tip头", group = "测试准备工作", order = 12)
public void loadTip() throws AppException {
tipNum = AppConstant.TIP_NUM;
}
pipetteCtrlDriver.zMotorMoveZeroBlock();
hbotBaseMoveExDriver.moveToZero();
hbotBaseMoveExDriver.hbotMoveTo(hbotTipPosMgr.getDropTipPos());
pipetteGunInit();
hbotBaseMoveExDriver.hbotMoveTo(new Pos3d(0, 0, 0));
tipNum = AppConstant.TIP_NUM;
@ExtApiFn(name = "设置吸液量", group = "测试准备工作", order = 13)
public void setM_loadUl(Integer m_loadUl) {
this.m_loadUl = m_loadUl;
}
@ExtApiFn(name = "设置LLD P阈值(建议20)", group = "测试准备工作", order = 14)
public void setLldpThreshold(Integer lldpThreshold) {
this.lldpThreshold = lldpThreshold;
@ExtApiFn(name = "停止测试", group = "基础", order = 12)
public void stopTest() throws AppException {
pipetteCtrlDriver.zMotorEnable(0);
hbotBaseMoveExDriver.enable(0);
}
@ExtApiFn(name = "校准系数(realul:实际体积)", group = "测试准备工作", order = 15)
public void calibration(Double realul) {
Double nowcoefficient = pipetteCtrlDriver.getVolumeCalibrationCoefficient();
Double coefficient = m_loadUl * nowcoefficient / realul;
pipetteGunExParamMgr.setVolumeCalibrationCoefficient(coefficient);
pipetteCtrlDriver.setVolumeCalibrationCoefficient(coefficient);
public void calibration(Double coefficientK, Double coefficientB) {
pipetteGunExParamMgr.setVolumeCalibrationCoefficient(coefficientK, coefficientB);
}
Boolean takeOneTip() throws AppException {
hbotBaseMoveExDriver.hbotMoveTo(hbotTipPosMgr.getDropTipPos());
pipetteCtrlDriver.pipetteInitDeviceBlock();
pipetteGunInit();
TipPos tipPos = new TipPos();
tipPos.group = TipGroup.GROUP0;
if (tipNum == 0) {
@ -135,174 +124,96 @@ public class PipetteGunVerificationV2 {
}
// @ExtApiFn(name = "吸取并释放一次", group = "测试", order = 21)
// public void aspirateAndDistruptOnce() throws AppException {
// if (loadUl == 0) {
// throw AppException.ofAECodeError("吸液量为0");
// }
//
// //
// // param
// //
//
// Integer startZPos = hbotConsumableParamMgr.getLargeBufferSamplePos(ConsumableGroup.GROUP0).z;
// Integer endZPos = hbotConsumableParamMgr.getLargeBufferSamplePosEnd(ConsumableGroup.GROUP0).z;
// Integer llfv = 5;
//
// while (!pipetteCtrlDriver.isHasTip()) {
// if (takeOneTip()) {
// break;
// }
// }
// //
// // lld
// //
// hbotCtrlService.moveToLargeBSSamplePos(ConsumableGroup.GROUP0);
// pipetteCtrlDriver.zMotorMoveToBlock(startZPos);
//
// pipetteCtrlDriver.pipetteLld(LldType.kclld, endZPos, 20, 20);
// if (!pipetteCtrlDriver.lldIsDetectLiquid()) {
// throw AppException.ofAECodeError("没有液体");
// }
//
// Integer liquidZPos = pipetteCtrlDriver.getReg(PipetteRegIndex.kreg_pipette_zm_pos);
// pipetteCtrlDriver.pipetteAspirate(0, 0, PipetteGunConstant.ASPIRATE_PUMP_V, 20);
// pipetteCtrlDriver.zMotorMoveToBlock(liquidZPos - 100);
// // pipetteCtrlDriver.pipetteClearHangingLiquid(3);
// pipetteCtrlDriver.pipettePumpMoveTo(1000, 0); //移除探测吸入的液体
// pipetteCtrlDriver.pipettePumpMoveTo(500, 50); //吸入10ul的空气消除部分误差
// pipetteCtrlDriver.zMotorMoveToBlock(liquidZPos);
//
// //
// // aspirate
// //
// if (loadUl < 50) {
// pipetteCtrlDriver.pipetteAspirate(llfv, endZPos, PipetteGunConstant.ASPIRATE_PUMP_V, loadUl + 10);
// pipetteCtrlDriver.pipetteDistribu(0, PipetteGunConstant.ASPIRATE_PUMP_V, 10);
// // pipetteCtrlDriver.pipetteAspirate(0, endZPos, PipetteGunConstant.ASPIRATE_PUMP_V, loadUl);
// } else {
// pipetteCtrlDriver.pipetteAspirate(llfv, endZPos, PipetteGunConstant.ASPIRATE_PUMP_V, loadUl);
// }
// pipetteCtrlDriver.zMotorMoveToZeroPointQuickBlock();
//
// //
// // move to distrube pos
// //
// hbotCtrlService.moveToLargeBSSamplePos(ConsumableGroup.GROUP1);
// // pipetteCtrlDriver.pipetteDistribu(0, PipetteGunConstant.ASPIRATE_PUMP_V, loadUl);
// pipetteCtrlDriver.pipettePumpMoveTo(1000, 0); //分配所有液体
// pipetteCtrlDriver.pipetteClearHangingLiquid(1);
// hbotCtrlService.moveQuickToZero();
// }
@ExtApiFn(name = "取一次10ul", group = "测试", order = 22)
public void aspirate10ul() throws AppException {
var loadUl = 10;
public void pumpMoveTo(Integer pumpvmax, Double ul) throws AppException {
pipetteCtrlDriver.liquidOperationClearParams();
pipetteCtrlDriver.liquidOperationSetGunRunParams(14, 14, 0, 1000, pumpvmax);
pipetteCtrlDriver.liquidOperationFreshParams();
pipetteCtrlDriver.pipettePumpMoveTo(ul);
}
//
// param
//
public Integer lld() throws AppException {
liquidPos = 0;
hbotCtrlService.moveToLargeBSSamplePosXY(ConsumableGroup.GROUP0);
Integer startZPos = hbotConsumableParamMgr.getLargeBufferSamplePos(ConsumableGroup.GROUP0).z;
Integer endZPos = hbotConsumableParamMgr.getLargeBufferSamplePosEnd(ConsumableGroup.GROUP0).z;
pipetteCtrlDriver.zMotorMoveToBlock(0);
//
// lld
//
hbotCtrlService.moveToLargeBSSamplePos(ConsumableGroup.GROUP0);
pipetteCtrlDriver.zMotorMoveToBlock(startZPos);
pumpMoveTo(8000, 0.0);
pumpMoveTo(8000, 50.0);
pipetteCtrlDriver.pipettePumpMoveTo(1000, 0); //移除探测吸入的液体
pipetteCtrlDriver.pipettePumpMoveTo(500, 100); //吸入10ul的空气消除部分误差
pipetteCtrlDriver.liquidOperationClearParams(); //
pipetteCtrlDriver.liquidOperationSetGunRunParams(14, 14, 0, 900, 30); //pump param
pipetteCtrlDriver.liquidOperationSetZMotorRunParams(0, 300, 30); // z motor param
pipetteCtrlDriver.liquidOperationFreshParams();
pipetteCtrlDriver.pipetteLld(LldType.kplld, 0, 15);
pipetteCtrlDriver.pipetteLld(LldType.kclld, endZPos, 20, 20);
if (!pipetteCtrlDriver.lldIsDetectLiquid()) {
throw AppException.ofAECodeError("没有液体");
if (pipetteCtrlDriver.lldIsDetectLiquid()) {
liquidPos = pipetteCtrlDriver.getReg(PipetteRegIndex.kreg_pipette_zm_pos);
}
pipetteCtrlDriver.pipetteAspirate(0, 10, 50, loadUl + 10);
pipetteCtrlDriver.pipetteDistribu(0, 50, 10);
pipetteCtrlDriver.zMotorMoveToZeroPointQuickBlock();
//
// move to distrube pos
//
hbotCtrlService.moveToLargeBSSamplePos(ConsumableGroup.GROUP1);
pipetteCtrlDriver.pipettePumpMoveTo(1000, 0); //分配所有液体
hbotCtrlService.moveQuickToZero();
pipetteCtrlDriver.zMotorMoveToBlock(0);
pumpMoveTo(8000, 0.0);
return liquidPos;
}
@ExtApiFn(name = "取多次", group = "测试", order = 23)
public void takeMuti(Integer times,Integer loadUl) throws AppException {
for (int i = 0; i < times; i++) {
takeOnce(loadUl);
}
}
@ExtApiFn(name = "取一次", group = "测试", order = 23)
public void takeOnce(Integer loadUl) throws AppException {
takeTip();
Integer startZPos = hbotConsumableParamMgr.getLargeBufferSamplePos(ConsumableGroup.GROUP0).z;
Integer endZPos = hbotConsumableParamMgr.getLargeBufferSamplePosEnd(ConsumableGroup.GROUP0).z;
// move To Take Pos
hbotCtrlService.moveToLargeBSSamplePos(ConsumableGroup.GROUP0);
// lld
pipetteCtrlDriver.pipettePumpMoveTo(1000, 0); //移除探测吸入的液体
pipetteCtrlDriver.pipettePumpMoveTo(500, 100); //吸入10ul的空气消除部分误差
pipetteCtrlDriver.zMotorMoveToBlock(startZPos);
pipetteCtrlDriver.pipetteLld(LldType.kplld, endZPos, 20, 10);
if (!pipetteCtrlDriver.lldIsDetectLiquid()) {
throw AppException.ofAECodeError("没有液体");
}
pipetteCtrlDriver.pipetteAspirate(10, endZPos, 200, 50);//
public void takeLiquid(Double ul) throws AppException {
/*
* 1.
*/
hbotCtrlService.moveToLargeBSSamplePosXY(ConsumableGroup.GROUP0);
pipetteCtrlDriver.zMotorMoveToBlock(0);
pumpMoveTo(8000, 0.0);
pumpMoveTo(8000, 150.0);
Integer liquidZPos = pipetteCtrlDriver.getReg(PipetteRegIndex.kreg_pipette_zm_pos);
pipetteCtrlDriver.zMotorMoveToBlock(startZPos);
pipetteCtrlDriver.pipetteAspirate(0, 0, 200, 5);
pipetteCtrlDriver.pipettePumpMoveTo(1000, 0);
pipetteCtrlDriver.pipettePumpMoveTo(500, 100);
pipetteCtrlDriver.zMotorMoveToBlock(liquidPos);
pipetteCtrlDriver.liquidOperationClearParams(); //
pipetteCtrlDriver.liquidOperationSetGunRunParams(14, 14, 0, 900, 100); //pump param
pipetteCtrlDriver.liquidOperationSetZMotorRunParams(0, 300, 10); // z motor param
pipetteCtrlDriver.liquidOperationFreshParams();
pipetteCtrlDriver.zMotorMoveToBlock(liquidZPos);
pipetteCtrlDriver.pipetteAspirate(0, 12, 50, loadUl + 50);
pipetteCtrlDriver.pipetteDistribu(0, 200, 50);
// move to distrube pos
hbotCtrlService.moveToLargeBSSamplePos(ConsumableGroup.GROUP1);
pipetteCtrlDriver.pipettePumpMoveTo(1000, 0); //分配所有液体
ul = pipetteGunExParamMgr.calibrateVolume(ul);
log.info("取液体 {}", ul);
pipetteCtrlDriver.pipettePumpMoveTo(200, 100); //分配所有液体
pipetteCtrlDriver.pipettePumpMoveTo(1000, 0); //分配所有液体
hbotCtrlService.moveQuickToZero();
pipetteCtrlDriver.pipetteAspirate(ul);
pipetteCtrlDriver.zMotorMoveToBlock(0);
}
@ExtApiStatu(name = "val", group = "tipNum", order = 100)
public Integer readTipNum() throws AppException {
return tipNum;
public void distributeLiquid() throws AppException {
hbotCtrlService.moveToLargeBSSamplePosXY(ConsumableGroup.GROUP5);
pipetteCtrlDriver.zMotorMoveToBlock(50);
pumpMoveTo(8000, 0.0);
pipetteCtrlDriver.zMotorMoveToBlock(0);
}
@ExtApiStatu(name = "val", group = "loadUl", order = 101)
public Integer readLoadUl() throws AppException {
return m_loadUl;
public void resetPos() throws AppException {
hbotCtrlService.moveToLargeBSSamplePosXY(ConsumableGroup.GROUP1);
}
@ExtApiStatu(name = "val", group = "lldpThreshold", order = 102)
public Integer readLldpThreshold() throws AppException {
return lldpThreshold;
@ExtApiFn(name = "取一次10ul", group = "测试", order = 22)
public void aspirate10ul() throws AppException {
takeTip();
lld();
if (liquidPos == 0)
throw AppException.ofAECodeError("未检测到液体");
takeLiquid(10.0);
distributeLiquid();
resetPos();
}
@ExtApiStatu(name = "val", group = "volumeCalibrationConff", order = 103)
public Double readVolumeCalibrationConff() throws AppException {
return pipetteCtrlDriver.getVolumeCalibrationCoefficient();
@ExtApiFn(name = "取一次75ul", group = "测试", order = 23)
public void aspirate75ul() throws AppException {
takeTip();
lld();
if (liquidPos == 0)
throw AppException.ofAECodeError("未检测到液体");
takeLiquid(75.0);
distributeLiquid();
resetPos();
}
}
Loading…
Cancel
Save