sige 1 year ago
parent
commit
5191851edd
  1. BIN
      app.db
  2. 83
      src/main/java/com/iflytop/digester/DigestionTaskThread.java
  3. 15
      src/main/java/com/iflytop/digester/controller/CameraController.java
  4. 9
      src/main/java/com/iflytop/digester/controller/DigestionTaskController.java
  5. 4
      src/main/java/com/iflytop/digester/controller/LiquidController.java
  6. 5
      src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableInstance.java
  7. 15
      src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionLiquid.java
  8. 16
      src/main/java/com/iflytop/digester/deviceinstance/TransferRobotArmInstance.java
  9. 5
      src/main/java/com/iflytop/digester/model/MdbDigestionTask.java
  10. 15
      src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbNotification.java
  11. 10
      src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbRuntimeVariable.java

BIN
app.db

83
src/main/java/com/iflytop/digester/DigestionTaskThread.java

@ -94,25 +94,38 @@ public class DigestionTaskThread extends Thread {
public void run() { public void run() {
try { try {
this.prepare(); this.prepare();
// 解析消解配方并取出首轮和末轮配置
var rounds = this.solution.getDigestionRounds(); var rounds = this.solution.getDigestionRounds();
var firstRound = rounds.remove(0);
var lastRound = rounds.remove(rounds.size() - 1);
MdbDigestionSolution.DigestionSolutionRound firstRound = null;
if ( !rounds.isEmpty() && rounds.size() > 1 ) {
firstRound = rounds.remove(0);
}
MdbDigestionSolution.DigestionSolutionRound lastRound = null;
if ( !rounds.isEmpty() ) {
lastRound = rounds.remove(rounds.size() - 1);
}
// 执行第一轮 // 执行第一轮
if ( null != firstRound ) {
this.executeRound(firstRound); this.executeRound(firstRound);
}
// 执行中间轮 // 执行中间轮
for (var round : rounds) { for (var round : rounds) {
this.executeRound(round); this.executeRound(round);
} }
// 执行最后一轮 // 执行最后一轮
if ( null != lastRound ) {
this.executeLastRound(lastRound); this.executeLastRound(lastRound);
}
this.errorProcessThread.join(); this.errorProcessThread.join();
this.updateTaskStatus("Finish", "消解任务结束"); this.updateTaskStatus("Finish", "消解任务结束");
this.finishCallback.callback(this);
} catch (Exception e) { } catch (Exception e) {
this.updateTaskStatus("Error", e.getMessage()); this.updateTaskStatus("Error", e.getMessage());
UfMdbNotification.error("消解任务执行失败 : " + e.getMessage()); UfMdbNotification.error("消解任务执行失败 : " + e.getMessage());
} finally {
this.finishCallback.callback(this);
} }
} }
@ -123,18 +136,24 @@ public class DigestionTaskThread extends Thread {
var device = Device.getInstance(); var device = Device.getInstance();
// 分配加热位 // 分配加热位
if ( "manual".equals(this.taskModel.mode) ) {
this.heatingSlot = device.heatingTurntable.getSlotByIndex(this.taskModel.heatingSlotIndex);
} else {
this.heatingSlot = device.heatingTurntable.allocSlot(this.taskModel.batchNo); this.heatingSlot = device.heatingTurntable.allocSlot(this.taskModel.batchNo);
}
this.heatingSlot.setTubes(this.taskModel.getTubes()); this.heatingSlot.setTubes(this.taskModel.getTubes());
this.taskModel.heatingSlotIndex = this.heatingSlot.index; this.taskModel.heatingSlotIndex = this.heatingSlot.index;
this.taskModel.save(); this.taskModel.save();
if ( "auto".equals(this.taskModel.mode) ) {
// 打开门 // 打开门
device.door.open(); device.door.open();
// 等待放入试管架 // 等待放入试管架
this.waitForTubeRackPutIn(false);
this.waitForTubeRackPutIn();
// 关闭门 // 关闭门
device.door.close(); device.door.close();
} }
}
// 检查试管 // 检查试管
private void tubeCheckAndMove() throws InterruptedException { private void tubeCheckAndMove() throws InterruptedException {
@ -171,7 +190,7 @@ public class DigestionTaskThread extends Thread {
if ( !this.errorTubeIndexes.isEmpty() ) { if ( !this.errorTubeIndexes.isEmpty() ) {
var device = Device.getInstance(); var device = Device.getInstance();
// 等待放入空试管架 // 等待放入空试管架
this.waitForTubeRackPutIn(true);
this.waitForEmptyTubeRackPutIn();
// 取出剩余异常试管 // 取出剩余异常试管
device.transferArm.takeOutTubesFromErrorSlot(this.errorTubeIndexes); device.transferArm.takeOutTubesFromErrorSlot(this.errorTubeIndexes);
// 等待取出试管架 // 等待取出试管架
@ -268,7 +287,8 @@ public class DigestionTaskThread extends Thread {
device.liquidAddition.addLiquidToTubes(this.heatingSlot.getExistTubeIndexes(), "water", digestionRound.waterVolume); device.liquidAddition.addLiquidToTubes(this.heatingSlot.getExistTubeIndexes(), "water", digestionRound.waterVolume);
} }
// 正常消解结束
// 正常消解结束
if ( "auto".equals(this.taskModel.mode) ) {
// 移动到加液盘 // 移动到加液盘
device.transferArm.moveTubeRackToLiquidPlate(this.heatingSlot.index); device.transferArm.moveTubeRackToLiquidPlate(this.heatingSlot.index);
// 打开门 // 打开门
@ -280,6 +300,7 @@ public class DigestionTaskThread extends Thread {
// 释放加热位 // 释放加热位
this.heatingSlot.setTubeRackNo(null); this.heatingSlot.setTubeRackNo(null);
} }
}
// 执行消解异常处理配置 // 执行消解异常处理配置
private void executeErrorRound( MdbDigestionSolution.DigestionSolutionErrorRound errorRound ) throws InterruptedException { private void executeErrorRound( MdbDigestionSolution.DigestionSolutionErrorRound errorRound ) throws InterruptedException {
@ -311,7 +332,7 @@ public class DigestionTaskThread extends Thread {
// 将试管架放入异常处理区域 // 将试管架放入异常处理区域
device.transferArm.moveTubeRackToHeatingTurntable(this.heatingSlot.index); device.transferArm.moveTubeRackToHeatingTurntable(this.heatingSlot.index);
// 等待放入空试管架 // 等待放入空试管架
this.waitForTubeRackPutIn(true);
this.waitForEmptyTubeRackPutIn();
// 取出消解完成的试管 // 取出消解完成的试管
device.transferArm.takeOutTubesFromErrorSlot(this.finishedErrorTubeIndexes); device.transferArm.takeOutTubesFromErrorSlot(this.finishedErrorTubeIndexes);
// 等待取出试管架 // 等待取出试管架
@ -321,14 +342,37 @@ public class DigestionTaskThread extends Thread {
} }
// 等待放入试管架 // 等待放入试管架
private void waitForTubeRackPutIn( Boolean requestEmptyTubeRack ) {
if ( requestEmptyTubeRack ) {
this.manager.sendMessageToTransBot("EmptyTubeRackPutIn", Map.of("batchNo", this.taskModel.batchNo));
private void waitForTubeRackPutIn() {
this.updateTaskStatus("TubeRackPutInWait", "等待放入试管架");
// 发送放入试管架消息
Map<String,Object> message = Map.of("batchNo", this.taskModel.batchNo, "taskId", this.taskModel.outTaskId);
this.manager.sendMessageToTransBot("TubeRackPutIn", message);
// 等待试管架放入完成
synchronized ( this.tubeRackPutInWaitLock ) {
try {
this.tubeRackPutInWaitLock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
this.updateTaskStatus("TubeRackPutInWaitDone", "试管架已放入");
}
// 等待放入试管架
private void waitForEmptyTubeRackPutIn() {
this.updateTaskStatus("TubeRackPutInWait", "等待放入空试管架");
// 发送放入试管架消息
Map<String,Object> message = Map.of("batchNo", this.taskModel.batchNo, "taskId", this.taskModel.outTaskId);
if ( "auto".equals(this.taskModel.mode) ) {
this.manager.sendMessageToTransBot("EmptyTubeRackPutIn", message);
} else { } else {
this.manager.sendMessageToTransBot("TubeRackPutIn", Map.of("batchNo", this.taskModel.batchNo));
UfMdbNotification.action("EmptyTubeRackPutIn", message);
} }
this.updateTaskStatus("TubeRackPutInWait", "等待放入试管架");
// 等待试管架放入完成
synchronized ( this.tubeRackPutInWaitLock ) { synchronized ( this.tubeRackPutInWaitLock ) {
try { try {
this.tubeRackPutInWaitLock.wait(); this.tubeRackPutInWaitLock.wait();
@ -341,8 +385,15 @@ public class DigestionTaskThread extends Thread {
// 等待取出试管架 // 等待取出试管架
private void waitForTubeRackTakeOut() { private void waitForTubeRackTakeOut() {
this.manager.sendMessageToTransBot("TubeRackTakeOut", Map.of("batchNo", this.taskModel.batchNo));
this.updateTaskStatus("TubeRackTakeOutWait", "等待取出试管架"); this.updateTaskStatus("TubeRackTakeOutWait", "等待取出试管架");
Map<String,Object> message = Map.of("batchNo", this.taskModel.batchNo, "taskId", this.taskModel.outTaskId);
if ( "auto".equals(this.taskModel.mode) ) {
this.manager.sendMessageToTransBot("TubeRackTakeOut", message);
} else {
UfMdbNotification.action("TubeRackTakeOut", message);
}
synchronized ( this.tubeRackTakeOutWaitLock ) { synchronized ( this.tubeRackTakeOutWaitLock ) {
try { try {
this.tubeRackTakeOutWaitLock.wait(); this.tubeRackTakeOutWaitLock.wait();
@ -356,6 +407,9 @@ public class DigestionTaskThread extends Thread {
// 拍照检查试管 // 拍照检查试管
private void takeShotAndCheckErrorTubes() { private void takeShotAndCheckErrorTubes() {
this.updateTaskStatus("TubeCheck", "拍照检查试管,等待确认异常试管"); this.updateTaskStatus("TubeCheck", "拍照检查试管,等待确认异常试管");
Map<String,Object> message = Map.of("batchNo", this.taskModel.batchNo, "taskId", this.taskModel.outTaskId);
UfMdbNotification.action("TubeCheck", message);
this.errorTubeIndexes.clear(); this.errorTubeIndexes.clear();
synchronized ( this.errorTubeIndexes ) { synchronized ( this.errorTubeIndexes ) {
try { try {
@ -370,6 +424,9 @@ public class DigestionTaskThread extends Thread {
// 拍照检查试管 // 拍照检查试管
private void takeShotAndCheckFinishedTubes() { private void takeShotAndCheckFinishedTubes() {
this.updateTaskStatus("ErrorTubeCheck", "拍照检查异常试管,等待确认完成试管"); this.updateTaskStatus("ErrorTubeCheck", "拍照检查异常试管,等待确认完成试管");
Map<String,Object> message = Map.of("batchNo", this.taskModel.batchNo, "taskId", this.taskModel.outTaskId);
UfMdbNotification.action("ErrorTubeCheck", message);
this.finishedErrorTubeIndexes.clear(); this.finishedErrorTubeIndexes.clear();
synchronized ( this.finishedErrorTubeIndexes ) { synchronized ( this.finishedErrorTubeIndexes ) {
try { try {

15
src/main/java/com/iflytop/digester/controller/CameraController.java

@ -0,0 +1,15 @@
package com.iflytop.digester.controller;
import com.iflytop.digester.underframework.controller.UfApiControllerBase;
import com.iflytop.digester.underframework.controller.UfApiResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Map;
@Controller
public class CameraController extends UfApiControllerBase {
@ResponseBody
@PostMapping("/api/camera/take-shot")
public UfApiResponse takeShot() {
return this.success(Map.of("data", "https://avatars.githubusercontent.com/u/53512912?v=4"));
}
}

9
src/main/java/com/iflytop/digester/controller/DigestionTaskController.java

@ -7,6 +7,7 @@ import com.iflytop.digester.underframework.util.UfJsonHelper;
import com.iflytop.digester.underframework.controller.UfApiControllerBase; import com.iflytop.digester.underframework.controller.UfApiControllerBase;
import com.iflytop.digester.underframework.controller.UfApiResponse; import com.iflytop.digester.underframework.controller.UfApiResponse;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@ -20,11 +21,13 @@ public class DigestionTaskController extends UfApiControllerBase {
@ResponseBody @ResponseBody
@PostMapping("/api/digestion-task/start") @PostMapping("/api/digestion-task/start")
public UfApiResponse start(@RequestBody Map<String,Object> params) {
public UfApiResponse start(HttpServletRequest request, @RequestBody Map<String,Object> params) {
String taskId = (String)params.get("taskId"); String taskId = (String)params.get("taskId");
String name = (String)params.get("name"); String name = (String)params.get("name");
String batchNo = (String)params.get("batchNo"); String batchNo = (String)params.get("batchNo");
List<Map<String,Object>> tubes = (List<Map<String,Object>>)params.get("tubes"); List<Map<String,Object>> tubes = (List<Map<String,Object>>)params.get("tubes");
String mode = (String)params.get("mode");
Integer slotIndex = (Integer)params.get("slotIndex");
var digestion = UfActiveRecord.findOne(MdbDigestionSolution.class, Map.of("name", name)); var digestion = UfActiveRecord.findOne(MdbDigestionSolution.class, Map.of("name", name));
if ( null == digestion ) { if ( null == digestion ) {
@ -39,7 +42,9 @@ public class DigestionTaskController extends UfApiControllerBase {
task.status = "pending"; task.status = "pending";
task.message = "等待中"; task.message = "等待中";
task.startedAt = (int)(System.currentTimeMillis() / 1000); task.startedAt = (int)(System.currentTimeMillis() / 1000);
task.startedBy = 0;
task.startedBy = this.getUserFromRequest(request).id;
task.mode = mode;
task.heatingSlotIndex = slotIndex;
task.save(); task.save();
this.taskManager.startTask(task); this.taskManager.startTask(task);

4
src/main/java/com/iflytop/digester/controller/LiquidController.java

@ -26,8 +26,8 @@ public class LiquidController extends UfApiControllerBase {
Integer bucketIndex = (Integer)params.get("index"); Integer bucketIndex = (Integer)params.get("index");
String liquidType = (String)params.get("type"); String liquidType = (String)params.get("type");
var bucket = this.device.liquidAddition.getLiquidByIndex(bucketIndex); var bucket = this.device.liquidAddition.getLiquidByIndex(bucketIndex);
bucket.type = liquidType;
bucket.volume = bucket.totalVolume;
bucket.setType(liquidType);
bucket.setVolume(bucket.totalVolume);
return this.success(); return this.success();
} }
} }

5
src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableInstance.java

@ -22,6 +22,11 @@ public class HeatingTurntableInstance {
return slots; return slots;
} }
// 根据索引获取槽位
public HeatingTurntableSlot getSlotByIndex(Integer index) {
return slots.get(index);
}
public HeatingTurntableSlot getSlotByLiquidPlateTubeRack() { public HeatingTurntableSlot getSlotByLiquidPlateTubeRack() {
for (HeatingTurntableSlot slot : slots) { for (HeatingTurntableSlot slot : slots) {
if (null != slot.tubeRackNo && slot.tubeRackLocation.equals("liquid-plate")) { if (null != slot.tubeRackNo && slot.tubeRackLocation.equals("liquid-plate")) {

15
src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionLiquid.java

@ -1,4 +1,7 @@
package com.iflytop.digester.deviceinstance; package com.iflytop.digester.deviceinstance;
import com.iflytop.digester.underframework.dao.model.UfMdbRuntimeVariable;
public class LiquidAdditionLiquid { public class LiquidAdditionLiquid {
// bucket index // bucket index
public Integer bucketIndex; public Integer bucketIndex;
@ -8,4 +11,16 @@ public class LiquidAdditionLiquid {
public Integer volume; public Integer volume;
// total volume // total volume
public Integer totalVolume; public Integer totalVolume;
// set type
public void setType( String type ) {
this.type = type;
UfMdbRuntimeVariable.setString(String.format("LiquidBucketType.%d", this.bucketIndex), type);
}
// set volume
public void setVolume( Integer volume ) {
this.volume = volume;
UfMdbRuntimeVariable.setInteger(String.format("LiquidBucketVolume.%d", this.bucketIndex), volume);
}
} }

16
src/main/java/com/iflytop/digester/deviceinstance/TransferRobotArmInstance.java

@ -3,6 +3,8 @@ import com.iflytop.digester.underframework.UfCmdSnippetExecutor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
@Component @Component
public class TransferRobotArmInstance { public class TransferRobotArmInstance {
// 等待锁队列 // 等待锁队列
@ -16,7 +18,12 @@ public class TransferRobotArmInstance {
// 执行从异常槽位取出试管 // 执行从异常槽位取出试管
UfCmdSnippetExecutor.execute("TubeTakeOutFromErrorSlotStart"); UfCmdSnippetExecutor.execute("TubeTakeOutFromErrorSlotStart");
for (Integer tubeIndex : tubeIndexes) { for (Integer tubeIndex : tubeIndexes) {
UfCmdSnippetExecutor.execute("TubeTakeOutFromErrorSlot." + tubeIndex);
UfCmdSnippetExecutor.execute("TubeTakeOutFromErrorSlot", Map.of(
"MotorLiquidPlatePos", 100,
"MotorArmLeftRightSrcPos", 100,
"MotorArmLeftRightDstPos", 100,
"MotorHeatingTurntablePos", 100
));
} }
UfCmdSnippetExecutor.execute("TubeTakeOutFromErrorSlotEnd"); UfCmdSnippetExecutor.execute("TubeTakeOutFromErrorSlotEnd");
@ -31,7 +38,12 @@ public class TransferRobotArmInstance {
// 执行移动试管到异常槽位 // 执行移动试管到异常槽位
UfCmdSnippetExecutor.execute("TubeMoveToErrorSlotStart"); UfCmdSnippetExecutor.execute("TubeMoveToErrorSlotStart");
for (Integer tubeIndex : tubeIndexes) { for (Integer tubeIndex : tubeIndexes) {
UfCmdSnippetExecutor.execute("TubeMoveToErrorSlot." + tubeIndex);
UfCmdSnippetExecutor.execute("TubeMoveToErrorSlot", Map.of(
"MotorLiquidPlatePos", 100,
"MotorArmLeftRightSrcPos", 100,
"MotorArmLeftRightDstPos", 100,
"MotorHeatingTurntablePos", 100
));
} }
UfCmdSnippetExecutor.execute("TubeMoveToErrorSlotEnd"); UfCmdSnippetExecutor.execute("TubeMoveToErrorSlotEnd");

5
src/main/java/com/iflytop/digester/model/MdbDigestionTask.java

@ -30,7 +30,7 @@ public class MdbDigestionTask extends UfActiveRecord {
public Integer startedAt; public Integer startedAt;
@UfActiveRecordField @UfActiveRecordField
public Integer startedBy;
public String startedBy;
@UfActiveRecordField @UfActiveRecordField
public Integer finishedAt = 0; public Integer finishedAt = 0;
@ -38,6 +38,9 @@ public class MdbDigestionTask extends UfActiveRecord {
@UfActiveRecordField @UfActiveRecordField
public Integer heatingSlotIndex = -1; public Integer heatingSlotIndex = -1;
@UfActiveRecordField
public String mode;
// get table name // get table name
public static String getTableName() { public static String getTableName() {
return "app_digestion_tasks"; return "app_digestion_tasks";

15
src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbNotification.java

@ -1,6 +1,10 @@
package com.iflytop.digester.underframework.dao.model; package com.iflytop.digester.underframework.dao.model;
import com.iflytop.digester.underframework.dao.record.UfActiveRecord; import com.iflytop.digester.underframework.dao.record.UfActiveRecord;
import com.iflytop.digester.underframework.dao.record.UfActiveRecordField; import com.iflytop.digester.underframework.dao.record.UfActiveRecordField;
import com.iflytop.digester.underframework.util.UfJsonHelper;
import java.util.Map;
public class UfMdbNotification extends UfActiveRecord { public class UfMdbNotification extends UfActiveRecord {
@UfActiveRecordField @UfActiveRecordField
public String type; public String type;
@ -59,4 +63,15 @@ public class UfMdbNotification extends UfActiveRecord {
notification.status = "new"; notification.status = "new";
notification.save(); notification.save();
} }
// notify action
public static void action( String action, Map<String,Object> params) {
var data = Map.of("action", action, "params", params);
var dataJson = UfJsonHelper.objectToJson(data);
var notification = new UfMdbNotification();
notification.type = "action";
notification.data = dataJson;
notification.status = "new";
notification.save();
}
} }

10
src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbRuntimeVariable.java

@ -42,19 +42,19 @@ public class UfMdbRuntimeVariable extends UfActiveRecord {
} }
// set string // set string
public static void setString(String value, String name, Object ... args ) {
var variable = UfMdbRuntimeVariable.getVariable(name, args);
public static void setString(String name, String value) {
var variable = UfActiveRecord.findOne(UfMdbRuntimeVariable.class, Map.of("key", name));
if ( null == variable ) { if ( null == variable ) {
variable = new UfMdbRuntimeVariable(); variable = new UfMdbRuntimeVariable();
variable.key = UfMdbRuntimeVariable.buildKey(name, args);
variable.key = name;
} }
variable.value = value; variable.value = value;
variable.save(); variable.save();
} }
// set integer // set integer
public static void setInteger(Integer value, String name, Object ... args ) {
UfMdbRuntimeVariable.setString(value.toString(), name, args);
public static void setInteger(String name, Integer value) {
UfMdbRuntimeVariable.setString(name, value.toString());
} }
// remove // remove

Loading…
Cancel
Save