From 548f55109aeda9ce1cb46aee10669a335075fe6d Mon Sep 17 00:00:00 2001 From: liuhanqing Date: Thu, 27 Nov 2025 15:40:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=8F=E8=BD=A6=E8=B0=83=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bas/srgvmap/service/RoadCacheService.java | 46 +-- .../service/impl/AgvPathProcessor.java | 77 +++- .../service/impl/RoadCacheServiceImpl.java | 389 +++++------------- .../plcRead/srgv/roadUtil/PathFinder.java | 35 +- .../scheduleTask/srgv/BaseSRgvThread.java | 382 +++-------------- 5 files changed, 273 insertions(+), 656 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/bas/srgvmap/service/RoadCacheService.java b/ruoyi-admin/src/main/java/com/ruoyi/bas/srgvmap/service/RoadCacheService.java index be913df..419543a 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/bas/srgvmap/service/RoadCacheService.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/bas/srgvmap/service/RoadCacheService.java @@ -9,30 +9,26 @@ import java.util.Map; public interface RoadCacheService { + /** + * 获取指定楼层的缓存 + * @param floor 楼层 + * @return + */ + Map getArrByRoadSite(Integer floor); - int[][] updateRoadCache(int floor, List grid ,int value); - - List findFullPath(int floor, int startX, int startY, int endX, int endY); - int[][] findFullMap(int floor, int startX, int startY, int endX, int endY); - int[][] findFullMap(int floor, int startX, int startY, int endX, int endY, DeviceSrgv srgvPlc); - - List findEmptyPath(int floor, int startX, int startY, int endX, int endY); - - int[][] findEmptyMap(int floor, int startX, int startY, int endX, int endY); - int[][] findEmptyMap(int floor, int startX, int startY, int endX, int endY, DeviceSrgv splc); - - Map getRoadSiteByArr(int floor); - - int[][] getRoadCache(int floor); - - Map getArrByRoadSite(int floor); - - List getRoadDataCache(int floor); - - - int[][] findMap(int floor); - - int[][] findFullMap(int floor, int startX, int startY, int endX, int endY,DeviceSrgv srgvPlc,List noSite); - - Map getSpaceDataCache(); + /** + * 处理地图 + * @param arrByRoadSite + * @param deviceSrgv + * @return + */ + int[][] handleMap(Map arrByRoadSite, DeviceSrgv deviceSrgv); + /** + * 根据x y z 获取指定位置的缓存 + * @param x + * @param y + * @param z + * @return + */ + WcsSrgvMap selectRoadSiteByArr(int x, int y, int z); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/bas/srgvmap/service/impl/AgvPathProcessor.java b/ruoyi-admin/src/main/java/com/ruoyi/bas/srgvmap/service/impl/AgvPathProcessor.java index af17c9d..f236619 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/bas/srgvmap/service/impl/AgvPathProcessor.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/bas/srgvmap/service/impl/AgvPathProcessor.java @@ -1,18 +1,19 @@ package com.ruoyi.bas.srgvmap.service.impl; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; import com.ruoyi.bas.srgvmap.domain.WcsSrgvMap; import com.ruoyi.bas.srgvmap.service.IWcsSrgvMapService; import com.ruoyi.bas.srgvmap.service.RoadCacheService; import com.ruoyi.device.srgv.domain.DeviceSrgv; import com.ruoyi.device.srgv.service.IDeviceSrgvService; +import com.ruoyi.queue.srgv.domain.WcsSrgvQueue; import com.ruoyi.queue.srgv.service.IWcsSrgvQueueService; +import com.ruoyi.schedule.plcRead.srgv.PlcSrgvRead; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; @Component @@ -31,14 +32,76 @@ public class AgvPathProcessor { public void processNoSites(int[][] roadCache, int floor, List noSite) { } - public void processAgvPathInfo(int[][] ints, int floor) { + public void processAgvPathInfo(Map maps,Integer agvId) { + List wcsSrgvQueues = wcsSagvQueueMapper.selectWcsSrgvQueueList(new WcsSrgvQueue()); + if (CollUtil.isNotEmpty(wcsSrgvQueues)) { + //筛选其他小车队列 + wcsSrgvQueues = wcsSrgvQueues.stream().filter(x -> x.getAgvId().equals(Convert.toStr(agvId))).collect(Collectors.toList()); + + //获取其他小车占用点位列表 + HashSet siteList = new HashSet<>(); + for (WcsSrgvQueue wcsSrgvQueue : wcsSrgvQueues) { + String[] split = wcsSrgvQueue.getPathInfo().split(","); + siteList.addAll(Arrays.asList(split)); + } + + //设置其他小车占用点位 + for (String site : siteList) { + if (maps.containsKey(site)){ + maps.get(site).setValue(0); + } + } + } } - public void processOnlineAgvSites(int[][] ints, int floor) { + /** + * 更新AGV路径映射,只保留当前站点及以后的路径 + */ + private void updateAgvPathMap(Map agvPathMap, List srgvPlcs) { + for (SRGVPlc plc : srgvPlcs) { + com.ruoyi.plc.sagv.SRGVData agvData = plc.getAgvData(); + if (agvData != null && agvData.getAgvId() != null) { + String agvId = agvData.getAgvId(); + String currSite = agvData.getCurrSite(); + + // 如果这个agvId在agvPathMap中存在,且currSite不为空 + if (agvPathMap.containsKey(agvId) && currSite != null) { + String pathInfo = agvPathMap.get(agvId); + + // 处理路径信息,只保留当前站点及以后的路径 + if (pathInfo != null && !pathInfo.isEmpty()) { + String[] pathArray = pathInfo.split(","); + StringBuilder newPathBuilder = new StringBuilder(); + + boolean foundCurrentSite = false; + for (String site : pathArray) { + if (site.trim().equals(currSite.trim())) { + foundCurrentSite = true; + } + + if (foundCurrentSite) { + if (newPathBuilder.length() > 0) { + newPathBuilder.append(","); + } + newPathBuilder.append(site); + } + } + + // 如果找到了当前站点,更新路径信息 + if (foundCurrentSite) { + agvPathMap.put(agvId, newPathBuilder.toString()); + } + } + } + } + } } - public void processOfflineAgvSites(int[][] ints, int floor) { + public void processOnlineAgvSites(Map maps) { + } + + public void processOfflineAgvSites(Map maps) { } /** diff --git a/ruoyi-admin/src/main/java/com/ruoyi/bas/srgvmap/service/impl/RoadCacheServiceImpl.java b/ruoyi-admin/src/main/java/com/ruoyi/bas/srgvmap/service/impl/RoadCacheServiceImpl.java index fdc2f36..38ebc31 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/bas/srgvmap/service/impl/RoadCacheServiceImpl.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/bas/srgvmap/service/impl/RoadCacheServiceImpl.java @@ -1,311 +1,150 @@ package com.ruoyi.bas.srgvmap.service.impl; -import cn.hutool.core.convert.Convert; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; import com.ruoyi.bas.srgvmap.domain.WcsSrgvMap; import com.ruoyi.bas.srgvmap.mapper.WcsSrgvMapMapper; import com.ruoyi.bas.srgvmap.service.RoadCacheService; import com.ruoyi.device.srgv.domain.DeviceSrgv; -import com.ruoyi.schedule.plcRead.srgv.roadUtil.PathFinder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.ruoyi.device.srgv.service.IDeviceSrgvService; +import com.ruoyi.queue.srgv.domain.WcsSrgvQueue; +import com.ruoyi.queue.srgv.service.IWcsSrgvQueueService; +import com.ruoyi.schedule.plcRead.srgv.PlcSrgvRead; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.CacheManager; -import org.springframework.cache.annotation.CachePut; -import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.*; +import java.util.stream.Collectors; @Service +@Slf4j public class RoadCacheServiceImpl implements RoadCacheService { - private final Logger log = LoggerFactory.getLogger(this.getClass()); - - @Autowired private WcsSrgvMapMapper wcsSrgvMapMapper; - @Autowired - private CacheManager cacheManager; - - + private IWcsSrgvQueueService wcsSrgvQueueService; @Autowired - private RoadCacheService selfProxy; // 注入代理对象 + private IDeviceSrgvService deviceSrgvService; - @Autowired - private AgvPathProcessor agvPathProcessor; + @Override + public Map getArrByRoadSite(Integer floor) { + WcsSrgvMap param = new WcsSrgvMap(); + param.setZ(floor); + List wcsSrgvMaps = wcsSrgvMapMapper.selectWcsSrgvMapList(param); + HashMap maps = new HashMap<>(); + for (WcsSrgvMap wcsSrgvMap : wcsSrgvMaps) { + maps.put(wcsSrgvMap.getSiteId(), wcsSrgvMap); + } + return maps; + } - /* - * - * - * */ - @Autowired - @Cacheable(value = "CSpaceDataCache" ,key = "'CSpaceDataCacheKey_'") - public Map getSpaceDataCache() { - log.info("从数据库获取初始化地图数据"); + @Override + public int[][] handleMap(Map maps, DeviceSrgv deviceSrgv) { - WcsSrgvMap wcsSrgvMap = new WcsSrgvMap(); - List wcsSrgvMaps = wcsSrgvMapMapper.selectWcsSrgvMapList(wcsSrgvMap); - //将集合转为map, - Map siteMap = new HashMap<>(); + //1.锁定其他车任务路径 + lockedOtherCarQueuePath(maps, deviceSrgv); + //2.锁定无任务小车当前位置 + lockedOtherCarCurrSite(maps, deviceSrgv); + //3.锁定离线小车当前位置 + lockedOfflineCarCurrSite(maps, deviceSrgv); - for (WcsSrgvMap srgvMap : wcsSrgvMaps) { - String siteId = srgvMap.getSiteId(); - String warehouse = srgvMap.getWarehouse(); - if(!Objects.equals(siteId,"000")){ - siteMap.put(siteId,warehouse); + int[][] mapsInt = new int[29][11]; + for (String site : maps.keySet()) { + WcsSrgvMap wcsSrgvMap = maps.get(site); + mapsInt[wcsSrgvMap.getX()][wcsSrgvMap.getY()] = wcsSrgvMap.getValue(); + } + return mapsInt; + } + + @Override + public WcsSrgvMap selectRoadSiteByArr(int x, int y, int z) { + WcsSrgvMap param = new WcsSrgvMap(); + param.setX(x); + param.setY(y); + param.setZ(z); + List wcsSrgvMaps = wcsSrgvMapMapper.selectWcsSrgvMapList(param); + if (CollUtil.isNotEmpty(wcsSrgvMaps)){ + return wcsSrgvMaps.get(0); + } + return null; + } + + /** + * 锁定离线小车当前位置 + * + * @param maps + * @param deviceSrgv + */ + private void lockedOfflineCarCurrSite(Map maps, DeviceSrgv deviceSrgv) { + //获取所有小车状态 + List deviceSrgvs = deviceSrgvService.selectDeviceSrgvList(new DeviceSrgv()); + //获取其他小车离线站点 + List offlineSrgvList = deviceSrgvs.stream().filter(x -> + !x.getDeviceId().equals(deviceSrgv.getDeviceId()) && + StrUtil.isNotEmpty(x.getOfflineSite()) + ).collect(Collectors.toList()); + //锁定离线小车站点 + if (CollUtil.isNotEmpty(offlineSrgvList)) { + for (DeviceSrgv offlineSrgv : offlineSrgvList) { + if (maps.containsKey(offlineSrgv.getOfflineSite())) { + maps.get(offlineSrgv.getOfflineSite()).setValue(0); + } } } - - - return siteMap; } - - @Cacheable(value = "RoadDataCache" ,key = "'RoadDataCacheKey_floor_' +#floor") - @Override - public List getRoadDataCache(int floor) { - log.info("从数据库获取初始化地图"); - - WcsSrgvMap wcsSrgvMap1 = new WcsSrgvMap(); - wcsSrgvMap1.setUz(floor); - List wcsSrgvMaps = wcsSrgvMapMapper.selectWcsSrgvMapList(wcsSrgvMap1); - - return wcsSrgvMaps; - } - - /* - * - * 每层二维地图 - * */ - @Override - @Cacheable(value = "RoadCache" ,key = "'RoadCacheKey_floor_' +#floor") - public int[][] getRoadCache(int floor) { - - List roadDataCache = selfProxy.getRoadDataCache(floor); - - //集合转为二维数组 - int[][] grid = new int[30][137]; - for (WcsSrgvMap roadMap : roadDataCache) { - grid[roadMap.getX().intValue()][roadMap.getY().intValue()] = roadMap.getValue().intValue(); + /** + * 锁定无任务小车当前位置 + * + * @param arrByRoadSite + * @param deviceSrgv + */ + private void lockedOtherCarCurrSite(Map arrByRoadSite, DeviceSrgv deviceSrgv) { + //锁定其他车当前位置 + for (String sRgv : PlcSrgvRead.deviceSrgvMap.keySet()) { + if (!sRgv.equals(deviceSrgv.getDeviceId().toString())) { + DeviceSrgv otherCar = PlcSrgvRead.deviceSrgvMap.get(sRgv); + String currSite = otherCar.getCurrSite(); + if (arrByRoadSite.containsKey(currSite)) { + arrByRoadSite.get(currSite).setValue(0); + } + } } - - return grid; } - - /* - * - * 每层 站点与二维数组关系 - * */ - @Override - @CachePut(value = "SiteCache" ,key = "'SiteKey_floor_' +#floor") - public Map getArrByRoadSite(int floor) { - List roadDataCache = selfProxy.getRoadDataCache(floor); - - //将集合转为map,key为siteId,value为x,y - Map siteMap = new HashMap<>(); - for (WcsSrgvMap map : roadDataCache) { - siteMap.put(map.getSiteId(), new int[]{map.getX(), map.getY(),floor}); + /** + * 锁定其他车任务路径 + * + * @param maps + * @param deviceSrgv + */ + private void lockedOtherCarQueuePath(Map maps, DeviceSrgv deviceSrgv) { + //查询所有小车作业 + List wcsSrgvQueues = wcsSrgvQueueService.selectWcsSrgvQueueList(new WcsSrgvQueue()); + if (CollUtil.isNotEmpty(wcsSrgvQueues)) { + //筛选其他小车队列 + List otherCarQueue = wcsSrgvQueues.stream().filter(x -> !x.getAgvId().equals(deviceSrgv.getDeviceId().toString())).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(otherCarQueue)) { + //添加其他小车路径列表 + HashSet otherCarSiteList = new HashSet<>(); + for (WcsSrgvQueue wcsSrgvQueue : otherCarQueue) { + otherCarSiteList.addAll(Arrays.asList(wcsSrgvQueue.getPathInfo().split(","))); + } + //锁定其他小车路径 + if (CollUtil.isNotEmpty(otherCarSiteList)) { + for (String siteId : otherCarSiteList) { + if (maps.containsKey(siteId)) { + maps.get(siteId).setValue(0); + } + } + } + } } - - return siteMap; - } - - /* - * - * - * */ - @Override - @CachePut(value = "ArrCache" ,key = "'ArrKey_floor_' +#floor") - public Map getRoadSiteByArr(int floor) { - List roadDataCache = selfProxy.getRoadDataCache(floor); - - //将集合转为map,key为x,y,value为siteId - Map siteMap = new HashMap<>(); - for (WcsSrgvMap map : roadDataCache) { - siteMap.put(map.getX()+","+map.getY(), map.getSiteId()); - } - - return siteMap; - } - - - - //更新地图 - @Override - @CachePut(value = "RoadCache" ,key = "'RoadCacheKey_floor_' +#floor") - public int[][] updateRoadCache(int floor, List grid,int value) { - - - int[][] roadCache = selfProxy.getRoadCache(floor); - - for (int[] ints : grid) { - roadCache[ints[0]][ints[1]] = value; - } - - return roadCache; - } - - - //获取载货路径 - @Override - public List findFullPath(int floor, int startX, int startY, int endX, int endY) { - - int[][] grid = selfProxy.getRoadCache(floor); - - //对二维数组 进行深拷贝 - int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new); - - //剔除不允许站点 - extractInflectionPoints(roadCache,floor); - - // 调用路径规划算法 - return PathFinder.findShortestPathFrom2To2Or1(roadCache,startX,startY,endX,endY); - } - - - @Override - public int[][] findFullMap(int floor, int startX, int startY, int endX, int endY) { - - int[][] grid = selfProxy.getRoadCache(floor); - - //对二维数组 进行深拷贝 - int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new); - - //剔除不允许站点 - extractInflectionPoints(roadCache,floor); - - // 调用路径规划算法 - return roadCache; - } - - @Override - public int[][] findFullMap(int floor, int startX, int startY, int endX, int endY,DeviceSrgv splc) { - - int[][] grid = selfProxy.getRoadCache(floor); - - //对二维数组 进行深拷贝 - int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new); - - //剔除不允许站点(不包含自己) - extractInflectionPoints(roadCache,floor,splc); - - // 调用路径规划算法 - return roadCache; - } - - @Override - public int[][] findFullMap(int floor, int startX, int startY, int endX, int endY,DeviceSrgv splc,List noSite) { - - int[][] grid = selfProxy.getRoadCache(floor); - - //对二维数组 进行深拷贝 - int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new); - - //剔除不允许站点(不包含自己) - extractInflectionPoints(roadCache,floor,splc); - - //将地图 roadCache 中的 所有站点noSite排除掉 - agvPathProcessor.processNoSites(roadCache,floor,noSite); - - // 调用路径规划算法 - return roadCache; - } - - - //获取空载路径 - @Override - public List findEmptyPath(int floor, int startX, int startY, int endX, int endY) { - - - int[][] grid = selfProxy.getRoadCache(floor); - - //对二维数组 进行深拷贝 - int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new); - - //剔除不允许站点 - extractInflectionPoints(roadCache,floor); - - List shortestPath = PathFinder.findShortestPath(grid, startX, startY, endX, endY); - return shortestPath; - } - - - @Override - public int[][] findEmptyMap(int floor, int startX, int startY, int endX, int endY, DeviceSrgv splc) { - - - int[][] grid = selfProxy.getRoadCache(floor); - - //对二维数组 进行深拷贝 - int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new); - - //剔除不允许站点(不包含自己) - extractInflectionPoints(roadCache,floor,splc); - - - return roadCache; - } - - @Override - public int[][] findEmptyMap(int floor, int startX, int startY, int endX, int endY) { - - - int[][] grid = selfProxy.getRoadCache(floor); - - //对二维数组 进行深拷贝 - int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new); - - //剔除不允许站点 - extractInflectionPoints(roadCache,floor); - - - return roadCache; - } - - /* - * 剔除不可用站点,并返回新地图 - * - * */ - private int[][] extractInflectionPoints(int[][] ints,int floor){ - - - //所有车锁定路径 - agvPathProcessor.processAgvPathInfo(ints,floor); - //所有在线车当前站点 - agvPathProcessor.processOnlineAgvSites(ints,floor); - //所有离线车站点 - agvPathProcessor.processOfflineAgvSites(ints,floor); - - return ints; - } - - private int[][] extractInflectionPoints(int[][] ints, int floor, DeviceSrgv splc){ - - String agvId = String.valueOf(splc.getDeviceId()); - String currSite = splc.getCurrSite(); - //所有车锁定路径 - agvPathProcessor.processAgvPathInfo(ints,floor); - //所有在线车当前站点 - agvPathProcessor.processOnlineAgvSites(ints,floor); - //所有离线车站点 - agvPathProcessor.processOfflineAgvSites(ints,floor); - - return ints; - } - - @Override - public int[][] findMap(int floor) { - int[][] grid = selfProxy.getRoadCache(floor); - - //对二维数组 进行深拷贝 - int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new); - - return roadCache; } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/schedule/plcRead/srgv/roadUtil/PathFinder.java b/ruoyi-admin/src/main/java/com/ruoyi/schedule/plcRead/srgv/roadUtil/PathFinder.java index cf59420..d3e394c 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/schedule/plcRead/srgv/roadUtil/PathFinder.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/schedule/plcRead/srgv/roadUtil/PathFinder.java @@ -128,7 +128,7 @@ public class PathFinder { int[][] gCost = new int[rows][cols]; // fCost: gCost + 启发式估计成本(从当前节点到终点) int[][] fCost = new int[rows][cols]; - // prev: 记录路径回溯信息 + // prev: 记录路径回溯信息,初始化为无效值 int[][][] prev = new int[rows][cols][2]; // closedSet: 记录已访问的节点 boolean[][] closedSet = new boolean[rows][cols]; @@ -137,6 +137,10 @@ public class PathFinder { for (int i = 0; i < rows; i++) { Arrays.fill(gCost[i], Integer.MAX_VALUE); Arrays.fill(fCost[i], Integer.MAX_VALUE); + // 初始化 prev 数组为无效值 [-1, -1] + for (int j = 0; j < cols; j++) { + prev[i][j] = new int[]{-1, -1}; + } } // 优先队列,按fCost排序 @@ -211,8 +215,8 @@ public class PathFinder { path.add(new int[]{currX, currY}); int[] p = prev[currX][currY]; - // 检查路径有效性 - if (p[0] == 0 && p[1] == 0 && (currX != startX || currY != startY)) { + // 检查路径有效性,使用 -1,-1 作为无效值判断 + if (p[0] == -1 && p[1] == -1 && (currX != startX || currY != startY)) { return null; } @@ -403,32 +407,13 @@ public class PathFinder { * - 方向变化点(水平转垂直 / 垂直转水平) * * @param path 路径坐标列表(逻辑坐标) - * @param grid 网格数据 * @return 拐点坐标列表(逻辑坐标) */ - public static List extractInflectionPoints2(List path, int[][] grid) { + public static List extractInflectionPoints2(List path) { List inflectionPoints = new ArrayList<>(); // 记录类型转换点和方向变化点 Set seen = new HashSet<>(); - - // 检测类型转换点(1 ↔ 2) - /*for (int i = 0; i < path.size() - 1; i++) { - int[] current = path.get(i); - int[] next = path.get(i + 1); - int currentValue = grid[current[0]][current[1]]; - int nextValue = grid[next[0]][next[1]]; - - if ((currentValue == 1 && nextValue == 2) || (currentValue == 2 && nextValue == 1)) { - int[] point = currentValue == 2 ? current : next; - String key = point[0] + "," + point[1]; - if (!seen.contains(key)) { - seen.add(key); - inflectionPoints.add(point); - } - } - }*/ - // 检测方向变化点(连续三点的方向变化) for (int i = 1; i < path.size() - 1; i++) { int[] prev = path.get(i - 1); @@ -448,9 +433,7 @@ public class PathFinder { } // 排序后返回(可选) - return inflectionPoints; /*.stream() - .sorted(Comparator.comparingInt(a -> a[0] * 1000 + a[1])) - .collect(Collectors.toList());*/ + return inflectionPoints; } /* diff --git a/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/srgv/BaseSRgvThread.java b/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/srgv/BaseSRgvThread.java index 8063cbb..a71a08a 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/srgv/BaseSRgvThread.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/srgv/BaseSRgvThread.java @@ -5,7 +5,6 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ObjUtil; -import com.ruoyi.bas.port.domain.WcsPort; import com.ruoyi.bas.port.service.IWcsPortService; import com.ruoyi.bas.srgvmap.domain.WcsSrgvMap; import com.ruoyi.bas.srgvmap.service.IWcsSrgvMapService; @@ -75,17 +74,14 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface { if (ObjUtil.isNotNull(PlcSrgvRead.deviceSrgvMap.get(code))) { DeviceSrgv deviceSrgv = PlcSrgvRead.deviceSrgvMap.get(code); - //循环所有楼层 - for (int i = 1; i <= 8; i++) { - sRgvTask(deviceSrgv, i); - } + sRgvTask(deviceSrgv); createCarInQueue(); createCarOutQueue(); } else { - log.error("堆垛机设备为空"); + log.error("小车设备为空"); } } } catch (RuntimeException e) { @@ -107,15 +103,15 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface { /** * 四向小车任务处理 */ - private void sRgvTask(DeviceSrgv deviceSrgv, int floor) { + private void sRgvTask(DeviceSrgv deviceSrgv) { //处理队列下发 - resQueue(deviceSrgv, floor); + resQueue(deviceSrgv); //小车完成队列 - completeCarTask(deviceSrgv, floor); + completeCarTask(deviceSrgv); //小车发送任务 - sendTask(deviceSrgv, floor); + sendTask(deviceSrgv); } @@ -213,10 +209,10 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface { /** * 小车发送任务 */ - private void sendTask(DeviceSrgv deviceSrgv, int floor) { + private void sendTask(DeviceSrgv deviceSrgv) { WcsSrgvQueue param = new WcsSrgvQueue(); param.setIssued("0"); - param.setTheFloor(Convert.toStr(floor)); + param.setAgvId(deviceSrgv.getDeviceId().toString()); List wcsSrgvQueues = wcsSagvQueueMapper.selectWcsSrgvQueueList(param); if (CollUtil.isEmpty(wcsSrgvQueues)) { return; @@ -232,10 +228,10 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface { //判断小车是否在起始点 if (currSite.equals(startSite)) { //小车在起始点 - sendMainTask(deviceSrgv, wcsSrgvQueue, currSite, endSite, floor); + sendMainTask(deviceSrgv, wcsSrgvQueue, currSite, endSite); } else { //小车不在起始点 - sendPointToPointTask(deviceSrgv, wcsSrgvQueue, currSite, startSite, floor); + sendPointToPointTask(deviceSrgv, wcsSrgvQueue, currSite, startSite); } } } @@ -246,51 +242,58 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface { /** * 小车发送点对点任务 */ - private void sendPointToPointTask(DeviceSrgv deviceSrgv, WcsSrgvQueue wcsSrgvQueue, String startSite, String endSite, int floor) { + private boolean sendPointToPointTask(DeviceSrgv deviceSrgv, WcsSrgvQueue wcsSrgvQueue, String startSite, String endSite) { + Integer floor = deviceSrgv.getCurrFloor(); //获取当前地图 - Map arrByRoadSite = roadCacheService.getArrByRoadSite(floor); + Map arrByRoadSite = roadCacheService.getArrByRoadSite(floor); + + //处理地图 + int[][] emptyMap = roadCacheService.handleMap(arrByRoadSite, deviceSrgv); - //获取空载地图 - int[][] emptyMap = roadCacheService.findEmptyMap(floor, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1], deviceSrgv); //计算最短路径 - List shortestPath = PathFinder.findShortestPath(emptyMap, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1]); + List shortestPath = PathFinder.findShortestPath(emptyMap, arrByRoadSite.get(startSite).getX(), arrByRoadSite.get(startSite).getY(), arrByRoadSite.get(endSite).getX(), arrByRoadSite.get(endSite).getY()); //判断是否能规划出最短路径 if (shortestPath == null || shortestPath.isEmpty()) { - return; + log.error("无最短路径 taskNo:{}", wcsSrgvQueue.getTaskNo()); + return false; } //获取拐点路径 - List trun = PathFinder.extractInflectionPoints2(shortestPath, emptyMap); + List trun = PathFinder.extractInflectionPoints2(shortestPath); // 路径点拼接 StringBuilder pathBuilder = new StringBuilder(); - Map roadSiteByArr = roadCacheService.getRoadSiteByArr(floor); - for (int[] point : shortestPath) { - String site = roadSiteByArr.get(point[0] + "," + point[1]); - if (!"000".equals(site)) { + if (!shortestPath.isEmpty()) { + for (int[] ints : shortestPath) { + WcsSrgvMap roadSiteByArr = roadCacheService.selectRoadSiteByArr(ints[0], ints[1], floor); + if (roadSiteByArr == null) { + log.error("无此站点 x y z :{},{},{}", ints[0], ints[1], floor); + throw new RuntimeException("点位信息错误"); + } + String site = roadSiteByArr.getSiteId(); pathBuilder.append(site).append(","); } - } - if (pathBuilder.length() > 0) { - pathBuilder.setLength(pathBuilder.length() - 1); // 移除最后一个逗号 - } - // 拐点拼接 - StringBuilder inflectionBuilder = new StringBuilder(); + StringBuilder turnBuilder = new StringBuilder(); if (!trun.isEmpty()) { for (int[] ints : trun) { - String site = roadSiteByArr.get(ints[0] + "," + ints[1]);//获取站点 - inflectionBuilder.append(site).append(","); + WcsSrgvMap roadSiteByArr = roadCacheService.selectRoadSiteByArr(ints[0], ints[1], floor); + if (roadSiteByArr == null) { + log.error("无此站点 x y z :{},{},{}", ints[0], ints[1], floor); + throw new RuntimeException("点位信息错误"); + } + String site = roadSiteByArr.getSiteId(); + turnBuilder.append(site).append(","); } - if (inflectionBuilder.length() > 0) { - inflectionBuilder.setLength(inflectionBuilder.length() - 1); + if (turnBuilder.length() > 0) { + turnBuilder.setLength(turnBuilder.length() - 1); } // 当trun长度小于6时,后面用0拼接 if (trun.size() < 6) { for (int i = trun.size(); i < 6; i++) { - inflectionBuilder.append(",0"); + turnBuilder.append(",0"); } } } @@ -299,7 +302,7 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface { if (!trun.isEmpty()) { SendData2 path = new SendData2(); path.setAddress("4000");//地址 - path.setData(startSite + "," + endSite + "," + inflectionBuilder.toString()); + path.setData(startSite + "," + endSite + "," + turnBuilder); path.setType(2); sendDataList.add(path); } else { @@ -335,23 +338,32 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface { //下发数据 boolean b = sendCarTask(sendDataList, deviceSrgv); - + if (b) { + wcsSrgvQueue.setPathInfo(pathBuilder.toString()); + wcsSrgvQueue.setTrunPath(turnBuilder.toString()); + wcsSagvQueueMapper.updateWcsSrgvQueue(wcsSrgvQueue); + return true; + } else { + log.error("小车下发失败 taskNo:{}", wcsSrgvQueue.getTaskNo()); + return false; + } } /** * 小车发送点对点主任务 */ - private void sendMainTask(DeviceSrgv deviceSrgv, WcsSrgvQueue wcsSrgvQueue, String currSite, String endSite, int floor) { - String taskType = wcsSrgvQueue.getTaskType(); + private void sendMainTask(DeviceSrgv deviceSrgv, WcsSrgvQueue wcsSrgvQueue, String currSite, String endSite) { + String taskType = wcsSrgvQueue.getDefault02(); boolean sendFlag = false; switch (taskType) { - case "1": + case "4": // 空车任务(充电、换层、手动点到点、除尘等) - sendFlag = sendEmptyCarTask(deviceSrgv, wcsSrgvQueue, currSite, endSite, floor); + sendFlag = sendPointToPointTask(deviceSrgv, wcsSrgvQueue, currSite, endSite); break; + case "1": case "2": // 载货任务(出库、入库、移库等) - sendFlag = sendFullCarTask(deviceSrgv, wcsSrgvQueue, currSite, endSite, floor); + sendFlag = sendPointToPointTask(deviceSrgv, wcsSrgvQueue, currSite, endSite); break; } @@ -360,253 +372,6 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface { } } - /** - * 小车发送载货任务 - */ - private boolean sendFullCarTask(DeviceSrgv deviceSrgv, WcsSrgvQueue wcsSrgvQueue, String startSite, String endSite, int floor) { - - //0 待机 1去向原站 2 到达原站托盘定位 3 上升至中位顶取货物 4生成去向目标站路径 - // 5去向目标站 6下降至低位放货,工作完成,将阶段设置为0. 20:执行点到点命令运行中 21:到达点到目标位置 22:小车充电中 - int workPhase = deviceSrgv.getWorkPhase(); - int status = deviceSrgv.getStatus();// 0:未知 1:待机 2:运行 3:报警 - int workMode = deviceSrgv.getWorkMode(); - - - //取货规划路径和下发,在货底下,并且待机,任务未被下发 - if ((workPhase == 0) && status == 1 && workMode == 5) { - //查找载货路径 - Map arrByRoadSite = roadCacheService.getArrByRoadSite(floor); - //获取空载地图(剔除不包含自己的障碍)(250919,排除其他站点) - - String noTar0 = null; - String noTar1 = null; - - if ("3".equals(wcsSrgvQueue.getCargo())) { - noTar0 = getNoTar(startSite); - noTar1 = getNoTar(endSite); - } else if ("1".equals(wcsSrgvQueue.getCargo())) { - noTar1 = getNoTar(endSite); - } else if ("2".equals(wcsSrgvQueue.getCargo())) { - noTar0 = getNoTar(startSite); - } - - - int[][] fullMap = null; - if (noTar0 == null && noTar1 == null) { - fullMap = roadCacheService.findFullMap(floor, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1], deviceSrgv); - } else { - List strings = new ArrayList<>();//排除站点 - if (noTar0 != null) { - strings.add(noTar0); - } - if (noTar1 != null) { - strings.add(noTar1); - } - - fullMap = roadCacheService.findFullMap(floor, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1], deviceSrgv, strings); - } - - //计算最短路径 - List shortestPath = PathFinder.findShortestPathFrom2To2Or1(fullMap, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1]); - //判断是否能规划出最短路径 - if (shortestPath == null || shortestPath.isEmpty()) { - //空车从当前点去目标点没有可以路径,校验是否是同层其他车影响,要上次其他车避让任务 - return false; - } - - //获取拐点路径 - List trun = PathFinder.extractInflectionPoints2(shortestPath, fullMap); - - // 路径点拼接 - StringBuilder pathBuilder = new StringBuilder(); - Map roadSiteByArr = roadCacheService.getRoadSiteByArr(Integer.parseInt(wcsSrgvQueue.getTheFloor())); - for (int[] point : shortestPath) { - String site = roadSiteByArr.get(point[0] + "," + point[1]); - if (!"000".equals(site)) { - pathBuilder.append(site).append(","); - } - } - if (pathBuilder.length() > 0) { - pathBuilder.setLength(pathBuilder.length() - 1); // 移除最后一个逗号 - } - - // 拐点拼接 - StringBuilder inflectionBuilder = new StringBuilder(); - if (!trun.isEmpty()) { - for (int[] ints : trun) { - String site = roadSiteByArr.get(ints[0] + "," + ints[1]);//获取站点 - inflectionBuilder.append(site).append(","); - } - if (inflectionBuilder.length() > 0) { - inflectionBuilder.setLength(inflectionBuilder.length() - 1); - } - // 当trun长度小于6时,后面用0拼接 - if (trun.size() < 6) { - for (int i = trun.size(); i < 6; i++) { - inflectionBuilder.append(",0"); - } - } - } - - List sendDataList = new ArrayList<>(); - - - if (!trun.isEmpty()) { - SendData2 path = new SendData2(); - path.setAddress("4000");//地址 - path.setData(startSite + "," + endSite + "," + inflectionBuilder); - path.setType(2); - sendDataList.add(path); - } else { - SendData2 path = new SendData2(); - path.setAddress("4000");//地址 - path.setData(startSite + "," + endSite); - path.setType(2); - sendDataList.add(path); - } - - - String siteId = wcsSrgvQueue.getTaskNo();//+ "," + startSite + "," + endSite; - SendData2 site = new SendData2(); - site.setAddress("4400"); - site.setData(siteId); - site.setType(2); - sendDataList.add(site); - //下发类型 - SendData2 taskType = new SendData2(); - taskType.setAddress("2200"); - taskType.setData(wcsSrgvQueue.getTaskType()); - taskType.setType(1); - sendDataList.add(taskType); - //下发标志转换 - SendData2 flag = new SendData2(); - flag.setAddress("2202"); - flag.setData("1"); - flag.setType(1); - sendDataList.add(flag); - - //boolean write = true; - return sendCarTask(sendDataList, deviceSrgv); - } - return false; - } - - /* - * 获取特俗区域的母通道排除站点 - * - * */ - private String getNoTar(String site) { - - String s = site.substring(site.length() - 4); - - String p = site.substring(0, 2); - int pi = Integer.parseInt(p); - - String l = site.substring(2, 4); - int li = Integer.parseInt(l);//排 - - String tarSite = null; - if (pi > 4 && pi < 15 && li > 30) { - tarSite = "16" + s; - } else { - - } - return tarSite; - } - - /** - * 小车发送空车任务 - */ - private boolean sendEmptyCarTask(DeviceSrgv deviceSrgv, WcsSrgvQueue wcsSrgvQueue, String startSite, String endSite, int floor) { - //获取当前地图 - Map arrByRoadSite = roadCacheService.getArrByRoadSite(floor); - //获取空载地图 - int[][] emptyMap = roadCacheService.findEmptyMap(floor, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1], deviceSrgv); - //计算最短路径 - List shortestPath = PathFinder.findShortestPath(emptyMap, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1]); - - //判断是否能规划出最短路径 - if (shortestPath == null || shortestPath.isEmpty()) { - - return false; - } - - //获取拐点路径 - List trun = PathFinder.extractInflectionPoints2(shortestPath, emptyMap); - - // 路径点拼接 - StringBuilder pathBuilder = new StringBuilder(); - Map roadSiteByArr = roadCacheService.getRoadSiteByArr(floor); - for (int[] point : shortestPath) { - String site = roadSiteByArr.get(point[0] + "," + point[1]); - if (!"000".equals(site)) { - pathBuilder.append(site).append(","); - } - - } - if (pathBuilder.length() > 0) { - pathBuilder.setLength(pathBuilder.length() - 1); // 移除最后一个逗号 - } - - // 拐点拼接 - StringBuilder inflectionBuilder = new StringBuilder(); - if (!trun.isEmpty()) { - for (int[] ints : trun) { - String site = roadSiteByArr.get(ints[0] + "," + ints[1]);//获取站点 - inflectionBuilder.append(site).append(","); - } - if (inflectionBuilder.length() > 0) { - inflectionBuilder.setLength(inflectionBuilder.length() - 1); - } - // 当trun长度小于6时,后面用0拼接 - if (trun.size() < 6) { - for (int i = trun.size(); i < 6; i++) { - inflectionBuilder.append(",0"); - } - } - } - - List sendDataList = new ArrayList<>(); - if (!trun.isEmpty()) { - SendData2 path = new SendData2(); - path.setAddress("4000");//地址 - path.setData(startSite + "," + endSite + "," + inflectionBuilder.toString()); - path.setType(2); - sendDataList.add(path); - } else { - SendData2 path = new SendData2(); - path.setAddress("4000");//地址 - path.setData(startSite + "," + endSite); - path.setType(2); - sendDataList.add(path); - } - - - //任务号、原、目标数据转换 - String siteId = wcsSrgvQueue.getTaskNo();//+ "," + startSite + "," + endSite; - SendData2 site = new SendData2(); - site.setAddress("4400"); - site.setData(siteId); - site.setType(2); - sendDataList.add(site); - - //任务类型转换 - SendData2 taskType = new SendData2(); - taskType.setAddress("2200"); - taskType.setData(wcsSrgvQueue.getDefault02()); - taskType.setType(1); - sendDataList.add(taskType); - - //下发标志转换 - SendData2 flag = new SendData2(); - flag.setAddress("2202"); - flag.setData("1"); - flag.setType(1); - sendDataList.add(flag); - - return sendCarTask(sendDataList, deviceSrgv); - } - /** * 小车发送任务 */ @@ -667,37 +432,10 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface { return b; } - /** - * 处理未指定目的地的任务 - */ - private void handleUnspecifiedDestination(WcsSrgvQueue wcsSrgvQueue, String startSite, int floor, DeviceSrgv deviceSrgv) { - } - - /** - * 判断站点是否是同一层 - * - * @param startSite - * @param endSite - * @return - */ - private boolean isSameFloor(String startSite, String endSite) { - // 参数校验 - if (startSite == null || endSite == null || startSite.length() < 2 || endSite.length() < 2) { - return false; - } - - // 正确提取起始和结束站点的楼层信息 - String startFloor = startSite.substring(startSite.length() - 2); - String endFloor = endSite.substring(endSite.length() - 2); - - // 比较是否在同一层 - return Objects.equals(startFloor, endFloor); - } - /** * 小车完成队列 */ - private void completeCarTask(DeviceSrgv deviceSrgv, int floor) { + private void completeCarTask(DeviceSrgv deviceSrgv) { //联机自动 if (deviceSrgv.getWorkMode() == 4) { //22到达充电位置 23到达换层目标 @@ -715,7 +453,7 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface { * 1、不处理终点是提升机站点的四向车 * 2、处理终点不是提升机站点的 * */ - boolean taskFinishFlag = finishTaskByQueue(deviceSrgv.getCurrSite(), wcsSrgvQueue, floor); + boolean taskFinishFlag = finishTaskByQueue(deviceSrgv.getCurrSite(), wcsSrgvQueue); if (taskFinishFlag) { String spare2 = deviceSrgv.getSpare2(); @@ -741,10 +479,9 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface { * * @param currSite * @param wcsSrgvQueue - * @param floor * @return */ - private boolean finishTaskByQueue(String currSite, WcsSrgvQueue wcsSrgvQueue, int floor) { + private boolean finishTaskByQueue(String currSite, WcsSrgvQueue wcsSrgvQueue) { //当前在放货站点 @@ -825,14 +562,13 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface { * * @param deviceSrgv */ - private void resQueue(DeviceSrgv deviceSrgv, int floor) { + private void resQueue(DeviceSrgv deviceSrgv) { int taskNo = deviceSrgv.getTaskNo(); String currSite = deviceSrgv.getCurrSite(); Integer deviceId = deviceSrgv.getDeviceId(); if (taskNo > 999 && !"000000".equals(currSite)) { WcsSrgvQueue param = new WcsSrgvQueue(); - param.setTheFloor(Convert.toStr(floor)); param.setTaskNo(Convert.toStr(taskNo)); param.setIssued("0"); param.setAgvId(String.valueOf(deviceId));