Browse Source

增加步骤:采样混合

master
sige 2 years ago
parent
commit
7d5c8e039f
  1. 2
      src/main/java/com/dreamworks/boditech/driver/Command.java
  2. 16
      src/main/java/com/dreamworks/boditech/driver/Device.java
  3. 10
      src/main/java/com/dreamworks/boditech/driver/actuator/ActArmXY.java
  4. 6
      src/main/java/com/dreamworks/boditech/driver/actuator/ActMotor.java
  5. 46
      src/main/java/com/dreamworks/boditech/driver/actuator/ActPipette.java
  6. 1
      src/main/java/com/dreamworks/boditech/driver/actuator/ActuatorModule.java
  7. 13
      src/main/java/com/dreamworks/boditech/driver/consumable/CsmBufferTubeA.java
  8. 7
      src/main/java/com/dreamworks/boditech/driver/consumable/CsmBufferTubeB.java
  9. 5
      src/main/java/com/dreamworks/boditech/driver/consumable/CsmLargeBufferTube.java
  10. 4
      src/main/java/com/dreamworks/boditech/driver/consumable/CsmPipetteTip.java
  11. 17
      src/main/java/com/dreamworks/boditech/driver/consumable/CsmSampleTube.java
  12. 11
      src/main/java/com/dreamworks/boditech/driver/consumable/ReactionTube.java
  13. 34
      src/main/java/com/dreamworks/boditech/driver/task/TaskTest.java
  14. 1
      src/main/java/com/dreamworks/boditech/driver/task/step/StepManager.java
  15. 2
      src/main/java/com/dreamworks/boditech/driver/task/step/StepPuncture.java
  16. 116
      src/main/java/com/dreamworks/boditech/driver/task/step/StepSampling.java
  17. 8
      src/main/java/com/dreamworks/boditech/mapper/OptionMapper.java
  18. 18
      src/main/java/com/dreamworks/boditech/service/RuntimeOptionService.java

2
src/main/java/com/dreamworks/boditech/driver/Command.java

@ -13,6 +13,8 @@ public class Command {
public static final Integer CMD_MOTOR_EASY_MOVE_BY = 0x0212;
public static final Integer CMD_MOTOR_EASY_MOVE_TO = 0x0213;
public static final Integer CMD_XYMOTOR_MOVE_TO = 0x0303;
public static final Integer CMD_PIPETTE_CTRL_INIT_DEVICE = 0x0501;
public static final Integer CMD_PIPETTE_CTRL_MOVE_TO_UL = 0x0503;
// command meta data
public static final Map<Integer,CommandMeta> cmdMetaMap = new HashMap<Integer,CommandMeta>();

16
src/main/java/com/dreamworks/boditech/driver/Device.java

@ -5,6 +5,7 @@ import com.dreamworks.boditech.driver.consumable.CsmBufferTubeA;
import com.dreamworks.boditech.driver.consumable.CsmBufferTubeB;
import com.dreamworks.boditech.driver.consumable.CsmLargeBufferTube;
import com.dreamworks.boditech.driver.consumable.CsmPipetteTip;
import com.dreamworks.boditech.service.RuntimeOptionService;
import com.dreamworks.boditech.utils.MyByteBuffer;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
@ -28,6 +29,9 @@ public class Device {
@Resource
private ComSerialPort serialPort;
@Resource
private RuntimeOptionService runtimeOptionService;
// actuators
private final Map<Integer, Actuator> actuators = new HashMap<Integer, Actuator>();
// pipette tips
@ -55,6 +59,7 @@ public class Device {
this.appendActuator(new ActMotor(ActuatorModule.TEST_TUBE_SHAKING_CLIP_MOTOR, this));
this.appendActuator(new ActArmXY(ActuatorModule.ARM_XY, this));
this.appendActuator(new ActMotor(ActuatorModule.ARM_Z_MOTOR, this));
this.appendActuator(new ActPipette(ActuatorModule.ARM_Z_PIPETTE, this));
}
// append actuator
@ -122,7 +127,7 @@ public class Device {
}
// get pipette tip
public CsmPipetteTip getPipeTip() {
public CsmPipetteTip getPipetteTip() {
if ( this.pipetteTips.isEmpty() ) {
throw new RuntimeException("no pipette tip");
}
@ -157,8 +162,17 @@ public class Device {
return tube;
}
// get location by name
public Integer getLocationByName( String name ) {
String key = "device.location." + name;
Integer value = this.runtimeOptionService.getInteger(key);
return value;
}
// call device command and wait for response
public ByteBuffer call( Integer cmd, Integer mid, Object ... params ) {
int length = 2 + 2 + 1 + 1 + 2;
for ( Object param : params ) {
if ( param instanceof Integer ) {

10
src/main/java/com/dreamworks/boditech/driver/actuator/ActArmXY.java

@ -26,4 +26,14 @@ public class ActArmXY extends ActuatorBase {
this.call(Command.CMD_XYMOTOR_MOVE_TO, x, y, velocity);
this.waitForFinish();
}
/**
* move to given position by name
* @param name name of position
*/
public void moveTo(String name) {
Integer x = this.getDevice().getLocationByName(name + ".x");
Integer y = this.getDevice().getLocationByName(name + ".y");
this.moveTo(x, y);
}
}

6
src/main/java/com/dreamworks/boditech/driver/actuator/ActMotor.java

@ -18,6 +18,12 @@ public class ActMotor extends ActuatorBase {
this.waitForFinish();
}
// move to given position by name
public void moveTo( String name ) {
Integer location = this.getDevice().getLocationByName(name);
this.moveTo(location);
}
// move by given distance
public void moveBy(int distance) {
this.call(Command.CMD_MOTOR_EASY_MOVE_BY, distance);

46
src/main/java/com/dreamworks/boditech/driver/actuator/ActPipette.java

@ -0,0 +1,46 @@
package com.dreamworks.boditech.driver.actuator;
import com.dreamworks.boditech.driver.Command;
import com.dreamworks.boditech.driver.Device;
public class ActPipette extends ActuatorBase {
// indicate whether the pipette has tip
// @TODO : this should be false by default
private boolean hasTip = true;
// constructor
public ActPipette(Integer mid, Device device) {
super(mid, device);
}
// set whether the pipette has tip
public void setHasTip(boolean hasTip) {
this.hasTip = hasTip;
}
// get whether the pipette has tip
public boolean getHasTip() {
return this.hasTip;
}
// init device
public void initDevice() {
this.call(Command.CMD_PIPETTE_CTRL_INIT_DEVICE);
this.waitForFinish();
}
// move to given position
public void aspiration(int volume) {
this.call(Command.CMD_PIPETTE_CTRL_MOVE_TO_UL, volume);
this.waitForFinish();
}
// move to given position
public void dispense(int volume) {
this.call(Command.CMD_PIPETTE_CTRL_MOVE_TO_UL, volume);
this.waitForFinish();
}
// move to given position
public void dispense() {
this.dispense(0);
}
}

1
src/main/java/com/dreamworks/boditech/driver/actuator/ActuatorModule.java

@ -2,6 +2,7 @@ package com.dreamworks.boditech.driver.actuator;
public class ActuatorModule {
public static Integer ARM_XY = 11;
public static Integer ARM_Z_MOTOR = 81;
public static Integer ARM_Z_PIPETTE = 82;
public static Integer TEST_TUBE_SHAKING_MOVE_MOTOR = 31;
public static Integer TEST_TUBE_SHAKING_ROTATE_MOTOR = 32;
public static Integer TEST_TUBE_SHAKING_CLIP_MOTOR = 33;

13
src/main/java/com/dreamworks/boditech/driver/consumable/CsmBufferTubeA.java

@ -1,5 +1,5 @@
package com.dreamworks.boditech.driver.consumable;
public class CsmBufferTubeA {
public class CsmBufferTubeA implements ReactionTube {
// area index
public Integer areaIndex;
// position
@ -8,10 +8,17 @@ public class CsmBufferTubeA {
public String projectName = "demo";
public Integer getLocationX() {
return 1000;
// @TODO: 需要根据areaIndex和position计算出x坐标
return 976;
}
public Integer getLocationY() {
return 1000;
// @TODO: 需要根据areaIndex和position计算出y坐标
return 1930;
}
// get location z
public Integer getLocationZ() {
return 800;
}
}

7
src/main/java/com/dreamworks/boditech/driver/consumable/CsmBufferTubeB.java

@ -1,5 +1,5 @@
package com.dreamworks.boditech.driver.consumable;
public class CsmBufferTubeB {
public class CsmBufferTubeB implements ReactionTube {
// area index
public Integer areaIndex;
// position
@ -14,4 +14,9 @@ public class CsmBufferTubeB {
public Integer getLocationY() {
return 0;
}
// get location z
public Integer getLocationZ() {
return 0;
}
}

5
src/main/java/com/dreamworks/boditech/driver/consumable/CsmLargeBufferTube.java

@ -15,6 +15,11 @@ public class CsmLargeBufferTube {
return 0;
}
// get location z
public Integer getLocationZ() {
return 0;
}
// get if the tube is empty
public boolean isEmpty() {
return false;

4
src/main/java/com/dreamworks/boditech/driver/consumable/CsmPipetteTip.java

@ -6,10 +6,10 @@ public class CsmPipetteTip {
public Integer position;
public Integer getLocationX() {
return 500;
return 5089;
}
public Integer getLocationY() {
return 500;
return -7;
}
}

17
src/main/java/com/dreamworks/boditech/driver/consumable/CsmSampleTube.java

@ -0,0 +1,17 @@
package com.dreamworks.boditech.driver.consumable;
public class CsmSampleTube {
// get location x
public Integer getLocationX() {
return 0;
}
// get location y
public Integer getLocationY() {
return 0;
}
// get location z
public Integer getLocationZ() {
return 1400;
}
}

11
src/main/java/com/dreamworks/boditech/driver/consumable/ReactionTube.java

@ -0,0 +1,11 @@
package com.dreamworks.boditech.driver.consumable;
public interface ReactionTube {
// get location x
public Integer getLocationX();
// get location y
public Integer getLocationY();
// get location z
public Integer getLocationZ();
}

34
src/main/java/com/dreamworks/boditech/driver/task/TaskTest.java

@ -2,6 +2,9 @@ package com.dreamworks.boditech.driver.task;
import com.dreamworks.boditech.driver.Task;
import com.dreamworks.boditech.driver.TaskExecutor;
import com.dreamworks.boditech.driver.TestStep;
import com.dreamworks.boditech.driver.consumable.CsmBufferTubeA;
import com.dreamworks.boditech.driver.consumable.CsmSampleTube;
import com.dreamworks.boditech.driver.consumable.ReactionTube;
import com.dreamworks.boditech.driver.task.step.Step;
import com.dreamworks.boditech.driver.task.step.StepManager;
@ -27,10 +30,39 @@ public class TaskTest implements Task {
public List<TestStep> steps;
// step index
public Integer stepIndex;
// reaction tube
private ReactionTube reactionTube;
// sample tube
private CsmSampleTube sampleTube;
// set reaction tube
public void setReactionTube(ReactionTube reactionTube) {
this.reactionTube = reactionTube;
}
// get reaction tube
public ReactionTube getReactionTube() {
return this.reactionTube;
}
// set sample tube
public void setSampleTube(CsmSampleTube sampleTube) {
this.sampleTube = sampleTube;
}
// get sample tube
public CsmSampleTube getSampleTube() {
return this.sampleTube;
}
@Override
public void execute(TaskExecutor executor) {
List<Step> steps = StepManager.buildSteps("[{\"action\":\"puncture\",\"tubeType\":\"A\"}]");
// @TODO : use real sample tube
this.sampleTube = new CsmSampleTube();
this.reactionTube = new CsmBufferTubeA();
List<Step> steps = StepManager.buildSteps("[{\"action\":\"sampling\",\"sourceTubeType\":\"Sample\",\"amount\":\"100\"}]");
for ( Step step : steps ) {
step.execute(executor, this);
}

1
src/main/java/com/dreamworks/boditech/driver/task/step/StepManager.java

@ -17,6 +17,7 @@ public class StepManager {
}
StepManager.stepMap.put("shake", StepShake.class);
StepManager.stepMap.put("puncture", StepPuncture.class);
StepManager.stepMap.put("sampling", StepSampling.class);
}
// build step by given name

2
src/main/java/com/dreamworks/boditech/driver/task/step/StepPuncture.java

@ -25,7 +25,7 @@ public class StepPuncture extends StepBase {
TaskTest taskTest = (TaskTest)task;
// 01. 移动到TIP区域
CsmPipetteTip tip = device.getPipeTip();
CsmPipetteTip tip = device.getPipetteTip();
armXY.moveTo(tip.getLocationX(), tip.getLocationY());
// 02. 下降到TIP区域

116
src/main/java/com/dreamworks/boditech/driver/task/step/StepSampling.java

@ -0,0 +1,116 @@
package com.dreamworks.boditech.driver.task.step;
import com.dreamworks.boditech.driver.Device;
import com.dreamworks.boditech.driver.Task;
import com.dreamworks.boditech.driver.TaskExecutor;
import com.dreamworks.boditech.driver.actuator.ActArmXY;
import com.dreamworks.boditech.driver.actuator.ActMotor;
import com.dreamworks.boditech.driver.actuator.ActPipette;
import com.dreamworks.boditech.driver.actuator.ActuatorModule;
import com.dreamworks.boditech.driver.consumable.*;
import com.dreamworks.boditech.driver.task.TaskTest;
import com.fasterxml.jackson.annotation.JsonProperty;
public class StepSampling extends StepBase {
@JsonProperty("action")
public String action;
@JsonProperty("sourceTubeType")
public String sourceTubeType;
@JsonProperty("amount")
public String amount;
@JsonProperty("dropTip")
public String dropTip = "YES";
@JsonProperty("requireNewTip")
public String requireNewTip = "YES";
@Override
public void execute(TaskExecutor executor, Task task) {
Device device = executor.getDevice();
ActPipette pipette = (ActPipette)device.getActuator(ActuatorModule.ARM_Z_PIPETTE);
ActArmXY armXY = (ActArmXY)device.getActuator(ActuatorModule.ARM_XY);
ActMotor armZMotor = (ActMotor)device.getActuator(ActuatorModule.ARM_Z_MOTOR);
TaskTest taskTest = (TaskTest)task;
// 丢弃TIP
if ( this.requireNewTip.equals("YES") && pipette.getHasTip() ) {
armXY.moveTo("tipDiscardPrepareHole");
armZMotor.moveTo("tipDiscardDepth");
armXY.moveTo("tipDiscardDrop");
armZMotor.moveTo(0);
armXY.moveTo(0, 0);
pipette.setHasTip(false);
}
// get tip
if ( !pipette.getHasTip() ) {
CsmPipetteTip tip = device.getPipetteTip();
armXY.moveTo(tip.getLocationX(), tip.getLocationY());
armZMotor.moveTo("tipPickUpDepth");
armZMotor.moveTo(0);
pipette.setHasTip(true);
}
// 1. 获取样本
// 2. 移动到样本采集位置
Integer srcTubeLocationZ = 0;
if ( this.sourceTubeType.equals("LargeBufferTube") ) {
CsmLargeBufferTube tube = device.getLargeBufferTube(taskTest.projectName);
armXY.moveTo(tube.getLocationX(), tube.getLocationY());
srcTubeLocationZ = tube.getLocationZ();
} else if ( this.sourceTubeType.equals("BufferTubeA") ) {
CsmBufferTubeA tube = device.getBufferTubeA(taskTest.projectName);
armXY.moveTo(tube.getLocationX(), tube.getLocationY());
srcTubeLocationZ = tube.getLocationZ();
} else if ( this.sourceTubeType.equals("BufferTubeB") ) {
CsmBufferTubeB tube = device.getBufferTubeB(taskTest.projectName);
armXY.moveTo(tube.getLocationX(), tube.getLocationY());
srcTubeLocationZ = tube.getLocationZ();
} else if ( this.sourceTubeType.equals("Sample") ) {
armXY.moveTo("sampleTestTube");
srcTubeLocationZ = taskTest.getSampleTube().getLocationZ();
} else {
throw new RuntimeException("unknown source tube type " + this.sourceTubeType);
}
// 3. 下降到样本采集位置
armZMotor.moveTo(srcTubeLocationZ);
// 4. 吸入样本
pipette.aspiration(Integer.parseInt(this.amount));
// 5. 上升到准备位置
armZMotor.moveTo(0);
// 6. 移动到反应试管放置位置
ReactionTube reactionTube = taskTest.getReactionTube();
armXY.moveTo(reactionTube.getLocationX(), reactionTube.getLocationY());
// 7. 下降到反应试管放置位置
armZMotor.moveTo(reactionTube.getLocationZ());
// 8. 吐出样本
pipette.dispense();
// 9. 吞吐混合均匀
int mixAmount = Integer.parseInt(this.amount);
for ( int i = 0; i < 3; i++ ) {
pipette.aspiration(mixAmount);
pipette.dispense();
}
// 10. 上升到准备位置
armZMotor.moveTo(0);
// 丢弃TIP
if ( this.dropTip.equals("YES") ) {
armXY.moveTo("tipDiscardPrepareHole");
armZMotor.moveTo("tipDiscardDepth");
armXY.moveTo("tipDiscardDrop");
armZMotor.moveTo(0);
armXY.moveTo(0, 0);
pipette.setHasTip(false);
}
}
}

8
src/main/java/com/dreamworks/boditech/mapper/OptionMapper.java

@ -0,0 +1,8 @@
package com.dreamworks.boditech.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface OptionMapper {
@Select("SELECT `value` FROM bdt_options WHERE name=#{name} LIMIT 1")
String findByName(String name);
}

18
src/main/java/com/dreamworks/boditech/service/RuntimeOptionService.java

@ -0,0 +1,18 @@
package com.dreamworks.boditech.service;
import com.dreamworks.boditech.mapper.OptionMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class RuntimeOptionService {
@Resource
private OptionMapper optionMapper;
// get integer value
public Integer getInteger(String name) {
String value = this.optionMapper.findByName(name);
if ( value == null ) {
throw new RuntimeException("option not found: " + name);
}
return Integer.parseInt(value);
}
}
Loading…
Cancel
Save