From 3a3d52c290a683293ca41b396f80877b6b832faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E5=87=A4=E5=90=89?= Date: Fri, 18 Jul 2025 20:08:45 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E5=96=B7=E6=B6=82=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E6=A0=A1=E5=87=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ms/app/device/spray/SprayTaskExecutor.java | 254 +++++++++------------ .../com/qyft/ms/app/device/status/SprayTask.java | 5 + .../app/front/cmd/business/MatrixSprayPause.java | 3 + 3 files changed, 114 insertions(+), 148 deletions(-) diff --git a/src/main/java/com/qyft/ms/app/device/spray/SprayTaskExecutor.java b/src/main/java/com/qyft/ms/app/device/spray/SprayTaskExecutor.java index 7ed7553..dc23928 100644 --- a/src/main/java/com/qyft/ms/app/device/spray/SprayTaskExecutor.java +++ b/src/main/java/com/qyft/ms/app/device/spray/SprayTaskExecutor.java @@ -75,10 +75,7 @@ public class SprayTaskExecutor { try { webSocketService.pushCMDResponseMsg(FrontResponseGenerator.generateJson(sprayTask.getCmdId(), sprayTask.getCmdCode(), CommandStatus.START, "喷涂任务开始执行")); //计算剩余时间 - List> finishTimeMap = estimateCompletionTimePerSlide(); - FinishTimeWsPushBO finishTimeWsPushBO = new FinishTimeWsPushBO(sprayTask.getCmdId(), sprayTask.getCmdCode(), finishTimeMap); - webSocketService.pushMsg(WebSocketMessageType.SPRAY_TASK_FINISH_TIME, finishTimeWsPushBO);//向前端推送当前路径 - sprayTask.setFinishTimeMap(finishTimeMap); + subFinishTime(); List sprayTaskParams = sprayTask.getSprayTaskParams(); for (SprayTaskParams sprayTaskParam : sprayTaskParams) {//循环玻片 if (sprayTask.getCurrentIndex() != null && sprayTaskParam.getIndex() <= sprayTask.getCurrentIndex()) {//喷涂过的玻片跳过 @@ -187,6 +184,7 @@ public class SprayTaskExecutor { sprayNum++; sprayTask.setSprayNum(sprayNum); sprayTask.setCurrentStep(0); + subFinishTime(); } sprayTask.setCurrentIndex(sprayTaskParam.getIndex()); sprayTask.setSprayNum(0); @@ -199,6 +197,7 @@ public class SprayTaskExecutor { DeviceCommand nozzleValveCloseCommand = DeviceCommandGenerator.nozzleValveClose();//关闭喷嘴阀 CommandFuture nozzleValveCloseCommandFuture = deviceCommandService.sendCommandSprayTask(sprayTask.getCmdId(), sprayTask.getCmdCode(), nozzleValveCloseCommand); commandWait(nozzleValveCloseCommandFuture); + sprayTask.setCannotPause(true);//喷涂完毕后就是回原点了,期间不可暂停 //XYZ回原点 DeviceCommand motorXOriginCommand = DeviceCommandGenerator.motorXOrigin(); @@ -311,173 +310,132 @@ public class SprayTaskExecutor { return sprayTaskStepList; } + public void subFinishTime() { + SprayTask sprayTask = SprayTask.getInstance(); + List> finishTimeMap = estimateFinishTimePerSlide(); + FinishTimeWsPushBO finishTimeWsPushBO = new FinishTimeWsPushBO(sprayTask.getCmdId(), sprayTask.getCmdCode(), finishTimeMap); + webSocketService.pushMsg(WebSocketMessageType.SPRAY_TASK_FINISH_TIME, finishTimeWsPushBO);//向前端推送当前路径 + sprayTask.setFinishTimeMap(finishTimeMap); + } + /** - * 返回一个 List,每个元素对应 sprayTaskParams 中每个玻片的预计耗时(毫秒), + * 返回每片的预计完成时间列表(包含 index 与 finishTime) */ - public List> estimateCompletionTimePerSlide() { - SprayTask task = SprayTask.getInstance(); - List params = task.getSprayTaskParams(); - int resumeIndex = task.getCurrentIndex() == null ? 0 : task.getCurrentIndex(); - int resumeSprayNum = task.getSprayNum(); - 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( - sysSettingsService.getOne( - new LambdaQueryWrapper() - .eq(SysSettings::getCode, "slide_height")) - .getValue() - ); + public List> estimateFinishTimePerSlide() { + SprayTask sprayTask = SprayTask.getInstance(); + + // ===== 常量 ===== + final long CMD_LAT_MS = 12L; // 单条命令往返耗时(ms) + final long PER_OVERHEAD_MS = 0L; // 每次喷涂后附加延时(ms) + final long JOB_OVERHEAD_MS = 0L; // 任务结束后全局延时(ms) + // ================ LocalDateTime startTime = LocalDateTime.now(); List> finishTimes = new ArrayList<>(); - long cumulativeMs = 0L; - - // 上一次喷涂结束位置,初始为原点(0,0,0) - double lastX = 0, lastY = 0, lastZ = 0; - - for (int i = 0; i < params.size(); i++) { - SprayTaskParams p = params.get(i); - int idx = p.getIndex(); - // 已完成玻片直接记录并跳过 - if (idx < resumeIndex) { - Map rec = new HashMap<>(); - rec.put("index", idx); - rec.put("finishTime", startTime.plus(Duration.ofMillis(cumulativeMs))); - finishTimes.add(rec); + List sprayTaskParams = sprayTask.getSprayTaskParams(); + double curX = 0, curY = 0, curZ = 0;//定义当前位置 + for (SprayTaskParams sprayTaskParam : sprayTaskParams) {//循环玻片 + if (sprayTask.getCurrentIndex() != null && sprayTaskParam.getIndex() <= sprayTask.getCurrentIndex()) {//喷涂过的玻片跳过 continue; } - - long sliceMs = 0L; - Double[] slide = slideArr[idx]; - SprayTimes firstT = p.getTimes().get(0); - - // 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); - if (!switched) { - sliceMs += COMMAND_LATENCY_MS + PIPELINE_DELAY_MS; - } - - // 3) 喷涂循环 - int sprayCount = 1; - for (SprayTimes t : p.getTimes()) { - // 跳过已完成轮次 - if (idx == resumeIndex && sprayCount < resumeSprayNum) { - if ("grid".equals(t.getMatrixPathType())) sprayCount++; - sprayCount++; + long sliceMs = 0L; //当前玻片耗时 + int sprayNum = 1; //当前玻片是第几次喷涂 + for (SprayTimes sprayTimes : sprayTaskParam.getTimes()) {//每个拨片有多次喷涂,循环每次喷涂 + if (sprayNum < sprayTask.getSprayNum()) { + sprayNum++; continue; } - // 指令开销 - sliceMs += COMMAND_LATENCY_MS * 3; - if (t.getHighVoltage()) sliceMs += COMMAND_LATENCY_MS * 2; - - // 路径移动(串行),跳过 resumeStep - int skip = (idx == resumeIndex && sprayCount == resumeSprayNum) ? resumeStep : 0; - for (SprayTaskStep step : getSprayPath(t)) { - for (Point2D pt : step.getSprayPathPointList()) { - if (skip-- > 0) continue; - 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; + Double[] slide = slideArr[sprayTaskParam.getIndex()];//获取玻片原点的坐标 + List sprayTaskStepList = getSprayPath(sprayTimes);//计算本次喷涂的路线 + if (sprayTask.getCurrentStep() == 0) { + //先移动到玻片左上角位置 + SysSettings slideHeightSysSettings = sysSettingsService.getOne(new LambdaQueryWrapper().eq(SysSettings::getCode, "slide_height")); + Double slideHeight = Double.parseDouble(slideHeightSysSettings.getValue()); + double height = slideHeight - sprayTimes.getMotorZHeight();//下降z轴高度 + sliceMs += concurrentMoveMs( + curX, slideArr[sprayTaskParam.getIndex()][0], 20, + curY, slideArr[sprayTaskParam.getIndex()][1], 20, + curZ, height, 20, + CMD_LAT_MS + ); + curX = slideArr[sprayTaskParam.getIndex()][0]; + curY = slideArr[sprayTaskParam.getIndex()][1]; + curZ = height; + } + sliceMs += CMD_LAT_MS + 500;//三通阀切换到注射器管路 + //因为走的是折线,所以单次指令只需要移动x或y,缓存上一个点位用来判断本次是走x还是y + double cacheXPoint = -1; + double cacheYPoint = -1; + int currentStep = 0; //记录当前线程喷涂步骤序号 + for (SprayTaskStep sprayTaskStep : sprayTaskStepList) {//因为田字格喷涂其实是两次 + if (currentStep >= sprayTask.getCurrentStep()) { + sliceMs += CMD_LAT_MS;//开启喷嘴阀 + sliceMs += CMD_LAT_MS;//推动移动注射泵 + if (sprayTimes.getHighVoltage()) {//加电 + sliceMs += CMD_LAT_MS;//开启高压 + } } - // 结束阀门 & 网格延时 - sliceMs += COMMAND_LATENCY_MS * 3; - if ("grid".equals(t.getMatrixPathType()) && t.getGridDelay() != null) { - sliceMs += t.getGridDelay() * 1000; + for (int i = 0; i < sprayTaskStep.getSprayPathPointList().size(); i++) {//循环路线 + if (currentStep < sprayTask.getCurrentStep()) { + currentStep++; + continue; + } + Point2D currentPoint = sprayTaskStep.getSprayPathPointList().get(i); + if (cacheXPoint != currentPoint.x) { + sliceMs += moveMs(curX, slide[0] + currentPoint.x, sprayTimes.getMovingSpeed(), CMD_LAT_MS); + cacheXPoint = currentPoint.x; + curX = slide[0] + currentPoint.x; + } + if (cacheYPoint != currentPoint.y) { + sliceMs += moveMs(curY, slide[1] + currentPoint.y, sprayTimes.getMovingSpeed(), CMD_LAT_MS); + cacheYPoint = currentPoint.y; + curY = slide[1] + currentPoint.y; + } + sliceMs += CMD_LAT_MS * 3;//向前端推送当前路径 + currentStep++;//当前喷涂步数。因为暂停可能本次路线还没走完,所以这里只有在走完一次路线后才会自增 + } + //一次喷涂完毕后停止推注射泵 + sliceMs += CMD_LAT_MS; //关闭高压 + sliceMs += CMD_LAT_MS; //停止推动注射泵 + sliceMs += CMD_LAT_MS; //关闭喷嘴阀 + if ("grid".equals(sprayTimes.getMatrixPathType()) && sprayTimes.getGridDelay() != null) { + if(sprayTask.getRemainingGridDelay() != null){ + sliceMs += sprayTask.getRemainingGridDelay(); + }else{ + sliceMs += sprayTimes.getGridDelay() * 1000; + } } } - // 喷涂后延时 & 附加 - sliceMs += t.getDelay() * 1000; - sliceMs += PER_SPRAY_OVERHEAD_MS; - sprayCount++; - } - - // 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; + if(sprayTask.getRemainingDelay() != null){ + sliceMs += sprayTask.getRemainingDelay(); + }else{ + sliceMs += sprayTimes.getDelay() * 1000; + } + sprayNum++; } - - // 累计并记录完成时间 - cumulativeMs += sliceMs; Map rec = new HashMap<>(); - rec.put("index", idx); - rec.put("finishTime", startTime.plus(Duration.ofMillis(cumulativeMs))); + rec.put("index", sprayTaskParam.getIndex()); + rec.put("finishTime", startTime.plus(Duration.ofMillis(sliceMs))); finishTimes.add(rec); } + return finishTimes; } - - /** - * 计算单轴移动耗时 + 指令平均延迟 - * - * @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 long moveMs(double from, double to, double speed, long cmdDelayMs) { + return (long) (Math.abs(to - from) / speed * 1000) + cmdDelayMs; } - /** - * 并行移动 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)); + double fx, double tx, double sx, + double fy, double ty, double sy, + double fz, double tz, double sz, + long cmd) { + long x = moveMs(fx, tx, sx, cmd); + long y = moveMs(fy, ty, sy, cmd); + long z = moveMs(fz, tz, sz, cmd); + return Math.max(x, Math.max(y, z)); } diff --git a/src/main/java/com/qyft/ms/app/device/status/SprayTask.java b/src/main/java/com/qyft/ms/app/device/status/SprayTask.java index cc5eb46..d32214c 100644 --- a/src/main/java/com/qyft/ms/app/device/status/SprayTask.java +++ b/src/main/java/com/qyft/ms/app/device/status/SprayTask.java @@ -74,6 +74,10 @@ public class SprayTask { */ private volatile boolean paused = false; /** + * 当前设备状态是否可以暂停 + */ + private volatile boolean cannotPause = false; + /** * 标志喷涂任务结束 */ private volatile boolean close = false; @@ -96,6 +100,7 @@ public class SprayTask { cmdId = null; cmdCode = null; paused = false; + cannotPause = false; close = false; spraying = false; currentStep = 0; diff --git a/src/main/java/com/qyft/ms/app/front/cmd/business/MatrixSprayPause.java b/src/main/java/com/qyft/ms/app/front/cmd/business/MatrixSprayPause.java index 59c372c..1ab35ce 100644 --- a/src/main/java/com/qyft/ms/app/front/cmd/business/MatrixSprayPause.java +++ b/src/main/java/com/qyft/ms/app/front/cmd/business/MatrixSprayPause.java @@ -41,6 +41,9 @@ public class MatrixSprayPause extends BaseCommandHandler { if(sprayTask.isPaused()){ throw new RuntimeException("设备暂停中"); } + if (sprayTask.isCannotPause()) { + throw new RuntimeException("当前喷涂任务不可暂停"); + } sprayTask.setPaused(true);//设置已暂停 try { sprayTaskExecutor.stopTask();//终止喷涂任务线程