sige 1 year ago
parent
commit
e8d8807871
  1. BIN
      app.db
  2. 194
      src/main/java/com/iflytop/digester/StartResetTaskThread.java
  3. 19
      src/main/java/com/iflytop/digester/controller/DeviceController.java
  4. 24
      src/main/java/com/iflytop/digester/underframework/UfActuatorCmdExecutor.java
  5. 10
      src/main/java/com/iflytop/digester/underframework/connection/UfZcancmderWebsocket.java
  6. 8
      src/main/java/com/iflytop/digester/underframework/controller/TsApiActuator.java
  7. 3
      src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbActuator.java
  8. 2
      src/main/resources/application.yml
  9. 2
      web

BIN
app.db

194
src/main/java/com/iflytop/digester/StartResetTaskThread.java

@ -1,9 +1,24 @@
package com.iflytop.digester;
import com.iflytop.digester.deviceinstance.Device;
import com.iflytop.digester.underframework.UfActuatorCmdExecutor;
import com.iflytop.digester.underframework.UfApplication;
import com.iflytop.digester.underframework.UfCmdSnippetExecutor;
import com.iflytop.digester.underframework.dao.model.UfMdbNotification;
import com.iflytop.digester.underframework.dao.model.UfMdbOption;
import com.iflytop.digester.underframework.dao.model.UfMdbRuntimeVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
public class StartResetTaskThread extends Thread {
// logger
public static final Logger LOG = LoggerFactory.getLogger(StartResetTaskThread.class);
// 是否需要放置异常处理试管架
private Boolean isErrorTubeRackRequired = true;
// pause lock
private final Object pauseLock = new Object();
@Override
public void run() {
@ -11,57 +26,15 @@ public class StartResetTaskThread extends Thread {
device.setStatus("preparing");
this.setProgressMessage("设备初始化...");
UfCmdSnippetExecutor.execute("StartResetInitDevices");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// this.getDevice().getIO().setValue("LightRed", 1);
//
// this.setProgressMessage("设备初始化 : 关闭设备门");
// DiActMotor doorMotor = this.getActuator(MyDevice.ACT_DOOR_MOTOR, DiActMotor.class);
// doorMotor.setEnable(true);
// MoveDoorClose.execute(this.getDevice());
//
// this.setProgressMessage("设备初始化 : 加液臂复位");
// DiActMotor liquidMotor = this.getActuator(MyDevice.ACT_LIQUID_MOTOR, DiActMotor.class);
// liquidMotor.setEnable(true);
// liquidMotor.reset();
// liquidMotor.moveTo("LiquidArmStandby");
//
// this.setProgressMessage("设备初始化 : 关闭夹爪");
// DiActServo transferClipServo = this.getActuator(MyDevice.ACT_TRANSFER_CLIP_SERVO, DiActServo.class);
// transferClipServo.setEnable(true);
// transferClipServo.moveTo("TransClipServoClose");
//
// this.setProgressMessage("设备初始化 : 搬运机械臂上下移动复位");
// DiActMotor transUdMotor = this.getActuator(MyDevice.ACT_TRANSFER_UD_MOTOR, DiActMotor.class);
// transUdMotor.setEnable(true);
// transUdMotor.reset();
// transUdMotor.moveTo("TransUdMotorStandby");
//
// this.setProgressMessage("设备初始化 : 搬运机械臂左右移动复位");
// DiActMotor transLrMotor = this.getActuator(MyDevice.ACT_TRANSFER_LR_MOTOR, DiActMotor.class);
// transLrMotor.setEnable(true);
// transLrMotor.reset();
// transLrMotor.setMoveOffset("TransLrMotorGlobalOffset");
// transLrMotor.moveTo("TransLrMotorStandby");
//
// // @TODO : http://127.0.0.1:5566/issues/39
// this.setProgressMessage("设备初始化 : 加液转盘复位");
// DiActMotor liquidPlateMotor = this.getActuator(MyDevice.ACT_LIQUID_PLATE_MOTOR, DiActMotor.class);
// liquidPlateMotor.setEnable(true);
// liquidPlateMotor.reset();
//
// // @TODO : http://127.0.0.1:5566/issues/40
// this.setProgressMessage("设备初始化 : 加热盘转盘复位");
// DiActMotor heatPlateMotor = this.getActuator(MyDevice.ACT_HEAT_PLATE_MOTOR, DiActMotor.class);
// heatPlateMotor.setEnable(true);
// heatPlateMotor.reset();
// heatPlateMotor.moveTo("HeatPlateStandby");
//
// this.setupHeatingSlotCover();
this.setupHeatingSlotCover();
// this.setupPeristalticPump();
//
// this.setProgressMessage("设备初始化 : 相机");
@ -146,63 +119,60 @@ public class StartResetTaskThread extends Thread {
// MoveDoorClose.execute(this.getDevice());
// }
//
// /**
// * 清理试管架
// * @issue : <a href="http://127.0.0.1:5566/issues/85">无法获取加液位置是否存在试管架</a>
// */
// private void setupHeatingSlotCover() {
// boolean isDoorOpen = false;
// Integer errorSlotIndex = this.getDevice().getEnv().getProperty("app.errorSlotIndex",Integer.class);
//
// for ( int i=0; i<5; i++ ) {
// this.setProgressMessage("设备初始化 : 检查试管架 " + (i+1) + "/5");
// String key = "HeatingPlateMotorSlotCover_" + i;
// DiActServo heatSlotCoverServo = this.getActuator(key, DiActServo.class);
// heatSlotCoverServo.setEnable(true);
// var currentPos = heatSlotCoverServo.getCurrentPos();
// LOG.info("HeatingPlateMotorSlotCover #{} : current pos = {}", i, currentPos);
//
// // 如果是空的则初始化位置后继续下一步
// var rackExistsPos = heatSlotCoverServo.getLocationValue("HeatingPlateMotorSlotCoverRackExists");
// if ( currentPos > rackExistsPos ) {
// heatSlotCoverServo.setCurrentPosAsMiddle();
// continue;
// }
//
// // 如果是空试管架 又是异常区域则不处理 因为异常区域始终要有个试管架
// var emptyRackExistsPos = heatSlotCoverServo.getLocationValue("HeatingPlateMotorSlotCoverEmptyRackExists");
// if ( currentPos > emptyRackExistsPos && null != errorSlotIndex && errorSlotIndex == i ) { // 异常区域存在空试管架
// this.isErrorTubeRackRequired = false;
// continue;
// }
//
// var moveToLiquidPlate = new MoveMoveTubeRackFromHeatPlateToLiquidPlate();
// moveToLiquidPlate.setDevice(this.getDevice());
// moveToLiquidPlate.slotIndex = i;
// moveToLiquidPlate.updateSlotStatus = false;
// moveToLiquidPlate.run();
//
// if ( !isDoorOpen ) {
// MoveDoorOpen.execute(this.getDevice());
// isDoorOpen = true;
// }
//
// heatSlotCoverServo.moveTo("HeatingPlateMotorSlotCoverEmpty");
// heatSlotCoverServo.setEnable(false);
//
// // 等待取出试管架
// DiMdbNotification.taskAction(this, "TaskStartResetErrorTubeRackTakeOut");
// this.waitAction("TaskStartResetErrorTubeRackTakeOut");
// LOG.info("HeatingPlateMotorSlotCover #{} : take out", i);
//
// heatSlotCoverServo.setEnable(true);
// heatSlotCoverServo.setCurrentPosAsMiddle();
// }
//
// if ( isDoorOpen ) {
// MoveDoorClose.execute(this.getDevice());
// }
// }
/**
* 清理试管架
* @issue : <a href="http://127.0.0.1:5566/issues/85">无法获取加液位置是否存在试管架</a>
*/
private void setupHeatingSlotCover() {
boolean isDoorOpen = false;
Integer errorSlotIndex = UfApplication.getApp().getEnv().getProperty("app.errorSlotIndex", Integer.class);
for ( int i=0; i<5; i++ ) {
this.setProgressMessage("设备初始化 : 检查试管架 " + (i+1) + "/5");
UfCmdSnippetExecutor.execute(String.format("HeatingSlotCoverEnable.%d",i));
var actuatorKey = String.format("HeatingPlateMotorSlotCover_%d", i);
var currentPosStr = UfActuatorCmdExecutor.execute(actuatorKey, "motor_read_pos");
var currentPos = Integer.parseInt(currentPosStr);
LOG.info("HeatingPlateMotorSlotCover #{} : current pos = {}", i, currentPos);
// 如果是空的则初始化位置后继续下一步
var rackExistsPos = UfMdbOption.getInteger("HeatingPlateMotorSlotCoverRackExists", 0);
if ( currentPos > rackExistsPos ) {
UfActuatorCmdExecutor.execute(actuatorKey, "motor_easy_set_current_pos", "2047");
continue;
}
// 如果是空试管架 又是异常区域则不处理 因为异常区域始终要有个试管架
var emptyRackExistsPos = UfMdbOption.getInteger("HeatingPlateMotorSlotCoverEmptyRackExists", 0);
if ( currentPos > emptyRackExistsPos && null != errorSlotIndex && errorSlotIndex == i ) { // 异常区域存在空试管架
this.isErrorTubeRackRequired = false;
continue;
}
// 将试管架移至加液盘
UfCmdSnippetExecutor.execute(String.format("TubeRackMoveToLiquidPlate.%d", i));
// 打开柜门
if ( !isDoorOpen ) {
UfCmdSnippetExecutor.execute("DoorOpen");
isDoorOpen = true;
}
// 禁用该区位密封盖用于后续重置状态
UfCmdSnippetExecutor.execute(String.format("HeatingSlotCoverDisable.%d", i));
// 等待取出试管架
UfMdbNotification.action("StartResetTubeRackTakeOut", new HashMap<>());
this.waitAction("TaskStartResetErrorTubeRackTakeOut");
LOG.info("HeatingPlateMotorSlotCover #{} : take out", i);
// 重新启用密封盖
UfCmdSnippetExecutor.execute(String.format("HeatingSlotCoverEnable.%d", i));
UfCmdSnippetExecutor.execute(String.format("HeatingSlotCoverServoSetCurPosAsMiddle.%d", i));
}
if ( isDoorOpen ) {
UfCmdSnippetExecutor.execute("DoorClose");
}
}
//
// // 异常处理位试管架取出
// public void actionErrorTubeRackTakeOut() {
@ -241,6 +211,26 @@ public class StartResetTaskThread extends Thread {
// action.finish();
// }
// wait for continue
private void waitAction( String key ) {
LOG.info("Start reset wait for action : {}", key);
synchronized (pauseLock) {
try {
pauseLock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
// execute action
public void executeAction( String key ) {
LOG.info("Start reset execute action : {}", key);
synchronized (pauseLock) {
pauseLock.notifyAll();
}
}
// set progress message
private void setProgressMessage(String message) {
UfMdbRuntimeVariable.setString(message, "device.start.message");

19
src/main/java/com/iflytop/digester/controller/DeviceController.java

@ -6,11 +6,18 @@ import com.iflytop.digester.underframework.controller.UfApiResponse;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Map;
@Controller
public class DeviceController extends UfApiControllerBase {
@Resource
private Device device;
// start reset task thread
private StartResetTaskThread startReset = null;
@ResponseBody
@PostMapping("/api/device/start")
@ -18,8 +25,16 @@ public class DeviceController extends UfApiControllerBase {
if (!"new".equals(this.device.getStatus())) {
return this.error("当前设备无法执行启动操作");
}
var startReset = new StartResetTaskThread();
startReset.start();
this.startReset = new StartResetTaskThread();
this.startReset.start();
return this.success();
}
@ResponseBody
@PostMapping("/api/device/start-action-execute")
public UfApiResponse startActionExecute(@RequestBody Map<String, Object> params) {
String action = (String)params.get("action");
this.startReset.executeAction(action);
return this.success();
}

24
src/main/java/com/iflytop/digester/underframework/UfActuatorCmdExecutor.java

@ -1,9 +1,33 @@
package com.iflytop.digester.underframework;
import com.iflytop.digester.underframework.dao.model.UfMdbActuator;
import com.iflytop.digester.underframework.dao.model.UfMdbActuatorCmd;
import com.iflytop.digester.underframework.dao.record.UfActiveRecord;
import java.util.Map;
public class UfActuatorCmdExecutor {
// execute cmd
public static String execute(UfMdbActuatorCmd cmd) {
var con = UfApplication.getApp().connections.get(cmd.connectionKey);
return con.execute(cmd);
}
// execute cmd
public static String execute(String actuatorKey, String cmdKey, String cmdParams ) {
var actuator = UfActiveRecord.findOne(UfMdbActuator.class, Map.of("key", actuatorKey));
if ( null == actuator ) {
throw new RuntimeException("无效的设备KEY :" + actuatorKey);
}
var command = UfActiveRecord.findOne(UfMdbActuatorCmd.class, Map.of("cmdKey", cmdKey, "actuatorId", actuator.id));
if ( null == command ) {
throw new RuntimeException("无效的命令KEY :" + cmdKey);
}
if ( null != cmdParams ) {
command.parameters = cmdParams;
}
return execute(command);
}
// execute cmd
public static String execute(String actuatorKey, String cmdKey) {
return execute(actuatorKey, cmdKey, null);
}
}

10
src/main/java/com/iflytop/digester/underframework/connection/UfZcancmderWebsocket.java

@ -1,5 +1,5 @@
package com.iflytop.digester.underframework.connection;
import com.iflytop.digester.underframework.dao.model.TsMdbActuator;
import com.iflytop.digester.underframework.dao.model.UfMdbActuator;
import com.iflytop.digester.underframework.dao.model.UfMdbActuatorCmd;
import com.iflytop.digester.underframework.dao.record.UfActiveRecord;
import com.iflytop.digester.underframework.util.TsByteBuffer;
@ -109,7 +109,7 @@ public class UfZcancmderWebsocket extends UfConnectionBase {
}
if ( null == this.response ) {
var actuator = UfActiveRecord.findOne(TsMdbActuator.class, actuatorCmd.actuatorId);
var actuator = UfActiveRecord.findOne(UfMdbActuator.class, actuatorCmd.actuatorId);
throw new RuntimeException(String.format("设备 [%s] 响应超时: %s", actuator.name, actuatorCmd.cmdKey));
}
@ -153,7 +153,7 @@ public class UfZcancmderWebsocket extends UfConnectionBase {
private void sendCommandRequest(UfMdbActuatorCmd actuatorCmd) {
String cmd = this.buildCommand(actuatorCmd);
TsMdbActuator actuator = TsMdbActuator.findOne(TsMdbActuator.class, actuatorCmd.actuatorId);
UfMdbActuator actuator = UfMdbActuator.findOne(UfMdbActuator.class, actuatorCmd.actuatorId);
LOG.info("[Command-Executor:{}] {}({}) => {}", actuator.name, actuatorCmd.cmdKey, actuatorCmd.parameters, cmd);
if ( !this.client.isOpen() ) {
throw new RuntimeException("ZCanCmder 连接已断开");
@ -177,7 +177,7 @@ public class UfZcancmderWebsocket extends UfConnectionBase {
paramList = List.of(params.split(","));
}
TsMdbActuator actuator = TsMdbActuator.findOne(TsMdbActuator.class, actuatorCmd.actuatorId);
UfMdbActuator actuator = UfMdbActuator.findOne(UfMdbActuator.class, actuatorCmd.actuatorId);
int moduleId = Integer.parseInt(actuatorCmd.cmdFlags);
int cmdId = Integer.parseInt(actuatorCmd.cmdId, 16);
@ -283,7 +283,7 @@ public class UfZcancmderWebsocket extends UfConnectionBase {
this.executeDeviceCommand(command);
this.waitForActuatorFinish(command);
var actuator = UfActiveRecord.findOne(TsMdbActuator.class, command.actuatorId);
var actuator = UfActiveRecord.findOne(UfMdbActuator.class, command.actuatorId);
var encoderAvailable = actuator.getProperty("encoderAvailable");
if ( null == encoderAvailable || !encoderAvailable.asBoolean() ) {
return ;

8
src/main/java/com/iflytop/digester/underframework/controller/TsApiActuator.java

@ -1,7 +1,7 @@
package com.iflytop.digester.underframework.controller;
import com.iflytop.digester.underframework.dao.record.UfActiveRecord;
import com.iflytop.digester.underframework.dao.record.UfActiveRecordCriteria;
import com.iflytop.digester.underframework.dao.model.TsMdbActuator;
import com.iflytop.digester.underframework.dao.model.UfMdbActuator;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -15,13 +15,13 @@ public class TsApiActuator extends UfApiControllerBase {
String moduleId = (String) params.get("moduleId");
var criteria = new UfActiveRecordCriteria();
criteria.conditions = Map.of("moduleId", moduleId);
var items = UfActiveRecord.find(TsMdbActuator.class, criteria);
var items = UfActiveRecord.find(UfMdbActuator.class, criteria);
return success(items);
}
@PostMapping("/api/actuator/save")
@ResponseBody
public UfApiResponse save(@RequestBody TsMdbActuator actuator ) {
public UfApiResponse save(@RequestBody UfMdbActuator actuator ) {
if ( null != actuator.id ) {
actuator.isNewRecord = false;
}
@ -31,7 +31,7 @@ public class TsApiActuator extends UfApiControllerBase {
@PostMapping("/api/actuator/delete")
@ResponseBody
public UfApiResponse delete(@RequestBody TsMdbActuator actuator ) {
public UfApiResponse delete(@RequestBody UfMdbActuator actuator ) {
actuator.delete();
return success();
}

3
src/main/java/com/iflytop/digester/underframework/dao/model/TsMdbActuator.java → src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbActuator.java

@ -2,13 +2,12 @@ package com.iflytop.digester.underframework.dao.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iflytop.digester.deviceinstance.HeatingTurntableSlotTube;
import com.iflytop.digester.underframework.dao.record.UfActiveRecord;
import com.iflytop.digester.underframework.dao.record.UfActiveRecordField;
/*
底层资源比如电机传感器等
*/
public class TsMdbActuator extends UfActiveRecord {
public class UfMdbActuator extends UfActiveRecord {
@UfActiveRecordField
public String moduleId;

2
src/main/resources/application.yml

@ -31,3 +31,5 @@ mqtt-broker:
my-topic : "stw-a80"
transbot-topic : "transbot"
app :
errorSlotIndex : 4

2
web

@ -1 +1 @@
Subproject commit e2b87526304961b2bac163b58e372fd54ebffdb3
Subproject commit 2b865293c1311ba5bcefddcb1df3ac83a97799ef
Loading…
Cancel
Save