|
|
@ -16,6 +16,7 @@ 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.DeviceCommandGenerator; |
|
|
|
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.service.WebSocketService; |
|
|
|
import com.qyft.ms.system.service.device.DeviceCommandService; |
|
|
@ -24,9 +25,9 @@ import lombok.RequiredArgsConstructor; |
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.springframework.stereotype.Component; |
|
|
|
|
|
|
|
import java.util.ArrayList; |
|
|
|
import java.util.Arrays; |
|
|
|
import java.util.List; |
|
|
|
import java.time.Duration; |
|
|
|
import java.time.LocalDateTime; |
|
|
|
import java.util.*; |
|
|
|
import java.util.concurrent.CompletableFuture; |
|
|
|
import java.util.concurrent.CopyOnWriteArrayList; |
|
|
|
import java.util.concurrent.ExecutionException; |
|
|
@ -74,6 +75,10 @@ public class SprayTaskExecutor { |
|
|
|
taskThread = new Thread(() -> { |
|
|
|
try { |
|
|
|
webSocketService.pushCMDResponseMsg(FrontResponseGenerator.generateJson(sprayTask.getCmdId(), sprayTask.getCmdCode(), CommandStatus.START, "喷涂任务开始执行")); |
|
|
|
//计算剩余时间 |
|
|
|
List<Map<String, Object>> finishTimeMap = estimateCompletionTimePerSlide(); |
|
|
|
webSocketService.pushMsg(WebSocketMessageType.SPRAY_TASK_FINISH_TIME, finishTimeMap);//向前端推送当前路径 |
|
|
|
sprayTask.setFinishTimeMap(finishTimeMap); |
|
|
|
List<SprayTaskParams> sprayTaskParams = sprayTask.getSprayTaskParams(); |
|
|
|
for (SprayTaskParams sprayTaskParam : sprayTaskParams) {//循环玻片 |
|
|
|
if (sprayTask.getCurrentIndex() != null && sprayTaskParam.getIndex() < sprayTask.getCurrentIndex()) {//喷涂过的玻片跳过 |
|
|
@ -107,7 +112,7 @@ public class SprayTaskExecutor { |
|
|
|
SysSettings slideHeightSysSettings = sysSettingsService.getOne(new LambdaQueryWrapper<SysSettings>().eq(SysSettings::getCode, "slide_height")); |
|
|
|
Double slideHeight = Double.parseDouble(slideHeightSysSettings.getValue()); |
|
|
|
Double height = slideHeight - sprayTimes.getMotorZHeight();//下降z轴高度 |
|
|
|
DeviceCommand motorZPositionSetAboveSlideCommand = DeviceCommandGenerator.motorZPositionSet(height, 15.0); |
|
|
|
DeviceCommand motorZPositionSetAboveSlideCommand = DeviceCommandGenerator.motorZPositionSet(height, 20.0); |
|
|
|
CommandFuture motorZPositionSetAboveSlideCommandFuture = deviceCommandService.sendCommandSprayTask(sprayTask.getCmdId(), sprayTask.getCmdCode(), motorZPositionSetAboveSlideCommand); |
|
|
|
commandWait(motorXPositionSetCommandFuture, motorYPositionSetCommandFuture, motorZPositionSetAboveSlideCommandFuture); |
|
|
|
} |
|
|
@ -305,6 +310,128 @@ public class SprayTaskExecutor { |
|
|
|
return sprayTaskStepList; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 返回一个 List,每个元素对应 sprayTaskParams 中每个玻片的预计耗时(毫秒), |
|
|
|
*/ |
|
|
|
public List<Map<String, Object>> estimateCompletionTimePerSlide() { |
|
|
|
SprayTask task = SprayTask.getInstance(); |
|
|
|
List<SprayTaskParams> params = task.getSprayTaskParams(); |
|
|
|
int resumeIndex = task.getCurrentIndex() == null ? 0 : task.getCurrentIndex(); |
|
|
|
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) |
|
|
|
|
|
|
|
double slideHeight = Double.parseDouble( |
|
|
|
sysSettingsService.getOne( |
|
|
|
new LambdaQueryWrapper<SysSettings>() |
|
|
|
.eq(SysSettings::getCode, "slide_height")) |
|
|
|
.getValue() |
|
|
|
); |
|
|
|
|
|
|
|
LocalDateTime startTime = LocalDateTime.now(); |
|
|
|
List<Map<String, Object>> finishTimeMap = new ArrayList<>(params.size()); |
|
|
|
|
|
|
|
long cumulativeMs = 0; |
|
|
|
for (int i = 0; i < params.size(); i++) { |
|
|
|
SprayTaskParams p = params.get(i); |
|
|
|
int idx = p.getIndex(); |
|
|
|
// 如果此玻片已在之前完成,直接添加当前累计时间 |
|
|
|
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); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
long sliceMs = 0; |
|
|
|
// 1) 移到玻片起点 + 下降 |
|
|
|
Double[] slide = slideArr[idx]; |
|
|
|
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) 管路切换 & 等待(已在中途恢复时跳过) |
|
|
|
boolean switched = (idx == resumeIndex && resumeSprayNum > 1); |
|
|
|
if (!switched) { |
|
|
|
sliceMs += COMMAND_LATENCY_MS + 500;//500是切换注射器固定等待时间 |
|
|
|
} |
|
|
|
|
|
|
|
// 3) 喷涂循环 |
|
|
|
double curX = slide[0], curY = slide[1]; |
|
|
|
int sprayCount = 1; |
|
|
|
for (SprayTimes t : p.getTimes()) { |
|
|
|
// 跳过已完成的喷涂轮次 |
|
|
|
if (idx == resumeIndex && sprayCount < resumeSprayNum) { |
|
|
|
// grid 模式双计数 |
|
|
|
if ("grid".equals(t.getMatrixPathType())) sprayCount++; |
|
|
|
sprayCount++; |
|
|
|
continue; |
|
|
|
} |
|
|
|
// 开阀/泵/高压指令 |
|
|
|
sliceMs += COMMAND_LATENCY_MS * 3; |
|
|
|
if (t.getHighVoltage()) sliceMs += COMMAND_LATENCY_MS * 2; |
|
|
|
// 路径移动 |
|
|
|
for (SprayTaskStep step : getSprayPath(t)) { |
|
|
|
for (Point2D pt : step.getSprayPathPointList()) { |
|
|
|
double nx = slide[0] + pt.getX(); |
|
|
|
double ny = slide[1] + pt.getY(); |
|
|
|
sliceMs += moveMs(curX, nx, t.getMovingSpeed(), COMMAND_LATENCY_MS); |
|
|
|
curX = nx; |
|
|
|
sliceMs += moveMs(curY, ny, t.getMovingSpeed(), COMMAND_LATENCY_MS); |
|
|
|
curY = ny; |
|
|
|
} |
|
|
|
// 结束阀门指令 + grid 延时 |
|
|
|
sliceMs += COMMAND_LATENCY_MS * 3; |
|
|
|
if ("grid".equals(t.getMatrixPathType()) && t.getGridDelay() != null) { |
|
|
|
sliceMs += t.getGridDelay() * 1000; |
|
|
|
} |
|
|
|
} |
|
|
|
// 喷涂后延时 + 附加时间 |
|
|
|
sliceMs += t.getDelay() * 1000; |
|
|
|
sliceMs += PER_SPRAY_OVERHEAD_MS; |
|
|
|
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); |
|
|
|
|
|
|
|
// 累计并加全局附加 |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
return finishTimeMap; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 计算单轴移动耗时 + 指令平均延迟 |
|
|
|
* |
|
|
|
* @param from 起始坐标 (mm) |
|
|
|
* @param to 目标坐标 (mm) |
|
|
|
* @param speed 运动速度 (mm/s) |
|
|
|
* @param cmdDelay 每条指令往返延迟 (ms) |
|
|
|
*/ |
|
|
|
private long moveMs(double from, double to, double speed, long cmdDelay) { |
|
|
|
double dist = Math.abs(to - from); |
|
|
|
return (long) (dist / speed * 1000) + cmdDelay; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void delay(long millisecond) throws InterruptedException { |
|
|
|
delay(null, millisecond); |
|
|
|
} |
|
|
|