Compare commits
3 Commits
e0330b604d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 474a7d0a68 | |||
| c47e2059a1 | |||
| 3b5f168b45 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,3 +27,4 @@ hs_err_pid*
|
||||
**/target/
|
||||
|
||||
/log/
|
||||
/.trae/
|
||||
|
||||
@@ -151,8 +151,8 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
||||
//下发断电任务
|
||||
// int i = PlcCdzRead.writeToCdz("2");
|
||||
// if (i == 1) {
|
||||
srgvChargingJobMapper.insertHistory(srgvChargingJob.getGuid());
|
||||
srgvChargingJobMapper.deleteSrgvChargingJobByGuid(srgvChargingJob.getGuid());
|
||||
srgvChargingJobMapper.insertHistory(srgvChargingJob.getGuid());
|
||||
srgvChargingJobMapper.deleteSrgvChargingJobByGuid(srgvChargingJob.getGuid());
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -180,7 +180,7 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
||||
String chargingId = srgvChargingJob.getChargingId();
|
||||
DeviceSrgv srgv = PlcSrgvRead.deviceSrgvMap.get(agvId);
|
||||
// DeviceCdz cdz = PlcCdzRead.deviceCdzMap.get(chargingId);
|
||||
if (srgv.getCurrFloor() == 1) {
|
||||
if (srgv.getCurrFloor()==1) {
|
||||
//生成四向小车充电队列
|
||||
String chargingSite = srgvChargingJob.getChargingSite();//充电桩站点
|
||||
WcsSrgvQueue wcsSrgvQueueParam = new WcsSrgvQueue();
|
||||
@@ -200,8 +200,8 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
||||
List<WcsSrgvQueue> wcsSrgvQueues = wcsSagvQueueMapper.selectWcsSrgvQueueList(wcsSrgvQueueParam);
|
||||
if (CollUtil.isEmpty(wcsSrgvQueues)) {
|
||||
createSrgvChargingQueue(deviceSrgv, chargingSite, "8", srgvChargingJob.getTaskNo());
|
||||
// srgvChargingJob.setJobStatus("2");
|
||||
// srgvChargingJobMapper.updateSrgvChargingJob(srgvChargingJob);
|
||||
srgvChargingJob.setJobStatus("2");
|
||||
srgvChargingJobMapper.updateSrgvChargingJob(srgvChargingJob);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -774,6 +774,234 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
||||
// Fallback to Strategy 2
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 策略2:自己避让 (原有逻辑)
|
||||
// ---------------------------------------------------------
|
||||
// =========================================================
|
||||
// 特殊优先策略:若目标点被其他小车占用,直接调度占用车到缓存点
|
||||
// 场景示例:1号车目标为 040701,但 2号车正停在 040701
|
||||
// 处理思路:不等待、不绕行,直接把占用目标点的小车移开
|
||||
// =========================================================
|
||||
try {
|
||||
// 查找占用目标点的阻挡车(排除当前车)
|
||||
String endBlockAgv = null;
|
||||
DeviceSrgv endBlockDevice = null;
|
||||
for (Map.Entry<String, DeviceSrgv> entry : PlcSrgvRead.deviceSrgvMap.entrySet()) {
|
||||
DeviceSrgv other = entry.getValue();
|
||||
if (other == null) continue;
|
||||
if (Objects.equals(other.getCurrSite(), endSite)
|
||||
&& !Objects.equals(Convert.toStr(deviceSrgv.getDeviceId()), entry.getKey())) {
|
||||
endBlockAgv = entry.getKey();
|
||||
endBlockDevice = other;
|
||||
break;
|
||||
}
|
||||
}
|
||||
WcsSrgvQueue wcsSrgvQueue1 =new WcsSrgvQueue();
|
||||
wcsSrgvQueue1.setAgvId(endBlockAgv);
|
||||
List<WcsSrgvQueue> wcsSrgvQueues = wcsSagvQueueMapper.selectWcsSrgvQueueList(wcsSrgvQueue1);
|
||||
if (endBlockDevice != null&&wcsSrgvQueues.isEmpty()) {
|
||||
// 选择当前层最近且可达的缓存点(避让点)
|
||||
WcsSrgvMap cacheParam = new WcsSrgvMap();
|
||||
cacheParam.setRemark("cache");
|
||||
cacheParam.setTheLayer(floor);
|
||||
List<WcsSrgvMap> cacheMaps = wcsSrgvMapService.selectWcsSrgvMapList(cacheParam);
|
||||
// 生成阻挡车的避让任务(点到点,高优先级,未下发)
|
||||
WcsSrgvQueue taskB = new WcsSrgvQueue();
|
||||
taskB.setGuid(UUID.randomUUID().toString());
|
||||
// 生成纯数字任务号(PLC要求),9 + HHmmss
|
||||
taskB.setTaskNo(String.valueOf(taskCache));
|
||||
taskB.setAgvId(endBlockAgv);
|
||||
taskB.setTaskType("4"); // 点到点移动
|
||||
taskB.setDefault02("4"); // 业务类型标识为点到点
|
||||
taskB.setPriority(9L); // 高优先级,尽快避让
|
||||
taskB.setIssued("0"); // 未下发
|
||||
taskB.setExecutionStatus("1");// 初始状态
|
||||
taskB.setStartSite(endBlockDevice.getCurrSite());
|
||||
taskB.setEndSite("050501");
|
||||
taskB.setTheFloor(floor.toString());
|
||||
taskB.setDefault03(endBlockDevice.getCurrSite());
|
||||
taskB.setDefault07(floor.toString());
|
||||
taskB.setDefault08("1");//避让任务,直接完成
|
||||
taskB.setCreateDate(DateUtil.now());
|
||||
wcsSagvQueueMapper.insertWcsSrgvQueue(taskB);
|
||||
taskCache++;
|
||||
log.info("目标点 {} 被小车 {} 占用,已调度其前往避让点 {}", endSite, endBlockAgv, "050501");
|
||||
// 当前车等待下一轮调度(待阻挡车移开后自然可达)
|
||||
return false;
|
||||
} else {
|
||||
log.warn("目标点 {} 被小车 {} 占用,但无可用避让点", endSite, endBlockAgv);
|
||||
// 无法直接移开阻挡车,后续进入常规策略(寻找阻挡者或自身避让)
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("终点占用直接避让策略执行异常", e);
|
||||
}
|
||||
// ---------------------------------------------------------
|
||||
// 策略1:尝试调度阻挡车避让 (新增逻辑)
|
||||
// ---------------------------------------------------------
|
||||
try {
|
||||
// 1. 获取纯净静态地图 (不含动态障碍物)
|
||||
// 重新获取原始地图数据,避免受 handleMap 修改的影响
|
||||
Map<String, WcsSrgvMap> cleanArrByRoadSite = roadCacheService.getArrByRoadSite(floor);
|
||||
int[][] staticMap = new int[29][16];
|
||||
for (WcsSrgvMap site : cleanArrByRoadSite.values()) {
|
||||
if (site.getX() != null && site.getY() != null) {
|
||||
staticMap[site.getX()][site.getY()] = site.getValue();
|
||||
}
|
||||
}
|
||||
// 2. 规划理想路径 (忽略其他小车)
|
||||
int sx = cleanArrByRoadSite.get(startSite).getX();
|
||||
int sy = cleanArrByRoadSite.get(startSite).getY();
|
||||
int ex = cleanArrByRoadSite.get(endSite).getX();
|
||||
int ey = cleanArrByRoadSite.get(endSite).getY();
|
||||
staticMap[sx][sy] = 2;
|
||||
staticMap[ex][ey] = 2;
|
||||
List<int[]> idealPath = PathFinder.findShortestPath(
|
||||
staticMap,
|
||||
sx, sy,
|
||||
ex, ey
|
||||
);
|
||||
// 3. 寻找阻挡车
|
||||
String blockingAgv = null;
|
||||
if (idealPath == null || idealPath.isEmpty()) {
|
||||
log.warn("理想路径为空,sx={},sy={},ex={},ey={},startVal={},endVal={}",
|
||||
sx, sy, ex, ey, staticMap[sx][sy], staticMap[ex][ey]);
|
||||
}
|
||||
if (idealPath != null && !idealPath.isEmpty()) {
|
||||
for (int[] point : idealPath) {
|
||||
// 通过坐标反查站点 (简单遍历)
|
||||
// 注意:这里假设同一层坐标唯一
|
||||
String pointSiteId = null;
|
||||
for (Map.Entry<String, WcsSrgvMap> entry : arrByRoadSite.entrySet()) {
|
||||
WcsSrgvMap s = entry.getValue();
|
||||
if (s.getX() == point[0] && s.getY() == point[1]) {
|
||||
pointSiteId = s.getSiteId();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pointSiteId != null) {
|
||||
// 检查是否有其他车在这个点
|
||||
for (Map.Entry<String, DeviceSrgv> entry : PlcSrgvRead.deviceSrgvMap.entrySet()) {
|
||||
String otherAgvCode = entry.getKey();
|
||||
DeviceSrgv otherAgv = entry.getValue();
|
||||
|
||||
if (!otherAgvCode.equals(wcsSrgvQueue.getAgvId()) && // 不是自己
|
||||
pointSiteId.equals(otherAgv.getCurrSite())) { // 是别人
|
||||
|
||||
blockingAgv = otherAgvCode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (blockingAgv != null) break; // 找到第一个阻挡者即可
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 调度阻挡车
|
||||
if (blockingAgv != null) {
|
||||
log.info("发现阻挡车: {}, 尝试调度避让", blockingAgv);
|
||||
|
||||
// 检查 B 是否忙碌 (是否有未完成任务)
|
||||
WcsSrgvQueue blockingParam = new WcsSrgvQueue();
|
||||
blockingParam.setAgvId(blockingAgv); // 注意:这里用 AgvId 还是 SrgvCode 需要确认,假设是一致的
|
||||
// 通常数据库存的是 ID,这里 blockingAgv 来自 deviceSrgvMap 的 key,通常是 code
|
||||
// 如果 code != id,需要转换。假设 code 就是 id。
|
||||
|
||||
List<WcsSrgvQueue> tasks = wcsSagvQueueMapper.selectWcsSrgvQueueList(blockingParam);
|
||||
boolean isBusy = CollUtil.isNotEmpty(tasks);
|
||||
// 这里简化判断:只要有队列记录就算忙。更精细的判断可以看 status。
|
||||
|
||||
if (isBusy) {
|
||||
log.info("阻挡车 {} 正在执行任务,当前车 {} 等待", blockingAgv, wcsSrgvQueue.getAgvId());
|
||||
return false; // B 忙,A 等待 (不做任何操作,下一轮循环再试)
|
||||
} else {
|
||||
// B 空闲,寻找避让点
|
||||
// 获取当前层所有避让点
|
||||
WcsSrgvMap cacheParam = new WcsSrgvMap();
|
||||
cacheParam.setRemark("cache");
|
||||
cacheParam.setTheLayer(floor);
|
||||
List<WcsSrgvMap> cacheMaps = wcsSrgvMapService.selectWcsSrgvMapList(cacheParam);
|
||||
|
||||
// 获取所有小车位置 (用于避让点占用检查)
|
||||
Set<String> occupiedSites = new HashSet<>();
|
||||
for (DeviceSrgv d : PlcSrgvRead.deviceSrgvMap.values()) {
|
||||
occupiedSites.add(d.getCurrSite());
|
||||
}
|
||||
|
||||
String bestCacheForB = null;
|
||||
int minLenForB = Integer.MAX_VALUE;
|
||||
|
||||
DeviceSrgv deviceB = PlcSrgvRead.deviceSrgvMap.get(blockingAgv);
|
||||
if (deviceB != null) {
|
||||
WcsSrgvMap startNodeB = arrByRoadSite.get(deviceB.getCurrSite());
|
||||
|
||||
for (WcsSrgvMap cache : cacheMaps) {
|
||||
String siteId = cache.getSiteId();
|
||||
if (occupiedSites.contains(siteId)) continue; // 已被占
|
||||
|
||||
// 关键:避让点不能在 A 的理想路径上
|
||||
boolean onIdealPath = false;
|
||||
for (int[] p : idealPath) {
|
||||
if (p[0] == cache.getX() && p[1] == cache.getY()) {
|
||||
onIdealPath = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (onIdealPath) continue;
|
||||
|
||||
// 检查 B 到避让点的可达性 (在静态地图上即可,因为其他车可能就是 A)
|
||||
// 此时 A 还没动,所以 B 应该能动。
|
||||
// 为了安全,还是用 emptyMap (含 A) 检查 B 的路径?
|
||||
// 不,用 emptyMap 检查 B 的路径,因为 A 还在原位。
|
||||
if (startNodeB != null && cache.getX() != null && cache.getY() != null) {
|
||||
List<int[]> pathB = PathFinder.findShortestPath(emptyMap,
|
||||
startNodeB.getX(), startNodeB.getY(),
|
||||
cache.getX(), cache.getY());
|
||||
|
||||
if (pathB != null && !pathB.isEmpty() && pathB.size() < minLenForB) {
|
||||
minLenForB = pathB.size();
|
||||
bestCacheForB = siteId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestCacheForB != null) {
|
||||
// 生成 B 的避让任务
|
||||
WcsSrgvQueue taskB = new WcsSrgvQueue();
|
||||
taskB.setGuid(UUID.randomUUID().toString());
|
||||
// 生成纯数字任务号,避免 PLC 解析错误
|
||||
// 格式:9 + HHmmss + 随机位 (防止重复)
|
||||
String timeStr = DateUtil.format(new Date(), "HHmmss");
|
||||
taskB.setTaskNo(String.valueOf(taskCache));
|
||||
taskB.setAgvId(blockingAgv);
|
||||
taskB.setTaskType("4"); // 点到点
|
||||
taskB.setPriority(9L); // 高优先级
|
||||
taskB.setIssued("0");
|
||||
taskB.setExecutionStatus("1");
|
||||
taskB.setStartSite(deviceB.getCurrSite());
|
||||
taskB.setEndSite(bestCacheForB);
|
||||
taskB.setTheFloor(floor.toString());
|
||||
taskB.setCreateDate(DateUtil.now());
|
||||
taskB.setDefault02("4");
|
||||
taskB.setDefault03(deviceB.getCurrSite()); // 默认值填充
|
||||
taskB.setDefault07(floor.toString());
|
||||
taskB.setDefault08("1");
|
||||
wcsSagvQueueMapper.insertWcsSrgvQueue(taskB);
|
||||
taskCache++;
|
||||
log.info("成功调度阻挡车 {} 前往避让点 {}", blockingAgv, bestCacheForB);
|
||||
return false; // A 等待
|
||||
} else {
|
||||
log.warn("阻挡车 {} 无可用避让点", blockingAgv);
|
||||
// Fallback to Strategy 2 (A moves)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("调度阻挡车避让逻辑异常", e);
|
||||
// Fallback to Strategy 2
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 策略2:自己避让 (原有逻辑)
|
||||
// ---------------------------------------------------------
|
||||
@@ -1237,8 +1465,8 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
||||
// }
|
||||
// }
|
||||
startSite = wcsSrgvQueue.getStartSite();
|
||||
if (startSite.equals("tsj")) {
|
||||
startSite = getSite(wcsSrgvQueue.getStartSite(), wcsSrgvQueue.getTheFloor(), wcsSrgvQueue.getTaskType());
|
||||
if (startSite.equals("tsj")){
|
||||
startSite=getSite(wcsSrgvQueue.getStartSite(),wcsSrgvQueue.getTheFloor(),wcsSrgvQueue.getTaskType());
|
||||
}
|
||||
if (!startSite.equals(currSite)) {
|
||||
wcsSrgvQueue.setIssued("1");
|
||||
|
||||
Reference in New Issue
Block a user