2026.2.9 小车避让

This commit is contained in:
1009473166@qq.com
2026-02-09 22:10:59 +08:00
parent 93da2f1cd0
commit cbc76be62f
2 changed files with 82 additions and 106 deletions

View File

@@ -99,17 +99,10 @@ public class PathFinder {
Collections.reverse(path); Collections.reverse(path);
return path; return path;
} }
/** /**
* 使用 A* 算法查找从起点到终点的最短路径。 * 使用 A* 算法查找从起点到终点的最短路径。
* *
@@ -203,7 +196,9 @@ public class PathFinder {
// 如果终点不可达 // 如果终点不可达
if (gCost[endX][endY] == Integer.MAX_VALUE) { if (gCost[endX][endY] == Integer.MAX_VALUE) {
return null; List<int[]> path = new ArrayList<>();
path.add(new int[]{-1, -1});
return path;
} }
// 回溯路径 // 回溯路径
@@ -272,14 +267,6 @@ public class PathFinder {
} }
/** /**
* 提取路径中的拐点(1→2 或 2→1 的边界点) * 提取路径中的拐点(1→2 或 2→1 的边界点)
* *
@@ -315,15 +302,12 @@ public class PathFinder {
List<int[]> collect = inflectionPoints.stream().distinct().collect(Collectors.toList()); List<int[]> collect = inflectionPoints.stream().distinct().collect(Collectors.toList());
return collect; return collect;
} }
/** /**
* 使用 BFS 查找从起点开始,路径上所有点的值为 2,直到终点(值为 1 或 2)的最短路径。 * 使用 BFS 查找从起点开始,路径上所有点的值为 2,直到终点(值为 1 或 2)的最短路径。
* *
@@ -398,9 +382,6 @@ public class PathFinder {
} }
/** /**
* 提取路径中的拐点: * 提取路径中的拐点:
* - 区域类型转换点(1 ↔ 2) * - 区域类型转换点(1 ↔ 2)
@@ -483,12 +464,12 @@ public class PathFinder {
/* /*
* 此方法使用情景 * 此方法使用情景
* 一个原点(目标点)、多个目标点(原点),多个目标点(原点)互相影响, * 一个原点(目标点)、多个目标点(原点),多个目标点(原点)互相影响,
* 按算法查找多个目标点(原点)的最优路径 * 按算法查找多个目标点(原点)的最优路径
* *
* */ * */
public static Site findOptimalCarWithObstacles(int[][] grid, Site srcSite, List<Site> tarSites){ public static Site findOptimalCarWithObstacles(int[][] grid, Site srcSite, List<Site> tarSites) {
//所有车先都设置为障碍 //所有车先都设置为障碍
tarSites.forEach(site -> { tarSites.forEach(site -> {
int[] pos = site.getStartPoint(); int[] pos = site.getStartPoint();
@@ -507,7 +488,6 @@ public class PathFinder {
} }
// 计算路径 // 计算路径
List<int[]> path = findShortestPath(grid, startPoint[0], startPoint[1], srcSite.getStartPoint()[0], srcSite.getStartPoint()[1]); List<int[]> path = findShortestPath(grid, startPoint[0], startPoint[1], srcSite.getStartPoint()[0], srcSite.getStartPoint()[1]);
if (path == null) { if (path == null) {
@@ -515,7 +495,6 @@ public class PathFinder {
} }
// 检查路径冲突 // 检查路径冲突
boolean blocked = tarSites.stream() boolean blocked = tarSites.stream()
.filter(other -> other != car) .filter(other -> other != car)
@@ -552,7 +531,7 @@ public class PathFinder {
* 载货查找最佳,使用情景 * 载货查找最佳,使用情景
* *
* */ * */
public static Site findOptimalWithCargo(int[][] grid, Site srcSite, List<Site> tarSites){ public static Site findOptimalWithCargo(int[][] grid, Site srcSite, List<Site> tarSites) {
// 并行计算所有车辆的路径 // 并行计算所有车辆的路径
Map<Site, PathInfo> carPathInfo = tarSites.parallelStream() Map<Site, PathInfo> carPathInfo = tarSites.parallelStream()
@@ -572,7 +551,6 @@ public class PathFinder {
} }
// 检查路径冲突 // 检查路径冲突
boolean blocked = tarSites.stream() boolean blocked = tarSites.stream()
.filter(other -> other != car) .filter(other -> other != car)
@@ -605,13 +583,12 @@ public class PathFinder {
} }
/* /*
* 空载查找最佳,使用情景 * 空载查找最佳,使用情景
* 小车不载货,一个原点(目标点),多个目标点(原点) * 小车不载货,一个原点(目标点),多个目标点(原点)
* *
* */ * */
public static Site findOptimalWithNoCargo(int[][] grid, Site srcSite, List<Site> tarSites){ public static Site findOptimalWithNoCargo(int[][] grid, Site srcSite, List<Site> tarSites) {
// 并行计算所有车辆的路径 // 并行计算所有车辆的路径
@@ -625,7 +602,6 @@ public class PathFinder {
} }
// 计算路径 // 计算路径
List<int[]> path = findShortestPath(grid, startPoint[0], startPoint[1], srcSite.getStartPoint()[0], srcSite.getStartPoint()[1]); List<int[]> path = findShortestPath(grid, startPoint[0], startPoint[1], srcSite.getStartPoint()[0], srcSite.getStartPoint()[1]);
if (path == null) { if (path == null) {
@@ -634,7 +610,6 @@ public class PathFinder {
} }
// 检查路径冲突 // 检查路径冲突
boolean blocked = tarSites.stream() boolean blocked = tarSites.stream()
.filter(other -> other != car) .filter(other -> other != car)
@@ -669,11 +644,10 @@ public class PathFinder {
} }
/* /*
* *
* 同层多车选择最优 * 同层多车选择最优
* */ * */
/* /*
* *
* 同层多车选择最优 * 同层多车选择最优
@@ -743,9 +717,6 @@ public class PathFinder {
} }
public static Site findOptimalCarForDestinationByFull( public static Site findOptimalCarForDestinationByFull(
int[][] grid, int endX, int endY, List<Site> cars) { int[][] grid, int endX, int endY, List<Site> cars) {
// 创建网格副本 // 创建网格副本
@@ -878,7 +849,4 @@ public class PathFinder {
} }
} }

View File

@@ -570,67 +570,7 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
// endSite="07050"+deviceSrgv.getCurrFloor(); // endSite="07050"+deviceSrgv.getCurrFloor();
// } // }
// //
String endBlockAgv = null;
DeviceSrgv endBlockDevice = null;
// TODO 通过arrByRoadSite 中的站点 查询是否存在其他车的站点,如果存在则生成其他车到避让点的队列
if (arrByRoadSite != null && !arrByRoadSite.isEmpty()) {
// 将arrByRoadSite转为String类型的Set(统一类型,方便匹配)
Set<String> roadSiteSet = arrByRoadSite.keySet().stream()
.filter(Objects::nonNull) // 过滤集合中的null值
.map(Object::toString) // 转为字符串,适配站点类型
.collect(Collectors.toSet());
// 2. Stream流式处理deviceSrgvMap
Optional<Map.Entry<String, DeviceSrgv>> targetEntry = PlcSrgvRead.deviceSrgvMap.entrySet().stream()
.filter(entry -> entry.getValue() != null) // 过滤other为null的条目
// 条件1:other的当前站点存在于roadSiteSet中
.filter(entry -> roadSiteSet.contains(entry.getValue().getCurrSite()))
// 条件2:设备ID不等于当前entry的key
.filter(entry -> !Objects.equals(Convert.toStr(deviceSrgv.getDeviceId()), entry.getKey()))
.findFirst(); // 找到第一个符合条件的条目(等价于原代码的break)
// 3. 处理结果(若找到则赋值)
if (targetEntry.isPresent()) {
endBlockAgv = targetEntry.get().getKey();
endBlockDevice = targetEntry.get().getValue();
}
}
WcsSrgvQueue wcsSrgvQueueBR = new WcsSrgvQueue();
wcsSrgvQueueBR.setAgvId(endBlockAgv);
List<WcsSrgvQueue> wcsSrgvQueueBRS = wcsSagvQueueMapper.selectWcsSrgvQueueList(wcsSrgvQueueBR);
if (endBlockDevice != null && wcsSrgvQueueBRS.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("1"); // 点到点移动
taskB.setDefault02("4"); // 业务类型标识为点到点
taskB.setPriority(9L); // 高优先级,尽快避让
taskB.setIssued("0"); // 未下发
taskB.setExecutionStatus("1");// 初始状态
taskB.setStartSite(endBlockDevice.getCurrSite());
taskB.setCargoPickSite(endBlockDevice.getCurrSite());
taskB.setCargoPlaceSite("05020"+endBlockDevice.getCurrFloor());
taskB.setEndSite("05020"+endBlockDevice.getCurrFloor());
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, "02050"+endBlockDevice.getCurrFloor());
// 当前车等待下一轮调度(待阻挡车移开后自然可达)
return false;
}
//处理地图 //处理地图
int[][] emptyMap = roadCacheService.handleMap(arrByRoadSite, deviceSrgv); int[][] emptyMap = roadCacheService.handleMap(arrByRoadSite, deviceSrgv);
@@ -638,6 +578,72 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
//计算最短路径 //计算最短路径
List<int[]> shortestPath = PathFinder.findShortestPath(emptyMap, arrByRoadSite.get(startSite).getX(), arrByRoadSite.get(startSite).getY(), arrByRoadSite.get(endSite).getX(), arrByRoadSite.get(endSite).getY()); List<int[]> shortestPath = PathFinder.findShortestPath(emptyMap, arrByRoadSite.get(startSite).getX(), arrByRoadSite.get(startSite).getY(), arrByRoadSite.get(endSite).getX(), arrByRoadSite.get(endSite).getY());
if (shortestPath.size() == 1 && shortestPath.get(0)[0] == -1 && shortestPath.get(0)[1] == -1) {
shortestPath = null;
String endBlockAgv = null;
DeviceSrgv endBlockDevice = null;
// TODO 通过arrByRoadSite 中的站点 查询是否存在其他车的站点,如果存在则生成其他车到避让点的队列
if (arrByRoadSite != null && !arrByRoadSite.isEmpty()) {
// 将arrByRoadSite转为String类型的Set(统一类型,方便匹配)
Set<String> roadSiteSet = arrByRoadSite.keySet().stream()
.filter(Objects::nonNull) // 过滤集合中的null值
.map(Object::toString) // 转为字符串,适配站点类型
.collect(Collectors.toSet());
// 2. Stream流式处理deviceSrgvMap
Optional<Map.Entry<String, DeviceSrgv>> targetEntry = PlcSrgvRead.deviceSrgvMap.entrySet().stream()
.filter(entry -> entry.getValue() != null) // 过滤other为null的条目
// 条件1:other的当前站点存在于roadSiteSet中
.filter(entry -> roadSiteSet.contains(entry.getValue().getCurrSite()))
// 条件2:设备ID不等于当前entry的key
.filter(entry -> !Objects.equals(Convert.toStr(deviceSrgv.getDeviceId()), entry.getKey()))
.findFirst(); // 找到第一个符合条件的条目(等价于原代码的break)
// 3. 处理结果(若找到则赋值)
if (targetEntry.isPresent()) {
endBlockAgv = targetEntry.get().getKey();
endBlockDevice = targetEntry.get().getValue();
}
}
WcsSrgvQueue wcsSrgvQueueBR = new WcsSrgvQueue();
wcsSrgvQueueBR.setAgvId(endBlockAgv);
List<WcsSrgvQueue> wcsSrgvQueueBRS = wcsSagvQueueMapper.selectWcsSrgvQueueList(wcsSrgvQueueBR);
if (endBlockDevice != null && wcsSrgvQueueBRS.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("1"); // 点到点移动
taskB.setDefault02("4"); // 业务类型标识为点到点
taskB.setPriority(9L); // 高优先级,尽快避让
taskB.setIssued("0"); // 未下发
taskB.setExecutionStatus("1");// 初始状态
taskB.setStartSite(endBlockDevice.getCurrSite());
taskB.setCargoPickSite(endBlockDevice.getCurrSite());
taskB.setCargoPlaceSite("05020" + endBlockDevice.getCurrFloor());
taskB.setEndSite("05020" + endBlockDevice.getCurrFloor());
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("目标点 {" + deviceSrgv.getCurrSite() + "} 被小车 {" + deviceSrgv.getDeviceId() + "} 占用,已调度其前往避让点 {}", endSite, endBlockAgv, "02050" + endBlockDevice.getCurrFloor());
// 当前车等待下一轮调度(待阻挡车移开后自然可达)
return false;
}
}
//判断是否能规划出最短路径 //判断是否能规划出最短路径
if (shortestPath == null || shortestPath.isEmpty()) { if (shortestPath == null || shortestPath.isEmpty()) {
//判断是否是1层 空车取货 或者 满车放货 //判断是否是1层 空车取货 或者 满车放货
@@ -697,9 +703,11 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
return false; return false;
} }
//获取拐点路径 //获取拐点路径
List<int[]> trun = PathFinder.extractInflectionPoints2(shortestPath); List<int[]> trun = PathFinder.extractInflectionPoints2(shortestPath);
// 路径点拼接 // 路径点拼接
StringBuilder pathBuilder = new StringBuilder(); StringBuilder pathBuilder = new StringBuilder();
if (!shortestPath.isEmpty()) { if (!shortestPath.isEmpty()) {