|
@ -16,7 +16,6 @@ import com.qyft.ms.system.common.constant.CommandStatus; |
|
|
import com.qyft.ms.system.common.device.command.CommandFuture; |
|
|
import com.qyft.ms.system.common.device.command.CommandFuture; |
|
|
import com.qyft.ms.system.common.device.command.DeviceCommandGenerator; |
|
|
import com.qyft.ms.system.common.device.command.DeviceCommandGenerator; |
|
|
import com.qyft.ms.system.common.device.command.FrontResponseGenerator; |
|
|
import com.qyft.ms.system.common.device.command.FrontResponseGenerator; |
|
|
import com.qyft.ms.system.common.utils.TimeUtils; |
|
|
|
|
|
import com.qyft.ms.system.model.bo.DeviceCommand; |
|
|
import com.qyft.ms.system.model.bo.DeviceCommand; |
|
|
import com.qyft.ms.system.service.WebSocketService; |
|
|
import com.qyft.ms.system.service.WebSocketService; |
|
|
import com.qyft.ms.system.service.device.DeviceCommandService; |
|
|
import com.qyft.ms.system.service.device.DeviceCommandService; |
|
@ -82,10 +81,9 @@ public class SprayTaskExecutor { |
|
|
sprayTask.setFinishTimeMap(finishTimeMap); |
|
|
sprayTask.setFinishTimeMap(finishTimeMap); |
|
|
List<SprayTaskParams> sprayTaskParams = sprayTask.getSprayTaskParams(); |
|
|
List<SprayTaskParams> sprayTaskParams = sprayTask.getSprayTaskParams(); |
|
|
for (SprayTaskParams sprayTaskParam : sprayTaskParams) {//循环玻片 |
|
|
for (SprayTaskParams sprayTaskParam : sprayTaskParams) {//循环玻片 |
|
|
if (sprayTask.getCurrentIndex() != null && sprayTaskParam.getIndex() < sprayTask.getCurrentIndex()) {//喷涂过的玻片跳过 |
|
|
|
|
|
|
|
|
if (sprayTask.getCurrentIndex() != null && sprayTaskParam.getIndex() <= sprayTask.getCurrentIndex()) {//喷涂过的玻片跳过 |
|
|
continue; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
sprayTask.setCurrentIndex(sprayTaskParam.getIndex()); |
|
|
|
|
|
int sprayNum = 1; //当前玻片是第几次喷涂 |
|
|
int sprayNum = 1; //当前玻片是第几次喷涂 |
|
|
sprayTask.setCurrentCountSprayNum(1); |
|
|
sprayTask.setCurrentCountSprayNum(1); |
|
|
for (SprayTimes sprayTimes : sprayTaskParam.getTimes()) {//每个拨片有多次喷涂,循环每次喷涂 |
|
|
for (SprayTimes sprayTimes : sprayTaskParam.getTimes()) {//每个拨片有多次喷涂,循环每次喷涂 |
|
@ -128,20 +126,21 @@ public class SprayTaskExecutor { |
|
|
double cacheYPoint = -1; |
|
|
double cacheYPoint = -1; |
|
|
int currentStep = 0; //记录当前线程喷涂步骤序号 |
|
|
int currentStep = 0; //记录当前线程喷涂步骤序号 |
|
|
for (SprayTaskStep sprayTaskStep : sprayTaskStepList) {//因为田字格喷涂其实是两次 |
|
|
for (SprayTaskStep sprayTaskStep : sprayTaskStepList) {//因为田字格喷涂其实是两次 |
|
|
DeviceCommand nozzleValveOpenCommand = DeviceCommandGenerator.nozzleValveOpen();//开启喷嘴阀 |
|
|
|
|
|
CommandFuture nozzleValveOpenCommandFuture = deviceCommandService.sendCommand(sprayTask.getCmdId(), sprayTask.getCmdCode(), nozzleValveOpenCommand); |
|
|
|
|
|
commandWait(nozzleValveOpenCommandFuture); |
|
|
|
|
|
|
|
|
|
|
|
DeviceCommand syringePumpForwardCommand = DeviceCommandGenerator.syringePumpForward(sprayTimes.getVolume());//推动移动注射泵 |
|
|
|
|
|
CommandFuture syringePumpForwardCommandFuture = deviceCommandService.sendCommandSprayTask(sprayTask.getCmdId(), sprayTask.getCmdCode(), syringePumpForwardCommand); |
|
|
|
|
|
commandWait(syringePumpForwardCommandFuture); |
|
|
|
|
|
|
|
|
|
|
|
if (sprayTimes.getHighVoltage()) {//加电 |
|
|
|
|
|
DeviceCommand highVoltageOpenCommand = DeviceCommandGenerator.highVoltageOpen(sprayTimes.getHighVoltageValue());//开启高压 |
|
|
|
|
|
CommandFuture highVoltageOpenCommandFuture = deviceCommandService.sendCommand(sprayTask.getCmdId(), sprayTask.getCmdCode(), highVoltageOpenCommand); |
|
|
|
|
|
commandWait(highVoltageOpenCommandFuture); |
|
|
|
|
|
|
|
|
if (currentStep >= sprayTask.getCurrentStep()) { |
|
|
|
|
|
DeviceCommand nozzleValveOpenCommand = DeviceCommandGenerator.nozzleValveOpen();//开启喷嘴阀 |
|
|
|
|
|
CommandFuture nozzleValveOpenCommandFuture = deviceCommandService.sendCommand(sprayTask.getCmdId(), sprayTask.getCmdCode(), nozzleValveOpenCommand); |
|
|
|
|
|
commandWait(nozzleValveOpenCommandFuture); |
|
|
|
|
|
|
|
|
|
|
|
DeviceCommand syringePumpForwardCommand = DeviceCommandGenerator.syringePumpForward(sprayTimes.getVolume());//推动移动注射泵 |
|
|
|
|
|
CommandFuture syringePumpForwardCommandFuture = deviceCommandService.sendCommandSprayTask(sprayTask.getCmdId(), sprayTask.getCmdCode(), syringePumpForwardCommand); |
|
|
|
|
|
commandWait(syringePumpForwardCommandFuture); |
|
|
|
|
|
|
|
|
|
|
|
if (sprayTimes.getHighVoltage()) {//加电 |
|
|
|
|
|
DeviceCommand highVoltageOpenCommand = DeviceCommandGenerator.highVoltageOpen(sprayTimes.getHighVoltageValue());//开启高压 |
|
|
|
|
|
CommandFuture highVoltageOpenCommandFuture = deviceCommandService.sendCommand(sprayTask.getCmdId(), sprayTask.getCmdCode(), highVoltageOpenCommand); |
|
|
|
|
|
commandWait(highVoltageOpenCommandFuture); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (int i = 0; i < sprayTaskStep.getSprayPathPointList().size(); i++) {//循环路线 |
|
|
for (int i = 0; i < sprayTaskStep.getSprayPathPointList().size(); i++) {//循环路线 |
|
|
if (currentStep < sprayTask.getCurrentStep()) { |
|
|
if (currentStep < sprayTask.getCurrentStep()) { |
|
|
currentStep++; |
|
|
currentStep++; |
|
@ -189,6 +188,7 @@ public class SprayTaskExecutor { |
|
|
sprayTask.setSprayNum(sprayNum); |
|
|
sprayTask.setSprayNum(sprayNum); |
|
|
sprayTask.setCurrentStep(0); |
|
|
sprayTask.setCurrentStep(0); |
|
|
} |
|
|
} |
|
|
|
|
|
sprayTask.setCurrentIndex(sprayTaskParam.getIndex()); |
|
|
sprayTask.setSprayNum(0); |
|
|
sprayTask.setSprayNum(0); |
|
|
} |
|
|
} |
|
|
//喷涂完毕 |
|
|
//喷涂完毕 |
|
@ -319,14 +319,17 @@ public class SprayTaskExecutor { |
|
|
List<SprayTaskParams> params = task.getSprayTaskParams(); |
|
|
List<SprayTaskParams> params = task.getSprayTaskParams(); |
|
|
int resumeIndex = task.getCurrentIndex() == null ? 0 : task.getCurrentIndex(); |
|
|
int resumeIndex = task.getCurrentIndex() == null ? 0 : task.getCurrentIndex(); |
|
|
int resumeSprayNum = task.getSprayNum(); |
|
|
int resumeSprayNum = task.getSprayNum(); |
|
|
|
|
|
|
|
|
// 常量 |
|
|
|
|
|
final long COMMAND_LATENCY_MS = 12;// 指令往返平均耗时(ms) |
|
|
|
|
|
final double HOME_SPEED_X = 20;// 回原点速度 X 轴 (mm/s) |
|
|
|
|
|
final double HOME_SPEED_Y = 20;// 回原点速度 Y 轴 (mm/s) |
|
|
|
|
|
final double HOME_SPEED_Z = 20;// 回原点速度 Z 轴 (mm/s) |
|
|
|
|
|
final long PER_SPRAY_OVERHEAD_MS = 1;// 每次喷涂固定附加时间(ms) |
|
|
|
|
|
final long TOTAL_JOB_OVERHEAD_MS = 1;// 全局附加时间(ms) |
|
|
|
|
|
|
|
|
int resumeStep = task.getCurrentStep(); |
|
|
|
|
|
|
|
|
|
|
|
// ======================= 常量定义 ======================= |
|
|
|
|
|
final long COMMAND_LATENCY_MS = 12L; // 单条命令平均往返耗时(ms) |
|
|
|
|
|
final double HOME_SPEED_X = 20.0; // X 轴速度(mm/s)——末片回原点/片间移动 |
|
|
|
|
|
final double HOME_SPEED_Y = 20.0; // Y 轴速度(mm/s) |
|
|
|
|
|
final double HOME_SPEED_Z = 20.0; // Z 轴速度(mm/s) |
|
|
|
|
|
final long PER_SPRAY_OVERHEAD_MS = 0L; // 每次喷涂后固定延时(ms) |
|
|
|
|
|
final long TOTAL_JOB_OVERHEAD_MS = 0L; // 全局结束后延时(ms) |
|
|
|
|
|
final long PIPELINE_DELAY_MS = 500L; // 管路切换延时(ms) |
|
|
|
|
|
// ======================================================= |
|
|
|
|
|
|
|
|
double slideHeight = Double.parseDouble( |
|
|
double slideHeight = Double.parseDouble( |
|
|
sysSettingsService.getOne( |
|
|
sysSettingsService.getOne( |
|
@ -336,53 +339,74 @@ public class SprayTaskExecutor { |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
LocalDateTime startTime = LocalDateTime.now(); |
|
|
LocalDateTime startTime = LocalDateTime.now(); |
|
|
List<Map<String, Object>> finishTimeMap = new ArrayList<>(params.size()); |
|
|
|
|
|
|
|
|
List<Map<String, Object>> finishTimes = new ArrayList<>(); |
|
|
|
|
|
long cumulativeMs = 0L; |
|
|
|
|
|
|
|
|
|
|
|
// 上一次喷涂结束位置,初始为原点(0,0,0) |
|
|
|
|
|
double lastX = 0, lastY = 0, lastZ = 0; |
|
|
|
|
|
|
|
|
long cumulativeMs = 0; |
|
|
|
|
|
for (int i = 0; i < params.size(); i++) { |
|
|
for (int i = 0; i < params.size(); i++) { |
|
|
SprayTaskParams p = params.get(i); |
|
|
SprayTaskParams p = params.get(i); |
|
|
int idx = p.getIndex(); |
|
|
int idx = p.getIndex(); |
|
|
// 如果此玻片已在之前完成,直接添加当前累计时间 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 已完成玻片直接记录并跳过 |
|
|
if (idx < resumeIndex) { |
|
|
if (idx < resumeIndex) { |
|
|
Map<String, Object> ft = new HashMap<>(); |
|
|
|
|
|
ft.put("index", p.getIndex()); |
|
|
|
|
|
ft.put("finishTime", startTime.plus(Duration.ofMillis(cumulativeMs))); |
|
|
|
|
|
finishTimeMap.add(ft); |
|
|
|
|
|
|
|
|
Map<String, Object> rec = new HashMap<>(); |
|
|
|
|
|
rec.put("index", idx); |
|
|
|
|
|
rec.put("finishTime", startTime.plus(Duration.ofMillis(cumulativeMs))); |
|
|
|
|
|
finishTimes.add(rec); |
|
|
continue; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
long sliceMs = 0; |
|
|
|
|
|
// 1) 移到玻片起点 + 下降 |
|
|
|
|
|
|
|
|
long sliceMs = 0L; |
|
|
Double[] slide = slideArr[idx]; |
|
|
Double[] slide = slideArr[idx]; |
|
|
SprayTimes firstT = p.getTimes().get(0); |
|
|
SprayTimes firstT = p.getTimes().get(0); |
|
|
sliceMs += moveMs(0, slide[0], firstT.getMovingSpeed(), COMMAND_LATENCY_MS); |
|
|
|
|
|
sliceMs += moveMs(0, slide[1], firstT.getMovingSpeed(), COMMAND_LATENCY_MS); |
|
|
|
|
|
double targetZ = slideHeight - firstT.getMotorZHeight(); |
|
|
|
|
|
sliceMs += moveMs(0, targetZ, 20, COMMAND_LATENCY_MS); |
|
|
|
|
|
|
|
|
|
|
|
// 2) 管路切换 & 等待(已在中途恢复时跳过) |
|
|
|
|
|
|
|
|
// 1) 并行移动到喷涂起点(X,Y,Z),暂停恢复时跳过 |
|
|
|
|
|
boolean isResumeSlide = (idx == resumeIndex && resumeStep > 0); |
|
|
|
|
|
double curX, curY, curZ; |
|
|
|
|
|
if (!isResumeSlide) { |
|
|
|
|
|
double targetZ = slideHeight - firstT.getMotorZHeight(); |
|
|
|
|
|
sliceMs += concurrentMoveMs( |
|
|
|
|
|
lastX, slide[0], firstT.getMovingSpeed(), |
|
|
|
|
|
lastY, slide[1], firstT.getMovingSpeed(), |
|
|
|
|
|
lastZ, targetZ, 20, |
|
|
|
|
|
COMMAND_LATENCY_MS |
|
|
|
|
|
); |
|
|
|
|
|
curX = slide[0]; |
|
|
|
|
|
curY = slide[1]; |
|
|
|
|
|
curZ = targetZ; |
|
|
|
|
|
} else { |
|
|
|
|
|
// 恢复喷涂,无需移动到玻片顶点 |
|
|
|
|
|
curX = lastX; |
|
|
|
|
|
curY = lastY; |
|
|
|
|
|
curZ = lastZ; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 2) 管路切换 & 等待 |
|
|
boolean switched = (idx == resumeIndex && resumeSprayNum > 1); |
|
|
boolean switched = (idx == resumeIndex && resumeSprayNum > 1); |
|
|
if (!switched) { |
|
|
if (!switched) { |
|
|
sliceMs += COMMAND_LATENCY_MS + 500;//500是切换注射器固定等待时间 |
|
|
|
|
|
|
|
|
sliceMs += COMMAND_LATENCY_MS + PIPELINE_DELAY_MS; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 3) 喷涂循环 |
|
|
// 3) 喷涂循环 |
|
|
double curX = slide[0], curY = slide[1]; |
|
|
|
|
|
int sprayCount = 1; |
|
|
int sprayCount = 1; |
|
|
for (SprayTimes t : p.getTimes()) { |
|
|
for (SprayTimes t : p.getTimes()) { |
|
|
// 跳过已完成的喷涂轮次 |
|
|
|
|
|
|
|
|
// 跳过已完成轮次 |
|
|
if (idx == resumeIndex && sprayCount < resumeSprayNum) { |
|
|
if (idx == resumeIndex && sprayCount < resumeSprayNum) { |
|
|
// grid 模式双计数 |
|
|
|
|
|
if ("grid".equals(t.getMatrixPathType())) sprayCount++; |
|
|
if ("grid".equals(t.getMatrixPathType())) sprayCount++; |
|
|
sprayCount++; |
|
|
sprayCount++; |
|
|
continue; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
// 开阀/泵/高压指令 |
|
|
|
|
|
|
|
|
// 指令开销 |
|
|
sliceMs += COMMAND_LATENCY_MS * 3; |
|
|
sliceMs += COMMAND_LATENCY_MS * 3; |
|
|
if (t.getHighVoltage()) sliceMs += COMMAND_LATENCY_MS * 2; |
|
|
if (t.getHighVoltage()) sliceMs += COMMAND_LATENCY_MS * 2; |
|
|
// 路径移动 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 路径移动(串行),跳过 resumeStep |
|
|
|
|
|
int skip = (idx == resumeIndex && sprayCount == resumeSprayNum) ? resumeStep : 0; |
|
|
for (SprayTaskStep step : getSprayPath(t)) { |
|
|
for (SprayTaskStep step : getSprayPath(t)) { |
|
|
for (Point2D pt : step.getSprayPathPointList()) { |
|
|
for (Point2D pt : step.getSprayPathPointList()) { |
|
|
|
|
|
if (skip-- > 0) continue; |
|
|
double nx = slide[0] + pt.getX(); |
|
|
double nx = slide[0] + pt.getX(); |
|
|
double ny = slide[1] + pt.getY(); |
|
|
double ny = slide[1] + pt.getY(); |
|
|
sliceMs += moveMs(curX, nx, t.getMovingSpeed(), COMMAND_LATENCY_MS); |
|
|
sliceMs += moveMs(curX, nx, t.getMovingSpeed(), COMMAND_LATENCY_MS); |
|
@ -390,35 +414,45 @@ public class SprayTaskExecutor { |
|
|
sliceMs += moveMs(curY, ny, t.getMovingSpeed(), COMMAND_LATENCY_MS); |
|
|
sliceMs += moveMs(curY, ny, t.getMovingSpeed(), COMMAND_LATENCY_MS); |
|
|
curY = ny; |
|
|
curY = ny; |
|
|
} |
|
|
} |
|
|
// 结束阀门指令 + grid 延时 |
|
|
|
|
|
|
|
|
// 结束阀门 & 网格延时 |
|
|
sliceMs += COMMAND_LATENCY_MS * 3; |
|
|
sliceMs += COMMAND_LATENCY_MS * 3; |
|
|
if ("grid".equals(t.getMatrixPathType()) && t.getGridDelay() != null) { |
|
|
if ("grid".equals(t.getMatrixPathType()) && t.getGridDelay() != null) { |
|
|
sliceMs += t.getGridDelay() * 1000; |
|
|
sliceMs += t.getGridDelay() * 1000; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
// 喷涂后延时 + 附加时间 |
|
|
|
|
|
|
|
|
// 喷涂后延时 & 附加 |
|
|
sliceMs += t.getDelay() * 1000; |
|
|
sliceMs += t.getDelay() * 1000; |
|
|
sliceMs += PER_SPRAY_OVERHEAD_MS; |
|
|
sliceMs += PER_SPRAY_OVERHEAD_MS; |
|
|
sprayCount++; |
|
|
sprayCount++; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 4) 回原点 |
|
|
|
|
|
sliceMs += moveMs(curX, 0, HOME_SPEED_X, COMMAND_LATENCY_MS); |
|
|
|
|
|
sliceMs += moveMs(curY, 0, HOME_SPEED_Y, COMMAND_LATENCY_MS); |
|
|
|
|
|
sliceMs += moveMs(targetZ, 0, HOME_SPEED_Z, COMMAND_LATENCY_MS); |
|
|
|
|
|
|
|
|
// 4) 片尾:非末片更新 last 位置;末片并行回原点 + 全局延时 |
|
|
|
|
|
if (i < params.size() - 1) { |
|
|
|
|
|
lastX = curX; |
|
|
|
|
|
lastY = curY; |
|
|
|
|
|
lastZ = curZ; |
|
|
|
|
|
} else { |
|
|
|
|
|
sliceMs += concurrentMoveMs( |
|
|
|
|
|
curX, 0.0, HOME_SPEED_X, |
|
|
|
|
|
curY, 0.0, HOME_SPEED_Y, |
|
|
|
|
|
curZ, 0.0, HOME_SPEED_Z, |
|
|
|
|
|
COMMAND_LATENCY_MS |
|
|
|
|
|
); |
|
|
|
|
|
sliceMs += TOTAL_JOB_OVERHEAD_MS; |
|
|
|
|
|
lastX = lastY = lastZ = 0.0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// 累计并加全局附加 |
|
|
|
|
|
|
|
|
// 累计并记录完成时间 |
|
|
cumulativeMs += sliceMs; |
|
|
cumulativeMs += sliceMs; |
|
|
if (i == params.size() - 1) cumulativeMs += TOTAL_JOB_OVERHEAD_MS; |
|
|
|
|
|
Map<String, Object> ft = new HashMap<>(); |
|
|
|
|
|
ft.put("index", p.getIndex()); |
|
|
|
|
|
ft.put("finishTime", TimeUtils.toEpochMilli(startTime.plus(Duration.ofMillis(cumulativeMs)))); |
|
|
|
|
|
finishTimeMap.add(ft); |
|
|
|
|
|
|
|
|
Map<String, Object> rec = new HashMap<>(); |
|
|
|
|
|
rec.put("index", idx); |
|
|
|
|
|
rec.put("finishTime", startTime.plus(Duration.ofMillis(cumulativeMs))); |
|
|
|
|
|
finishTimes.add(rec); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return finishTimeMap; |
|
|
|
|
|
|
|
|
return finishTimes; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 计算单轴移动耗时 + 指令平均延迟 |
|
|
* 计算单轴移动耗时 + 指令平均延迟 |
|
|
* |
|
|
* |
|
@ -432,6 +466,20 @@ public class SprayTaskExecutor { |
|
|
return (long) (dist / speed * 1000) + cmdDelay; |
|
|
return (long) (dist / speed * 1000) + cmdDelay; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 并行移动 XYZ:各轴耗时取最大值;包含单轴指令延迟 |
|
|
|
|
|
*/ |
|
|
|
|
|
private long concurrentMoveMs( |
|
|
|
|
|
double fromX, double toX, double speedX, |
|
|
|
|
|
double fromY, double toY, double speedY, |
|
|
|
|
|
double fromZ, double toZ, double speedZ, |
|
|
|
|
|
long cmdDelayMs) { |
|
|
|
|
|
long tx = moveMs(fromX, toX, speedX, cmdDelayMs); |
|
|
|
|
|
long ty = moveMs(fromY, toY, speedY, cmdDelayMs); |
|
|
|
|
|
long tz = moveMs(fromZ, toZ, speedZ, cmdDelayMs); |
|
|
|
|
|
return Math.max(tx, Math.max(ty, tz)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void delay(long millisecond) throws InterruptedException { |
|
|
private void delay(long millisecond) throws InterruptedException { |
|
|
delay(null, millisecond); |
|
|
delay(null, millisecond); |
|
|