Browse Source

fix:优化喷涂路线

master
白凤吉 2 weeks ago
parent
commit
22d3d138a4
  1. 164
      src/main/java/com/qyft/ms/app/device/spray/SprayTaskExecutor.java
  2. 4
      src/main/java/com/qyft/ms/app/service/VirtualDeviceService.java

164
src/main/java/com/qyft/ms/app/device/spray/SprayTaskExecutor.java

@ -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);

4
src/main/java/com/qyft/ms/app/service/VirtualDeviceService.java

@ -33,7 +33,9 @@ public class VirtualDeviceService {
String action = cmdToDevice.getAction(); String action = cmdToDevice.getAction();
String device = cmdToDevice.getDevice(); String device = cmdToDevice.getDevice();
if (code.contains("controlMotorCmd")) { if (code.contains("controlMotorCmd")) {
if (!action.contains("set")) {//非设置电机参数也就是电机移动
if(action.contains("origin")){
Thread.sleep(3000);
}else if (!action.contains("set")) {//非设置电机参数也就是电机移动
Thread.sleep(300); Thread.sleep(300);
} }
} else if (code.contains("getInfoCmd")) { } else if (code.contains("getInfoCmd")) {

Loading…
Cancel
Save